ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks
[firefly-linux-kernel-4.4.55.git] / drivers / pci / hotplug / acpiphp_glue.c
index 1971d2943de455cf1594e5827a8062635b63a91f..9d6e535e74a14c1dc860144d74882d20248c7d12 100644 (file)
@@ -528,6 +528,16 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
        }
 }
 
+static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
+{
+       struct acpiphp_func *func;
+
+       list_for_each_entry(func, &slot->funcs, sibling)
+               acpiphp_bus_add(func_to_handle(func));
+
+       return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
+}
+
 /**
  * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
@@ -544,10 +554,7 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
        LIST_HEAD(add_list);
        int nr_found;
 
-       list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_add(func_to_handle(func));
-
-       nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
+       nr_found = acpiphp_rescan_slot(slot);
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
                list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -840,11 +847,22 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
                dbg("%s: Device check notify on %s\n", __func__, objname);
-               if (bridge)
+               if (bridge) {
                        acpiphp_check_bridge(bridge);
-               else
-                       acpiphp_check_bridge(func->parent);
+               } else {
+                       struct acpiphp_slot *slot = func->slot;
+                       int ret;
 
+                       /*
+                        * Check if anything has changed in the slot and rescan
+                        * from the parent if that's the case.
+                        */
+                       mutex_lock(&slot->crit_sect);
+                       ret = acpiphp_rescan_slot(slot);
+                       mutex_unlock(&slot->crit_sect);
+                       if (ret)
+                               acpiphp_check_bridge(func->parent);
+               }
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST: