> Date: Thu, 10 Feb 2022 23:46:43 -0800
> From: guent...@openbsd.org
> 
> On Thu, 10 Feb 2022, Jan Stary wrote:
> > > > When you build a kernel with this, do please add ACPI_DEBUG to your 
> > > > kernel 
> > > > config, so we can see more details about what the firmware is telling 
> > > > us.
> > > 
> > > Full dmesg below, without ACPI_DEBUG.
> > > 
> > > Also below, full /var/log/messages with ACPI_DEBUG,
> > > as it spams dmesg so much that /var/run/dmesg.boot
> > > does not really contain the booting kernel device messages,
> > > being rolled off by the storm of ACPI_DEBUG messages.
> > > (Is there a way to increase that buffer,
> > > so that dmesg.boot would hold everything?)
> > > Of course, this is only after syslogd has started;
> > > hopefully the acpicpu events are there.
> > > 
> > > Both contain a log of the same scenario: cold start the machine on AC,
> > > plug AC out, in, out, in; shutdown with the power button.
> > 
> > With MSGBUFSIZE cranked up,
> > here is a dmesg containing all,
> > up to before the shutdown.
> 
> Uh, wow, I had forgotten how horrifically verbose ACPI_DEBUG was.  I'm 
> half inclined to delete all the uses of ACPI_DEBUG from acpicpu.c and use 
> a different #define for them.

Go for it.

> That said, the data shows the expected 0x81 notifications (and no 0x80 
> notifications) on the CPU objects, and the values appear to be accurately 
> parsed the acpicpu.c.  Whew.
> 
> 
> So here's a revised diff that tries to make it safe for ACPI to notify us 
> that a CPU's _CST has changed while that cpu is entering idle.  Revert the 
> previous diff before trying to apply this one.  Please give it a shot; no 
> need for ACPI_DEBUG now!
> 
> 
> Philip
> 
> 
> Index: sys/dev/acpi/acpicpu.c
> ===================================================================
> RCS file: /data/src/openbsd/src/sys/dev/acpi/acpicpu.c,v
> retrieving revision 1.91
> diff -u -p -r1.91 acpicpu.c
> --- sys/dev/acpi/acpicpu.c    9 Jan 2022 05:42:37 -0000       1.91
> +++ sys/dev/acpi/acpicpu.c    11 Feb 2022 07:19:11 -0000
> @@ -25,6 +25,7 @@
>  #include <sys/malloc.h>
>  #include <sys/queue.h>
>  #include <sys/atomic.h>
> +#include <sys/mutex.h>
>  
>  #include <machine/bus.h>
>  #include <machine/cpu.h>
> @@ -80,6 +81,7 @@ void        acpicpu_setperf_ppc_change(struct a
>  #define CST_FLAG_FALLBACK            0x4000  /* fallback for broken _CST */
>  #define CST_FLAG_SKIP                        0x8000  /* state is worse 
> choice */
>  
> +#define FLAGS_NOCST          0x01
>  #define FLAGS_MWAIT_ONLY     0x02
>  #define FLAGS_BMCHECK                0x04
>  #define FLAGS_NOTHROTTLE     0x08
> @@ -130,6 +132,11 @@ struct acpicpu_softc {
>       struct cpu_info         *sc_ci;
>       SLIST_HEAD(,acpi_cstate) sc_cstates;
>  
> +     /* sc_mtx protects sc_cstates_active and sc_mwait_only */
> +     struct mutex            sc_mtx;
> +     struct acpi_cstate      *sc_cstates_active;
> +     int                     sc_mwait_only;
> +
>       bus_space_tag_t         sc_iot;
>       bus_space_handle_t      sc_ioh;
>  
> @@ -161,10 +168,12 @@ struct acpicpu_softc {
>  
>  void acpicpu_add_cstatepkg(struct aml_value *, void *);
>  void acpicpu_add_cdeppkg(struct aml_value *, void *);
> +void acpicpu_cst_activate(struct acpicpu_softc *);
>  int  acpicpu_getppc(struct acpicpu_softc *);
>  int  acpicpu_getpct(struct acpicpu_softc *);
>  int  acpicpu_getpss(struct acpicpu_softc *);
>  int  acpicpu_getcst(struct acpicpu_softc *);
> +void acpicpu_free_states(struct acpi_cstate *);
>  void acpicpu_getcst_from_fadt(struct acpicpu_softc *);
>  void acpicpu_print_one_cst(struct acpi_cstate *_cx);
>  void acpicpu_print_cst(struct acpicpu_softc *_sc);
> @@ -511,10 +520,10 @@ acpicpu_getcst(struct acpicpu_softc *sc)
>       int                     use_nonmwait;
>  
>       /* delete the existing list */
> -     while ((cx = SLIST_FIRST(&sc->sc_cstates)) != NULL) {
> -             SLIST_REMOVE_HEAD(&sc->sc_cstates, link);
> -             free(cx, M_DEVBUF, sizeof(*cx));
> -     }
> +     cx = SLIST_FIRST(&sc->sc_cstates);
> +     SLIST_INIT(&sc->sc_cstates);
> +     if (cx != sc->sc_cstates_active)
> +             acpicpu_free_states(cx);
>  
>       /* provide a fallback C1-via-halt in case _CST's C1 is bogus */
>       acpicpu_add_cstate(sc, ACPI_STATE_C1, CST_METH_HALT,
> @@ -526,17 +535,18 @@ acpicpu_getcst(struct acpicpu_softc *sc)
>       aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
>       aml_freevalue(&res);
>  
> +     use_nonmwait = 0;
> +
>       /* only have fallback state?  then no _CST objects were understood */
>       cx = SLIST_FIRST(&sc->sc_cstates);
>       if (cx->flags & CST_FLAG_FALLBACK)
> -             return (1);
> +             goto done;
>  
>       /*
>        * Skip states >= C2 if the CPU's LAPIC timer stops in deep
>        * states (i.e., it doesn't have the 'ARAT' bit set).
>        * Also keep track if all the states we'll use use mwait.
>        */
> -     use_nonmwait = 0;
>       while ((next_cx = SLIST_NEXT(cx, link)) != NULL) {
>               if (cx->state > 1 &&
>                   (sc->sc_ci->ci_feature_tpmflags & TPM_ARAT) == 0)
> @@ -545,6 +555,7 @@ acpicpu_getcst(struct acpicpu_softc *sc)
>                       use_nonmwait = 1;
>               cx = next_cx;
>       }
> +done:
>       if (use_nonmwait)
>               sc->sc_flags &= ~FLAGS_MWAIT_ONLY;
>       else
> @@ -558,6 +569,16 @@ acpicpu_getcst(struct acpicpu_softc *sc)
>       return (0);
>  }
>  
> +void
> +acpicpu_free_states(struct acpi_cstate *cx)
> +{
> +     while (cx != NULL) {
> +             struct acpi_cstate *next_cx = SLIST_NEXT(cx, link);
> +             free(cx, M_DEVBUF, sizeof(*cx));
> +             cx = next_cx;
> +     }
> +}
> +
>  /*
>   * old-style fixed C-state info in the FADT.
>   * Note that this has extra restrictions on values and flags.
> @@ -689,7 +710,9 @@ acpicpu_attach(struct device *parent, st
>       sc->sc_acpi = (struct acpi_softc *)parent;
>       sc->sc_devnode = aa->aaa_node;
>  
> +     mtx_init(&sc->sc_mtx, IPL_NONE);
>       SLIST_INIT(&sc->sc_cstates);
> +     sc->sc_cstates_active = NULL;
>  
>       if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
>           "_UID", 0, NULL, &uid) == 0)
> @@ -734,9 +757,10 @@ acpicpu_attach(struct device *parent, st
>  #endif
>  
>       /* Get C-States from _CST or FADT */
> -     if (acpicpu_getcst(sc) || SLIST_EMPTY(&sc->sc_cstates))
> +     if (acpicpu_getcst(sc) || SLIST_EMPTY(&sc->sc_cstates)) {
>               acpicpu_getcst_from_fadt(sc);
> -     else {
> +             sc->sc_flags |= FLAGS_NOCST;
> +     } else {
>               /* Notify BIOS we use _CST objects */
>               if (sc->sc_acpi->sc_fadt->cst_cnt) {
>                       acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0,
> @@ -794,9 +818,6 @@ acpicpu_attach(struct device *parent, st
>                                   0, sc->sc_acpi->sc_fadt->pstate_cnt);
>                       }
>  
> -                     aml_register_notify(sc->sc_devnode, NULL,
> -                         acpicpu_notify, sc, ACPIDEV_NOPOLL);
> -
>                       acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
>                           sc->sc_pct.pct_status.grd_gas.address_space_id,
>                           sc->sc_pct.pct_status.grd_gas.address,
> @@ -838,6 +859,39 @@ acpicpu_attach(struct device *parent, st
>       }
>  
>       printf("\n");
> +     acpicpu_cst_activate(sc);
> +
> +     /*
> +      * If we understood either the provided _CST or _PPC
> +      * resources, register for notification of changes.
> +      */
> +     if ((sc->sc_flags & FLAGS_NOCST) == 0 ||
> +         (sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT)) == 0)
> +     {
> +#ifdef ACPI_DEBUG
> +             printf(": %s: enabling notification\n", sc->sc_devnode->name);
> +#endif
> +             aml_register_notify(sc->sc_devnode, NULL,
> +                 acpicpu_notify, sc, ACPIDEV_NOPOLL);
> +     }
> +}
> +
> +void
> +acpicpu_cst_activate(struct acpicpu_softc *sc)
> +{
> +     struct acpi_cstate      *cx, *old_states;
> +
> +     mtx_enter(&sc->sc_mtx);
> +     cx = SLIST_FIRST(&sc->sc_cstates);
> +     old_states = sc->sc_cstates_active;
> +     if (cx != old_states)
> +             sc->sc_cstates_active = cx;
> +     else
> +             old_states = NULL;
> +     sc->sc_mwait_only = (sc->sc_flags & FLAGS_MWAIT_ONLY) != 0;
> +     mtx_leave(&sc->sc_mtx);
> +
> +     acpicpu_free_states(old_states);
>  }
>  
>  int
> @@ -1023,10 +1077,13 @@ acpicpu_notify(struct aml_node *node, in
>               break;
>  
>       case 0x81:      /* _CST changed, retrieve new values */
> +             if (sc->sc_flags & FLAGS_NOCST)
> +                     break;
>               acpicpu_getcst(sc);
>               printf("%s: notify", DEVNAME(sc));
>               acpicpu_print_cst(sc);
>               printf("\n");
> +             acpicpu_cst_activate(sc);
>               break;
>  
>       default:
> @@ -1151,18 +1208,23 @@ acpicpu_setperf(int level)
>  void
>  acpicpu_idle(void)
>  {
> -     struct cpu_info *ci = curcpu();
> -     struct acpicpu_softc *sc = (struct acpicpu_softc *)ci->ci_acpicpudev;
> -     struct acpi_cstate *best, *cx;
> -     unsigned long itime;
> +     struct cpu_info         *ci = curcpu();
> +     struct acpicpu_softc    *sc = (struct acpicpu_softc *)ci->ci_acpicpudev;
> +     struct acpi_cstate      *best, *cx;
> +     unsigned long           itime;
> +     u_short                 state;
> +     short                   method;
> +     u_int                   address;
>  
>       if (sc == NULL) {
>               __asm volatile("sti");
>               panic("null acpicpu");
>       }
>  
> +     mtx_enter(&sc->sc_mtx);
> +
>       /* possibly update the MWAIT_ONLY flag in cpu_info */
> -     if (sc->sc_flags & FLAGS_MWAIT_ONLY) {
> +     if (sc->sc_mwait_only) {
>               if ((ci->ci_mwait & MWAIT_ONLY) == 0)
>                       atomic_setbits_int(&ci->ci_mwait, MWAIT_ONLY);
>       } else if (ci->ci_mwait & MWAIT_ONLY)
> @@ -1172,7 +1234,7 @@ acpicpu_idle(void)
>        * Find the first state with a latency we'll accept, ignoring
>        * states marked skippable
>        */
> -     best = cx = SLIST_FIRST(&sc->sc_cstates);
> +     best = cx = sc->sc_cstates_active;
>       while ((cx->flags & CST_FLAG_SKIP) ||
>           cx->latency * 3 > sc->sc_prev_sleep) {
>               if ((cx = SLIST_NEXT(cx, link)) == NULL)
> @@ -1196,18 +1258,23 @@ acpicpu_idle(void)
>               best = cx;
>       }
>  
> +     /* made our choice; save the values we need and unlock */
> +     state   = best->state;
> +     method  = best->method;
> +     address = best->address;
> +     mtx_leave(&sc->sc_mtx);
>  
> -     atomic_inc_long(&cst_stats[best->state]);
> +     atomic_inc_long(&cst_stats[state]);
>  
>       itime = tick / 2;
> -     switch (best->method) {
> +     switch (method) {
>       default:
>       case CST_METH_HALT:
>               __asm volatile("sti; hlt");
>               break;
>  
>       case CST_METH_IO_HALT:
> -             inb((u_short)best->address);
> +             inb((u_short)address);
>               __asm volatile("sti; hlt");
>               break;
>  
> @@ -1238,7 +1305,7 @@ acpicpu_idle(void)
>                * something to the queue and called cpu_unidle() between
>                * the check in sched_idle() and here.
>                */
> -             hints = (unsigned)best->address;
> +             hints = (unsigned)address;
>               microuptime(&start);
>               atomic_setbits_int(&ci->ci_mwait, MWAIT_IDLING);
>               if (cpu_is_idle(ci)) {
> @@ -1265,7 +1332,7 @@ acpicpu_idle(void)
>               }
>  
>       case CST_METH_GAS_IO:
> -             inb((u_short)best->address);
> +             inb((u_short)address);
>               /* something harmless to give system time to change state */
>               acpi_read_pmreg(acpi_softc, ACPIREG_PM1_STS, 0);
>               break;
> 
> 

Reply via email to