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 | |
| 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>
| -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) |
