aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-06-13 19:04:40 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-13 19:04:40 -0400
commita187177ae047e005a7b40229555837a529a9c2cc (patch)
treef5b56902875f1f9e4e9ea9baa0dfc35e22d54b05 /drivers
parent4d17e8516a0b24240cd3f5d024b2ca10cb0b5208 (diff)
parentce29ca3ea40744f24c2b5d88431e8ac566d257cc (diff)
Merge branch 'topic/kong-acpiphp-remove' into next
* topic/kong-acpiphp-remove: PCI: acpiphp: remove all functions in slot, even without ACPI _EJx PCI: acpiphp: fix function 0 leak when disabling a slot
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c43
-rw-r--r--drivers/pci/search.c2
2 files changed, 35 insertions, 10 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 62d0ae4dfcad..73af3374e915 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -878,6 +878,24 @@ static void disable_bridges(struct pci_bus *bus)
878 } 878 }
879} 879}
880 880
881/* return first device in slot, acquiring a reference on it */
882static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
883{
884 struct pci_bus *bus = slot->bridge->pci_bus;
885 struct pci_dev *dev;
886 struct pci_dev *ret = NULL;
887
888 down_read(&pci_bus_sem);
889 list_for_each_entry(dev, &bus->devices, bus_list)
890 if (PCI_SLOT(dev->devfn) == slot->device) {
891 ret = pci_dev_get(dev);
892 break;
893 }
894 up_read(&pci_bus_sem);
895
896 return ret;
897}
898
881/** 899/**
882 * disable_device - disable a slot 900 * disable_device - disable a slot
883 * @slot: ACPI PHP slot 901 * @slot: ACPI PHP slot
@@ -893,6 +911,7 @@ static int disable_device(struct acpiphp_slot *slot)
893 pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); 911 pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
894 if (!pdev) 912 if (!pdev)
895 goto err_exit; 913 goto err_exit;
914 pci_dev_put(pdev);
896 915
897 list_for_each_entry(func, &slot->funcs, sibling) { 916 list_for_each_entry(func, &slot->funcs, sibling) {
898 if (func->bridge) { 917 if (func->bridge) {
@@ -901,18 +920,22 @@ static int disable_device(struct acpiphp_slot *slot)
901 (u32)1, NULL, NULL); 920 (u32)1, NULL, NULL);
902 func->bridge = NULL; 921 func->bridge = NULL;
903 } 922 }
923 }
904 924
905 pdev = pci_get_slot(slot->bridge->pci_bus, 925 /*
906 PCI_DEVFN(slot->device, func->function)); 926 * enable_device() enumerates all functions in this device via
907 if (pdev) { 927 * pci_scan_slot(), whether they have associated ACPI hotplug
908 pci_stop_bus_device(pdev); 928 * methods (_EJ0, etc.) or not. Therefore, we remove all functions
909 if (pdev->subordinate) { 929 * here.
910 disable_bridges(pdev->subordinate); 930 */
911 pci_disable_device(pdev); 931 while ((pdev = dev_in_slot(slot))) {
912 } 932 pci_stop_bus_device(pdev);
913 __pci_remove_bus_device(pdev); 933 if (pdev->subordinate) {
914 pci_dev_put(pdev); 934 disable_bridges(pdev->subordinate);
935 pci_disable_device(pdev);
915 } 936 }
937 __pci_remove_bus_device(pdev);
938 pci_dev_put(pdev);
916 } 939 }
917 940
918 list_for_each_entry(func, &slot->funcs, sibling) { 941 list_for_each_entry(func, &slot->funcs, sibling) {
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 9d75dc8ca602..993d4a0a2469 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -15,6 +15,8 @@
15#include "pci.h" 15#include "pci.h"
16 16
17DECLARE_RWSEM(pci_bus_sem); 17DECLARE_RWSEM(pci_bus_sem);
18EXPORT_SYMBOL_GPL(pci_bus_sem);
19
18/* 20/*
19 * find the upstream PCIe-to-PCI bridge of a PCI device 21 * find the upstream PCIe-to-PCI bridge of a PCI device
20 * if the device is PCIE, return NULL 22 * if the device is PCIE, return NULL