Module Name: src Committed By: jruoho Date: Mon Aug 16 20:07:57 UTC 2010
Modified Files: src/sys/dev/acpi: acpi_cpu.c acpi_cpu_pstate.c Log Message: Two changes: 1. Initialize P-states properly to P0. It is processor-specific what value we might get without initialization. (Some AMD CPUs have even specific registers for the state after cold reset.) 2. Following design notes for Windows, set the lowest-power P-state upon suspend and restore the saved state after resume. To generate a diff of this commit: cvs rdiff -u -r1.17 -r1.18 src/sys/dev/acpi/acpi_cpu.c cvs rdiff -u -r1.24 -r1.25 src/sys/dev/acpi/acpi_cpu_pstate.c 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_cpu.c diff -u src/sys/dev/acpi/acpi_cpu.c:1.17 src/sys/dev/acpi/acpi_cpu.c:1.18 --- src/sys/dev/acpi/acpi_cpu.c:1.17 Mon Aug 16 17:58:42 2010 +++ src/sys/dev/acpi/acpi_cpu.c Mon Aug 16 20:07:57 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_cpu.c,v 1.17 2010/08/16 17:58:42 jruoho Exp $ */ +/* $NetBSD: acpi_cpu.c,v 1.18 2010/08/16 20:07:57 jruoho Exp $ */ /*- * Copyright (c) 2010 Jukka Ruohonen <jruoho...@iki.fi> @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.17 2010/08/16 17:58:42 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.18 2010/08/16 20:07:57 jruoho Exp $"); #include <sys/param.h> #include <sys/cpu.h> @@ -519,8 +519,6 @@ { struct acpicpu_softc *sc = device_private(self); - sc->sc_cold = true; - if ((sc->sc_flags & ACPICPU_FLAG_C) != 0) (void)acpicpu_cstate_suspend(self); @@ -530,6 +528,8 @@ if ((sc->sc_flags & ACPICPU_FLAG_T) != 0) (void)acpicpu_tstate_suspend(self); + sc->sc_cold = true; + return true; } @@ -538,6 +538,8 @@ { struct acpicpu_softc *sc = device_private(self); + sc->sc_cold = false; + if ((sc->sc_flags & ACPICPU_FLAG_C) != 0) (void)acpicpu_cstate_resume(self); @@ -547,8 +549,6 @@ if ((sc->sc_flags & ACPICPU_FLAG_T) != 0) (void)acpicpu_tstate_resume(self); - sc->sc_cold = false; - return true; } Index: src/sys/dev/acpi/acpi_cpu_pstate.c diff -u src/sys/dev/acpi/acpi_cpu_pstate.c:1.24 src/sys/dev/acpi/acpi_cpu_pstate.c:1.25 --- src/sys/dev/acpi/acpi_cpu_pstate.c:1.24 Mon Aug 16 17:58:42 2010 +++ src/sys/dev/acpi/acpi_cpu_pstate.c Mon Aug 16 20:07:57 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_cpu_pstate.c,v 1.24 2010/08/16 17:58:42 jruoho Exp $ */ +/* $NetBSD: acpi_cpu_pstate.c,v 1.25 2010/08/16 20:07:57 jruoho Exp $ */ /*- * Copyright (c) 2010 Jukka Ruohonen <jruoho...@iki.fi> @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_cpu_pstate.c,v 1.24 2010/08/16 17:58:42 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_cpu_pstate.c,v 1.25 2010/08/16 20:07:57 jruoho Exp $"); #include <sys/param.h> #include <sys/evcnt.h> @@ -55,6 +55,8 @@ static void acpicpu_pstate_change(struct acpicpu_softc *); static void acpicpu_pstate_bios(void); +static uint32_t acpicpu_pstate_saved; + void acpicpu_pstate_attach(device_t self) { @@ -105,7 +107,6 @@ (void)acpicpu_pstate_max(sc); sc->sc_flags |= ACPICPU_FLAG_P; - sc->sc_pstate_current = sc->sc_pstate[0].ps_freq; acpicpu_pstate_bios(); acpicpu_pstate_attach_evcnt(sc); @@ -225,13 +226,35 @@ acpicpu_pstate_start(device_t self) { struct acpicpu_softc *sc = device_private(self); + struct acpicpu_pstate *ps; + uint32_t i; int rv; rv = acpicpu_md_pstate_start(); - if (rv == 0) - return; + if (rv != 0) + goto fail; + + /* + * Initialize the state to the maximum. + */ + for (i = 0, rv = ENXIO; i < sc->sc_pstate_count; i++) { + + ps = &sc->sc_pstate[i]; + if (ps->ps_freq != 0) { + sc->sc_cold = false; + rv = acpicpu_pstate_set(sc, ps->ps_freq); + break; + } + } + + if (rv != 0) + goto fail; + + return; + +fail: sc->sc_flags &= ~ACPICPU_FLAG_P; aprint_error_dev(self, "failed to start P-states (err %d)\n", rv); } @@ -239,6 +262,40 @@ bool acpicpu_pstate_suspend(device_t self) { + struct acpicpu_softc *sc = device_private(self); + struct acpicpu_pstate *ps = NULL; + int32_t i; + + if (acpicpu_pstate_saved != 0) + return true; + + /* + * Following design notes for Windows, we set the highest + * P-state when entering any of the system sleep states. + * When resuming, the saved P-state will be restored. + * + * Microsoft Corporation: Windows Native Processor + * Performance Control. Version 1.1a, November, 2002. + */ + for (i = sc->sc_pstate_count - 1; i >= 0; i--) { + + if (sc->sc_pstate[i].ps_freq != 0) { + ps = &sc->sc_pstate[i]; + break; + } + } + + if (__predict_false(ps == NULL)) + return true; + + mutex_enter(&sc->sc_mtx); + acpicpu_pstate_saved = sc->sc_pstate_current; + mutex_exit(&sc->sc_mtx); + + if (acpicpu_pstate_saved == ps->ps_freq) + return true; + + (void)acpicpu_pstate_set(sc, ps->ps_freq); return true; } @@ -246,6 +303,12 @@ bool acpicpu_pstate_resume(device_t self) { + struct acpicpu_softc *sc = device_private(self); + + if (acpicpu_pstate_saved != 0) { + (void)acpicpu_pstate_set(sc, acpicpu_pstate_saved); + acpicpu_pstate_saved = 0; + } acpicpu_pstate_callback(self); @@ -278,7 +341,7 @@ * If the maximum changed, proactively * raise or lower the target frequency. */ - acpicpu_pstate_set(sc, sc->sc_pstate[new].ps_freq); + (void)acpicpu_pstate_set(sc, sc->sc_pstate[new].ps_freq); #endif }