-
-
Save dmffen/dd2d3519722f10823223d57b9eaecee3 to your computer and use it in GitHub Desktop.
Detect and mitigate uncontrolled ACPI GPE interrupt storms on OpenBSD (7.3 through 7.8-stable)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Index: src/sys/dev/acpi/acpi.c | |
| =================================================================== | |
| RCS file: /cvs/src/sys/dev/acpi/acpi.c,v | |
| diff -u -p -r1.454 acpi.c | |
| --- src/sys/dev/acpi/acpi.c 20 Sep 2025 17:43:28 -0000 1.454 | |
| +++ src/sys/dev/acpi/acpi.c 24 Oct 2025 20:02:22 -0000 | |
| @@ -45,6 +45,9 @@ | |
| #include <machine/apmvar.h> | |
| +#define GPE_RATE_MIN_CYCLE 5 /* seconds */ | |
| +#define GPE_RATE_MAX 1000 /* per second */ | |
| + | |
| #include "wd.h" | |
| extern int cpu_suspended; | |
| @@ -95,6 +98,8 @@ void acpi_disable_allgpes(struct acpi_so | |
| struct gpe_block *acpi_find_gpe(struct acpi_softc *, int); | |
| void acpi_enable_onegpe(struct acpi_softc *, int); | |
| int acpi_gpe(struct acpi_softc *, int, void *); | |
| +void acpi_init_gpe_rate(struct acpi_softc *, int); | |
| +int acpi_gpe_rate(struct acpi_softc *, int); | |
| void acpi_enable_rungpes(struct acpi_softc *); | |
| @@ -2280,6 +2285,7 @@ acpi_enable_onegpe(struct acpi_softc *sc | |
| dnprintf(50, "enabling GPE %.2x (current: %sabled) %.2x\n", | |
| gpe, (en & mask) ? "en" : "dis", en); | |
| acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, en | mask); | |
| + acpi_init_gpe_rate(sc, gpe); | |
| } | |
| /* Clear all GPEs */ | |
| @@ -2358,7 +2364,40 @@ acpi_gpe(struct acpi_softc *sc, int gpe, | |
| if (sc->gpe_table[gpe].flags & GPE_LEVEL) | |
| acpi_write_pmreg(sc, ACPIREG_GPE_STS, gpe>>3, mask); | |
| en = acpi_read_pmreg(sc, ACPIREG_GPE_EN, gpe>>3); | |
| - acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, en | mask); | |
| + /* Re-enable if GPE rate passes, otherwise leave disabled */ | |
| + if (!acpi_gpe_rate(sc, gpe)) | |
| + acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, en | mask); | |
| + return (0); | |
| +} | |
| + | |
| +void | |
| +acpi_init_gpe_rate(struct acpi_softc *sc, int gpe) | |
| +{ | |
| + sc->gpe_table[gpe].rate_start = getuptime(); | |
| + sc->gpe_table[gpe].rate_count = 0; | |
| +} | |
| + | |
| +int | |
| +acpi_gpe_rate(struct acpi_softc *sc, int gpe) | |
| +{ | |
| + struct gpe_block *pgpe = &sc->gpe_table[gpe]; | |
| + time_t cycle; | |
| + | |
| + pgpe->rate_count++; | |
| + dnprintf(10, "rate GPE %.2x start %lld elapsed %lld count %zu\n", gpe, | |
| + pgpe->rate_start, getuptime() - pgpe->rate_start, pgpe->rate_count); | |
| + | |
| + cycle = getuptime() - pgpe->rate_start; | |
| + if (cycle >= GPE_RATE_MIN_CYCLE) { | |
| + if (pgpe->rate_count > (GPE_RATE_MAX * cycle)) { | |
| + printf("uncontrolled GPE storm %lld/s, disabling GPE %.2x\n", | |
| + pgpe->rate_count / cycle, gpe); | |
| + return (1); | |
| + } | |
| + | |
| + /* Reset and start a new cycle */ | |
| + acpi_init_gpe_rate(sc, gpe); | |
| + } | |
| return (0); | |
| } | |
| Index: src/sys/dev/acpi/acpivar.h | |
| =================================================================== | |
| RCS file: /cvs/src/sys/dev/acpi/acpivar.h,v | |
| diff -u -p -r1.138 acpivar.h | |
| --- src/sys/dev/acpi/acpivar.h 20 Sep 2025 17:43:28 -0000 1.138 | |
| +++ src/sys/dev/acpi/acpivar.h 24 Oct 2025 20:02:22 -0000 | |
| @@ -181,6 +181,9 @@ struct gpe_block { | |
| void *arg; | |
| int active; | |
| int flags; | |
| + | |
| + time_t rate_start; | |
| + size_t rate_count; | |
| }; | |
| struct acpi_devlist { | |
| Index: src/sys/kern/sched_bsd.c | |
| =================================================================== | |
| RCS file: /cvs/src/sys/kern/sched_bsd.c,v | |
| diff -u -p -r1.105 sched_bsd.c | |
| --- src/sys/kern/sched_bsd.c 25 Sep 2025 08:46:50 -0000 1.105 | |
| +++ src/sys/kern/sched_bsd.c 24 Oct 2025 20:02:23 -0000 | |
| @@ -594,11 +594,6 @@ setperf_auto(void *v) | |
| if (cpu_setperf == NULL) | |
| return; | |
| - if (current_perfpolicy() == PERFPOL_HIGH) { | |
| - speedup = 1; | |
| - goto faster; | |
| - } | |
| - | |
| if (!idleticks) | |
| if (!(idleticks = mallocarray(ncpusfound, sizeof(*idleticks), | |
| M_DEVBUF, M_NOWAIT | M_ZERO))) | |
| @@ -642,7 +637,6 @@ setperf_auto(void *v) | |
| downbeats++; | |
| if (speedup && perflevel != 100) { | |
| -faster: | |
| perflevel = 100; | |
| cpu_setperf(perflevel); | |
| } else if (!speedup && perflevel != 0 && --downbeats <= 0) { |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also re-enables dormant frequency scaling code in sched_bsd.c
Update source (from https://www.openbsd.org/anoncvs.html#updating)
Apply this patch (download gist to working directory first)
Build modded objects
Replace stock relink objects and link a new kernel
Reboot to use
Check
dmesgfor line similar touncontrolled GPE storm 5634/s, disabling GPE 6fand much-reduced CPU usage in system processacpi0Check
sysctl hw.sensorsfor frequency scaling