Commit 1c0c5443 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

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
29ed1f29 (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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
parent af9d8adc
Loading
Loading
Loading
Loading
+5 −23
Original line number Diff line number Diff line
@@ -625,32 +625,15 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
	}
}

/* return first device in slot, acquiring a reference on it */
static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
{
	struct pci_bus *bus = slot->bus;
	struct pci_dev *dev;
	struct pci_dev *ret = NULL;

	down_read(&pci_bus_sem);
	list_for_each_entry(dev, &bus->devices, bus_list)
		if (PCI_SLOT(dev->devfn) == slot->device) {
			ret = pci_dev_get(dev);
			break;
		}
	up_read(&pci_bus_sem);

	return ret;
}

/**
 * disable_slot - disable a slot
 * @slot: ACPI PHP slot
 */
static void disable_slot(struct acpiphp_slot *slot)
{
	struct pci_bus *bus = slot->bus;
	struct pci_dev *dev, *prev;
	struct acpiphp_func *func;
	struct pci_dev *pdev;

	/*
	 * enable_slot() enumerates all functions in this device via
@@ -658,10 +641,9 @@ static void disable_slot(struct acpiphp_slot *slot)
	 * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
	 * here.
	 */
	while ((pdev = dev_in_slot(slot))) {
		pci_stop_and_remove_bus_device(pdev);
		pci_dev_put(pdev);
	}
	list_for_each_entry_safe_reverse(dev, prev, &bus->devices, bus_list)
		if (PCI_SLOT(dev->devfn) == slot->device)
			pci_stop_and_remove_bus_device(dev);

	list_for_each_entry(func, &slot->funcs, sibling)
		acpiphp_bus_trim(func_to_handle(func));