git: b8a0dfb17e3b - main - Add support for _CR3 critical standby (S3) threshold.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 22 Nov 2022 06:12:39 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=b8a0dfb17e3b62f228bb29e1098b34b3198f8e73

commit b8a0dfb17e3b62f228bb29e1098b34b3198f8e73
Author:     Cyrus Rahman <crahman@gmail.com>
AuthorDate: 2022-11-18 18:30:30 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-11-22 06:12:04 +0000

    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
---
 share/man/man4/acpi_thermal.4 |  5 ++++-
 sys/dev/acpica/acpi_thermal.c | 26 +++++++++++++++++++++-----
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/acpi_thermal.4 b/share/man/man4/acpi_thermal.4
index d1cf8ee60ef2..1b9395a24be3 100644
--- a/share/man/man4/acpi_thermal.4
+++ b/share/man/man4/acpi_thermal.4
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 17, 2007
+.Dd November 21, 2022
 .Dt ACPI_THERMAL 4
 .Os
 .Sh NAME
@@ -84,6 +84,9 @@ Current temperature for this zone.
 .It Va hw.acpi.thermal.tz%d._PSV
 Temperature to start passive cooling by throttling down CPU, etc.
 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
 Temperature to start critical suspend to disk (S4).
 This value can be overridden by the user.
diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c
index bd9ecf455e26..2ff9de6802fb 100644
--- a/sys/dev/acpica/acpi_thermal.c
+++ b/sys/dev/acpica/acpi_thermal.c
@@ -60,7 +60,7 @@ ACPI_MODULE_NAME("THERMAL")
 #define TZ_NOTIFY_TEMPERATURE	0x80 /* Temperature changed. */
 #define TZ_NOTIFY_LEVELS	0x81 /* Cooling levels 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 */
 #define TZ_POLLRATE	10
@@ -78,6 +78,7 @@ struct acpi_tz_zone {
     ACPI_BUFFER	al[TZ_NUMLEVELS];
     int		crt;
     int		hot;
+    int		cr3;
     ACPI_BUFFER	psl;
     int		psv;
     int		tc1;
@@ -97,8 +98,9 @@ struct acpi_tz_softc {
     int				tz_thflags;	/*Current temp-related flags*/
 #define TZ_THFLAG_NONE		0
 #define TZ_THFLAG_PSV		(1<<0)
-#define TZ_THFLAG_HOT		(1<<2)
-#define TZ_THFLAG_CRT		(1<<3)
+#define TZ_THFLAG_CR3		(1<<2)
+#define TZ_THFLAG_HOT		(1<<3)
+#define TZ_THFLAG_CRT		(1<<4)
     int				tz_flags;
 #define TZ_FLAG_NO_SCP		(1<<0)		/*No _SCP method*/
 #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,
 	offsetof(struct acpi_tz_softc, tz_zone.psv), acpi_tz_temp_sysctl, "IK",
 	"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),
         OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc,
 	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, "_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.Pointer = NULL;
     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.hot, "_HOT");
+    acpi_tz_sanity(sc, &sc->tz_zone.cr3, "_CR3");
     acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
     for (i = 0; i < TZ_NUMLEVELS; i++)
 	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
 acpi_tz_monitor(void *Context)
 {
+    struct acpi_softc	 *acpi_sc;
     struct acpi_tz_softc *sc;
     struct	timespec curtime;
     int		temp;
@@ -544,6 +553,8 @@ acpi_tz_monitor(void *Context)
     newflags = TZ_THFLAG_NONE;
     if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.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)
 	newflags |= TZ_THFLAG_HOT;
     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 ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
+    if ((newflags & (TZ_THFLAG_CR3 | TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
 	sc->tz_validchecks++;
 	if (sc->tz_validchecks == TZ_VALIDCHECKS) {
 	    device_printf(sc->tz_dev,
 		"WARNING - current temperature (%d.%dC) exceeds safe limits\n",
 		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)
 	    acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL);
     } else {