Home | History | Annotate | Line # | Download | only in acpi
acpi_tz.c revision 1.86
      1 /* $NetBSD: acpi_tz.c,v 1.86 2012/07/19 18:03:32 christos Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2003 Jared D. McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. The name of the author may not be used to endorse or promote products
     13  *    derived from this software without specific prior written permission.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * ACPI Thermal Zone driver
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.86 2012/07/19 18:03:32 christos Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/device.h>
     37 #include <sys/callout.h>
     38 #include <sys/kernel.h>
     39 #include <sys/module.h>
     40 #include <sys/systm.h>
     41 #include <sys/kmem.h>
     42 #include <sys/rnd.h>
     43 
     44 #include <dev/acpi/acpireg.h>
     45 #include <dev/acpi/acpivar.h>
     46 #include <dev/acpi/acpi_power.h>
     47 
     48 #define _COMPONENT		ACPI_TZ_COMPONENT
     49 ACPI_MODULE_NAME		("acpi_tz")
     50 
     51 #define ACPI_NOTIFY_TZ_ZONE	0x80
     52 #define ACPI_NOTIFY_TZ_TRIP	0x81
     53 #define ACPI_NOTIFY_TZ_DEVLIST	0x82
     54 
     55 #define ATZ_F_CRITICAL		0x01	/* zone critical */
     56 #define ATZ_F_HOT		0x02	/* zone hot */
     57 #define ATZ_F_PASSIVE		0x04	/* zone passive cooling */
     58 #define ATZ_F_PASSIVEONLY	0x08	/* zone is passive cooling only */
     59 
     60 #define ATZ_ACTIVE_NONE		  -1
     61 
     62 /*
     63  * The constants are as follows:
     64  *
     65  *   ATZ_TZP_RATE	default polling interval (30 seconds) if no _TZP
     66  *   ATZ_NLEVELS	number of cooling levels for _ACx and _ALx
     67  *   ATZ_ZEROC		0 C, measured in 0.1 Kelvin
     68  *   ATZ_TMP_INVALID	temporarily invalid temperature
     69  *   ATZ_ZONE_EXPIRE	zone info refetch interval (15 minutes)
     70  */
     71 #define ATZ_TZP_RATE		300
     72 #define ATZ_NLEVELS		10
     73 #define ATZ_ZEROC		2732
     74 #define ATZ_TMP_INVALID		0xffffffff
     75 #define ATZ_ZONE_EXPIRE		9000
     76 
     77 /*
     78  * All temperatures are reported in 0.1 Kelvin.
     79  * The ACPI specification assumes that K = C + 273.2
     80  * rather than the nominal 273.15 used by envsys(4).
     81  */
     82 #define	ATZ2UKELVIN(t) ((t) * 100000 - 50000)
     83 
     84 struct acpitz_zone {
     85 	ACPI_BUFFER		 al[ATZ_NLEVELS];
     86 	uint32_t		 ac[ATZ_NLEVELS];
     87 	uint32_t		 crt;
     88 	uint32_t		 hot;
     89 	uint32_t		 rtv;
     90 	uint32_t		 psv;
     91 	uint32_t		 tc1;
     92 	uint32_t		 tc2;
     93 	uint32_t		 tmp;
     94 	uint32_t		 prevtmp;
     95 	uint32_t		 tzp;
     96 	uint32_t		 fanmin;
     97 	uint32_t		 fanmax;
     98 	uint32_t		 fancurrent;
     99 	uint32_t		 fanprev;
    100 };
    101 
    102 struct acpitz_softc {
    103 	struct acpi_devnode	*sc_node;
    104 	struct sysmon_envsys	*sc_sme;
    105 	struct acpitz_zone	 sc_zone;
    106 	struct callout		 sc_callout;
    107 	envsys_data_t		 sc_temp_sensor;
    108 	envsys_data_t		 sc_fan_sensor;
    109 	int			 sc_active;
    110 	int			 sc_flags;
    111 	int			 sc_zone_expire;
    112 	bool			 sc_first;
    113 	bool			 sc_have_fan;
    114 	struct cpu_info	       **sc_psl;
    115 	size_t			 sc_psl_size;
    116 	krndsource_t		 sc_tmp_rs;
    117 	krndsource_t		 sc_fan_rs;
    118 };
    119 
    120 static int		acpitz_match(device_t, cfdata_t, void *);
    121 static void		acpitz_attach(device_t, device_t, void *);
    122 static int		acpitz_detach(device_t, int);
    123 static void		acpitz_get_status(void *);
    124 static void		acpitz_get_zone(void *, int);
    125 static void		acpitz_get_zone_quiet(void *);
    126 static char	       *acpitz_celcius_string(int);
    127 static void		acpitz_power_off(struct acpitz_softc *);
    128 static void		acpitz_power_zone(struct acpitz_softc *, int, int);
    129 static void		acpitz_sane_temp(uint32_t *tmp);
    130 static ACPI_STATUS	acpitz_switch_cooler(ACPI_OBJECT *, void *);
    131 static void		acpitz_notify_handler(ACPI_HANDLE, uint32_t, void *);
    132 static int		acpitz_get_integer(device_t, const char *, uint32_t *);
    133 static void		acpitz_tick(void *);
    134 static void		acpitz_init_envsys(device_t);
    135 static void		acpitz_get_limits(struct sysmon_envsys *,
    136 					  envsys_data_t *,
    137 					  sysmon_envsys_lim_t *, uint32_t *);
    138 static int		acpitz_get_fanspeed(device_t, uint32_t *,
    139 					    uint32_t *, uint32_t *);
    140 #ifdef notyet
    141 static ACPI_STATUS	acpitz_set_fanspeed(device_t, uint32_t);
    142 #endif
    143 static void		acpitz_print_processor_list(device_t);
    144 
    145 CFATTACH_DECL_NEW(acpitz, sizeof(struct acpitz_softc),
    146     acpitz_match, acpitz_attach, acpitz_detach, NULL);
    147 
    148 /*
    149  * acpitz_match: autoconf(9) match routine
    150  */
    151 static int
    152 acpitz_match(device_t parent, cfdata_t match, void *aux)
    153 {
    154 	struct acpi_attach_args *aa = aux;
    155 
    156 	if (aa->aa_node->ad_type != ACPI_TYPE_THERMAL)
    157 		return 0;
    158 
    159 	return 1;
    160 }
    161 
    162 /*
    163  * acpitz_attach: autoconf(9) attach routine
    164  */
    165 static void
    166 acpitz_attach(device_t parent, device_t self, void *aux)
    167 {
    168 	struct acpitz_softc *sc = device_private(self);
    169 	struct acpi_attach_args *aa = aux;
    170 	char tmpname[sizeof(sc->sc_tmp_rs.name)];
    171 	char fanname[sizeof(sc->sc_fan_rs.name)];
    172 	ACPI_INTEGER val;
    173 	ACPI_STATUS rv;
    174 
    175 	sc->sc_first = true;
    176 	sc->sc_have_fan = false;
    177 	sc->sc_node = aa->aa_node;
    178 	sc->sc_zone.tzp = ATZ_TZP_RATE;
    179 
    180 	aprint_naive("\n");
    181 	acpitz_print_processor_list(self);
    182 	aprint_normal("\n");
    183 
    184 	/*
    185 	 * The _TZP (ACPI 4.0, p. 430) defines the recommended
    186 	 * polling interval (in tenths of seconds). A value zero
    187 	 * means that polling "should not be necessary".
    188 	 */
    189 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_TZP", &val);
    190 
    191 	if (ACPI_SUCCESS(rv) && val != 0)
    192 		sc->sc_zone.tzp = val;
    193 
    194 	aprint_debug_dev(self, "polling interval %d.%d seconds\n",
    195 	    sc->sc_zone.tzp / 10, sc->sc_zone.tzp % 10);
    196 
    197 	sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp;
    198 
    199 	/*
    200 	 * XXX: The fan controls seen here are available on
    201 	 *	some HP laptops. Arguably these should not
    202 	 *	appear in a generic device driver like this.
    203 	 */
    204 	if (acpitz_get_fanspeed(self, &sc->sc_zone.fanmin,
    205 		&sc->sc_zone.fanmax, &sc->sc_zone.fancurrent) == 0)
    206 		sc->sc_have_fan = true;
    207 
    208 	acpitz_get_zone(self, 1);
    209 	acpitz_get_status(self);
    210 
    211 	(void)pmf_device_register(self, NULL, NULL);
    212 	(void)acpi_power_register(sc->sc_node->ad_handle);
    213 	(void)acpi_register_notify(sc->sc_node, acpitz_notify_handler);
    214 
    215 	callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
    216 	callout_setfunc(&sc->sc_callout, acpitz_tick, self);
    217 
    218 	acpitz_init_envsys(self);
    219 
    220 	if (sc->sc_have_fan) {
    221 		snprintf(fanname, sizeof(fanname), "%s-fan",
    222 			 device_xname(self));
    223 		snprintf(tmpname, sizeof(tmpname), "%s-tmp",
    224 			 device_xname(self));
    225 		rnd_attach_source(&sc->sc_fan_rs,
    226 				  fanname, RND_TYPE_ENV, 0);
    227 		rnd_attach_source(&sc->sc_tmp_rs,
    228 				  tmpname, RND_TYPE_ENV, 0);
    229 	} else {
    230 		rnd_attach_source(&sc->sc_tmp_rs,
    231 				  device_xname(self), RND_TYPE_ENV, 0);
    232 	}
    233 
    234 	callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10);
    235 }
    236 
    237 static int
    238 acpitz_detach(device_t self, int flags)
    239 {
    240 	struct acpitz_softc *sc = device_private(self);
    241 	ACPI_HANDLE hdl;
    242 	ACPI_BUFFER al;
    243 	ACPI_STATUS rv;
    244 	int i;
    245 
    246 	callout_halt(&sc->sc_callout, NULL);
    247 	callout_destroy(&sc->sc_callout);
    248 
    249 	rnd_detach_source(&sc->sc_tmp_rs);
    250 	if (sc->sc_have_fan) {
    251 		rnd_detach_source(&sc->sc_fan_rs);
    252 	}
    253 
    254 	pmf_device_deregister(self);
    255 	acpi_deregister_notify(sc->sc_node);
    256 
    257 	/*
    258 	 * Although the device itself should not contain any power
    259 	 * resources, we have possibly used the resources of active
    260 	 * cooling devices. To unregister these, first fetch a fresh
    261 	 * active cooling zone, and then detach the resources from
    262 	 * the reference handles contained in the cooling zone.
    263 	 */
    264 	acpitz_get_zone(self, 0);
    265 
    266 	for (i = 0; i < ATZ_NLEVELS; i++) {
    267 
    268 		if (sc->sc_zone.al[i].Pointer == NULL)
    269 			continue;
    270 
    271 		al = sc->sc_zone.al[i];
    272 		rv = acpi_eval_reference_handle(al.Pointer, &hdl);
    273 
    274 		if (ACPI_SUCCESS(rv))
    275 			acpi_power_deregister(hdl);
    276 
    277 		ACPI_FREE(sc->sc_zone.al[i].Pointer);
    278 	}
    279 
    280 	if (sc->sc_psl)
    281 		kmem_free(sc->sc_psl, sc->sc_psl_size);
    282 
    283 	if (sc->sc_sme != NULL)
    284 		sysmon_envsys_unregister(sc->sc_sme);
    285 
    286 	return 0;
    287 }
    288 
    289 static void
    290 acpitz_get_zone_quiet(void *opaque)
    291 {
    292 	acpitz_get_zone(opaque, 0);
    293 }
    294 
    295 static void
    296 acpitz_get_status(void *opaque)
    297 {
    298 	device_t dv = opaque;
    299 	struct acpitz_softc *sc = device_private(dv);
    300 	uint32_t tmp, fmin, fmax, fcurrent;
    301 	int active, changed, flags, i;
    302 
    303 	sc->sc_zone_expire--;
    304 
    305 	if (sc->sc_zone_expire <= 0) {
    306 		sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp;
    307 
    308 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
    309 			"%s: zone refetch forced\n", device_xname(dv)));
    310 
    311 		acpitz_get_zone(dv, 0);
    312 	}
    313 
    314 	if (acpitz_get_integer(dv, "_TMP", &tmp) != 0)
    315 		return;
    316 
    317 	sc->sc_zone.prevtmp = sc->sc_zone.tmp;
    318 	sc->sc_zone.tmp = tmp;
    319 
    320 	if (sc->sc_first != false)
    321 		sc->sc_zone.prevtmp = tmp; /* XXX: Sanity check? */
    322 
    323 	if (sc->sc_zone.prevtmp != sc->sc_zone.tmp) {
    324 		rnd_add_uint32(&sc->sc_tmp_rs, sc->sc_zone.tmp);
    325 	}
    326 
    327 	if (acpitz_get_fanspeed(dv, &fmin, &fmax, &fcurrent) == 0) {
    328 		if (fcurrent != ATZ_TMP_INVALID) {
    329 			sc->sc_zone.fanprev = sc->sc_zone.fancurrent;
    330 			sc->sc_zone.fancurrent = fcurrent;
    331 			if (sc->sc_zone.fanprev != sc->sc_zone.fancurrent) {
    332 				rnd_add_uint32(&sc->sc_fan_rs,
    333 						sc->sc_zone.fancurrent);
    334 			}
    335 		}
    336 	}
    337 
    338 	sc->sc_temp_sensor.state = ENVSYS_SVALID;
    339 	sc->sc_temp_sensor.value_cur = ATZ2UKELVIN(sc->sc_zone.tmp);
    340 
    341 	sc->sc_fan_sensor.state = ENVSYS_SVALID;
    342 	sc->sc_fan_sensor.value_cur = sc->sc_zone.fancurrent;
    343 
    344 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: zone temperature is %s C\n",
    345 		device_xname(dv), acpitz_celcius_string(sc->sc_zone.tmp)));
    346 
    347 	/*
    348 	 * XXX: Passive cooling is not yet supported.
    349 	 */
    350 	if ((sc->sc_flags & ATZ_F_PASSIVEONLY) != 0)
    351 		return;
    352 
    353 	/*
    354 	 * As noted in ACPI 4.0 (p. 420), the temperature
    355 	 * thresholds are conveyed in the optional _ACx
    356 	 * object (x = 0 ... 9). The smaller the x, the
    357 	 * greater the cooling level. We prefer to keep
    358 	 * the highest cooling mode when in "active".
    359 	 */
    360 	active = ATZ_ACTIVE_NONE;
    361 
    362 	for (i = ATZ_NLEVELS - 1; i >= 0; i--) {
    363 
    364 		if (sc->sc_zone.ac[i] == ATZ_TMP_INVALID)
    365 			continue;
    366 
    367 		if (sc->sc_zone.ac[i] <= tmp)
    368 			active = i;
    369 	}
    370 
    371 	flags = sc->sc_flags & ~(ATZ_F_CRITICAL | ATZ_F_HOT | ATZ_F_PASSIVE);
    372 
    373 	if (sc->sc_zone.psv != ATZ_TMP_INVALID && tmp >= sc->sc_zone.psv)
    374 		flags |= ATZ_F_PASSIVE;
    375 
    376 	if (sc->sc_zone.hot != ATZ_TMP_INVALID && tmp >= sc->sc_zone.hot)
    377 		flags |= ATZ_F_HOT;
    378 
    379 	if (sc->sc_zone.crt != ATZ_TMP_INVALID && tmp >= sc->sc_zone.crt)
    380 		flags |= ATZ_F_CRITICAL;
    381 
    382 	if (flags != sc->sc_flags) {
    383 
    384 		changed = (sc->sc_flags ^ flags) & flags;
    385 		sc->sc_flags = flags;
    386 
    387 		if ((changed & ATZ_F_CRITICAL) != 0) {
    388 			sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
    389 
    390 			aprint_debug_dev(dv, "zone went critical, %s C\n",
    391 			    acpitz_celcius_string(tmp));
    392 
    393 		} else if ((changed & ATZ_F_HOT) != 0) {
    394 			sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
    395 
    396 			aprint_debug_dev(dv, "zone went hot, %s C\n",
    397 			    acpitz_celcius_string(tmp));
    398 		}
    399 	}
    400 
    401 	/* Power on the fans. */
    402 	if (sc->sc_active != active) {
    403 
    404 		if (sc->sc_active != ATZ_ACTIVE_NONE)
    405 			acpitz_power_zone(sc, sc->sc_active, 0);
    406 
    407 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: active cooling "
    408 			"level %d\n", device_xname(dv), active));
    409 
    410 		if (active != ATZ_ACTIVE_NONE)
    411 			acpitz_power_zone(sc, active, 1);
    412 
    413 		sc->sc_active = active;
    414 	}
    415 }
    416 
    417 static char *
    418 acpitz_celcius_string(int dk)
    419 {
    420 	static char buf[10];
    421 	int dc;
    422 
    423 	dc = abs(dk - ATZ_ZEROC);
    424 
    425 	(void)snprintf(buf, sizeof(buf), "%s%d.%d",
    426 	    (dk >= ATZ_ZEROC) ? "" : "-", dc / 10, dc % 10);
    427 
    428 	return buf;
    429 }
    430 
    431 static ACPI_STATUS
    432 acpitz_switch_cooler(ACPI_OBJECT *obj, void *arg)
    433 {
    434 	int flag, pwr_state;
    435 	ACPI_HANDLE cooler;
    436 	ACPI_STATUS rv;
    437 
    438 	/*
    439 	 * The _ALx object is a package in which the elements
    440 	 * are reference handles to an active cooling device
    441 	 * (typically PNP0C0B, ACPI fan device). Try to turn
    442 	 * on (or off) the power resources behind these handles
    443 	 * to start (or terminate) the active cooling.
    444 	 */
    445 	flag = *(int *)arg;
    446 	pwr_state = (flag != 0) ? ACPI_STATE_D0 : ACPI_STATE_D3;
    447 
    448 	rv = acpi_eval_reference_handle(obj, &cooler);
    449 
    450 	if (ACPI_FAILURE(rv))
    451 		return rv;
    452 
    453 	(void)acpi_power_set(cooler, pwr_state);
    454 
    455 	return AE_OK;
    456 }
    457 
    458 /*
    459  * acpitz_power_zone:
    460  *
    461  *	Power on or off the i:th part of the zone zone.
    462  */
    463 static void
    464 acpitz_power_zone(struct acpitz_softc *sc, int i, int on)
    465 {
    466 
    467 	KASSERT(i >= 0 && i < ATZ_NLEVELS);
    468 
    469 	(void)acpi_foreach_package_object(sc->sc_zone.al[i].Pointer,
    470 	    acpitz_switch_cooler, &on);
    471 }
    472 
    473 
    474 /*
    475  * acpitz_power_off:
    476  *
    477  *	Power off parts of the zone.
    478  */
    479 static void
    480 acpitz_power_off(struct acpitz_softc *sc)
    481 {
    482 	int i;
    483 
    484 	for (i = 0 ; i < ATZ_NLEVELS; i++) {
    485 
    486 		if (sc->sc_zone.al[i].Pointer == NULL)
    487 			continue;
    488 
    489 		acpitz_power_zone(sc, i, 0);
    490 	}
    491 
    492 	sc->sc_active = ATZ_ACTIVE_NONE;
    493 	sc->sc_flags &= ~(ATZ_F_CRITICAL | ATZ_F_HOT | ATZ_F_PASSIVE);
    494 }
    495 
    496 static void
    497 acpitz_get_zone(void *opaque, int verbose)
    498 {
    499 	device_t dv = opaque;
    500 	struct acpitz_softc *sc = device_private(dv);
    501 	int comma, i, valid_levels;
    502 	ACPI_OBJECT *obj;
    503 	ACPI_STATUS rv;
    504 	char buf[5];
    505 
    506 	if (sc->sc_first != true) {
    507 		acpitz_power_off(sc);
    508 
    509 		for (i = 0; i < ATZ_NLEVELS; i++) {
    510 
    511 			if (sc->sc_zone.al[i].Pointer != NULL)
    512 				ACPI_FREE(sc->sc_zone.al[i].Pointer);
    513 
    514 			sc->sc_zone.al[i].Pointer = NULL;
    515 		}
    516 	}
    517 
    518 	valid_levels = 0;
    519 
    520 	for (i = 0; i < ATZ_NLEVELS; i++) {
    521 
    522 		(void)snprintf(buf, sizeof(buf), "_AC%d", i);
    523 
    524 		if (acpitz_get_integer(dv, buf, &sc->sc_zone.ac[i]))
    525 			continue;
    526 
    527 		(void)snprintf(buf, sizeof(buf), "_AL%d", i);
    528 
    529 		rv = acpi_eval_struct(sc->sc_node->ad_handle, buf,
    530 		    &sc->sc_zone.al[i]);
    531 
    532 		if (ACPI_FAILURE(rv)) {
    533 			sc->sc_zone.al[i].Pointer = NULL;
    534 			continue;
    535 		}
    536 
    537 		obj = sc->sc_zone.al[i].Pointer;
    538 
    539 		if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count == 0) {
    540 			sc->sc_zone.al[i].Pointer = NULL;
    541 			ACPI_FREE(obj);
    542 			continue;
    543 		}
    544 
    545 		if (sc->sc_first != false)
    546 			aprint_normal_dev(dv, "active cooling level %d: %sC\n",
    547 			    i, acpitz_celcius_string(sc->sc_zone.ac[i]));
    548 
    549 		valid_levels++;
    550 	}
    551 
    552 	/*
    553 	 * A brief summary (ACPI 4.0, section 11.4):
    554 	 *
    555 	 *    _TMP : current temperature (in tenths of degrees)
    556 	 *    _CRT : critical trip-point at which to shutdown
    557 	 *    _HOT : critical trip-point at which to go to S4
    558 	 *    _PSV : passive cooling policy threshold
    559 	 *    _TC1 : thermal constant for passive cooling
    560 	 *    _TC2 : thermal constant for passive cooling
    561 	 */
    562 	(void)acpitz_get_integer(dv, "_TMP", &sc->sc_zone.tmp);
    563 	(void)acpitz_get_integer(dv, "_CRT", &sc->sc_zone.crt);
    564 	(void)acpitz_get_integer(dv, "_HOT", &sc->sc_zone.hot);
    565 	(void)acpitz_get_integer(dv, "_PSV", &sc->sc_zone.psv);
    566 	(void)acpitz_get_integer(dv, "_TC1", &sc->sc_zone.tc1);
    567 	(void)acpitz_get_integer(dv, "_TC2", &sc->sc_zone.tc2);
    568 
    569 	/*
    570 	 * If _RTV is not present or present and zero,
    571 	 * values are absolute (see ACPI 4.0, 425).
    572 	 */
    573 	acpitz_get_integer(dv, "_RTV", &sc->sc_zone.rtv);
    574 
    575 	if (sc->sc_zone.rtv == ATZ_TMP_INVALID)
    576 		sc->sc_zone.rtv = 0;
    577 
    578 	acpitz_sane_temp(&sc->sc_zone.tmp);
    579 	acpitz_sane_temp(&sc->sc_zone.crt);
    580 	acpitz_sane_temp(&sc->sc_zone.hot);
    581 	acpitz_sane_temp(&sc->sc_zone.psv);
    582 
    583 	if (verbose != 0) {
    584 		comma = 0;
    585 
    586 		aprint_verbose_dev(dv, "levels: ");
    587 
    588 		if (sc->sc_zone.crt != ATZ_TMP_INVALID) {
    589 			aprint_verbose("critical %s C",
    590 			    acpitz_celcius_string(sc->sc_zone.crt));
    591 			comma = 1;
    592 		}
    593 
    594 		if (sc->sc_zone.hot != ATZ_TMP_INVALID) {
    595 			aprint_verbose("%shot %s C", comma ? ", " : "",
    596 			    acpitz_celcius_string(sc->sc_zone.hot));
    597 			comma = 1;
    598 		}
    599 
    600 		if (sc->sc_zone.psv != ATZ_TMP_INVALID) {
    601 			aprint_verbose("%spassive %s C", comma ? ", " : "",
    602 			    acpitz_celcius_string(sc->sc_zone.psv));
    603 			comma = 1;
    604 		}
    605 
    606 		if (valid_levels == 0) {
    607 			sc->sc_flags |= ATZ_F_PASSIVEONLY;
    608 
    609 			if (sc->sc_first != false)
    610 				aprint_verbose("%spassive cooling", comma ?
    611 				    ", " : "");
    612 		}
    613 
    614 		aprint_verbose("\n");
    615 	}
    616 
    617 	for (i = 0; i < ATZ_NLEVELS; i++)
    618 		acpitz_sane_temp(&sc->sc_zone.ac[i]);
    619 
    620 	acpitz_power_off(sc);
    621 	sc->sc_first = false;
    622 }
    623 
    624 static void
    625 acpitz_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque)
    626 {
    627 	ACPI_OSD_EXEC_CALLBACK func = NULL;
    628 	device_t dv = opaque;
    629 
    630 	switch (notify) {
    631 
    632 	case ACPI_NOTIFY_TZ_ZONE:
    633 		func = acpitz_get_status;
    634 		break;
    635 
    636 	case ACPI_NOTIFY_TZ_TRIP:
    637 	case ACPI_NOTIFY_TZ_DEVLIST:
    638 		func = acpitz_get_zone_quiet;
    639 		break;
    640 
    641 	default:
    642 		aprint_debug_dev(dv, "unknown notify 0x%02X\n", notify);
    643 		return;
    644 	}
    645 
    646 	(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, func, dv);
    647 }
    648 
    649 static void
    650 acpitz_sane_temp(uint32_t *tmp)
    651 {
    652 	/* Sane temperatures are beteen 0 and 150 C. */
    653 	if (*tmp < ATZ_ZEROC || *tmp > ATZ_ZEROC + 1500)
    654 		*tmp = ATZ_TMP_INVALID;
    655 }
    656 
    657 static int
    658 acpitz_get_integer(device_t dv, const char *cm, uint32_t *val)
    659 {
    660 	struct acpitz_softc *sc = device_private(dv);
    661 	ACPI_INTEGER tmp;
    662 	ACPI_STATUS rv;
    663 
    664 	rv = acpi_eval_integer(sc->sc_node->ad_handle, cm, &tmp);
    665 
    666 	if (ACPI_FAILURE(rv)) {
    667 		*val = ATZ_TMP_INVALID;
    668 
    669 		ACPI_DEBUG_PRINT((ACPI_DB_DEBUG_OBJECT,
    670 			"%s: failed to evaluate %s: %s\n",
    671 			device_xname(dv), cm, AcpiFormatException(rv)));
    672 
    673 		return 1;
    674 	}
    675 
    676 	*val = tmp;
    677 
    678 	return 0;
    679 }
    680 
    681 static int
    682 acpitz_get_fanspeed(device_t dv,
    683     uint32_t *fanmin, uint32_t *fanmax, uint32_t *fancurrent)
    684 {
    685 	struct acpitz_softc *sc = device_private(dv);
    686 	ACPI_INTEGER fmin, fmax, fcurr;
    687 	ACPI_HANDLE handle;
    688 	ACPI_STATUS rv;
    689 	int rc = 0;
    690 
    691 	handle = sc->sc_node->ad_handle;
    692 
    693 	rv = acpi_eval_integer(handle, "FMIN", &fmin);
    694 
    695 	if (ACPI_FAILURE(rv)) {
    696 		fmin = ATZ_TMP_INVALID;
    697 		rc = 1;
    698 	}
    699 
    700 	rv = acpi_eval_integer(handle, "FMAX", &fmax);
    701 
    702 	if (ACPI_FAILURE(rv)) {
    703 		fmax = ATZ_TMP_INVALID;
    704 		rc = 1;
    705 	}
    706 	rv = acpi_eval_integer(handle, "FRSP", &fcurr);
    707 
    708 	if (ACPI_FAILURE(rv)) {
    709 		fcurr = ATZ_TMP_INVALID;
    710 		rc = 1;
    711 	}
    712 
    713 	if (fanmin != NULL)
    714 		*fanmin = fmin;
    715 
    716 	if (fanmax != NULL)
    717 		*fanmax = fmax;
    718 
    719 	if (fancurrent != NULL)
    720 		*fancurrent = fcurr;
    721 
    722 	return rc;
    723 }
    724 
    725 #ifdef notyet
    726 static ACPI_STATUS
    727 acpitz_set_fanspeed(device_t dv, uint32_t fanspeed)
    728 {
    729 	struct acpitz_softc *sc = device_private(dv);
    730 	ACPI_HANDLE handle;
    731 	ACPI_STATUS rv;
    732 
    733 	handle = sc->sc_node->ad_handle;
    734 
    735 	rv = acpi_eval_set_integer(handle, "FSSP", fanspeed);
    736 
    737 	if (ACPI_FAILURE(rv))
    738 		aprint_debug_dev(dv, "failed to set fan speed to %u RPM: %s\n",
    739 		    fanspeed, AcpiFormatException(rv));
    740 
    741 	return rv;
    742 }
    743 #endif
    744 
    745 static void
    746 acpitz_print_processor_list(device_t dv)
    747 {
    748 	struct acpitz_softc *sc = device_private(dv);
    749 	ACPI_HANDLE handle = sc->sc_node->ad_handle;
    750 	ACPI_OBJECT *obj, *pref;
    751 	ACPI_HANDLE prhandle;
    752 	ACPI_BUFFER buf;
    753 	ACPI_STATUS rv;
    754 	struct cpu_info *ci;
    755 	unsigned int i, cnt;
    756 
    757 	rv = acpi_eval_struct(handle, "_PSL", &buf);
    758 
    759 	if (ACPI_FAILURE(rv) || buf.Pointer == NULL)
    760 		return;
    761 
    762 	obj = buf.Pointer;
    763 
    764 	if (obj->Type != ACPI_TYPE_PACKAGE || obj->Package.Count == 0)
    765 		goto done;
    766 
    767 	sc->sc_psl_size = sizeof(ci) * (obj->Package.Count + 1);
    768 	sc->sc_psl = kmem_zalloc(sc->sc_psl_size, KM_SLEEP);
    769 	for (cnt = i = 0; i < obj->Package.Count; i++) {
    770 
    771 		pref = &obj->Package.Elements[i];
    772 		rv = acpi_eval_reference_handle(pref, &prhandle);
    773 
    774 		if (ACPI_FAILURE(rv))
    775 			continue;
    776 
    777 		ci = acpi_match_cpu_handle(prhandle);
    778 
    779 		if (ci == NULL)
    780 			continue;
    781 
    782 		if (cnt == 0)
    783 			aprint_normal(":");
    784 
    785 		aprint_normal(" %s", device_xname(ci->ci_dev));
    786 
    787 		if (sc->sc_psl)
    788 			sc->sc_psl[cnt] = ci;
    789 		++cnt;
    790 	}
    791 
    792 done:
    793 	ACPI_FREE(buf.Pointer);
    794 }
    795 
    796 static void
    797 acpitz_tick(void *opaque)
    798 {
    799 	device_t dv = opaque;
    800 	struct acpitz_softc *sc = device_private(dv);
    801 
    802 	(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, acpitz_get_status, dv);
    803 
    804 	callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10);
    805 }
    806 
    807 static void
    808 acpitz_init_envsys(device_t dv)
    809 {
    810 	const int flags = ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
    811 	struct acpitz_softc *sc = device_private(dv);
    812 	unsigned int i;
    813 
    814 	sc->sc_sme = sysmon_envsys_create();
    815 
    816 	sc->sc_sme->sme_cookie = sc;
    817 	sc->sc_sme->sme_name = device_xname(dv);
    818 	sc->sc_sme->sme_flags = SME_DISABLE_REFRESH;
    819 	sc->sc_sme->sme_get_limits = acpitz_get_limits;
    820 
    821 	sc->sc_temp_sensor.flags = flags;
    822 	sc->sc_temp_sensor.units = ENVSYS_STEMP;
    823 	sc->sc_temp_sensor.state = ENVSYS_SINVALID;
    824 
    825 	memset(sc->sc_temp_sensor.desc, 0, sizeof(sc->sc_temp_sensor.desc));
    826 	if (sc->sc_psl) {
    827 		for (i = 0; sc->sc_psl[i] != NULL; i++) {
    828 			if (i > 0)
    829 				strlcat(sc->sc_temp_sensor.desc, "/",
    830 				    sizeof(sc->sc_temp_sensor.desc));
    831 			strlcat(sc->sc_temp_sensor.desc,
    832 			    device_xname(sc->sc_psl[i]->ci_dev),
    833 			    sizeof(sc->sc_temp_sensor.desc));
    834 		}
    835 		strlcat(sc->sc_temp_sensor.desc, " ",
    836 		    sizeof(sc->sc_temp_sensor.desc));
    837 	}
    838 	strlcat(sc->sc_temp_sensor.desc, "temperature",
    839 	    sizeof(sc->sc_temp_sensor.desc));
    840 
    841 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_sensor))
    842 		goto out;
    843 
    844 	if (sc->sc_have_fan != false) {
    845 
    846 		sc->sc_fan_sensor.flags = flags;
    847 		sc->sc_fan_sensor.units = ENVSYS_SFANRPM;
    848 		sc->sc_fan_sensor.state = ENVSYS_SINVALID;
    849 
    850 		(void)strlcpy(sc->sc_fan_sensor.desc,
    851 		    "FAN", sizeof(sc->sc_fan_sensor.desc));
    852 
    853 		/* Ignore error because fan sensor is optional. */
    854 		(void)sysmon_envsys_sensor_attach(sc->sc_sme,
    855 		    &sc->sc_fan_sensor);
    856 	}
    857 
    858 	if (sysmon_envsys_register(sc->sc_sme) == 0)
    859 		return;
    860 
    861 out:
    862 	aprint_error_dev(dv, "unable to register with sysmon\n");
    863 
    864 	sysmon_envsys_destroy(sc->sc_sme);
    865 	sc->sc_sme = NULL;
    866 }
    867 
    868 static void
    869 acpitz_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
    870 		  sysmon_envsys_lim_t *limits, uint32_t *props)
    871 {
    872 	struct acpitz_softc *sc = sme->sme_cookie;
    873 
    874 	switch (edata->units) {
    875 	case ENVSYS_STEMP:
    876 		*props = 0;
    877 		if (sc->sc_zone.hot != ATZ_TMP_INVALID) {
    878 			*props |= PROP_CRITMAX;
    879 			limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.hot);
    880 		} else if (sc->sc_zone.crt != ATZ_TMP_INVALID) {
    881 			*props |= PROP_CRITMAX;
    882 			limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.crt);
    883 		}
    884 		break;
    885 
    886 	case ENVSYS_SFANRPM:
    887 		*props = 0;
    888 		if (sc->sc_zone.fanmin != ATZ_TMP_INVALID) {
    889 			*props |= PROP_WARNMIN;
    890 			limits->sel_warnmin = sc->sc_zone.fanmin;
    891 		}
    892 		if (sc->sc_zone.fanmax != ATZ_TMP_INVALID) {
    893 			*props |= PROP_WARNMAX;
    894 			limits->sel_warnmax = sc->sc_zone.fanmax;
    895 		}
    896 		break;
    897 	}
    898 }
    899 
    900 MODULE(MODULE_CLASS_DRIVER, acpitz, NULL);
    901 
    902 #ifdef _MODULE
    903 #include "ioconf.c"
    904 #endif
    905 
    906 static int
    907 acpitz_modcmd(modcmd_t cmd, void *aux)
    908 {
    909 	int rv = 0;
    910 
    911 	switch (cmd) {
    912 
    913 	case MODULE_CMD_INIT:
    914 
    915 #ifdef _MODULE
    916 		rv = config_init_component(cfdriver_ioconf_acpitz,
    917 		    cfattach_ioconf_acpitz, cfdata_ioconf_acpitz);
    918 #endif
    919 		break;
    920 
    921 	case MODULE_CMD_FINI:
    922 
    923 #ifdef _MODULE
    924 		rv = config_fini_component(cfdriver_ioconf_acpitz,
    925 		    cfattach_ioconf_acpitz, cfdata_ioconf_acpitz);
    926 #endif
    927 		break;
    928 
    929 	default:
    930 		rv = ENOTTY;
    931 	}
    932 
    933 	return rv;
    934 }
    935