From 79cc9601c3e42b4f0650fe7e69132ebce7ab48f9 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Tue, 22 Nov 2011 21:06:53 -0800 Subject: PCI: Only call pci_stop_bus_device() one time for child devices at remove During debugging pcie hotplug with SRIOV with pcie switch, I found pci_stop_bus_device() is called several times for some child devices. So change original pci_remove_bus_device() to __pci_remove_bus_device(), and make it only do remove work, and add a new pci_remove_bus_device that calls pci_stop_bus_device() one time, and then call __pci_remove_bus_device(). Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/remove.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/pci/remove.c') diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 7f87beed35ac..6def3624c688 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -89,9 +89,8 @@ EXPORT_SYMBOL(pci_remove_bus); * device lists, remove the /proc entry, and notify userspace * (/sbin/hotplug). */ -void pci_remove_bus_device(struct pci_dev *dev) +static void __pci_remove_bus_device(struct pci_dev *dev) { - pci_stop_bus_device(dev); if (dev->subordinate) { struct pci_bus *b = dev->subordinate; @@ -102,6 +101,11 @@ void pci_remove_bus_device(struct pci_dev *dev) pci_destroy_dev(dev); } +void pci_remove_bus_device(struct pci_dev *dev) +{ + pci_stop_bus_device(dev); + __pci_remove_bus_device(dev); +} /** * pci_remove_behind_bridge - remove all devices behind a PCI bridge @@ -117,7 +121,7 @@ void pci_remove_behind_bridge(struct pci_dev *dev) if (dev->subordinate) list_for_each_safe(l, n, &dev->subordinate->devices) - pci_remove_bus_device(pci_dev_b(l)); + __pci_remove_bus_device(pci_dev_b(l)); } static void pci_stop_bus_devices(struct pci_bus *bus) -- cgit v1.2.3 From 3682a3946d2b0bad621db871e3bead83e523a238 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 4 Feb 2012 22:55:00 -0800 Subject: PCI: Fix pci cardbus removal During test busn_res allocation with cardbus, found pci card removal is not working anymore, and it turns out it is broken by: |commit 79cc9601c3e42b4f0650fe7e69132ebce7ab48f9 |Date: Tue Nov 22 21:06:53 2011 -0800 | | PCI: Only call pci_stop_bus_device() one time for child devices at remove The above changed the behavior of pci_remove_behind_bridge that yenta_cardbus depended on. So restore the old behavoir of pci_remove_behind_bridge (which requires stopping and removing of all devices) by: 1. rename pci_remove_behind_bridge to __pci_remove_behind_bridge, and let __pci_remove_bus_device() call it instead. 2. add pci_stop_behind_bridge that will stop devices behind a bridge 3. add back pci_remove_behind_bridge that will stop and remove devices under bridge. -v2: update commit description a little bit. Tested-by: Dominik Brodowski Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes --- drivers/pci/remove.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers/pci/remove.c') diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 6def3624c688..ef8b18c48f26 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -77,6 +77,7 @@ void pci_remove_bus(struct pci_bus *pci_bus) } EXPORT_SYMBOL(pci_remove_bus); +static void __pci_remove_behind_bridge(struct pci_dev *dev); /** * pci_remove_bus_device - remove a PCI device and any children * @dev: the device to remove @@ -94,7 +95,7 @@ static void __pci_remove_bus_device(struct pci_dev *dev) if (dev->subordinate) { struct pci_bus *b = dev->subordinate; - pci_remove_behind_bridge(dev); + __pci_remove_behind_bridge(dev); pci_remove_bus(b); dev->subordinate = NULL; } @@ -107,6 +108,24 @@ void pci_remove_bus_device(struct pci_dev *dev) __pci_remove_bus_device(dev); } +static void __pci_remove_behind_bridge(struct pci_dev *dev) +{ + struct list_head *l, *n; + + if (dev->subordinate) + list_for_each_safe(l, n, &dev->subordinate->devices) + __pci_remove_bus_device(pci_dev_b(l)); +} + +static void pci_stop_behind_bridge(struct pci_dev *dev) +{ + struct list_head *l, *n; + + if (dev->subordinate) + list_for_each_safe(l, n, &dev->subordinate->devices) + pci_stop_bus_device(pci_dev_b(l)); +} + /** * pci_remove_behind_bridge - remove all devices behind a PCI bridge * @dev: PCI bridge device @@ -117,11 +136,8 @@ void pci_remove_bus_device(struct pci_dev *dev) */ void pci_remove_behind_bridge(struct pci_dev *dev) { - struct list_head *l, *n; - - if (dev->subordinate) - list_for_each_safe(l, n, &dev->subordinate->devices) - __pci_remove_bus_device(pci_dev_b(l)); + pci_stop_behind_bridge(dev); + __pci_remove_behind_bridge(dev); } static void pci_stop_bus_devices(struct pci_bus *bus) -- cgit v1.2.3