summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpica/Osd
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2001-12-22 16:05:41 +0000
committeriwasaki <iwasaki@FreeBSD.org>2001-12-22 16:05:41 +0000
commit4c7abcd3372368396a11a120c259afdb0fe2b015 (patch)
tree7c96c678372cc5f9e23154023196e80b72311f86 /sys/dev/acpica/Osd
parent23a35cbf8dc1e76d3a4e856806e0ee472c65e5af (diff)
downloadFreeBSD-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.c3
-rw-r--r--sys/dev/acpica/Osd/OsdSchedule.c131
-rw-r--r--sys/dev/acpica/Osd/OsdSynch.c160
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(&currenttv);
+ timevaladd(&timeouttv, &currenttv);
+
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(&currenttv);
+ timevalsub(&timelefttv, &currenttv);
+ 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);
OpenPOWER on IntegriCloud