diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cd929aed3613..e2a783fdb98f 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -210,10 +210,29 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) | |||
210 | } | 210 | } |
211 | } | 211 | } |
212 | 212 | ||
213 | static void dock_event(acpi_handle handle, u32 type, void *data) | ||
214 | { | ||
215 | struct acpiphp_context *context; | ||
216 | |||
217 | mutex_lock(&acpiphp_context_lock); | ||
218 | context = acpiphp_get_context(handle); | ||
219 | if (!context || WARN_ON(context->handle != handle) | ||
220 | || context->func.parent->is_going_away) { | ||
221 | mutex_unlock(&acpiphp_context_lock); | ||
222 | return; | ||
223 | } | ||
224 | get_bridge(context->func.parent); | ||
225 | acpiphp_put_context(context); | ||
226 | mutex_unlock(&acpiphp_context_lock); | ||
227 | |||
228 | hotplug_event(handle, type, data); | ||
229 | |||
230 | put_bridge(context->func.parent); | ||
231 | } | ||
213 | 232 | ||
214 | static const struct acpi_dock_ops acpiphp_dock_ops = { | 233 | static const struct acpi_dock_ops acpiphp_dock_ops = { |
215 | .fixup = post_dock_fixups, | 234 | .fixup = post_dock_fixups, |
216 | .handler = hotplug_event, | 235 | .handler = dock_event, |
217 | }; | 236 | }; |
218 | 237 | ||
219 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ | 238 | /* Check whether the PCI device is managed by native PCIe hotplug driver */ |
@@ -441,7 +460,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
441 | list_del(&bridge->list); | 460 | list_del(&bridge->list); |
442 | mutex_unlock(&bridge_mutex); | 461 | mutex_unlock(&bridge_mutex); |
443 | 462 | ||
463 | mutex_lock(&acpiphp_context_lock); | ||
444 | bridge->is_going_away = true; | 464 | bridge->is_going_away = true; |
465 | mutex_unlock(&acpiphp_context_lock); | ||
445 | } | 466 | } |
446 | 467 | ||
447 | /** | 468 | /** |
@@ -742,7 +763,7 @@ static void trim_stale_devices(struct pci_dev *dev) | |||
742 | 763 | ||
743 | /* The device is a bridge. so check the bus below it. */ | 764 | /* The device is a bridge. so check the bus below it. */ |
744 | pm_runtime_get_sync(&dev->dev); | 765 | pm_runtime_get_sync(&dev->dev); |
745 | list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) | 766 | list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) |
746 | trim_stale_devices(child); | 767 | trim_stale_devices(child); |
747 | 768 | ||
748 | pm_runtime_put(&dev->dev); | 769 | pm_runtime_put(&dev->dev); |
@@ -773,8 +794,8 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
773 | ; /* do nothing */ | 794 | ; /* do nothing */ |
774 | } else if (get_slot_status(slot) == ACPI_STA_ALL) { | 795 | } else if (get_slot_status(slot) == ACPI_STA_ALL) { |
775 | /* remove stale devices if any */ | 796 | /* remove stale devices if any */ |
776 | list_for_each_entry_safe(dev, tmp, &bus->devices, | 797 | list_for_each_entry_safe_reverse(dev, tmp, |
777 | bus_list) | 798 | &bus->devices, bus_list) |
778 | if (PCI_SLOT(dev->devfn) == slot->device) | 799 | if (PCI_SLOT(dev->devfn) == slot->device) |
779 | trim_stale_devices(dev); | 800 | trim_stale_devices(dev); |
780 | 801 | ||
@@ -805,7 +826,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) | |||
805 | int i; | 826 | int i; |
806 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 827 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; |
807 | 828 | ||
808 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | 829 | list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { |
809 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { | 830 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { |
810 | struct resource *res = &dev->resource[i]; | 831 | struct resource *res = &dev->resource[i]; |
811 | if ((res->flags & type_mask) && !res->start && | 832 | if ((res->flags & type_mask) && !res->start && |
@@ -829,7 +850,11 @@ void acpiphp_check_host_bridge(acpi_handle handle) | |||
829 | 850 | ||
830 | bridge = acpiphp_handle_to_bridge(handle); | 851 | bridge = acpiphp_handle_to_bridge(handle); |
831 | if (bridge) { | 852 | if (bridge) { |
853 | pci_lock_rescan_remove(); | ||
854 | |||
832 | acpiphp_check_bridge(bridge); | 855 | acpiphp_check_bridge(bridge); |
856 | |||
857 | pci_unlock_rescan_remove(); | ||
833 | put_bridge(bridge); | 858 | put_bridge(bridge); |
834 | } | 859 | } |
835 | } | 860 | } |
@@ -852,6 +877,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
852 | 877 | ||
853 | mutex_unlock(&acpiphp_context_lock); | 878 | mutex_unlock(&acpiphp_context_lock); |
854 | 879 | ||
880 | pci_lock_rescan_remove(); | ||
855 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 881 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
856 | 882 | ||
857 | switch (type) { | 883 | switch (type) { |
@@ -905,6 +931,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
905 | break; | 931 | break; |
906 | } | 932 | } |
907 | 933 | ||
934 | pci_unlock_rescan_remove(); | ||
908 | if (bridge) | 935 | if (bridge) |
909 | put_bridge(bridge); | 936 | put_bridge(bridge); |
910 | } | 937 | } |
@@ -915,11 +942,9 @@ static void hotplug_event_work(void *data, u32 type) | |||
915 | acpi_handle handle = context->handle; | 942 | acpi_handle handle = context->handle; |
916 | 943 | ||
917 | acpi_scan_lock_acquire(); | 944 | acpi_scan_lock_acquire(); |
918 | pci_lock_rescan_remove(); | ||
919 | 945 | ||
920 | hotplug_event(handle, type, context); | 946 | hotplug_event(handle, type, context); |
921 | 947 | ||
922 | pci_unlock_rescan_remove(); | ||
923 | acpi_scan_lock_release(); | 948 | acpi_scan_lock_release(); |
924 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); | 949 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); |
925 | put_bridge(context->func.parent); | 950 | put_bridge(context->func.parent); |
@@ -937,6 +962,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | |||
937 | { | 962 | { |
938 | struct acpiphp_context *context; | 963 | struct acpiphp_context *context; |
939 | u32 ost_code = ACPI_OST_SC_SUCCESS; | 964 | u32 ost_code = ACPI_OST_SC_SUCCESS; |
965 | acpi_status status; | ||
940 | 966 | ||
941 | switch (type) { | 967 | switch (type) { |
942 | case ACPI_NOTIFY_BUS_CHECK: | 968 | case ACPI_NOTIFY_BUS_CHECK: |
@@ -972,13 +998,20 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | |||
972 | 998 | ||
973 | mutex_lock(&acpiphp_context_lock); | 999 | mutex_lock(&acpiphp_context_lock); |
974 | context = acpiphp_get_context(handle); | 1000 | context = acpiphp_get_context(handle); |
975 | if (context && !WARN_ON(context->handle != handle)) { | 1001 | if (!context || WARN_ON(context->handle != handle) |
976 | get_bridge(context->func.parent); | 1002 | || context->func.parent->is_going_away) |
977 | acpiphp_put_context(context); | 1003 | goto err_out; |
978 | acpi_hotplug_execute(hotplug_event_work, context, type); | 1004 | |
1005 | get_bridge(context->func.parent); | ||
1006 | acpiphp_put_context(context); | ||
1007 | status = acpi_hotplug_execute(hotplug_event_work, context, type); | ||
1008 | if (ACPI_SUCCESS(status)) { | ||
979 | mutex_unlock(&acpiphp_context_lock); | 1009 | mutex_unlock(&acpiphp_context_lock); |
980 | return; | 1010 | return; |
981 | } | 1011 | } |
1012 | put_bridge(context->func.parent); | ||
1013 | |||
1014 | err_out: | ||
982 | mutex_unlock(&acpiphp_context_lock); | 1015 | mutex_unlock(&acpiphp_context_lock); |
983 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 1016 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
984 | 1017 | ||