summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2009-06-10 03:42:21 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2009-06-10 03:42:21 +0000
commitb824424ec915426376b254de20d2dce35bd78aa9 (patch)
tree88e6498b3123cae24549030e0567f28003b549ff /sys/dev
parent8ac48e3106a31781ca1936d46d4308bbb159e58c (diff)
Re introduce the _PDC code backed out before 4.5, in addition to evaluating the
PDC (which tells the ACPI code what we as OSPM are capable of) we also evaluate the OSC method on the acpicpu device. Original cause of problems that resulted in this getting backed out appear to be fixed by the mp_setperf change, so hopefully the third time is the charm. Tested by many. ok marco@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpi/acpicpu.c141
1 files changed, 119 insertions, 22 deletions
diff --git a/sys/dev/acpi/acpicpu.c b/sys/dev/acpi/acpicpu.c
index c10bbf7da3a..40983ef82ae 100644
--- a/sys/dev/acpi/acpicpu.c
+++ b/sys/dev/acpi/acpicpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpicpu.c,v 1.53 2009/02/24 13:20:02 deraadt Exp $ */
+/* $OpenBSD: acpicpu.c,v 1.54 2009/06/10 03:42:20 gwk Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
*
@@ -41,12 +41,29 @@ int acpicpu_match(struct device *, void *, void *);
void acpicpu_attach(struct device *, struct device *, void *);
int acpicpu_notify(struct aml_node *, int, void *);
void acpicpu_setperf(int);
+void acpicpu_setperf_ppc_change(struct acpicpu_pss *, int);
#define ACPI_STATE_C0 0x00
#define ACPI_STATE_C1 0x01
#define ACPI_STATE_C2 0x02
#define ACPI_STATE_C3 0x03
+#define ACPI_PDC_REVID 0x1
+#define ACPI_PDC_SMP 0xa
+#define ACPI_PDC_MSR 0x1
+
+/* _PDC Intel capabilities flags from linux */
+#define ACPI_PDC_P_FFH 0x0001
+#define ACPI_PDC_C_C1_HALT 0x0002
+#define ACPI_PDC_T_FFH 0x0004
+#define ACPI_PDC_SMP_C1PT 0x0008
+#define ACPI_PDC_SMP_C2C3 0x0010
+#define ACPI_PDC_SMP_P_SWCOORD 0x0020
+#define ACPI_PDC_SMP_C_SWCOORD 0x0040
+#define ACPI_PDC_SMP_T_SWCOORD 0x0080
+#define ACPI_PDC_C_C1_FFH 0x0100
+#define ACPI_PDC_C_C2C3_FFH 0x0200
+
#define FLAGS_NO_C2 0x01
#define FLAGS_NO_C3 0x02
#define FLAGS_BMCHECK 0x04
@@ -121,6 +138,8 @@ int acpicpu_getpct(struct acpicpu_softc *);
int acpicpu_getpss(struct acpicpu_softc *);
struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int,
int);
+void acpicpu_set_pdc(struct acpicpu_softc *);
+
#if 0
void acpicpu_set_throttle(struct acpicpu_softc *, int);
struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
@@ -170,6 +189,55 @@ acpicpu_find_cstate(struct acpicpu_softc *sc, int type)
}
#endif
+
+void
+acpicpu_set_pdc(struct acpicpu_softc *sc)
+{
+ struct aml_value cmd, osc_cmd[4];
+ struct aml_value res;
+ uint32_t buf[3];
+
+ /* 4077A616-290C-47BE-9EBD-D87058713953 */
+ static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29,
+ 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70,
+ 0x58, 0x71, 0x39, 0x53 };
+ /* Evaluate _PDC */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.type = AML_OBJTYPE_BUFFER;
+ cmd.v_buffer = (uint8_t *)&buf;
+ cmd.length = sizeof(buf);
+
+ buf[0] = ACPI_PDC_REVID;
+ buf[1] = 1;
+ buf[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_P_FFH | ACPI_PDC_C_C1_FFH
+ | ACPI_PDC_C_C2C3_FFH | ACPI_PDC_SMP_P_SWCOORD | ACPI_PDC_SMP_C2C3
+ | ACPI_PDC_SMP_C1PT;
+
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 1, &cmd, &res);
+
+ /* Evalualte _OSC */
+ memset(&osc_cmd, 0, sizeof(cmd) * 4);
+ osc_cmd[0].type = AML_OBJTYPE_BUFFER;
+ osc_cmd[0].v_buffer = (uint8_t *)&cpu_oscuuid;
+ osc_cmd[0].length = sizeof(cpu_oscuuid);
+
+ osc_cmd[1].type = AML_OBJTYPE_INTEGER;
+ osc_cmd[1].v_integer = 1;
+ osc_cmd[1].length = 1;
+
+ osc_cmd[2].type = AML_OBJTYPE_INTEGER;
+ osc_cmd[2].v_integer = 1;
+ osc_cmd[2].length = 1;
+
+ buf[0] = 0;
+ osc_cmd[3].type = AML_OBJTYPE_BUFFER;
+ osc_cmd[3].v_buffer = (int8_t *)&buf;
+ osc_cmd[3].length = sizeof(buf);
+
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", 4, osc_cmd, &res);
+}
+
+
struct acpi_cstate *
acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int power,
int address)
@@ -268,15 +336,17 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux)
}
sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset;
sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
+
+ acpicpu_set_pdc(sc);
+
if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
sc->sc_flags |= FLAGS_NOTHROTTLE;
#ifdef ACPI_DEBUG
printf(": %s: ", sc->sc_devnode->name);
- printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x (%d throttling states)\n",
- sc->sc_acpi->sc_fadt->hdr_revision,
- sc->sc_pblk_addr, sc->sc_pblk_len,
- sc->sc_duty_off, sc->sc_duty_wid,
- sc->sc_acpi->sc_fadt->pstate_cnt,
+ printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x "
+ "(%d throttling states)\n", sc->sc_acpi->sc_fadt->hdr_revision,
+ sc->sc_pblk_addr, sc->sc_pblk_len, sc->sc_duty_off,
+ sc->sc_duty_wid, sc->sc_acpi->sc_fadt->pstate_cnt,
CPU_MAXSTATE(sc));
#endif
@@ -342,6 +412,7 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux)
DEVNAME(sc), status, sc->sc_level);
if (setperf_prio < 30) {
cpu_setperf = acpicpu_setperf;
+ acpicpu_set_notify(acpicpu_setperf_ppc_change);
setperf_prio = 30;
acpi_hasprocfvs = 1;
}
@@ -492,7 +563,7 @@ int
acpicpu_getpss(struct acpicpu_softc *sc)
{
struct aml_value res;
- int i;
+ int i, c, cf;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) {
dprintf("%s: no _PSS\n", DEVNAME(sc));
@@ -505,21 +576,39 @@ acpicpu_getpss(struct acpicpu_softc *sc)
sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF,
M_WAITOK | M_ZERO);
+ c = 0;
for (i = 0; i < res.length; i++) {
- sc->sc_pss[i].pss_core_freq = aml_val2int(
- res.v_package[i]->v_package[0]);
- sc->sc_pss[i].pss_power = aml_val2int(
+ cf = aml_val2int(res.v_package[i]->v_package[0]);
+
+ /* This heuristic comes from FreeBSDs
+ * dev/acpica/acpi_perf.c to weed out invalid PSS entries.
+ */
+ if (cf == sc->sc_pss[c].pss_core_freq) {
+ printf("%s: struck PSS entry, core frequency equals "
+ " last\n", sc->sc_dev.dv_xname);
+ continue;
+ }
+
+ if (cf == 0xFFFF || cf == 0x9999 || cf == 99999 || cf == 0) {
+ printf("%s: struck PSS entry, inappropriate core "
+ "frequency value\n", sc->sc_dev.dv_xname);
+ continue;
+ }
+
+ sc->sc_pss[c].pss_core_freq = cf;
+ sc->sc_pss[c].pss_power = aml_val2int(
res.v_package[i]->v_package[1]);
- sc->sc_pss[i].pss_trans_latency = aml_val2int(
+ sc->sc_pss[c].pss_trans_latency = aml_val2int(
res.v_package[i]->v_package[2]);
- sc->sc_pss[i].pss_bus_latency = aml_val2int(
+ sc->sc_pss[c].pss_bus_latency = aml_val2int(
res.v_package[i]->v_package[3]);
- sc->sc_pss[i].pss_ctrl = aml_val2int(
+ sc->sc_pss[c].pss_ctrl = aml_val2int(
res.v_package[i]->v_package[4]);
- sc->sc_pss[i].pss_status = aml_val2int(
+ sc->sc_pss[c].pss_status = aml_val2int(
res.v_package[i]->v_package[5]);
+ c++;
}
- sc->sc_pss_len = res.length;
+ sc->sc_pss_len = c;
aml_freevalue(&res);
@@ -535,8 +624,6 @@ acpicpu_fetch_pss(struct acpicpu_pss **pss)
* XXX: According to the ACPI spec in an SMP system all processors
* are supposed to support the same states. For now we pray
* the bios ensures this...
- * XXX part deux: this needs to account for _PPC as well
- * when AC is removed the nr of _PSS entries can go down
*/
sc = acpicpu_sc[0];
@@ -562,9 +649,6 @@ acpicpu_notify(struct aml_node *node, int notify_type, void *arg)
if (sc->sc_notify)
sc->sc_notify(sc->sc_pss, sc->sc_pss_len);
- /* reset performance to current percentage */
- /* XXX will fail for amd64 for now */
- cpu_setperf(sc->sc_level);
break;
default:
printf("%s: unhandled cpu event %x\n", DEVNAME(sc),
@@ -576,7 +660,8 @@ acpicpu_notify(struct aml_node *node, int notify_type, void *arg)
}
void
-acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) {
+acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int))
+{
struct acpicpu_softc *sc;
sc = acpicpu_sc[0];
@@ -585,6 +670,17 @@ acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) {
}
void
+acpicpu_setperf_ppc_change(struct acpicpu_pss *pss, int npss)
+{
+ struct acpicpu_softc *sc;
+
+ sc = acpicpu_sc[0];
+
+ if (sc != NULL)
+ cpu_setperf(sc->sc_level);
+}
+
+void
acpicpu_setperf(int level)
{
struct acpicpu_softc *sc;
@@ -608,7 +704,8 @@ acpicpu_setperf(int level)
* the duty cycle method instead of pss exclusively
*/
if (sc->sc_flags & FLAGS_NOPSS || sc->sc_flags & FLAGS_NOPCT) {
- dnprintf(10, "%s: acpicpu no _PSS or _PCT\n", sc->sc_devnode->name);
+ dnprintf(10, "%s: acpicpu no _PSS or _PCT\n",
+ sc->sc_devnode->name);
return;
}