diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cd929aed3613..7c7a388c85ab 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 | /** |
@@ -709,6 +730,17 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) | |||
709 | return (unsigned int)sta; | 730 | return (unsigned int)sta; |
710 | } | 731 | } |
711 | 732 | ||
733 | static inline bool device_status_valid(unsigned int sta) | ||
734 | { | ||
735 | /* | ||
736 | * ACPI spec says that _STA may return bit 0 clear with bit 3 set | ||
737 | * if the device is valid but does not require a device driver to be | ||
738 | * loaded (Section 6.3.7 of ACPI 5.0A). | ||
739 | */ | ||
740 | unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; | ||
741 | return (sta & mask) == mask; | ||
742 | } | ||
743 | |||
712 | /** | 744 | /** |
713 | * trim_stale_devices - remove PCI devices that are not responding. | 745 | * trim_stale_devices - remove PCI devices that are not responding. |
714 | * @dev: PCI device to start walking the hierarchy from. | 746 | * @dev: PCI device to start walking the hierarchy from. |
@@ -724,7 +756,7 @@ static void trim_stale_devices(struct pci_dev *dev) | |||
724 | unsigned long long sta; | 756 | unsigned long long sta; |
725 | 757 | ||
726 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | 758 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); |
727 | alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) | 759 | alive = (ACPI_SUCCESS(status) && device_status_valid(sta)) |
728 | || acpiphp_no_hotplug(handle); | 760 | || acpiphp_no_hotplug(handle); |
729 | } | 761 | } |
730 | if (!alive) { | 762 | if (!alive) { |
@@ -742,7 +774,7 @@ static void trim_stale_devices(struct pci_dev *dev) | |||
742 | 774 | ||
743 | /* The device is a bridge. so check the bus below it. */ | 775 | /* The device is a bridge. so check the bus below it. */ |
744 | pm_runtime_get_sync(&dev->dev); | 776 | pm_runtime_get_sync(&dev->dev); |
745 | list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) | 777 | list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) |
746 | trim_stale_devices(child); | 778 | trim_stale_devices(child); |
747 | 779 | ||
748 | pm_runtime_put(&dev->dev); | 780 | pm_runtime_put(&dev->dev); |
@@ -771,10 +803,10 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
771 | mutex_lock(&slot->crit_sect); | 803 | mutex_lock(&slot->crit_sect); |
772 | if (slot_no_hotplug(slot)) { | 804 | if (slot_no_hotplug(slot)) { |
773 | ; /* do nothing */ | 805 | ; /* do nothing */ |
774 | } else if (get_slot_status(slot) == ACPI_STA_ALL) { | 806 | } else if (device_status_valid(get_slot_status(slot))) { |
775 | /* remove stale devices if any */ | 807 | /* remove stale devices if any */ |
776 | list_for_each_entry_safe(dev, tmp, &bus->devices, | 808 | list_for_each_entry_safe_reverse(dev, tmp, |
777 | bus_list) | 809 | &bus->devices, bus_list) |
778 | if (PCI_SLOT(dev->devfn) == slot->device) | 810 | if (PCI_SLOT(dev->devfn) == slot->device) |
779 | trim_stale_devices(dev); | 811 | trim_stale_devices(dev); |
780 | 812 | ||
@@ -805,7 +837,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) | |||
805 | int i; | 837 | int i; |
806 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; | 838 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; |
807 | 839 | ||
808 | list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { | 840 | list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) { |
809 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { | 841 | for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { |
810 | struct resource *res = &dev->resource[i]; | 842 | struct resource *res = &dev->resource[i]; |
811 | if ((res->flags & type_mask) && !res->start && | 843 | if ((res->flags & type_mask) && !res->start && |
@@ -829,7 +861,11 @@ void acpiphp_check_host_bridge(acpi_handle handle) | |||
829 | 861 | ||
830 | bridge = acpiphp_handle_to_bridge(handle); | 862 | bridge = acpiphp_handle_to_bridge(handle); |
831 | if (bridge) { | 863 | if (bridge) { |
864 | pci_lock_rescan_remove(); | ||
865 | |||
832 | acpiphp_check_bridge(bridge); | 866 | acpiphp_check_bridge(bridge); |
867 | |||
868 | pci_unlock_rescan_remove(); | ||
833 | put_bridge(bridge); | 869 | put_bridge(bridge); |
834 | } | 870 | } |
835 | } | 871 | } |
@@ -852,6 +888,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
852 | 888 | ||
853 | mutex_unlock(&acpiphp_context_lock); | 889 | mutex_unlock(&acpiphp_context_lock); |
854 | 890 | ||
891 | pci_lock_rescan_remove(); | ||
855 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 892 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
856 | 893 | ||
857 | switch (type) { | 894 | switch (type) { |
@@ -905,6 +942,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
905 | break; | 942 | break; |
906 | } | 943 | } |
907 | 944 | ||
945 | pci_unlock_rescan_remove(); | ||
908 | if (bridge) | 946 | if (bridge) |
909 | put_bridge(bridge); | 947 | put_bridge(bridge); |
910 | } | 948 | } |
@@ -915,11 +953,9 @@ static void hotplug_event_work(void *data, u32 type) | |||
915 | acpi_handle handle = context->handle; | 953 | acpi_handle handle = context->handle; |
916 | 954 | ||
917 | acpi_scan_lock_acquire(); | 955 | acpi_scan_lock_acquire(); |
918 | pci_lock_rescan_remove(); | ||
919 | 956 | ||
920 | hotplug_event(handle, type, context); | 957 | hotplug_event(handle, type, context); |
921 | 958 | ||
922 | pci_unlock_rescan_remove(); | ||
923 | acpi_scan_lock_release(); | 959 | acpi_scan_lock_release(); |
924 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); | 960 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); |
925 | put_bridge(context->func.parent); | 961 | put_bridge(context->func.parent); |
@@ -937,6 +973,7 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | |||
937 | { | 973 | { |
938 | struct acpiphp_context *context; | 974 | struct acpiphp_context *context; |
939 | u32 ost_code = ACPI_OST_SC_SUCCESS; | 975 | u32 ost_code = ACPI_OST_SC_SUCCESS; |
976 | acpi_status status; | ||
940 | 977 | ||
941 | switch (type) { | 978 | switch (type) { |
942 | case ACPI_NOTIFY_BUS_CHECK: | 979 | case ACPI_NOTIFY_BUS_CHECK: |
@@ -972,13 +1009,20 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data) | |||
972 | 1009 | ||
973 | mutex_lock(&acpiphp_context_lock); | 1010 | mutex_lock(&acpiphp_context_lock); |
974 | context = acpiphp_get_context(handle); | 1011 | context = acpiphp_get_context(handle); |
975 | if (context && !WARN_ON(context->handle != handle)) { | 1012 | if (!context || WARN_ON(context->handle != handle) |
976 | get_bridge(context->func.parent); | 1013 | || context->func.parent->is_going_away) |
977 | acpiphp_put_context(context); | 1014 | goto err_out; |
978 | acpi_hotplug_execute(hotplug_event_work, context, type); | 1015 | |
1016 | get_bridge(context->func.parent); | ||
1017 | acpiphp_put_context(context); | ||
1018 | status = acpi_hotplug_execute(hotplug_event_work, context, type); | ||
1019 | if (ACPI_SUCCESS(status)) { | ||
979 | mutex_unlock(&acpiphp_context_lock); | 1020 | mutex_unlock(&acpiphp_context_lock); |
980 | return; | 1021 | return; |
981 | } | 1022 | } |
1023 | put_bridge(context->func.parent); | ||
1024 | |||
1025 | err_out: | ||
982 | mutex_unlock(&acpiphp_context_lock); | 1026 | mutex_unlock(&acpiphp_context_lock); |
983 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; | 1027 | ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; |
984 | 1028 | ||