aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
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
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')
-rw-r--r--drivers/acpi/ec.c5
-rw-r--r--drivers/acpi/osl.c80
-rw-r--r--drivers/acpi/thermal.c3
3 files changed, 56 insertions, 32 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 79b09d76c180..1e3222762bf3 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -763,8 +763,7 @@ static u32 acpi_ec_gpe_poll_handler(void *data)
763 763
764 acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR); 764 acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
765 765
766 status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, 766 status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
767 acpi_ec_gpe_query, ec);
768 767
769 if (status == AE_OK) 768 if (status == AE_OK)
770 return ACPI_INTERRUPT_HANDLED; 769 return ACPI_INTERRUPT_HANDLED;
@@ -799,7 +798,7 @@ static u32 acpi_ec_gpe_intr_handler(void *data)
799 798
800 if (value & ACPI_EC_FLAG_SCI) { 799 if (value & ACPI_EC_FLAG_SCI) {
801 atomic_add(1, &ec->intr.pending_gpe); 800 atomic_add(1, &ec->intr.pending_gpe);
802 status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, 801 status = acpi_os_execute(OSL_EC_BURST_HANDLER,
803 acpi_ec_gpe_query, ec); 802 acpi_ec_gpe_query, ec);
804 return status == AE_OK ? 803 return status == AE_OK ?
805 ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; 804 ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
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{
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19f3ea48475e..fba9c230a84d 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -684,8 +684,7 @@ static void acpi_thermal_run(unsigned long data)
684{ 684{
685 struct acpi_thermal *tz = (struct acpi_thermal *)data; 685 struct acpi_thermal *tz = (struct acpi_thermal *)data;
686 if (!tz->zombie) 686 if (!tz->zombie)
687 acpi_os_queue_for_execution(OSD_PRIORITY_GPE, 687 acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
688 acpi_thermal_check, (void *)data);
689} 688}
690 689
691static void acpi_thermal_check(void *data) 690static void acpi_thermal_check(void *data)