From 26571a80a0664b93d0fea71da44f7ed6beec92b7 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 8 Aug 2024 07:01:22 +0000 Subject: [PATCH] Make intelmpc(4) print information about the residency counters advertised in the LPIT table. ok mlarkin@, deraadt@ --- sys/dev/acpi/acpireg.h | 26 +++++++++- sys/dev/acpi/intelpmc.c | 112 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h index 8719ea336d3..67b7fa0852e 100644 --- a/sys/dev/acpi/acpireg.h +++ b/sys/dev/acpi/acpireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpireg.h,v 1.60 2023/09/12 08:32:58 jmatthew Exp $ */ +/* $OpenBSD: acpireg.h,v 1.61 2024/08/08 07:01:22 kettenis Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * Copyright (c) 2005 Marco Peereboom @@ -476,6 +476,30 @@ struct acpi_tpm2 { uint32_t start_method; } __packed; +/* + * Intel ACPI Low Power S0 Idle + */ +struct acpi_lpit { + struct acpi_table_header hdr; +#define LPIT_SIG "LPIT" + /* struct acpi_lpit_entry[]; */ +} __packed; + +struct acpi_lpit_entry { + uint32_t type; + uint32_t length; + uint16_t uid; + uint16_t reserved; + uint32_t flags; +#define LPIT_DISABLED (1L << 0) +#define LPIT_COUNTER_NOT_AVAILABLE (1L << 1) + struct acpi_gas entry_trigger; + uint32_t residency; + uint32_t latency; + struct acpi_gas residency_counter; + uint64_t residency_frequency; +}; + /* * Intel ACPI DMA Remapping Entries */ diff --git a/sys/dev/acpi/intelpmc.c b/sys/dev/acpi/intelpmc.c index 7e06bc5f461..c22da5a76b0 100644 --- a/sys/dev/acpi/intelpmc.c +++ b/sys/dev/acpi/intelpmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intelpmc.c,v 1.1 2024/08/04 11:05:18 kettenis Exp $ */ +/* $OpenBSD: intelpmc.c,v 1.2 2024/08/08 07:01:22 kettenis Exp $ */ /* * Copyright (c) 2024 Mark Kettenis * @@ -46,6 +46,9 @@ struct intelpmc_softc { struct acpi_softc *sc_acpi; struct aml_node *sc_node; + struct acpi_gas sc_counter[4]; + int sc_num_counters; + #ifdef INTELPMC_DEBUG uint64_t sc_c3[2]; uint64_t sc_c6[2]; @@ -57,6 +60,7 @@ struct intelpmc_softc { uint64_t sc_pc8[2]; uint64_t sc_pc9[2]; uint64_t sc_pc10[2]; + uint64_t sc_lpit[4][2]; #endif }; @@ -78,6 +82,7 @@ const char *intelpmc_hids[] = { NULL }; +void intelpmc_parse_lpit(struct intelpmc_softc *, struct acpi_lpit *); void intelpmc_suspend(void *); void intelpmc_resume(void *); @@ -95,12 +100,25 @@ intelpmc_attach(struct device *parent, struct device *self, void *aux) { struct intelpmc_softc *sc = (struct intelpmc_softc *)self; struct acpi_attach_args *aaa = aux; + struct acpi_q *entry; + struct acpi_lpit *lpit = NULL; sc->sc_acpi = (struct acpi_softc *)parent; sc->sc_node = aaa->aaa_node; printf(": %s\n", aaa->aaa_node->name); + SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { + if (memcmp(entry->q_table, LPIT_SIG, + sizeof(LPIT_SIG) - 1) == 0) { + lpit = entry->q_table; + break; + } + } + + if (lpit) + intelpmc_parse_lpit(sc, lpit); + sc->sc_acpi->sc_pmc_suspend = intelpmc_suspend; sc->sc_acpi->sc_pmc_resume = intelpmc_resume; sc->sc_acpi->sc_pmc_cookie = sc; @@ -111,6 +129,7 @@ intelpmc_activate(struct device *self, int act) { #ifdef INTELPMC_DEBUG struct intelpmc_softc *sc = (struct intelpmc_softc *)self; + int i; switch (act) { case DVACT_RESUME: @@ -124,6 +143,10 @@ intelpmc_activate(struct device *self, int act) printf("PC8: %lld -> %lld\n", sc->sc_pc8[0], sc->sc_pc8[1]); printf("PC9: %lld -> %lld\n", sc->sc_pc9[0], sc->sc_pc9[1]); printf("PC10: %lld -> %lld\n", sc->sc_pc10[0], sc->sc_pc10[1]); + for (i = 0; i < sc->sc_num_counters; i++) { + printf("LPIT%d: %lld -> %lld\n", i, + sc->sc_lpit[i][0], sc->sc_lpit[i][1]); + } break; } #endif @@ -131,6 +154,63 @@ intelpmc_activate(struct device *self, int act) return 0; } +void +intelpmc_parse_lpit(struct intelpmc_softc *sc, struct acpi_lpit *lpit) +{ + caddr_t addr = (caddr_t)(lpit + 1); + + while (addr < (caddr_t)lpit + lpit->hdr.length) { + struct acpi_lpit_entry *entry = (struct acpi_lpit_entry *)addr; + uint32_t length = entry->length; + + if (length < 8) + return; + + if (addr + length > (caddr_t)lpit + lpit->hdr.length) + return; + + switch (entry->type) { + case 0: + if (length != sizeof(struct acpi_lpit_entry)) + return; + + if (entry->flags & LPIT_DISABLED) + break; + +#ifdef INTELPMC_DEBUG + printf("state %d: 0x%02x:%d:%d:0x%02x:0x%016llx\n", + entry->uid, entry->entry_trigger.address_space_id, + entry->entry_trigger.register_bit_width, + entry->entry_trigger.register_bit_offset, + entry->entry_trigger.access_size, + entry->entry_trigger.address); +#endif + + if (entry->flags & LPIT_COUNTER_NOT_AVAILABLE) + break; + +#ifdef INTELPMC_DEBUG + printf("counter: 0x%02x:%d:%d:0x%02x:0x%016llx\n", + entry->residency_counter.address_space_id, + entry->residency_counter.register_bit_width, + entry->residency_counter.register_bit_offset, + entry->residency_counter.access_size, + entry->residency_counter.address); + printf("frequency: %lld\n", + entry->residency_frequency); +#endif + + if (sc->sc_num_counters >= nitems(sc->sc_counter)) + break; + memcpy(&sc->sc_counter[sc->sc_num_counters++], + &entry->residency_counter, sizeof(struct acpi_gas)); + break; + } + + addr += length; + } +} + int intelpmc_dsm(struct acpi_softc *sc, struct aml_node *node, int func) { @@ -173,6 +253,9 @@ void intelpmc_suspend(void *cookie) { struct intelpmc_softc *sc = cookie; +#ifdef INTELPMC_DEBUG + int i; +#endif if (sc->sc_acpi->sc_state != ACPI_STATE_S0) return; @@ -188,6 +271,18 @@ intelpmc_suspend(void *cookie) rdmsr_safe(MSR_PKG_C8_RESIDENCY, &sc->sc_pc8[0]); rdmsr_safe(MSR_PKG_C9_RESIDENCY, &sc->sc_pc9[0]); rdmsr_safe(MSR_PKG_C10_RESIDENCY, &sc->sc_pc10[0]); + for (i = 0; i < sc->sc_num_counters; i++) { + if (sc->sc_counter[i].address_space_id == GAS_FUNCTIONAL_FIXED) + rdmsr_safe(sc->sc_counter[i].address, &sc->sc_lpit[i][0]); + else { + acpi_gasio(sc->sc_acpi, ACPI_IOREAD, + sc->sc_counter[i].address_space_id, + sc->sc_counter[i].address, + (1 << sc->sc_counter[i].access_size), + sc->sc_counter[i].register_bit_width / 8, + &sc->sc_lpit[i][0]); + } + } #endif intelpmc_dsm(sc->sc_acpi, sc->sc_node, ACPI_LPS0_SCREEN_OFF); @@ -198,6 +293,9 @@ void intelpmc_resume(void *cookie) { struct intelpmc_softc *sc = cookie; +#ifdef INTELPMC_DEBUG + int i; +#endif if (sc->sc_acpi->sc_state != ACPI_STATE_S0) return; @@ -216,5 +314,17 @@ intelpmc_resume(void *cookie) rdmsr_safe(MSR_PKG_C8_RESIDENCY, &sc->sc_pc8[1]); rdmsr_safe(MSR_PKG_C9_RESIDENCY, &sc->sc_pc9[1]); rdmsr_safe(MSR_PKG_C10_RESIDENCY, &sc->sc_pc10[1]); + for (i = 0; i < sc->sc_num_counters; i++) { + if (sc->sc_counter[i].address_space_id == GAS_FUNCTIONAL_FIXED) + rdmsr_safe(sc->sc_counter[i].address, &sc->sc_lpit[i][1]); + else { + acpi_gasio(sc->sc_acpi, ACPI_IOREAD, + sc->sc_counter[i].address_space_id, + sc->sc_counter[i].address, + (1 << sc->sc_counter[i].access_size), + sc->sc_counter[i].register_bit_width / 8, + &sc->sc_lpit[i][1]); + } + } #endif } -- 2.20.1