ACPI: created a dedicated workqueue for notify() execution From: Alexey Starikovskiy Needed to handle while loop in GPE handler of HP notebooks. http://bugzilla.kernel.org/show_bug.cgi?id=5534 Yield processor before execution of deferred event queue. Needed to avoid flooding of Compaq n620c with events. --- drivers/acpi/osl.c | 51 +++++++++++++++++++++++++++++++++++---------------- 1 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 068fe4f..169ca04 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -34,6 +34,7 @@ #include #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static struct workqueue_struct *kacpi_notify_wq; acpi_status acpi_os_initialize(void) { @@ -91,8 +93,9 @@ acpi_status acpi_os_initialize1(void) return AE_NULL_ENTRY; } kacpid_wq = create_singlethread_workqueue("kacpid"); + kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify"); BUG_ON(!kacpid_wq); - + BUG_ON(!kacpi_notify_wq); return AE_OK; } @@ -104,6 +107,7 @@ acpi_status acpi_os_terminate(void) } destroy_workqueue(kacpid_wq); + destroy_workqueue(kacpi_notify_wq); return AE_OK; } @@ -566,10 +570,23 @@ void acpi_os_derive_pci_id(acpi_handle r static void acpi_os_execute_deferred(void *context) { - struct acpi_os_dpc *dpc = NULL; + struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context; + if (!dpc) { + printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); + return; + } + + sys_sched_yield(); + dpc->function(dpc->context); + + kfree(dpc); + return; +} - dpc = (struct acpi_os_dpc *)context; +static void acpi_os_execute_notify(void *context) +{ + struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context; if (!dpc) { printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); return; @@ -604,14 +621,12 @@ acpi_status acpi_os_execute(acpi_execute struct acpi_os_dpc *dpc; struct work_struct *task; - ACPI_FUNCTION_TRACE("os_queue_for_execution"); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context)); if (!function) - return_ACPI_STATUS(AE_BAD_PARAMETER); + return AE_BAD_PARAMETER; /* * Allocate/initialize DPC structure. Note that this memory will be @@ -624,9 +639,8 @@ acpi_status acpi_os_execute(acpi_execute * from the same memory. */ - dpc = - kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct), - GFP_ATOMIC); + dpc = kzalloc(sizeof(struct acpi_os_dpc) + + sizeof(struct work_struct), GFP_ATOMIC); if (!dpc) return_ACPI_STATUS(AE_NO_MEMORY); @@ -634,13 +648,18 @@ acpi_status acpi_os_execute(acpi_execute dpc->context = context; task = (void *)(dpc + 1); - INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); - - if (!queue_work(kacpid_wq, task)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Call to queue_work() failed.\n")); - kfree(dpc); - status = AE_ERROR; + if (type == OSL_NOTIFY_HANDLER) { + INIT_WORK(task, acpi_os_execute_notify, (void *)dpc); + if (!queue_work(kacpi_notify_wq, task)) { + status = AE_ERROR; + kfree(dpc); + } + } else { + INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); + if (!queue_work(kacpid_wq, task)) { + status = AE_ERROR; + kfree(dpc); + } } return_ACPI_STATUS(status);