Module Name:    src
Committed By:   cegger
Date:           Wed Nov 25 13:54:23 UTC 2009

Modified Files:
        src/sys/dev/acpi: acpi_tz.c

Log Message:
By reading the ACPI dump I figured out that my
HP Pavillion dv9700 laptop features a fan sensor
in the ACPI Thermal Zone which is beyond of the ACPI
Spec.

envstat shows
[acpitz0]
  Processor Thermal Zone:     56.000   95.000                       degC
                     FAN:       2840                                 RPM

envstat -W shows the limits
[acpitz0]
  Processor Thermal Zone:     55.000                                degC
                     FAN:       2570     4500     2000               RPM

Patch presented on tech-k...@.

No comments.


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/sys/dev/acpi/acpi_tz.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_tz.c
diff -u src/sys/dev/acpi/acpi_tz.c:1.48 src/sys/dev/acpi/acpi_tz.c:1.49
--- src/sys/dev/acpi/acpi_tz.c:1.48	Mon Nov 23 14:42:39 2009
+++ src/sys/dev/acpi/acpi_tz.c	Wed Nov 25 13:54:23 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_tz.c,v 1.48 2009/11/23 14:42:39 cegger Exp $ */
+/* $NetBSD: acpi_tz.c,v 1.49 2009/11/25 13:54:23 cegger Exp $ */
 
 /*
  * Copyright (c) 2003 Jared D. McNeill <jmcne...@invisible.ca>
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.48 2009/11/23 14:42:39 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.49 2009/11/25 13:54:23 cegger Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -100,13 +100,17 @@
 	/* Thermal constants for use in passive cooling formulas */
 	UINT32 tc1, tc2;
 	/* Current temperature of the thermal zone */
-	UINT32 tmp;
+	UINT32 prevtmp, tmp;
 	/* Thermal sampling period for passive cooling, in tenths of seconds */
 	UINT32 tsp;
 	/* Package of references to devices in this TZ (optional) */
 	ACPI_BUFFER tzd;
 	/* Recommended TZ polling frequency, in tenths of seconds */
 	UINT32 tzp;
+	/* Thermal zone name */
+	char *name;
+	/* FAN min, max, current rpms */
+	UINT32 fanmin, fanmax, fancurrent;
 };
 
 struct acpitz_softc {
@@ -114,13 +118,15 @@
 	struct acpitz_zone sc_zone;
 	struct callout sc_callout;
 	struct sysmon_envsys *sc_sme;
-	envsys_data_t sc_sensor;
+	envsys_data_t sc_temp_sensor;
+	envsys_data_t sc_fan_sensor;
 	int sc_active;		/* active cooling level */
 	int sc_flags;
 	int sc_rate;		/* tz poll rate */
 	int sc_zone_expire;
 
 	int sc_first;
+	int sc_have_fan;	/* FAN sensor is optional */
 };
 
 static void	acpitz_get_status(void *);
@@ -139,6 +145,11 @@
 static void	acpitz_init_envsys(device_t);
 static void	acpitz_get_limits(struct sysmon_envsys *, envsys_data_t *,
 				  sysmon_envsys_lim_t *);
+static int	acpitz_get_fanspeed(device_t, UINT32 *, UINT32 *, UINT32 *);
+#ifdef notyet
+static ACPI_STATUS
+		acpitz_set_fanspeed(device_t, UINT32);
+#endif
 
 CFATTACH_DECL_NEW(acpitz, sizeof(struct acpitz_softc), acpitz_match,
     acpitz_attach, NULL, NULL);
@@ -190,7 +201,16 @@
 
 	sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp;
 	sc->sc_first = 1;
+	sc->sc_have_fan = 0;
+	if (acpitz_get_fanspeed(self,
+	    &sc->sc_zone.fanmin, &sc->sc_zone.fanmax, &sc->sc_zone.fancurrent)
+	    == 0)
+		sc->sc_have_fan = 1;
 
+	rv = acpi_eval_string(sc->sc_devnode->ad_handle,
+	    "REGN", &sc->sc_zone.name);
+	if (ACPI_FAILURE(rv))
+		sc->sc_zone.name = __UNCONST("temperature");
 	acpitz_get_zone(self, 1);
 	acpitz_get_status(self);
 
@@ -226,6 +246,7 @@
 	struct acpitz_softc *sc = device_private(dv);
 	UINT32 tmp, active;
 	int i, flags;
+	UINT32 fmin, fmax, fcurrent;
 
 	sc->sc_zone_expire--;
 	if (sc->sc_zone_expire <= 0) {
@@ -239,17 +260,29 @@
 		aprint_error_dev(dv, "failed to evaluate _TMP\n");
 		return;
 	}
+
+	sc->sc_zone.prevtmp = sc->sc_zone.tmp;
 	sc->sc_zone.tmp = tmp;
+	if (sc->sc_first)
+		sc->sc_zone.prevtmp = tmp;
 	/* XXX sanity check for tmp here? */
 
+	if (acpitz_get_fanspeed(dv, &fmin, &fmax, &fcurrent) == 0) {
+		if (fcurrent != ATZ_TMP_INVALID)
+			sc->sc_zone.fancurrent = fcurrent;
+	}
+
 	/*
 	 * The temperature unit for envsys(4) is microKelvin, so convert to
 	 * that from ACPI's microKelvin. Also, the ACPI specification assumes
 	 * that K = C + 273.2 rather than the nominal 273.15 used by envsys(4),
 	 * so we correct for that too.
 	 */
-	sc->sc_sensor.value_cur = ATZ2UKELVIN(sc->sc_zone.tmp);
-	sc->sc_sensor.state = ENVSYS_SVALID;
+	sc->sc_temp_sensor.value_cur = ATZ2UKELVIN(sc->sc_zone.tmp);
+	sc->sc_temp_sensor.state = ENVSYS_SVALID;
+
+	sc->sc_fan_sensor.value_cur = sc->sc_zone.fancurrent;
+	sc->sc_fan_sensor.state = ENVSYS_SVALID;
 
 	if (sc->sc_flags & ATZ_F_VERBOSE)
 		acpitz_print_status(dv);
@@ -271,7 +304,7 @@
 				active = i;
 		}
 		if (active != ATZ_ACTIVE_NONE)
-			sc->sc_sensor.state = ENVSYS_SWARNOVER;
+			sc->sc_temp_sensor.state = ENVSYS_SWARNOVER;
 
 		flags = sc->sc_flags &
 		    ~(ATZ_F_CRITICAL|ATZ_F_HOT|ATZ_F_PASSIVE);
@@ -289,12 +322,12 @@
 			int changed = (sc->sc_flags ^ flags) & flags;
 			sc->sc_flags = flags;
 			if (changed & ATZ_F_CRITICAL) {
-				sc->sc_sensor.state = ENVSYS_SCRITOVER;
+				sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
 				aprint_debug_dev(dv,
 				    "zone went critical at temp %sC\n",
 				    acpitz_celcius_string(tmp));
 			} else if (changed & ATZ_F_HOT) {
-				sc->sc_sensor.state = ENVSYS_SCRITOVER;
+				sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
 				aprint_debug_dev(dv,
 				    "zone went hot at temp %sC\n",
 				    acpitz_celcius_string(tmp));
@@ -338,6 +371,10 @@
 
 	printf("%s: zone temperature is now %sC\n", device_xname(dv),
 	    acpitz_celcius_string(sc->sc_zone.tmp));
+	if (sc->sc_have_fan) {
+		printf("%s: fan rpm %u\n", device_xname(dv),
+		    sc->sc_zone.fancurrent);
+	}
 
 	return;
 }
@@ -478,7 +515,8 @@
 	acpitz_get_integer(dv, "_HOT", &sc->sc_zone.hot);
 	sc->sc_zone.psl.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
 	sc->sc_zone.psl.Pointer = NULL;
-	AcpiEvaluateObject(sc, "_PSL", NULL, &sc->sc_zone.psl);
+	AcpiEvaluateObject(sc->sc_devnode->ad_handle,
+	    "_PSL", NULL, &sc->sc_zone.psl);
 	acpitz_get_integer(dv, "_PSV", &sc->sc_zone.psv);
 	acpitz_get_integer(dv, "_TC1", &sc->sc_zone.tc1);
 	acpitz_get_integer(dv, "_TC2", &sc->sc_zone.tc2);
@@ -584,6 +622,59 @@
 	return 0;
 }
 
+static int
+acpitz_get_fanspeed(device_t dv,
+    UINT32 *fanmin, UINT32 *fanmax, UINT32 *fancurrent)
+{
+	struct acpitz_softc *sc = device_private(dv);
+	ACPI_STATUS rv;
+	ACPI_HANDLE handle;
+	ACPI_INTEGER fmin, fmax, fcurr;
+	int rc = 0;
+
+	handle = sc->sc_devnode->ad_handle;
+	rv = acpi_eval_integer(handle, "FMIN", &fmin);
+	if (ACPI_FAILURE(rv)) {
+		fmin = ATZ_TMP_INVALID;
+		rc = 1;
+	}
+	rv = acpi_eval_integer(handle, "FMAX", &fmax);
+	if (ACPI_FAILURE(rv)) {
+		fmax = ATZ_TMP_INVALID;
+		rc = 1;
+	}
+	rv = acpi_eval_integer(handle, "FRSP", &fcurr);
+	if (ACPI_FAILURE(rv)) {
+		fcurr = ATZ_TMP_INVALID;
+		rc = 1;
+	}
+
+	if (fanmin)
+		*fanmin = fmin;
+	if (fanmax)
+		*fanmax = fmax;
+	if (fancurrent)
+		*fancurrent = fcurr;
+	return rc;
+}
+
+#ifdef notyet
+static ACPI_STATUS
+acpitz_set_fanspeed(device_t dv, UINT32 fanspeed)
+{
+	struct acpitz_softc *sc = device_private(dv);
+	ACPI_STATUS rv;
+	ACPI_HANDLE handle;
+	handle = sc->sc_devnode->ad_handle;
+
+	rv = acpi_eval_set_integer(handle, "FSSP", fanspeed);
+	if (ACPI_FAILURE(rv))
+		aprint_debug_dev(dv, "failed to set fanspeed to %u rpm: %s\n",
+			fanspeed, AcpiFormatException(rv));
+	return rv;
+}
+#endif
+
 static void
 acpitz_tick(void *opaque)
 {
@@ -605,16 +696,31 @@
 	sc->sc_sme->sme_cookie = sc;
 	sc->sc_sme->sme_name = device_xname(dv);
 	sc->sc_sme->sme_flags = SME_DISABLE_REFRESH;
-	sc->sc_sensor.monitor = true;
-	sc->sc_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
-	sc->sc_sensor.units = ENVSYS_STEMP;
-	strlcpy(sc->sc_sensor.desc, "temperature", sizeof(sc->sc_sensor.desc));
-	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor))
+
+	sc->sc_temp_sensor.monitor = true;
+	sc->sc_temp_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
+	sc->sc_temp_sensor.units = ENVSYS_STEMP;
+	strlcpy(sc->sc_temp_sensor.desc,
+	    sc->sc_zone.name, sizeof(sc->sc_temp_sensor.desc));
+	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_sensor))
 		goto out;
 
+	if (sc->sc_have_fan) {
+		sc->sc_fan_sensor.monitor = true;
+		sc->sc_fan_sensor.flags =
+		    ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
+		sc->sc_fan_sensor.units = ENVSYS_SFANRPM;
+		strlcpy(sc->sc_fan_sensor.desc,
+		    "FAN", sizeof(sc->sc_fan_sensor.desc));
+		if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan_sensor))
+			/* ignore error because fan sensor is optional */
+			aprint_error_dev(dv, "unable to attach fan sensor\n");
+	}
+
 	/* hook into sysmon */
 	if (sysmon_envsys_register(sc->sc_sme) == 0)
 		return;
+
 out:
 	aprint_error_dev(dv, "unable to register with sysmon\n");
 	sysmon_envsys_destroy(sc->sc_sme);
@@ -627,19 +733,40 @@
 	struct acpitz_softc *sc = sme->sme_cookie;
 	int i;
 
-	limits->sel_flags = 0;
+	printf("%s: units: %u\n", __func__, edata->units);
 
-	if (sc->sc_zone.hot != ATZ_TMP_INVALID) {
-		limits->sel_flags |= PROP_CRITMAX;
-		limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.hot);
-	} else if (sc->sc_zone.crt != ATZ_TMP_INVALID) {
-		limits->sel_flags |= PROP_CRITMAX;
-		limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.crt);
-	}
-	for (i = 0; i < ATZ_NLEVELS; i++) 
-		if (sc->sc_zone.ac[i] != ATZ_TMP_INVALID) {
-			limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.ac[i]);
+	switch (edata->units) {
+	case ENVSYS_STEMP:
+		limits->sel_flags = 0;
+		if (sc->sc_zone.hot != ATZ_TMP_INVALID) {
+			limits->sel_flags |= PROP_CRITMAX;
+			limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.hot);
+		} else if (sc->sc_zone.crt != ATZ_TMP_INVALID) {
+			limits->sel_flags |= PROP_CRITMAX;
+			limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.crt);
+		}
+		for (i = 0; i < ATZ_NLEVELS; i++) {
+			if (sc->sc_zone.ac[i] != ATZ_TMP_INVALID) {
+				limits->sel_critmax =
+				    ATZ2UKELVIN(sc->sc_zone.ac[i]);
+				limits->sel_flags |= PROP_WARNMAX;
+				break;
+			}
+		}
+		break;
+
+	case ENVSYS_SFANRPM:
+		limits->sel_flags = 0;
+		if (sc->sc_zone.fanmin != ATZ_TMP_INVALID) {
+			limits->sel_flags |= PROP_WARNMIN;
+			limits->sel_warnmin = sc->sc_zone.fanmin;
+			sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MIN;
+		}
+		if (sc->sc_zone.fanmax != ATZ_TMP_INVALID) {
 			limits->sel_flags |= PROP_WARNMAX;
-			break;
+			limits->sel_warnmax = sc->sc_zone.fanmax;
+			sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MAX;
 		}
+		break;
+	}
 }

Reply via email to