Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Dec 2012 18:01:01 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r243760 - head/sys/dev/acpica
Message-ID:  <201212011801.qB1I11qN061413@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Sat Dec  1 18:01:01 2012
New Revision: 243760
URL: http://svnweb.freebsd.org/changeset/base/243760

Log:
  acpi_cpu: change cpu_disable_idle to be a per-cpu flag...
  
  and make it safe to manipulate and check the flag
  
  With help from:	jhb
  Tested by:	trociny, emaste, dumbbell
  MFC after:	1 week

Modified:
  head/sys/dev/acpica/acpi_cpu.c

Modified: head/sys/dev/acpica/acpi_cpu.c
==============================================================================
--- head/sys/dev/acpica/acpi_cpu.c	Sat Dec  1 17:50:39 2012	(r243759)
+++ head/sys/dev/acpica/acpi_cpu.c	Sat Dec  1 18:01:01 2012	(r243760)
@@ -92,6 +92,7 @@ struct acpi_cpu_softc {
     struct sysctl_oid	*cpu_sysctl_tree;
     int			 cpu_cx_lowest;
     int			 cpu_cx_lowest_lim;
+    int			 cpu_disable_idle; /* Disable entry to idle function */
     char 		 cpu_cx_supported[64];
 };
 
@@ -138,9 +139,6 @@ static uint32_t		 cpu_smi_cmd;	/* Value 
 static uint8_t		 cpu_cst_cnt;	/* Indicate we are _CST aware. */
 static int		 cpu_quirks;	/* Indicate any hardware bugs. */
 
-/* Runtime state. */
-static int		 cpu_disable_idle; /* Disable entry to idle function */
-
 /* Values for sysctl. */
 static struct sysctl_ctx_list cpu_sysctl_ctx;
 static struct sysctl_oid *cpu_sysctl_tree;
@@ -419,6 +417,39 @@ acpi_cpu_postattach(void *unused __unuse
 SYSINIT(acpi_cpu, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE,
     acpi_cpu_postattach, NULL);
 
+static void
+disable_idle(struct acpi_cpu_softc *sc)
+{
+    cpuset_t cpuset;
+
+    CPU_SETOF(sc->cpu_pcpu->pc_cpuid, &cpuset);
+    sc->cpu_disable_idle = TRUE;
+
+    /*
+     * Ensure that the CPU is not in idle state or in acpi_cpu_idle().
+     * Note that this code depends on the fact that the rendezvous IPI
+     * can not penetrate context where interrupts are disabled and acpi_cpu_idle
+     * is called and executed in such a context with interrupts being re-enabled
+     * right before return.
+     */
+    smp_rendezvous_cpus(cpuset, smp_no_rendevous_barrier, NULL,
+	smp_no_rendevous_barrier, NULL);
+}
+
+static void
+enable_idle(struct acpi_cpu_softc *sc)
+{
+
+    sc->cpu_disable_idle = FALSE;
+}
+
+static int
+is_idle_disabled(struct acpi_cpu_softc *sc)
+{
+
+    return (sc->cpu_disable_idle);
+}
+
 /*
  * Disable any entry to the idle function during suspend and re-enable it
  * during resume.
@@ -431,7 +462,7 @@ acpi_cpu_suspend(device_t dev)
     error = bus_generic_suspend(dev);
     if (error)
 	return (error);
-    cpu_disable_idle = TRUE;
+    disable_idle(device_get_softc(dev));
     return (0);
 }
 
@@ -439,7 +470,7 @@ static int
 acpi_cpu_resume(device_t dev)
 {
 
-    cpu_disable_idle = FALSE;
+    enable_idle(device_get_softc(dev));
     return (bus_generic_resume(dev));
 }
 
@@ -573,12 +604,14 @@ acpi_cpu_shutdown(device_t dev)
     bus_generic_shutdown(dev);
 
     /*
-     * Disable any entry to the idle function.  There is a small race where
-     * an idle thread have passed this check but not gone to sleep.  This
-     * is ok since device_shutdown() does not free the softc, otherwise
-     * we'd have to be sure all threads were evicted before returning.
+     * Disable any entry to the idle function.
+     */
+    disable_idle(device_get_softc(dev));
+
+    /*
+     * CPU devices are not truely detached and remain referenced,
+     * so their resources are not freed.
      */
-    cpu_disable_idle = TRUE;
 
     return_VALUE (0);
 }
@@ -860,7 +893,10 @@ acpi_cpu_startup(void *arg)
 
     /* Take over idling from cpu_idle_default(). */
     cpu_cx_lowest_lim = 0;
-    cpu_disable_idle = FALSE;
+    for (i = 0; i < cpu_ndevices; i++) {
+	sc = device_get_softc(cpu_devices[i]);
+	enable_idle(sc);
+    }
     cpu_idle_hook = acpi_cpu_idle;
 }
 
@@ -926,12 +962,6 @@ acpi_cpu_idle()
     uint32_t	start_time, end_time;
     int		bm_active, cx_next_idx, i;
 
-    /* If disabled, return immediately. */
-    if (cpu_disable_idle) {
-	ACPI_ENABLE_IRQS();
-	return;
-    }
-
     /*
      * Look up our CPU id to get our softc.  If it's NULL, we'll use C1
      * since there is no ACPI processor object for this CPU.  This occurs
@@ -943,6 +973,12 @@ acpi_cpu_idle()
 	return;
     }
 
+    /* If disabled, return immediately. */
+    if (is_idle_disabled(sc)) {
+	ACPI_ENABLE_IRQS();
+	return;
+    }
+
     /* Find the lowest state that has small enough latency. */
     cx_next_idx = 0;
     if (cpu_disable_deep_sleep)



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