Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
30edc14b KRW |
2 | /* |
3 | * PCI Backend Xenbus Setup - handles setup with frontend and xend | |
4 | * | |
5 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> | |
6 | */ | |
283c0972 JP |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
9 | ||
59aa56bf | 10 | #include <linux/moduleparam.h> |
30edc14b KRW |
11 | #include <linux/init.h> |
12 | #include <linux/list.h> | |
13 | #include <linux/vmalloc.h> | |
14 | #include <linux/workqueue.h> | |
15 | #include <xen/xenbus.h> | |
16 | #include <xen/events.h> | |
6221a9b2 | 17 | #include <asm/xen/pci.h> |
30edc14b KRW |
18 | #include "pciback.h" |
19 | ||
20 | #define INVALID_EVTCHN_IRQ (-1) | |
30edc14b | 21 | |
90ab5ee9 | 22 | static bool __read_mostly passthrough; |
2ebdc426 KRW |
23 | module_param(passthrough, bool, S_IRUGO); |
24 | MODULE_PARM_DESC(passthrough, | |
25 | "Option to specify how to export PCI topology to guest:\n"\ | |
26 | " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ | |
27 | " there is a single PCI bus with only the exported devices on it.\n"\ | |
28 | " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ | |
29 | " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ | |
30 | " 1 - Passthrough provides a real view of the PCI topology to the\n"\ | |
31 | " frontend (for example, a device at 06:01.b will still appear at\n"\ | |
32 | " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ | |
33 | " exposed PCI devices to its driver domains. This may be required\n"\ | |
34 | " for drivers which depend on finding their hardward in certain\n"\ | |
35 | " bus/slot locations."); | |
36 | ||
a92336a1 | 37 | static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) |
30edc14b | 38 | { |
a92336a1 | 39 | struct xen_pcibk_device *pdev; |
30edc14b | 40 | |
a92336a1 | 41 | pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL); |
30edc14b KRW |
42 | if (pdev == NULL) |
43 | goto out; | |
44 | dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev); | |
45 | ||
46 | pdev->xdev = xdev; | |
30edc14b | 47 | |
b1766b62 | 48 | mutex_init(&pdev->dev_lock); |
30edc14b KRW |
49 | |
50 | pdev->sh_info = NULL; | |
51 | pdev->evtchn_irq = INVALID_EVTCHN_IRQ; | |
52 | pdev->be_watching = 0; | |
53 | ||
a92336a1 | 54 | INIT_WORK(&pdev->op_work, xen_pcibk_do_op); |
30edc14b | 55 | |
a92336a1 | 56 | if (xen_pcibk_init_devices(pdev)) { |
30edc14b KRW |
57 | kfree(pdev); |
58 | pdev = NULL; | |
59 | } | |
584a561a DG |
60 | |
61 | dev_set_drvdata(&xdev->dev, pdev); | |
62 | ||
30edc14b KRW |
63 | out: |
64 | return pdev; | |
65 | } | |
66 | ||
a92336a1 | 67 | static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev) |
30edc14b | 68 | { |
b1766b62 | 69 | mutex_lock(&pdev->dev_lock); |
30edc14b KRW |
70 | /* Ensure the guest can't trigger our handler before removing devices */ |
71 | if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) { | |
72 | unbind_from_irqhandler(pdev->evtchn_irq, pdev); | |
73 | pdev->evtchn_irq = INVALID_EVTCHN_IRQ; | |
74 | } | |
75 | ||
76 | /* If the driver domain started an op, make sure we complete it | |
77 | * before releasing the shared memory */ | |
494ef20d | 78 | |
429eafe6 | 79 | flush_work(&pdev->op_work); |
30edc14b KRW |
80 | |
81 | if (pdev->sh_info != NULL) { | |
82 | xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); | |
83 | pdev->sh_info = NULL; | |
84 | } | |
b1766b62 | 85 | mutex_unlock(&pdev->dev_lock); |
30edc14b KRW |
86 | } |
87 | ||
a92336a1 | 88 | static void free_pdev(struct xen_pcibk_device *pdev) |
30edc14b | 89 | { |
494ef20d | 90 | if (pdev->be_watching) { |
30edc14b | 91 | unregister_xenbus_watch(&pdev->be_watch); |
494ef20d KRW |
92 | pdev->be_watching = 0; |
93 | } | |
30edc14b | 94 | |
a92336a1 | 95 | xen_pcibk_disconnect(pdev); |
30edc14b | 96 | |
8be9df6d KRW |
97 | /* N.B. This calls pcistub_put_pci_dev which does the FLR on all |
98 | * of the PCIe devices. */ | |
a92336a1 | 99 | xen_pcibk_release_devices(pdev); |
30edc14b KRW |
100 | |
101 | dev_set_drvdata(&pdev->xdev->dev, NULL); | |
102 | pdev->xdev = NULL; | |
103 | ||
104 | kfree(pdev); | |
105 | } | |
106 | ||
a92336a1 | 107 | static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, |
0102e4ef | 108 | evtchn_port_t remote_evtchn) |
30edc14b KRW |
109 | { |
110 | int err = 0; | |
111 | void *vaddr; | |
112 | ||
113 | dev_dbg(&pdev->xdev->dev, | |
0102e4ef | 114 | "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n", |
30edc14b KRW |
115 | gnt_ref, remote_evtchn); |
116 | ||
ccc9d90a | 117 | err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); |
30edc14b KRW |
118 | if (err < 0) { |
119 | xenbus_dev_fatal(pdev->xdev, err, | |
120 | "Error mapping other domain page in ours."); | |
121 | goto out; | |
122 | } | |
494ef20d | 123 | |
30edc14b KRW |
124 | pdev->sh_info = vaddr; |
125 | ||
c2711441 | 126 | err = bind_interdomain_evtchn_to_irqhandler_lateeoi( |
f2fa0e5e | 127 | pdev->xdev, remote_evtchn, xen_pcibk_handle_event, |
a92336a1 | 128 | 0, DRV_NAME, pdev); |
30edc14b KRW |
129 | if (err < 0) { |
130 | xenbus_dev_fatal(pdev->xdev, err, | |
131 | "Error binding event channel to IRQ"); | |
132 | goto out; | |
133 | } | |
134 | pdev->evtchn_irq = err; | |
135 | err = 0; | |
136 | ||
137 | dev_dbg(&pdev->xdev->dev, "Attached!\n"); | |
138 | out: | |
139 | return err; | |
140 | } | |
141 | ||
a92336a1 | 142 | static int xen_pcibk_attach(struct xen_pcibk_device *pdev) |
30edc14b KRW |
143 | { |
144 | int err = 0; | |
0102e4ef YY |
145 | int gnt_ref; |
146 | evtchn_port_t remote_evtchn; | |
30edc14b KRW |
147 | char *magic = NULL; |
148 | ||
30edc14b | 149 | |
b1766b62 | 150 | mutex_lock(&pdev->dev_lock); |
30edc14b KRW |
151 | /* Make sure we only do this setup once */ |
152 | if (xenbus_read_driver_state(pdev->xdev->nodename) != | |
153 | XenbusStateInitialised) | |
154 | goto out; | |
155 | ||
156 | /* Wait for frontend to state that it has published the configuration */ | |
157 | if (xenbus_read_driver_state(pdev->xdev->otherend) != | |
158 | XenbusStateInitialised) | |
159 | goto out; | |
160 | ||
161 | dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); | |
162 | ||
163 | err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, | |
164 | "pci-op-ref", "%u", &gnt_ref, | |
165 | "event-channel", "%u", &remote_evtchn, | |
166 | "magic", NULL, &magic, NULL); | |
167 | if (err) { | |
168 | /* If configuration didn't get read correctly, wait longer */ | |
169 | xenbus_dev_fatal(pdev->xdev, err, | |
170 | "Error reading configuration from frontend"); | |
171 | goto out; | |
172 | } | |
173 | ||
174 | if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { | |
175 | xenbus_dev_fatal(pdev->xdev, -EFAULT, | |
176 | "version mismatch (%s/%s) with pcifront - " | |
402c5e15 | 177 | "halting " DRV_NAME, |
30edc14b | 178 | magic, XEN_PCI_MAGIC); |
2ef76032 | 179 | err = -EFAULT; |
30edc14b KRW |
180 | goto out; |
181 | } | |
182 | ||
a92336a1 | 183 | err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); |
30edc14b KRW |
184 | if (err) |
185 | goto out; | |
186 | ||
187 | dev_dbg(&pdev->xdev->dev, "Connecting...\n"); | |
188 | ||
189 | err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); | |
190 | if (err) | |
191 | xenbus_dev_fatal(pdev->xdev, err, | |
192 | "Error switching to connected state!"); | |
193 | ||
194 | dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); | |
195 | out: | |
b1766b62 | 196 | mutex_unlock(&pdev->dev_lock); |
30edc14b KRW |
197 | |
198 | kfree(magic); | |
199 | ||
200 | return err; | |
201 | } | |
202 | ||
a92336a1 | 203 | static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, |
30edc14b KRW |
204 | unsigned int domain, unsigned int bus, |
205 | unsigned int devfn, unsigned int devid) | |
206 | { | |
207 | int err; | |
208 | int len; | |
209 | char str[64]; | |
210 | ||
211 | len = snprintf(str, sizeof(str), "vdev-%d", devid); | |
212 | if (unlikely(len >= (sizeof(str) - 1))) { | |
213 | err = -ENOMEM; | |
214 | goto out; | |
215 | } | |
216 | ||
e4de866a | 217 | /* Note: The PV protocol uses %02x, don't change it */ |
30edc14b KRW |
218 | err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, |
219 | "%04x:%02x:%02x.%02x", domain, bus, | |
220 | PCI_SLOT(devfn), PCI_FUNC(devfn)); | |
221 | ||
222 | out: | |
223 | return err; | |
224 | } | |
225 | ||
a92336a1 | 226 | static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, |
30edc14b KRW |
227 | int domain, int bus, int slot, int func, |
228 | int devid) | |
229 | { | |
230 | struct pci_dev *dev; | |
231 | int err = 0; | |
232 | ||
233 | dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", | |
234 | domain, bus, slot, func); | |
235 | ||
236 | dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); | |
237 | if (!dev) { | |
238 | err = -EINVAL; | |
239 | xenbus_dev_fatal(pdev->xdev, err, | |
240 | "Couldn't locate PCI device " | |
e4de866a | 241 | "(%04x:%02x:%02x.%d)! " |
30edc14b KRW |
242 | "perhaps already in-use?", |
243 | domain, bus, slot, func); | |
244 | goto out; | |
245 | } | |
246 | ||
a92336a1 KRW |
247 | err = xen_pcibk_add_pci_dev(pdev, dev, devid, |
248 | xen_pcibk_publish_pci_dev); | |
30edc14b KRW |
249 | if (err) |
250 | goto out; | |
251 | ||
15390613 | 252 | dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); |
6221a9b2 KRW |
253 | if (xen_register_device_domain_owner(dev, |
254 | pdev->xdev->otherend_id) != 0) { | |
6c254de1 KRW |
255 | dev_err(&dev->dev, "Stealing ownership from dom%d.\n", |
256 | xen_find_device_domain_owner(dev)); | |
6221a9b2 KRW |
257 | xen_unregister_device_domain_owner(dev); |
258 | xen_register_device_domain_owner(dev, pdev->xdev->otherend_id); | |
259 | } | |
260 | ||
30edc14b KRW |
261 | /* TODO: It'd be nice to export a bridge and have all of its children |
262 | * get exported with it. This may be best done in xend (which will | |
263 | * have to calculate resource usage anyway) but we probably want to | |
264 | * put something in here to ensure that if a bridge gets given to a | |
265 | * driver domain, that all devices under that bridge are not given | |
266 | * to other driver domains (as he who controls the bridge can disable | |
267 | * it and stop the other devices from working). | |
268 | */ | |
269 | out: | |
270 | return err; | |
271 | } | |
272 | ||
a92336a1 | 273 | static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, |
30edc14b KRW |
274 | int domain, int bus, int slot, int func) |
275 | { | |
276 | int err = 0; | |
277 | struct pci_dev *dev; | |
278 | ||
279 | dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", | |
280 | domain, bus, slot, func); | |
281 | ||
a92336a1 | 282 | dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); |
30edc14b KRW |
283 | if (!dev) { |
284 | err = -EINVAL; | |
285 | dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " | |
e4de866a | 286 | "(%04x:%02x:%02x.%d)! not owned by this domain\n", |
30edc14b KRW |
287 | domain, bus, slot, func); |
288 | goto out; | |
289 | } | |
290 | ||
6221a9b2 KRW |
291 | dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); |
292 | xen_unregister_device_domain_owner(dev); | |
293 | ||
8be9df6d KRW |
294 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up |
295 | * doing the FLR. */ | |
e8801a74 | 296 | xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); |
30edc14b KRW |
297 | |
298 | out: | |
299 | return err; | |
300 | } | |
301 | ||
a92336a1 | 302 | static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, |
30edc14b KRW |
303 | unsigned int domain, unsigned int bus) |
304 | { | |
305 | unsigned int d, b; | |
306 | int i, root_num, len, err; | |
307 | char str[64]; | |
308 | ||
309 | dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); | |
310 | ||
311 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, | |
312 | "root_num", "%d", &root_num); | |
313 | if (err == 0 || err == -ENOENT) | |
314 | root_num = 0; | |
315 | else if (err < 0) | |
316 | goto out; | |
317 | ||
318 | /* Verify that we haven't already published this pci root */ | |
319 | for (i = 0; i < root_num; i++) { | |
320 | len = snprintf(str, sizeof(str), "root-%d", i); | |
321 | if (unlikely(len >= (sizeof(str) - 1))) { | |
322 | err = -ENOMEM; | |
323 | goto out; | |
324 | } | |
325 | ||
326 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, | |
327 | str, "%x:%x", &d, &b); | |
328 | if (err < 0) | |
329 | goto out; | |
330 | if (err != 2) { | |
331 | err = -EINVAL; | |
332 | goto out; | |
333 | } | |
334 | ||
335 | if (d == domain && b == bus) { | |
336 | err = 0; | |
337 | goto out; | |
338 | } | |
339 | } | |
340 | ||
341 | len = snprintf(str, sizeof(str), "root-%d", root_num); | |
342 | if (unlikely(len >= (sizeof(str) - 1))) { | |
343 | err = -ENOMEM; | |
344 | goto out; | |
345 | } | |
346 | ||
347 | dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", | |
348 | root_num, domain, bus); | |
349 | ||
350 | err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, | |
351 | "%04x:%02x", domain, bus); | |
352 | if (err) | |
353 | goto out; | |
354 | ||
355 | err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, | |
356 | "root_num", "%d", (root_num + 1)); | |
357 | ||
358 | out: | |
359 | return err; | |
360 | } | |
361 | ||
c81d3d24 JB |
362 | static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev, |
363 | enum xenbus_state state) | |
30edc14b KRW |
364 | { |
365 | int err = 0; | |
366 | int num_devs; | |
367 | int domain, bus, slot, func; | |
4e81f1ca | 368 | unsigned int substate; |
30edc14b KRW |
369 | int i, len; |
370 | char state_str[64]; | |
371 | char dev_str[64]; | |
372 | ||
30edc14b KRW |
373 | |
374 | dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); | |
375 | ||
b1766b62 | 376 | mutex_lock(&pdev->dev_lock); |
c81d3d24 | 377 | if (xenbus_read_driver_state(pdev->xdev->nodename) != state) |
30edc14b KRW |
378 | goto out; |
379 | ||
380 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", | |
381 | &num_devs); | |
382 | if (err != 1) { | |
383 | if (err >= 0) | |
384 | err = -EINVAL; | |
385 | xenbus_dev_fatal(pdev->xdev, err, | |
386 | "Error reading number of devices"); | |
387 | goto out; | |
388 | } | |
389 | ||
390 | for (i = 0; i < num_devs; i++) { | |
391 | len = snprintf(state_str, sizeof(state_str), "state-%d", i); | |
392 | if (unlikely(len >= (sizeof(state_str) - 1))) { | |
393 | err = -ENOMEM; | |
394 | xenbus_dev_fatal(pdev->xdev, err, | |
395 | "String overflow while reading " | |
396 | "configuration"); | |
397 | goto out; | |
398 | } | |
4e81f1ca JG |
399 | substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str, |
400 | XenbusStateUnknown); | |
30edc14b KRW |
401 | |
402 | switch (substate) { | |
403 | case XenbusStateInitialising: | |
404 | dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); | |
405 | ||
406 | len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); | |
407 | if (unlikely(len >= (sizeof(dev_str) - 1))) { | |
408 | err = -ENOMEM; | |
409 | xenbus_dev_fatal(pdev->xdev, err, | |
410 | "String overflow while " | |
411 | "reading configuration"); | |
412 | goto out; | |
413 | } | |
414 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, | |
415 | dev_str, "%x:%x:%x.%x", | |
416 | &domain, &bus, &slot, &func); | |
417 | if (err < 0) { | |
418 | xenbus_dev_fatal(pdev->xdev, err, | |
419 | "Error reading device " | |
420 | "configuration"); | |
421 | goto out; | |
422 | } | |
423 | if (err != 4) { | |
424 | err = -EINVAL; | |
425 | xenbus_dev_fatal(pdev->xdev, err, | |
426 | "Error parsing pci device " | |
427 | "configuration"); | |
428 | goto out; | |
429 | } | |
430 | ||
a92336a1 | 431 | err = xen_pcibk_export_device(pdev, domain, bus, slot, |
30edc14b KRW |
432 | func, i); |
433 | if (err) | |
434 | goto out; | |
435 | ||
436 | /* Publish pci roots. */ | |
a92336a1 KRW |
437 | err = xen_pcibk_publish_pci_roots(pdev, |
438 | xen_pcibk_publish_pci_root); | |
30edc14b KRW |
439 | if (err) { |
440 | xenbus_dev_fatal(pdev->xdev, err, | |
441 | "Error while publish PCI root" | |
442 | "buses for frontend"); | |
443 | goto out; | |
444 | } | |
445 | ||
446 | err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, | |
447 | state_str, "%d", | |
448 | XenbusStateInitialised); | |
449 | if (err) { | |
450 | xenbus_dev_fatal(pdev->xdev, err, | |
451 | "Error switching substate of " | |
452 | "dev-%d\n", i); | |
453 | goto out; | |
454 | } | |
455 | break; | |
456 | ||
457 | case XenbusStateClosing: | |
458 | dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); | |
459 | ||
460 | len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); | |
461 | if (unlikely(len >= (sizeof(dev_str) - 1))) { | |
462 | err = -ENOMEM; | |
463 | xenbus_dev_fatal(pdev->xdev, err, | |
464 | "String overflow while " | |
465 | "reading configuration"); | |
466 | goto out; | |
467 | } | |
468 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, | |
469 | dev_str, "%x:%x:%x.%x", | |
470 | &domain, &bus, &slot, &func); | |
471 | if (err < 0) { | |
472 | xenbus_dev_fatal(pdev->xdev, err, | |
473 | "Error reading device " | |
474 | "configuration"); | |
475 | goto out; | |
476 | } | |
477 | if (err != 4) { | |
478 | err = -EINVAL; | |
479 | xenbus_dev_fatal(pdev->xdev, err, | |
480 | "Error parsing pci device " | |
481 | "configuration"); | |
482 | goto out; | |
483 | } | |
484 | ||
a92336a1 | 485 | err = xen_pcibk_remove_device(pdev, domain, bus, slot, |
30edc14b KRW |
486 | func); |
487 | if (err) | |
488 | goto out; | |
489 | ||
490 | /* TODO: If at some point we implement support for pci | |
491 | * root hot-remove on pcifront side, we'll need to | |
492 | * remove unnecessary xenstore nodes of pci roots here. | |
493 | */ | |
494 | ||
495 | break; | |
496 | ||
497 | default: | |
498 | break; | |
499 | } | |
500 | } | |
501 | ||
c81d3d24 JB |
502 | if (state != XenbusStateReconfiguring) |
503 | /* Make sure we only reconfigure once. */ | |
504 | goto out; | |
505 | ||
30edc14b KRW |
506 | err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); |
507 | if (err) { | |
508 | xenbus_dev_fatal(pdev->xdev, err, | |
509 | "Error switching to reconfigured state!"); | |
510 | goto out; | |
511 | } | |
512 | ||
513 | out: | |
b1766b62 | 514 | mutex_unlock(&pdev->dev_lock); |
30edc14b KRW |
515 | return 0; |
516 | } | |
517 | ||
a92336a1 | 518 | static void xen_pcibk_frontend_changed(struct xenbus_device *xdev, |
30edc14b KRW |
519 | enum xenbus_state fe_state) |
520 | { | |
a92336a1 | 521 | struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev); |
30edc14b KRW |
522 | |
523 | dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); | |
524 | ||
525 | switch (fe_state) { | |
526 | case XenbusStateInitialised: | |
a92336a1 | 527 | xen_pcibk_attach(pdev); |
30edc14b KRW |
528 | break; |
529 | ||
530 | case XenbusStateReconfiguring: | |
c81d3d24 | 531 | xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring); |
30edc14b KRW |
532 | break; |
533 | ||
534 | case XenbusStateConnected: | |
535 | /* pcifront switched its state from reconfiguring to connected. | |
536 | * Then switch to connected state. | |
537 | */ | |
538 | xenbus_switch_state(xdev, XenbusStateConnected); | |
539 | break; | |
540 | ||
541 | case XenbusStateClosing: | |
a92336a1 | 542 | xen_pcibk_disconnect(pdev); |
30edc14b KRW |
543 | xenbus_switch_state(xdev, XenbusStateClosing); |
544 | break; | |
545 | ||
546 | case XenbusStateClosed: | |
a92336a1 | 547 | xen_pcibk_disconnect(pdev); |
30edc14b KRW |
548 | xenbus_switch_state(xdev, XenbusStateClosed); |
549 | if (xenbus_dev_is_online(xdev)) | |
550 | break; | |
df561f66 | 551 | fallthrough; /* if not online */ |
30edc14b KRW |
552 | case XenbusStateUnknown: |
553 | dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); | |
554 | device_unregister(&xdev->dev); | |
555 | break; | |
556 | ||
557 | default: | |
558 | break; | |
559 | } | |
560 | } | |
561 | ||
a92336a1 | 562 | static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) |
30edc14b KRW |
563 | { |
564 | /* Get configuration from xend (if available now) */ | |
565 | int domain, bus, slot, func; | |
566 | int err = 0; | |
567 | int i, num_devs; | |
568 | char dev_str[64]; | |
569 | char state_str[64]; | |
570 | ||
b1766b62 | 571 | mutex_lock(&pdev->dev_lock); |
30edc14b KRW |
572 | /* It's possible we could get the call to setup twice, so make sure |
573 | * we're not already connected. | |
574 | */ | |
575 | if (xenbus_read_driver_state(pdev->xdev->nodename) != | |
576 | XenbusStateInitWait) | |
577 | goto out; | |
578 | ||
579 | dev_dbg(&pdev->xdev->dev, "getting be setup\n"); | |
580 | ||
581 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", | |
582 | &num_devs); | |
583 | if (err != 1) { | |
584 | if (err >= 0) | |
585 | err = -EINVAL; | |
586 | xenbus_dev_fatal(pdev->xdev, err, | |
587 | "Error reading number of devices"); | |
588 | goto out; | |
589 | } | |
590 | ||
591 | for (i = 0; i < num_devs; i++) { | |
592 | int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); | |
593 | if (unlikely(l >= (sizeof(dev_str) - 1))) { | |
594 | err = -ENOMEM; | |
595 | xenbus_dev_fatal(pdev->xdev, err, | |
596 | "String overflow while reading " | |
597 | "configuration"); | |
598 | goto out; | |
599 | } | |
600 | ||
601 | err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, | |
602 | "%x:%x:%x.%x", &domain, &bus, &slot, &func); | |
603 | if (err < 0) { | |
604 | xenbus_dev_fatal(pdev->xdev, err, | |
605 | "Error reading device configuration"); | |
606 | goto out; | |
607 | } | |
608 | if (err != 4) { | |
609 | err = -EINVAL; | |
610 | xenbus_dev_fatal(pdev->xdev, err, | |
611 | "Error parsing pci device " | |
612 | "configuration"); | |
613 | goto out; | |
614 | } | |
615 | ||
a92336a1 | 616 | err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); |
30edc14b KRW |
617 | if (err) |
618 | goto out; | |
619 | ||
620 | /* Switch substate of this device. */ | |
621 | l = snprintf(state_str, sizeof(state_str), "state-%d", i); | |
622 | if (unlikely(l >= (sizeof(state_str) - 1))) { | |
623 | err = -ENOMEM; | |
624 | xenbus_dev_fatal(pdev->xdev, err, | |
625 | "String overflow while reading " | |
626 | "configuration"); | |
627 | goto out; | |
628 | } | |
629 | err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, | |
630 | "%d", XenbusStateInitialised); | |
631 | if (err) { | |
632 | xenbus_dev_fatal(pdev->xdev, err, "Error switching " | |
633 | "substate of dev-%d\n", i); | |
634 | goto out; | |
635 | } | |
636 | } | |
637 | ||
a92336a1 | 638 | err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); |
30edc14b KRW |
639 | if (err) { |
640 | xenbus_dev_fatal(pdev->xdev, err, | |
641 | "Error while publish PCI root buses " | |
642 | "for frontend"); | |
643 | goto out; | |
644 | } | |
645 | ||
646 | err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); | |
647 | if (err) | |
648 | xenbus_dev_fatal(pdev->xdev, err, | |
649 | "Error switching to initialised state!"); | |
650 | ||
651 | out: | |
b1766b62 | 652 | mutex_unlock(&pdev->dev_lock); |
30edc14b KRW |
653 | if (!err) |
654 | /* see if pcifront is already configured (if not, we'll wait) */ | |
a92336a1 | 655 | xen_pcibk_attach(pdev); |
30edc14b KRW |
656 | return err; |
657 | } | |
658 | ||
a92336a1 | 659 | static void xen_pcibk_be_watch(struct xenbus_watch *watch, |
5584ea25 | 660 | const char *path, const char *token) |
30edc14b | 661 | { |
a92336a1 KRW |
662 | struct xen_pcibk_device *pdev = |
663 | container_of(watch, struct xen_pcibk_device, be_watch); | |
30edc14b KRW |
664 | |
665 | switch (xenbus_read_driver_state(pdev->xdev->nodename)) { | |
666 | case XenbusStateInitWait: | |
a92336a1 | 667 | xen_pcibk_setup_backend(pdev); |
30edc14b KRW |
668 | break; |
669 | ||
c81d3d24 JB |
670 | case XenbusStateInitialised: |
671 | /* | |
672 | * We typically move to Initialised when the first device was | |
673 | * added. Hence subsequent devices getting added may need | |
674 | * reconfiguring. | |
675 | */ | |
676 | xen_pcibk_reconfigure(pdev, XenbusStateInitialised); | |
677 | break; | |
678 | ||
30edc14b KRW |
679 | default: |
680 | break; | |
681 | } | |
682 | } | |
683 | ||
a92336a1 | 684 | static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, |
30edc14b KRW |
685 | const struct xenbus_device_id *id) |
686 | { | |
687 | int err = 0; | |
a92336a1 | 688 | struct xen_pcibk_device *pdev = alloc_pdev(dev); |
30edc14b KRW |
689 | |
690 | if (pdev == NULL) { | |
691 | err = -ENOMEM; | |
692 | xenbus_dev_fatal(dev, err, | |
a92336a1 | 693 | "Error allocating xen_pcibk_device struct"); |
30edc14b KRW |
694 | goto out; |
695 | } | |
696 | ||
697 | /* wait for xend to configure us */ | |
698 | err = xenbus_switch_state(dev, XenbusStateInitWait); | |
699 | if (err) | |
700 | goto out; | |
701 | ||
702 | /* watch the backend node for backend configuration information */ | |
703 | err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, | |
2e85d32b | 704 | NULL, xen_pcibk_be_watch); |
30edc14b KRW |
705 | if (err) |
706 | goto out; | |
494ef20d | 707 | |
30edc14b KRW |
708 | pdev->be_watching = 1; |
709 | ||
710 | /* We need to force a call to our callback here in case | |
711 | * xend already configured us! | |
712 | */ | |
515762b9 | 713 | xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL); |
30edc14b KRW |
714 | |
715 | out: | |
716 | return err; | |
717 | } | |
718 | ||
a92336a1 | 719 | static int xen_pcibk_xenbus_remove(struct xenbus_device *dev) |
30edc14b | 720 | { |
a92336a1 | 721 | struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); |
30edc14b KRW |
722 | |
723 | if (pdev != NULL) | |
724 | free_pdev(pdev); | |
725 | ||
726 | return 0; | |
727 | } | |
728 | ||
73db144b | 729 | static const struct xenbus_device_id xen_pcibk_ids[] = { |
30edc14b KRW |
730 | {"pci"}, |
731 | {""}, | |
732 | }; | |
733 | ||
95afae48 DV |
734 | static struct xenbus_driver xen_pcibk_driver = { |
735 | .name = DRV_NAME, | |
736 | .ids = xen_pcibk_ids, | |
a92336a1 KRW |
737 | .probe = xen_pcibk_xenbus_probe, |
738 | .remove = xen_pcibk_xenbus_remove, | |
739 | .otherend_changed = xen_pcibk_frontend_changed, | |
95afae48 | 740 | }; |
30edc14b | 741 | |
402c5e15 | 742 | const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; |
2ebdc426 | 743 | |
a92336a1 | 744 | int __init xen_pcibk_xenbus_register(void) |
30edc14b | 745 | { |
2ebdc426 KRW |
746 | xen_pcibk_backend = &xen_pcibk_vpci_backend; |
747 | if (passthrough) | |
748 | xen_pcibk_backend = &xen_pcibk_passthrough_backend; | |
283c0972 | 749 | pr_info("backend is %s\n", xen_pcibk_backend->name); |
73db144b | 750 | return xenbus_register_backend(&xen_pcibk_driver); |
30edc14b KRW |
751 | } |
752 | ||
a92336a1 | 753 | void __exit xen_pcibk_xenbus_unregister(void) |
30edc14b | 754 | { |
73db144b | 755 | xenbus_unregister_driver(&xen_pcibk_driver); |
30edc14b | 756 | } |