diff options
-rw-r--r-- | drivers/pci/bus.c | 2 | ||||
-rw-r--r-- | drivers/pci/pci.h | 11 | ||||
-rw-r--r-- | drivers/pci/remove.c | 19 |
3 files changed, 19 insertions, 13 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 55c853686051..e41dfece0d96 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -348,7 +348,7 @@ void pci_bus_add_device(struct pci_dev *dev) if (retval < 0 && retval != -EPROBE_DEFER) pci_warn(dev, "device attach failed (%d)\n", retval); - pci_dev_assign_added(dev, true); + pci_dev_assign_added(dev); if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) { retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL, diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 14d00ce45bfa..0d9169e0e7d2 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -470,9 +470,16 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 -static inline void pci_dev_assign_added(struct pci_dev *dev, bool added) +static inline void pci_dev_assign_added(struct pci_dev *dev) { - assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added); + smp_mb__before_atomic(); + set_bit(PCI_DEV_ADDED, &dev->priv_flags); + smp_mb__after_atomic(); +} + +static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev) +{ + return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags); } static inline bool pci_dev_is_added(const struct pci_dev *dev) diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index e4ce1145aa3e..78863f241a88 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -33,16 +33,15 @@ static void pci_stop_dev(struct pci_dev *dev) { pci_pme_active(dev, false); - if (pci_dev_is_added(dev)) { - device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), - pci_pwrctl_unregister); - device_release_driver(&dev->dev); - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - of_pci_remove_node(dev); - - pci_dev_assign_added(dev, false); - } + if (!pci_dev_test_and_clear_added(dev)) + return; + + device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), + pci_pwrctl_unregister); + device_release_driver(&dev->dev); + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + of_pci_remove_node(dev); } static void pci_destroy_dev(struct pci_dev *dev) |