powerpc/perf: Fix core-imc hotplug callback failure during imc initialization
[sfrench/cifs-2.6.git] / drivers / s390 / char / sclp_pci.c
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
29 static DEFINE_MUTEX(sclp_pci_mutex);
30 static struct sclp_register sclp_pci_event = {
31         .send_mask = EVTYP_ERRNOTIFY_MASK,
32 };
33
34 struct 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
43 struct err_notify_sccb {
44         struct sccb_header header;
45         struct err_notify_evbuf evbuf;
46 } __packed;
47
48 struct 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
56 static 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         }
84 out:
85         free_page((unsigned long) sccb);
86         return rc;
87 }
88
89 int sclp_pci_configure(u32 fid)
90 {
91         return do_pci_configure(SCLP_CMDW_CONFIGURE_PCI, fid);
92 }
93 EXPORT_SYMBOL(sclp_pci_configure);
94
95 int sclp_pci_deconfigure(u32 fid)
96 {
97         return do_pci_configure(SCLP_CMDW_DECONFIGURE_PCI, fid);
98 }
99 EXPORT_SYMBOL(sclp_pci_deconfigure);
100
101 static void sclp_pci_callback(struct sclp_req *req, void *data)
102 {
103         struct completion *completion = data;
104
105         complete(completion);
106 }
107
108 static 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
123 int 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
186 out_free_req:
187         free_page((unsigned long) sccb);
188 out_unregister:
189         sclp_unregister(&sclp_pci_event);
190 out_unlock:
191         mutex_unlock(&sclp_pci_mutex);
192         return ret;
193 }