diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-02-05 01:55:00 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-10 15:19:31 -0500 |
commit | 3682a3946d2b0bad621db871e3bead83e523a238 (patch) | |
tree | 22fa013f268abeb35863ac7be2016912c4977762 /drivers/pci | |
parent | 8161fe91d8da34c1a231b6e2d4454b4b3179a5d4 (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/pci')
-rw-r--r-- | drivers/pci/remove.c | 28 |
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 | } |
78 | EXPORT_SYMBOL(pci_remove_bus); | 78 | EXPORT_SYMBOL(pci_remove_bus); |
79 | 79 | ||
80 | static 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 | ||
111 | static 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 | |||
120 | static 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 | */ |
118 | void pci_remove_behind_bridge(struct pci_dev *dev) | 137 | void 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 | ||
127 | static void pci_stop_bus_devices(struct pci_bus *bus) | 143 | static void pci_stop_bus_devices(struct pci_bus *bus) |