aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNate Lawson <njl@FreeBSD.org>2004-08-13 06:21:32 +0000
committerNate Lawson <njl@FreeBSD.org>2004-08-13 06:21:32 +0000
commit15e2f34f9061e88a771a2ae15231644fb14c530d (patch)
tree8bb6c73908ffafa5c5d8c1f9f463e7de5a0ce611 /sys
parent3a9865dd3496e05063617254850a7d7b89e84fd8 (diff)
downloadsrc-15e2f34f9061e88a771a2ae15231644fb14c530d.tar.gz
src-15e2f34f9061e88a771a2ae15231644fb14c530d.zip
MPSAFE locking
* Serialize calls to acpi_alloc_resource(), acpi_release_resource(), acpi_Enable(), acpi_Disable(), and acpi_debug_sysctl(). * Acquire the ACPI mutex in acpi_register_ioctl(), acpi_deregister_ioctl(), and acpiioctl(). * Acquire the mutex while disabling subsequent requests to enter a sleep state in acpi_SetSleepState(). * Be sure to re-enable sleep requests and don't run resume methods when the current request fails. * Don't check if sleep requests are disabled in the ACPIIO_SETSLPSTATE ioctl. acpi_SetSleepState() does this for us. * Remove the acquisition of Giant from the struct cdevsw. * Remove the ACPI_USE_THREADS option.
Notes
Notes: svn path=/head/; revision=133612
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/acpica/acpi.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index a8fe9e755a6f..7c90b3298e03 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -71,7 +71,6 @@ static d_ioctl_t acpiioctl;
static struct cdevsw acpi_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
.d_open = acpiopen,
.d_close = acpiclose,
.d_ioctl = acpiioctl,
@@ -188,6 +187,8 @@ static devclass_t acpi_devclass;
DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0);
MODULE_VERSION(acpi, 1);
+ACPI_SERIAL_DECL(acpi, "ACPI root bus");
+
#define ACPI_MINIMUM_AWAKETIME 5
static const char* sleep_state_names[] = {
@@ -547,10 +548,8 @@ acpi_attach(device_t dev)
"acpi");
sc->acpi_dev_t->si_drv1 = sc;
-#ifdef ACPI_USE_THREADS
if ((error = acpi_task_thread_init()))
goto out;
-#endif
if ((error = acpi_machdep_init(dev)))
goto out;
@@ -757,6 +756,9 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
struct resource *res;
struct rman *rm;
+ res = NULL;
+ ACPI_SERIAL_BEGIN(acpi);
+
/*
* If this is an allocation of the "default" range for a given RID, and
* we know what the resources for this device are (i.e., they're on the
@@ -765,7 +767,7 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
if (start == 0UL && end == ~0UL) {
rle = resource_list_find(rl, type, *rid);
if (rle == NULL)
- return (NULL);
+ goto out;
start = rle->start;
end = rle->end;
count = rle->count;
@@ -794,7 +796,7 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
child);
if (res == NULL)
- return (NULL);
+ goto out;
/* Copy the bus tag and handle from the pre-allocated resource. */
rman_set_bustag(res, rman_get_bustag(rle->res));
@@ -804,7 +806,8 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
if (flags & RF_ACTIVE)
if (bus_activate_resource(child, type, *rid, res) != 0) {
rman_release_resource(res);
- return (NULL);
+ res = NULL;
+ goto out;
}
}
@@ -823,6 +826,9 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
acpi_config_intr(child, &ares);
break;
}
+
+out:
+ ACPI_SERIAL_END(acpi);
return (res);
}
@@ -832,6 +838,8 @@ acpi_release_resource(device_t bus, device_t child, int type, int rid,
{
int ret;
+ ACPI_SERIAL_BEGIN(acpi);
+
/*
* If we know about this address, deactivate it and release it to the
* local pool. If we don't, pass this request up to the parent.
@@ -840,12 +848,14 @@ acpi_release_resource(device_t bus, device_t child, int type, int rid,
if (rman_get_flags(r) & RF_ACTIVE) {
ret = bus_deactivate_resource(child, type, rid, r);
if (ret != 0)
- return (ret);
+ goto out;
}
ret = rman_release_resource(r);
} else
ret = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r);
+out:
+ ACPI_SERIAL_END(acpi);
return (ret);
}
@@ -1706,6 +1716,14 @@ acpi_sleep_enable(void *arg)
((struct acpi_softc *)arg)->acpi_sleep_disabled = 0;
}
+enum acpi_sleep_state {
+ ACPI_SS_NONE,
+ ACPI_SS_GPE_SET,
+ ACPI_SS_DEV_SUSPEND,
+ ACPI_SS_SLP_PREP,
+ ACPI_SS_SLEPT,
+};
+
/*
* Set the system sleep state
*
@@ -1714,20 +1732,26 @@ acpi_sleep_enable(void *arg)
ACPI_STATUS
acpi_SetSleepState(struct acpi_softc *sc, int state)
{
- ACPI_STATUS status = AE_OK;
+ ACPI_STATUS status;
UINT8 TypeA;
UINT8 TypeB;
+ enum acpi_sleep_state slp_state;
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
- /* Avoid reentry if already attempting to suspend. */
- if (sc->acpi_sstate != ACPI_STATE_S0)
- return_ACPI_STATUS (AE_BAD_PARAMETER);
-
- /* We recently woke up so don't suspend again for a while. */
- if (sc->acpi_sleep_disabled)
- return_ACPI_STATUS (AE_OK);
+ status = AE_OK;
+ ACPI_LOCK(acpi);
+ if (sc->acpi_sleep_disabled) {
+ if (sc->acpi_sstate != ACPI_STATE_S0)
+ status = AE_ERROR;
+ ACPI_UNLOCK(acpi);
+ printf("acpi: suspend request ignored (not ready yet)\n");
+ return (status);
+ }
+ sc->acpi_sleep_disabled = 1;
+ ACPI_UNLOCK(acpi);
+ slp_state = ACPI_SS_NONE;
switch (state) {
case ACPI_STATE_S1:
case ACPI_STATE_S2:
@@ -1745,10 +1769,10 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
}
sc->acpi_sstate = state;
- sc->acpi_sleep_disabled = 1;
/* Enable any GPEs as appropriate and requested by the user. */
acpi_wake_prep_walk(state);
+ slp_state = ACPI_SS_GPE_SET;
/*
* Inform all devices that we are going to sleep. If at least one
@@ -1758,8 +1782,11 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
* followed by a "real thing" pass would be better, but the current
* bus interface does not provide for this.
*/
- if (DEVICE_SUSPEND(root_bus) != 0)
- return_ACPI_STATUS (AE_ERROR);
+ if (DEVICE_SUSPEND(root_bus) != 0) {
+ device_printf(sc->acpi_dev, "device_suspend failed\n");
+ break;
+ }
+ slp_state = ACPI_SS_DEV_SUSPEND;
status = AcpiEnterSleepStatePrep(state);
if (ACPI_FAILURE(status)) {
@@ -1767,6 +1794,7 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
AcpiFormatException(status));
break;
}
+ slp_state = ACPI_SS_SLP_PREP;
if (sc->acpi_sleep_delay > 0)
DELAY(sc->acpi_sleep_delay * 1000000);
@@ -1786,13 +1814,7 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
break;
}
}
-
- /* Resume devices, re-enable GPEs and fixed events. */
- acpi_wake_prep_walk(state);
- AcpiLeaveSleepState((UINT8)state);
- DEVICE_RESUME(root_bus);
- sc->acpi_sstate = ACPI_STATE_S0;
- acpi_enable_fixed_events(sc);
+ slp_state = ACPI_SS_SLEPT;
break;
case ACPI_STATE_S5:
/*
@@ -1807,8 +1829,23 @@ acpi_SetSleepState(struct acpi_softc *sc, int state)
break;
}
- /* Disable a second sleep request for a short period */
- if (sc->acpi_sleep_disabled)
+ /*
+ * Back out state according to how far along we got in the suspend
+ * process. This handles both the error and success cases.
+ */
+ if (slp_state >= ACPI_SS_GPE_SET) {
+ acpi_wake_prep_walk(state);
+ sc->acpi_sstate = ACPI_STATE_S0;
+ }
+ if (slp_state >= ACPI_SS_DEV_SUSPEND)
+ DEVICE_RESUME(root_bus);
+ if (slp_state >= ACPI_SS_SLP_PREP)
+ AcpiLeaveSleepState(state);
+ if (slp_state >= ACPI_SS_SLEPT)
+ acpi_enable_fixed_events(sc);
+
+ /* Allow another sleep request after a while. */
+ if (state != ACPI_STATE_S5)
timeout(acpi_sleep_enable, (caddr_t)sc, hz * ACPI_MINIMUM_AWAKETIME);
return_ACPI_STATUS (status);
@@ -2123,10 +2160,12 @@ acpi_Enable(struct acpi_softc *sc)
flags = ACPI_NO_ADDRESS_SPACE_INIT | ACPI_NO_HARDWARE_INIT |
ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
+ ACPI_SERIAL_BEGIN(acpi);
if (!sc->acpi_enabled)
status = AcpiEnableSubsystem(flags);
if (ACPI_SUCCESS(status))
sc->acpi_enabled = 1;
+ ACPI_SERIAL_END(acpi);
return_ACPI_STATUS (status);
}
@@ -2139,10 +2178,12 @@ acpi_Disable(struct acpi_softc *sc)
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
status = AE_ERROR;
+ ACPI_SERIAL_BEGIN(acpi);
if (sc->acpi_enabled)
status = AcpiDisable();
if (ACPI_SUCCESS(status))
sc->acpi_enabled = 0;
+ ACPI_SERIAL_END(acpi);
return_ACPI_STATUS (status);
}
@@ -2347,30 +2388,33 @@ acpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg)
hp->cmd = cmd;
hp->fn = fn;
hp->arg = arg;
+
+ ACPI_LOCK(acpi);
if (acpi_ioctl_hooks_initted == 0) {
TAILQ_INIT(&acpi_ioctl_hooks);
acpi_ioctl_hooks_initted = 1;
}
TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
+ ACPI_UNLOCK(acpi);
+
return (0);
}
-/*
- * Deregister an ioctl handler.
- */
void
acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
{
struct acpi_ioctl_hook *hp;
+ ACPI_LOCK(acpi);
TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
- if ((hp->cmd == cmd) && (hp->fn == fn))
+ if (hp->cmd == cmd && hp->fn == fn)
break;
if (hp != NULL) {
TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
free(hp, M_ACPIDEV);
}
+ ACPI_UNLOCK(acpi);
}
static int
@@ -2399,11 +2443,13 @@ acpiioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
/*
* Scan the list of registered ioctls, looking for handlers.
*/
+ ACPI_LOCK(acpi);
if (acpi_ioctl_hooks_initted)
TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
if (hp->cmd == cmd)
break;
}
+ ACPI_UNLOCK(acpi);
if (hp)
return (hp->fn(cmd, addr, hp->arg));
@@ -2426,10 +2472,6 @@ acpiioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
error = ENXIO;
break;
case ACPIIO_SETSLPSTATE:
- if (!sc->acpi_enabled) {
- error = ENXIO;
- break;
- }
error = EINVAL;
state = *(int *)addr;
if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
@@ -2691,6 +2733,7 @@ acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
}
/* Get old values if this is a get request. */
+ ACPI_SERIAL_BEGIN(acpi);
if (*dbg == 0) {
sbuf_cpy(&sb, "NONE");
} else if (req->newptr == NULL) {
@@ -2712,6 +2755,7 @@ acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
setenv((char *)oidp->oid_arg1, (char *)req->newptr);
acpi_set_debugging(NULL);
}
+ ACPI_SERIAL_END(acpi);
return (error);
}