aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2009-03-30 12:50:14 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-04-06 14:30:26 -0400
commit5d4a4b25ddc3e864d3a562c024bebdc922118854 (patch)
tree9f0c9cdf4c14487517be83e82596a83616d905af /drivers/pci
parentc2ac7cdc6707a8a3fc5cdaebb65cb724ba8ecdef (diff)
PCI Hotplug: acpiphp: grab refcount on p2p subordinate bus
If a logical hot unplug (remove) is performed on a bridge claimed by acpiphp and then acpiphp is unloaded, we will encounter an oops. This is because acpiphp will access the bridge's subordinate bus, which was released by the user's prior hot unplug. The solution is to grab a reference on the subordinate PCI bus. This will prevent the bus from release until acpiphp is unloaded. Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Tested-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Reported-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 803d9ddd6e75..a33794d9e0dc 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -38,6 +38,8 @@
38 * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() 38 * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
39 * when the bridge is scanned and it loses a refcount when the bridge 39 * when the bridge is scanned and it loses a refcount when the bridge
40 * is removed. 40 * is removed.
41 * - When a P2P bridge is present, we elevate the refcount on the subordinate
42 * bus. It loses the refcount when the the driver unloads.
41 */ 43 */
42 44
43#include <linux/init.h> 45#include <linux/init.h>
@@ -440,6 +442,12 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
440 goto err; 442 goto err;
441 } 443 }
442 444
445 /*
446 * Grab a ref to the subordinate PCI bus in case the bus is
447 * removed via PCI core logical hotplug. The ref pins the bus
448 * (which we access during module unload).
449 */
450 get_device(&bridge->pci_bus->dev);
443 spin_lock_init(&bridge->res_lock); 451 spin_lock_init(&bridge->res_lock);
444 452
445 init_bridge_misc(bridge); 453 init_bridge_misc(bridge);
@@ -619,6 +627,12 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
619 slot = next; 627 slot = next;
620 } 628 }
621 629
630 /*
631 * Only P2P bridges have a pci_dev
632 */
633 if (bridge->pci_dev)
634 put_device(&bridge->pci_bus->dev);
635
622 pci_dev_put(bridge->pci_dev); 636 pci_dev_put(bridge->pci_dev);
623 list_del(&bridge->list); 637 list_del(&bridge->list);
624 kfree(bridge); 638 kfree(bridge);