commit dda902e86efbaff32c431e8eddf0f49657af1f73 Author: Matthew Garrett Date: Tue Aug 18 17:12:22 2009 +0100 acpiphp integration diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index e68d5f2..3cc46eb 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -125,6 +125,7 @@ struct acpiphp_slot { * typically 8 objects per slot (i.e. for each PCI function) */ struct acpiphp_func { + struct list_head list; struct acpiphp_slot *slot; /* parent */ struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 0cb0f83..9552649 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -52,15 +52,14 @@ #include "acpiphp.h" static LIST_HEAD(bridge_list); +static LIST_HEAD(func_list); static LIST_HEAD(ioapic_list); static DEFINE_SPINLOCK(ioapic_list_lock); #define MY_NAME "acpiphp_glue" -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus); -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context); /* callback routine to check for the existence of a pci dock device */ static acpi_status @@ -112,7 +111,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, static struct acpi_dock_ops acpiphp_dock_ops = { - .handler = handle_hotplug_event_func, + .handler = acpiphp_handle_hotplug_event_func, }; /* callback routine to register each ACPI PCI slot object */ @@ -240,14 +239,16 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!(newfunc->flags & FUNC_HAS_DCK)) { status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); + acpiphp_handle_hotplug_event_func, + NULL); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) err("failed to register interrupt notify handler\n"); } else status = AE_OK; + list_add(&newfunc->list, &func_list); + return status; err_exit: @@ -322,16 +323,16 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { status = acpi_remove_notify_handler(bridge->func->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); + acpiphp_handle_hotplug_event_func); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); + acpiphp_handle_hotplug_event_bridge, + NULL); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) { err("failed to register interrupt notify handler\n"); } } @@ -563,6 +564,20 @@ static int add_bridge(acpi_handle handle) return 0; } +static struct acpiphp_func *acpiphp_handle_to_func(acpi_handle handle) +{ + struct list_head *head; + list_for_each(head, &func_list) { + struct acpiphp_func *func = list_entry(head, + struct acpiphp_func, + list); + if (func->handle == handle) + return func; + } + + return NULL; +} + static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) { struct list_head *head; @@ -584,7 +599,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) acpi_handle handle = bridge->handle; status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); + acpiphp_handle_hotplug_event_bridge); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); @@ -592,8 +607,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { status = acpi_install_notify_handler(bridge->func->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - bridge->func); + acpiphp_handle_hotplug_event_func, + NULL); if (ACPI_FAILURE(status)) err("failed to install interrupt notify handler\n"); } @@ -611,10 +626,11 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) if (!(func->flags & FUNC_HAS_DCK)) { status = acpi_remove_notify_handler(func->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); + acpiphp_handle_hotplug_event_func); if (ACPI_FAILURE(status)) err("failed to remove notify handler\n"); } + list_del(&func->list); list_del(list); kfree(func); } @@ -673,7 +689,7 @@ static void remove_bridge(acpi_handle handle) cleanup_bridge(bridge); else acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); + acpiphp_handle_hotplug_event_bridge); } static struct pci_dev * get_apic_pci_info(acpi_handle handle) @@ -1471,14 +1487,15 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) } /** - * handle_hotplug_event_bridge - handle ACPI event on bridges + * acpiphp_handle_hotplug_event_bridge - handle ACPI event on bridges * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_bridge structure * * Handles ACPI event notification on {host,p2p} bridges. */ -static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) +void acpiphp_handle_hotplug_event_bridge(acpi_handle handle, u32 type, + void *context) { struct acpiphp_bridge *bridge; char objname[64]; @@ -1565,14 +1582,16 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont } /** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * acpiphp_handle_hotplug_event_func - handle ACPI event on functions + * (i.e. slots) * @handle: Notify()'ed acpi_handle * @type: Notify code * @context: pointer to acpiphp_func structure * * Handles ACPI event notification on slots. */ -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) +void acpiphp_handle_hotplug_event_func(acpi_handle handle, u32 type, + void *context) { struct acpiphp_func *func; char objname[64]; @@ -1581,7 +1600,10 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - func = (struct acpiphp_func *)context; + func = acpiphp_handle_to_func(handle); + + if (!func) + return; switch (type) { case ACPI_NOTIFY_BUS_CHECK: @@ -1622,7 +1644,7 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) if (acpi_is_root_bridge(handle)) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, NULL); + acpiphp_handle_hotplug_event_bridge, NULL); (*count)++; } return AE_OK ; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 09d1a9a..905deee 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -170,6 +170,8 @@ static void pci_device_notify(acpi_handle handle, u32 event, void *data) if (event == ACPI_NOTIFY_DEVICE_WAKE) pm_runtime_resume(dev); + else + acpiphp_handle_hotplug_event_func(handle, event, NULL); } static void pci_root_bridge_notify(acpi_handle handle, u32 event, void *data) @@ -179,6 +181,8 @@ static void pci_root_bridge_notify(acpi_handle handle, u32 event, void *data) if (event == ACPI_NOTIFY_DEVICE_WAKE) pci_bus_pme_event(pci_dev); + else + acpiphp_handle_hotplug_event_bridge(handle, event, NULL); } /* ACPI bus type */ diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 93a7c08..ac32403 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -33,4 +33,18 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { return NULL; } #endif +#ifdef CONFIG_HOTPLUG_PCI_ACPI +void acpiphp_handle_hotplug_event_func(acpi_handle handle, u32 type, + void* context); +void acpiphp_handle_hotplug_event_bridge(acpi_handle handle, u32 type, + void* context); +#else +static inline void acpiphp_handle_hotplug_event_func(acpi_handle handle, + u32 type, void* context) +{ } +static inline void acpiphp_handle_hotplug_event_bridge(acpi_handle handle, + u32 type, void* context) +{ } +#endif + #endif /* _PCI_ACPI_H_ */