[PATCH] acpi hotplug: clean up notify handlers on acpiphp unload

A root bridge may not have directly attached hotpluggable slots under it.
Instead, it may have p2p bridges with slots under it. In this case, we need
to clean up the p2p bridges and slots properly too. Patch below applies on
top of the original patch, and fixes this problem. Without this, acpiphp
leaves behind notify handlers on module unload, and subsequent module load
attempts don't work properly too. Patch was tested on an ia64 Tiger4 box.

Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Rajesh Shah and committed by
Greg Kroah-Hartman
364d5094 42f49a6a

+26 -8
+26 -8
drivers/pci/hotplug/acpiphp_glue.c
··· 487 return NULL; 488 } 489 490 - static void remove_bridge(acpi_handle handle) 491 { 492 struct list_head *list, *tmp; 493 - struct acpiphp_bridge *bridge; 494 struct acpiphp_slot *slot; 495 acpi_status status; 496 - 497 - bridge = acpiphp_handle_to_bridge(handle); 498 - if (!bridge) { 499 - err("Could not find bridge for handle %p\n", handle); 500 - return; 501 - } 502 503 status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 504 handle_hotplug_event_bridge); ··· 523 kfree(bridge); 524 } 525 526 527 static int power_on_slot(struct acpiphp_slot *slot) 528 {
··· 487 return NULL; 488 } 489 490 + static void cleanup_bridge(struct acpiphp_bridge *bridge) 491 { 492 struct list_head *list, *tmp; 493 struct acpiphp_slot *slot; 494 acpi_status status; 495 + acpi_handle handle = bridge->handle; 496 497 status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 498 handle_hotplug_event_bridge); ··· 529 kfree(bridge); 530 } 531 532 + static acpi_status 533 + cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) 534 + { 535 + struct acpiphp_bridge *bridge; 536 + 537 + if (!(bridge = acpiphp_handle_to_bridge(handle))) 538 + return AE_OK; 539 + cleanup_bridge(bridge); 540 + return AE_OK; 541 + } 542 + 543 + static void remove_bridge(acpi_handle handle) 544 + { 545 + struct acpiphp_bridge *bridge; 546 + 547 + bridge = acpiphp_handle_to_bridge(handle); 548 + if (bridge) { 549 + cleanup_bridge(bridge); 550 + } else { 551 + /* clean-up p2p bridges under this host bridge */ 552 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 553 + (u32)1, cleanup_p2p_bridge, NULL, NULL); 554 + } 555 + } 556 557 static int power_on_slot(struct acpiphp_slot *slot) 558 {