Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3682a394 authored by Yinghai Lu's avatar Yinghai Lu Committed by Jesse Barnes
Browse files

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 79cc9601
|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: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 8161fe91
Loading
Loading
Loading
Loading
+22 −6
Original line number Original line Diff line number Diff line
@@ -77,6 +77,7 @@ void pci_remove_bus(struct pci_bus *pci_bus)
}
}
EXPORT_SYMBOL(pci_remove_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
 * pci_remove_bus_device - remove a PCI device and any children
 * @dev: the device to remove
 * @dev: the device to remove
@@ -94,7 +95,7 @@ static void __pci_remove_bus_device(struct pci_dev *dev)
	if (dev->subordinate) {
	if (dev->subordinate) {
		struct pci_bus *b = dev->subordinate;
		struct pci_bus *b = dev->subordinate;


		pci_remove_behind_bridge(dev);
		__pci_remove_behind_bridge(dev);
		pci_remove_bus(b);
		pci_remove_bus(b);
		dev->subordinate = NULL;
		dev->subordinate = NULL;
	}
	}
@@ -107,6 +108,24 @@ void pci_remove_bus_device(struct pci_dev *dev)
	__pci_remove_bus_device(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
 * pci_remove_behind_bridge - remove all devices behind a PCI bridge
 * @dev: PCI bridge device
 * @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)
void pci_remove_behind_bridge(struct pci_dev *dev)
{
{
	struct list_head *l, *n;
	pci_stop_behind_bridge(dev);

	__pci_remove_behind_bridge(dev);
	if (dev->subordinate)
		list_for_each_safe(l, n, &dev->subordinate->devices)
			__pci_remove_bus_device(pci_dev_b(l));
}
}


static void pci_stop_bus_devices(struct pci_bus *bus)
static void pci_stop_bus_devices(struct pci_bus *bus)