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>
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);
return err;
}
+static void walk_pcifront_hvm(void);
+
static int pcifront_hvm_xenbus_probe(struct xenbus_device *xdev,
const struct xenbus_device_id *id)
{
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;
}
.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
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;
bus_unregister_notifier(&pci_bus_type, notifier);
return rc;
}
- walk_pcifront_hvm();
return 0;
}