sclp_pci.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * PCI I/O adapter configuration related functions.
  4. *
  5. * Copyright IBM Corp. 2016
  6. */
  7. #define KMSG_COMPONENT "sclp_cmd"
  8. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  9. #include <linux/completion.h>
  10. #include <linux/export.h>
  11. #include <linux/mutex.h>
  12. #include <linux/errno.h>
  13. #include <linux/slab.h>
  14. #include <linux/init.h>
  15. #include <linux/err.h>
  16. #include <asm/sclp.h>
  17. #include "sclp.h"
  18. #define SCLP_CMDW_CONFIGURE_PCI 0x001a0001
  19. #define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001
  20. #define SCLP_ATYPE_PCI 2
  21. #define SCLP_ERRNOTIFY_AQ_REPAIR 1
  22. #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
  23. static DEFINE_MUTEX(sclp_pci_mutex);
  24. static struct sclp_register sclp_pci_event = {
  25. .send_mask = EVTYP_ERRNOTIFY_MASK,
  26. };
  27. struct err_notify_evbuf {
  28. struct evbuf_header header;
  29. u8 action;
  30. u8 atype;
  31. u32 fh;
  32. u32 fid;
  33. u8 data[0];
  34. } __packed;
  35. struct err_notify_sccb {
  36. struct sccb_header header;
  37. struct err_notify_evbuf evbuf;
  38. } __packed;
  39. struct pci_cfg_sccb {
  40. struct sccb_header header;
  41. u8 atype; /* adapter type */
  42. u8 reserved1;
  43. u16 reserved2;
  44. u32 aid; /* adapter identifier */
  45. } __packed;
  46. static int do_pci_configure(sclp_cmdw_t cmd, u32 fid)
  47. {
  48. struct pci_cfg_sccb *sccb;
  49. int rc;
  50. if (!SCLP_HAS_PCI_RECONFIG)
  51. return -EOPNOTSUPP;
  52. sccb = (struct pci_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  53. if (!sccb)
  54. return -ENOMEM;
  55. sccb->header.length = PAGE_SIZE;
  56. sccb->atype = SCLP_ATYPE_PCI;
  57. sccb->aid = fid;
  58. rc = sclp_sync_request(cmd, sccb);
  59. if (rc)
  60. goto out;
  61. switch (sccb->header.response_code) {
  62. case 0x0020:
  63. case 0x0120:
  64. break;
  65. default:
  66. pr_warn("configure PCI I/O adapter failed: cmd=0x%08x response=0x%04x\n",
  67. cmd, sccb->header.response_code);
  68. rc = -EIO;
  69. break;
  70. }
  71. out:
  72. free_page((unsigned long) sccb);
  73. return rc;
  74. }
  75. int sclp_pci_configure(u32 fid)
  76. {
  77. return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid);
  78. }
  79. EXPORT_SYMBOL(sclp_pci_configure);
  80. int sclp_pci_deconfigure(u32 fid)
  81. {
  82. return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid);
  83. }
  84. EXPORT_SYMBOL(sclp_pci_deconfigure);
  85. static void sclp_pci_callback(struct sclp_req *req, void *data)
  86. {
  87. struct completion *completion = data;
  88. complete(completion);
  89. }
  90. static int sclp_pci_check_report(struct zpci_report_error_header *report)
  91. {
  92. if (report->version != 1)
  93. return -EINVAL;
  94. if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
  95. report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
  96. return -EINVAL;
  97. if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
  98. return -EINVAL;
  99. return 0;
  100. }
  101. int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid)
  102. {
  103. DECLARE_COMPLETION_ONSTACK(completion);
  104. struct err_notify_sccb *sccb;
  105. struct sclp_req req;
  106. int ret;
  107. ret = sclp_pci_check_report(report);
  108. if (ret)
  109. return ret;
  110. mutex_lock(&sclp_pci_mutex);
  111. ret = sclp_register(&sclp_pci_event);
  112. if (ret)
  113. goto out_unlock;
  114. if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) {
  115. ret = -EOPNOTSUPP;
  116. goto out_unregister;
  117. }
  118. sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
  119. if (!sccb) {
  120. ret = -ENOMEM;
  121. goto out_unregister;
  122. }
  123. memset(&req, 0, sizeof(req));
  124. req.callback_data = &completion;
  125. req.callback = sclp_pci_callback;
  126. req.command = SCLP_CMDW_WRITE_EVENT_DATA;
  127. req.status = SCLP_REQ_FILLED;
  128. req.sccb = sccb;
  129. sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length;
  130. sccb->evbuf.header.type = EVTYP_ERRNOTIFY;
  131. sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length;
  132. sccb->evbuf.action = report->action;
  133. sccb->evbuf.atype = SCLP_ATYPE_PCI;
  134. sccb->evbuf.fh = fh;
  135. sccb->evbuf.fid = fid;
  136. memcpy(sccb->evbuf.data, report->data, report->length);
  137. ret = sclp_add_request(&req);
  138. if (ret)
  139. goto out_free_req;
  140. wait_for_completion(&completion);
  141. if (req.status != SCLP_REQ_DONE) {
  142. pr_warn("request failed (status=0x%02x)\n",
  143. req.status);
  144. ret = -EIO;
  145. goto out_free_req;
  146. }
  147. if (sccb->header.response_code != 0x0020) {
  148. pr_warn("request failed with response code 0x%x\n",
  149. sccb->header.response_code);
  150. ret = -EIO;
  151. }
  152. out_free_req:
  153. free_page((unsigned long) sccb);
  154. out_unregister:
  155. sclp_unregister(&sclp_pci_event);
  156. out_unlock:
  157. mutex_unlock(&sclp_pci_mutex);
  158. return ret;
  159. }