Revisit the wake-device code once more.

1. Remove the AcpiEnableGpe() call. This was wrong.

  2. Only call _PSW or _DSW for devices that are scheduled for wake.
     This was an old bug.

  3. Only enable wake GPEs during suspend. Disabling these for
     devices not setup for wake was causing problems.

  4. No wake GPEs should be enabled at runtime.
     Unconditionally disable these during resume.

This should make the wake-device code work again. Note that waking via
pckbd(4) has always been unreliable; the _PRW object is not typically located
under the PC keyboard object, but in the parent of it (e.g. the LPC bridge).
This commit is contained in:
jruoho 2011-02-19 09:52:32 +00:00
parent 01ec12c085
commit 3af8b2cb19
3 changed files with 47 additions and 69 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 jruoho Exp $ */
/* $NetBSD: acpi.c,v 1.237 2011/02/19 09:52:32 jruoho Exp $ */
/*-
* Copyright (c) 2003, 2007 The NetBSD Foundation, Inc.
@ -100,7 +100,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 jruoho Exp $");
__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.237 2011/02/19 09:52:32 jruoho Exp $");
#include "opt_acpi.h"
#include "opt_pcifixup.h"
@ -1389,6 +1389,7 @@ acpi_enter_sleep_state(int state)
(void)pmf_system_resume(PMF_Q_NONE);
}
acpi_wakedev_commit(sc, ACPI_STATE_S0);
break;
case ACPI_STATE_S5:

View File

@ -1,4 +1,4 @@
/* $NetBSD: acpi_wakedev.c,v 1.23 2011/02/18 13:56:03 jruoho Exp $ */
/* $NetBSD: acpi_wakedev.c,v 1.24 2011/02/19 09:52:32 jruoho Exp $ */
/*-
* Copyright (c) 2009, 2010, 2011 Jared D. McNeill <jmcneill@invisible.ca>
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.23 2011/02/18 13:56:03 jruoho Exp $");
__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.24 2011/02/19 09:52:32 jruoho Exp $");
#include <sys/param.h>
#include <sys/device.h>
@ -54,8 +54,8 @@ static const char * const acpi_wakedev_default[] = {
static int32_t acpi_wakedev_acpinode = CTL_EOL;
static int32_t acpi_wakedev_wakenode = CTL_EOL;
static void acpi_wakedev_power(struct acpi_devnode *, ACPI_OBJECT *);
static void acpi_wakedev_set(struct acpi_devnode *, int);
static void acpi_wakedev_power_add(struct acpi_devnode *, ACPI_OBJECT *);
static void acpi_wakedev_power_set(struct acpi_devnode *, bool);
static void acpi_wakedev_method(struct acpi_devnode *, int);
void
@ -143,13 +143,13 @@ acpi_wakedev_init(struct acpi_devnode *ad)
elm = &obj->Package.Elements[1];
if (elm->Type == ACPI_TYPE_INTEGER)
ad->ad_wakedev->aw_sleep = elm->Integer.Value;
ad->ad_wakedev->aw_state = elm->Integer.Value;
/*
* The rest of the elements are reference
* handles to power resources. Store these.
*/
acpi_wakedev_power(ad, obj);
acpi_wakedev_power_add(ad, obj);
/*
* Last but not least, mark the GPE for wake.
@ -166,7 +166,7 @@ out:
}
static void
acpi_wakedev_power(struct acpi_devnode *ad, ACPI_OBJECT *obj)
acpi_wakedev_power_add(struct acpi_devnode *ad, ACPI_OBJECT *obj)
{
struct acpi_wakedev *aw = ad->ad_wakedev;
uint32_t i, j, n;
@ -194,6 +194,21 @@ acpi_wakedev_power(struct acpi_devnode *ad, ACPI_OBJECT *obj)
}
}
static void
acpi_wakedev_power_set(struct acpi_devnode *ad, bool enable)
{
struct acpi_wakedev *aw = ad->ad_wakedev;
uint8_t i;
for (i = 0; i < __arraycount(aw->aw_power); i++) {
if (aw->aw_power[i] == NULL)
continue;
(void)acpi_power_res(aw->aw_power[i], ad->ad_handle, enable);
}
}
void
acpi_wakedev_add(struct acpi_devnode *ad)
{
@ -277,79 +292,41 @@ void
acpi_wakedev_commit(struct acpi_softc *sc, int state)
{
struct acpi_devnode *ad;
ACPI_INTEGER val;
ACPI_HANDLE hdl;
/*
* To prepare a device for wakeup:
*
* 1. Set appropriate GPEs.
* 1. Set the wake GPE.
*
* 2. Enable all power resources in _PRW.
* 2. Turn on power resources.
*
* 3. If present, execute _DSW/_PSW method.
* 3. Execute _DSW or _PSW method.
*/
SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
if (ad->ad_wakedev == NULL)
continue;
acpi_wakedev_set(ad, state);
if (state > ad->ad_wakedev->aw_state)
continue;
hdl = ad->ad_wakedev->aw_handle;
val = ad->ad_wakedev->aw_number;
if (state == ACPI_STATE_S0) {
(void)AcpiSetGpeWakeMask(hdl, val, ACPI_GPE_DISABLE);
continue;
}
(void)AcpiSetGpeWakeMask(hdl, val, ACPI_GPE_ENABLE);
acpi_wakedev_power_set(ad, true);
acpi_wakedev_method(ad, state);
}
}
static void
acpi_wakedev_set(struct acpi_devnode *ad, int state)
{
struct acpi_wakedev *aw = ad->ad_wakedev;
ACPI_INTEGER val = aw->aw_number;
ACPI_HANDLE hdl = aw->aw_handle;
ACPI_STATUS rv;
uint8_t i;
/*
* Enable or disable wake GPEs.
*/
if (aw->aw_enable != true)
rv = AcpiSetGpeWakeMask(hdl, val, ACPI_GPE_DISABLE);
else {
rv = AcpiSetGpeWakeMask(hdl, val, ACPI_GPE_ENABLE);
if (ACPI_FAILURE(rv))
goto out;
rv = AcpiEnableGpe(hdl, val);
if (ACPI_FAILURE(rv))
goto out;
/*
* Turn power resources on.
*
* XXX: We should also turn these off for devices
* that are not allowed to wake the system.
* However, as these are not yet integrated
* with pmf(9), we can not risk devices to
* possibly resume in a power-off state.
*/
for (i = 0; i < __arraycount(aw->aw_power); i++) {
if (aw->aw_power[i] == NULL)
continue;
(void)acpi_power_res(aw->aw_power[i], hdl, true);
}
}
out:
if (state > aw->aw_sleep)
aprint_error_dev(ad->ad_root, "sleep state S%d "
"loses wake for %s\n", state, ad->ad_name);
if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
aprint_error_dev(ad->ad_root, "failed to set wake GPE "
"for %s: %s\n", ad->ad_name, AcpiFormatException(rv));
}
static void
acpi_wakedev_method(struct acpi_devnode *ad, int state)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: acpi_wakedev.h,v 1.5 2011/02/17 19:36:49 jruoho Exp $ */
/* $NetBSD: acpi_wakedev.h,v 1.6 2011/02/19 09:52:32 jruoho Exp $ */
/*-
* Copyright (c) 2009, 2011 Jared D. McNeill <jmcneill@invisible.ca>
@ -33,8 +33,8 @@ struct acpi_wakedev {
ACPI_HANDLE aw_power[8]; /* Power resources */
ACPI_HANDLE aw_handle; /* Wake GPE handle */
ACPI_INTEGER aw_number; /* Wake GPE number */
ACPI_INTEGER aw_sleep; /* Highest sleep state for wake */
bool aw_enable; /* Wake enabled? */
ACPI_INTEGER aw_state; /* Highest sleep state for wake */
bool aw_enable; /* Wake enabled (sysctl)? */
};
void acpi_wakedev_init(struct acpi_devnode *);