diff options
author | Jordan Hargrave <jordan@cvs.openbsd.org> | 2011-01-02 04:56:58 +0000 |
---|---|---|
committer | Jordan Hargrave <jordan@cvs.openbsd.org> | 2011-01-02 04:56:58 +0000 |
commit | 3ec6aa883c28c24f24dc786655ed0b7f3213a870 (patch) | |
tree | 68e4149630b26b2976ad38f7b53f7c1bb6cf820a /sys | |
parent | 4ca44bef3da389cc4556166e0c99ec18a7dca17a (diff) |
Re-add code for ACPI taskqueue, eliminates need for state vars in acpi softc
Serialize processing ACPI tasks for sleep/powerdown/GPE event
ok deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/acpi/acpi.c | 215 | ||||
-rw-r--r-- | sys/dev/acpi/acpibtn.c | 8 | ||||
-rw-r--r-- | sys/dev/acpi/acpisony.c | 5 | ||||
-rw-r--r-- | sys/dev/acpi/acpithinkpad.c | 5 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 22 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.c | 37 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.h | 3 |
7 files changed, 194 insertions, 101 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 55d17e39a29..116a123e563 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.221 2010/10/31 21:52:46 guenther Exp $ */ +/* $OpenBSD: acpi.c,v 1.222 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -86,6 +86,10 @@ struct acpi_q *acpi_maptable(struct acpi_softc *, paddr_t, const char *, void acpi_init_states(struct acpi_softc *); +void acpi_gpe_task(void *, int); +void acpi_sbtn_task(void *, int); +void acpi_pbtn_task(void *, int); + #ifndef SMALL_KERNEL int acpi_thinkpad_enabled; @@ -1204,6 +1208,54 @@ acpi_init_states(struct acpi_softc *sc) } } +/* ACPI Workqueue support */ +SIMPLEQ_HEAD(,acpi_taskq) acpi_taskq = + SIMPLEQ_HEAD_INITIALIZER(acpi_taskq); + +void +acpi_addtask(struct acpi_softc *sc, void (*handler)(void *, int), + void *arg0, int arg1) +{ + struct acpi_taskq *wq; + int s; + + wq = malloc(sizeof(*wq), M_DEVBUF, M_ZERO | M_NOWAIT); + if (wq == NULL) + return; + wq->handler = handler; + wq->arg0 = arg0; + wq->arg1 = arg1; + + s = spltty(); + SIMPLEQ_INSERT_TAIL(&acpi_taskq, wq, next); + splx(s); +} + +int +acpi_dotask(struct acpi_softc *sc) +{ + struct acpi_taskq *wq; + int s; + + s = spltty(); + if (SIMPLEQ_EMPTY(&acpi_taskq)) { + splx(s); + + /* we don't have anything to do */ + return (0); + } + wq = SIMPLEQ_FIRST(&acpi_taskq); + SIMPLEQ_REMOVE_HEAD(&acpi_taskq, next); + splx(s); + + wq->handler(wq->arg0, wq->arg1); + + free(wq, M_DEVBUF); + + /* We did something */ + return (1); +} + #ifndef SMALL_KERNEL int is_ata(struct aml_node *node) @@ -1346,6 +1398,82 @@ acpi_reset(void) delay(100000); } +void +acpi_gpe_task(void *arg0, int gpe) +{ + struct acpi_softc *sc = acpi_softc; + struct gpe_block *pgpe = &sc->gpe_table[gpe]; + + dnprintf(10, "handle gpe: %x\n", gpe); + if (pgpe->handler && pgpe->active) { + pgpe->active = 0; + pgpe->handler(sc, gpe, pgpe->arg); + } +} + +void +acpi_pbtn_task(void *arg0, int dummy) +{ + struct acpi_softc *sc = arg0; + uint16_t en; + int s; + + dnprintf(1,"power button pressed\n"); + + /* Reset the latch and re-enable the GPE */ + s = spltty(); + en = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0); + acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, + en | ACPI_PM1_PWRBTN_EN); + splx(s); + + acpi_addtask(sc, acpi_powerdown_task, sc, 0); +} + +void +acpi_sbtn_task(void *arg0, int dummy) +{ + struct acpi_softc *sc = arg0; + uint16_t en; + int s; + + dnprintf(1,"sleep button pressed\n"); + aml_notify_dev(ACPI_DEV_SBD, 0x80); + + /* Reset the latch and re-enable the GPE */ + s = spltty(); + en = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0); + acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, + en | ACPI_PM1_SLPBTN_EN); + splx(s); +} + +void +acpi_powerdown_task(void *arg0, int dummy) +{ + /* XXX put a knob in front of this */ + psignal(initproc, SIGUSR2); +} + +void +acpi_sleep_task(void *arg0, int sleepmode) +{ + struct acpi_softc *sc = arg0; + struct acpi_ac *ac; + struct acpi_bat *bat; + + /* System goes to sleep here.. */ + acpi_sleep_state(sc, sleepmode); + + /* AC and battery information needs refreshing */ + SLIST_FOREACH(ac, &sc->sc_ac, aac_link) + aml_notify(ac->aac_softc->sc_devnode, + 0x80); + SLIST_FOREACH(bat, &sc->sc_bat, aba_link) + aml_notify(bat->aba_softc->sc_devnode, + 0x80); +} + int acpi_interrupt(void *arg) { @@ -1366,6 +1494,8 @@ acpi_interrupt(void *arg) if (en & sts & (1L << jdx)) { /* Signal this GPE */ sc->gpe_table[idx+jdx].active = 1; + dnprintf(10, "queue gpe: %x\n", idx+jdx); + acpi_addtask(sc, acpi_gpe_task, NULL, idx+jdx); /* * Edge interrupts need their STS bits @@ -1395,7 +1525,8 @@ acpi_interrupt(void *arg) acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_PWRBTN_STS); sts &= ~ACPI_PM1_PWRBTN_STS; - sc->sc_powerbtn = 1; + + acpi_addtask(sc, acpi_pbtn_task, sc, 0); } if (sts & ACPI_PM1_SLPBTN_STS) { /* Mask and acknowledge */ @@ -1404,7 +1535,8 @@ acpi_interrupt(void *arg) acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_SLPBTN_STS); sts &= ~ACPI_PM1_SLPBTN_STS; - sc->sc_sleepbtn = 1; + + acpi_addtask(sc, acpi_sbtn_task, sc, 0); } if (sts) { printf("%s: PM1 stuck (en 0x%x st 0x%x), clearing\n", @@ -2017,7 +2149,6 @@ acpi_thread(void *arg) struct acpi_thread *thread = arg; struct acpi_softc *sc = thread->sc; extern int aml_busy; - u_int32_t gpe; int s; rw_enter_write(&sc->sc_lck); @@ -2065,77 +2196,9 @@ acpi_thread(void *arg) continue; } - for (gpe = 0; gpe < sc->sc_lastgpe; gpe++) { - struct gpe_block *pgpe = &sc->gpe_table[gpe]; - - if (pgpe->active) { - pgpe->active = 0; - dnprintf(50, "softgpe: %.2x\n", gpe); - if (pgpe->handler) - pgpe->handler(sc, gpe, pgpe->arg); - } - } - if (sc->sc_powerbtn) { - uint16_t en; - - sc->sc_powerbtn = 0; - dnprintf(1,"power button pressed\n"); - sc->sc_powerdown = 1; - - /* Reset the latch and re-enable the GPE */ - s = spltty(); - en = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0); - acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, - en | ACPI_PM1_PWRBTN_EN); - splx(s); - - } - if (sc->sc_sleepbtn) { - uint16_t en; - - sc->sc_sleepbtn = 0; - dnprintf(1,"sleep button pressed\n"); - aml_notify_dev(ACPI_DEV_SBD, 0x80); - - /* Reset the latch and re-enable the GPE */ - s = spltty(); - en = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0); - acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, - en | ACPI_PM1_SLPBTN_EN); - splx(s); - } - - /* handle polling here to keep code non-concurrent*/ - if (sc->sc_poll) { - sc->sc_poll = 0; - acpi_poll_notify(); - } - - if (sc->sc_powerdown) { - sc->sc_powerdown = 0; - - /* XXX put a knob in front of this */ - psignal(initproc, SIGUSR2); - } - - if (sc->sc_sleepmode) { - struct acpi_ac *ac; - struct acpi_bat *bat; - int sleepmode = sc->sc_sleepmode; - - sc->sc_sleepmode = 0; - acpi_sleep_state(sc, sleepmode); - - /* AC and battery information needs refreshing */ - SLIST_FOREACH(ac, &sc->sc_ac, aac_link) - aml_notify(ac->aac_softc->sc_devnode, - 0x80); - SLIST_FOREACH(bat, &sc->sc_bat, aba_link) - aml_notify(bat->aba_softc->sc_devnode, - 0x80); - - continue; - } + /* Run ACPI taskqueue */ + while(acpi_dotask(acpi_softc)) + ; } free(thread, M_DEVBUF); @@ -2425,7 +2488,7 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) if ((flag & FWRITE) == 0) { error = EBADF; } else { - sc->sc_sleepmode = ACPI_STATE_S3; + acpi_addtask(sc, acpi_sleep_task, sc, ACPI_STATE_S3); acpi_wakeup(sc); } break; diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index 20cc016d540..b7b1f617b97 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibtn.c,v 1.33 2010/08/07 16:21:20 deraadt Exp $ */ +/* $OpenBSD: acpibtn.c,v 1.34 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -198,14 +198,16 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) sleep: /* Request to go to sleep */ if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) - sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_addtask(sc->sc_acpi, acpi_sleep_task, + sc->sc_acpi, ACPI_STATE_S3); break; } #endif /* SMALL_KERNEL */ break; case ACPIBTN_POWER: if (notify_type == 0x80) - sc->sc_acpi->sc_powerdown = 1; + acpi_addtask(sc->sc_acpi, acpi_powerdown_task, + sc->sc_acpi, 0); break; default: printf("%s: spurious acpi button interrupt %i\n", DEVNAME(sc), diff --git a/sys/dev/acpi/acpisony.c b/sys/dev/acpi/acpisony.c index 716db37130c..e6bede881ed 100644 --- a/sys/dev/acpi/acpisony.c +++ b/sys/dev/acpi/acpisony.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpisony.c,v 1.3 2010/08/07 16:21:20 deraadt Exp $ */ +/* $OpenBSD: acpisony.c,v 1.4 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2010 Paul Irofti <pirofti@openbsd.org> * @@ -198,7 +198,8 @@ acpisony_notify(struct aml_node *node, int notify, void *arg) DPRINTF(("suspend-pressed\n")); #ifndef SMALL_KERNEL if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) - sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_addtask(sc->sc_acpi, acpi_sleep_task, + sc->sc_acpi, ACPI_STATE_S3); #endif break; case SONY_NOTIFY_SUSPEND_RELEASED: diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c index bfff2073eda..8e7d2173499 100644 --- a/sys/dev/acpi/acpithinkpad.c +++ b/sys/dev/acpi/acpithinkpad.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpithinkpad.c,v 1.24 2010/08/07 16:21:20 deraadt Exp $ */ +/* $OpenBSD: acpithinkpad.c,v 1.25 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2008 joshua stein <jcs@openbsd.org> * @@ -284,7 +284,8 @@ thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) case THINKPAD_BUTTON_SUSPEND: #ifndef SMALL_KERNEL if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) - sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_addtask(sc->sc_acpi, acpi_sleep_task, + sc->sc_acpi, ACPI_STATE_S3); #endif handled = 1; break; diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index 1e4752d3407..e9a172b5681 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.68 2010/10/31 21:52:46 guenther Exp $ */ +/* $OpenBSD: acpivar.h,v 1.69 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -82,6 +82,13 @@ struct acpi_q { u_int8_t q_data[0]; }; +struct acpi_taskq { + SIMPLEQ_ENTRY(acpi_taskq) next; + void (*handler)(void *, int); + void *arg0; + int arg1; +}; + struct acpi_wakeq { SIMPLEQ_ENTRY(acpi_wakeq) q_next; struct aml_node *q_node; @@ -206,12 +213,6 @@ struct acpi_softc { void *sc_interrupt; - int sc_powerbtn; - int sc_sleepbtn; - - int sc_sleepmode; - int sc_powerdown; - struct rwlock sc_lck; struct { @@ -241,7 +242,6 @@ struct acpi_softc { struct acpi_bat_head sc_bat; struct timeout sc_dev_timeout; - int sc_poll; int sc_revision; @@ -333,6 +333,12 @@ int acpi_matchhids(struct acpi_attach_args *, const char *[], const char *); int acpi_record_event(struct acpi_softc *, u_int); +void acpi_addtask(struct acpi_softc *, void (*)(void *, int), void *, int); +int acpi_dotask(struct acpi_softc *); + +void acpi_powerdown_task(void *, int); +void acpi_sleep_task(void *, int); + #endif #endif /* !_ACPI_WAKECODE */ diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index c41ecf6d47e..3c18fbe947d 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.c,v 1.180 2010/10/31 21:52:46 guenther Exp $ */ +/* $OpenBSD: dsdt.c,v 1.181 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -104,6 +104,9 @@ void aml_dump(int, u_int8_t *); void _aml_die(const char *fn, int line, const char *fmt, ...); #define aml_die(x...) _aml_die(__FUNCTION__, __LINE__, x) +void aml_notify_task(void *, int); +void acpi_poll_notify_task(void *, int); + /* * @@@: Global variables */ @@ -515,19 +518,32 @@ aml_setbit(u_int8_t *pb, int bit, int val) /* * @@@: Notify functions */ +#ifndef SMALL_KERNEL void acpi_poll(void *arg) { int s; s = spltty(); - acpi_softc->sc_poll = 1; + acpi_addtask(acpi_softc, acpi_poll_notify_task, NULL, 0); acpi_softc->sc_threadwaiting = 0; wakeup(acpi_softc); splx(s); timeout_add_sec(&acpi_softc->sc_dev_timeout, 10); } +#endif + +void +aml_notify_task(void *node, int notify_value) +{ + struct aml_notify_data *pdata = NULL; + + dnprintf(10,"run notify: %s %x\n", aml_nodename(node), notify_value); + SLIST_FOREACH(pdata, &aml_notify_list, link) + if (pdata->node == node) + pdata->cbproc(pdata->node, notify_value, pdata->cbarg); +} void aml_register_notify(struct aml_node *node, const char *pnpid, @@ -557,14 +573,11 @@ aml_register_notify(struct aml_node *node, const char *pnpid, void aml_notify(struct aml_node *node, int notify_value) { - struct aml_notify_data *pdata = NULL; - if (node == NULL) return; - SLIST_FOREACH(pdata, &aml_notify_list, link) - if (pdata->node == node) - pdata->cbproc(pdata->node, notify_value, pdata->cbarg); + dnprintf(10,"queue notify: %s %x\n", aml_nodename(node), notify_value); + acpi_addtask(acpi_softc, aml_notify_task, node, notify_value); } #ifndef SMALL_KERNEL @@ -582,7 +595,7 @@ aml_notify_dev(const char *pnpid, int notify_value) } void -acpi_poll_notify(void) +acpi_poll_notify_task(void *arg0, int arg1) { struct aml_notify_data *pdata = NULL; @@ -2472,6 +2485,14 @@ acpi_xmutex_release(struct aml_scope *scope, struct aml_value *mtx) int acpi_xevent_wait(struct aml_scope *scope, struct aml_value *evt, int timeout) { + /* Wait for event to occur; do work in meantime */ + evt->v_evt.state = 0; + while (!evt->v_evt.state) { + if (!acpi_dotask(acpi_softc) && !cold) + tsleep(evt, PWAIT, "acpievt", 1); + else + delay(100); + } if (evt->v_evt.state == 1) { /* Object is signaled */ return (0); diff --git a/sys/dev/acpi/dsdt.h b/sys/dev/acpi/dsdt.h index 0c58b1cccf8..aef42b43ded 100644 --- a/sys/dev/acpi/dsdt.h +++ b/sys/dev/acpi/dsdt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.h,v 1.55 2010/08/04 18:11:56 jordan Exp $ */ +/* $OpenBSD: dsdt.h,v 1.56 2011/01/02 04:56:57 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -274,7 +274,6 @@ int aml_rdpciaddr(struct aml_node *pcidev, #ifndef SMALL_KERNEL void acpi_getdevlist(struct acpi_devlist_head *, struct aml_node *, struct aml_value *, int); -void acpi_poll_notify(void); void aml_notify_dev(const char *, int); #endif |