Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Sep 2010 08:11:43 +0900
From:      Taku YAMAMOTO <taku@tackymt.homeip.net>
To:        freebsd-acpi@freebsd.org
Subject:   Follow-up: CPU C-state storange on Panasonic TOUGH BOOK CF-R9
Message-ID:  <20100915081143.c7783553.taku@tackymt.homeip.net>
In-Reply-To: <20100915080124.c6d53391.taku@tackymt.homeip.net>
References:  <4C8BCAC5.5050008@root.org> <mailpost.1284277196.1767764.83548.mailing.freebsd.current@FreeBSD.cs.nctu.edu.tw> <4C8C8B64.8020907@FreeBSD.org> <20100912182625.c49d3f1d.nork@FreeBSD.org> <4C8C9F06.4090505@icyb.net.ua> <20100912190537.621e357e.nork@FreeBSD.org> <20100912190952.8c0d5726.nork@FreeBSD.org> <20100912192518.e791c191.nork@FreeBSD.org> <4C8CAC01.70004@icyb.net.ua> <4C8CAD7D.50602@FreeBSD.org> <4C8CF03F.1050902@icyb.net.ua> <4C8CF412.9080601@icyb.net.ua> <4C8CF91A.4040804@FreeBSD.org> <4C8E5A5D.6000303@icyb.net.ua> <4C8F35FD.2090603@freebsd.org> <20100915080124.c6d53391.taku@tackymt.homeip.net>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.

--Multipart=_Wed__15_Sep_2010_08_11_43_+0900_VGPL5SoSZBB5p/0F
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

On Wed, 15 Sep 2010 08:01:24 +0900
Taku YAMAMOTO <taku@tackymt.homeip.net> wrote:

> On Tue, 14 Sep 2010 11:44:45 +0300
> Andriy Gapon <avg@freebsd.org> wrote:
> 
> > Additionally, it seems that we do not currently have any support for Functional
> > Fixed Hardware (FFH) way of providing C states.  In this case _CST returns GAS
> > of a register used to enter a C state with address space ID set to
> > ACPI_ADR_SPACE_FIXED_HARDWARE (0x7f/127).  Such addresses should be handled in a
> > special way:
> > ftp://download.intel.com/technology/IAPC/acpi/downloads/30222305.pdf
> > 
> > Currently we simply (and silently) ignore such _CST entries.
> > I think that this should be useful (if not necessary) with mwait.
> 
> I have a proof-of-concept, quick'n'dirty patch against pre-r212541
> to utilize FFH _CST.
> 
> Unfortunately I have no time to catch up the latest and fantastic work by mav,
> though.

Uh, the patch got eaten by mailman...
Here it is.

-- 
-|-__   YAMAMOTO, Taku
 | __ <     <taku@tackymt.homeip.net>

      - A chicken is an egg's way of producing more eggs. -

--Multipart=_Wed__15_Sep_2010_08_11_43_+0900_VGPL5SoSZBB5p/0F
Content-Type: text/plain;
 name="native_cx-20100724.patch"
Content-Disposition: attachment;
 filename="native_cx-20100724.patch"
Content-Transfer-Encoding: 7bit

diff -rup /sys/dev/acpica/acpi_cpu.c ./dev/acpica/acpi_cpu.c
--- sys/dev/acpica/acpi_cpu.c	2010-02-11 17:50:21.000000000 +0900
+++ sys/dev/acpica/acpi_cpu.c	2010-05-12 05:21:13.000000000 +0900
@@ -65,6 +65,13 @@ struct acpi_cx {
     uint32_t		 trans_lat;	/* Transition latency (usec). */
     uint32_t		 power;		/* Power consumed (mW). */
     int			 res_type;	/* Resource type for p_lvlx. */
+#ifdef ACPI_USE_NATIVE_CX
+#define pseudo_BUS_SPACE_FFIXEDHW	-1	/* FFixedHW pseudo resource */
+    uint8_t		 vendor;	/* Encoded as BitWidth */
+    uint8_t		 classcode;	/* Encoded as BitOffset */
+    uint8_t		 arg1;		/* Encoded as AccessWidth */
+    uint64_t		 arg0;		/* Encoded as Address */
+#endif /* ACPI_USE_NATIVE_CX */
 };
 #define MAX_CX_STATES	 8
 
@@ -336,6 +343,9 @@ acpi_cpu_attach(device_t dev)
      * SMP control where each CPU can have different settings.
      */
     sc->cpu_features = ACPI_CAP_SMP_SAME | ACPI_CAP_SMP_SAME_C3;
+#ifdef ACPI_USE_NATIVE_CX /* XXX */
+    sc->cpu_features |= ACPI_CAP_SMP_C1_NATIVE | ACPI_CAP_SMP_CX_NATIVE;
+#endif
     if (devclass_get_drivers(acpi_cpu_devclass, &drivers, &drv_count) == 0) {
 	for (i = 0; i < drv_count; i++) {
 	    if (ACPI_GET_FEATURES(drivers[i], &features) == 0)
@@ -688,9 +698,13 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *s
 	switch (cx_ptr->type) {
 	case ACPI_STATE_C1:
 	    sc->cpu_non_c3 = i;
+#ifdef ACPI_USE_NATIVE_CX
+	    break;
+#else
 	    cx_ptr++;
 	    sc->cpu_cx_count++;
 	    continue;
+#endif
 	case ACPI_STATE_C2:
 	    if (cx_ptr->trans_lat > 100) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -721,6 +735,21 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *s
 	}
 #endif
 
+#ifdef ACPI_USE_NATIVE_CX
+	/* Check for FFixedHW first. */
+	if (acpi_PkgGasFFH(pkg, 0, &cx_ptr->vendor, &cx_ptr->classcode, &cx_ptr->arg1, &cx_ptr->arg0) == 0) {
+	    /* We do not increment cpu_rid, because FixedHW isn't a resource. */
+	    cx_ptr->res_type = pseudo_BUS_SPACE_FFIXEDHW;
+	    ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			     "acpi_cpu%d: Got C%d - %d latency\n",
+			     device_get_unit(sc->cpu_dev), cx_ptr->type,
+			     cx_ptr->trans_lat));
+	    cx_ptr++;
+	    sc->cpu_cx_count++;
+	    continue;
+	}
+#endif
+
 	/* Allocate the control register for C2 or C3. */
 	acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->res_type, &sc->cpu_rid,
 	    &cx_ptr->p_lvlx, RF_SHAREABLE);
@@ -779,6 +808,8 @@ acpi_cpu_startup(void *arg)
 	    if (sc->cpu_cx_count < cpu_cx_count)
 		cpu_cx_count = sc->cpu_cx_count;
 	}
+	if (cpu_cx_count <= 1)
+	    return;
     } else {
 	/*
 	 * We are using _CST mode, remove C3 state if necessary.
@@ -859,14 +890,12 @@ acpi_cpu_startup_cx(struct acpi_cpu_soft
 		    (void *)sc, 0, acpi_cpu_usage_sysctl, "A",
 		    "percent usage for each Cx state");
 
-#ifdef notyet
     /* Signal platform that we can handle _CST notification. */
     if (!cpu_cx_generic && cpu_cst_cnt != 0) {
 	ACPI_LOCK(acpi);
 	AcpiOsWritePort(cpu_smi_cmd, cpu_cst_cnt, 8);
 	ACPI_UNLOCK(acpi);
     }
-#endif
 }
 
 /*
@@ -933,7 +962,11 @@ acpi_cpu_idle()
      * precisely calculate the time spent in C1 since the place we wake up
      * is an ISR.  Assume we slept no more than half of quantum.
      */
-    if (cx_next->type == ACPI_STATE_C1) {
+    if (cx_next->type == ACPI_STATE_C1
+#ifdef ACPI_USE_NATIVE_CX
+	&& cx_next->vendor == 0 && cx_next->classcode == 0
+#endif
+	    ) {
 	AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
 	acpi_cpu_c1();
 	AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
@@ -958,6 +991,12 @@ acpi_cpu_idle()
      * is the only reliable time source.
      */
     AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
+#ifdef ACPI_USE_NATIVE_CX
+    if (cx_next->res_type == pseudo_BUS_SPACE_FFIXEDHW) {
+	acpi_cpu_cx_native(cx_next->vendor, cx_next->classcode, cx_next->arg1, cx_next->arg0);
+	AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+    } else {
+#endif
     CPU_GET_REG(cx_next->p_lvlx, 1);
 
     /*
@@ -967,6 +1006,9 @@ acpi_cpu_idle()
      */
     AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
     AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+#ifdef ACPI_USE_NATIVE_CX
+    }
+#endif
 
     /* Enable bus master arbitration and disable bus master wakeup. */
     if (cx_next->type == ACPI_STATE_C3 &&
diff -rup /sys/dev/acpica/acpi_package.c ./dev/acpica/acpi_package.c
--- sys/dev/acpica/acpi_package.c	2010-05-06 21:14:43.080994553 +0900
+++ sys/dev/acpica/acpi_package.c	2010-05-12 05:22:33.000000000 +0900
@@ -103,11 +103,9 @@ acpi_PkgStr(ACPI_OBJECT *res, int idx, v
     return (0);
 }
 
-int
-acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
-    struct resource **dst, u_int flags)
+static int
+acpi_get_PkgGas(ACPI_OBJECT *res, int idx, ACPI_GENERIC_ADDRESS *gas)
 {
-    ACPI_GENERIC_ADDRESS gas;
     ACPI_OBJECT *obj;
 
     obj = &res->Package.Elements[idx];
@@ -115,11 +113,46 @@ acpi_PkgGas(device_t dev, ACPI_OBJECT *r
 	obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3)
 	return (EINVAL);
 
-    memcpy(&gas, obj->Buffer.Pointer + 3, sizeof(gas));
+    memcpy(gas, obj->Buffer.Pointer + 3, sizeof(*gas));
+    return (0);
+}
+
+int
+acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
+    struct resource **dst, u_int flags)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    int r;
 
+    r = acpi_get_PkgGas(res, idx, &gas);
+    if (r != 0)
+	return (r);
     return (acpi_bus_alloc_gas(dev, type, rid, &gas, dst, flags));
 }
 
+int
+acpi_PkgGasFFH(ACPI_OBJECT *res, int idx, uint8_t *vendor, uint8_t *classcode,
+    uint8_t *arg1, UINT64 *arg0)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    int r;
+
+    r = acpi_get_PkgGas(res, idx, &gas);
+    if (r != 0)
+	return (r);
+
+    if (gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE)
+	return (EOPNOTSUPP);
+
+    /* Extract encoded values. */
+    *vendor = gas.BitWidth;
+    *classcode = gas.BitOffset;
+    *arg1 = gas.AccessWidth;
+    *arg0 = gas.Address;
+
+    return (0);
+}
+
 ACPI_HANDLE
 acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj)
 {
diff -rup /sys/dev/acpica/acpivar.h ./dev/acpica/acpivar.h
--- sys/dev/acpica/acpivar.h	2010-05-06 21:14:43.140066765 +0900
+++ sys/dev/acpica/acpivar.h	2010-05-10 05:29:23.000000000 +0900
@@ -201,6 +201,7 @@ extern struct mtx			acpi_mutex;
 #define ACPI_CAP_SMP_DIFF_CX	(1 << 6) /* MP Cx (different, using _CSD) */
 #define ACPI_CAP_SMP_DIFF_TX	(1 << 7) /* MP Tx (different, using _TSD) */
 #define ACPI_CAP_SMP_C1_NATIVE	(1 << 8) /* MP C1 support other than halt */
+#define ACPI_CAP_SMP_CX_NATIVE	(1 << 9) /* MP Cx support other than halt */
 
 /*
  * Quirk flags.
@@ -449,6 +450,8 @@ int		acpi_PkgInt32(ACPI_OBJECT *res, int
 int		acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size);
 int		acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type,
 		    int *rid, struct resource **dst, u_int flags);
+int		acpi_PkgGasFFH(ACPI_OBJECT *res, int idx, uint8_t *vendor,
+		    uint8_t *classcode, uint8_t *arg1, UINT64 *arg0);
 ACPI_HANDLE	acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj);
 
 /*
diff -rup /sys/i386/acpica/acpi_machdep.c ./i386/acpica/acpi_machdep.c
--- sys/i386/acpica/acpi_machdep.c	2010-05-06 21:15:10.955047053 +0900
+++ sys/i386/acpica/acpi_machdep.c	2010-05-11 04:51:27.000000000 +0900
@@ -560,6 +560,47 @@ acpi_cpu_c1()
 }
 
 /*
+ * vendor: ACPI_GENERIC_ADDRESS.BitWidth (8-bit).
+ * classcode: ACPI_GENERIC_ADDRESS.BitOffset (8-bit).
+ * arg1: ACPI_GENERIC_ADDRESS.AccessWidth (8-bit).
+ * arg0: ACPI_GENERIC_ADDRESS.Address (64-bit).
+ */
+void
+acpi_cpu_cx_native(uint8_t vendor, uint8_t classcode, uint8_t arg1, uint64_t arg0)
+{
+	switch (vendor) {
+	case 1:	/* Intel */
+		switch (classcode) {
+		case 1:
+			/*
+			 * C1 I/O then HLT.
+			 * arg0: I/O port address to inb.
+			 * arg1: not used (supposed to be 0).
+			 */
+			inb((u_int)arg0);
+			break;
+
+		case 2:
+			/*
+			 * Native C state insn, a.k.a. MWAIT.
+			 * arg0[31:0] : hint for MWAIT (through EAX).
+			 * arg1[0] : H/W-coordinated.
+			 * arg1[1] : Requires bus-master avoidance. (?)
+			 */
+#define	MWAIT_INTR	0x01 /* an INT breaks MWAIT even if it's disabled. */
+			cpu_mwait(MWAIT_INTR, (uint32_t)arg0);
+			return;
+		}
+		break;
+
+		/* More vendors? */
+	}
+
+	/* Defaults to STI-HLT sequence. */
+	__asm __volatile("sti; hlt");
+}
+
+/*
  * Support for mapping ACPI tables during early boot.  This abuses the
  * crashdump map because the kernel cannot allocate KVA in
  * pmap_mapbios() when this is used.  This makes the following
diff -rup /sys/i386/i386/machdep.c ./i386/i386/machdep.c
--- sys/i386/i386/machdep.c	2010-04-13 19:12:58.000000000 +0900
+++ sys/i386/i386/machdep.c	2010-05-13 05:54:57.941747275 +0900
@@ -1227,6 +1227,23 @@ cpu_idle_acpi(int busy)
 		__asm __volatile("sti; hlt");
 }
 
+static int cpu_ident_mwait_ext = 0;
+
+static int
+cpu_probe_mwait_ext(void)
+{
+	u_int regs[4]; /* XXX - should we prefer register_t? */
+
+	if (!(cpu_feature2 & CPUID2_MON))
+		return (0);
+	do_cpuid(5 /* CPUID_MONITOR */, regs);
+	if ((regs[2/*ecx*/] & 0x03/*MON_EXT|MON_INTR*/) == 0x03/*both set*/) {
+		cpu_ident_mwait_ext = 1;
+		return (1);
+	}
+	return (0);
+}
+
 static int cpu_ident_amdc1e = 0;
 
 static int
@@ -1322,6 +1339,14 @@ cpu_idle(int busy)
 #define	MWAIT_C3	0x20
 #define	MWAIT_C4	0x30
 
+/*
+ * mwait extensions.
+ */
+#define MWAIT_INTR	0x01
+
+/*
+ * monitorbuf usage.
+ */
 #define	MWAIT_DISABLED	0x0
 #define	MWAIT_WOKEN	0x1
 #define	MWAIT_WAITING	0x2
@@ -1359,6 +1384,27 @@ cpu_idle_mwait_hlt(int busy)
 		cpu_mwait(0, MWAIT_C1);
 }
 
+static void
+cpu_idle_acpi_mwait(int busy)
+{
+	int *mwait;
+
+	disable_intr();
+	mwait = (int *)PCPU_PTR(monitorbuf);
+	*mwait = MWAIT_WAITING;
+	if (sched_runnable())
+		goto done;
+	cpu_monitor(mwait, 0, 0);
+	if (*mwait == MWAIT_WAITING) {
+		if (cpu_idle_hook)
+			cpu_idle_hook();
+		else
+			cpu_mwait(MWAIT_INTR, MWAIT_C1);
+	}
+done:
+	enable_intr();
+}
+
 int
 cpu_idle_wakeup(int cpu)
 {
@@ -1367,7 +1413,8 @@ cpu_idle_wakeup(int cpu)
 
 	if (cpu_idle_fn == cpu_idle_spin)
 		return (1);
-	if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt)
+	if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt
+	    && cpu_idle_fn != cpu_idle_acpi_mwait)
 		return (0);
 	pcpu = pcpu_find(cpu);
 	mwait = (int *)pcpu->pc_monitorbuf;
@@ -1395,6 +1442,7 @@ struct {
 	{ cpu_idle_amdc1e, "amdc1e" },
 	{ cpu_idle_hlt, "hlt" },
 	{ cpu_idle_acpi, "acpi" },
+	{ cpu_idle_acpi_mwait, "acpi_mwait" },
 	{ NULL, NULL }
 };
 
@@ -1414,6 +1462,9 @@ idle_sysctl_available(SYSCTL_HANDLER_ARG
 		if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 &&
 		    cpu_ident_amdc1e == 0)
 			continue;
+		if (strcmp(idle_tbl[i].id_name, "acpi_mwait") == 0 &&
+		    cpu_ident_mwait_ext == 0)
+			continue;
 		p += sprintf(p, "%s, ", idle_tbl[i].id_name);
 	}
 	error = sysctl_handle_string(oidp, avail, 0, req);
@@ -1447,6 +1498,9 @@ idle_sysctl(SYSCTL_HANDLER_ARGS)
 		if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 &&
 		    cpu_ident_amdc1e == 0)
 			continue;
+		if (strcmp(idle_tbl[i].id_name, "acpi_mwait") == 0 &&
+		    cpu_ident_mwait_ext == 0)
+			continue;
 		if (strcmp(idle_tbl[i].id_name, buf))
 			continue;
 		cpu_idle_fn = idle_tbl[i].id_fn;
@@ -2954,6 +3008,8 @@ init386(first)
 	thread0.td_pcb->pcb_ext = 0;
 	thread0.td_frame = &proc0_tf;
 
+	if (cpu_probe_mwait_ext())
+		cpu_idle_fn = cpu_idle_acpi_mwait;
 	if (cpu_probe_amdc1e())
 		cpu_idle_fn = cpu_idle_amdc1e;
 }
diff -rup /sys/i386/include/acpica_machdep.h ./i386/include/acpica_machdep.h
--- sys/i386/include/acpica_machdep.h	2009-10-07 06:34:28.915016725 +0900
+++ sys/i386/include/acpica_machdep.h	2010-05-11 04:43:31.000000000 +0900
@@ -94,9 +94,11 @@ extern int	acpi_release_global_lock(uint
 #define	COMPILER_DEPENDENT_INT64       long long
 #define	COMPILER_DEPENDENT_UINT64      unsigned long long
 #define	ACPI_USE_NATIVE_DIVIDE
+#define	ACPI_USE_NATIVE_CX
 
 void	acpi_SetDefaultIntrModel(int model);
 void	acpi_cpu_c1(void);
+void	acpi_cpu_cx_native(uint8_t vendor, uint8_t classcode, uint8_t arg1, uint64_t arg0);
 void	*acpi_map_table(vm_paddr_t pa, const char *sig);
 void	acpi_unmap_table(void *table);
 vm_paddr_t acpi_find_table(const char *sig);

--Multipart=_Wed__15_Sep_2010_08_11_43_+0900_VGPL5SoSZBB5p/0F--



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