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

Reply via email to