1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * PCI Backend Xenbus Setup - handles setup with frontend and xend |
4 | * |
5 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/moduleparam.h> |
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> |
17 | #include <xen/pci.h> |
18 | #include "pciback.h" |
19 | |
20 | #define INVALID_EVTCHN_IRQ (-1) |
21 | |
22 | static bool __read_mostly passthrough; |
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 hardware in certain\n" \ |
35 | " bus/slot locations." ); |
36 | |
37 | static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) |
38 | { |
39 | struct xen_pcibk_device *pdev; |
40 | |
41 | pdev = kzalloc(size: sizeof(struct xen_pcibk_device), GFP_KERNEL); |
42 | if (pdev == NULL) |
43 | goto out; |
44 | dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n" , pdev); |
45 | |
46 | pdev->xdev = xdev; |
47 | |
48 | mutex_init(&pdev->dev_lock); |
49 | |
50 | pdev->sh_info = NULL; |
51 | pdev->evtchn_irq = INVALID_EVTCHN_IRQ; |
52 | pdev->be_watching = 0; |
53 | |
54 | INIT_WORK(&pdev->op_work, xen_pcibk_do_op); |
55 | |
56 | if (xen_pcibk_init_devices(pdev)) { |
57 | kfree(objp: pdev); |
58 | pdev = NULL; |
59 | } |
60 | |
61 | dev_set_drvdata(dev: &xdev->dev, data: pdev); |
62 | |
63 | out: |
64 | return pdev; |
65 | } |
66 | |
67 | static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev) |
68 | { |
69 | mutex_lock(&pdev->dev_lock); |
70 | /* Ensure the guest can't trigger our handler before removing devices */ |
71 | if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) { |
72 | unbind_from_irqhandler(irq: pdev->evtchn_irq, dev_id: 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 */ |
78 | |
79 | flush_work(work: &pdev->op_work); |
80 | |
81 | if (pdev->sh_info != NULL) { |
82 | xenbus_unmap_ring_vfree(dev: pdev->xdev, vaddr: pdev->sh_info); |
83 | pdev->sh_info = NULL; |
84 | } |
85 | mutex_unlock(lock: &pdev->dev_lock); |
86 | } |
87 | |
88 | static void free_pdev(struct xen_pcibk_device *pdev) |
89 | { |
90 | if (pdev->be_watching) { |
91 | unregister_xenbus_watch(watch: &pdev->be_watch); |
92 | pdev->be_watching = 0; |
93 | } |
94 | |
95 | xen_pcibk_disconnect(pdev); |
96 | |
97 | /* N.B. This calls pcistub_put_pci_dev which does the FLR on all |
98 | * of the PCIe devices. */ |
99 | xen_pcibk_release_devices(pdev); |
100 | |
101 | dev_set_drvdata(dev: &pdev->xdev->dev, NULL); |
102 | pdev->xdev = NULL; |
103 | |
104 | kfree(objp: pdev); |
105 | } |
106 | |
107 | static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, |
108 | evtchn_port_t remote_evtchn) |
109 | { |
110 | int err = 0; |
111 | void *vaddr; |
112 | |
113 | dev_dbg(&pdev->xdev->dev, |
114 | "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n" , |
115 | gnt_ref, remote_evtchn); |
116 | |
117 | err = xenbus_map_ring_valloc(dev: pdev->xdev, gnt_refs: &gnt_ref, nr_grefs: 1, vaddr: &vaddr); |
118 | if (err < 0) { |
119 | xenbus_dev_fatal(dev: pdev->xdev, err, |
120 | fmt: "Error mapping other domain page in ours." ); |
121 | goto out; |
122 | } |
123 | |
124 | pdev->sh_info = vaddr; |
125 | |
126 | err = bind_interdomain_evtchn_to_irqhandler_lateeoi( |
127 | dev: pdev->xdev, remote_port: remote_evtchn, handler: xen_pcibk_handle_event, |
128 | irqflags: 0, DRV_NAME, dev_id: pdev); |
129 | if (err < 0) { |
130 | xenbus_dev_fatal(dev: pdev->xdev, err, |
131 | fmt: "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 | |
142 | static int xen_pcibk_attach(struct xen_pcibk_device *pdev) |
143 | { |
144 | int err = 0; |
145 | int gnt_ref; |
146 | evtchn_port_t remote_evtchn; |
147 | char *magic = NULL; |
148 | |
149 | |
150 | mutex_lock(&pdev->dev_lock); |
151 | /* Make sure we only do this setup once */ |
152 | if (xenbus_read_driver_state(path: 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(path: 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, dir: 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 - " |
177 | "halting " DRV_NAME, |
178 | magic, XEN_PCI_MAGIC); |
179 | err = -EFAULT; |
180 | goto out; |
181 | } |
182 | |
183 | err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); |
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: |
196 | mutex_unlock(&pdev->dev_lock); |
197 | |
198 | kfree(magic); |
199 | |
200 | return err; |
201 | } |
202 | |
203 | static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, |
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(buf: str, size: sizeof(str), fmt: "vdev-%d" , devid); |
212 | if (unlikely(len >= (sizeof(str) - 1))) { |
213 | err = -ENOMEM; |
214 | goto out; |
215 | } |
216 | |
217 | /* Note: The PV protocol uses %02x, don't change it */ |
218 | err = xenbus_printf(XBT_NIL, dir: pdev->xdev->nodename, node: str, |
219 | fmt: "%04x:%02x:%02x.%02x" , domain, bus, |
220 | PCI_SLOT(devfn), PCI_FUNC(devfn)); |
221 | |
222 | out: |
223 | return err; |
224 | } |
225 | |
226 | static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, |
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(dev: pdev->xdev, err, |
240 | fmt: "Couldn't locate PCI device " |
241 | "(%04x:%02x:%02x.%d)! " |
242 | "perhaps already in-use?" , |
243 | domain, bus, slot, func); |
244 | goto out; |
245 | } |
246 | |
247 | err = xen_pcibk_add_pci_dev(pdev, dev, devid, |
248 | publish_cb: xen_pcibk_publish_pci_dev); |
249 | if (err) |
250 | goto out; |
251 | |
252 | dev_info(&dev->dev, "registering for %d\n" , pdev->xdev->otherend_id); |
253 | if (xen_register_device_domain_owner(dev, |
254 | domain: pdev->xdev->otherend_id) != 0) { |
255 | dev_err(&dev->dev, "Stealing ownership from dom%d.\n" , |
256 | xen_find_device_domain_owner(dev)); |
257 | xen_unregister_device_domain_owner(dev); |
258 | xen_register_device_domain_owner(dev, domain: pdev->xdev->otherend_id); |
259 | } |
260 | |
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 | |
273 | static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, |
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 | |
282 | dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); |
283 | if (!dev) { |
284 | err = -EINVAL; |
285 | dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " |
286 | "(%04x:%02x:%02x.%d)! not owned by this domain\n" , |
287 | domain, bus, slot, func); |
288 | goto out; |
289 | } |
290 | |
291 | dev_dbg(&dev->dev, "unregistering for %d\n" , pdev->xdev->otherend_id); |
292 | xen_unregister_device_domain_owner(dev); |
293 | |
294 | /* N.B. This ends up calling pcistub_put_pci_dev which ends up |
295 | * doing the FLR. */ |
296 | xen_pcibk_release_pci_dev(pdev, dev, lock: true /* use the lock. */); |
297 | |
298 | out: |
299 | return err; |
300 | } |
301 | |
302 | static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, |
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, dir: pdev->xdev->nodename, |
312 | node: "root_num" , fmt: "%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 | |
362 | static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev, |
363 | enum xenbus_state state) |
364 | { |
365 | int err = 0; |
366 | int num_devs; |
367 | int domain, bus, slot, func; |
368 | unsigned int substate; |
369 | int i, len; |
370 | char state_str[64]; |
371 | char dev_str[64]; |
372 | |
373 | |
374 | dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n" ); |
375 | |
376 | mutex_lock(&pdev->dev_lock); |
377 | if (xenbus_read_driver_state(path: pdev->xdev->nodename) != state) |
378 | goto out; |
379 | |
380 | err = xenbus_scanf(XBT_NIL, dir: pdev->xdev->nodename, node: "num_devs" , fmt: "%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 | } |
399 | substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str, |
400 | XenbusStateUnknown); |
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 | |
431 | err = xen_pcibk_export_device(pdev, domain, bus, slot, |
432 | func, i); |
433 | if (err) |
434 | goto out; |
435 | |
436 | /* Publish pci roots. */ |
437 | err = xen_pcibk_publish_pci_roots(pdev, |
438 | xen_pcibk_publish_pci_root); |
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 | |
485 | err = xen_pcibk_remove_device(pdev, domain, bus, slot, |
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 | |
502 | if (state != XenbusStateReconfiguring) |
503 | /* Make sure we only reconfigure once. */ |
504 | goto out; |
505 | |
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: |
514 | mutex_unlock(&pdev->dev_lock); |
515 | return 0; |
516 | } |
517 | |
518 | static void xen_pcibk_frontend_changed(struct xenbus_device *xdev, |
519 | enum xenbus_state fe_state) |
520 | { |
521 | struct xen_pcibk_device *pdev = dev_get_drvdata(dev: &xdev->dev); |
522 | |
523 | dev_dbg(&xdev->dev, "fe state changed %d\n" , fe_state); |
524 | |
525 | switch (fe_state) { |
526 | case XenbusStateInitialised: |
527 | xen_pcibk_attach(pdev); |
528 | break; |
529 | |
530 | case XenbusStateReconfiguring: |
531 | xen_pcibk_reconfigure(pdev, state: XenbusStateReconfiguring); |
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(dev: xdev, new_state: XenbusStateConnected); |
539 | break; |
540 | |
541 | case XenbusStateClosing: |
542 | xen_pcibk_disconnect(pdev); |
543 | xenbus_switch_state(dev: xdev, new_state: XenbusStateClosing); |
544 | break; |
545 | |
546 | case XenbusStateClosed: |
547 | xen_pcibk_disconnect(pdev); |
548 | xenbus_switch_state(dev: xdev, new_state: XenbusStateClosed); |
549 | if (xenbus_dev_is_online(dev: xdev)) |
550 | break; |
551 | fallthrough; /* if not online */ |
552 | case XenbusStateUnknown: |
553 | dev_dbg(&xdev->dev, "frontend is gone! unregister device\n" ); |
554 | device_unregister(dev: &xdev->dev); |
555 | break; |
556 | |
557 | default: |
558 | break; |
559 | } |
560 | } |
561 | |
562 | static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) |
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 | |
571 | mutex_lock(&pdev->dev_lock); |
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(path: 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, dir: pdev->xdev->nodename, node: "num_devs" , fmt: "%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 | |
616 | err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); |
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 | |
638 | err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); |
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: |
652 | mutex_unlock(&pdev->dev_lock); |
653 | if (!err) |
654 | /* see if pcifront is already configured (if not, we'll wait) */ |
655 | xen_pcibk_attach(pdev); |
656 | return err; |
657 | } |
658 | |
659 | static void xen_pcibk_be_watch(struct xenbus_watch *watch, |
660 | const char *path, const char *token) |
661 | { |
662 | struct xen_pcibk_device *pdev = |
663 | container_of(watch, struct xen_pcibk_device, be_watch); |
664 | |
665 | switch (xenbus_read_driver_state(path: pdev->xdev->nodename)) { |
666 | case XenbusStateInitWait: |
667 | xen_pcibk_setup_backend(pdev); |
668 | break; |
669 | |
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, state: XenbusStateInitialised); |
677 | break; |
678 | |
679 | default: |
680 | break; |
681 | } |
682 | } |
683 | |
684 | static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, |
685 | const struct xenbus_device_id *id) |
686 | { |
687 | int err = 0; |
688 | struct xen_pcibk_device *pdev = alloc_pdev(xdev: dev); |
689 | |
690 | if (pdev == NULL) { |
691 | err = -ENOMEM; |
692 | xenbus_dev_fatal(dev, err, |
693 | fmt: "Error allocating xen_pcibk_device struct" ); |
694 | goto out; |
695 | } |
696 | |
697 | /* wait for xend to configure us */ |
698 | err = xenbus_switch_state(dev, new_state: XenbusStateInitWait); |
699 | if (err) |
700 | goto out; |
701 | |
702 | /* watch the backend node for backend configuration information */ |
703 | err = xenbus_watch_path(dev, path: dev->nodename, watch: &pdev->be_watch, |
704 | NULL, callback: xen_pcibk_be_watch); |
705 | if (err) |
706 | goto out; |
707 | |
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 | */ |
713 | xen_pcibk_be_watch(watch: &pdev->be_watch, NULL, NULL); |
714 | |
715 | out: |
716 | return err; |
717 | } |
718 | |
719 | static void xen_pcibk_xenbus_remove(struct xenbus_device *dev) |
720 | { |
721 | struct xen_pcibk_device *pdev = dev_get_drvdata(dev: &dev->dev); |
722 | |
723 | if (pdev != NULL) |
724 | free_pdev(pdev); |
725 | } |
726 | |
727 | static const struct xenbus_device_id xen_pcibk_ids[] = { |
728 | {"pci" }, |
729 | {"" }, |
730 | }; |
731 | |
732 | static struct xenbus_driver xen_pcibk_driver = { |
733 | .name = DRV_NAME, |
734 | .ids = xen_pcibk_ids, |
735 | .probe = xen_pcibk_xenbus_probe, |
736 | .remove = xen_pcibk_xenbus_remove, |
737 | .otherend_changed = xen_pcibk_frontend_changed, |
738 | }; |
739 | |
740 | const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; |
741 | |
742 | int __init xen_pcibk_xenbus_register(void) |
743 | { |
744 | if (!xen_pcibk_pv_support()) |
745 | return 0; |
746 | |
747 | xen_pcibk_backend = &xen_pcibk_vpci_backend; |
748 | if (passthrough) |
749 | xen_pcibk_backend = &xen_pcibk_passthrough_backend; |
750 | pr_info("backend is %s\n" , xen_pcibk_backend->name); |
751 | return xenbus_register_backend(&xen_pcibk_driver); |
752 | } |
753 | |
754 | void __exit xen_pcibk_xenbus_unregister(void) |
755 | { |
756 | if (xen_pcibk_pv_support()) |
757 | xenbus_unregister_driver(drv: &xen_pcibk_driver); |
758 | } |
759 | |