git: d2aa0a4dace1 - main - acpi: New R/O 'hw.acpi.s4bios_supported' sysctl, gate S4BIOS with it
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 06 Feb 2026 14:47:08 UTC
The branch main has been updated by olce:
URL: https://cgit.FreeBSD.org/src/commit/?id=d2aa0a4dace1d0cf8d52614c25b6a8f5cf03fd32
commit d2aa0a4dace1d0cf8d52614c25b6a8f5cf03fd32
Author: Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2026-01-09 13:43:23 +0000
Commit: Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-02-06 14:45:22 +0000
acpi: New R/O 'hw.acpi.s4bios_supported' sysctl, gate S4BIOS with it
This new sysctl knob indicates whether the ACPI implementation supports
S4BIOS (FACS present with bit S4BIOS_F set, as per the standard).
If S4BIOS is not supported, do not allow 'hw.acpi.s4bios' to be set to
true.
This is also in preparation of probably switching the default for
'hw.acpi.s4bios' to false once OSPM-initiated S4 support is ready, in
which case administrators need some way to determine whether
firmware-initiated S4 support is possible. For now, we keep the default
of setting 'hw.acpi.s4bios' to true (1) when S4BIOS is supported.
Reviewed by: obiwac
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D54627
---
sys/amd64/acpica/acpi_wakeup.c | 2 +-
sys/dev/acpica/acpi.c | 35 +++++++++++++++++++++++++++++++----
sys/dev/acpica/acpivar.h | 8 ++++++++
sys/i386/acpica/acpi_wakeup.c | 2 +-
4 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c
index 8cada2f4f911..6e6b9ac618dd 100644
--- a/sys/amd64/acpica/acpi_wakeup.c
+++ b/sys/amd64/acpica/acpi_wakeup.c
@@ -218,7 +218,7 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
/* Call ACPICA to enter the desired sleep state */
- if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
+ if (state == ACPI_STATE_S4 && acpi_should_do_s4bios(sc))
status = AcpiEnterSleepStateS4bios();
else
status = AcpiEnterSleepState(state);
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 53099db8ae84..59ae4624f407 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -193,6 +193,7 @@ static void acpi_system_eventhandler_sleep(void *arg,
enum power_stype stype);
static void acpi_system_eventhandler_wakeup(void *arg,
enum power_stype stype);
+static int acpi_s4bios_sysctl(SYSCTL_HANDLER_ARGS);
static enum power_stype acpi_sstate_to_stype(int sstate);
static int acpi_sname_to_sstate(const char *sname);
static const char *acpi_sstate_to_sname(int sstate);
@@ -624,9 +625,12 @@ acpi_attach(device_t dev)
if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER)
sc->acpi_handle_reboot = 1;
- /* Only enable S4BIOS by default if the FACS says it is available. */
+ /*
+ * Mark whether S4BIOS is available according to the FACS, and if it is,
+ * enable it by default.
+ */
if (AcpiGbl_FACS != NULL && AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT)
- sc->acpi_s4bios = true;
+ sc->acpi_s4bios = sc->acpi_s4bios_supported = true;
/*
* Probe all supported ACPI sleep states. Awake (S0) is always supported,
@@ -754,9 +758,13 @@ acpi_attach(device_t dev)
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0,
"sleep delay in seconds");
- SYSCTL_ADD_BOOL(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
- OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0,
+ SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+ OID_AUTO, "s4bios", CTLTYPE_U8 | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ sc, 0, acpi_s4bios_sysctl, "CU",
"On hibernate, have the firmware save/restore the machine state (S4BIOS).");
+ SYSCTL_ADD_BOOL(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
+ OID_AUTO, "s4bios_supported", CTLFLAG_RD, &sc->acpi_s4bios_supported, 0,
+ "Whether firmware supports saving/restoring the machine state (S4BIOS).");
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode");
SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
@@ -4433,6 +4441,25 @@ acpiioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
return (error);
}
+static int
+acpi_s4bios_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct acpi_softc *const sc = arg1;
+ bool val;
+ int error;
+
+ val = sc->acpi_s4bios;
+ error = sysctl_handle_bool(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ if (val && !sc->acpi_s4bios_supported)
+ return (EOPNOTSUPP);
+ sc->acpi_s4bios = val;
+
+ return (0);
+}
+
static int
acpi_sname_to_sstate(const char *sname)
{
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 51881c580d4b..d585fc8f2e23 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -65,6 +65,7 @@ struct acpi_softc {
int acpi_standby_sx;
bool acpi_s4bios;
+ bool acpi_s4bios_supported;
int acpi_sleep_delay;
int acpi_do_disable;
@@ -530,6 +531,13 @@ acpi_d_state_to_str(int state)
return (strs[state]);
}
+static __inline bool
+acpi_should_do_s4bios(struct acpi_softc *sc)
+{
+ MPASS(!sc->acpi_s4bios || sc->acpi_s4bios_supported);
+ return (sc->acpi_s4bios);
+}
+
char *acpi_name(ACPI_HANDLE handle);
int acpi_avoid(ACPI_HANDLE handle);
int acpi_disabled(char *subsys);
diff --git a/sys/i386/acpica/acpi_wakeup.c b/sys/i386/acpica/acpi_wakeup.c
index 96be64de017b..b5390f3cd659 100644
--- a/sys/i386/acpica/acpi_wakeup.c
+++ b/sys/i386/acpica/acpi_wakeup.c
@@ -240,7 +240,7 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
pmap_remap_lowptdi(true);
/* Call ACPICA to enter the desired sleep state */
- if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
+ if (state == ACPI_STATE_S4 && acpi_should_do_s4bios(sc))
status = AcpiEnterSleepStateS4bios();
else
status = AcpiEnterSleepState(state);