Add support for _CR3 critical standby (S3) threshold.

Along with _PSV, _HOT, and _CRT, ACPI supports the _CR3 threshold
which specifies a temperature above which a system should transition
to the S3 standby state.

On FreeBSD, this is more useful than _HOT, which specifies the S4
transition threshold temperature (since FreeBSD does not generally
support the S4 state), or, in many cases, _CRT, since after
transitioning to S3 the system can cool and then be resumed.

Reviewed by:	jhb, bcr (manpages)
Relnotes:	yes
Differential Revision:	https://reviews.freebsd.org/D35980
This commit is contained in:
Cyrus Rahman 2022-11-18 10:30:30 -08:00 committed by John Baldwin
parent 20a66ab4bf
commit b8a0dfb17e
2 changed files with 25 additions and 6 deletions

View File

@ -24,7 +24,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd March 17, 2007 .Dd November 21, 2022
.Dt ACPI_THERMAL 4 .Dt ACPI_THERMAL 4
.Os .Os
.Sh NAME .Sh NAME
@ -84,6 +84,9 @@ Current temperature for this zone.
.It Va hw.acpi.thermal.tz%d._PSV .It Va hw.acpi.thermal.tz%d._PSV
Temperature to start passive cooling by throttling down CPU, etc. Temperature to start passive cooling by throttling down CPU, etc.
This value can be overridden by the user. This value can be overridden by the user.
.It Va hw.acpi.thermal.tz%d._CR3
Temperature to start critical suspend to RAM (S3).
This value can be overridden by the user.
.It Va hw.acpi.thermal.tz%d._HOT .It Va hw.acpi.thermal.tz%d._HOT
Temperature to start critical suspend to disk (S4). Temperature to start critical suspend to disk (S4).
This value can be overridden by the user. This value can be overridden by the user.

View File

@ -60,7 +60,7 @@ ACPI_MODULE_NAME("THERMAL")
#define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ #define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */
#define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ #define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */
#define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ #define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */
#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ #define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT/_CR3 reached. */
/* Check for temperature changes every 10 seconds by default */ /* Check for temperature changes every 10 seconds by default */
#define TZ_POLLRATE 10 #define TZ_POLLRATE 10
@ -78,6 +78,7 @@ struct acpi_tz_zone {
ACPI_BUFFER al[TZ_NUMLEVELS]; ACPI_BUFFER al[TZ_NUMLEVELS];
int crt; int crt;
int hot; int hot;
int cr3;
ACPI_BUFFER psl; ACPI_BUFFER psl;
int psv; int psv;
int tc1; int tc1;
@ -97,8 +98,9 @@ struct acpi_tz_softc {
int tz_thflags; /*Current temp-related flags*/ int tz_thflags; /*Current temp-related flags*/
#define TZ_THFLAG_NONE 0 #define TZ_THFLAG_NONE 0
#define TZ_THFLAG_PSV (1<<0) #define TZ_THFLAG_PSV (1<<0)
#define TZ_THFLAG_HOT (1<<2) #define TZ_THFLAG_CR3 (1<<2)
#define TZ_THFLAG_CRT (1<<3) #define TZ_THFLAG_HOT (1<<3)
#define TZ_THFLAG_CRT (1<<4)
int tz_flags; int tz_flags;
#define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ #define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/
#define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ #define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/
@ -281,6 +283,10 @@ acpi_tz_attach(device_t dev)
OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
offsetof(struct acpi_tz_softc, tz_zone.psv), acpi_tz_temp_sysctl, "IK", offsetof(struct acpi_tz_softc, tz_zone.psv), acpi_tz_temp_sysctl, "IK",
"passive cooling temp setpoint"); "passive cooling temp setpoint");
SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
OID_AUTO, "_CR3", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
offsetof(struct acpi_tz_softc, tz_zone.cr3), acpi_tz_temp_sysctl, "IK",
"too warm temp setpoint (standby now)");
SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
offsetof(struct acpi_tz_softc, tz_zone.hot), acpi_tz_temp_sysctl, "IK", offsetof(struct acpi_tz_softc, tz_zone.hot), acpi_tz_temp_sysctl, "IK",
@ -420,6 +426,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc)
} }
acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
acpi_tz_getparam(sc, "_CR3", &sc->tz_zone.cr3);
sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER;
sc->tz_zone.psl.Pointer = NULL; sc->tz_zone.psl.Pointer = NULL;
AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
@ -437,6 +444,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc)
*/ */
acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT");
acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT");
acpi_tz_sanity(sc, &sc->tz_zone.cr3, "_CR3");
acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
for (i = 0; i < TZ_NUMLEVELS; i++) for (i = 0; i < TZ_NUMLEVELS; i++)
acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx");
@ -494,6 +502,7 @@ acpi_tz_get_temperature(struct acpi_tz_softc *sc)
static void static void
acpi_tz_monitor(void *Context) acpi_tz_monitor(void *Context)
{ {
struct acpi_softc *acpi_sc;
struct acpi_tz_softc *sc; struct acpi_tz_softc *sc;
struct timespec curtime; struct timespec curtime;
int temp; int temp;
@ -544,6 +553,8 @@ acpi_tz_monitor(void *Context)
newflags = TZ_THFLAG_NONE; newflags = TZ_THFLAG_NONE;
if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv)
newflags |= TZ_THFLAG_PSV; newflags |= TZ_THFLAG_PSV;
if (sc->tz_zone.cr3 != -1 && temp >= sc->tz_zone.cr3)
newflags |= TZ_THFLAG_CR3;
if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot)
newflags |= TZ_THFLAG_HOT; newflags |= TZ_THFLAG_HOT;
if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt)
@ -603,13 +614,18 @@ acpi_tz_monitor(void *Context)
* *
* If we're almost at that threshold, notify the user through devd(8). * If we're almost at that threshold, notify the user through devd(8).
*/ */
if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { if ((newflags & (TZ_THFLAG_CR3 | TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
sc->tz_validchecks++; sc->tz_validchecks++;
if (sc->tz_validchecks == TZ_VALIDCHECKS) { if (sc->tz_validchecks == TZ_VALIDCHECKS) {
device_printf(sc->tz_dev, device_printf(sc->tz_dev,
"WARNING - current temperature (%d.%dC) exceeds safe limits\n", "WARNING - current temperature (%d.%dC) exceeds safe limits\n",
TZ_KELVTOC(sc->tz_temperature)); TZ_KELVTOC(sc->tz_temperature));
shutdown_nice(RB_POWEROFF); if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0)
shutdown_nice(RB_POWEROFF);
else {
acpi_sc = acpi_device_get_parent_softc(sc->tz_dev);
acpi_ReqSleepState(acpi_sc, ACPI_STATE_S3);
}
} else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT)
acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL);
} else { } else {