diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2007-12-27 19:04:07 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2007-12-27 19:04:07 +0000 |
commit | fa6ff6da51fb08d7ae274834b14f3f55db58eb64 (patch) | |
tree | 2263ea8d95ff8a84e86f39f983518ca6563a015b /sys/dev/acpi | |
parent | fb95a4b3c8b94c38d07e78a31cf7c35c6ed7a55a (diff) |
Add _PPC support. Tested by several people.
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/acpicpu.c | 134 |
1 files changed, 86 insertions, 48 deletions
diff --git a/sys/dev/acpi/acpicpu.c b/sys/dev/acpi/acpicpu.c index b0030ed00c8..08196a1be4e 100644 --- a/sys/dev/acpi/acpicpu.c +++ b/sys/dev/acpi/acpicpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpicpu.c,v 1.37 2007/12/27 01:18:50 marco Exp $ */ +/* $OpenBSD: acpicpu.c,v 1.38 2007/12/27 19:04:06 marco Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -94,9 +94,16 @@ struct acpicpu_softc { struct aml_node *sc_devnode; int sc_pss_len; + int sc_ppc; + int sc_level; struct acpicpu_pss *sc_pss; struct acpicpu_pct sc_pct; + /* save compensation for pct access for lying bios' */ + u_int32_t sc_pct_stat_as; + u_int32_t sc_pct_ctrl_as; + u_int32_t sc_pct_stat_len; + u_int32_t sc_pct_ctrl_len; /* * XXX: _PPC Change listener * PPC changes can occur when for example a machine is disconnected @@ -110,6 +117,7 @@ struct acpicpu_softc { void acpicpu_set_throttle(struct acpicpu_softc *, int); void acpicpu_add_cstatepkg(struct aml_value *, void *); +int acpicpu_getppc(struct acpicpu_softc *); int acpicpu_getpct(struct acpicpu_softc *); int acpicpu_getpss(struct acpicpu_softc *); struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int, @@ -236,6 +244,7 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) struct aml_value res; int i; struct acpi_cstate *cx; + u_int32_t status = 0; sc->sc_acpi = (struct acpi_softc *)parent; sc->sc_devnode = aa->aaa_node; @@ -286,7 +295,6 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) sc->sc_pblk_addr + 5); } if (acpicpu_getpss(sc)) { - /* XXX not the right test but has to do for now */ sc->sc_flags |= FLAGS_NOPSS; } else { #ifdef ACPI_DEBUG @@ -301,6 +309,14 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) } dnprintf(20, "\n"); #endif + if (sc->sc_pss_len == 0) { + /* this should never happen */ + printf("%s: invalid _PSS length\n"); + sc->sc_flags |= FLAGS_NOPSS; + goto bypass; + } + + acpicpu_getppc(sc); if (acpicpu_getpct(sc)) sc->sc_flags |= FLAGS_NOPCT; else { @@ -313,15 +329,22 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) aml_register_notify(sc->sc_devnode, NULL, acpicpu_notify, sc, ACPIDEV_NOPOLL); + acpi_gasio(sc->sc_acpi, ACPI_IOREAD, + sc->sc_pct.pct_status.grd_gas.address_space_id, + sc->sc_pct.pct_status.grd_gas.address, + sc->sc_pct_stat_as, sc->sc_pct_stat_as, &status); + sc->sc_level = (100 / sc->sc_pss_len) * + (sc->sc_pss_len - status); + dnprintf(20, "%s: cpu index %d, percentage %d\n", + DEVNAME(sc), status, sc->sc_level); if (setperf_prio < 30) { - printf("acpi does throttle\n"); cpu_setperf = acpicpu_setperf; setperf_prio = 30; acpi_hasprocfvs = 1; } } } - +bypass: /* * Nicely enumerate what power management capabilities * ACPI CPU provides. @@ -372,19 +395,30 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux) } int -acpicpu_getpct(struct acpicpu_softc *sc) +acpicpu_getppc(struct acpicpu_softc *sc) { struct aml_value res; - int rv = 1; + + sc->sc_ppc = 0; if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) { dnprintf(10, "%s: no _PPC\n", DEVNAME(sc)); return (1); } - dnprintf(10, "_PPC: %d\n", aml_val2int(&res)); + sc->sc_ppc = aml_val2int(&res); + dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc); aml_freevalue(&res); + return (0); +} + +int +acpicpu_getpct(struct acpicpu_softc *sc) +{ + struct aml_value res; + int rv = 1; + if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) { dnprintf(20, "%s: no _PCT\n", DEVNAME(sc)); return (1); @@ -430,6 +464,21 @@ acpicpu_getpct(struct acpicpu_softc *sc) sc->sc_pct.pct_status.grd_gas.access_size, sc->sc_pct.pct_status.grd_gas.address); + /* if not set assume single 32 bit access */ + sc->sc_pct_stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width + / 8; + if (sc->sc_pct_stat_as == 0) + sc->sc_pct_stat_as = 4; + sc->sc_pct_ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8; + if (sc->sc_pct_ctrl_as == 0) + sc->sc_pct_ctrl_as = 4; + sc->sc_pct_stat_len = sc->sc_pct.pct_status.grd_gas.access_size; + if (sc->sc_pct_stat_len == 0) + sc->sc_pct_stat_len = sc->sc_pct_stat_as; + sc->sc_pct_ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size; + if (sc->sc_pct_ctrl_len == 0) + sc->sc_pct_ctrl_len = sc->sc_pct_ctrl_as; + rv = 0; ffh: aml_freevalue(&res); @@ -505,10 +554,9 @@ acpicpu_notify(struct aml_node *node, int notify_type, void *arg) switch (notify_type) { case 0x80: /* _PPC changed, retrieve new values */ - acpicpu_getpct(sc); - acpicpu_getpss(sc); - if (sc->sc_notify) - sc->sc_notify(sc->sc_pss, sc->sc_pss_len); + acpicpu_getppc(sc); + /* reset performance to current percentage */ + acpicpu_setperf(sc->sc_level); break; default: printf("%s: unhandled cpu event %x\n", DEVNAME(sc), @@ -533,8 +581,7 @@ acpicpu_setperf(int level) { struct acpicpu_softc *sc; struct acpicpu_pss *pss = NULL; - int idx; - u_int32_t stat_as, ctrl_as, stat_len, ctrl_len; + int idx, len; u_int32_t status = 0; sc = acpicpu_sc[cpu_number()]; @@ -552,54 +599,44 @@ acpicpu_setperf(int level) * XXX this should be handled more gracefully and it needs to also do * the duty cycle method instead of pss exclusively */ - if (sc->sc_pss_len == 0) { + if (sc->sc_flags & FLAGS_NOPSS) { dnprintf(10, "%s: acpicpu no _PSS\n", sc->sc_devnode->name); return; } - idx = (sc->sc_pss_len - 1) - (level / (100 / sc->sc_pss_len)); + if (sc->sc_ppc) + len = sc->sc_ppc; + else + len = sc->sc_pss_len; + idx = (len - 1) - (level / (100 / len)); if (idx < 0) - idx = 0; /* compensate */ - if (idx > sc->sc_pss_len) { - /* XXX should never happen */ - printf("%s: acpicpu setperf index out of range\n", - sc->sc_devnode->name); - return; - } + idx = 0; - dnprintf(10, "%s: acpicpu setperf index %d\n", - sc->sc_devnode->name, idx); + if (sc->sc_ppc) + idx += sc->sc_pss_len - sc->sc_ppc; - pss = &sc->sc_pss[idx]; + if (idx > sc->sc_pss_len) + idx = sc->sc_pss_len - 1; - /* if not set assume single 32 bit access */ - stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width / 8; - if (stat_as == 0) - stat_as = 4; - ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8; - if (ctrl_as == 0) - ctrl_as = 4; - stat_len = sc->sc_pct.pct_status.grd_gas.access_size; - if (stat_len == 0) - stat_len = stat_as; - ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size; - if (ctrl_len == 0) - ctrl_len = ctrl_as; + dnprintf(10, "%s: acpicpu setperf index %d pss_len %d ppc %d\n", + sc->sc_devnode->name, idx, sc->sc_pss_len, sc->sc_ppc); + + pss = &sc->sc_pss[idx]; #ifdef ACPI_DEBUG /* keep this for now since we will need this for debug in the field */ printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n", sc->sc_pct.pct_status.grd_gas.address_space_id, sc->sc_pct.pct_status.grd_gas.address, - stat_as, stat_len, + sc->sc_pct_stat_as, sc->sc_pct_stat_len, sc->sc_pct.pct_ctrl.grd_gas.address_space_id, sc->sc_pct.pct_ctrl.grd_gas.address, - ctrl_as, ctrl_len); + sc->sc_pct_ctrl_as, sc->sc_pct_ctrl_len); #endif acpi_gasio(sc->sc_acpi, ACPI_IOREAD, sc->sc_pct.pct_status.grd_gas.address_space_id, - sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_len, - &status); + sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, + sc->sc_pct_stat_len, &status); dnprintf(20, "1 status: %u <- %u\n", status, pss->pss_status); /* Are we already at the requested frequency? */ @@ -608,20 +645,21 @@ acpicpu_setperf(int level) acpi_gasio(sc->sc_acpi, ACPI_IOWRITE, sc->sc_pct.pct_ctrl.grd_gas.address_space_id, - sc->sc_pct.pct_ctrl.grd_gas.address, ctrl_as, ctrl_len, - &pss->pss_ctrl); + sc->sc_pct.pct_ctrl.grd_gas.address, sc->sc_pct_ctrl_as, + sc->sc_pct_ctrl_len, &pss->pss_ctrl); dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl); acpi_gasio(sc->sc_acpi, ACPI_IOREAD, sc->sc_pct.pct_status.grd_gas.address_space_id, - sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_as, - &status); + sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, + sc->sc_pct_stat_as, &status); dnprintf(20, "2 status: %d\n", status); /* Did the transition succeed? */ - if (status == pss->pss_status) + if (status == pss->pss_status) { cpuspeed = pss->pss_core_freq; - else + sc->sc_level = level; + } else printf("%s: acpicpu setperf failed to alter frequency\n", sc->sc_devnode->name); } |