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.
This commit is contained in:
parent
1b3d626a13
commit
c573e654b7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88420
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
free(at, M_ACPITASK);
|
||||
|
||||
Function(Context);
|
||||
free(at, M_ACPITASK);
|
||||
#endif
|
||||
|
||||
return_VOID;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
if ((as = acpi_EvaluateIntoBuffer(h, "_BST", NULL, &sc->bst_buffer)) != AE_OK) {
|
||||
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) {
|
||||
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 @@ acpi_cmbat_get_bst(void *context)
|
||||
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;
|
||||
}
|
||||
if ((as = acpi_EvaluateIntoBuffer(h, "_BIF", NULL, &sc->bif_buffer)) != AE_OK) {
|
||||
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) {
|
||||
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 @@ acpi_cmbat_get_bif(void *context)
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user