diff options
author | iwasaki <iwasaki@FreeBSD.org> | 2001-12-22 16:05:41 +0000 |
---|---|---|
committer | iwasaki <iwasaki@FreeBSD.org> | 2001-12-22 16:05:41 +0000 |
commit | 4c7abcd3372368396a11a120c259afdb0fe2b015 (patch) | |
tree | 7c96c678372cc5f9e23154023196e80b72311f86 /sys/dev/acpica/Osd | |
parent | 23a35cbf8dc1e76d3a4e856806e0ee472c65e5af (diff) | |
download | FreeBSD-src-4c7abcd3372368396a11a120c259afdb0fe2b015.zip FreeBSD-src-4c7abcd3372368396a11a120c259afdb0fe2b015.tar.gz |
Add OS layer ACPI mutex and threading support.
- Temporary fix a bug of Intel ACPI CA core code.
- Add OS layer ACPI mutex support. This can be disabled by
specifying option ACPI_NO_SEMAPHORES.
- Add ACPI threading support. Now that we have a dedicate taskqueue for
ACPI tasks and more ACPI task threads can be created by specifying option
ACPI_MAX_THREADS.
- Change acpi_EvaluateIntoBuffer() behavior slightly to reuse given
caller's buffer unless AE_BUFFER_OVERFLOW occurs. Also CM battery's
evaluations were changed to use acpi_EvaluateIntoBuffer().
- Add new utility function acpi_ConvertBufferToInteger().
- Add simple locking for CM battery and temperature updating.
- Fix a minor problem on EC locking.
- Make the thermal zone polling rate to be changeable.
- Change minor things on AcpiOsSignal(); in ACPI_SIGNAL_FATAL case,
entering Debugger is easier to investigate the problem rather than panic.
Diffstat (limited to 'sys/dev/acpica/Osd')
-rw-r--r-- | sys/dev/acpica/Osd/OsdDebug.c | 3 | ||||
-rw-r--r-- | sys/dev/acpica/Osd/OsdSchedule.c | 131 | ||||
-rw-r--r-- | sys/dev/acpica/Osd/OsdSynch.c | 160 |
3 files changed, 268 insertions, 26 deletions
diff --git a/sys/dev/acpica/Osd/OsdDebug.c b/sys/dev/acpica/Osd/OsdDebug.c index 776e871..cfcf5b6 100644 --- a/sys/dev/acpica/Osd/OsdDebug.c +++ b/sys/dev/acpica/Osd/OsdDebug.c @@ -84,8 +84,9 @@ AcpiOsSignal ( switch(Function) { case ACPI_SIGNAL_FATAL: fatal = (ACPI_SIGNAL_FATAL_INFO *)Info; - panic("ACPI fatal signal, type 0x%x code 0x%x argument 0x%x", + printf("ACPI fatal signal, type 0x%x code 0x%x argument 0x%x", fatal->Type, fatal->Code, fatal->Argument); + Debugger("AcpiOsSignal"); break; case ACPI_SIGNAL_BREAKPOINT: diff --git a/sys/dev/acpica/Osd/OsdSchedule.c b/sys/dev/acpica/Osd/OsdSchedule.c index 8a952df..60a8f48 100644 --- a/sys/dev/acpica/Osd/OsdSchedule.c +++ b/sys/dev/acpica/Osd/OsdSchedule.c @@ -33,21 +33,30 @@ #include "acpi.h" +#include "opt_acpi.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/interrupt.h> #include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> #include <sys/malloc.h> +#include <sys/mutex.h> #include <sys/proc.h> #include <sys/taskqueue.h> #include <machine/clock.h> +#include <sys/bus.h> + +#include <dev/acpica/acpivar.h> + #define _COMPONENT ACPI_OS_SERVICES MODULE_NAME("SCHEDULE") /* * This is a little complicated due to the fact that we need to build and then * free a 'struct task' for each task we enqueue. - * - * We use the default taskqueue_swi queue, since it really doesn't matter what - * else we're queued along with. */ MALLOC_DEFINE(M_ACPITASK, "acpitask", "ACPI deferred task"); @@ -60,6 +69,95 @@ struct acpi_task { void *at_context; }; +struct acpi_task_queue { + STAILQ_ENTRY(acpi_task_queue) at_q; + struct acpi_task *at; +}; + +/* + * Private task queue definition for ACPI + */ +TASKQUEUE_DECLARE(acpi); +static void *taskqueue_acpi_ih; + +static void +taskqueue_acpi_enqueue(void *context) +{ + swi_sched(taskqueue_acpi_ih, SWI_NOSWITCH); +} + +static void +taskqueue_acpi_run(void *dummy) +{ + taskqueue_run(taskqueue_acpi); +} + +TASKQUEUE_DEFINE(acpi, taskqueue_acpi_enqueue, 0, + swi_add(NULL, "acpitaskq", taskqueue_acpi_run, NULL, + SWI_TQ, 0, &taskqueue_acpi_ih)); + +#if defined(ACPI_MAX_THREADS) && ACPI_MAX_THREADS > 0 +#define ACPI_USE_THREADS +#endif + +#ifdef ACPI_USE_THREADS +STAILQ_HEAD(, acpi_task_queue) acpi_task_queue; +static struct mtx acpi_task_mtx; + +static void +acpi_task_thread(void *arg) +{ + struct acpi_task_queue *atq; + OSD_EXECUTION_CALLBACK Function; + void *Context; + + for (;;) { + mtx_lock(&acpi_task_mtx); + if ((atq = STAILQ_FIRST(&acpi_task_queue)) == NULL) { + msleep(&acpi_task_queue, &acpi_task_mtx, PCATCH, "actask", 0); + mtx_unlock(&acpi_task_mtx); + continue; + } + + STAILQ_REMOVE_HEAD(&acpi_task_queue, at_q); + mtx_unlock(&acpi_task_mtx); + + Function = (OSD_EXECUTION_CALLBACK)atq->at->at_function; + Context = atq->at->at_context; + + mtx_lock(&Giant); + Function(Context); + + free(atq->at, M_ACPITASK); + free(atq, M_ACPITASK); + mtx_unlock(&Giant); + } + + kthread_exit(0); +} + +int +acpi_task_thread_init(void) +{ + int i, err; + struct proc *acpi_kthread_proc; + + err = 0; + STAILQ_INIT(&acpi_task_queue); + mtx_init(&acpi_task_mtx, "ACPI task", MTX_DEF); + + for (i = 0; i < ACPI_MAX_THREADS; i++) { + err = kthread_create(acpi_task_thread, NULL, &acpi_kthread_proc, + 0, "acpi_task%d", i); + if (err != 0) { + printf("%s: kthread_create failed(%d)\n", __func__, err); + break; + } + } + return (err); +} +#endif + ACPI_STATUS AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void *Context) { @@ -97,25 +195,46 @@ AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void * } TASK_INIT(&at->at_task, pri, AcpiOsExecuteQueue, at); - taskqueue_enqueue(taskqueue_swi, (struct task *)at); + taskqueue_enqueue(taskqueue_acpi, (struct task *)at); return_ACPI_STATUS(AE_OK); } static void AcpiOsExecuteQueue(void *arg, int pending) { - struct acpi_task *at = (struct acpi_task *)arg; + struct acpi_task *at; + struct acpi_task_queue *atq; OSD_EXECUTION_CALLBACK Function; void *Context; FUNCTION_TRACE(__func__); + at = (struct acpi_task *)arg; + atq = NULL; + Function = NULL; + Context = NULL; + +#ifdef ACPI_USE_THREADS + atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); + if (atq == NULL) { + printf("%s: no memory\n", __func__); + return; + } + + atq->at = at; + + mtx_lock(&acpi_task_mtx); + STAILQ_INSERT_TAIL(&acpi_task_queue, atq, at_q); + mtx_unlock(&acpi_task_mtx); + wakeup_one(&acpi_task_queue); +#else Function = (OSD_EXECUTION_CALLBACK)at->at_function; Context = at->at_context; + Function(Context); free(at, M_ACPITASK); +#endif - Function(Context); return_VOID; } diff --git a/sys/dev/acpica/Osd/OsdSynch.c b/sys/dev/acpica/Osd/OsdSynch.c index 5c5141d..1d5533f 100644 --- a/sys/dev/acpica/Osd/OsdSynch.c +++ b/sys/dev/acpica/Osd/OsdSynch.c @@ -33,19 +33,18 @@ #include "acpi.h" +#include "opt_acpi.h" #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> +#include <sys/sysctl.h> #define _COMPONENT ACPI_OS_SERVICES MODULE_NAME("SYNCH") static MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); -/* disable semaphores - AML in the field doesn't use them correctly */ -#define ACPI_NO_SEMAPHORES - /* * Simple counting semaphore implemented using a mutex. (Subsequently used * in the OSI code to implement a mutex. Go figure.) @@ -54,8 +53,21 @@ struct acpi_semaphore { struct mtx as_mtx; UINT32 as_units; UINT32 as_maxunits; + UINT32 as_pendings; + UINT32 as_resetting; + UINT32 as_timeouts; }; +#ifndef ACPI_NO_SEMAPHORES +#ifndef ACPI_SEMAPHORES_MAX_PENDING +#define ACPI_SEMAPHORES_MAX_PENDING 4 +#endif +static int acpi_semaphore_debug = 0; +TUNABLE_INT("debug.acpi_semaphore_debug", &acpi_semaphore_debug); +SYSCTL_INT(_debug, OID_AUTO, acpi_semaphore_debug, CTLFLAG_RW, + &acpi_semaphore_debug, 0, ""); +#endif + ACPI_STATUS AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_HANDLE *OutHandle) { @@ -72,12 +84,15 @@ AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_HANDLE *OutHand if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT)) == NULL) return_ACPI_STATUS(AE_NO_MEMORY); + bzero(as, sizeof(*as)); mtx_init(&as->as_mtx, "ACPI semaphore", MTX_DEF); as->as_units = InitialUnits; as->as_maxunits = MaxUnits; + as->as_pendings = as->as_resetting = as->as_timeouts = 0; - DEBUG_PRINT(TRACE_MUTEX, ("created semaphore %p max %d, initial %d\n", - as, InitialUnits, MaxUnits)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "created semaphore %p max %d, initial %d\n", + as, InitialUnits, MaxUnits)); *OutHandle = (ACPI_HANDLE)as; return_ACPI_STATUS(AE_OK); @@ -95,7 +110,7 @@ AcpiOsDeleteSemaphore (ACPI_HANDLE Handle) FUNCTION_TRACE(__func__); - DEBUG_PRINT(TRACE_MUTEX, ("destroyed semaphore %p\n", as)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as)); mtx_destroy(&as->as_mtx); free(Handle, M_ACPISEM); return_ACPI_STATUS(AE_OK); @@ -116,27 +131,58 @@ AcpiOsWaitSemaphore(ACPI_HANDLE Handle, UINT32 Units, UINT32 Timeout) struct acpi_semaphore *as = (struct acpi_semaphore *)Handle; ACPI_STATUS result; int rv, tmo; + struct timeval timeouttv, currenttv, timelefttv; FUNCTION_TRACE(__func__); if (as == NULL) return_ACPI_STATUS(AE_BAD_PARAMETER); - /* a timeout of -1 means "forever" */ - if (Timeout == -1) { + if (cold) + return_ACPI_STATUS(AE_OK); + +#if 0 + if (as->as_units < Units && as->as_timeouts > 10) { + printf("%s: semaphore %p too many timeouts, resetting\n", __func__, as); + mtx_lock(&as->as_mtx); + as->as_units = as->as_maxunits; + if (as->as_pendings) + as->as_resetting = 1; + as->as_timeouts = 0; + wakeup(as); + mtx_unlock(&as->as_mtx); + return_ACPI_STATUS(AE_TIME); + } + + if (as->as_resetting) { + return_ACPI_STATUS(AE_TIME); + } +#endif + + /* a timeout of WAIT_FOREVER means "forever" */ + if (Timeout == WAIT_FOREVER) { tmo = 0; + timeouttv.tv_sec = ((0xffff/1000) + 1); /* cf. ACPI spec */ + timeouttv.tv_usec = 0; } else { /* compute timeout using microseconds per tick */ tmo = (Timeout * 1000) / (1000000 / hz); if (tmo <= 0) tmo = 1; + timeouttv.tv_sec = Timeout / 1000; + timeouttv.tv_usec = (Timeout % 1000) * 1000; } + /* calculate timeout value in timeval */ + getmicrotime(¤ttv); + timevaladd(&timeouttv, ¤ttv); + mtx_lock(&as->as_mtx); - DEBUG_PRINT(TRACE_MUTEX, ("get %d units from semaphore %p (has %d), timeout %d\n", - Units, as, as->as_units, Timeout)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "get %d units from semaphore %p (has %d), timeout %d\n", + Units, as, as->as_units, Timeout)); for (;;) { - if (as->as_inits == ACPI_NO_UNIT_LIMIT) { + if (as->as_units == ACPI_NO_UNIT_LIMIT) { result = AE_OK; break; } @@ -145,20 +191,89 @@ AcpiOsWaitSemaphore(ACPI_HANDLE Handle, UINT32 Units, UINT32 Timeout) result = AE_OK; break; } - if (Timeout < 0) { + + /* limit number of pending treads */ + if (as->as_pendings >= ACPI_SEMAPHORES_MAX_PENDING) { result = AE_TIME; break; } - DEBUG_PRINT(TRACE_MUTEX, ("semaphore blocked, calling msleep(%p, %p, %d, \"acpisem\", %d)\n", - as, as->as_mtx, 0, tmo)); - - rv = msleep(as, &as->as_mtx, 0, "acpisem", tmo); - DEBUG_PRINT(TRACE_MUTEX, ("msleep returned %d\n", rv)); + + /* if timeout values of zero is specified, return immediately */ + if (Timeout == 0) { + result = AE_TIME; + break; + } + + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "semaphore blocked, calling msleep(%p, %p, %d, \"acsem\", %d)\n", + as, &as->as_mtx, PCATCH, tmo)); + + as->as_pendings++; + + if (acpi_semaphore_debug) { + printf("%s: Sleep %d, pending %d, semaphore %p, thread %d\n", + __func__, Timeout, as->as_pendings, as, AcpiOsGetThreadId()); + } + + rv = msleep(as, &as->as_mtx, PCATCH, "acsem", tmo); + + as->as_pendings--; + +#if 0 + if (as->as_resetting) { + /* semaphore reset, return immediately */ + if (as->as_pendings == 0) { + as->as_resetting = 0; + } + result = AE_TIME; + break; + } +#endif + + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "msleep(%d) returned %d\n", tmo, rv)); if (rv == EWOULDBLOCK) { result = AE_TIME; break; } + + /* check if we already awaited enough */ + timelefttv = timeouttv; + getmicrotime(¤ttv); + timevalsub(&timelefttv, ¤ttv); + if (timelefttv.tv_sec < 0) { + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "await semaphore %p timeout\n", as)); + result = AE_TIME; + break; + } + + /* adjust timeout for the next sleep */ + tmo = (timelefttv.tv_sec * 1000000 + timelefttv.tv_usec) / (1000000 / hz); + if (tmo <= 0) + tmo = 1; + + if (acpi_semaphore_debug) { + printf("%s: Wakeup timeleft(%lu, %lu), tmo %u, semaphore %p, thread %d\n", + __func__, timelefttv.tv_sec, timelefttv.tv_usec, tmo, as, AcpiOsGetThreadId()); + } + } + + if (acpi_semaphore_debug) { + if (result == AE_TIME && Timeout > 0) { + printf("%s: Timeout %d, pending %d, semaphore %p\n", + __func__, Timeout, as->as_pendings, as); + } + if (result == AE_OK && (as->as_timeouts > 0 || as->as_pendings > 0)) { + printf("%s: Acquire %d, units %d, pending %d, semaphore %p, thread %d\n", + __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId()); + } + } + + if (result == AE_TIME) { + as->as_timeouts++; + } else { + as->as_timeouts = 0; } + mtx_unlock(&as->as_mtx); return_ACPI_STATUS(result); @@ -179,13 +294,20 @@ AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units) return_ACPI_STATUS(AE_BAD_PARAMETER); mtx_lock(&as->as_mtx); - DEBUG_PRINT(TRACE_MUTEX, ("return %d units to semaphore %p (has %d)\n", - Units, as, as->as_units)); + ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, + "return %d units to semaphore %p (has %d)\n", + Units, as, as->as_units)); if (as->as_units != ACPI_NO_UNIT_LIMIT) { as->as_units += Units; if (as->as_units > as->as_maxunits) as->as_units = as->as_maxunits; } + + if (acpi_semaphore_debug && (as->as_timeouts > 0 || as->as_pendings > 0)) { + printf("%s: Release %d, units %d, pending %d, semaphore %p, thread %d\n", + __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId()); + } + wakeup(as); mtx_unlock(&as->as_mtx); return_ACPI_STATUS(AE_OK); |