1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-27 11:55:06 +00:00

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.
This commit is contained in:
Nate Lawson 2004-08-13 06:21:32 +00:00
parent 3a9865dd34
commit 15e2f34f90
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=133612

View File

@ -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);
}