blob: 7f4ce8d874a4c5044ed569cd70f82c81c20cf0e6 [file] [log] [blame]
Jan Glaubera755a452012-11-29 12:55:21 +01001/*
2 * Copyright IBM Corp. 2012
3 *
4 * Author(s):
5 * Jan Glauber <jang@linux.vnet.ibm.com>
6 */
7
8#define COMPONENT "zPCI"
9#define pr_fmt(fmt) COMPONENT ": " fmt
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/err.h>
14#include <linux/delay.h>
15#include <linux/pci.h>
16#include <asm/pci_clp.h>
17
18/*
19 * Call Logical Processor
20 * Retry logic is handled by the caller.
21 */
22static inline u8 clp_instr(void *req)
23{
24 u64 ilpm;
25 u8 cc;
26
27 asm volatile (
28 " .insn rrf,0xb9a00000,%[ilpm],%[req],0x0,0x2\n"
29 " ipm %[cc]\n"
30 " srl %[cc],28\n"
31 : [cc] "=d" (cc), [ilpm] "=d" (ilpm)
32 : [req] "a" (req)
33 : "cc", "memory");
34 return cc;
35}
36
37static void *clp_alloc_block(void)
38{
39 struct page *page = alloc_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE));
40 return (page) ? page_address(page) : NULL;
41}
42
43static void clp_free_block(void *ptr)
44{
45 free_pages((unsigned long) ptr, get_order(CLP_BLK_SIZE));
46}
47
48static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
49 struct clp_rsp_query_pci_grp *response)
50{
Jan Glauber828b35f2012-11-29 14:33:30 +010051 zdev->tlb_refresh = response->refresh;
52 zdev->dma_mask = response->dasm;
Jan Glauber9a4da8a2012-11-29 13:05:05 +010053 zdev->msi_addr = response->msia;
54
55 pr_debug("Supported number of MSI vectors: %u\n", response->noi);
Jan Glaubera755a452012-11-29 12:55:21 +010056 switch (response->version) {
57 case 1:
58 zdev->max_bus_speed = PCIE_SPEED_5_0GT;
59 break;
60 default:
61 zdev->max_bus_speed = PCI_SPEED_UNKNOWN;
62 break;
63 }
64}
65
66static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)
67{
68 struct clp_req_rsp_query_pci_grp *rrb;
69 int rc;
70
71 rrb = clp_alloc_block();
72 if (!rrb)
73 return -ENOMEM;
74
75 memset(rrb, 0, sizeof(*rrb));
76 rrb->request.hdr.len = sizeof(rrb->request);
77 rrb->request.hdr.cmd = CLP_QUERY_PCI_FNGRP;
78 rrb->response.hdr.len = sizeof(rrb->response);
79 rrb->request.pfgid = pfgid;
80
81 rc = clp_instr(rrb);
82 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
83 clp_store_query_pci_fngrp(zdev, &rrb->response);
84 else {
85 pr_err("Query PCI FNGRP failed with response: %x cc: %d\n",
86 rrb->response.hdr.rsp, rc);
87 rc = -EIO;
88 }
89 clp_free_block(rrb);
90 return rc;
91}
92
93static int clp_store_query_pci_fn(struct zpci_dev *zdev,
94 struct clp_rsp_query_pci *response)
95{
96 int i;
97
98 for (i = 0; i < PCI_BAR_COUNT; i++) {
99 zdev->bars[i].val = le32_to_cpu(response->bar[i]);
100 zdev->bars[i].size = response->bar_size[i];
101 }
Jan Glauber828b35f2012-11-29 14:33:30 +0100102 zdev->start_dma = response->sdma;
103 zdev->end_dma = response->edma;
Jan Glaubera755a452012-11-29 12:55:21 +0100104 zdev->pchid = response->pchid;
105 zdev->pfgid = response->pfgid;
106 return 0;
107}
108
109static int clp_query_pci_fn(struct zpci_dev *zdev, u32 fh)
110{
111 struct clp_req_rsp_query_pci *rrb;
112 int rc;
113
114 rrb = clp_alloc_block();
115 if (!rrb)
116 return -ENOMEM;
117
118 memset(rrb, 0, sizeof(*rrb));
119 rrb->request.hdr.len = sizeof(rrb->request);
120 rrb->request.hdr.cmd = CLP_QUERY_PCI_FN;
121 rrb->response.hdr.len = sizeof(rrb->response);
122 rrb->request.fh = fh;
123
124 rc = clp_instr(rrb);
125 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
126 rc = clp_store_query_pci_fn(zdev, &rrb->response);
127 if (rc)
128 goto out;
129 if (rrb->response.pfgid)
130 rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);
131 } else {
132 pr_err("Query PCI failed with response: %x cc: %d\n",
133 rrb->response.hdr.rsp, rc);
134 rc = -EIO;
135 }
136out:
137 clp_free_block(rrb);
138 return rc;
139}
140
141int clp_add_pci_device(u32 fid, u32 fh, int configured)
142{
143 struct zpci_dev *zdev;
144 int rc;
145
146 zdev = zpci_alloc_device();
147 if (IS_ERR(zdev))
148 return PTR_ERR(zdev);
149
150 zdev->fh = fh;
151 zdev->fid = fid;
152
153 /* Query function properties and update zdev */
154 rc = clp_query_pci_fn(zdev, fh);
155 if (rc)
156 goto error;
157
158 if (configured)
159 zdev->state = ZPCI_FN_STATE_CONFIGURED;
160 else
161 zdev->state = ZPCI_FN_STATE_STANDBY;
162
163 rc = zpci_create_device(zdev);
164 if (rc)
165 goto error;
166 return 0;
167
168error:
169 zpci_free_device(zdev);
170 return rc;
171}
172
173/*
174 * Enable/Disable a given PCI function defined by its function handle.
175 */
176static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
177{
178 struct clp_req_rsp_set_pci *rrb;
179 int rc, retries = 1000;
180
181 rrb = clp_alloc_block();
182 if (!rrb)
183 return -ENOMEM;
184
185 do {
186 memset(rrb, 0, sizeof(*rrb));
187 rrb->request.hdr.len = sizeof(rrb->request);
188 rrb->request.hdr.cmd = CLP_SET_PCI_FN;
189 rrb->response.hdr.len = sizeof(rrb->response);
190 rrb->request.fh = *fh;
191 rrb->request.oc = command;
192 rrb->request.ndas = nr_dma_as;
193
194 rc = clp_instr(rrb);
195 if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) {
196 retries--;
197 if (retries < 0)
198 break;
199 msleep(1);
200 }
201 } while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
202
203 if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
204 *fh = rrb->response.fh;
205 else {
206 pr_err("Set PCI FN failed with response: %x cc: %d\n",
207 rrb->response.hdr.rsp, rc);
208 rc = -EIO;
209 }
210 clp_free_block(rrb);
211 return rc;
212}
213
214int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
215{
216 u32 fh = zdev->fh;
217 int rc;
218
219 rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
220 if (!rc)
221 /* Success -> store enabled handle in zdev */
222 zdev->fh = fh;
223 return rc;
224}
225
226int clp_disable_fh(struct zpci_dev *zdev)
227{
228 u32 fh = zdev->fh;
229 int rc;
230
231 if (!zdev_enabled(zdev))
232 return 0;
233
234 dev_info(&zdev->pdev->dev, "disabling fn handle: 0x%x\n", fh);
235 rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
236 if (!rc)
237 /* Success -> store disabled handle in zdev */
238 zdev->fh = fh;
239 else
240 dev_err(&zdev->pdev->dev,
241 "Failed to disable fn handle: 0x%x\n", fh);
242 return rc;
243}
244
245static void clp_check_pcifn_entry(struct clp_fh_list_entry *entry)
246{
247 int present, rc;
248
249 if (!entry->vendor_id)
250 return;
251
252 /* TODO: be a little bit more scalable */
253 present = zpci_fid_present(entry->fid);
254
255 if (present)
256 pr_debug("%s: device %x already present\n", __func__, entry->fid);
257
258 /* skip already used functions */
259 if (present && entry->config_state)
260 return;
261
262 /* aev 306: function moved to stand-by state */
263 if (present && !entry->config_state) {
264 /*
265 * The handle is already disabled, that means no iota/irq freeing via
266 * the firmware interfaces anymore. Need to free resources manually
267 * (DMA memory, debug, sysfs)...
268 */
269 zpci_stop_device(get_zdev_by_fid(entry->fid));
270 return;
271 }
272
273 rc = clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
274 if (rc)
275 pr_err("Failed to add fid: 0x%x\n", entry->fid);
276}
277
278int clp_find_pci_devices(void)
279{
280 struct clp_req_rsp_list_pci *rrb;
281 u64 resume_token = 0;
282 int entries, i, rc;
283
284 rrb = clp_alloc_block();
285 if (!rrb)
286 return -ENOMEM;
287
288 do {
289 memset(rrb, 0, sizeof(*rrb));
290 rrb->request.hdr.len = sizeof(rrb->request);
291 rrb->request.hdr.cmd = CLP_LIST_PCI;
292 /* store as many entries as possible */
293 rrb->response.hdr.len = CLP_BLK_SIZE - LIST_PCI_HDR_LEN;
294 rrb->request.resume_token = resume_token;
295
296 /* Get PCI function handle list */
297 rc = clp_instr(rrb);
298 if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
299 pr_err("List PCI failed with response: 0x%x cc: %d\n",
300 rrb->response.hdr.rsp, rc);
301 rc = -EIO;
302 goto out;
303 }
304
305 WARN_ON_ONCE(rrb->response.entry_size !=
306 sizeof(struct clp_fh_list_entry));
307
308 entries = (rrb->response.hdr.len - LIST_PCI_HDR_LEN) /
309 rrb->response.entry_size;
310 pr_info("Detected number of PCI functions: %u\n", entries);
311
312 /* Store the returned resume token as input for the next call */
313 resume_token = rrb->response.resume_token;
314
315 for (i = 0; i < entries; i++)
316 clp_check_pcifn_entry(&rrb->response.fh_list[i]);
317 } while (resume_token);
318
319 pr_debug("Maximum number of supported PCI functions: %u\n",
320 rrb->response.max_fn);
321out:
322 clp_free_block(rrb);
323 return rc;
324}