From owner-freebsd-acpi@FreeBSD.ORG Tue Sep 14 23:11:29 2010 Return-Path: Delivered-To: freebsd-acpi@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CDB5B1065670 for ; Tue, 14 Sep 2010 23:11:29 +0000 (UTC) (envelope-from taku@tackymt.homeip.net) Received: from basalt.tackymt.homeip.net (unknown [IPv6:2001:3e0:577:0:20d:61ff:fecc:2253]) by mx1.freebsd.org (Postfix) with ESMTP id CD6598FC0C for ; Tue, 14 Sep 2010 23:11:28 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by basalt.tackymt.homeip.net (Postfix) with ESMTP id 2CE8F1074D for ; Wed, 15 Sep 2010 08:11:28 +0900 (JST) X-Virus-Scanned: amavisd-new at tackymt.homeip.net Received: from localhost ([127.0.0.1]) by localhost (basalt.tackymt.homeip.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JzzZ0zBgU948 for ; Wed, 15 Sep 2010 08:11:25 +0900 (JST) Received: from biotite.tackymt.homeip.net (biotite.tackymt.homeip.net [IPv6:2001:3e0:577:0:216:cfff:febc:1472]) by basalt.tackymt.homeip.net (Postfix) with ESMTP for ; Wed, 15 Sep 2010 08:11:25 +0900 (JST) Date: Wed, 15 Sep 2010 08:11:43 +0900 From: Taku YAMAMOTO To: freebsd-acpi@freebsd.org Message-Id: <20100915081143.c7783553.taku@tackymt.homeip.net> In-Reply-To: <20100915080124.c6d53391.taku@tackymt.homeip.net> References: <4C8BCAC5.5050008@root.org> <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> X-Mailer: Sylpheed 2.7.1 (GTK+ 2.18.5; i386-portbld-freebsd9.0) Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="Multipart=_Wed__15_Sep_2010_08_11_43_+0900_VGPL5SoSZBB5p/0F" Subject: Follow-up: CPU C-state storange on Panasonic TOUGH BOOK CF-R9 X-BeenThere: freebsd-acpi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: ACPI and power management development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Sep 2010 23:11:30 -0000 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 wrote: > On Tue, 14 Sep 2010 11:44:45 +0300 > Andriy Gapon 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 | __ < - 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--