aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/xen-pciback/xenbus.c
diff options
context:
space:
mode:
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2009-10-13 17:22:20 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-07-19 20:58:01 -0400
commit30edc14bf39afde24ef7db2de66c91805db80828 (patch)
tree1cf5b6f28a3ea4159a09bcef9d11be6d427e3558 /drivers/xen/xen-pciback/xenbus.c
parent56299378726d5f2ba8d3c8cbbd13cb280ba45e4f (diff)
xen/pciback: xen pci backend driver.
This is the host side counterpart to the frontend driver in drivers/pci/xen-pcifront.c. The PV protocol is also implemented by frontend drivers in other OSes too, such as the BSDs. The PV protocol is rather simple. There is page shared with the guest, which has the 'struct xen_pci_sharedinfo' embossed in it. The backend has a thread that is kicked every-time the structure is changed and based on the operation field it performs specific tasks: XEN_PCI_OP_conf_[read|write]: Read/Write 0xCF8/0xCFC filtered data. (conf_space*.c) Based on which field is probed, we either enable/disable the PCI device, change power state, read VPD, etc. The major goal of this call is to provide a Physical IRQ (PIRQ) to the guest. The PIRQ is Xen hypervisor global IRQ value irrespective of the IRQ is tied in to the IO-APIC, or is a vector. For GSI type interrupts, the PIRQ==GSI holds. For MSI/MSI-X the PIRQ value != Linux IRQ number (thought PIRQ==vector). Please note, that with Xen, all interrupts (except those level shared ones) are injected directly to the guest - there is no host interaction. XEN_PCI_OP_[enable|disable]_msi[|x] (pciback_ops.c) Enables/disables the MSI/MSI-X capability of the device. These operations setup the MSI/MSI-X vectors for the guest and pass them to the frontend. When the device is activated, the interrupts are directly injected in the guest without involving the host. XEN_PCI_OP_aer_[detected|resume|mmio|slotreset]: In case of failure, perform the appropriate AER commands on the guest. Right now that is a cop-out - we just kill the guest. Besides implementing those commands, it can also - hide a PCI device from the host. When booting up, the user can specify xen-pciback.hide=(1:0:0)(BDF..) so that host does not try to use the device. The driver was lifted from linux-2.6.18.hg tree and fixed up so that it could compile under v3.0. Per suggestion from Jesse Barnes moved the driver to drivers/xen/xen-pciback. Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'drivers/xen/xen-pciback/xenbus.c')
-rw-r--r--drivers/xen/xen-pciback/xenbus.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
new file mode 100644
index 000000000000..af6c25a1d729
--- /dev/null
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -0,0 +1,709 @@
1/*
2 * PCI Backend Xenbus Setup - handles setup with frontend and xend
3 *
4 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
5 */
6#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/list.h>
9#include <linux/vmalloc.h>
10#include <linux/workqueue.h>
11#include <xen/xenbus.h>
12#include <xen/events.h>
13#include <linux/workqueue.h>
14#include "pciback.h"
15
16#define INVALID_EVTCHN_IRQ (-1)
17struct workqueue_struct *pciback_wq;
18
19static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
20{
21 struct pciback_device *pdev;
22
23 pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
24 if (pdev == NULL)
25 goto out;
26 dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
27
28 pdev->xdev = xdev;
29 dev_set_drvdata(&xdev->dev, pdev);
30
31 spin_lock_init(&pdev->dev_lock);
32
33 pdev->sh_info = NULL;
34 pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
35 pdev->be_watching = 0;
36
37 INIT_WORK(&pdev->op_work, pciback_do_op);
38
39 if (pciback_init_devices(pdev)) {
40 kfree(pdev);
41 pdev = NULL;
42 }
43out:
44 return pdev;
45}
46
47static void pciback_disconnect(struct pciback_device *pdev)
48{
49 spin_lock(&pdev->dev_lock);
50
51 /* Ensure the guest can't trigger our handler before removing devices */
52 if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
53 unbind_from_irqhandler(pdev->evtchn_irq, pdev);
54 pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
55 }
56
57 /* If the driver domain started an op, make sure we complete it
58 * before releasing the shared memory */
59 flush_workqueue(pciback_wq);
60
61 if (pdev->sh_info != NULL) {
62 xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
63 pdev->sh_info = NULL;
64 }
65
66 spin_unlock(&pdev->dev_lock);
67}
68
69static void free_pdev(struct pciback_device *pdev)
70{
71 if (pdev->be_watching)
72 unregister_xenbus_watch(&pdev->be_watch);
73
74 pciback_disconnect(pdev);
75
76 pciback_release_devices(pdev);
77
78 dev_set_drvdata(&pdev->xdev->dev, NULL);
79 pdev->xdev = NULL;
80
81 kfree(pdev);
82}
83
84static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
85 int remote_evtchn)
86{
87 int err = 0;
88 void *vaddr;
89
90 dev_dbg(&pdev->xdev->dev,
91 "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
92 gnt_ref, remote_evtchn);
93
94 err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr);
95 if (err < 0) {
96 xenbus_dev_fatal(pdev->xdev, err,
97 "Error mapping other domain page in ours.");
98 goto out;
99 }
100 pdev->sh_info = vaddr;
101
102 err = bind_interdomain_evtchn_to_irqhandler(
103 pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
104 0, "pciback", pdev);
105 if (err < 0) {
106 xenbus_dev_fatal(pdev->xdev, err,
107 "Error binding event channel to IRQ");
108 goto out;
109 }
110 pdev->evtchn_irq = err;
111 err = 0;
112
113 dev_dbg(&pdev->xdev->dev, "Attached!\n");
114out:
115 return err;
116}
117
118static int pciback_attach(struct pciback_device *pdev)
119{
120 int err = 0;
121 int gnt_ref, remote_evtchn;
122 char *magic = NULL;
123
124 spin_lock(&pdev->dev_lock);
125
126 /* Make sure we only do this setup once */
127 if (xenbus_read_driver_state(pdev->xdev->nodename) !=
128 XenbusStateInitialised)
129 goto out;
130
131 /* Wait for frontend to state that it has published the configuration */
132 if (xenbus_read_driver_state(pdev->xdev->otherend) !=
133 XenbusStateInitialised)
134 goto out;
135
136 dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
137
138 err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
139 "pci-op-ref", "%u", &gnt_ref,
140 "event-channel", "%u", &remote_evtchn,
141 "magic", NULL, &magic, NULL);
142 if (err) {
143 /* If configuration didn't get read correctly, wait longer */
144 xenbus_dev_fatal(pdev->xdev, err,
145 "Error reading configuration from frontend");
146 goto out;
147 }
148
149 if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
150 xenbus_dev_fatal(pdev->xdev, -EFAULT,
151 "version mismatch (%s/%s) with pcifront - "
152 "halting pciback",
153 magic, XEN_PCI_MAGIC);
154 goto out;
155 }
156
157 err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
158 if (err)
159 goto out;
160
161 dev_dbg(&pdev->xdev->dev, "Connecting...\n");
162
163 err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
164 if (err)
165 xenbus_dev_fatal(pdev->xdev, err,
166 "Error switching to connected state!");
167
168 dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
169out:
170 spin_unlock(&pdev->dev_lock);
171
172 kfree(magic);
173
174 return err;
175}
176
177static int pciback_publish_pci_dev(struct pciback_device *pdev,
178 unsigned int domain, unsigned int bus,
179 unsigned int devfn, unsigned int devid)
180{
181 int err;
182 int len;
183 char str[64];
184
185 len = snprintf(str, sizeof(str), "vdev-%d", devid);
186 if (unlikely(len >= (sizeof(str) - 1))) {
187 err = -ENOMEM;
188 goto out;
189 }
190
191 err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
192 "%04x:%02x:%02x.%02x", domain, bus,
193 PCI_SLOT(devfn), PCI_FUNC(devfn));
194
195out:
196 return err;
197}
198
199static int pciback_export_device(struct pciback_device *pdev,
200 int domain, int bus, int slot, int func,
201 int devid)
202{
203 struct pci_dev *dev;
204 int err = 0;
205
206 dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
207 domain, bus, slot, func);
208
209 dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
210 if (!dev) {
211 err = -EINVAL;
212 xenbus_dev_fatal(pdev->xdev, err,
213 "Couldn't locate PCI device "
214 "(%04x:%02x:%02x.%01x)! "
215 "perhaps already in-use?",
216 domain, bus, slot, func);
217 goto out;
218 }
219
220 err = pciback_add_pci_dev(pdev, dev, devid, pciback_publish_pci_dev);
221 if (err)
222 goto out;
223
224 /* TODO: It'd be nice to export a bridge and have all of its children
225 * get exported with it. This may be best done in xend (which will
226 * have to calculate resource usage anyway) but we probably want to
227 * put something in here to ensure that if a bridge gets given to a
228 * driver domain, that all devices under that bridge are not given
229 * to other driver domains (as he who controls the bridge can disable
230 * it and stop the other devices from working).
231 */
232out:
233 return err;
234}
235
236static int pciback_remove_device(struct pciback_device *pdev,
237 int domain, int bus, int slot, int func)
238{
239 int err = 0;
240 struct pci_dev *dev;
241
242 dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
243 domain, bus, slot, func);
244
245 dev = pciback_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
246 if (!dev) {
247 err = -EINVAL;
248 dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
249 "(%04x:%02x:%02x.%01x)! not owned by this domain\n",
250 domain, bus, slot, func);
251 goto out;
252 }
253
254 pciback_release_pci_dev(pdev, dev);
255
256out:
257 return err;
258}
259
260static int pciback_publish_pci_root(struct pciback_device *pdev,
261 unsigned int domain, unsigned int bus)
262{
263 unsigned int d, b;
264 int i, root_num, len, err;
265 char str[64];
266
267 dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
268
269 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
270 "root_num", "%d", &root_num);
271 if (err == 0 || err == -ENOENT)
272 root_num = 0;
273 else if (err < 0)
274 goto out;
275
276 /* Verify that we haven't already published this pci root */
277 for (i = 0; i < root_num; i++) {
278 len = snprintf(str, sizeof(str), "root-%d", i);
279 if (unlikely(len >= (sizeof(str) - 1))) {
280 err = -ENOMEM;
281 goto out;
282 }
283
284 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
285 str, "%x:%x", &d, &b);
286 if (err < 0)
287 goto out;
288 if (err != 2) {
289 err = -EINVAL;
290 goto out;
291 }
292
293 if (d == domain && b == bus) {
294 err = 0;
295 goto out;
296 }
297 }
298
299 len = snprintf(str, sizeof(str), "root-%d", root_num);
300 if (unlikely(len >= (sizeof(str) - 1))) {
301 err = -ENOMEM;
302 goto out;
303 }
304
305 dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
306 root_num, domain, bus);
307
308 err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
309 "%04x:%02x", domain, bus);
310 if (err)
311 goto out;
312
313 err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
314 "root_num", "%d", (root_num + 1));
315
316out:
317 return err;
318}
319
320static int pciback_reconfigure(struct pciback_device *pdev)
321{
322 int err = 0;
323 int num_devs;
324 int domain, bus, slot, func;
325 int substate;
326 int i, len;
327 char state_str[64];
328 char dev_str[64];
329
330 spin_lock(&pdev->dev_lock);
331
332 dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
333
334 /* Make sure we only reconfigure once */
335 if (xenbus_read_driver_state(pdev->xdev->nodename) !=
336 XenbusStateReconfiguring)
337 goto out;
338
339 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
340 &num_devs);
341 if (err != 1) {
342 if (err >= 0)
343 err = -EINVAL;
344 xenbus_dev_fatal(pdev->xdev, err,
345 "Error reading number of devices");
346 goto out;
347 }
348
349 for (i = 0; i < num_devs; i++) {
350 len = snprintf(state_str, sizeof(state_str), "state-%d", i);
351 if (unlikely(len >= (sizeof(state_str) - 1))) {
352 err = -ENOMEM;
353 xenbus_dev_fatal(pdev->xdev, err,
354 "String overflow while reading "
355 "configuration");
356 goto out;
357 }
358 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
359 "%d", &substate);
360 if (err != 1)
361 substate = XenbusStateUnknown;
362
363 switch (substate) {
364 case XenbusStateInitialising:
365 dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
366
367 len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
368 if (unlikely(len >= (sizeof(dev_str) - 1))) {
369 err = -ENOMEM;
370 xenbus_dev_fatal(pdev->xdev, err,
371 "String overflow while "
372 "reading configuration");
373 goto out;
374 }
375 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
376 dev_str, "%x:%x:%x.%x",
377 &domain, &bus, &slot, &func);
378 if (err < 0) {
379 xenbus_dev_fatal(pdev->xdev, err,
380 "Error reading device "
381 "configuration");
382 goto out;
383 }
384 if (err != 4) {
385 err = -EINVAL;
386 xenbus_dev_fatal(pdev->xdev, err,
387 "Error parsing pci device "
388 "configuration");
389 goto out;
390 }
391
392 err = pciback_export_device(pdev, domain, bus, slot,
393 func, i);
394 if (err)
395 goto out;
396
397 /* Publish pci roots. */
398 err = pciback_publish_pci_roots(pdev,
399 pciback_publish_pci_root);
400 if (err) {
401 xenbus_dev_fatal(pdev->xdev, err,
402 "Error while publish PCI root"
403 "buses for frontend");
404 goto out;
405 }
406
407 err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
408 state_str, "%d",
409 XenbusStateInitialised);
410 if (err) {
411 xenbus_dev_fatal(pdev->xdev, err,
412 "Error switching substate of "
413 "dev-%d\n", i);
414 goto out;
415 }
416 break;
417
418 case XenbusStateClosing:
419 dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
420
421 len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
422 if (unlikely(len >= (sizeof(dev_str) - 1))) {
423 err = -ENOMEM;
424 xenbus_dev_fatal(pdev->xdev, err,
425 "String overflow while "
426 "reading configuration");
427 goto out;
428 }
429 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
430 dev_str, "%x:%x:%x.%x",
431 &domain, &bus, &slot, &func);
432 if (err < 0) {
433 xenbus_dev_fatal(pdev->xdev, err,
434 "Error reading device "
435 "configuration");
436 goto out;
437 }
438 if (err != 4) {
439 err = -EINVAL;
440 xenbus_dev_fatal(pdev->xdev, err,
441 "Error parsing pci device "
442 "configuration");
443 goto out;
444 }
445
446 err = pciback_remove_device(pdev, domain, bus, slot,
447 func);
448 if (err)
449 goto out;
450
451 /* TODO: If at some point we implement support for pci
452 * root hot-remove on pcifront side, we'll need to
453 * remove unnecessary xenstore nodes of pci roots here.
454 */
455
456 break;
457
458 default:
459 break;
460 }
461 }
462
463 err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
464 if (err) {
465 xenbus_dev_fatal(pdev->xdev, err,
466 "Error switching to reconfigured state!");
467 goto out;
468 }
469
470out:
471 spin_unlock(&pdev->dev_lock);
472
473 return 0;
474}
475
476static void pciback_frontend_changed(struct xenbus_device *xdev,
477 enum xenbus_state fe_state)
478{
479 struct pciback_device *pdev = dev_get_drvdata(&xdev->dev);
480
481 dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
482
483 switch (fe_state) {
484 case XenbusStateInitialised:
485 pciback_attach(pdev);
486 break;
487
488 case XenbusStateReconfiguring:
489 pciback_reconfigure(pdev);
490 break;
491
492 case XenbusStateConnected:
493 /* pcifront switched its state from reconfiguring to connected.
494 * Then switch to connected state.
495 */
496 xenbus_switch_state(xdev, XenbusStateConnected);
497 break;
498
499 case XenbusStateClosing:
500 pciback_disconnect(pdev);
501 xenbus_switch_state(xdev, XenbusStateClosing);
502 break;
503
504 case XenbusStateClosed:
505 pciback_disconnect(pdev);
506 xenbus_switch_state(xdev, XenbusStateClosed);
507 if (xenbus_dev_is_online(xdev))
508 break;
509 /* fall through if not online */
510 case XenbusStateUnknown:
511 dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
512 device_unregister(&xdev->dev);
513 break;
514
515 default:
516 break;
517 }
518}
519
520static int pciback_setup_backend(struct pciback_device *pdev)
521{
522 /* Get configuration from xend (if available now) */
523 int domain, bus, slot, func;
524 int err = 0;
525 int i, num_devs;
526 char dev_str[64];
527 char state_str[64];
528
529 spin_lock(&pdev->dev_lock);
530
531 /* It's possible we could get the call to setup twice, so make sure
532 * we're not already connected.
533 */
534 if (xenbus_read_driver_state(pdev->xdev->nodename) !=
535 XenbusStateInitWait)
536 goto out;
537
538 dev_dbg(&pdev->xdev->dev, "getting be setup\n");
539
540 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
541 &num_devs);
542 if (err != 1) {
543 if (err >= 0)
544 err = -EINVAL;
545 xenbus_dev_fatal(pdev->xdev, err,
546 "Error reading number of devices");
547 goto out;
548 }
549
550 for (i = 0; i < num_devs; i++) {
551 int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
552 if (unlikely(l >= (sizeof(dev_str) - 1))) {
553 err = -ENOMEM;
554 xenbus_dev_fatal(pdev->xdev, err,
555 "String overflow while reading "
556 "configuration");
557 goto out;
558 }
559
560 err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
561 "%x:%x:%x.%x", &domain, &bus, &slot, &func);
562 if (err < 0) {
563 xenbus_dev_fatal(pdev->xdev, err,
564 "Error reading device configuration");
565 goto out;
566 }
567 if (err != 4) {
568 err = -EINVAL;
569 xenbus_dev_fatal(pdev->xdev, err,
570 "Error parsing pci device "
571 "configuration");
572 goto out;
573 }
574
575 err = pciback_export_device(pdev, domain, bus, slot, func, i);
576 if (err)
577 goto out;
578
579 /* Switch substate of this device. */
580 l = snprintf(state_str, sizeof(state_str), "state-%d", i);
581 if (unlikely(l >= (sizeof(state_str) - 1))) {
582 err = -ENOMEM;
583 xenbus_dev_fatal(pdev->xdev, err,
584 "String overflow while reading "
585 "configuration");
586 goto out;
587 }
588 err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
589 "%d", XenbusStateInitialised);
590 if (err) {
591 xenbus_dev_fatal(pdev->xdev, err, "Error switching "
592 "substate of dev-%d\n", i);
593 goto out;
594 }
595 }
596
597 err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
598 if (err) {
599 xenbus_dev_fatal(pdev->xdev, err,
600 "Error while publish PCI root buses "
601 "for frontend");
602 goto out;
603 }
604
605 err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
606 if (err)
607 xenbus_dev_fatal(pdev->xdev, err,
608 "Error switching to initialised state!");
609
610out:
611 spin_unlock(&pdev->dev_lock);
612
613 if (!err)
614 /* see if pcifront is already configured (if not, we'll wait) */
615 pciback_attach(pdev);
616
617 return err;
618}
619
620static void pciback_be_watch(struct xenbus_watch *watch,
621 const char **vec, unsigned int len)
622{
623 struct pciback_device *pdev =
624 container_of(watch, struct pciback_device, be_watch);
625
626 switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
627 case XenbusStateInitWait:
628 pciback_setup_backend(pdev);
629 break;
630
631 default:
632 break;
633 }
634}
635
636static int pciback_xenbus_probe(struct xenbus_device *dev,
637 const struct xenbus_device_id *id)
638{
639 int err = 0;
640 struct pciback_device *pdev = alloc_pdev(dev);
641
642 if (pdev == NULL) {
643 err = -ENOMEM;
644 xenbus_dev_fatal(dev, err,
645 "Error allocating pciback_device struct");
646 goto out;
647 }
648
649 /* wait for xend to configure us */
650 err = xenbus_switch_state(dev, XenbusStateInitWait);
651 if (err)
652 goto out;
653
654 /* watch the backend node for backend configuration information */
655 err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
656 pciback_be_watch);
657 if (err)
658 goto out;
659 pdev->be_watching = 1;
660
661 /* We need to force a call to our callback here in case
662 * xend already configured us!
663 */
664 pciback_be_watch(&pdev->be_watch, NULL, 0);
665
666out:
667 return err;
668}
669
670static int pciback_xenbus_remove(struct xenbus_device *dev)
671{
672 struct pciback_device *pdev = dev_get_drvdata(&dev->dev);
673
674 if (pdev != NULL)
675 free_pdev(pdev);
676
677 return 0;
678}
679
680static const struct xenbus_device_id xenpci_ids[] = {
681 {"pci"},
682 {""},
683};
684
685static struct xenbus_driver xenbus_pciback_driver = {
686 .name = "pciback",
687 .owner = THIS_MODULE,
688 .ids = xenpci_ids,
689 .probe = pciback_xenbus_probe,
690 .remove = pciback_xenbus_remove,
691 .otherend_changed = pciback_frontend_changed,
692};
693
694int __init pciback_xenbus_register(void)
695{
696 pciback_wq = create_workqueue("pciback_workqueue");
697 if (!pciback_wq) {
698 printk(KERN_ERR "pciback_xenbus_register: create"
699 "pciback_workqueue failed\n");
700 return -EFAULT;
701 }
702 return xenbus_register_backend(&xenbus_pciback_driver);
703}
704
705void __exit pciback_xenbus_unregister(void)
706{
707 destroy_workqueue(pciback_wq);
708 xenbus_unregister_driver(&xenbus_pciback_driver);
709}