Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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