summaryrefslogtreecommitdiffstats
path: root/sys
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
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')
-rw-r--r--sys/conf/options2
-rw-r--r--sys/contrib/dev/acpica/exsystem.c10
-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
-rw-r--r--sys/dev/acpica/acpi.c50
-rw-r--r--sys/dev/acpica/acpi_cmbat.c83
-rw-r--r--sys/dev/acpica/acpi_ec.c4
-rw-r--r--sys/dev/acpica/acpi_powerres.c3
-rw-r--r--sys/dev/acpica/acpi_thermal.c36
-rw-r--r--sys/dev/acpica/acpivar.h9
-rw-r--r--sys/modules/acpi/Makefile6
12 files changed, 378 insertions, 119 deletions
diff --git a/sys/conf/options b/sys/conf/options
index 3ec6231..066911f 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -513,6 +513,8 @@ WITNESS_SKIPSPIN opt_witness.h
ACPI_DEBUG opt_acpi.h
AML_DEBUG opt_acpi.h
ACPI_NO_ENABLE_ON_BOOT opt_acpi.h
+ACPI_NO_SEMAPHORES opt_acpi.h
+ACPI_MAX_THREADS opt_acpi.h
# options for DEVFS, see sys/fs/devfs/devfs.h
NDEVFSINO opt_devfs.h
diff --git a/sys/contrib/dev/acpica/exsystem.c b/sys/contrib/dev/acpica/exsystem.c
index df03448..b462597 100644
--- a/sys/contrib/dev/acpica/exsystem.c
+++ b/sys/contrib/dev/acpica/exsystem.c
@@ -147,7 +147,7 @@ AcpiExSystemWaitSemaphore (
ACPI_HANDLE Semaphore,
UINT32 Timeout)
{
- ACPI_STATUS Status;
+ ACPI_STATUS Status, Status2;
FUNCTION_TRACE ("ExSystemWaitSemaphore");
@@ -172,12 +172,12 @@ AcpiExSystemWaitSemaphore (
/* Reacquire the interpreter */
- Status = AcpiExEnterInterpreter ();
- if (ACPI_SUCCESS (Status))
+ Status2 = AcpiExEnterInterpreter ();
+ if (ACPI_FAILURE (Status2))
{
- /* Restore the timeout exception */
+ /* Report fatal error, could not acquire interpreter */
- Status = AE_TIME;
+ return_ACPI_STATUS (Status2);
}
}
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);
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 5bbc688..6ebce70 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -471,6 +471,12 @@ acpi_attach(device_t dev)
acpi_EnterDebugger();
#endif
+#if defined(ACPI_MAX_THREADS) && ACPI_MAX_THREADS > 0
+ if ((error = acpi_task_thread_init())) {
+ goto out;
+ }
+#endif
+
if ((error = acpi_machdep_init(dev))) {
goto out;
}
@@ -1078,7 +1084,7 @@ acpi_GetTableIntoBuffer(ACPI_TABLE_TYPE table, UINT32 instance, ACPI_BUFFER *buf
/*
* Perform the tedious double-evaluate procedure for evaluating something into
- * an ACPI_BUFFER that has not been initialised. Note that this evaluates
+ * an ACPI_BUFFER if it has not been initialised. Note that this evaluates
* twice, so avoid applying this to things that may have side-effects.
*
* This is like AcpiEvaluateObject with automatic buffer allocation.
@@ -1091,11 +1097,10 @@ acpi_EvaluateIntoBuffer(ACPI_HANDLE object, ACPI_STRING pathname, ACPI_OBJECT_LI
ACPI_ASSERTLOCK;
- buf->Length = 0;
- buf->Pointer = NULL;
-
if ((status = AcpiEvaluateObject(object, pathname, params, buf)) != AE_BUFFER_OVERFLOW)
return(status);
+ if (buf->Pointer != NULL)
+ AcpiOsFree(buf->Pointer);
if ((buf->Pointer = AcpiOsCallocate(buf->Length)) == NULL)
return(AE_NO_MEMORY);
return(AcpiEvaluateObject(object, pathname, params, buf));
@@ -1109,8 +1114,7 @@ acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number)
{
ACPI_STATUS error;
ACPI_BUFFER buf;
- ACPI_OBJECT param, *p;
- int i;
+ ACPI_OBJECT param;
ACPI_ASSERTLOCK;
@@ -1144,18 +1148,7 @@ acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number)
error = AE_NO_MEMORY;
} else {
if ((error = AcpiEvaluateObject(handle, path, NULL, &buf)) == AE_OK) {
- p = (ACPI_OBJECT *)buf.Pointer;
- if (p->Type != ACPI_TYPE_BUFFER) {
- error = AE_TYPE;
- } else {
- if (p->Buffer.Length > sizeof(int)) {
- error = AE_BAD_DATA;
- } else {
- *number = 0;
- for (i = 0; i < p->Buffer.Length; i++)
- *number += (*(p->Buffer.Pointer + i) << (i * 8));
- }
- }
+ error = acpi_ConvertBufferToInteger(&buf, number);
}
}
AcpiOsFree(buf.Pointer);
@@ -1163,6 +1156,27 @@ acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number)
return(error);
}
+ACPI_STATUS
+acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, int *number)
+{
+ ACPI_OBJECT *p;
+ int i;
+
+ p = (ACPI_OBJECT *)bufp->Pointer;
+ if (p->Type == ACPI_TYPE_INTEGER) {
+ *number = p->Integer.Value;
+ return(AE_OK);
+ }
+ if (p->Type != ACPI_TYPE_BUFFER)
+ return(AE_TYPE);
+ if (p->Buffer.Length > sizeof(int))
+ return(AE_BAD_DATA);
+ *number = 0;
+ for (i = 0; i < p->Buffer.Length; i++)
+ *number += (*(p->Buffer.Pointer + i) << (i * 8));
+ return(AE_OK);
+}
+
/*
* Iterate over the elements of an a package object, calling the supplied
* function for each element.
diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c
index dc78c42..ccab956 100644
--- a/sys/dev/acpica/acpi_cmbat.c
+++ b/sys/dev/acpica/acpi_cmbat.c
@@ -108,6 +108,8 @@ struct acpi_cmbat_softc {
ACPI_BUFFER bst_buffer;
struct timespec bif_lastupdated;
struct timespec bst_lastupdated;
+ int bif_updating;
+ int bst_updating;
int not_present;
int cap;
@@ -195,42 +197,17 @@ acpi_cmbat_get_bst(void *context)
return;
}
- untimeout(acpi_cmbat_timeout, (caddr_t)dev, sc->cmbat_timeout);
-retry:
- if (sc->bst_buffer.Length == 0) {
- if (sc->bst_buffer.Pointer != NULL) {
- free(sc->bst_buffer.Pointer, M_ACPICMBAT);
- sc->bst_buffer.Pointer = NULL;
- }
- as = AcpiEvaluateObject(h, "_BST", NULL, &sc->bst_buffer);
- if (as != AE_BUFFER_OVERFLOW) {
- ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "couldn't find _BST - %s\n", AcpiFormatException(as));
- goto end;
- }
-
- sc->bst_buffer.Pointer = malloc(sc->bst_buffer.Length, M_ACPICMBAT, M_NOWAIT);
- if (sc->bst_buffer.Pointer == NULL) {
- device_printf(dev, "malloc failed");
- goto end;
- }
+ if (sc->bst_updating) {
+ return;
}
+ sc->bst_updating = 1;
- bzero(sc->bst_buffer.Pointer, sc->bst_buffer.Length);
- as = AcpiEvaluateObject(h, "_BST", NULL, &sc->bst_buffer);
+ untimeout(acpi_cmbat_timeout, (caddr_t)dev, sc->cmbat_timeout);
- if (as == AE_BUFFER_OVERFLOW) {
- if (sc->bst_buffer.Pointer != NULL) {
- free(sc->bst_buffer.Pointer, M_ACPICMBAT);
- sc->bst_buffer.Pointer = NULL;
- }
- ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "bst size changed to %d\n", sc->bst_buffer.Length);
- sc->bst_buffer.Length = 0;
- goto retry;
- } else if (as != AE_OK) {
+ if ((as = acpi_EvaluateIntoBuffer(h, "_BST", NULL, &sc->bst_buffer)) != AE_OK) {
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "couldn't find _BST - %s\n", AcpiFormatException(as));
+ "error fetching current battery status -- %s\n",
+ AcpiFormatException(as));
goto end;
}
@@ -248,6 +225,7 @@ retry:
PKG_GETINT(res, tmp, 3, sc->bst.volt, end);
acpi_cmbat_info_updated(&sc->bst_lastupdated);
end:
+ sc->bst_updating = 0;
sc->cmbat_timeout = timeout(acpi_cmbat_timeout, dev, CMBAT_POLLRATE);
}
@@ -268,42 +246,17 @@ acpi_cmbat_get_bif(void *context)
return;
}
- untimeout(acpi_cmbat_timeout, (caddr_t)dev, sc->cmbat_timeout);
-retry:
- if (sc->bif_buffer.Length == 0) {
- if (sc->bif_buffer.Pointer != NULL) {
- free(sc->bif_buffer.Pointer, M_ACPICMBAT);
- sc->bif_buffer.Pointer = NULL;
- }
- as = AcpiEvaluateObject(h, "_BIF", NULL, &sc->bif_buffer);
- if (as != AE_BUFFER_OVERFLOW) {
- ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "couldn't find _BIF - %s\n", AcpiFormatException(as));
- goto end;
- }
-
- sc->bif_buffer.Pointer = malloc(sc->bif_buffer.Length, M_ACPICMBAT, M_NOWAIT);
- if (sc->bif_buffer.Pointer == NULL) {
- device_printf(dev, "malloc failed");
- goto end;
- }
+ if (sc->bif_updating) {
+ return;
}
+ sc->bif_updating = 1;
- bzero(sc->bif_buffer.Pointer, sc->bif_buffer.Length);
- as = AcpiEvaluateObject(h, "_BIF", NULL, &sc->bif_buffer);
+ untimeout(acpi_cmbat_timeout, (caddr_t)dev, sc->cmbat_timeout);
- if (as == AE_BUFFER_OVERFLOW) {
- if (sc->bif_buffer.Pointer != NULL) {
- free(sc->bif_buffer.Pointer, M_ACPICMBAT);
- sc->bif_buffer.Pointer = NULL;
- }
- ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "bif size changed to %d\n", sc->bif_buffer.Length);
- sc->bif_buffer.Length = 0;
- goto retry;
- } else if (as != AE_OK) {
+ if ((as = acpi_EvaluateIntoBuffer(h, "_BIF", NULL, &sc->bif_buffer)) != AE_OK) {
ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
- "couldn't find _BIF - %s\n", AcpiFormatException(as));
+ "error fetching current battery info -- %s\n",
+ AcpiFormatException(as));
goto end;
}
@@ -330,6 +283,7 @@ retry:
PKG_GETSTR(res, tmp, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN, end);
acpi_cmbat_info_updated(&sc->bif_lastupdated);
end:
+ sc->bif_updating = 0;
sc->cmbat_timeout = timeout(acpi_cmbat_timeout, dev, CMBAT_POLLRATE);
}
@@ -391,6 +345,7 @@ acpi_cmbat_attach(device_t dev)
bzero(&sc->bif_buffer, sizeof(sc->bif_buffer));
bzero(&sc->bst_buffer, sizeof(sc->bst_buffer));
+ sc->bif_updating = sc->bst_updating = 0;
sc->dev = dev;
timespecclear(&sc->bif_lastupdated);
diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c
index adc09a6..331d389 100644
--- a/sys/dev/acpica/acpi_ec.c
+++ b/sys/dev/acpica/acpi_ec.c
@@ -251,7 +251,9 @@ EcLock(struct acpi_ec_softc *sc)
ACPI_STATUS status;
status = AcpiAcquireGlobalLock();
- (sc)->ec_locked = 1;
+ if (status == AE_OK)
+ (sc)->ec_locked = 1;
+
return(status);
}
diff --git a/sys/dev/acpica/acpi_powerres.c b/sys/dev/acpica/acpi_powerres.c
index a274549..c6415fd 100644
--- a/sys/dev/acpica/acpi_powerres.c
+++ b/sys/dev/acpica/acpi_powerres.c
@@ -166,6 +166,7 @@ acpi_pwr_register_resource(ACPI_HANDLE res)
rp->ap_resource = res;
/* get the Power Resource object */
+ bzero(&buf, sizeof(buf));
if ((status = acpi_EvaluateIntoBuffer(res, NULL, NULL, &buf)) != AE_OK) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n"));
goto out;
@@ -373,6 +374,7 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
if (AcpiGetHandle(consumer, "_PR0", &pr0_handle) != AE_OK) {
goto bad;
}
+ bzero(&reslist_buffer, sizeof(reslist_buffer));
status = acpi_EvaluateIntoBuffer(pr0_handle, NULL, NULL, &reslist_buffer);
if (status != AE_OK) {
goto bad;
@@ -389,6 +391,7 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
* Check that we can actually fetch the list of power resources
*/
if (reslist_handle != NULL) {
+ bzero(&reslist_buffer, sizeof(reslist_buffer));
if ((status = acpi_EvaluateIntoBuffer(reslist_handle, NULL, NULL, &reslist_buffer)) != AE_OK) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
acpi_name(reslist_handle)));
diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c
index a2e10c8..9cde5f4 100644
--- a/sys/dev/acpica/acpi_thermal.c
+++ b/sys/dev/acpica/acpi_thermal.c
@@ -51,7 +51,7 @@ MODULE_NAME("THERMAL")
#define TZ_NOTIFY_DEVICES 0x81
#define TZ_NOTIFY_LEVELS 0x82
-#define TZ_POLLRATE (hz * 10) /* every ten seconds */
+#define TZ_POLLRATE 30 /* every 30 seconds by default */
#define TZ_NUMLEVELS 10 /* defined by ACPI spec */
struct acpi_tz_zone {
@@ -90,6 +90,8 @@ struct acpi_tz_softc {
struct sysctl_oid *tz_sysctl_tree;
struct acpi_tz_zone tz_zone; /* thermal zone parameters */
+ ACPI_BUFFER tz_tmp_buffer;
+ int tz_tmp_updating;
};
static int acpi_tz_probe(device_t dev);
@@ -127,6 +129,7 @@ static struct sysctl_ctx_list acpi_tz_sysctl_ctx;
static struct sysctl_oid *acpi_tz_sysctl_tree;
static int acpi_tz_min_runtime = 0;/* minimum cooling run time */
+static int acpi_tz_polling_rate = TZ_POLLRATE;
/*
* Match an ACPI thermal zone.
@@ -170,6 +173,8 @@ acpi_tz_attach(device_t dev)
sc->tz_dev = dev;
sc->tz_handle = acpi_get_handle(dev);
sc->tz_requested = TZ_ACTIVE_NONE;
+ bzero(&sc->tz_tmp_buffer, sizeof(sc->tz_tmp_buffer));
+ sc->tz_tmp_updating = 0;
/*
* Parse the current state of the thermal zone and build control
@@ -199,6 +204,10 @@ acpi_tz_attach(device_t dev)
SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
OID_AUTO, "min_runtime", CTLFLAG_RD | CTLFLAG_RW,
&acpi_tz_min_runtime, 0, "minimum cooling run time in sec");
+ SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
+ OID_AUTO, "polling_rate", CTLFLAG_RD | CTLFLAG_RW,
+ &acpi_tz_polling_rate, 0, "monitor polling rate");
}
sysctl_ctx_init(&sc->tz_sysctl_ctx);
sprintf(oidname, "tz%d", device_get_unit(dev));
@@ -249,7 +258,7 @@ acpi_tz_attach(device_t dev)
* Start the timeout routine, with enough delay for the rest of the
* subsystem to come up.
*/
- sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE);
+ sc->tz_timeout = timeout(acpi_tz_timeout, sc, acpi_tz_polling_rate * hz);
return_VALUE(error);
}
@@ -288,6 +297,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc)
sprintf(nbuf, "_AC%d", i);
acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]);
sprintf(nbuf, "_AL%d", i);
+ bzero(&sc->tz_zone.al[i], sizeof(sc->tz_zone.al[i]));
acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]);
obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer;
if (obj != NULL) {
@@ -301,6 +311,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc)
}
acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
+ bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl));
acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv);
acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1);
@@ -358,16 +369,29 @@ acpi_tz_monitor(struct acpi_tz_softc *sc)
ACPI_ASSERTLOCK;
+ if (sc->tz_tmp_updating) {
+ goto out;
+ }
+ sc->tz_tmp_updating = 1;
+
/*
* Get the current temperature.
*/
- if ((status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) {
+ if ((status = acpi_EvaluateIntoBuffer(sc->tz_handle, "_TMP", NULL, &sc->tz_tmp_buffer)) != AE_OK) {
ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
"error fetching current temperature -- %s\n",
AcpiFormatException(status));
/* XXX disable zone? go to max cooling? */
- return_VOID;
+ goto out;
}
+ if ((status = acpi_ConvertBufferToInteger(&sc->tz_tmp_buffer, &temp)) != AE_OK) {
+ ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
+ "error fetching current temperature -- %s\n",
+ AcpiFormatException(status));
+ /* XXX disable zone? go to max cooling? */
+ goto out;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
sc->tz_temperature = temp;
@@ -454,6 +478,8 @@ acpi_tz_monitor(struct acpi_tz_softc *sc)
}
sc->tz_thflags = newflags;
+out:
+ sc->tz_tmp_updating = 0;
return_VOID;
}
@@ -693,7 +719,7 @@ acpi_tz_timeout(void *arg)
/* XXX passive cooling actions? */
/* re-register ourself */
- sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE);
+ sc->tz_timeout = timeout(acpi_tz_timeout, sc, acpi_tz_polling_rate * hz);
ACPI_UNLOCK;
}
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 6191859..2ab2e15 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -244,6 +244,7 @@ extern ACPI_STATUS acpi_GetTableIntoBuffer(ACPI_TABLE_TYPE table, UINT32 instanc
extern ACPI_STATUS acpi_EvaluateIntoBuffer(ACPI_HANDLE object, ACPI_STRING pathname,
ACPI_OBJECT_LIST *params, ACPI_BUFFER *buf);
extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number);
+extern ACPI_STATUS acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, int *number);
extern ACPI_STATUS acpi_ForeachPackageObject(ACPI_OBJECT *obj,
void (* func)(ACPI_OBJECT *comp, void *arg),
void *arg);
@@ -362,3 +363,11 @@ extern void powerprofile_set_state(int state);
typedef void (*powerprofile_change_hook)(void *);
EVENTHANDLER_DECLARE(powerprofile_change, powerprofile_change_hook);
+
+#ifndef ACPI_NO_THREADS
+/*
+ * ACPI task kernel thread initialization.
+ */
+extern int acpi_task_thread_init(void);
+#endif
+
diff --git a/sys/modules/acpi/Makefile b/sys/modules/acpi/Makefile
index 4b33d7d..42a39df 100644
--- a/sys/modules/acpi/Makefile
+++ b/sys/modules/acpi/Makefile
@@ -36,6 +36,12 @@ SRCS+= OsdHardware.c OsdInterrupt.c OsdMemory.c OsdSchedule.c
SRCS+= OsdStream.c OsdSynch.c OsdEnvironment.c
SRCS+= opt_acpi.h opt_ddb.h
SRCS+= device_if.h bus_if.h pci_if.h pcib_if.h isa_if.h
+.if ACPI_NO_SEMAPHORES
+CFLAGS+=-DACPI_NO_SEMAPHORES
+.endif
+.if ACPI_MAX_THREADS
+CFLAGS+=-DACPI_MAX_THREADS=${ACPI_MAX_THREADS}
+.endif
# Debugging support
.if ACPI_DEBUG
OpenPOWER on IntegriCloud