Can we get some tests on this?

On Sun, Jun 07, 2009 at 02:48:24PM -0500, jor...@peereboom.us wrote:
> 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