summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}