The patch makes my dell d430 reboot at boot (just after acpi stuff).

jor...@peereboom.us a icrit :
Sending out an initial attempt at implementing C-states for APCI CPUs.
The C-states are used to implement the CPU idle loop per CPU.

Please send dmesgs of booting using this patch.

Index: acpicpu.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpicpu.c,v
retrieving revision 1.53
diff -u -p -u -p -b -r1.53 acpicpu.c
--- acpicpu.c   24 Feb 2009 13:20:02 -0000      1.53
+++ acpicpu.c   7 Jun 2009 19:47:34 -0000
@@ -41,6 +41,10 @@ int  acpicpu_match(struct device *, void
 void   acpicpu_attach(struct device *, struct device *, void *);
 int    acpicpu_notify(struct aml_node *, int, void *);
 void   acpicpu_setperf(int);
+void    acpicpu_idle(void);
+
+#define C2_OVERHEAD            4
+#define C3_OVERHEAD            4

 #define ACPI_STATE_C0          0x00
 #define ACPI_STATE_C1          0x01
@@ -65,14 +69,20 @@ void        acpicpu_setperf(int);
 /* Make sure throttling bits are valid,a=addr,o=offset,w=width */
 #define valid_throttle(o,w,a)  (a && w && (o+w)<=31 && (o>4 || (o+w)<=4))

+TAILQ_HEAD(acpi_cstatehead, acpi_cstate);
+
 struct acpi_cstate
 {
        int      type;
        int      latency;
        int      power;
        int      address;
+       int      enter;
+
+       int      pthr, dthr;
+       int      pcount, dcount;

-       SLIST_ENTRY(acpi_cstate) link;
+       TAILQ_ENTRY(acpi_cstate) link;
 };

 struct acpicpu_softc {
@@ -85,7 +95,9 @@ struct acpicpu_softc {
        int                     sc_pblk_len;
        int                     sc_flags;

-       SLIST_HEAD(,acpi_cstate) sc_cstates;
+       int                      sc_prevsleep;
+       struct acpi_cstate      *sc_cx;
+       struct acpi_cstatehead   sc_cstates;

        bus_space_tag_t         sc_iot;
        bus_space_handle_t      sc_ioh;
@@ -121,6 +133,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);
+u_int   acpicpu_ticks(struct acpicpu_softc *, u_int, u_int);
+int     acpicpu_get_cstaddr(union acpi_resource *, void *);
 #if 0
 void    acpicpu_set_throttle(struct acpicpu_softc *, int);
 struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
@@ -163,31 +177,36 @@ acpicpu_find_cstate(struct acpicpu_softc
 {
        struct acpi_cstate      *cx;

-       SLIST_FOREACH(cx, &sc->sc_cstates, link)
+       TAILQ_FOREACH(cx, &sc->sc_cstates, link) {
                if (cx->type == type)
                        return cx;
+       }
        return (NULL);
 }
 #endif

 struct acpi_cstate *
-acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int
power,
+acpicpu_add_cstate(struct acpicpu_softc *sc,
+    int type, int latency, int power,
     int address)
 {
        struct acpi_cstate      *cx;

+       printf("C%d: latency:%d power:%d addr:%.4x\n",
+               type, latency, power, address);
+
        dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n",
            type, latency, power, address);

        switch (type) {
        case ACPI_STATE_C2:
                if (latency > ACPI_MAX_C2_LATENCY || !address ||
-                   (sc->sc_flags & FLAGS_NO_C2))
+                       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))
+                       sc->sc_flags & FLAGS_NO_C3)
                        goto bad;
                break;
        }
@@ -199,7 +218,19 @@ acpicpu_add_cstate(struct acpicpu_softc
        cx->latency = latency;
        cx->address = address;

-       SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
+       if (type == ACPI_STATE_C1)
+               cx->pthr = 10;
+       else if (type == ACPI_STATE_C2) {
+               cx->dthr = 1;
+               cx->pthr = 4;
+       }
+       else if (type == ACPI_STATE_C3)
+               cx->dthr = 1;
+
+       TAILQ_INSERT_TAIL(&sc->sc_cstates, cx, link);
+
+       if (sc->sc_cx == NULL)
+               sc->sc_cx = cx;

        return (cx);
  bad:
@@ -207,21 +238,34 @@ acpicpu_add_cstate(struct acpicpu_softc
        return (NULL);
 }

+int
+acpicpu_get_cstaddr(union acpi_resource *crs, void *arg)
+{
+       struct acpi_gas *gas = arg;
+
+       if (AML_CRSTYPE(crs) == LR_GENREGISTER)
+               memcpy(gas, crs->pad+3, sizeof(*gas));
+       return 0;
+}
+
 /* Found a _CST object, add new cstate for each entry */
 void
 acpicpu_add_cstatepkg(struct aml_value *val, void *arg)
 {
        struct acpicpu_softc    *sc = arg;
+       struct acpi_gas         gas;

-#if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL)
-       aml_showvalue(val, 0);
-#endif
        if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4)
                return;

+       memset(&gas, 0, sizeof(gas));
+       aml_parse_resource(val->v_package[0]->length,
+           val->v_package[0]->v_buffer,
+           acpicpu_get_cstaddr, &gas);
        acpicpu_add_cstate(sc, val->v_package[1]->v_integer,
            val->v_package[2]->v_integer,
-           val->v_package[3]->v_integer, -1);
+           val->v_package[3]->v_integer,
+           gas.address);
 }


@@ -249,12 +293,13 @@ acpicpu_attach(struct device *parent, st
        int                     i;
        struct acpi_cstate      *cx;
        u_int32_t               status = 0;
+       u_int32_t               pdc[4];

        sc->sc_acpi = (struct acpi_softc *)parent;
        sc->sc_devnode = aa->aaa_node;
        acpicpu_sc[sc->sc_dev.dv_unit] = sc;

-       SLIST_INIT(&sc->sc_cstates);
+       TAILQ_INIT(&sc->sc_cstates);

        sc->sc_pss = NULL;

@@ -270,7 +315,7 @@ acpicpu_attach(struct device *parent, st
        sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
        if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
                sc->sc_flags |= FLAGS_NOTHROTTLE;
-#ifdef ACPI_DEBUG
+#if 1
        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,
@@ -280,20 +325,29 @@ acpicpu_attach(struct device *parent, st
                CPU_MAXSTATE(sc));
 #endif

+       pdc[0] = 1;
+       pdc[1] = 1;
+       pdc[2] = -1;
+       memset(&res, 0, sizeof(res));
+       res.type = AML_OBJTYPE_BUFFER;
+       res.v_buffer = (void *)pdc;
+       if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 1, &res, 0))
+               printf("_PDC exists\n");
+
        /* Get C-States from _CST or FADT */
        if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res)) {
+               printf("Eval _CST\n");
                aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
                aml_freevalue(&res);
        }
        else {
                /* Some systems don't export a full PBLK reduce functionality */
-               if (sc->sc_pblk_len < 5)
-                       sc->sc_flags |= FLAGS_NO_C2;
-               if (sc->sc_pblk_len < 6)
-                       sc->sc_flags |= FLAGS_NO_C3;
+               acpicpu_add_cstate(sc, ACPI_STATE_C1, 0, -1, 0);
+               if (sc->sc_pblk_len >= 5)
                acpicpu_add_cstate(sc, ACPI_STATE_C2,
                    sc->sc_acpi->sc_fadt->p_lvl2_lat, -1,
                    sc->sc_pblk_addr + 4);
+               if (sc->sc_pblk_len >= 6)
                acpicpu_add_cstate(sc, ACPI_STATE_C3,
                    sc->sc_acpi->sc_fadt->p_lvl3_lat, -1,
                    sc->sc_pblk_addr + 5);
@@ -352,11 +406,11 @@ acpicpu_attach(struct device *parent, st
         * Nicely enumerate what power management capabilities
         * ACPI CPU provides.
         */
-       if (!SLIST_EMPTY(&sc->sc_cstates)) {
+       if (!TAILQ_EMPTY(&sc->sc_cstates)) {
                printf(":");

                i = 0;
-               SLIST_FOREACH(cx, &sc->sc_cstates, link) {
+               TAILQ_FOREACH(cx, &sc->sc_cstates, link) {
                        if (i++)
                                printf(",");
                        switch (cx->type) {
@@ -378,7 +432,7 @@ acpicpu_attach(struct device *parent, st

        if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT)) ||
            !(sc->sc_flags & FLAGS_NOPSS)) {
-               printf("%c ", SLIST_EMPTY(&sc->sc_cstates) ? ':' : ',');
+               printf("%c ", TAILQ_EMPTY(&sc->sc_cstates) ? ':' : ',');

                /*
                 * If acpicpu is itself providing the capability to transition
@@ -394,24 +448,26 @@ acpicpu_attach(struct device *parent, st
                        printf("PSS");
        }

+       if (sc->sc_cx != NULL)
+               cpu_idle_cycle_fcn = acpicpu_idle;
+
        printf("\n");
 }

 int
 acpicpu_getppc(struct acpicpu_softc *sc)
 {
-       struct aml_value        res;
+       int64_t ppc;

        sc->sc_ppc = 0;

-       if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) {
+       if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, 
&ppc)) {
                dnprintf(10, "%s: no _PPC\n", DEVNAME(sc));
                return (1);
        }

-       sc->sc_ppc = aml_val2int(&res);
+       sc->sc_ppc = ppc;
        dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc);
-       aml_freevalue(&res);

        return (0);
 }
@@ -670,4 +726,82 @@ acpicpu_setperf(int level)
        } else
                printf("%s: acpicpu setperf failed to alter frequency\n",
                    sc->sc_devnode->name);
+}
+
+u_int
+acpicpu_ticks(struct acpicpu_softc *sc, u_int t1, u_int t2)
+{
+       if (t2 >= t1)
+               return t2 - t1;
+       else if (sc->sc_acpi->sc_fadt->flags & FADT_TMR_VAL_EXT)
+               return ((0xFFFFFFFF - t1) + t2 + 1);
+       else
+               return ((0x00FFFFFF - t1) + t2 + 1) & 0x00FFFFFF;
+}
+
+void
+acpicpu_idle(void)
+{
+       struct acpicpu_softc *sc;
+       struct acpi_cstate *cx, *cxdemote, *cxpromote;
+       struct timeval ts, te, td;
+       u_int32_t uSec;
+       int bm;
+
+       sc = acpicpu_sc[cpu_number()];
+
+       /* Get current states */
+       cx = sc->sc_cx;
+       cxdemote = TAILQ_PREV(cx, acpi_cstatehead, link);
+       cxpromote = TAILQ_NEXT(cx, link);
+
+       cx->enter++;
+       switch (cx->type) {
+       case ACPI_STATE_C1:
+               __asm__ __volatile__("hlt");
+               td.tv_sec = 0;
+               td.tv_usec = 1;
+               break;
+       case ACPI_STATE_C2:
+               microtime(&ts);
+               inb(cx->address);
+               microtime(&te);
+               timersub(&te, &ts, &td);
+               break;
+       case ACPI_STATE_C3:
+
+               /* Disable BM ARB */
+               acpi_write_pmreg(sc->sc_acpi, ACPIREG_PM2_CNT, 1,
+                   ACPI_PM2_ARB_DIS);
+
+               microtime(&ts);
+               inb(cx->address);
+               microtime(&te);
+
+               /* Enable BM ARB */
+               bm = inb(sc->sc_acpi->sc_fadt->pm2_cnt_blk);
+               outb(sc->sc_acpi->sc_fadt->pm2_cnt_blk, bm & ~ACPI_PM2_ARB_DIS);
+
+               timersub(&te, &ts, &td);
+               break;
+       }
+       uSec = td.tv_sec * 1000000 + td.tv_usec;
+       if (cxpromote && uSec > cxpromote->latency) {
+               cx->pcount++;
+               cx->dcount = 0;
+               if (cx->pcount >= cx->pthr) {
+                       printf("promoting C%d to C%d\n",
+                           cx->type, cxpromote->type);
+                       sc->sc_cx = cxpromote;
+               }
+       }
+       if (cxdemote && uSec < cxdemote->latency) {
+               cx->dcount++;
+               cx->pcount = 0;
+               if (cx->dcount >= cx->dthr) {
+                       printf("demoting C%d to C%d\n",
+                           cx->type, cxdemote->type);
+                       sc->sc_cx = cxdemote;
+               }
+       }
 }

Reply via email to