Some time ago, I had added support for using the MWAIT instruction in the 
idle loop.  Various people found that made their boxes run hot, to the 
point that several developers diked it out of their own builds; I've 
committed one of those yesteryad pending a proper fix.

So, to start on that: the diff below expands our handling of the ACPI _CST 
values to detect the Intel "functional fixed hardware" register type for 
C-state control and report it in the acpicpu dmesg lines, ala:

acpicpu0 at acpi0: C3, C2, C1(mwait), PSS

I have diff on top of this that adds callbacks and amd64 bits to properly 
notify CPUs of the C1 type and thus enable mwait use if the _CST specifies 
it, but let's first see if the _CST output matches our expectations.


IN PARTICULAR, IF YOUR BOX RAN HOT WITH MWAIT, please run with this diff 
report your dmesg!


Philip


Index: dev/acpi/acpicpu.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpicpu.c,v
retrieving revision 1.62
diff -u -p -r1.62 acpicpu.c
--- dev/acpi/acpicpu.c  9 Dec 2014 06:58:29 -0000       1.62
+++ dev/acpi/acpicpu.c  14 Dec 2014 21:41:44 -0000
@@ -111,7 +111,8 @@ struct acpicpu_softc {
 
        int                     sc_pss_len;
        int                     sc_ppc;
-       int                     sc_level;
+       short                   sc_level;
+       u_int8_t                sc_cst_c1_type;
        struct acpicpu_pss      *sc_pss;
 
        struct acpicpu_pct      sc_pct;
@@ -120,6 +121,8 @@ struct acpicpu_softc {
        u_int32_t               sc_pct_ctrl_as;
        u_int32_t               sc_pct_stat_len;
        u_int32_t               sc_pct_ctrl_len;
+       u_int64_t               sc_cst_c1_addr;         /* or mwait hint */
+
        /*
         * XXX: _PPC Change listener
         * PPC changes can occur when for example a machine is disconnected
@@ -135,6 +138,7 @@ void    acpicpu_add_cstatepkg(struct aml
 int    acpicpu_getppc(struct acpicpu_softc *);
 int    acpicpu_getpct(struct acpicpu_softc *);
 int    acpicpu_getpss(struct acpicpu_softc *);
+int    acpicpu_getcst(struct acpicpu_softc *);
 struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int,
     int);
 void   acpicpu_set_pdc(struct acpicpu_softc *);
@@ -284,13 +288,11 @@ acpicpu_add_cstate(struct acpicpu_softc 
 
        switch (type) {
        case ACPI_STATE_C2:
-               if (latency > ACPI_MAX_C2_LATENCY || !address ||
-                   (sc->sc_flags & FLAGS_NO_C2))
+               if (!address || (sc->sc_flags & FLAGS_NO_C2))
                        goto bad;
                break;
        case ACPI_STATE_C3:
-               if (latency > ACPI_MAX_C3_LATENCY || !address ||
-                   (sc->sc_flags & FLAGS_NO_C3))
+               if (!address || (sc->sc_flags & FLAGS_NO_C3))
                        goto bad;
                break;
        }
@@ -315,6 +317,7 @@ void
 acpicpu_add_cstatepkg(struct aml_value *val, void *arg)
 {
        struct acpicpu_softc    *sc = arg;
+       int64_t state;
 
 #if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL)
        aml_showvalue(val, 0);
@@ -322,11 +325,77 @@ acpicpu_add_cstatepkg(struct aml_value *
        if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4)
                return;
 
-       acpicpu_add_cstate(sc, val->v_package[1]->v_integer,
-           val->v_package[2]->v_integer,
+       state = val->v_package[1]->v_integer;
+
+       /*
+        * Is there an C1 state implemented via either "I/O then halt"
+        * or mwait?  Look for a "generic register" which is of
+        * Functional Fixed Hardware type for intel
+        */
+       if (state == 1 && val->v_package[0]->type == AML_OBJTYPE_BUFFER) {
+               u_int8_t *buf = val->v_package[0]->v_buffer;
+
+               if (buf[0] == LR_GENREGISTER &&
+                   buf[1] == 0x0C &&           /* length (low) */
+                   buf[2] == 0x00 &&           /* length (high) */
+                   buf[3] == GAS_FUNCTIONAL_FIXED &&
+                   buf[4] == 0x01) {           /* vendor == intel */
+
+                       /* extract the bottom 32 bit of address */
+                       sc->sc_cst_c1_addr = buf[8] + (buf[9] << 8) +
+                           (buf[10] << 16) + (buf[11] << 24);
+
+                       switch (buf[5]) {
+                       case CST_C1_HALT:
+                               sc->sc_cst_c1_type = CST_C1_HALT;
+                               break;
+
+                       case CST_C1_IO_HALT:
+                               sc->sc_cst_c1_type = CST_C1_IO_HALT;
+
+                               /* extract the top 32 bits of address */
+                               sc->sc_cst_c1_addr +=
+                                   (u_int64_t)(buf[12] + (buf[13] << 8) +
+                                   (buf[14] << 16) + (buf[15] << 24)) << 32;
+                               break;
+
+                       case CST_C1_MWAIT:
+                               /* skip if bus master avoidance required */
+                               if ((buf[6] & 0x02) == 0)
+                                       sc->sc_cst_c1_type = CST_C1_MWAIT;
+                               break;
+                       }
+               }
+       }
+
+       acpicpu_add_cstate(sc, state, val->v_package[2]->v_integer,
            val->v_package[3]->v_integer, -1);
 }
 
+int
+acpicpu_getcst(struct acpicpu_softc *sc)
+{
+       struct aml_value        res;
+       struct acpi_cstate      *cx;
+
+       /* delete the existing list */
+       while ((cx = SLIST_FIRST(&sc->sc_cstates)) != NULL) {
+               SLIST_REMOVE_HEAD(&sc->sc_cstates, link);
+               free(cx, M_DEVBUF, 0);
+       }
+
+       /* reset the C1 info */
+       sc->sc_cst_c1_type = CST_C1_NONE;
+
+       if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res))
+               return (1);
+
+       aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
+       aml_freevalue(&res);
+
+       return (0);
+}
+
 
 int
 acpicpu_match(struct device *parent, void *match, void *aux)
@@ -386,15 +455,13 @@ acpicpu_attach(struct device *parent, st
 #endif
 
        /* Get C-States from _CST or FADT */
-       if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res)) {
-               aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
-               aml_freevalue(&res);
-       }
-       else {
+       if (acpicpu_getcst(sc)) {
                /* Some systems don't export a full PBLK reduce functionality */
-               if (sc->sc_pblk_len < 5)
+               if (sc->sc_pblk_len < 5 ||
+                   sc->sc_acpi->sc_fadt->p_lvl2_lat > ACPI_MAX_C2_LATENCY)
                        sc->sc_flags |= FLAGS_NO_C2;
-               if (sc->sc_pblk_len < 6)
+               if (sc->sc_pblk_len < 6 ||
+                   sc->sc_acpi->sc_fadt->p_lvl3_lat > ACPI_MAX_C3_LATENCY)
                        sc->sc_flags |= FLAGS_NO_C3;
                acpicpu_add_cstate(sc, ACPI_STATE_C2,
                    sc->sc_acpi->sc_fadt->p_lvl2_lat, -1,
@@ -470,6 +537,21 @@ acpicpu_attach(struct device *parent, st
                                break;
                        case ACPI_STATE_C1:
                                printf(" C1");
+                               switch (sc->sc_cst_c1_type) {
+                               case CST_C1_HALT:
+                                       printf("(halt)");
+                                       break;
+                               case CST_C1_IO_HALT:
+                                       printf("(I/O-halt)");
+                                       break;
+                               case CST_C1_MWAIT:
+                                       printf("(mwait");
+                                       if (sc->sc_cst_c1_addr != 0)
+                                               printf(".%llx",
+                                                   sc->sc_cst_c1_addr);
+                                       printf(")");
+                                       break;
+                               }
                                break;
                        case ACPI_STATE_C2:
                                printf(" C2");
@@ -682,8 +764,12 @@ acpicpu_notify(struct aml_node *node, in
                acpicpu_getpss(sc);
                if (sc->sc_notify)
                        sc->sc_notify(sc->sc_pss, sc->sc_pss_len);
+               break;
 
+       case 0x81:      /* _CST changed, retrieve new values */
+               acpicpu_getcst(sc);
                break;
+
        default:
                printf("%s: unhandled cpu event %x\n", DEVNAME(sc),
                    notify_type);
Index: dev/acpi/acpidev.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpidev.h,v
retrieving revision 1.36
diff -u -p -r1.36 acpidev.h
--- dev/acpi/acpidev.h  23 Nov 2014 20:33:47 -0000      1.36
+++ dev/acpi/acpidev.h  14 Dec 2014 21:41:44 -0000
@@ -229,6 +229,12 @@ struct acpicpu_pss {
 
 int acpicpu_fetch_pss(struct acpicpu_pss **);
 void acpicpu_set_notify(void (*)(struct acpicpu_pss *, int));
+
+#define CST_C1_NONE    (-1)
+#define CST_C1_HALT    0x0
+#define CST_C1_IO_HALT 0x1
+#define CST_C1_MWAIT   0x2
+
 /*
  * XXX this is returned in a buffer and is not a "natural" type.
  *

Reply via email to