C-state FFH on x41

2015-06-28 Thread Mark Kettenis
I have an x41 that prints the following in dmesg:

acpicpu0 at acpi0
C1: unknown FFH vendor 8: !C3(250@85 io@0x1015), C2(500@1 io@0x1014), PSS

The relevant AML indead has that strange value in the "Bit Width" field:

   Name (CST1, Package (0x02)
{
0x01, 
Package (0x04)
{
ResourceTemplate ()
{
Register (FFixedHW, 
0x08,   // Bit Width
0x00,   // Bit Offset
0x, // Address
,)
}, 

0x01, 
0x01, 
0x03E8
}
})

Obviously this ACPI BIOS is buggy and perhaps we should indeed
complain.  But we also should include a C1 HALT state in the list
regardless, and I don't think we currently do that.



Re: C-state FFH on x41

2015-06-28 Thread Philip Guenther
On Sun, 28 Jun 2015, Mark Kettenis wrote:
> I have an x41 that prints the following in dmesg:
> 
> acpicpu0 at acpi0
> C1: unknown FFH vendor 8: !C3(250@85 io@0x1015), C2(500@1 io@0x1014), PSS
> 
> The relevant AML indead has that strange value in the "Bit Width" field:
...
> Obviously this ACPI BIOS is buggy and perhaps we should indeed
> complain.  But we also should include a C1 HALT state in the list
> regardless, and I don't think we currently do that.

Give the diff below a try.  It inserts a fallback "C1-via-halt" state 
before parsing the _CST objects, overwriting it if a valid _CST C1 state 
is found.  If no valid _CST C1 was found, the fallback should show in 
dmesg as "C1(@1 halt!)".

As a side-benefit, this renders a couple paranoia checks obsolete in 
acpicpu_idle().


Index: dev/acpi/acpicpu.c
===
RCS file: /data/src/openbsd/src/sys/dev/acpi/acpicpu.c,v
retrieving revision 1.64
diff -u -p -r1.64 acpicpu.c
--- dev/acpi/acpicpu.c  13 Jun 2015 21:41:42 -  1.64
+++ dev/acpi/acpicpu.c  28 Jun 2015 21:55:51 -
@@ -77,7 +77,7 @@ void  acpicpu_setperf_ppc_change(struct a
 /* flags on Intel's FFH mwait method */
 #define CST_FLAG_MWAIT_HW_COORD0x1
 #define CST_FLAG_MWAIT_BM_AVOIDANCE0x2
-#define CST_FLAG_UP_ONLY   0x4000  /* ignore if MP */
+#define CST_FLAG_FALLBACK  0x4000  /* fallback for broken _CST */
 #define CST_FLAG_SKIP  0x8000  /* state is worse choice */
 
 #define FLAGS_MWAIT_ONLY   0x02
@@ -339,7 +339,13 @@ acpicpu_add_cstate(struct acpicpu_softc 
dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.16llx\n",
state, latency, power, address);
 
-   cx = malloc(sizeof(*cx), M_DEVBUF, M_WAITOK);
+   /* add a new state, or overwrite the fallback C1 state? */
+   if (state != ACPI_STATE_C1 ||
+   (cx = SLIST_FIRST(&sc->sc_cstates)) == NULL ||
+   (cx->flags & CST_FLAG_FALLBACK) == 0) {
+   cx = malloc(sizeof(*cx), M_DEVBUF, M_WAITOK);
+   SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
+   }
 
cx->state = state;
cx->method = method;
@@ -347,8 +353,6 @@ acpicpu_add_cstate(struct acpicpu_softc 
cx->latency = latency;
cx->power = power;
cx->address = address;
-
-   SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
 }
 
 /* Found a _CST object, add new cstate for each entry */
@@ -489,9 +493,18 @@ acpicpu_getcst(struct acpicpu_softc *sc)
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res))
return (1);
 
+   /* provide a fallback C1-via-halt in case _CST's C1 is bogus */
+   acpicpu_add_cstate(sc, ACPI_STATE_C1, CST_METH_HALT,
+   CST_FLAG_FALLBACK, 1, -1, 0);
+
aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
aml_freevalue(&res);
 
+   /* only have fallback state?  then no _CST objects were understood */
+   cx = SLIST_FIRST(&sc->sc_cstates);
+   if (cx->flags & CST_FLAG_FALLBACK)
+   return (1);
+
/*
 * Scan the list for states that are neither lower power nor
 * lower latency than the next state; mark them to be skipped.
@@ -500,19 +513,15 @@ acpicpu_getcst(struct acpicpu_softc *sc)
 * Also keep track if all the states we'll use use mwait.
 */
use_nonmwait = 0;
-   if ((cx = SLIST_FIRST(&sc->sc_cstates)) == NULL)
-   use_nonmwait = 1;
-   else {
-   while ((next_cx = SLIST_NEXT(cx, link)) != NULL) {
-   if ((cx->power >= next_cx->power &&
-   cx->latency >= next_cx->latency) ||
-   (cx->state > 1 &&
-   (sc->sc_ci->ci_feature_tpmflags & TPM_ARAT) == 0))
-   cx->flags |= CST_FLAG_SKIP;
-   else if (cx->method != CST_METH_MWAIT)
-   use_nonmwait = 1;
-   cx = next_cx;
-   }
+   while ((next_cx = SLIST_NEXT(cx, link)) != NULL) {
+   if ((cx->power >= next_cx->power &&
+   cx->latency >= next_cx->latency) ||
+   (cx->state > 1 &&
+   (sc->sc_ci->ci_feature_tpmflags & TPM_ARAT) == 0))
+   cx->flags |= CST_FLAG_SKIP;
+   else if (cx->method != CST_METH_MWAIT)
+   use_nonmwait = 1;
+   cx = next_cx;
}
if (use_nonmwait)
sc->sc_flags &= ~FLAGS_MWAIT_ONLY;
@@ -581,8 +590,12 @@ acpicpu_print_one_cst(struct acpi_cstate
if (cx->power != -1)
printf("%d", cx->power);
printf("@%d%s", cx->latency, meth);
-   if (cx->flags & ~CST_FLAG_SKIP)
-   printf(".%x", (cx->flags & ~CST_FLAG_SKIP));
+   if (cx->flags & ~CST_FLAG_SKIP) {
+   if (cx->flags & CST_FLAG_FALLBACK)
+