]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
powerpc/eeh: Release EEH device state synchronously
authorSam Bobroff <sbobroff@linux.ibm.com>
Tue, 28 Apr 2020 03:45:06 +0000 (13:45 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 18 May 2020 11:58:44 +0000 (21:58 +1000)
EEH device state is currently removed (by eeh_remove_device()) during
the device release handler, which is invoked as the device's reference
count drops to zero. This may take some time, or forever, as other
threads may hold references.

However, the PCI device state is released synchronously by
pci_stop_and_remove_bus_device(). This mismatch causes problems, for
example the device may be re-discovered as a new device before the
release handler has been called, leaving the PCI and EEH state
mismatched.

So instead, call eeh_remove_device() from the bus device removal
handlers, which are called synchronously in the removal path.

Signed-off-by: Sam Bobroff <sbobroff@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/0a1f5105d3a33b1c090bba31de63eb0cdd25de7b.1588045502.git.sbobroff@linux.ibm.com
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/pci-hotplug.c

index 7cdcb413bb44d898288a4023bc637a7073e3f572..d407981dec76b09f6956cb10bf010a7b1f364094 100644 (file)
@@ -1106,6 +1106,37 @@ static int eeh_init(void)
 
 core_initcall_sync(eeh_init);
 
+static int eeh_device_notifier(struct notifier_block *nb,
+                              unsigned long action, void *data)
+{
+       struct device *dev = data;
+
+       switch (action) {
+       /*
+        * Note: It's not possible to perform EEH device addition (i.e.
+        * {pseries,pnv}_pcibios_bus_add_device()) here because it depends on
+        * the device's resources, which have not yet been set up.
+        */
+       case BUS_NOTIFY_DEL_DEVICE:
+               eeh_remove_device(to_pci_dev(dev));
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block eeh_device_nb = {
+       .notifier_call = eeh_device_notifier,
+};
+
+static __init int eeh_set_bus_notifier(void)
+{
+       bus_register_notifier(&pci_bus_type, &eeh_device_nb);
+       return 0;
+}
+arch_initcall(eeh_set_bus_notifier);
+
 /**
  * eeh_probe_device() - Perform EEH initialization for the indicated pci device
  * @dev: pci device for which to set up EEH
index bf83f76563a33812ce407b822f3cd51290085c58..2fc12198ec071ca20973143d4df310ef48ca08b5 100644 (file)
@@ -57,8 +57,6 @@ void pcibios_release_device(struct pci_dev *dev)
        struct pci_controller *phb = pci_bus_to_host(dev->bus);
        struct pci_dn *pdn = pci_get_pdn(dev);
 
-       eeh_remove_device(dev);
-
        if (phb->controller_ops.release_device)
                phb->controller_ops.release_device(dev);