]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
xen/pcifront: Walk the PCI bus after XenStore notification
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Thu, 30 Nov 2017 15:31:58 +0000 (10:31 -0500)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Mon, 4 Dec 2017 18:51:07 +0000 (13:51 -0500)
Prior to this patch we would only update the 'struct pci_dev'
if a PCI hotplug (new device) event would happen.

This works fine if the device is part of the guest config, that is:

pci=["0a:11.1"]

or such.

Unfortunatly if you are doing PCI hotplug:

xm pci-attach vnuma 0a:11.1

There are two events we need to stamp the 'struct pci_dev'
with the PXM node information:
 - ACPI hotplug to inject the PCI device.
 - XenBus entries being created

And those are created in the wrong order - first is the
ACPI hotplug event, followed by the XenBus update.

That means 'pcifront_hvm_notifier' gets called when
the ACPI hotplug even has started, but XenBus hasn't been
yet created so the scan from there returns NULL.

Later on we get an XenBus notification (pcifront_hvm_xenbus_probe),
update our internal list, and then the PCI notifier would find it.

The one way to make this work is to listen to an
extra event: BUS_NOTIFY_BOUND_DRIVER

That is signaled once the driver has loaded itself and is
ready. When the 'pcifront_hvm_notifier' gets that information
it can walk over the PCI bus and stamp all the 'struct pci_dev'
with the updated PXM data. In other words the operations
are now:

 - ACPI hotplug to inject the PCI device.
 - udev is called, modprobe <XYZ> is invoked
 - XenBus entries being created
 - <XYZ> driver is finished
 - pcifront_hvm_notifier is called, figures out which
   'struct pci_dev' needs its PXM update and updates.

OraBug: 27200813

Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
drivers/pci/xen-pcifront.c

index accc00d9815de46b1882d005f58d9d3c28d87104..10bc3e26eb02b9984a93e0feb6e5ac2c38b1961e 100644 (file)
@@ -1207,7 +1207,7 @@ static int pcifront_hvm_notifier(struct notifier_block *nb,
        struct device *dev = data;
        struct pci_dev *pci_dev = to_pci_dev(dev);
 
-       if (action == BUS_NOTIFY_ADD_DEVICE) {
+       if (action == BUS_NOTIFY_BOUND_DRIVER) {
                mutex_lock(&pcifront_devs_mutex);
                pcifront_hvm_set_node(pci_dev, NULL);
                mutex_unlock(&pcifront_devs_mutex);
@@ -1344,6 +1344,8 @@ static int pcifront_hvm_add(struct xenbus_device *xdev)
        return err;
 }
 
+static void walk_pcifront_hvm(void);
+
 static int pcifront_hvm_xenbus_probe(struct xenbus_device *xdev,
                                     const struct xenbus_device_id *id)
 {
@@ -1351,8 +1353,11 @@ static int pcifront_hvm_xenbus_probe(struct xenbus_device *xdev,
 
        mutex_lock(&pcifront_devs_mutex);
        err = pcifront_hvm_add(xdev);
-       mutex_unlock(&pcifront_devs_mutex);
 
+       if (!err)
+               walk_pcifront_hvm();
+
+       mutex_unlock(&pcifront_devs_mutex);
        return err;
 }
 
@@ -1401,13 +1406,11 @@ static struct xenbus_driver xenpci_driver_hvm = {
        .otherend_changed       = pcifront_hvm_backend_changed,
 };
 
-static void __init walk_pcifront_hvm(void)
+static void walk_pcifront_hvm(void)
 {
        if (!xen_hvm_domain())
                return;
 
-       mutex_lock(&pcifront_devs_mutex);
-
        /*
         * PCI devices may have been added during guest init, which means
         * the pcifront_hvm_notifier would have gotten called - but the
@@ -1422,7 +1425,6 @@ static void __init walk_pcifront_hvm(void)
                list_for_each_entry(root_bus, &pci_root_buses, node)
                        pci_walk_bus(root_bus, pcifront_hvm_set_node, NULL);
        }
-       mutex_unlock(&pcifront_devs_mutex);
 };
 
 static struct xenbus_driver *pcifront_driver = &xenpci_driver;
@@ -1450,7 +1452,6 @@ static int __init pcifront_init(void)
                        bus_unregister_notifier(&pci_bus_type, notifier);
                return rc;
        }
-       walk_pcifront_hvm();
 
        return 0;
 }