diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-03 18:37:02 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-02-05 11:40:24 -0500 |
commit | 1c0c5443de5f1f03ae2abce569fb673377f0fd0e (patch) | |
tree | 62222070f5db7109408148498eea7f34e8d64be1 | |
parent | af9d8adc6b832003bbe3d83fde665ae6b4f072eb (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.c | 28 |
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 */ | ||
629 | static 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 | */ |
650 | static void disable_slot(struct acpiphp_slot *slot) | 632 | static 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)); |