aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <alexey.y.starikovskiy@intel.com>2006-05-05 03:23:00 -0400
committerLen Brown <len.brown@intel.com>2006-06-14 02:43:23 -0400
commitb8d35192c55fb055792ff0641408eaaec7c88988 (patch)
tree87272903bda56a4ddedcc513d35a74f072ab1f5d /drivers/acpi/osl.c
parent958dd242b691f64ab4632b4903dbb1e16fee8269 (diff)
ACPI: execute Notify() handlers on new thread
http://bugzilla.kernel.org/show_bug.cgi?id=5534 Thanks to Peter Wainwright for isolating the issue. Thanks to Andi Kleen and Bob Moore for feedback. Thanks to Richard Mace and others for testing. Updates by Konstantin Karasyov. Signed-off-by: Konstantin Karasyov <konstantin.a.karasyov@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 109c3f8ae7df..e80ca4730a44 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -37,6 +37,7 @@
37#include <linux/delay.h> 37#include <linux/delay.h>
38#include <linux/workqueue.h> 38#include <linux/workqueue.h>
39#include <linux/nmi.h> 39#include <linux/nmi.h>
40#include <linux/kthread.h>
40#include <acpi/acpi.h> 41#include <acpi/acpi.h>
41#include <asm/io.h> 42#include <asm/io.h>
42#include <acpi/acpi_bus.h> 43#include <acpi/acpi_bus.h>
@@ -600,23 +601,41 @@ static void acpi_os_execute_deferred(void *context)
600 return_VOID; 601 return_VOID;
601} 602}
602 603
603acpi_status 604static int acpi_os_execute_thread(void *context)
604acpi_os_queue_for_execution(u32 priority, 605{
606 struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
607 if (dpc) {
608 dpc->function(dpc->context);
609 kfree(dpc);
610 }
611 do_exit(0);
612}
613
614/*******************************************************************************
615 *
616 * FUNCTION: acpi_os_execute
617 *
618 * PARAMETERS: Type - Type of the callback
619 * Function - Function to be executed
620 * Context - Function parameters
621 *
622 * RETURN: Status
623 *
624 * DESCRIPTION: Depending on type, either queues function for deferred execution or
625 * immediately executes function on a separate thread.
626 *
627 ******************************************************************************/
628
629acpi_status acpi_os_execute(acpi_execute_type type,
605 acpi_osd_exec_callback function, void *context) 630 acpi_osd_exec_callback function, void *context)
606{ 631{
607 acpi_status status = AE_OK; 632 acpi_status status = AE_OK;
608 struct acpi_os_dpc *dpc; 633 struct acpi_os_dpc *dpc;
609 struct work_struct *task; 634 struct work_struct *task;
610 635 struct task_struct *p;
611 ACPI_FUNCTION_TRACE("os_queue_for_execution");
612
613 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
614 "Scheduling function [%p(%p)] for deferred execution.\n",
615 function, context));
616 636
617 if (!function) 637 if (!function)
618 return_ACPI_STATUS(AE_BAD_PARAMETER); 638 return AE_BAD_PARAMETER;
619
620 /* 639 /*
621 * Allocate/initialize DPC structure. Note that this memory will be 640 * Allocate/initialize DPC structure. Note that this memory will be
622 * freed by the callee. The kernel handles the tq_struct list in a 641 * freed by the callee. The kernel handles the tq_struct list in a
@@ -627,30 +646,37 @@ acpi_os_queue_for_execution(u32 priority,
627 * We can save time and code by allocating the DPC and tq_structs 646 * We can save time and code by allocating the DPC and tq_structs
628 * from the same memory. 647 * from the same memory.
629 */ 648 */
630 649 if (type == OSL_NOTIFY_HANDLER) {
631 dpc = 650 dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_KERNEL);
632 kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct), 651 } else {
633 GFP_ATOMIC); 652 dpc = kmalloc(sizeof(struct acpi_os_dpc) +
653 sizeof(struct work_struct), GFP_ATOMIC);
654 }
634 if (!dpc) 655 if (!dpc)
635 return_ACPI_STATUS(AE_NO_MEMORY); 656 return AE_NO_MEMORY;
636
637 dpc->function = function; 657 dpc->function = function;
638 dpc->context = context; 658 dpc->context = context;
639 659
640 task = (void *)(dpc + 1); 660 if (type == OSL_NOTIFY_HANDLER) {
641 INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc); 661 p = kthread_create(acpi_os_execute_thread, dpc, "kacpid_notify");
642 662 if (!IS_ERR(p)) {
643 if (!queue_work(kacpid_wq, task)) { 663 wake_up_process(p);
644 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 664 } else {
645 "Call to queue_work() failed.\n")); 665 status = AE_NO_MEMORY;
646 kfree(dpc); 666 kfree(dpc);
647 status = AE_ERROR; 667 }
668 } else {
669 task = (void *)(dpc + 1);
670 INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
671 if (!queue_work(kacpid_wq, task)) {
672 status = AE_ERROR;
673 kfree(dpc);
674 }
648 } 675 }
649 676 return status;
650 return_ACPI_STATUS(status);
651} 677}
652 678
653EXPORT_SYMBOL(acpi_os_queue_for_execution); 679EXPORT_SYMBOL(acpi_os_execute);
654 680
655void acpi_os_wait_events_complete(void *context) 681void acpi_os_wait_events_complete(void *context)
656{ 682{