Index: conf/options =================================================================== RCS file: /home/ncvs/src/sys/conf/options,v retrieving revision 1.297 diff -u -r1.297 options --- conf/options 15 Nov 2001 16:03:24 -0000 1.297 +++ conf/options 5 Dec 2001 03:31:53 -0000 @@ -512,6 +512,8 @@ 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_NO_THREADS opt_acpi.h # options for DEVFS, see sys/fs/devfs/devfs.h NDEVFSINO opt_devfs.h Index: contrib/dev/acpica/exsystem.c =================================================================== RCS file: /home/ncvs/src/sys/contrib/dev/acpica/exsystem.c,v retrieving revision 1.1.1.7 diff -u -r1.1.1.7 exsystem.c --- contrib/dev/acpica/exsystem.c 7 Sep 2001 01:22:24 -0000 1.1.1.7 +++ contrib/dev/acpica/exsystem.c 5 Dec 2001 03:31:53 -0000 @@ -172,10 +172,13 @@ /* Reacquire the interpreter */ - Status = AcpiExEnterInterpreter (); - if (ACPI_SUCCESS (Status)) + if (ACPI_FAILURE(AcpiExEnterInterpreter ())) { /* Restore the timeout exception */ + if (ACPI_SUCCESS (Status)) + { + AcpiOsSignalSemaphore (Semaphore, 1); + } Status = AE_TIME; } Index: dev/acpica/acpi.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi.c,v retrieving revision 1.52 diff -u -r1.52 acpi.c --- dev/acpica/acpi.c 30 Nov 2001 16:06:00 -0000 1.52 +++ dev/acpica/acpi.c 5 Dec 2001 03:31:54 -0000 @@ -470,6 +470,12 @@ acpi_EnterDebugger(); #endif +#ifndef ACPI_NO_THREADS + if ((error = acpi_task_thread_init())) { + goto out; + } +#endif + if ((error = acpi_machdep_init(dev))) { goto out; } @@ -1077,7 +1083,7 @@ /* * 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. @@ -1090,11 +1096,10 @@ 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)); @@ -1108,8 +1113,7 @@ { ACPI_STATUS error; ACPI_BUFFER buf; - ACPI_OBJECT param, *p; - int i; + ACPI_OBJECT param; ACPI_ASSERTLOCK; @@ -1143,23 +1147,33 @@ 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); } 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); } /* Index: dev/acpica/acpi_cmbat.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi_cmbat.c,v retrieving revision 1.13 diff -u -r1.13 acpi_cmbat.c --- dev/acpica/acpi_cmbat.c 22 Nov 2001 17:43:15 -0000 1.13 +++ dev/acpica/acpi_cmbat.c 5 Dec 2001 03:31:54 -0000 @@ -108,6 +108,8 @@ 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 @@ return; } + if (sc->bst_updating) { + return; + } + sc->bst_updating = 1; + 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; - } - } - - bzero(sc->bst_buffer.Pointer, sc->bst_buffer.Length); - as = AcpiEvaluateObject(h, "_BST", NULL, &sc->bst_buffer); - - 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 @@ 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 @@ return; } + if (sc->bif_updating) { + return; + } + sc->bif_updating = 1; + 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; - } - } - - bzero(sc->bif_buffer.Pointer, sc->bif_buffer.Length); - as = AcpiEvaluateObject(h, "_BIF", NULL, &sc->bif_buffer); - - 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 @@ 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 @@ 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); Index: dev/acpica/acpi_ec.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi_ec.c,v retrieving revision 1.20 diff -u -r1.20 acpi_ec.c --- dev/acpica/acpi_ec.c 28 Nov 2001 04:36:29 -0000 1.20 +++ dev/acpica/acpi_ec.c 5 Dec 2001 03:31:54 -0000 @@ -251,7 +251,9 @@ ACPI_STATUS status; status = AcpiAcquireGlobalLock(); - (sc)->ec_locked = 1; + if (status == AE_OK) + (sc)->ec_locked = 1; + return(status); } Index: dev/acpica/acpi_powerres.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi_powerres.c,v retrieving revision 1.8 diff -u -r1.8 acpi_powerres.c --- dev/acpica/acpi_powerres.c 4 Oct 2001 08:32:18 -0000 1.8 +++ dev/acpica/acpi_powerres.c 5 Dec 2001 03:31:54 -0000 @@ -166,6 +166,7 @@ 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 @@ 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 @@ * 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))); Index: dev/acpica/acpi_thermal.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpi_thermal.c,v retrieving revision 1.19 diff -u -r1.19 acpi_thermal.c --- dev/acpica/acpi_thermal.c 18 Nov 2001 18:12:07 -0000 1.19 +++ dev/acpica/acpi_thermal.c 5 Dec 2001 03:31:54 -0000 @@ -51,7 +51,7 @@ #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 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_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 @@ 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 @@ 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 @@ * 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 @@ 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_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_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 @@ } sc->tz_thflags = newflags; +out: + sc->tz_tmp_updating = 0; return_VOID; } @@ -693,7 +719,7 @@ /* 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; } Index: dev/acpica/acpivar.h =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/acpivar.h,v retrieving revision 1.23 diff -u -r1.23 acpivar.h --- dev/acpica/acpivar.h 18 Nov 2001 18:12:07 -0000 1.23 +++ dev/acpica/acpivar.h 5 Dec 2001 03:31:54 -0000 @@ -243,6 +243,7 @@ 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); @@ -361,3 +362,11 @@ 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 + Index: dev/acpica/Osd/OsdDebug.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/Osd/OsdDebug.c,v retrieving revision 1.2 diff -u -r1.2 OsdDebug.c --- dev/acpica/Osd/OsdDebug.c 21 Jul 2001 04:10:01 -0000 1.2 +++ dev/acpica/Osd/OsdDebug.c 5 Dec 2001 03:31:54 -0000 @@ -84,8 +84,9 @@ 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: Index: dev/acpica/Osd/OsdSchedule.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/Osd/OsdSchedule.c,v retrieving revision 1.14 diff -u -r1.14 OsdSchedule.c --- dev/acpica/Osd/OsdSchedule.c 26 Oct 2001 18:46:46 -0000 1.14 +++ dev/acpica/Osd/OsdSchedule.c 5 Dec 2001 03:31:54 -0000 @@ -33,12 +33,20 @@ #include "acpi.h" +#include "opt_acpi.h" #include +#include +#include #include +#include #include #include #include +#include + +#include + #define _COMPONENT ACPI_OS_SERVICES MODULE_NAME("SCHEDULE") @@ -60,6 +68,73 @@ void *at_context; }; +struct acpi_task_queue { + STAILQ_ENTRY(acpi_task_queue) at_q; + struct acpi_task *at; +}; + +#ifndef ACPI_NO_THREADS +#ifndef ACPI_MAX_THREADS +#define ACPI_MAX_THREADS 1 +#endif + +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(__func__ ": kthread_create failed(%d)\n", err); + break; + } + } + return (err); +} +#endif + ACPI_STATUS AcpiOsQueueForExecution(UINT32 Priority, OSD_EXECUTION_CALLBACK Function, void *Context) { @@ -104,18 +179,39 @@ 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; + +#ifndef ACPI_NO_THREADS + atq = malloc(sizeof(*atq), M_ACPITASK, M_NOWAIT); + if (atq == NULL) { + printf(__func__ ": no memory\n"); + 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; } Index: dev/acpica/Osd/OsdSynch.c =================================================================== RCS file: /home/ncvs/src/sys/dev/acpica/Osd/OsdSynch.c,v retrieving revision 1.9 diff -u -r1.9 OsdSynch.c --- dev/acpica/Osd/OsdSynch.c 21 Jul 2001 04:10:01 -0000 1.9 +++ dev/acpica/Osd/OsdSynch.c 5 Dec 2001 03:31:54 -0000 @@ -33,19 +33,18 @@ #include "acpi.h" +#include "opt_acpi.h" #include #include #include #include +#include #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 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 = 1; +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 @@ 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 @@ 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 @@ 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 1 + if (as->as_units < Units && as->as_timeouts > 10) { + printf(__func__ ": semaphore %p too many timeouts, resetting\n", 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 0xffffffff means "forever" */ + if (Timeout == 0xffffffff) { 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 @@ result = AE_OK; break; } - if (Timeout < 0) { + + /* limit number of pending treads */ + if (as->as_pendings >= ACPI_SEMAPHORES_MAX_PENDING) { + result = AE_TIME; + break; + } + + /* if timeout values of zero is specified, return immediately */ + if (Timeout == 0) { 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)); + + 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(__func__ ": Sleep %d, pending %d, semaphore %p, thread %d\n", + Timeout, as->as_pendings, as, AcpiOsGetThreadId()); + } + + rv = msleep(as, &as->as_mtx, PCATCH, "acsem", tmo); + + as->as_pendings--; + +#if 1 + 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(__func__ ": Wakeup timeleft(%lu, %lu), tmo %u, semaphore %p, thread %d\n", + timelefttv.tv_sec, timelefttv.tv_usec, tmo, as, AcpiOsGetThreadId()); + } } + + if (acpi_semaphore_debug) { + if (result == AE_TIME && Timeout > 0) { + printf(__func__ ": Timeout %d, pending %d, semaphore %p\n", + Timeout, as->as_pendings, as); + } + if (result == AE_OK && (as->as_timeouts > 0 || as->as_pendings > 0)) { + printf(__func__ ": Acquire %d, units %d, pending %d, semaphore %p, thread %d\n", + 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 @@ 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(__func__ ": Release %d, units %d, pending %d, semaphore %p, thread %d\n", + Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId()); + } + wakeup(as); mtx_unlock(&as->as_mtx); return_ACPI_STATUS(AE_OK); Index: modules/acpi/Makefile =================================================================== RCS file: /home/ncvs/src/sys/modules/acpi/Makefile,v retrieving revision 1.17 diff -u -r1.17 Makefile --- modules/acpi/Makefile 6 Nov 2001 15:00:30 -0000 1.17 +++ modules/acpi/Makefile 5 Dec 2001 03:31:54 -0000 @@ -36,6 +36,12 @@ 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_NO_THREADS +CFLAGS+=-DACPI_NO_THREADS +.endif # Debugging support .if ACPI_DEBUG