summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/bus.c2
-rw-r--r--drivers/pci/pci.h11
-rw-r--r--drivers/pci/remove.c19
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)