diff options
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e86439283a5d..ee26bac2d378 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -432,6 +432,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
432 | pr_err("failed to remove notify handler\n"); | 432 | pr_err("failed to remove notify handler\n"); |
433 | } | 433 | } |
434 | } | 434 | } |
435 | slot->flags |= SLOT_IS_GOING_AWAY; | ||
435 | if (slot->slot) | 436 | if (slot->slot) |
436 | acpiphp_unregister_hotplug_slot(slot); | 437 | acpiphp_unregister_hotplug_slot(slot); |
437 | } | 438 | } |
@@ -439,6 +440,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) | |||
439 | mutex_lock(&bridge_mutex); | 440 | mutex_lock(&bridge_mutex); |
440 | list_del(&bridge->list); | 441 | list_del(&bridge->list); |
441 | mutex_unlock(&bridge_mutex); | 442 | mutex_unlock(&bridge_mutex); |
443 | |||
444 | bridge->is_going_away = true; | ||
442 | } | 445 | } |
443 | 446 | ||
444 | /** | 447 | /** |
@@ -757,6 +760,10 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
757 | { | 760 | { |
758 | struct acpiphp_slot *slot; | 761 | struct acpiphp_slot *slot; |
759 | 762 | ||
763 | /* Bail out if the bridge is going away. */ | ||
764 | if (bridge->is_going_away) | ||
765 | return; | ||
766 | |||
760 | list_for_each_entry(slot, &bridge->slots, node) { | 767 | list_for_each_entry(slot, &bridge->slots, node) { |
761 | struct pci_bus *bus = slot->bus; | 768 | struct pci_bus *bus = slot->bus; |
762 | struct pci_dev *dev, *tmp; | 769 | struct pci_dev *dev, *tmp; |
@@ -827,6 +834,8 @@ void acpiphp_check_host_bridge(acpi_handle handle) | |||
827 | } | 834 | } |
828 | } | 835 | } |
829 | 836 | ||
837 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); | ||
838 | |||
830 | static void hotplug_event(acpi_handle handle, u32 type, void *data) | 839 | static void hotplug_event(acpi_handle handle, u32 type, void *data) |
831 | { | 840 | { |
832 | struct acpiphp_context *context = data; | 841 | struct acpiphp_context *context = data; |
@@ -856,6 +865,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
856 | } else { | 865 | } else { |
857 | struct acpiphp_slot *slot = func->slot; | 866 | struct acpiphp_slot *slot = func->slot; |
858 | 867 | ||
868 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
869 | break; | ||
870 | |||
859 | mutex_lock(&slot->crit_sect); | 871 | mutex_lock(&slot->crit_sect); |
860 | enable_slot(slot); | 872 | enable_slot(slot); |
861 | mutex_unlock(&slot->crit_sect); | 873 | mutex_unlock(&slot->crit_sect); |
@@ -871,6 +883,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data) | |||
871 | struct acpiphp_slot *slot = func->slot; | 883 | struct acpiphp_slot *slot = func->slot; |
872 | int ret; | 884 | int ret; |
873 | 885 | ||
886 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
887 | break; | ||
888 | |||
874 | /* | 889 | /* |
875 | * Check if anything has changed in the slot and rescan | 890 | * Check if anything has changed in the slot and rescan |
876 | * from the parent if that's the case. | 891 | * from the parent if that's the case. |
@@ -900,9 +915,11 @@ static void hotplug_event_work(void *data, u32 type) | |||
900 | acpi_handle handle = context->handle; | 915 | acpi_handle handle = context->handle; |
901 | 916 | ||
902 | acpi_scan_lock_acquire(); | 917 | acpi_scan_lock_acquire(); |
918 | pci_lock_rescan_remove(); | ||
903 | 919 | ||
904 | hotplug_event(handle, type, context); | 920 | hotplug_event(handle, type, context); |
905 | 921 | ||
922 | pci_unlock_rescan_remove(); | ||
906 | acpi_scan_lock_release(); | 923 | acpi_scan_lock_release(); |
907 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); | 924 | acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); |
908 | put_bridge(context->func.parent); | 925 | put_bridge(context->func.parent); |
@@ -1070,12 +1087,19 @@ void acpiphp_remove_slots(struct pci_bus *bus) | |||
1070 | */ | 1087 | */ |
1071 | int acpiphp_enable_slot(struct acpiphp_slot *slot) | 1088 | int acpiphp_enable_slot(struct acpiphp_slot *slot) |
1072 | { | 1089 | { |
1090 | pci_lock_rescan_remove(); | ||
1091 | |||
1092 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
1093 | return -ENODEV; | ||
1094 | |||
1073 | mutex_lock(&slot->crit_sect); | 1095 | mutex_lock(&slot->crit_sect); |
1074 | /* configure all functions */ | 1096 | /* configure all functions */ |
1075 | if (!(slot->flags & SLOT_ENABLED)) | 1097 | if (!(slot->flags & SLOT_ENABLED)) |
1076 | enable_slot(slot); | 1098 | enable_slot(slot); |
1077 | 1099 | ||
1078 | mutex_unlock(&slot->crit_sect); | 1100 | mutex_unlock(&slot->crit_sect); |
1101 | |||
1102 | pci_unlock_rescan_remove(); | ||
1079 | return 0; | 1103 | return 0; |
1080 | } | 1104 | } |
1081 | 1105 | ||
@@ -1083,10 +1107,12 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) | |||
1083 | * acpiphp_disable_and_eject_slot - power off and eject slot | 1107 | * acpiphp_disable_and_eject_slot - power off and eject slot |
1084 | * @slot: ACPI PHP slot | 1108 | * @slot: ACPI PHP slot |
1085 | */ | 1109 | */ |
1086 | int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) | 1110 | static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) |
1087 | { | 1111 | { |
1088 | struct acpiphp_func *func; | 1112 | struct acpiphp_func *func; |
1089 | int retval = 0; | 1113 | |
1114 | if (slot->flags & SLOT_IS_GOING_AWAY) | ||
1115 | return -ENODEV; | ||
1090 | 1116 | ||
1091 | mutex_lock(&slot->crit_sect); | 1117 | mutex_lock(&slot->crit_sect); |
1092 | 1118 | ||
@@ -1104,9 +1130,18 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) | |||
1104 | } | 1130 | } |
1105 | 1131 | ||
1106 | mutex_unlock(&slot->crit_sect); | 1132 | mutex_unlock(&slot->crit_sect); |
1107 | return retval; | 1133 | return 0; |
1108 | } | 1134 | } |
1109 | 1135 | ||
1136 | int acpiphp_disable_slot(struct acpiphp_slot *slot) | ||
1137 | { | ||
1138 | int ret; | ||
1139 | |||
1140 | pci_lock_rescan_remove(); | ||
1141 | ret = acpiphp_disable_and_eject_slot(slot); | ||
1142 | pci_unlock_rescan_remove(); | ||
1143 | return ret; | ||
1144 | } | ||
1110 | 1145 | ||
1111 | /* | 1146 | /* |
1112 | * slot enabled: 1 | 1147 | * slot enabled: 1 |
@@ -1117,7 +1152,6 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) | |||
1117 | return (slot->flags & SLOT_ENABLED); | 1152 | return (slot->flags & SLOT_ENABLED); |
1118 | } | 1153 | } |
1119 | 1154 | ||
1120 | |||
1121 | /* | 1155 | /* |
1122 | * latch open: 1 | 1156 | * latch open: 1 |
1123 | * latch closed: 0 | 1157 | * latch closed: 0 |
@@ -1127,7 +1161,6 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot) | |||
1127 | return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); | 1161 | return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); |
1128 | } | 1162 | } |
1129 | 1163 | ||
1130 | |||
1131 | /* | 1164 | /* |
1132 | * adapter presence : 1 | 1165 | * adapter presence : 1 |
1133 | * absence : 0 | 1166 | * absence : 0 |