Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Jul 2012 16:57:13 +0000 (UTC)
From:      Sean Bruno <sbruno@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r238004 - in head: etc/rc.d sys/dev/acpica
Message-ID:  <201207021657.q62GvD7j082717@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sbruno
Date: Mon Jul  2 16:57:13 2012
New Revision: 238004
URL: http://svn.freebsd.org/changeset/base/238004

Log:
  Cosmetic display change of Cx states via cx_supported sysctl entries.
  
  Adjust power_profile script to handle the new world order as well.
  
  Some vendors are opting out of a C2 state and only defining C1 & C3.  This
  leads the acpi_cpu display to indicate that the machine supports C1 & C2
  which is caused by the (mis)use of the index of the cx_state array as the
  ACPI_STATE_CX value.
  
  e.g. the code was pretending that cx_state[i] would
  always convert to i by subtracting 1.
  
  cx_state[2] == ACPI_STATE_C3
  cx_state[1] == ACPI_STATE_C2
  cx_state[0] == ACPI_STATE_C1
  
  however, on certain machines this would lead to
  cx_state[1] == ACPI_STATE_C3
  cx_state[0] == ACPI_STATE_C1
  
  This didn't break anything but led to a display of:
   * dev.cpu.0.cx_supported: C1/1 C2/96
  
  Instead of
   * dev.cpu.0.cx_supported: C1/1 C3/96
  
  MFC after:	2 weeks

Modified:
  head/etc/rc.d/power_profile
  head/sys/dev/acpica/acpi_cpu.c

Modified: head/etc/rc.d/power_profile
==============================================================================
--- head/etc/rc.d/power_profile	Mon Jul  2 16:44:09 2012	(r238003)
+++ head/etc/rc.d/power_profile	Mon Jul  2 16:57:13 2012	(r238004)
@@ -90,7 +90,7 @@ node="dev.cpu.0.freq"
 highest_value="`(sysctl -n dev.cpu.0.freq_levels | \
 	awk '{ split($0, a, "[/ ]"); print a[1] }' -) 2> /dev/null`"
 lowest_value="`(sysctl -n dev.cpu.0.freq_levels | \
-	awk '{ split($0, a, "[/ ]"); print a[length(a) - 1] }' -) 2> /dev/null`"
+	awk '{ split($0, a, "[ /]"); print a[length(a) - 1] }' -) 2> /dev/null`"
 eval value=\$${profile}_cpu_freq
 sysctl_set
 

Modified: head/sys/dev/acpica/acpi_cpu.c
==============================================================================
--- head/sys/dev/acpica/acpi_cpu.c	Mon Jul  2 16:44:09 2012	(r238003)
+++ head/sys/dev/acpica/acpi_cpu.c	Mon Jul  2 16:57:13 2012	(r238004)
@@ -88,7 +88,7 @@ struct acpi_cpu_softc {
     /* Values for sysctl. */
     struct sysctl_ctx_list cpu_sysctl_ctx;
     struct sysctl_oid	*cpu_sysctl_tree;
-    int			 cpu_cx_lowest;
+    int			 cpu_cx_lowest; /* Index of lowest Cx state in cpu_cx_states[] */
     char 		 cpu_cx_supported[64];
     int			 cpu_rid;
 };
@@ -144,7 +144,8 @@ static int		 cpu_cx_count;	/* Number of 
 static struct sysctl_ctx_list cpu_sysctl_ctx;
 static struct sysctl_oid *cpu_sysctl_tree;
 static int		 cpu_cx_generic;
-static int		 cpu_cx_lowest;
+/* Lowest valid Cstate for all cpus -- Cx */
+static int		 global_lowest_cstate;
 
 static device_t		*cpu_devices;
 static int		 cpu_ndevices;
@@ -871,7 +872,7 @@ acpi_cpu_startup(void *arg)
 	"Global lowest Cx sleep state to use");
 
     /* Take over idling from cpu_idle_default(). */
-    cpu_cx_lowest = 0;
+    global_lowest_cstate = 0;
     cpu_disable_idle = FALSE;
     cpu_idle_hook = acpi_cpu_idle;
 }
@@ -889,7 +890,8 @@ acpi_cpu_cx_list(struct acpi_cpu_softc *
     sbuf_new(&sb, sc->cpu_cx_supported, sizeof(sc->cpu_cx_supported),
 	SBUF_FIXEDLEN);
     for (i = 0; i < sc->cpu_cx_count; i++) {
-	sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cpu_cx_states[i].trans_lat);
+	sbuf_printf(&sb, "C%d/%d ", sc->cpu_cx_states[i].type,
+				    sc->cpu_cx_states[i].trans_lat);
 	if (sc->cpu_cx_states[i].type < ACPI_STATE_C3)
 	    sc->cpu_non_c3 = i;
 	else
@@ -963,9 +965,10 @@ acpi_cpu_idle()
 
     /* Find the lowest state that has small enough latency. */
     cx_next_idx = 0;
-    if (cpu_disable_deep_sleep)
+    if (cpu_disable_deep_sleep) {
+	/* Chose the lowest valid index in the cpu_cx_states array */
 	i = min(sc->cpu_cx_lowest, sc->cpu_non_c3);
-    else
+    } else
 	i = sc->cpu_cx_lowest;
     for (; i >= 0; i--) {
 	if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) {
@@ -1080,8 +1083,8 @@ acpi_cpu_notify(ACPI_HANDLE h, UINT32 no
 	if (isc->cpu_cx_count > cpu_cx_count)
 	    cpu_cx_count = isc->cpu_cx_count;
     }
-    if (sc->cpu_cx_lowest < cpu_cx_lowest)
-	acpi_cpu_set_cx_lowest(sc, min(cpu_cx_lowest, sc->cpu_cx_count - 1));
+    if (sc->cpu_cx_lowest < global_lowest_cstate)
+	acpi_cpu_set_cx_lowest(sc, sc->cpu_cx_states[sc->cpu_cx_lowest].type);
     ACPI_SERIAL_END(cpu);
 }
 
@@ -1208,13 +1211,31 @@ acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARG
     return (0);
 }
 
+/*
+ * val is the ACPI_STATE_CX enum request by the caller
+ */
 static int
 acpi_cpu_set_cx_lowest(struct acpi_cpu_softc *sc, int val)
 {
     int i;
 
     ACPI_SERIAL_ASSERT(cpu);
-    sc->cpu_cx_lowest = val;
+    /*
+     * scan list of valid cstates.  if we do no
+     * find a match to the requested val, return
+     * EINVAL
+     * once we match, set cpu_cx_lowest to the found
+     * index i
+     */
+     for (i = 0; i < sc->cpu_cx_count; i++) {
+         if (sc->cpu_cx_states[i].type == val) {
+              sc->cpu_cx_lowest = i;
+              break;
+         }
+     }
+     if (i == sc->cpu_cx_count)
+          return (EINVAL);
+
 
     /* If not disabling, cache the new lowest non-C3 state. */
     sc->cpu_non_c3 = 0;
@@ -1238,21 +1259,22 @@ acpi_cpu_cx_lowest_sysctl(SYSCTL_HANDLER
     int		 val, error;
 
     sc = (struct acpi_cpu_softc *) arg1;
-    snprintf(state, sizeof(state), "C%d", sc->cpu_cx_lowest + 1);
+    snprintf(state, sizeof(state), "C%d",
+            sc->cpu_cx_states[sc->cpu_cx_lowest].type);
     error = sysctl_handle_string(oidp, state, sizeof(state), req);
     if (error != 0 || req->newptr == NULL)
 	return (error);
     if (strlen(state) < 2 || toupper(state[0]) != 'C')
 	return (EINVAL);
-    val = (int) strtol(state + 1, NULL, 10) - 1;
-    if (val < 0 || val > sc->cpu_cx_count - 1)
+    val = (int) strtol(state + 1, NULL, 10);
+    if (val < 0 || val > MAX_CX_STATES)
 	return (EINVAL);
 
     ACPI_SERIAL_BEGIN(cpu);
-    acpi_cpu_set_cx_lowest(sc, val);
+    error = acpi_cpu_set_cx_lowest(sc, val);
     ACPI_SERIAL_END(cpu);
 
-    return (0);
+    return (error);
 }
 
 static int
@@ -1262,24 +1284,28 @@ acpi_cpu_global_cx_lowest_sysctl(SYSCTL_
     char	state[8];
     int		val, error, i;
 
-    snprintf(state, sizeof(state), "C%d", cpu_cx_lowest + 1);
+    snprintf(state, sizeof(state), "C%d", global_lowest_cstate);
     error = sysctl_handle_string(oidp, state, sizeof(state), req);
     if (error != 0 || req->newptr == NULL)
 	return (error);
     if (strlen(state) < 2 || toupper(state[0]) != 'C')
 	return (EINVAL);
-    val = (int) strtol(state + 1, NULL, 10) - 1;
-    if (val < 0 || val > cpu_cx_count - 1)
+    val = (int) strtol(state + 1, NULL, 10);
+    if (val < 0 || val > MAX_CX_STATES)
 	return (EINVAL);
-    cpu_cx_lowest = val;
 
     /* Update the new lowest useable Cx state for all CPUs. */
     ACPI_SERIAL_BEGIN(cpu);
     for (i = 0; i < cpu_ndevices; i++) {
 	sc = device_get_softc(cpu_devices[i]);
-	acpi_cpu_set_cx_lowest(sc, min(val, sc->cpu_cx_count - 1));
+	error =  acpi_cpu_set_cx_lowest(sc, val);
+	if (error) {
+		ACPI_SERIAL_END(cpu);
+		return(error);
+	}
     }
     ACPI_SERIAL_END(cpu);
+    global_lowest_cstate = val;
 
     return (0);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207021657.q62GvD7j082717>