diff options
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 8580e53355ec..cc3cbb4435f8 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
@@ -1518,6 +1518,53 @@ parse_error: | |||
1518 | fs_initcall(pcistub_init); | 1518 | fs_initcall(pcistub_init); |
1519 | #endif | 1519 | #endif |
1520 | 1520 | ||
1521 | #ifdef CONFIG_PCI_IOV | ||
1522 | static struct pcistub_device *find_vfs(const struct pci_dev *pdev) | ||
1523 | { | ||
1524 | struct pcistub_device *psdev = NULL; | ||
1525 | unsigned long flags; | ||
1526 | bool found = false; | ||
1527 | |||
1528 | spin_lock_irqsave(&pcistub_devices_lock, flags); | ||
1529 | list_for_each_entry(psdev, &pcistub_devices, dev_list) { | ||
1530 | if (!psdev->pdev && psdev->dev != pdev | ||
1531 | && pci_physfn(psdev->dev) == pdev) { | ||
1532 | found = true; | ||
1533 | break; | ||
1534 | } | ||
1535 | } | ||
1536 | spin_unlock_irqrestore(&pcistub_devices_lock, flags); | ||
1537 | if (found) | ||
1538 | return psdev; | ||
1539 | return NULL; | ||
1540 | } | ||
1541 | |||
1542 | static int pci_stub_notifier(struct notifier_block *nb, | ||
1543 | unsigned long action, void *data) | ||
1544 | { | ||
1545 | struct device *dev = data; | ||
1546 | const struct pci_dev *pdev = to_pci_dev(dev); | ||
1547 | |||
1548 | if (action != BUS_NOTIFY_UNBIND_DRIVER) | ||
1549 | return NOTIFY_DONE; | ||
1550 | |||
1551 | if (!pdev->is_physfn) | ||
1552 | return NOTIFY_DONE; | ||
1553 | |||
1554 | for (;;) { | ||
1555 | struct pcistub_device *psdev = find_vfs(pdev); | ||
1556 | if (!psdev) | ||
1557 | break; | ||
1558 | device_release_driver(&psdev->dev->dev); | ||
1559 | } | ||
1560 | return NOTIFY_DONE; | ||
1561 | } | ||
1562 | |||
1563 | static struct notifier_block pci_stub_nb = { | ||
1564 | .notifier_call = pci_stub_notifier, | ||
1565 | }; | ||
1566 | #endif | ||
1567 | |||
1521 | static int __init xen_pcibk_init(void) | 1568 | static int __init xen_pcibk_init(void) |
1522 | { | 1569 | { |
1523 | int err; | 1570 | int err; |
@@ -1539,12 +1586,19 @@ static int __init xen_pcibk_init(void) | |||
1539 | err = xen_pcibk_xenbus_register(); | 1586 | err = xen_pcibk_xenbus_register(); |
1540 | if (err) | 1587 | if (err) |
1541 | pcistub_exit(); | 1588 | pcistub_exit(); |
1589 | #ifdef CONFIG_PCI_IOV | ||
1590 | else | ||
1591 | bus_register_notifier(&pci_bus_type, &pci_stub_nb); | ||
1592 | #endif | ||
1542 | 1593 | ||
1543 | return err; | 1594 | return err; |
1544 | } | 1595 | } |
1545 | 1596 | ||
1546 | static void __exit xen_pcibk_cleanup(void) | 1597 | static void __exit xen_pcibk_cleanup(void) |
1547 | { | 1598 | { |
1599 | #ifdef CONFIG_PCI_IOV | ||
1600 | bus_unregister_notifier(&pci_bus_type, &pci_stub_nb); | ||
1601 | #endif | ||
1548 | xen_pcibk_xenbus_unregister(); | 1602 | xen_pcibk_xenbus_unregister(); |
1549 | pcistub_exit(); | 1603 | pcistub_exit(); |
1550 | } | 1604 | } |