changeset 10961:76b611950d1e

6887482 CPU power management broken on SPARC workstations
author aubrey.li@intel.com
date Thu, 05 Nov 2009 12:09:02 -0500
parents dcc7d6f9faa8
children 6e86215199ca
files usr/src/uts/common/io/cpudrv.c usr/src/uts/common/sys/cpudrv.h usr/src/uts/i86pc/io/cpudrv_mach.c usr/src/uts/i86pc/os/cpupm/cpu_idle.c usr/src/uts/i86pc/os/cpupm/cpupm_mach.c
diffstat 5 files changed, 78 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/cpudrv.c	Thu Nov 05 08:59:19 2009 -0800
+++ b/usr/src/uts/common/io/cpudrv.c	Thu Nov 05 12:09:02 2009 -0500
@@ -277,17 +277,6 @@
 			return (DDI_FAILURE);
 		}
 
-		mutex_enter(&cpu_lock);
-		cpudsp->cp = cpu_get(cpudsp->cpu_id);
-		mutex_exit(&cpu_lock);
-		if (cpudsp->cp == NULL) {
-			cmn_err(CE_WARN, "cpudrv_attach: instance %d: "
-			    "can't get cpu_t", ddi_get_instance(cpudsp->dip));
-			ddi_soft_state_free(cpudrv_state, instance);
-			cpudrv_enabled = B_FALSE;
-			return (DDI_FAILURE);
-		}
-
 		mutex_init(&cpudsp->lock, NULL, MUTEX_DRIVER, NULL);
 		if (cpudrv_is_enabled(cpudsp)) {
 			if (cpudrv_init(cpudsp) != DDI_SUCCESS) {
@@ -556,6 +545,11 @@
 		return (DDI_FAILURE);
 	}
 
+	/*
+	 * We're not ready until we can  get a cpu_t
+	 */
+	is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
+
 	mutex_enter(&cpudsp->lock);
 	cpudrvpm = &(cpudsp->cpudrv_pm);
 
@@ -595,15 +589,16 @@
 	 * Additionally, for x86 platforms we cannot power manage an instance,
 	 * until it has been initialized.
 	 */
-	ASSERT(cpudsp->cp);
-	is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
-	if (!is_ready) {
-		DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
-		    "CPU not ready for x-calls\n", instance));
-	} else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
-		DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
-		    "waiting for all CPUs to be power manageable\n",
-		    instance));
+	if (is_ready) {
+		is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
+		if (!is_ready) {
+			DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
+			    "CPU not ready for x-calls\n", instance));
+		} else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
+			DPRINTF(D_POWER, ("cpudrv_power: instance %d: "
+			    "waiting for all CPUs to be power manageable\n",
+			    instance));
+		}
 	}
 	if (!is_ready) {
 		CPUDRV_RESET_GOVERNOR_THREAD(cpudrvpm);
@@ -986,6 +981,11 @@
 	cnt = msnsecs[state] - cpupm->lastquan_mstate[state]; \
 	cpupm->lastquan_mstate[state] = msnsecs[state]
 
+	/*
+	 * We're not ready until we can  get a cpu_t
+	 */
+	is_ready = (cpudrv_get_cpu(cpudsp) == DDI_SUCCESS);
+
 	mutex_enter(&cpudsp->lock);
 	cpupm = &(cpudsp->cpudrv_pm);
 	if (cpupm->timeout_id == 0) {
@@ -1003,15 +1003,17 @@
 	 * Additionally, for x86 platforms we cannot power manage an
 	 * instance, until it has been initialized.
 	 */
-	ASSERT(cpudsp->cp);
-	is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
-	if (!is_ready) {
-		DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
-		    "CPU not ready for x-calls\n", ddi_get_instance(dip)));
-	} else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
-		DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
-		    "waiting for all CPUs to be power manageable\n",
-		    ddi_get_instance(dip)));
+	if (is_ready) {
+		is_ready = CPUDRV_XCALL_IS_READY(cpudsp->cpu_id);
+		if (!is_ready) {
+			DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
+			    "CPU not ready for x-calls\n",
+			    ddi_get_instance(dip)));
+		} else if (!(is_ready = cpudrv_power_ready(cpudsp->cp))) {
+			DPRINTF(D_PM_MONITOR, ("cpudrv_monitor: instance %d: "
+			    "waiting for all CPUs to be power manageable\n",
+			    ddi_get_instance(dip)));
+		}
 	}
 	if (!is_ready) {
 		/*
@@ -1041,17 +1043,6 @@
 		goto do_return;
 	}
 
-	mutex_enter(&cpu_lock);
-	if (cpudsp->cp == NULL &&
-	    (cpudsp->cp = cpu_get(cpudsp->cpu_id)) == NULL) {
-		mutex_exit(&cpu_lock);
-		CPUDRV_MONITOR_INIT(cpudsp);
-		mutex_exit(&cpudsp->lock);
-		cmn_err(CE_WARN, "cpudrv_monitor: instance %d: can't get "
-		    "cpu_t", ddi_get_instance(dip));
-		goto do_return;
-	}
-
 	if (!cpupm->pm_started) {
 		cpupm->pm_started = B_TRUE;
 		cpudrv_set_supp_freqs(cpudsp);
@@ -1068,7 +1059,6 @@
 	 */
 	if (cpupm->lastquan_ticks == 0) {
 		cpupm->lastquan_ticks = NSEC_TO_TICK(gethrtime());
-		mutex_exit(&cpu_lock);
 		CPUDRV_MONITOR_INIT(cpudsp);
 		mutex_exit(&cpudsp->lock);
 		goto do_return;
@@ -1087,7 +1077,7 @@
 	tick_cnt = ticks - cpupm->lastquan_ticks;
 	ASSERT(tick_cnt != 0);
 	cpupm->lastquan_ticks = ticks;
-	mutex_exit(&cpu_lock);
+
 	/*
 	 * Time taken between recording the current counts and
 	 * arranging the next call of this routine is an error in our
@@ -1178,3 +1168,32 @@
 	cv_signal(&cpupm->timeout_cv);
 	mutex_exit(&cpupm->timeout_lock);
 }
+
+/*
+ * get cpu_t structure for cpudrv_devstate_t
+ */
+int
+cpudrv_get_cpu(cpudrv_devstate_t *cpudsp)
+{
+	ASSERT(cpudsp != NULL);
+
+	/*
+	 * return DDI_SUCCESS if cpudrv_devstate_t
+	 * already contains cpu_t structure
+	 */
+	if (cpudsp->cp != NULL)
+		return (DDI_SUCCESS);
+
+	if (MUTEX_HELD(&cpu_lock)) {
+		cpudsp->cp = cpu_get(cpudsp->cpu_id);
+	} else {
+		mutex_enter(&cpu_lock);
+		cpudsp->cp = cpu_get(cpudsp->cpu_id);
+		mutex_exit(&cpu_lock);
+	}
+
+	if (cpudsp->cp == NULL)
+		return (DDI_FAILURE);
+
+	return (DDI_SUCCESS);
+}
--- a/usr/src/uts/common/sys/cpudrv.h	Thu Nov 05 08:59:19 2009 -0800
+++ b/usr/src/uts/common/sys/cpudrv.h	Thu Nov 05 12:09:02 2009 -0500
@@ -204,6 +204,7 @@
 extern boolean_t cpudrv_power_ready(cpu_t *);
 extern boolean_t cpudrv_is_enabled(cpudrv_devstate_t *);
 extern void cpudrv_set_supp_freqs(cpudrv_devstate_t *);
+extern int cpudrv_get_cpu(cpudrv_devstate_t *);
 
 #endif /* _KERNEL */
 
--- a/usr/src/uts/i86pc/io/cpudrv_mach.c	Thu Nov 05 08:59:19 2009 -0800
+++ b/usr/src/uts/i86pc/io/cpudrv_mach.c	Thu Nov 05 12:09:02 2009 -0500
@@ -335,6 +335,12 @@
 uint_t
 cpudrv_get_speeds(cpudrv_devstate_t *cpudsp, int **speeds)
 {
+	/*
+	 * return nspeeds = 0 if can't get cpu_t
+	 */
+	if (cpudrv_get_cpu(cpudsp) != DDI_SUCCESS)
+		return (0);
+
 	return (cpupm_get_speeds(cpudsp->cp, speeds));
 }
 
--- a/usr/src/uts/i86pc/os/cpupm/cpu_idle.c	Thu Nov 05 08:59:19 2009 -0800
+++ b/usr/src/uts/i86pc/os/cpupm/cpu_idle.c	Thu Nov 05 12:09:02 2009 -0500
@@ -741,7 +741,7 @@
 	/*
 	 * idle cpu points back to the generic one
 	 */
-	idle_cpu = CPU->cpu_m.mcpu_idle_cpu = non_deep_idle_cpu;
+	idle_cpu = cp->cpu_m.mcpu_idle_cpu = non_deep_idle_cpu;
 	disp_enq_thread = non_deep_idle_disp_enq_thread;
 
 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
@@ -780,6 +780,14 @@
 	cpu_acpi_cstate_t *cstate;
 	uint_t cpu_max_cstates, i;
 
+	/*
+	 * place the CPUs in a safe place so that we can disable
+	 * deep c-state on them.
+	 */
+	pause_cpus(NULL);
+	cp->cpu_m.mcpu_idle_cpu = non_deep_idle_cpu;
+	start_cpus();
+
 	cstate = (cpu_acpi_cstate_t *)CPU_ACPI_CSTATES(handle);
 	if (cstate) {
 		cpu_max_cstates = cpu_acpi_get_max_cstates(handle);
--- a/usr/src/uts/i86pc/os/cpupm/cpupm_mach.c	Thu Nov 05 08:59:19 2009 -0800
+++ b/usr/src/uts/i86pc/os/cpupm/cpupm_mach.c	Thu Nov 05 12:09:02 2009 -0500
@@ -526,7 +526,6 @@
 	    (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state);
 	cpupm_state_domains_t *dptr;
 	uint32_t pm_domain;
-	ulong_t iflag;
 
 	ASSERT(mach_state);
 
@@ -560,15 +559,13 @@
 
 	/*
 	 * We found one matched power domain, remove CPU from its cpuset.
-	 * Interrupt is disabled here to avoid the race conditions between
+	 * pm_lock(spin lock) here to avoid the race conditions between
 	 * event change notification and cpu remove.
 	 */
-	iflag = intr_clear();
 	mutex_enter(&dptr->pm_lock);
 	if (CPU_IN_SET(dptr->pm_cpus, cp->cpu_id))
 		CPUSET_DEL(dptr->pm_cpus, cp->cpu_id);
 	mutex_exit(&dptr->pm_lock);
-	intr_restore(iflag);
 }
 
 void