From: Sepherosa Ziehau Date: Thu, 29 Dec 2011 08:33:11 +0000 (+0800) Subject: acpi/pstate: Fix the long standing P-State detection problem on Intel CPUs X-Git-Tag: v3.0.0~235 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/47cf4819ea1fbf8eb9d0da5cd92623dcac44298b acpi/pstate: Fix the long standing P-State detection problem on Intel CPUs - Rename the ACPI_CAP to ACPI_PDC according to Intel's document. While I'm here, update the document revision. - Remove unapplied comment about _OSC and _PDC's revision; Intel's document states clearly that it should be 1 - Fix the 'Count' argument for _OSC evaluation; the intergers in 'Capabilities buffer' argument is 2 - Fix the buffer length of _OSC's 'Capabilities buffer'; we only pass 2 intergers. - Perfer _OSC evaluation, fall back to _PDC evaluation only if _OSC evaluation fails. - Add MD cpu features, so MD code could deliver proper settings. For AMD CPUs, the old configuration just works (AMD actually has no documents about _PDC and _OSC). For Intel CPUs w/ EST, it looks like P-State's _PCT will appear only when bit0 (P-State MSR), bit5 (P-State software coordination) and bit11 (P-State hardware coordination) are turned on. --- diff --git a/sys/dev/acpica5/Makefile b/sys/dev/acpica5/Makefile index 8b6ce7c..ec9292a 100644 --- a/sys/dev/acpica5/Makefile +++ b/sys/dev/acpica5/Makefile @@ -98,6 +98,8 @@ SRCS+= OsdCache.c # Machine-specific code for P-State SRCS+= acpi_pstate_machdep.c +# Machine-specific code for CPU +SRCS+= acpi_cpu_machdep.c # Machine-specific code such as sleep/wakeup SRCS+= acpi_machdep.c acpi_wakecode.h SRCS+= acpi_wakeup.c diff --git a/sys/dev/acpica5/acpi_cpu.c b/sys/dev/acpica5/acpi_cpu.c index 51631ab..093bf1a 100644 --- a/sys/dev/acpica5/acpi_cpu.c +++ b/sys/dev/acpica5/acpi_cpu.c @@ -150,7 +150,7 @@ acpi_cpu_attach(device_t dev) struct acpi_cpux_softc *sc = device_get_softc(dev); ACPI_HANDLE handle; device_t child; - int cpu_id; + int cpu_id, cpu_features; struct acpi_softc *acpi_sc; handle = acpi_get_handle(dev); @@ -177,6 +177,63 @@ acpi_cpu_attach(device_t dev) return ENOMEM; } + /* + * Before calling any CPU methods, collect child driver feature hints + * and notify ACPI of them. We support unified SMP power control + * so advertise this ourselves. Note this is not the same as independent + * SMP control where each CPU can have different settings. + */ + cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; + cpu_features |= acpi_cpu_md_features(); + + /* + * CPU capabilities are specified as a buffer of 32-bit integers: + * revision, count, and one or more capabilities. + */ + if (cpu_features) { + ACPI_OBJECT_LIST arglist; + uint32_t cap_set[3]; + ACPI_OBJECT arg[4]; + ACPI_STATUS status; + + /* UUID needed by _OSC evaluation */ + static uint8_t cpu_oscuuid[16] = { + 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47, + 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53 + }; + + arglist.Pointer = arg; + arglist.Count = 4; + arg[0].Type = ACPI_TYPE_BUFFER; + arg[0].Buffer.Length = sizeof(cpu_oscuuid); + arg[0].Buffer.Pointer = cpu_oscuuid; /* UUID */ + arg[1].Type = ACPI_TYPE_INTEGER; + arg[1].Integer.Value = 1; /* revision */ + arg[2].Type = ACPI_TYPE_INTEGER; + arg[2].Integer.Value = 2; /* # of capabilities integers */ + arg[3].Type = ACPI_TYPE_BUFFER; + arg[3].Buffer.Length = sizeof(cap_set[0]) * 2; /* capabilities buffer */ + arg[3].Buffer.Pointer = (uint8_t *)cap_set; + cap_set[0] = 0; + cap_set[1] = cpu_features; + status = AcpiEvaluateObject(handle, "_OSC", &arglist, NULL); + + if (!ACPI_SUCCESS(status)) { + if (bootverbose) + device_printf(dev, "_OSC failed, use _PDC\n"); + + arglist.Pointer = arg; + arglist.Count = 1; + arg[0].Type = ACPI_TYPE_BUFFER; + arg[0].Buffer.Length = sizeof(cap_set); + arg[0].Buffer.Pointer = (uint8_t *)cap_set; + cap_set[0] = 1; /* revision */ + cap_set[1] = 1; /* # of capabilities integers */ + cap_set[2] = cpu_features; + AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); + } + } + child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); if (child == NULL) return ENXIO; diff --git a/sys/dev/acpica5/acpi_cpu.h b/sys/dev/acpica5/acpi_cpu.h index 98ddfe5..356f892 100644 --- a/sys/dev/acpica5/acpi_cpu.h +++ b/sys/dev/acpica5/acpi_cpu.h @@ -43,4 +43,6 @@ struct acpi_cpux_softc { struct sysctl_oid *pcpu_sysctl_tree; /* hw.acpi.cpuX */ }; +uint32_t acpi_cpu_md_features(void); + #endif /* !__ACPI_CPU_H__ */ diff --git a/sys/dev/acpica5/acpi_cpu_cstate.c b/sys/dev/acpica5/acpi_cpu_cstate.c index 209256a..028d77b 100644 --- a/sys/dev/acpica5/acpi_cpu_cstate.c +++ b/sys/dev/acpica5/acpi_cpu_cstate.c @@ -79,7 +79,6 @@ struct acpi_cpu_softc { struct acpi_cx cpu_cx_states[MAX_CX_STATES]; int cpu_cx_count; /* Number of valid Cx states. */ int cpu_prev_sleep;/* Last idle sleep duration. */ - int cpu_features; /* Child driver supported features. */ /* Runtime state. */ int cpu_non_c3; /* Index of lowest non-C3 state. */ u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */ @@ -235,20 +234,11 @@ static int acpi_cpu_cst_attach(device_t dev) { ACPI_BUFFER buf; - ACPI_OBJECT arg[4], *obj; - ACPI_OBJECT_LIST arglist; + ACPI_OBJECT *obj; struct mdglobaldata *md; struct acpi_cpu_softc *sc; ACPI_STATUS status; - u_int features; - int cpu_id, drv_count, i; - driver_t **drivers; - uint32_t cap_set[3]; - - /* UUID needed by _OSC evaluation */ - static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, - 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70, - 0x58, 0x71, 0x39, 0x53 }; + int cpu_id; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -291,60 +281,6 @@ acpi_cpu_cst_attach(device_t dev) AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cpu_startup, NULL); } - /* - * Before calling any CPU methods, collect child driver feature hints - * and notify ACPI of them. We support unified SMP power control - * so advertise this ourselves. Note this is not the same as independent - * SMP control where each CPU can have different settings. - */ - sc->cpu_features = ACPI_CAP_SMP_SAME | ACPI_CAP_SMP_SAME_C3; - if (devclass_get_drivers(acpi_cpu_cst_devclass, - &drivers, &drv_count) == 0) { - for (i = 0; i < drv_count; i++) { - if (ACPI_GET_FEATURES(drivers[i], &features) == 0) - sc->cpu_features |= features; - } - kfree(drivers, M_TEMP); - } - - /* - * CPU capabilities are specified as a buffer of 32-bit integers: - * revision, count, and one or more capabilities. The revision of - * "1" is not specified anywhere but seems to match Linux. - */ - if (sc->cpu_features) { - arglist.Pointer = arg; - arglist.Count = 1; - arg[0].Type = ACPI_TYPE_BUFFER; - arg[0].Buffer.Length = sizeof(cap_set); - arg[0].Buffer.Pointer = (uint8_t *)cap_set; - cap_set[0] = 1; /* revision */ - cap_set[1] = 1; /* number of capabilities integers */ - cap_set[2] = sc->cpu_features; - AcpiEvaluateObject(sc->cpu_handle, "_PDC", &arglist, NULL); - - /* - * On some systems we need to evaluate _OSC so that the ASL - * loads the _PSS and/or _PDC methods at runtime. - * - * TODO: evaluate failure of _OSC. - */ - arglist.Pointer = arg; - arglist.Count = 4; - arg[0].Type = ACPI_TYPE_BUFFER; - arg[0].Buffer.Length = sizeof(cpu_oscuuid); - arg[0].Buffer.Pointer = cpu_oscuuid; /* UUID */ - arg[1].Type = ACPI_TYPE_INTEGER; - arg[1].Integer.Value = 1; /* revision */ - arg[2].Type = ACPI_TYPE_INTEGER; - arg[2].Integer.Value = 1; /* count */ - arg[3].Type = ACPI_TYPE_BUFFER; - arg[3].Buffer.Length = sizeof(cap_set); /* Capabilities buffer */ - arg[3].Buffer.Pointer = (uint8_t *)cap_set; - cap_set[0] = 0; - AcpiEvaluateObject(sc->cpu_handle, "_OSC", &arglist, NULL); - } - /* Probe for Cx state support. */ acpi_cpu_cx_probe(sc); diff --git a/sys/dev/acpica5/acpivar.h b/sys/dev/acpica5/acpivar.h index 353809a..be98784 100644 --- a/sys/dev/acpica5/acpivar.h +++ b/sys/dev/acpica5/acpivar.h @@ -198,17 +198,19 @@ extern struct lock acpi_lock; * Various features and capabilities for the acpi_get_features() method. * In particular, these are used for the ACPI 3.0 _PDC and _OSC methods. * See the Intel document titled "Processor Driver Capabilities Bit - * Definitions", number 302223-002. + * Definitions", number 302223-005. */ -#define ACPI_CAP_PERF_MSRS (1 << 0) /* Intel SpeedStep PERF_CTL MSRs */ -#define ACPI_CAP_C1_IO_HALT (1 << 1) /* Intel C1 "IO then halt" sequence */ -#define ACPI_CAP_THR_MSRS (1 << 2) /* Intel OnDemand throttling MSRs */ -#define ACPI_CAP_SMP_SAME (1 << 3) /* MP C1, Px, and Tx (all the same) */ -#define ACPI_CAP_SMP_SAME_C3 (1 << 4) /* MP C2 and C3 (all the same) */ -#define ACPI_CAP_SMP_DIFF_PX (1 << 5) /* MP Px (different, using _PSD) */ -#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_PDC_PX_MSR (1 << 0) /* Intel SpeedStep PERF_CTL MSRs */ +#define ACPI_PDC_MP_C1_IO_HALT (1 << 1) /* Intel C1 "IO then halt" sequence */ +#define ACPI_PDC_TX_MSR (1 << 2) /* Intel OnDemand throttling MSRs */ +#define ACPI_PDC_MP_C1PXTX (1 << 3) /* MP C1, Px, and Tx */ +#define ACPI_PDC_MP_C2C3 (1 << 4) /* MP C2 and C3 */ +#define ACPI_PDC_MP_PX_SWCORD (1 << 5) /* MP Px, using _PSD */ +#define ACPI_PDC_MP_CX_SWCORD (1 << 6) /* MP Cx, using _CSD */ +#define ACPI_PDC_MP_TX_SWCORD (1 << 7) /* MP Tx, using _TSD */ +#define ACPI_PDC_MP_C1_NATIVE (1 << 8) /* MP C1 support other than halt */ +#define ACPI_PDC_MP_C2C3_NATIVE (1 << 9) /* MP C2 and C3 support */ +#define ACPI_PDC_PX_HWCORD (1 << 11)/* Hardware coordination of Px */ /* * Quirk flags. diff --git a/sys/platform/pc32/acpica5/acpi_cpu_machdep.c b/sys/platform/pc32/acpica5/acpi_cpu_machdep.c new file mode 100644 index 0000000..4a87be5 --- /dev/null +++ b/sys/platform/pc32/acpica5/acpi_cpu_machdep.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "acpi.h" +#include "acpivar.h" +#include "acpi_cpu.h" + +uint32_t +acpi_cpu_md_features(void) +{ + if (cpu_vendor_id == CPU_VENDOR_INTEL) { + if (cpu_feature2 & CPUID2_EST) { + return (ACPI_PDC_PX_MSR | + ACPI_PDC_MP_PX_SWCORD | + ACPI_PDC_PX_HWCORD); + } + } + return 0; +} diff --git a/sys/platform/pc64/acpica5/acpi_cpu_machdep.c b/sys/platform/pc64/acpica5/acpi_cpu_machdep.c new file mode 100644 index 0000000..4a87be5 --- /dev/null +++ b/sys/platform/pc64/acpica5/acpi_cpu_machdep.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "acpi.h" +#include "acpivar.h" +#include "acpi_cpu.h" + +uint32_t +acpi_cpu_md_features(void) +{ + if (cpu_vendor_id == CPU_VENDOR_INTEL) { + if (cpu_feature2 & CPUID2_EST) { + return (ACPI_PDC_PX_MSR | + ACPI_PDC_MP_PX_SWCORD | + ACPI_PDC_PX_HWCORD); + } + } + return 0; +}