diff options
author | Prarit Bhargava <prarit@redhat.com> | 2011-09-28 19:40:53 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-10-14 12:05:31 -0400 |
commit | 6af8bef14d6fc9e4e52c83fd646412e9dedadd26 (patch) | |
tree | a1ddb0962fe8d5704cff9f3627322eb2fe0fa479 /drivers/pci | |
parent | 379021d5c0899fcf9410cae4ca7a59a5a94ca769 (diff) |
PCI hotplug: acpiphp: Prevent deadlock on PCI-to-PCI bridge remove
I originally submitted a patch to workaround this by pushing all Ejection
Requests and Device Checks onto the kacpi_hotplug queue.
http://marc.info/?l=linux-acpi&m=131678270930105&w=2
The patch is still insufficient in that Bus Checks also need to be added.
Rather than add all events, including non-PCI-hotplug events, to the
hotplug queue, mjg suggested that a better approach would be to modify
the acpiphp driver so only acpiphp events would be added to the
kacpi_hotplug queue.
It's a longer patch, but at least we maintain the benefit of having separate
queues in ACPI. This, of course, is still only a workaround the problem.
As Bjorn and mjg pointed out, we have to refactor a lot of this code to do
the right thing but at this point it is a better to have this code working.
The acpi core places all events on the kacpi_notify queue. When the acpiphp
driver is loaded and a PCI card with a PCI-to-PCI bridge is removed the
following call sequence occurs:
cleanup_p2p_bridge()
-> cleanup_bridge()
-> acpi_remove_notify_handler()
-> acpi_os_wait_events_complete()
-> flush_workqueue(kacpi_notify_wq)
which is the queue we are currently executing on and the process will hang.
Move all hotplug acpiphp events onto the kacpi_hotplug workqueue. In
handle_hotplug_event_bridge() and handle_hotplug_event_func() we can simply
push the rest of the work onto the kacpi_hotplug queue and then avoid the
deadlock.
Signed-off-by: Prarit Bhargava <prarit@redhat.com>
Cc: mjg@redhat.com
Cc: bhelgaas@google.com
Cc: linux-acpi@vger.kernel.org
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 109 |
1 files changed, 94 insertions, 15 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 220285760b68..596172b4ae95 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/pci-acpi.h> | 48 | #include <linux/pci-acpi.h> |
49 | #include <linux/mutex.h> | 49 | #include <linux/mutex.h> |
50 | #include <linux/slab.h> | 50 | #include <linux/slab.h> |
51 | #include <linux/acpi.h> | ||
51 | 52 | ||
52 | #include "../pci.h" | 53 | #include "../pci.h" |
53 | #include "acpiphp.h" | 54 | #include "acpiphp.h" |
@@ -1149,15 +1150,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
1149 | return AE_OK ; | 1150 | return AE_OK ; |
1150 | } | 1151 | } |
1151 | 1152 | ||
1152 | /** | 1153 | struct acpiphp_hp_work { |
1153 | * handle_hotplug_event_bridge - handle ACPI event on bridges | 1154 | struct work_struct work; |
1154 | * @handle: Notify()'ed acpi_handle | 1155 | acpi_handle handle; |
1155 | * @type: Notify code | 1156 | u32 type; |
1156 | * @context: pointer to acpiphp_bridge structure | 1157 | void *context; |
1157 | * | 1158 | }; |
1158 | * Handles ACPI event notification on {host,p2p} bridges. | 1159 | |
1159 | */ | 1160 | static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type, |
1160 | static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) | 1161 | void *context, |
1162 | void (*func)(struct work_struct *work)) | ||
1163 | { | ||
1164 | struct acpiphp_hp_work *hp_work; | ||
1165 | int ret; | ||
1166 | |||
1167 | hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL); | ||
1168 | if (!hp_work) | ||
1169 | return; | ||
1170 | |||
1171 | hp_work->handle = handle; | ||
1172 | hp_work->type = type; | ||
1173 | hp_work->context = context; | ||
1174 | |||
1175 | INIT_WORK(&hp_work->work, func); | ||
1176 | ret = queue_work(kacpi_hotplug_wq, &hp_work->work); | ||
1177 | if (!ret) | ||
1178 | kfree(hp_work); | ||
1179 | } | ||
1180 | |||
1181 | static void _handle_hotplug_event_bridge(struct work_struct *work) | ||
1161 | { | 1182 | { |
1162 | struct acpiphp_bridge *bridge; | 1183 | struct acpiphp_bridge *bridge; |
1163 | char objname[64]; | 1184 | char objname[64]; |
@@ -1165,11 +1186,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1165 | .pointer = objname }; | 1186 | .pointer = objname }; |
1166 | struct acpi_device *device; | 1187 | struct acpi_device *device; |
1167 | int num_sub_bridges = 0; | 1188 | int num_sub_bridges = 0; |
1189 | struct acpiphp_hp_work *hp_work; | ||
1190 | acpi_handle handle; | ||
1191 | u32 type; | ||
1192 | |||
1193 | hp_work = container_of(work, struct acpiphp_hp_work, work); | ||
1194 | handle = hp_work->handle; | ||
1195 | type = hp_work->type; | ||
1168 | 1196 | ||
1169 | if (acpi_bus_get_device(handle, &device)) { | 1197 | if (acpi_bus_get_device(handle, &device)) { |
1170 | /* This bridge must have just been physically inserted */ | 1198 | /* This bridge must have just been physically inserted */ |
1171 | handle_bridge_insertion(handle, type); | 1199 | handle_bridge_insertion(handle, type); |
1172 | return; | 1200 | goto out; |
1173 | } | 1201 | } |
1174 | 1202 | ||
1175 | bridge = acpiphp_handle_to_bridge(handle); | 1203 | bridge = acpiphp_handle_to_bridge(handle); |
@@ -1180,7 +1208,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1180 | 1208 | ||
1181 | if (!bridge && !num_sub_bridges) { | 1209 | if (!bridge && !num_sub_bridges) { |
1182 | err("cannot get bridge info\n"); | 1210 | err("cannot get bridge info\n"); |
1183 | return; | 1211 | goto out; |
1184 | } | 1212 | } |
1185 | 1213 | ||
1186 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 1214 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
@@ -1241,22 +1269,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont | |||
1241 | warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); | 1269 | warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); |
1242 | break; | 1270 | break; |
1243 | } | 1271 | } |
1272 | |||
1273 | out: | ||
1274 | kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ | ||
1244 | } | 1275 | } |
1245 | 1276 | ||
1246 | /** | 1277 | /** |
1247 | * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) | 1278 | * handle_hotplug_event_bridge - handle ACPI event on bridges |
1248 | * @handle: Notify()'ed acpi_handle | 1279 | * @handle: Notify()'ed acpi_handle |
1249 | * @type: Notify code | 1280 | * @type: Notify code |
1250 | * @context: pointer to acpiphp_func structure | 1281 | * @context: pointer to acpiphp_bridge structure |
1251 | * | 1282 | * |
1252 | * Handles ACPI event notification on slots. | 1283 | * Handles ACPI event notification on {host,p2p} bridges. |
1253 | */ | 1284 | */ |
1254 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) | 1285 | static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, |
1286 | void *context) | ||
1287 | { | ||
1288 | /* | ||
1289 | * Currently the code adds all hotplug events to the kacpid_wq | ||
1290 | * queue when it should add hotplug events to the kacpi_hotplug_wq. | ||
1291 | * The proper way to fix this is to reorganize the code so that | ||
1292 | * drivers (dock, etc.) do not call acpi_os_execute(), etc. | ||
1293 | * For now just re-add this work to the kacpi_hotplug_wq so we | ||
1294 | * don't deadlock on hotplug actions. | ||
1295 | */ | ||
1296 | alloc_acpiphp_hp_work(handle, type, context, | ||
1297 | _handle_hotplug_event_bridge); | ||
1298 | } | ||
1299 | |||
1300 | static void _handle_hotplug_event_func(struct work_struct *work) | ||
1255 | { | 1301 | { |
1256 | struct acpiphp_func *func; | 1302 | struct acpiphp_func *func; |
1257 | char objname[64]; | 1303 | char objname[64]; |
1258 | struct acpi_buffer buffer = { .length = sizeof(objname), | 1304 | struct acpi_buffer buffer = { .length = sizeof(objname), |
1259 | .pointer = objname }; | 1305 | .pointer = objname }; |
1306 | struct acpiphp_hp_work *hp_work; | ||
1307 | acpi_handle handle; | ||
1308 | u32 type; | ||
1309 | void *context; | ||
1310 | |||
1311 | hp_work = container_of(work, struct acpiphp_hp_work, work); | ||
1312 | handle = hp_work->handle; | ||
1313 | type = hp_work->type; | ||
1314 | context = hp_work->context; | ||
1260 | 1315 | ||
1261 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 1316 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
1262 | 1317 | ||
@@ -1291,8 +1346,32 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex | |||
1291 | warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); | 1346 | warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); |
1292 | break; | 1347 | break; |
1293 | } | 1348 | } |
1349 | |||
1350 | kfree(hp_work); /* allocated in handle_hotplug_event_func */ | ||
1294 | } | 1351 | } |
1295 | 1352 | ||
1353 | /** | ||
1354 | * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) | ||
1355 | * @handle: Notify()'ed acpi_handle | ||
1356 | * @type: Notify code | ||
1357 | * @context: pointer to acpiphp_func structure | ||
1358 | * | ||
1359 | * Handles ACPI event notification on slots. | ||
1360 | */ | ||
1361 | static void handle_hotplug_event_func(acpi_handle handle, u32 type, | ||
1362 | void *context) | ||
1363 | { | ||
1364 | /* | ||
1365 | * Currently the code adds all hotplug events to the kacpid_wq | ||
1366 | * queue when it should add hotplug events to the kacpi_hotplug_wq. | ||
1367 | * The proper way to fix this is to reorganize the code so that | ||
1368 | * drivers (dock, etc.) do not call acpi_os_execute(), etc. | ||
1369 | * For now just re-add this work to the kacpi_hotplug_wq so we | ||
1370 | * don't deadlock on hotplug actions. | ||
1371 | */ | ||
1372 | alloc_acpiphp_hp_work(handle, type, context, | ||
1373 | _handle_hotplug_event_func); | ||
1374 | } | ||
1296 | 1375 | ||
1297 | static acpi_status | 1376 | static acpi_status |
1298 | find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) | 1377 | find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) |