aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-03 18:37:02 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-05 11:40:24 -0500
commit1c0c5443de5f1f03ae2abce569fb673377f0fd0e (patch)
tree62222070f5db7109408148498eea7f34e8d64be1
parentaf9d8adc6b832003bbe3d83fde665ae6b4f072eb (diff)
ACPI / hotplug / PCI: Simplify disable_slot()
After recent PCI core changes related to the rescan/remove locking, the ACPIPHP's disable_slot() function is only called under the general PCI rescan/remove lock, so it doesn't have to use dev_in_slot() any more to avoid race conditions. Make it simply walk the devices on the bus and drop the ones in the slot being disabled and drop dev_in_slot() which has no more users. Moreover, to avoid problems described in the changelog of commit 29ed1f29b68a (PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device), make disable_slot() carry out the list walk in reverse order. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c28
1 files changed, 5 insertions, 23 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index e2a783fdb98f..f24c19c8f8c4 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -625,32 +625,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
625 } 625 }
626} 626}
627 627
628/* return first device in slot, acquiring a reference on it */
629static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
630{
631 struct pci_bus *bus = slot->bus;
632 struct pci_dev *dev;
633 struct pci_dev *ret = NULL;
634
635 down_read(&pci_bus_sem);
636 list_for_each_entry(dev, &bus->devices, bus_list)
637 if (PCI_SLOT(dev->devfn) == slot->device) {
638 ret = pci_dev_get(dev);
639 break;
640 }
641 up_read(&pci_bus_sem);
642
643 return ret;
644}
645
646/** 628/**
647 * disable_slot - disable a slot 629 * disable_slot - disable a slot
648 * @slot: ACPI PHP slot 630 * @slot: ACPI PHP slot
649 */ 631 */
650static void disable_slot(struct acpiphp_slot *slot) 632static void disable_slot(struct acpiphp_slot *slot)
651{ 633{
634 struct pci_bus *bus = slot->bus;
635 struct pci_dev *dev, *prev;
652 struct acpiphp_func *func; 636 struct acpiphp_func *func;
653 struct pci_dev *pdev;
654 637
655 /* 638 /*
656 * enable_slot() enumerates all functions in this device via 639 * enable_slot() enumerates all functions in this device via
@@ -658,10 +641,9 @@ static void disable_slot(struct acpiphp_slot *slot)
658 * methods (_EJ0, etc.) or not. Therefore, we remove all functions 641 * methods (_EJ0, etc.) or not. Therefore, we remove all functions
659 * here. 642 * here.
660 */ 643 */
661 while ((pdev = dev_in_slot(slot))) { 644 list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list)
662 pci_stop_and_remove_bus_device(pdev); 645 if (PCI_SLOT(dev->devfn) == slot->device)
663 pci_dev_put(pdev); 646 pci_stop_and_remove_bus_device(dev);
664 }
665 647
666 list_for_each_entry(func, &slot->funcs, sibling) 648 list_for_each_entry(func, &slot->funcs, sibling)
667 acpiphp_bus_trim(func_to_handle(func)); 649 acpiphp_bus_trim(func_to_handle(func));