summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2013-11-06 10:40:37 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2013-11-06 10:40:37 +0000
commit1b2cca43962b305f5786dcdfc424ca22ce44cce6 (patch)
tree47f46e685c87dffdf5bee15e7cb55f4aee71f6a9 /sys
parent65d3cf7e6b97615ce69a5bc0815fcdd5f188376e (diff)
Add support for Power Resources for Dx states and the necessary hook
for PCI devices. This hook should be called twice, before and after changing the power state of a PCI device. Before setting the device to the new state, the ACPI layer will notify every power resources linked to the device for that state and make sure they are turned "_ON". After changing the state of the device, it will decrement the reference of every power resources linked to that device for the old state and turn them "_OFF" if they are no longer referenced. This fixes the no-USB after resume problem seen on various ThinkPad, problem initialy diagnosed with Alexander Polakov. ok kettenis@, deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/include/pci_machdep.h3
-rw-r--r--sys/arch/amd64/pci/pci_machdep.c16
-rw-r--r--sys/arch/i386/pci/pci_machdep.c16
-rw-r--r--sys/arch/i386/pci/pci_machdep.h3
-rw-r--r--sys/dev/acpi/acpi.c92
-rw-r--r--sys/dev/acpi/acpipwrres.c240
-rw-r--r--sys/dev/acpi/acpireg.h10
-rw-r--r--sys/dev/acpi/acpivar.h26
-rw-r--r--sys/dev/acpi/files.acpi4
9 files changed, 322 insertions, 88 deletions
diff --git a/sys/arch/amd64/include/pci_machdep.h b/sys/arch/amd64/include/pci_machdep.h
index 51894074a34..395970faffd 100644
--- a/sys/arch/amd64/include/pci_machdep.h
+++ b/sys/arch/amd64/include/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.21 2012/09/19 23:23:50 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.22 2013/11/06 10:40:36 mpi Exp $ */
/* $NetBSD: pci_machdep.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */
/*
@@ -95,6 +95,7 @@ void pci_decompose_tag(pci_chipset_tag_t, pcitag_t,
void pci_dev_postattach(struct device *, struct pci_attach_args *);
pcireg_t pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
+void pci_set_powerstate_md(pci_chipset_tag_t, pcitag_t, int, int);
/*
* ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
diff --git a/sys/arch/amd64/pci/pci_machdep.c b/sys/arch/amd64/pci/pci_machdep.c
index b6afa739d27..9fac42f5785 100644
--- a/sys/arch/amd64/pci/pci_machdep.c
+++ b/sys/arch/amd64/pci/pci_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.c,v 1.57 2013/05/30 16:19:25 deraadt Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.58 2013/11/06 10:40:36 mpi Exp $ */
/* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */
/*-
@@ -665,6 +665,8 @@ pci_init_extents(void)
#include "acpi.h"
#if NACPI > 0
void acpi_pci_match(struct device *, struct pci_attach_args *);
+pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
+void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
#endif
void
@@ -675,10 +677,6 @@ pci_dev_postattach(struct device *dev, struct pci_attach_args *pa)
#endif
}
-#if NACPI > 0
-pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
-#endif
-
pcireg_t
pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
{
@@ -688,3 +686,11 @@ pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
return pci_get_powerstate(pc, tag);
#endif
}
+
+void
+pci_set_powerstate_md(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre)
+{
+#if NACPI > 0
+ acpi_pci_set_powerstate(pc, tag, state, pre);
+#endif
+}
diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c
index 374a7373842..d7b394a81c5 100644
--- a/sys/arch/i386/pci/pci_machdep.c
+++ b/sys/arch/i386/pci/pci_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.c,v 1.76 2013/07/10 21:31:12 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.77 2013/11/06 10:40:36 mpi Exp $ */
/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
/*-
@@ -941,6 +941,8 @@ pci_init_extents(void)
#include "acpi.h"
#if NACPI > 0
void acpi_pci_match(struct device *, struct pci_attach_args *);
+pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
+void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
#endif
void
@@ -951,10 +953,6 @@ pci_dev_postattach(struct device *dev, struct pci_attach_args *pa)
#endif
}
-#if NACPI > 0
-pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
-#endif
-
pcireg_t
pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
{
@@ -964,3 +962,11 @@ pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
return pci_get_powerstate(pc, tag);
#endif
}
+
+void
+pci_set_powerstate_md(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre)
+{
+#if NACPI > 0
+ acpi_pci_set_powerstate(pc, tag, state, pre);
+#endif
+}
diff --git a/sys/arch/i386/pci/pci_machdep.h b/sys/arch/i386/pci/pci_machdep.h
index 1a45e9c9537..d6c298cb8c0 100644
--- a/sys/arch/i386/pci/pci_machdep.h
+++ b/sys/arch/i386/pci/pci_machdep.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_machdep.h,v 1.25 2012/09/19 23:03:12 kettenis Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.26 2013/11/06 10:40:36 mpi Exp $ */
/* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */
/*
@@ -111,6 +111,7 @@ void pci_decompose_tag(pci_chipset_tag_t, pcitag_t,
void pci_dev_postattach(struct device *, struct pci_attach_args *);
pcireg_t pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
+void pci_set_powerstate_md(pci_chipset_tag_t, pcitag_t, int, int);
/*
* Section 6.2.4, `Miscellaneous Functions' of the PIC Specification,
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index 9d65faa395c..1683dbdc36c 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.246 2013/06/01 23:00:16 mlarkin Exp $ */
+/* $OpenBSD: acpi.c,v 1.247 2013/11/06 10:40:36 mpi Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -74,6 +74,7 @@ int acpi_hasprocfvs;
void acpi_pci_match(struct device *, struct pci_attach_args *);
pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
+void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
int acpi_match(struct device *, void *, void *);
void acpi_attach(struct device *, struct device *, void *);
@@ -559,15 +560,26 @@ void
acpi_pci_match(struct device *dev, struct pci_attach_args *pa)
{
struct acpi_pci *pdev;
+ int state;
TAILQ_FOREACH(pdev, &acpi_pcidevs, next) {
- if (pdev->bus == pa->pa_bus &&
- pdev->dev == pa->pa_device &&
- pdev->fun == pa->pa_function) {
- dnprintf(10,"%s at acpi0 %s\n",
- dev->dv_xname, aml_nodename(pdev->node));
- pdev->device = dev;
- }
+ if (pdev->bus != pa->pa_bus ||
+ pdev->dev != pa->pa_device ||
+ pdev->fun != pa->pa_function)
+ continue;
+
+ dnprintf(10,"%s at acpi0 %s\n", dev->dv_xname,
+ aml_nodename(pdev->node));
+
+ pdev->device = dev;
+
+ /*
+ * If some Power Resources are dependent on this device
+ * initialize them.
+ */
+ state = pci_get_powerstate(pa->pa_pc, pa->pa_tag);
+ acpi_pci_set_powerstate(pa->pa_pc, pa->pa_tag, state, 1);
+ acpi_pci_set_powerstate(pa->pa_pc, pa->pa_tag, state, 0);
}
}
@@ -604,6 +616,66 @@ acpi_pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
}
void
+acpi_pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre)
+{
+#if NACPIPWRRES > 0
+ struct acpi_softc *sc = acpi_softc;
+ struct acpi_pwrres *pr;
+ struct acpi_pci *pdev;
+ int bus, dev, fun;
+ char name[5];
+
+ pci_decompose_tag(pc, tag, &bus, &dev, &fun);
+ TAILQ_FOREACH(pdev, &acpi_pcidevs, next) {
+ if (pdev->bus == bus && pdev->dev == dev && pdev->fun == fun)
+ break;
+ }
+
+ /* XXX Add a check to discard nodes without Power Resources? */
+ if (pdev == NULL)
+ return;
+
+ SIMPLEQ_FOREACH(pr, &sc->sc_pwrresdevs, p_next) {
+ if (pr->p_node != pdev->node)
+ continue;
+
+ /*
+ * If the firmware is already aware that the device
+ * is in the given state, there's nothing to do.
+ */
+ if (pr->p_state == state)
+ continue;
+
+ if (pre) {
+ /*
+ * If a Resource is dependent on this device for
+ * the given state, make sure it is turned "_ON".
+ */
+ if (pr->p_res_state == state)
+ acpipwrres_ref_incr(pr->p_res_sc, pr->p_node);
+ } else {
+ /*
+ * If a Resource was referenced for the state we
+ * left, drop a reference and turn it "_OFF" if
+ * it was the last one.
+ */
+ if (pr->p_res_state == pr->p_state)
+ acpipwrres_ref_decr(pr->p_res_sc, pr->p_node);
+
+ if (pr->p_res_state == state) {
+ snprintf(name, sizeof(name), "_PS%d", state);
+ aml_evalname(sc, pr->p_node, name, 0,
+ NULL, NULL);
+ }
+
+ pr->p_state = state;
+ }
+
+ }
+#endif /* NACPIPWRRES > 0 */
+}
+
+void
acpi_pciroots_attach(struct device *dev, void *aux, cfprint_t pr)
{
struct acpi_pci *pdev;
@@ -658,6 +730,10 @@ acpi_attach(struct device *parent, struct device *self, void *aux)
SIMPLEQ_INIT(&sc->sc_tables);
SIMPLEQ_INIT(&sc->sc_wakedevs);
+#if NACPIPWRRES > 0
+ SIMPLEQ_INIT(&sc->sc_pwrresdevs);
+#endif /* NACPIPWRRES > 0 */
+
#ifndef SMALL_KERNEL
sc->sc_note = malloc(sizeof(struct klist), M_DEVBUF, M_NOWAIT | M_ZERO);
diff --git a/sys/dev/acpi/acpipwrres.c b/sys/dev/acpi/acpipwrres.c
index 8f3afccdbc7..56c4c89103b 100644
--- a/sys/dev/acpi/acpipwrres.c
+++ b/sys/dev/acpi/acpipwrres.c
@@ -1,5 +1,7 @@
-/* $OpenBSD: acpipwrres.c,v 1.4 2010/07/21 19:35:15 deraadt Exp $ */
+/* $OpenBSD: acpipwrres.c,v 1.5 2013/11/06 10:40:36 mpi Exp $ */
+
/*
+ * Copyright (c) 2013 Martin Pieuchot <mpi@openbsd.org>
* Copyright (c) 2009 Paul Irofti <pirofti@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -14,6 +16,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
@@ -31,10 +34,6 @@
int acpipwrres_match(struct device *, void *, void *);
void acpipwrres_attach(struct device *, struct device *, void *);
-int acpipwrres_notify(struct aml_node *, int, void *);
-
-#define NOTIFY_PWRRES_OFF 0
-#define NOTIFY_PWRRES_ON 1
#ifdef ACPIPWRRES_DEBUG
#define DPRINTF(x) printf x
@@ -51,11 +50,11 @@ struct acpipwrres_softc {
struct acpi_softc *sc_acpi;
struct aml_node *sc_devnode;
- TAILQ_HEAD(acpipwrres_cons_h, acpipwrres_consumer) sc_cons;
+ SIMPLEQ_HEAD(, acpipwrres_consumer) sc_cons;
+ int sc_cons_ref;
int sc_level;
int sc_order;
- int sc_ncons;
int sc_state;
#define ACPIPWRRES_OFF 0
#define ACPIPWRRES_ON 1
@@ -64,7 +63,7 @@ struct acpipwrres_softc {
struct acpipwrres_consumer {
struct aml_node *cs_node;
- TAILQ_ENTRY(acpipwrres_consumer) cs_link;
+ SIMPLEQ_ENTRY(acpipwrres_consumer) cs_next;
};
struct cfattach acpipwrres_ca = {
@@ -75,6 +74,8 @@ struct cfdriver acpipwrres_cd = {
NULL, "acpipwrres", DV_DULL
};
+int acpipwrres_hascons(struct acpipwrres_softc *, struct aml_node *);
+int acpipwrres_addcons(struct acpipwrres_softc *, struct aml_node *);
int acpipwrres_foundcons(struct aml_node *, void *);
int
@@ -93,9 +94,10 @@ acpipwrres_match(struct device *parent, void *match, void *aux)
void
acpipwrres_attach(struct device *parent, struct device *self, void *aux)
{
- struct acpipwrres_softc *sc = (struct acpipwrres_softc *)self;
- struct acpi_attach_args *aaa = aux;
- struct aml_value res;
+ struct acpipwrres_softc *sc = (struct acpipwrres_softc *)self;
+ struct acpi_attach_args *aaa = aux;
+ struct aml_value res;
+ struct acpipwrres_consumer *cons;
extern struct aml_node aml_root;
@@ -103,10 +105,7 @@ acpipwrres_attach(struct device *parent, struct device *self, void *aux)
sc->sc_devnode = aaa->aaa_node;
memset(&res, 0, sizeof res);
- printf(": %s\n", sc->sc_devnode->name);
-
- aml_register_notify(sc->sc_devnode, aaa->aaa_dev,
- acpipwrres_notify, sc, ACPIDEV_NOPOLL);
+ printf(": %s", sc->sc_devnode->name);
if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
sc->sc_state = (int)aml_val2int(&res);
@@ -115,7 +114,7 @@ acpipwrres_attach(struct device *parent, struct device *self, void *aux)
sc->sc_state = ACPIPWRRES_UNK;
} else
sc->sc_state = ACPIPWRRES_UNK;
- DPRINTF(("%s: state = %d\n", DEVNAME(sc), sc->sc_state));
+ DPRINTF(("\n%s: state = %d\n", DEVNAME(sc), sc->sc_state));
if (aml_evalnode(sc->sc_acpi, aaa->aaa_node, 0, NULL, &res) == 0) {
sc->sc_level = res.v_powerrsrc.pwr_level;
sc->sc_order = res.v_powerrsrc.pwr_order;
@@ -125,86 +124,199 @@ acpipwrres_attach(struct device *parent, struct device *self, void *aux)
}
/* Get the list of consumers */
- TAILQ_INIT(&sc->sc_cons);
+ SIMPLEQ_INIT(&sc->sc_cons);
+#if notyet
aml_find_node(&aml_root, "_PRW", acpipwrres_foundcons, sc);
+#endif
aml_find_node(&aml_root, "_PR0", acpipwrres_foundcons, sc);
aml_find_node(&aml_root, "_PR1", acpipwrres_foundcons, sc);
aml_find_node(&aml_root, "_PR2", acpipwrres_foundcons, sc);
+ aml_find_node(&aml_root, "_PR3", acpipwrres_foundcons, sc);
+
+ DPRINTF(("%s", DEVNAME(sc)));
+ if (!SIMPLEQ_EMPTY(&sc->sc_cons)) {
+ printf(": resource for");
+ SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next)
+ printf(" %s%s", cons->cs_node->name,
+ (SIMPLEQ_NEXT(cons, cs_next) == NULL) ? "" : ",");
+ }
+ printf("\n");
}
int
-acpipwrres_notify(struct aml_node *node, int notify, void *arg)
+acpipwrres_ref_incr(struct acpipwrres_softc *sc, struct aml_node *node)
{
- int fmatch = 0;
- struct acpipwrres_consumer *cons;
- struct acpipwrres_softc *sc = arg;
struct aml_value res;
- memset(&res, 0, sizeof res);
+ if (!acpipwrres_hascons(sc, node))
+ return (1);
- TAILQ_FOREACH(cons, &sc->sc_cons, cs_link)
- if (cons->cs_node == node) {
- fmatch = 1;
- break;
- }
- if (!fmatch)
- return (0);
+ DPRINTF(("%s: dev %s ON %d\n", DEVNAME(sc), node->name,
+ sc->sc_cons_ref));
- switch (notify) {
- case NOTIFY_PWRRES_ON:
- DPRINTF(("pwr: on devs %d\n", sc->sc_ncons));
- if (sc->sc_ncons++ == 0)
- aml_evalname(sc->sc_acpi, sc->sc_devnode, "_ON", 0, NULL,
- &res);
+ if (sc->sc_cons_ref++ == 0) {
+ memset(&res, 0, sizeof(res));
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "_ON", 0,
+ NULL, &res);
aml_freevalue(&res);
- break;
- case NOTIFY_PWRRES_OFF:
- DPRINTF(("pwr: off devs %d\n", sc->sc_ncons));
- if (--sc->sc_ncons == 0)
- aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OFF", 0, NULL,
- &res);
+ }
+
+ return (0);
+}
+
+int
+acpipwrres_ref_decr(struct acpipwrres_softc *sc, struct aml_node *node)
+{
+ struct aml_value res;
+
+ if (!acpipwrres_hascons(sc, node))
+ return (1);
+
+ DPRINTF(("%s: dev %s OFF %d\n", DEVNAME(sc), node->name,
+ sc->sc_cons_ref));
+
+ if (--sc->sc_cons_ref == 0) {
+ memset(&res, 0, sizeof(res));
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OFF", 0,
+ NULL, &res);
aml_freevalue(&res);
- break;
- default:
- printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
- break;
}
return (0);
}
int
-acpipwrres_foundcons(struct aml_node *node, void *arg)
+acpipwrres_hascons(struct acpipwrres_softc *sc, struct aml_node *node)
+{
+ struct acpipwrres_consumer *cons;
+
+ SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next) {
+ if (cons->cs_node == node)
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+acpipwrres_addcons(struct acpipwrres_softc *sc, struct aml_node *node)
{
- int i = 0;
struct acpipwrres_consumer *cons;
- struct aml_node *pnode;
+ struct acpi_pwrres *pr;
+ int state;
+
+ /*
+ * Add handlers to put the device into Dx states.
+ *
+ * XXX What about PRW?
+ */
+ if (strcmp(node->name, "_PR0") == 0) {
+ state = ACPI_STATE_D0;
+ } else if (strcmp(node->name, "_PR1") == 0) {
+ state = ACPI_STATE_D1;
+ } else if (strcmp(node->name, "_PR2") == 0) {
+ state = ACPI_STATE_D2;
+ } else if (strcmp(node->name, "_PR3") == 0) {
+ state = ACPI_STATE_D3;
+ } else {
+ return (0);
+ }
+
+ if (!acpipwrres_hascons(sc, node->parent)) {
+ cons = malloc(sizeof(*cons), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (cons == NULL)
+ return (ENOMEM);
+
+ cons->cs_node = node->parent;
+ SIMPLEQ_INSERT_TAIL(&sc->sc_cons, cons, cs_next);
+ }
+
+ DPRINTF(("%s: resource for %s (D%d) \n", DEVNAME(sc),
+ node->parent->name, state));
+
+ /*
+ * Make sure we attach only once the same Power Resource for a
+ * given state.
+ */
+ SIMPLEQ_FOREACH(pr, &sc->sc_acpi->sc_pwrresdevs, p_next) {
+ if (pr->p_node == node->parent &&
+ pr->p_res_state == state &&
+ pr->p_res_sc == sc) {
+ DPRINTF(("error: pr for %s already set\n",
+ aml_nodename(pr->p_node)));
+ return (EINVAL);
+ }
+ }
+
+ pr = malloc(sizeof(struct acpi_pwrres), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (pr == NULL)
+ return (ENOMEM);
+
+ pr->p_node = node->parent;
+ pr->p_state = -1;
+ pr->p_res_state = state;
+ pr->p_res_sc = sc;
+
+ SIMPLEQ_INSERT_TAIL(&sc->sc_acpi->sc_pwrresdevs, pr, p_next);
+
+ return (0);
+}
+
+int
+acpipwrres_foundcons(struct aml_node *node, void *arg)
+{
struct acpipwrres_softc *sc = (struct acpipwrres_softc *)arg;
- struct aml_value res;
+ struct aml_value res, *ref;
+ int i = 0;
extern struct aml_node aml_root;
- memset(&res, 0, sizeof res);
+ memset(&res, 0, sizeof(res));
if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) {
DPRINTF(("pwr: consumer not found\n"));
- return (-1);
- } else {
- DPRINTF(("%s: node name %s\n", DEVNAME(sc), aml_nodename(node)));
- if (!strcmp(node->name, "_PRW"))
- i = 2; /* _PRW first two values are ints */
- for (; i < res.length; i++) {
- pnode = aml_searchname(&aml_root,
- res.v_package[i]->v_string);
- if (pnode == sc->sc_devnode) {
- DPRINTF(("%s: consumer match\n", DEVNAME(sc)));
- cons = malloc(sizeof *cons, M_DEVBUF,
- M_WAITOK | M_ZERO);
- cons->cs_node = pnode;
- TAILQ_INSERT_HEAD(&sc->sc_cons, cons, cs_link);
+ return (1);
+ }
+
+ if (res.type != AML_OBJTYPE_PACKAGE) {
+ DPRINTF(("%s: %s is not a package\n", DEVNAME(sc),
+ aml_nodename(node)));
+ aml_freevalue(&res);
+ return (1);
+ }
+
+ DPRINTF(("%s: node name %s\n", DEVNAME(sc), aml_nodename(node)));
+ if (!strcmp(node->name, "_PRW"))
+ i = 2; /* _PRW first two values are ints */
+
+ for (; i < res.length; i++) {
+ ref = res.v_package[i];
+
+ if (ref->type == AML_OBJTYPE_STRING) {
+ struct aml_node *pnode;
+
+ pnode = aml_searchrel(&aml_root, ref->v_string);
+ if (pnode == NULL) {
+ DPRINTF(("%s: device %s not found\n",
+ DEVNAME(sc), ref->v_string));
+ continue;
}
+ ref = pnode->value;
}
+
+ if (ref->type == AML_OBJTYPE_OBJREF)
+ ref = ref->v_objref.ref;
+
+ if (ref->type != AML_OBJTYPE_POWERRSRC) {
+ DPRINTF(("%s: object reference has a wrong type (%d)\n",
+ DEVNAME(sc), ref->type));
+ continue;
+ }
+
+ if (ref->node == sc->sc_devnode)
+ (void)acpipwrres_addcons(sc, node);
}
+ aml_freevalue(&res);
return (0);
}
diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h
index ebc2edaa169..420fe9173e8 100644
--- a/sys/dev/acpi/acpireg.h
+++ b/sys/dev/acpi/acpireg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpireg.h,v 1.28 2012/07/13 11:51:41 pirofti Exp $ */
+/* $OpenBSD: acpireg.h,v 1.29 2013/11/06 10:40:36 mpi Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
@@ -702,6 +702,14 @@ struct acpi_ivrs {
#define ACPI_STATE_S5 5
/*
+ * Device Power States
+ */
+#define ACPI_STATE_D0 0
+#define ACPI_STATE_D1 1
+#define ACPI_STATE_D2 2
+#define ACPI_STATE_D3 3
+
+/*
* ACPI Device IDs
*/
#define ACPI_DEV_TIM "PNP0100" /* System timer */
diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h
index 78e8303df3c..023ced0408c 100644
--- a/sys/dev/acpi/acpivar.h
+++ b/sys/dev/acpi/acpivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpivar.h,v 1.75 2012/11/27 17:38:46 pirofti Exp $ */
+/* $OpenBSD: acpivar.h,v 1.76 2013/11/06 10:40:36 mpi Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -26,6 +26,8 @@
#include <sys/rwlock.h>
#include <machine/biosvar.h>
+#include "acpipwrres.h"
+
/* #define ACPI_DEBUG */
#ifdef ACPI_DEBUG
extern int acpi_debug;
@@ -43,6 +45,7 @@ extern u_int8_t acpi_lapic_flags[LAPIC_MAP_SIZE];
struct klist;
struct acpiec_softc;
+struct acpipwrres_softc;
struct acpivideo_softc {
struct device sc_dev;
@@ -89,6 +92,19 @@ struct acpi_wakeq {
int q_state;
};
+#if NACPIPWRRES > 0
+struct acpi_pwrres {
+ SIMPLEQ_ENTRY(acpi_pwrres) p_next;
+ struct aml_node *p_node; /* device's node */
+ int p_state; /* current state */
+
+ int p_res_state;
+ struct acpipwrres_softc *p_res_sc;
+};
+
+typedef SIMPLEQ_HEAD(, acpi_pwrres) acpi_pwrreshead_t;
+#endif /* NACPIPWRRES > 0 */
+
typedef SIMPLEQ_HEAD(, acpi_q) acpi_qhead_t;
typedef SIMPLEQ_HEAD(, acpi_wakeq) acpi_wakeqhead_t;
@@ -193,6 +209,9 @@ struct acpi_softc {
struct acpi_fadt *sc_fadt;
acpi_qhead_t sc_tables;
acpi_wakeqhead_t sc_wakedevs;
+#if NACPIPWRRES > 0
+ acpi_pwrreshead_t sc_pwrresdevs;
+#endif /* NACPIPWRRES > 0 */
/*
* Second-level information from FADT
@@ -309,6 +328,11 @@ void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
void acpiec_handle_events(struct acpiec_softc *);
+#if NACPIPWRRES > 0
+int acpipwrres_ref_incr(struct acpipwrres_softc *, struct aml_node *);
+int acpipwrres_ref_decr(struct acpipwrres_softc *, struct aml_node *);
+#endif /* NACPIPWRRES > 0 */
+
int acpi_read_pmreg(struct acpi_softc *, int, int);
void acpi_write_pmreg(struct acpi_softc *, int, int, int);
diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi
index 6c23a65ef8b..97802ad9c4e 100644
--- a/sys/dev/acpi/files.acpi
+++ b/sys/dev/acpi/files.acpi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.acpi,v 1.26 2011/06/16 23:02:11 pirofti Exp $
+# $OpenBSD: files.acpi,v 1.27 2013/11/06 10:40:36 mpi Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
@@ -105,7 +105,7 @@ file dev/acpi/acpivout.c acpivout
# ACPI pwrres
device acpipwrres
attach acpipwrres at acpi
-file dev/acpi/acpipwrres.c acpipwrres
+file dev/acpi/acpipwrres.c acpipwrres needs-flag
# ASUSTeK AI Booster ATK0110
device aibs