On Fri, 27 May 2022, Jan Stary wrote:
> ... and with the latest snapshot, they are back.
...
> acpicpu0 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> C1(1000@1 mwait.1), PSS
> acpicpu1 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> C1(1000@1 mwait.1), PSS
> acpicpu2 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> C1(1000@1 mwait.1), PSS
> acpicpu3 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> C1(1000@1 mwait.1), PSS
>
> On May 26 14:34:43, [email protected] wrote:
> > This is current/adm64, dmesgs below.
> > With the current snapshot, the C states are gone:
> >
> > -acpicpu0 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> > C1(1000@1 mwait.1), PSS
> > -acpicpu1 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> > C1(1000@1 mwait.1), PSS
> > -acpicpu2 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> > C1(1000@1 mwait.1), PSS
> > -acpicpu3 at acpi0: C3(350@96 mwait.1@0x20), C2(500@64 mwait.1@0x10),
> > C1(1000@1 mwait.1), PSS
> > +acpicpu0 at acpi0: C1(@1 halt!), PSS
> > +acpicpu1 at acpi0: C1(@1 halt!), PSS
> > +acpicpu2 at acpi0: C1(@1 halt!), PSS
> > +acpicpu3 at acpi0: C1(@1 halt!), PSS
> >
> > Is this expected?
> > Is it related to the recent apmd -A change?
Not really. Well, unless your box is one where the states change
depending on, say, whether the box is plugged in.
You could give this diff a shot. It enables processing of CST change
notifications. No committers have a (working) box that does that, so I
couldn't get any interest and I have no idea when--or even if--it might go
in.
Philip Guenther
Index: sys/dev/acpi/acpicpu.c
===================================================================
RCS file: /data/src/openbsd/src/sys/dev/acpi/acpicpu.c,v
retrieving revision 1.92
diff -u -p -r1.92 acpicpu.c
--- sys/dev/acpi/acpicpu.c 6 Apr 2022 18:59:27 -0000 1.92
+++ sys/dev/acpi/acpicpu.c 12 Apr 2022 06:13:55 -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
@@ -113,8 +115,10 @@ struct acpi_cstate
uint64_t address; /* or mwait hint */
};
-unsigned long cst_stats[4] = { 0 };
-
+/*
+ * Locking:
+ * m sc_mtx
+ */
struct acpicpu_softc {
struct device sc_dev;
int sc_cpu;
@@ -130,6 +134,10 @@ struct acpicpu_softc {
struct cpu_info *sc_ci;
SLIST_HEAD(,acpi_cstate) sc_cstates;
+ struct mutex sc_mtx;
+ struct acpi_cstate *sc_cstates_active; /* [m] */
+ int sc_mwait_only; /* [m] */
+
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
@@ -161,10 +169,13 @@ 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 *);
+int acpicpu_cst_changed(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);
@@ -510,11 +521,11 @@ acpicpu_getcst(struct acpicpu_softc *sc)
struct acpi_cstate *cx, *next_cx;
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));
- }
+ /* set aside the existing list and free it if not active */
+ 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,
@@ -528,8 +539,10 @@ acpicpu_getcst(struct acpicpu_softc *sc)
/* only have fallback state? then no _CST objects were understood */
cx = SLIST_FIRST(&sc->sc_cstates);
- if (cx->flags & CST_FLAG_FALLBACK)
+ if (cx->flags & CST_FLAG_FALLBACK) {
+ sc->sc_flags &= ~FLAGS_MWAIT_ONLY;
return (1);
+ }
/*
* Skip states >= C2 if the CPU's LAPIC timer stops in deep
@@ -558,6 +571,38 @@ acpicpu_getcst(struct acpicpu_softc *sc)
return (0);
}
+int
+acpicpu_cst_changed(struct acpicpu_softc *sc)
+{
+ struct acpi_cstate *active, *new;
+
+ active = sc->sc_cstates_active;
+ new = SLIST_FIRST(&sc->sc_cstates);
+
+ while (active != NULL && new != NULL) {
+ if (active->state != new->state ||
+ active->method != new->method ||
+ active->flags != new->flags ||
+ active->latency != new->latency ||
+ active->address != new->address)
+ return 1;
+ active = SLIST_NEXT(active, link);
+ new = SLIST_NEXT(new, link);
+ }
+
+ return active != NULL || new != NULL;
+}
+
+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 +734,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 +781,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 +842,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 +883,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
@@ -1016,6 +1094,8 @@ acpicpu_notify(struct aml_node *node, in
switch (notify_type) {
case 0x80: /* _PPC changed, retrieve new values */
+ if (sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT))
+ break;
acpicpu_getppc(sc);
acpicpu_getpss(sc);
if (sc->sc_notify)
@@ -1023,10 +1103,15 @@ 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");
+ if (acpicpu_cst_changed(sc)) {
+ printf("%s: notify", DEVNAME(sc));
+ acpicpu_print_cst(sc);
+ printf("\n");
+ acpicpu_cst_activate(sc);
+ }
break;
default:
@@ -1151,18 +1236,22 @@ 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;
+ 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 +1261,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 +1285,20 @@ acpicpu_idle(void)
best = cx;
}
-
- atomic_inc_long(&cst_stats[best->state]);
+ /* made our choice; save the values we need and unlock */
+ method = best->method;
+ address = best->address;
+ mtx_leave(&sc->sc_mtx);
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 +1329,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 +1356,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;