aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2012-02-05 01:55:00 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-02-10 15:19:31 -0500
commit3682a3946d2b0bad621db871e3bead83e523a238 (patch)
tree22fa013f268abeb35863ac7be2016912c4977762 /drivers
parent8161fe91d8da34c1a231b6e2d4454b4b3179a5d4 (diff)
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 <linux@dominikbrodowski.net> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/remove.c28
1 files changed, 22 insertions, 6 deletions
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)
77} 77}
78EXPORT_SYMBOL(pci_remove_bus); 78EXPORT_SYMBOL(pci_remove_bus);
79 79
80static void __pci_remove_behind_bridge(struct pci_dev *dev);
80/** 81/**
81 * pci_remove_bus_device - remove a PCI device and any children 82 * pci_remove_bus_device - remove a PCI device and any children
82 * @dev: the device to remove 83 * @dev: the device to remove
@@ -94,7 +95,7 @@ static void __pci_remove_bus_device(struct pci_dev *dev)
94 if (dev->subordinate) { 95 if (dev->subordinate) {
95 struct pci_bus *b = dev->subordinate; 96 struct pci_bus *b = dev->subordinate;
96 97
97 pci_remove_behind_bridge(dev); 98 __pci_remove_behind_bridge(dev);
98 pci_remove_bus(b); 99 pci_remove_bus(b);
99 dev->subordinate = NULL; 100 dev->subordinate = NULL;
100 } 101 }
@@ -107,6 +108,24 @@ void pci_remove_bus_device(struct pci_dev *dev)
107 __pci_remove_bus_device(dev); 108 __pci_remove_bus_device(dev);
108} 109}
109 110
111static void __pci_remove_behind_bridge(struct pci_dev *dev)
112{
113 struct list_head *l, *n;
114
115 if (dev->subordinate)
116 list_for_each_safe(l, n, &dev->subordinate->devices)
117 __pci_remove_bus_device(pci_dev_b(l));
118}
119
120static void pci_stop_behind_bridge(struct pci_dev *dev)
121{
122 struct list_head *l, *n;
123
124 if (dev->subordinate)
125 list_for_each_safe(l, n, &dev->subordinate->devices)
126 pci_stop_bus_device(pci_dev_b(l));
127}
128
110/** 129/**
111 * pci_remove_behind_bridge - remove all devices behind a PCI bridge 130 * pci_remove_behind_bridge - remove all devices behind a PCI bridge
112 * @dev: PCI bridge device 131 * @dev: PCI bridge device
@@ -117,11 +136,8 @@ void pci_remove_bus_device(struct pci_dev *dev)
117 */ 136 */
118void pci_remove_behind_bridge(struct pci_dev *dev) 137void pci_remove_behind_bridge(struct pci_dev *dev)
119{ 138{
120 struct list_head *l, *n; 139 pci_stop_behind_bridge(dev);
121 140 __pci_remove_behind_bridge(dev);
122 if (dev->subordinate)
123 list_for_each_safe(l, n, &dev->subordinate->devices)
124 __pci_remove_bus_device(pci_dev_b(l));
125} 141}
126 142
127static void pci_stop_bus_devices(struct pci_bus *bus) 143static void pci_stop_bus_devices(struct pci_bus *bus)