svn commit: r195714 - in stable/7/sys: . contrib/pf dev/acpica

Alexander Motin mav at FreeBSD.org
Thu Jul 16 08:27:13 UTC 2009


Author: mav
Date: Thu Jul 16 08:27:12 2009
New Revision: 195714
URL: http://svn.freebsd.org/changeset/base/195714

Log:
  MFC rev. 191760, 191763, 191764.
  
  Avoid comparing negative signed to positive unsignad values. It was
  leading to a bug, when C-state does not decrease on sleep shorter then
  declared transition latency. Fixing this deprecates workaround for broken
  C-states on some hardware.
  
  By the way, change state selecting logic a bit. Instead of last sleep
  time use short-time average of it. Global interrupts rate in system is a
  quite random value, to corellate subsequent sleeps so directly.
  
  Make dev.cpu.X.cx_usage sysctl also report current average of sleep time.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/acpica/acpi_cpu.c

Modified: stable/7/sys/dev/acpica/acpi_cpu.c
==============================================================================
--- stable/7/sys/dev/acpica/acpi_cpu.c	Wed Jul 15 22:27:36 2009	(r195713)
+++ stable/7/sys/dev/acpica/acpi_cpu.c	Thu Jul 16 08:27:12 2009	(r195714)
@@ -79,7 +79,6 @@ struct acpi_cpu_softc {
     int			 cpu_features;	/* Child driver supported features. */
     /* Runtime state. */
     int			 cpu_non_c3;	/* Index of lowest non-C3 state. */
-    int			 cpu_short_slp;	/* Count of < 1us sleeps. */
     u_int		 cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
     /* Values for sysctl. */
     struct sysctl_ctx_list cpu_sysctl_ctx;
@@ -875,43 +874,13 @@ acpi_cpu_idle()
 	return;
     }
 
-    /*
-     * If we slept 100 us or more, use the lowest Cx state.  Otherwise,
-     * find the lowest state that has a latency less than or equal to
-     * the length of our last sleep.
-     */
-    cx_next_idx = sc->cpu_cx_lowest;
-    if (sc->cpu_prev_sleep < 100) {
-	/*
-	 * If we sleep too short all the time, this system may not implement
-	 * C2/3 correctly (i.e. reads return immediately).  In this case,
-	 * back off and use the next higher level.
-	 * It seems that when you have a dual core cpu (like the Intel Core Duo)
-	 * that both cores will get out of C3 state as soon as one of them
-	 * requires it. This breaks the sleep detection logic as the sleep
-	 * counter is local to each cpu. Disable the sleep logic for now as a
-	 * workaround if there's more than one CPU. The right fix would probably
-	 * be to add quirks for system that don't really support C3 state.
-	 */
-	if (mp_ncpus < 2 && sc->cpu_prev_sleep <= 1) {
-	    sc->cpu_short_slp++;
-	    if (sc->cpu_short_slp == 1000 && sc->cpu_cx_lowest != 0) {
-		if (sc->cpu_non_c3 == sc->cpu_cx_lowest && sc->cpu_non_c3 != 0)
-		    sc->cpu_non_c3--;
-		sc->cpu_cx_lowest--;
-		sc->cpu_short_slp = 0;
-		device_printf(sc->cpu_dev,
-		    "too many short sleeps, backing off to C%d\n",
-		    sc->cpu_cx_lowest + 1);
-	    }
-	} else
-	    sc->cpu_short_slp = 0;
-
-	for (i = sc->cpu_cx_lowest; i >= 0; i--)
-	    if (sc->cpu_cx_states[i].trans_lat <= sc->cpu_prev_sleep) {
-		cx_next_idx = i;
-		break;
-	    }
+    /* Find the lowest state that has small enough latency. */
+    cx_next_idx = 0;
+    for (i = sc->cpu_cx_lowest; i >= 0; i--) {
+	if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) {
+	    cx_next_idx = i;
+	    break;
+	}
     }
 
     /*
@@ -936,10 +905,10 @@ acpi_cpu_idle()
     /*
      * Execute HLT (or equivalent) and wait for an interrupt.  We can't
      * calculate the time spent in C1 since the place we wake up is an
-     * ISR.  Assume we slept one quantum and return.
+     * ISR.  Assume we slept half of quantum and return.
      */
     if (cx_next->type == ACPI_STATE_C1) {
-	sc->cpu_prev_sleep = 1000000 / hz;
+	sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + 500000 / hz) / 4;
 	acpi_cpu_c1();
 	return;
     }
@@ -982,9 +951,9 @@ acpi_cpu_idle()
     }
     ACPI_ENABLE_IRQS();
 
-    /* Find the actual time asleep in microseconds, minus overhead. */
+    /* Find the actual time asleep in microseconds. */
     end_time = acpi_TimerDelta(end_time, start_time);
-    sc->cpu_prev_sleep = PM_USEC(end_time) - cx_next->trans_lat;
+    sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + PM_USEC(end_time)) / 4;
 }
 
 /*
@@ -1106,8 +1075,9 @@ acpi_cpu_usage_sysctl(SYSCTL_HANDLER_ARG
 	    sbuf_printf(&sb, "%u.%02u%% ", (u_int)(whole / sum),
 		(u_int)(fract / sum));
 	} else
-	    sbuf_printf(&sb, "0%% ");
+	    sbuf_printf(&sb, "0.00%% ");
     }
+    sbuf_printf(&sb, "last %dus", sc->cpu_prev_sleep);
     sbuf_trim(&sb);
     sbuf_finish(&sb);
     sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);


More information about the svn-src-all mailing list