Module Name: src Committed By: jruoho Date: Thu Jul 29 22:42:58 UTC 2010
Modified Files: src/sys/dev/acpi: acpi_cpu.c acpi_cpu.h acpi_cpu_cstate.c Log Message: Add a per ACPI CPU mutex for C-states. Protect the _CST update with this: when the idle-information is being updated (e.g. due acpiacad(4) events), we can not enter the idle-loop. The lock must run at the same priority (IPL_NONE) as ACPICA's mutexes obtained via AcpiOsCreateMutex() a.k.a. AcpiOsCreateSemaphore(). Also check want_resched as the first thing and clarify the suspend/resume path. There is still one race condition identified: when the driver is loaded as a module, we must gracefully kick all CPUs out from the ACPI idle-loop upon detachment. To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/dev/acpi/acpi_cpu.c cvs rdiff -u -r1.6 -r1.7 src/sys/dev/acpi/acpi_cpu.h cvs rdiff -u -r1.11 -r1.12 src/sys/dev/acpi/acpi_cpu_cstate.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.8 src/sys/dev/acpi/acpi_cpu.c:1.9 --- src/sys/dev/acpi/acpi_cpu.c:1.8 Mon Jul 26 15:14:33 2010 +++ src/sys/dev/acpi/acpi_cpu.c Thu Jul 29 22:42:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_cpu.c,v 1.8 2010/07/26 15:14:33 jruoho Exp $ */ +/* $NetBSD: acpi_cpu.c,v 1.9 2010/07/29 22:42:58 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.8 2010/07/26 15:14:33 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_cpu.c,v 1.9 2010/07/29 22:42:58 jruoho Exp $"); #include <sys/param.h> #include <sys/cpu.h> @@ -114,6 +114,7 @@ KASSERT(acpicpu_sc != NULL); sc->sc_dev = self; + sc->sc_cold = false; sc->sc_iot = aa->aa_iot; sc->sc_node = aa->aa_node; sc->sc_cpuid = acpicpu_id(sc->sc_object.ao_procid); @@ -468,6 +469,8 @@ { struct acpicpu_softc *sc = device_private(self); + sc->sc_cold = true; + if ((sc->sc_flags & ACPICPU_FLAG_C) != 0) (void)acpicpu_cstate_suspend(self); @@ -479,6 +482,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); Index: src/sys/dev/acpi/acpi_cpu.h diff -u src/sys/dev/acpi/acpi_cpu.h:1.6 src/sys/dev/acpi/acpi_cpu.h:1.7 --- src/sys/dev/acpi/acpi_cpu.h:1.6 Tue Jul 27 05:11:32 2010 +++ src/sys/dev/acpi/acpi_cpu.h Thu Jul 29 22:42:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_cpu.h,v 1.6 2010/07/27 05:11:32 jruoho Exp $ */ +/* $NetBSD: acpi_cpu.h,v 1.7 2010/07/29 22:42:58 jruoho Exp $ */ /*- * Copyright (c) 2010 Jukka Ruohonen <jruoho...@iki.fi> @@ -120,14 +120,16 @@ struct acpicpu_softc { device_t sc_dev; struct acpi_devnode *sc_node; - struct acpicpu_cstate sc_cstate[ACPI_C_STATE_COUNT]; struct acpicpu_object sc_object; + struct acpicpu_cstate sc_cstate[ACPI_C_STATE_COUNT]; + kmutex_t sc_cstate_mtx; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; uint32_t sc_sleep; uint32_t sc_cpuid; uint32_t sc_cap; uint32_t sc_flags; + bool sc_cold; }; /* Index: src/sys/dev/acpi/acpi_cpu_cstate.c diff -u src/sys/dev/acpi/acpi_cpu_cstate.c:1.11 src/sys/dev/acpi/acpi_cpu_cstate.c:1.12 --- src/sys/dev/acpi/acpi_cpu_cstate.c:1.11 Tue Jul 27 05:11:33 2010 +++ src/sys/dev/acpi/acpi_cpu_cstate.c Thu Jul 29 22:42:58 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: acpi_cpu_cstate.c,v 1.11 2010/07/27 05:11:33 jruoho Exp $ */ +/* $NetBSD: acpi_cpu_cstate.c,v 1.12 2010/07/29 22:42:58 jruoho Exp $ */ /*- * Copyright (c) 2010 Jukka Ruohonen <jruoho...@iki.fi> @@ -27,13 +27,14 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: acpi_cpu_cstate.c,v 1.11 2010/07/27 05:11:33 jruoho Exp $"); +__KERNEL_RCSID(0, "$NetBSD: acpi_cpu_cstate.c,v 1.12 2010/07/29 22:42:58 jruoho Exp $"); #include <sys/param.h> #include <sys/cpu.h> #include <sys/device.h> #include <sys/kernel.h> #include <sys/once.h> +#include <sys/mutex.h> #include <sys/timetc.h> #include <dev/pci/pcivar.h> @@ -63,7 +64,6 @@ static void acpicpu_cstate_idle_enter(struct acpicpu_softc *,int); extern struct acpicpu_softc **acpicpu_sc; -extern int acpi_suspended; /* * XXX: The local APIC timer (as well as TSC) is typically @@ -101,6 +101,8 @@ acpicpu_cstate_quirks(sc); acpicpu_cstate_attach_print(sc); + + mutex_init(&sc->sc_cstate_mtx, MUTEX_DEFAULT, IPL_NONE); } void @@ -175,9 +177,19 @@ int acpicpu_cstate_detach(device_t self) { + struct acpicpu_softc *sc = device_private(self); static ONCE_DECL(once_detach); + int rv; + + rv = RUN_ONCE(&once_detach, acpicpu_md_idle_stop); + + if (rv != 0) + return rv; + + sc->sc_flags &= ~ACPICPU_FLAG_C; + mutex_destroy(&sc->sc_cstate_mtx); - return RUN_ONCE(&once_detach, acpicpu_md_idle_stop); + return 0; } int @@ -241,9 +253,9 @@ return; } - (void)acpicpu_md_idle_stop(); + mutex_enter(&sc->sc_cstate_mtx); (void)acpicpu_cstate_cst(sc); - (void)acpicpu_md_idle_start(); + mutex_exit(&sc->sc_cstate_mtx); } static ACPI_STATUS @@ -702,6 +714,9 @@ struct acpicpu_softc *sc; int state; + if (__predict_false(ci->ci_want_resched) != 0) + return; + acpi_md_OsDisableInterrupt(); KASSERT(acpicpu_sc != NULL); @@ -710,20 +725,19 @@ sc = acpicpu_sc[ci->ci_cpuid]; - /* - * If all CPUs do not have their ACPI counterparts, the softc - * may be NULL. In this case fall back to normal C1 with HALT. - */ - if (__predict_false(sc == NULL)) { - acpicpu_md_idle_enter(ACPICPU_C_STATE_HALT, ACPI_STATE_C1); - return; - } + if (__predict_false(sc == NULL)) + goto halt; - if (__predict_false(acpi_suspended != 0)) { - acpicpu_md_idle_enter(ACPICPU_C_STATE_HALT, ACPI_STATE_C1); - return; - } + if (__predict_false(sc->sc_cold != false)) + goto halt; + + if (__predict_false((sc->sc_flags & ACPICPU_FLAG_C) == 0)) + goto halt; + + if (__predict_false(mutex_tryenter(&sc->sc_cstate_mtx) == 0)) + goto halt; + mutex_exit(&sc->sc_cstate_mtx); state = acpicpu_cstate_latency(sc); /* @@ -780,6 +794,11 @@ if ((sc->sc_flags & ACPICPU_FLAG_C_ARB) != 0) (void)AcpiWriteBitRegister(ACPI_BITREG_ARB_DISABLE, 0); + + return; + +halt: + acpicpu_md_idle_enter(ACPICPU_C_STATE_HALT, ACPI_STATE_C1); } static void