Module Name: src
Committed By: jruoho
Date: Thu Feb 17 19:36:49 UTC 2011
Modified Files:
src/sys/dev/acpi: acpi.c acpi_wakedev.c acpi_wakedev.h acpivar.h
Log Message:
As explained in the new ACPICA documentation, as of ACPICA 20101207, the
_PRW methods are no longer automatically executed as part of the ACPICA
initialization. Refactor and rewrite the wake-device code to account this.
To generate a diff of this commit:
cvs rdiff -u -r1.235 -r1.236 src/sys/dev/acpi/acpi.c
cvs rdiff -u -r1.21 -r1.22 src/sys/dev/acpi/acpi_wakedev.c
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/acpi/acpi_wakedev.h
cvs rdiff -u -r1.67 -r1.68 src/sys/dev/acpi/acpivar.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/acpi/acpi.c
diff -u src/sys/dev/acpi/acpi.c:1.235 src/sys/dev/acpi/acpi.c:1.236
--- src/sys/dev/acpi/acpi.c:1.235 Tue Feb 15 20:24:11 2011
+++ src/sys/dev/acpi/acpi.c Thu Feb 17 19:36:49 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi.c,v 1.235 2011/02/15 20:24:11 jruoho Exp $ */
+/* $NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 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.235 2011/02/15 20:24:11 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.236 2011/02/17 19:36:49 jruoho Exp $");
#include "opt_acpi.h"
#include "opt_pcifixup.h"
@@ -685,6 +685,14 @@
(void)acpi_rescan(sc->sc_dev, NULL, NULL);
/*
+ * Update GPE information.
+ *
+ * Note that this must be called after
+ * all GPE handlers have been installed.
+ */
+ (void)AcpiUpdateAllGpes();
+
+ /*
* Defer rest of the configuration.
*/
(void)config_defer(sc->sc_dev, acpi_rescan_capabilities);
@@ -724,6 +732,7 @@
ad->ad_device = NULL;
ad->ad_notify = NULL;
ad->ad_pciinfo = NULL;
+ ad->ad_wakedev = NULL;
ad->ad_type = type;
ad->ad_handle = handle;
@@ -735,6 +744,13 @@
acpi_set_node(ad);
acpi_make_name(ad, devinfo->Name);
+ /*
+ * Identify wake GPEs from the _PRW. Note that
+ * AcpiUpdateAllGpes() must be called afterwards.
+ */
+ if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE)
+ acpi_wakedev_init(ad);
+
SIMPLEQ_INIT(&ad->ad_child_head);
SIMPLEQ_INSERT_TAIL(&sc->ad_head, ad, ad_list);
@@ -940,9 +956,7 @@
/*
* Scan wake-up capabilities.
*/
- rv = AcpiGetHandle(ad->ad_handle, "_PRW", &tmp);
-
- if (ACPI_SUCCESS(rv)) {
+ if (ad->ad_wakedev != NULL) {
ad->ad_flags |= ACPI_DEVICE_WAKEUP;
acpi_wakedev_add(ad);
}
Index: src/sys/dev/acpi/acpi_wakedev.c
diff -u src/sys/dev/acpi/acpi_wakedev.c:1.21 src/sys/dev/acpi/acpi_wakedev.c:1.22
--- src/sys/dev/acpi/acpi_wakedev.c:1.21 Thu Feb 17 10:49:29 2011
+++ src/sys/dev/acpi/acpi_wakedev.c Thu Feb 17 19:36:49 2011
@@ -1,7 +1,7 @@
-/* $NetBSD: acpi_wakedev.c,v 1.21 2011/02/17 10:49:29 jruoho Exp $ */
+/* $NetBSD: acpi_wakedev.c,v 1.22 2011/02/17 19:36:49 jruoho Exp $ */
/*-
- * Copyright (c) 2009, 2010 Jared D. McNeill <[email protected]>
+ * Copyright (c) 2009, 2010, 2011 Jared D. McNeill <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.21 2011/02/17 10:49:29 jruoho Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_wakedev.c,v 1.22 2011/02/17 19:36:49 jruoho Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
@@ -51,62 +52,164 @@
NULL,
};
+MALLOC_DECLARE(M_ACPI);
+
static int32_t acpi_wakedev_acpinode = CTL_EOL;
static int32_t acpi_wakedev_wakenode = CTL_EOL;
-static void acpi_wakedev_method(struct acpi_devnode *, int, int);
-static void acpi_wakedev_gpe(struct acpi_devnode *, int, int);
static void acpi_wakedev_power(struct acpi_devnode *, ACPI_OBJECT *);
+static void acpi_wakedev_set(struct acpi_devnode *, int);
+static void acpi_wakedev_method(struct acpi_devnode *, int);
-SYSCTL_SETUP(sysctl_acpi_wakedev_setup, "sysctl hw.acpi.wake subtree setup")
+void
+acpi_wakedev_init(struct acpi_devnode *ad)
{
- const struct sysctlnode *rnode;
- int err;
+ ACPI_OBJECT *elm, *obj;
+ ACPI_HANDLE hdl = NULL;
+ ACPI_INTEGER val = 0;
+ ACPI_BUFFER buf;
+ ACPI_STATUS rv;
- err = sysctl_createv(NULL, 0, NULL, &rnode,
- CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw",
- NULL, NULL, 0, NULL, 0,
- CTL_HW, CTL_EOL);
+ rv = acpi_eval_struct(ad->ad_handle, "_PRW", &buf);
- if (err != 0)
- return;
+ if (ACPI_FAILURE(rv))
+ goto out;
- err = sysctl_createv(NULL, 0, &rnode, &rnode,
- CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi",
- NULL, NULL, 0, NULL, 0,
- CTL_CREATE, CTL_EOL);
+ obj = buf.Pointer;
- if (err != 0)
+ if (obj->Type != ACPI_TYPE_PACKAGE) {
+ rv = AE_TYPE;
+ goto out;
+ }
+
+ if (obj->Package.Count < 2) {
+ rv = AE_LIMIT;
+ goto out;
+ }
+
+ /*
+ * As noted in ACPI 3.0 (section 7.2.10), the _PRW object is
+ * a package in which the first element is either an integer
+ * or again a package. In the latter case the package inside
+ * the package element has two elements, a reference handle
+ * and the GPE number.
+ */
+ elm = &obj->Package.Elements[0];
+
+ switch (elm->Type) {
+
+ case ACPI_TYPE_INTEGER:
+ val = elm->Integer.Value;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+
+ if (elm->Package.Count < 2) {
+ rv = AE_LIMIT;
+ goto out;
+ }
+
+ rv = AE_TYPE;
+
+ if (elm->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE)
+ goto out;
+
+ if (elm->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
+ goto out;
+
+ hdl = elm->Package.Elements[0].Reference.Handle;
+ val = elm->Package.Elements[1].Integer.Value;
+ break;
+
+ default:
+ rv = AE_TYPE;
+ goto out;
+ }
+
+ ad->ad_wakedev = malloc(sizeof(*ad->ad_wakedev),
+ M_ACPI, M_NOWAIT | M_ZERO);
+
+ if (ad->ad_wakedev == NULL)
return;
- acpi_wakedev_acpinode = rnode->sysctl_num;
+ ad->ad_wakedev->aw_handle = hdl;
+ ad->ad_wakedev->aw_number = val;
- err = sysctl_createv(NULL, 0, &rnode, &rnode,
- CTLFLAG_PERMANENT, CTLTYPE_NODE,
- "wake", SYSCTL_DESCR("ACPI device wake-up"),
- NULL, 0, NULL, 0,
- CTL_CREATE, CTL_EOL);
+ /*
+ * The second element in _PRW is an integer
+ * that contains the lowest sleep state that
+ * can be entered while still providing wakeup.
+ */
+ elm = &obj->Package.Elements[1];
- if (err != 0)
+ if (elm->Type == ACPI_TYPE_INTEGER)
+ ad->ad_wakedev->aw_sleep = elm->Integer.Value;
+
+ /*
+ * Rest of the elements are references
+ * to power resources. Store these.
+ */
+ acpi_wakedev_power(ad, obj);
+
+ /*
+ * Last but not least, mark GPEs for wake.
+ */
+ rv = AcpiSetupGpeForWake(ad->ad_handle, hdl, val);
+
+out:
+ if (buf.Pointer != NULL)
+ ACPI_FREE(buf.Pointer);
+
+ if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
+ aprint_error_dev(ad->ad_root, "failed to evaluate _PRW "
+ "for %s: %s\n", ad->ad_name, AcpiFormatException(rv));
+}
+
+static void
+acpi_wakedev_power(struct acpi_devnode *ad, ACPI_OBJECT *obj)
+{
+ struct acpi_wakedev *aw = ad->ad_wakedev;
+ uint32_t i, j, n;
+ ACPI_OBJECT *elm;
+ ACPI_HANDLE hdl;
+ ACPI_STATUS rv;
+
+ for (i = 0; i < __arraycount(aw->aw_power); i++)
+ aw->aw_power[i] = NULL;
+
+ n = obj->Package.Count;
+
+ if (n < 3 || n - 2 > __arraycount(aw->aw_power))
return;
- acpi_wakedev_wakenode = rnode->sysctl_num;
+ for (i = 2, j = 0; i < n; i++, j++) {
+
+ elm = &obj->Package.Elements[i];
+ rv = acpi_eval_reference_handle(elm, &hdl);
+
+ if (ACPI_FAILURE(rv))
+ continue;
+
+ ad->ad_wakedev->aw_power[j] = hdl;
+ }
}
void
acpi_wakedev_add(struct acpi_devnode *ad)
{
+ struct acpi_wakedev *aw;
const char *str = NULL;
device_t dev;
int err;
- KASSERT(ad != NULL && ad->ad_root != NULL);
+ KASSERT(ad != NULL && ad->ad_wakedev != NULL);
KASSERT((ad->ad_flags & ACPI_DEVICE_WAKEUP) != 0);
- ad->ad_wake = 0;
+ aw = ad->ad_wakedev;
+ aw->aw_enable = false;
if (acpi_match_hid(ad->ad_devinfo, acpi_wakedev_default))
- ad->ad_wake = 1;
+ ad->ad_wakedev->aw_enable = true;
if (acpi_wakedev_acpinode == CTL_EOL ||
acpi_wakedev_wakenode == CTL_EOL)
@@ -126,7 +229,7 @@
err = sysctl_createv(NULL, 0, NULL, NULL,
CTLFLAG_READWRITE, CTLTYPE_BOOL, str,
- NULL, NULL, 0, &ad->ad_wake, 0, CTL_HW,
+ NULL, NULL, 0, &ad->ad_wakedev->aw_enable, 0, CTL_HW,
acpi_wakedev_acpinode, acpi_wakedev_wakenode,
CTL_CREATE, CTL_EOL);
@@ -135,6 +238,41 @@
"(hw.acpi.wake.%s) failed (err %d)\n", str, err);
}
+SYSCTL_SETUP(sysctl_acpi_wakedev_setup, "sysctl hw.acpi.wake subtree setup")
+{
+ const struct sysctlnode *rnode;
+ int err;
+
+ err = sysctl_createv(NULL, 0, NULL, &rnode,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw",
+ NULL, NULL, 0, NULL, 0,
+ CTL_HW, CTL_EOL);
+
+ if (err != 0)
+ return;
+
+ err = sysctl_createv(NULL, 0, &rnode, &rnode,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi",
+ NULL, NULL, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL);
+
+ if (err != 0)
+ return;
+
+ acpi_wakedev_acpinode = rnode->sysctl_num;
+
+ err = sysctl_createv(NULL, 0, &rnode, &rnode,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE,
+ "wake", SYSCTL_DESCR("ACPI device wake-up"),
+ NULL, 0, NULL, 0,
+ CTL_CREATE, CTL_EOL);
+
+ if (err != 0)
+ return;
+
+ acpi_wakedev_wakenode = rnode->sysctl_num;
+}
+
void
acpi_wakedev_commit(struct acpi_softc *sc, int state)
{
@@ -151,17 +289,66 @@
*/
SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
- if ((ad->ad_flags & ACPI_DEVICE_WAKEUP) == 0)
+ if (ad->ad_wakedev == NULL)
continue;
- acpi_wakedev_gpe(ad, ad->ad_wake, state);
- acpi_wakedev_method(ad, ad->ad_wake, state);
+ acpi_wakedev_set(ad, state);
+ acpi_wakedev_method(ad, state);
}
}
static void
-acpi_wakedev_method(struct acpi_devnode *ad, int enable, int state)
+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 on power resources.
+ */
+ 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);
+ }
+ }
+
+ if (state > aw->aw_sleep)
+ aprint_error_dev(ad->ad_root, "sleep state S%d "
+ "loses wake for %s\n", state, ad->ad_name);
+
+out:
+ 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)
+{
+ const bool enable = ad->ad_wakedev->aw_enable;
ACPI_OBJECT_LIST arg;
ACPI_OBJECT obj[3];
ACPI_STATUS rv;
@@ -211,122 +398,3 @@
aprint_error_dev(ad->ad_root, "failed to evaluate wake "
"control method: %s\n", AcpiFormatException(rv));
}
-
-static void
-acpi_wakedev_gpe(struct acpi_devnode *ad, int enable, int state)
-{
- ACPI_OBJECT *elm, *obj;
- ACPI_HANDLE hdl = NULL;
- ACPI_INTEGER val;
- ACPI_BUFFER buf;
- ACPI_STATUS rv;
-
- rv = acpi_eval_struct(ad->ad_handle, "_PRW", &buf);
-
- if (ACPI_FAILURE(rv))
- return;
-
- obj = buf.Pointer;
-
- if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count < 2)
- goto out;
-
- /*
- * As noted in ACPI 3.0 (section 7.2.10), the _PRW object is
- * a package in which the first element is either an integer
- * or again a package. In the latter case the package inside
- * the package element has two elements, a reference handle
- * and the GPE number.
- */
- elm = &obj->Package.Elements[0];
-
- switch (elm->Type) {
-
- case ACPI_TYPE_INTEGER:
- val = elm->Integer.Value;
- break;
-
- case ACPI_TYPE_PACKAGE:
-
- if (elm->Package.Count < 2)
- goto out;
-
- if (elm->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE)
- goto out;
-
- if (elm->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
- goto out;
-
- hdl = elm->Package.Elements[0].Reference.Handle;
- val = elm->Package.Elements[1].Integer.Value;
- break;
-
- default:
- goto out;
- }
-
- /*
- * The second element is an integer that contains the
- * lowest sleep state that can be entered while still
- * providing wake-up functionality. The rest of the
- * elements are references to power resources.
- */
- elm = &obj->Package.Elements[1];
-
- if (elm->Type != ACPI_TYPE_INTEGER)
- goto out;
-
- if (state > elm->Integer.Value)
- aprint_error_dev(ad->ad_root, "sleep state S%d "
- "loses wake for %s\n", state, ad->ad_name);
-
- /*
- * Turn on power resources.
- */
- if (enable != 0)
- acpi_wakedev_power(ad, obj);
-
- /*
- * This affects only wake GPEs, provided that _PRW works.
- */
- if (enable != 0)
- (void)AcpiSetGpe(hdl, val, ACPI_GPE_ENABLE);
- else
- (void)AcpiSetGpe(hdl, val, ACPI_GPE_DISABLE);
-
- /*
- * XXX: Is this right?
- */
- (void)AcpiUpdateAllGpes();
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "wake GPE %s for %s\n",
- (enable != 0) ? "enabled" : "disabled", ad->ad_name));
-
-out:
- ACPI_FREE(buf.Pointer);
-}
-
-static void
-acpi_wakedev_power(struct acpi_devnode *ad, ACPI_OBJECT *obj)
-{
- ACPI_OBJECT *elm;
- ACPI_HANDLE hdl;
- ACPI_STATUS rv;
- uint32_t i, n;
-
- n = obj->Package.Count;
-
- if (n < 3)
- return;
-
- for (i = 2; i < n; i++) {
-
- elm = &obj->Package.Elements[i];
- rv = acpi_eval_reference_handle(elm, &hdl);
-
- if (ACPI_FAILURE(rv))
- continue;
-
- (void)acpi_power_res(hdl, ad->ad_handle, true);
- }
-}
Index: src/sys/dev/acpi/acpi_wakedev.h
diff -u src/sys/dev/acpi/acpi_wakedev.h:1.4 src/sys/dev/acpi/acpi_wakedev.h:1.5
--- src/sys/dev/acpi/acpi_wakedev.h:1.4 Tue Mar 16 05:48:43 2010
+++ src/sys/dev/acpi/acpi_wakedev.h Thu Feb 17 19:36:49 2011
@@ -1,7 +1,7 @@
-/* $NetBSD: acpi_wakedev.h,v 1.4 2010/03/16 05:48:43 jruoho Exp $ */
+/* $NetBSD: acpi_wakedev.h,v 1.5 2011/02/17 19:36:49 jruoho Exp $ */
/*-
- * Copyright (c) 2009 Jared D. McNeill <[email protected]>
+ * Copyright (c) 2009, 2011 Jared D. McNeill <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,16 @@
#ifndef _SYS_DEV_ACPI_ACPI_WAKEDEV_H
#define _SYS_DEV_ACPI_ACPI_WAKEDEV_H
-void acpi_wakedev_add(struct acpi_devnode *);
-void acpi_wakedev_commit(struct acpi_softc *, int);
+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? */
+};
+
+void acpi_wakedev_init(struct acpi_devnode *);
+void acpi_wakedev_add(struct acpi_devnode *);
+void acpi_wakedev_commit(struct acpi_softc *, int);
#endif /* !_SYS_DEV_ACPI_ACPI_WAKEDEV_H */
Index: src/sys/dev/acpi/acpivar.h
diff -u src/sys/dev/acpi/acpivar.h:1.67 src/sys/dev/acpi/acpivar.h:1.68
--- src/sys/dev/acpi/acpivar.h:1.67 Mon Jan 17 15:49:13 2011
+++ src/sys/dev/acpi/acpivar.h Thu Feb 17 19:36:49 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: acpivar.h,v 1.67 2011/01/17 15:49:13 jmcneill Exp $ */
+/* $NetBSD: acpivar.h,v 1.68 2011/02/17 19:36:49 jruoho Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -108,6 +108,7 @@
* ad_root never NULL
* ad_parent only NULL if root of the tree ("\")
* ad_pciinfo NULL if not a PCI device
+ * ad_wakedev NULL if no wakeup capabilities
* ad_notify NULL if there is no notify handler
* ad_devinfo never NULL
* ad_handle never NULL
@@ -120,6 +121,7 @@
device_t ad_root; /* Backpointer to acpi_softc */
struct acpi_devnode *ad_parent; /* Backpointer to parent */
struct acpi_pci_info *ad_pciinfo; /* PCI info */
+ struct acpi_wakedev *ad_wakedev; /* Device wake */
ACPI_NOTIFY_HANDLER ad_notify; /* Device notify */
ACPI_DEVICE_INFO *ad_devinfo; /* Device info */
ACPI_HANDLE ad_handle; /* Device handle */
@@ -127,7 +129,6 @@
uint32_t ad_flags; /* Device flags */
uint32_t ad_type; /* Device type */
int ad_state; /* Device power state */
- int ad_wake; /* Device wakeup */
SIMPLEQ_ENTRY(acpi_devnode) ad_list;
SIMPLEQ_ENTRY(acpi_devnode) ad_child_list;