167761Smsmith/*-
278915Smsmith * Copyright (c) 2000, 2001 Michael Smith
367761Smsmith * Copyright (c) 2000 BSDi
467761Smsmith * All rights reserved.
567761Smsmith *
667761Smsmith * Redistribution and use in source and binary forms, with or without
767761Smsmith * modification, are permitted provided that the following conditions
867761Smsmith * are met:
967761Smsmith * 1. Redistributions of source code must retain the above copyright
1067761Smsmith *    notice, this list of conditions and the following disclaimer.
1167761Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1267761Smsmith *    notice, this list of conditions and the following disclaimer in the
1367761Smsmith *    documentation and/or other materials provided with the distribution.
1467761Smsmith *
1567761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1667761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1767761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1867761Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1967761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2067761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2167761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2267761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2367761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2467761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2567761Smsmith * SUCH DAMAGE.
2667761Smsmith */
2767761Smsmith
28119418Sobrien#include <sys/cdefs.h>
29119418Sobrien__FBSDID("$FreeBSD$");
30119418Sobrien
3167761Smsmith#include "opt_acpi.h"
3267761Smsmith#include <sys/param.h>
3367761Smsmith#include <sys/kernel.h>
34133624Snjl#include <sys/bus.h>
35148138Sume#include <sys/cpu.h>
3691126Smsmith#include <sys/kthread.h>
37133624Snjl#include <sys/malloc.h>
38129879Sphk#include <sys/module.h>
3991126Smsmith#include <sys/proc.h>
40128991Snjl#include <sys/reboot.h>
4179283Smsmith#include <sys/sysctl.h>
4291126Smsmith#include <sys/unistd.h>
4391640Siwasaki#include <sys/power.h>
4467761Smsmith
45148138Sume#include "cpufreq_if.h"
46148138Sume
47193530Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193530Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193530Sjkim
5067761Smsmith#include <dev/acpica/acpivar.h>
5167761Smsmith
52119529Snjl/* Hooks for the ACPI CA debugging infrastructure */
5378999Smsmith#define _COMPONENT	ACPI_THERMAL
5491126SmsmithACPI_MODULE_NAME("THERMAL")
5569744Smsmith
56300421Sloos#define TZ_ZEROC	2731
57160657Snjl#define TZ_KELVTOC(x)	(((x) - TZ_ZEROC) / 10), abs(((x) - TZ_ZEROC) % 10)
5867761Smsmith
59125366Snjl#define TZ_NOTIFY_TEMPERATURE	0x80 /* Temperature changed. */
60125366Snjl#define TZ_NOTIFY_LEVELS	0x81 /* Cooling levels changed. */
61125366Snjl#define TZ_NOTIFY_DEVICES	0x82 /* Device lists changed. */
62125366Snjl#define TZ_NOTIFY_CRITICAL	0xcc /* Fake notify that _CRT/_HOT reached. */
6378915Smsmith
64125335Snjl/* Check for temperature changes every 10 seconds by default */
65125335Snjl#define TZ_POLLRATE	10
6678915Smsmith
67125335Snjl/* Make sure the reported temperature is valid for this number of polls. */
68125335Snjl#define TZ_VALIDCHECKS	3
69125335Snjl
70125366Snjl/* Notify the user we will be shutting down in one more poll cycle. */
71125366Snjl#define TZ_NOTIFYCOUNT	(TZ_VALIDCHECKS - 1)
72125366Snjl
73119529Snjl/* ACPI spec defines this */
74119529Snjl#define TZ_NUMLEVELS	10
7579375Smsmithstruct acpi_tz_zone {
7678915Smsmith    int		ac[TZ_NUMLEVELS];
7778915Smsmith    ACPI_BUFFER	al[TZ_NUMLEVELS];
7878915Smsmith    int		crt;
7978915Smsmith    int		hot;
8078915Smsmith    ACPI_BUFFER	psl;
8178915Smsmith    int		psv;
8278915Smsmith    int		tc1;
8378915Smsmith    int		tc2;
8478915Smsmith    int		tsp;
8578915Smsmith    int		tzp;
8678915Smsmith};
8778915Smsmith
8867761Smsmithstruct acpi_tz_softc {
89119529Snjl    device_t			tz_dev;
90119529Snjl    ACPI_HANDLE			tz_handle;	/*Thermal zone handle*/
91119529Snjl    int				tz_temperature;	/*Current temperature*/
92119529Snjl    int				tz_active;	/*Current active cooling*/
9379375Smsmith#define TZ_ACTIVE_NONE		-1
94178506Srpaulo#define TZ_ACTIVE_UNKNOWN	-2
95119529Snjl    int				tz_requested;	/*Minimum active cooling*/
96119529Snjl    int				tz_thflags;	/*Current temp-related flags*/
9779375Smsmith#define TZ_THFLAG_NONE		0
9879375Smsmith#define TZ_THFLAG_PSV		(1<<0)
9979375Smsmith#define TZ_THFLAG_HOT		(1<<2)
100148138Sume#define TZ_THFLAG_CRT		(1<<3)
10179283Smsmith    int				tz_flags;
102119529Snjl#define TZ_FLAG_NO_SCP		(1<<0)		/*No _SCP method*/
103119529Snjl#define TZ_FLAG_GETPROFILE	(1<<1)		/*Get power_profile in timeout*/
104133624Snjl#define TZ_FLAG_GETSETTINGS	(1<<2)		/*Get devs/setpoints*/
105119529Snjl    struct timespec		tz_cooling_started;
106119529Snjl					/*Current cooling starting time*/
10779283Smsmith
108119529Snjl    struct sysctl_ctx_list	tz_sysctl_ctx;
10979283Smsmith    struct sysctl_oid		*tz_sysctl_tree;
110133624Snjl    eventhandler_tag		tz_event;
111133624Snjl
112119529Snjl    struct acpi_tz_zone 	tz_zone;	/*Thermal zone parameters*/
113125335Snjl    int				tz_validchecks;
114255077Sdumbbell    int				tz_insane_tmp_notified;
115148138Sume
116148138Sume    /* passive cooling */
117148138Sume    struct proc			*tz_cooling_proc;
118148703Sume    int				tz_cooling_proc_running;
119148138Sume    int				tz_cooling_enabled;
120148138Sume    int				tz_cooling_active;
121148138Sume    int				tz_cooling_updated;
122149201Sume    int				tz_cooling_saved_freq;
12367761Smsmith};
12467761Smsmith
125241538Savg#define	TZ_ACTIVE_LEVEL(act)	((act) >= 0 ? (act) : TZ_NUMLEVELS)
126241538Savg
127148138Sume#define CPUFREQ_MAX_LEVELS	64 /* XXX cpufreq should export this */
128148138Sume
12967761Smsmithstatic int	acpi_tz_probe(device_t dev);
13067761Smsmithstatic int	acpi_tz_attach(device_t dev);
13178915Smsmithstatic int	acpi_tz_establish(struct acpi_tz_softc *sc);
132119529Snjlstatic void	acpi_tz_monitor(void *Context);
13378915Smsmithstatic void	acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg);
13478915Smsmithstatic void	acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg);
135119529Snjlstatic void	acpi_tz_getparam(struct acpi_tz_softc *sc, char *node,
136119529Snjl				 int *data);
13779283Smsmithstatic void	acpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what);
13879375Smsmithstatic int	acpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS);
139148138Sumestatic int	acpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS);
140160657Snjlstatic int	acpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS);
141174889Sumestatic int	acpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS);
142119529Snjlstatic void	acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify,
143119529Snjl				       void *context);
144133624Snjlstatic void	acpi_tz_signal(struct acpi_tz_softc *sc, int flags);
145133624Snjlstatic void	acpi_tz_timeout(struct acpi_tz_softc *sc, int flags);
14691640Siwasakistatic void	acpi_tz_power_profile(void *arg);
14791126Smsmithstatic void	acpi_tz_thread(void *arg);
148148138Sumestatic int	acpi_tz_cooling_is_available(struct acpi_tz_softc *sc);
149148138Sumestatic int	acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc);
15091126Smsmith
15167761Smsmithstatic device_method_t acpi_tz_methods[] = {
15267761Smsmith    /* Device interface */
15367761Smsmith    DEVMETHOD(device_probe,	acpi_tz_probe),
15467761Smsmith    DEVMETHOD(device_attach,	acpi_tz_attach),
15567761Smsmith
156246128Ssbz    DEVMETHOD_END
15767761Smsmith};
15867761Smsmith
15967761Smsmithstatic driver_t acpi_tz_driver = {
16067761Smsmith    "acpi_tz",
16167761Smsmith    acpi_tz_methods,
16267761Smsmith    sizeof(struct acpi_tz_softc),
16367761Smsmith};
16467761Smsmith
165255077Sdumbbellstatic char *acpi_tz_tmp_name = "_TMP";
166255077Sdumbbell
16789054Smsmithstatic devclass_t acpi_tz_devclass;
16867761SmsmithDRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0);
169128071SnjlMODULE_DEPEND(acpi_tz, acpi, 1, 1, 1);
17067761Smsmith
17179283Smsmithstatic struct sysctl_ctx_list	acpi_tz_sysctl_ctx;
17279283Smsmithstatic struct sysctl_oid	*acpi_tz_sysctl_tree;
17379283Smsmith
174119529Snjl/* Minimum cooling run time */
175160657Snjlstatic int			acpi_tz_min_runtime;
17688420Siwasakistatic int			acpi_tz_polling_rate = TZ_POLLRATE;
177160657Snjlstatic int			acpi_tz_override;
17885699Siwasaki
179119529Snjl/* Timezone polling thread */
180119529Snjlstatic struct proc		*acpi_tz_proc;
181133624SnjlACPI_LOCK_DECL(thermal, "ACPI thermal zone");
182119529Snjl
183176329Sumestatic int			acpi_tz_cooling_unit = -1;
184176329Sume
18567761Smsmithstatic int
18667761Smsmithacpi_tz_probe(device_t dev)
18767761Smsmith{
18878999Smsmith    int		result;
189148138Sume
190119529Snjl    if (acpi_get_type(dev) == ACPI_TYPE_THERMAL && !acpi_disabled("thermal")) {
191120453Snjl	device_set_desc(dev, "Thermal Zone");
19278999Smsmith	result = -10;
193133624Snjl    } else
19478999Smsmith	result = ENXIO;
195119529Snjl    return (result);
19667761Smsmith}
19767761Smsmith
19867761Smsmithstatic int
19967761Smsmithacpi_tz_attach(device_t dev)
20067761Smsmith{
20167761Smsmith    struct acpi_tz_softc	*sc;
20279283Smsmith    struct acpi_softc		*acpi_sc;
20378915Smsmith    int				error;
20479283Smsmith    char			oidname[8];
20567761Smsmith
20696926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
20769744Smsmith
20867761Smsmith    sc = device_get_softc(dev);
20967761Smsmith    sc->tz_dev = dev;
21067761Smsmith    sc->tz_handle = acpi_get_handle(dev);
21179375Smsmith    sc->tz_requested = TZ_ACTIVE_NONE;
212178506Srpaulo    sc->tz_active = TZ_ACTIVE_UNKNOWN;
213135548Snjl    sc->tz_thflags = TZ_THFLAG_NONE;
214148138Sume    sc->tz_cooling_proc = NULL;
215148703Sume    sc->tz_cooling_proc_running = FALSE;
216148138Sume    sc->tz_cooling_active = FALSE;
217148138Sume    sc->tz_cooling_updated = FALSE;
218176329Sume    sc->tz_cooling_enabled = FALSE;
21967761Smsmith
22078915Smsmith    /*
22178915Smsmith     * Parse the current state of the thermal zone and build control
222133624Snjl     * structures.  We don't need to worry about interference with the
223133624Snjl     * control thread since we haven't fully attached this device yet.
22478915Smsmith     */
22578915Smsmith    if ((error = acpi_tz_establish(sc)) != 0)
226133624Snjl	return (error);
227133624Snjl
22878915Smsmith    /*
22978915Smsmith     * Register for any Notify events sent to this zone.
23078915Smsmith     */
231148138Sume    AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY,
23278999Smsmith			     acpi_tz_notify_handler, sc);
23370271Stakawata
23471874Smsmith    /*
23579283Smsmith     * Create our sysctl nodes.
23679283Smsmith     *
23779283Smsmith     * XXX we need a mechanism for adding nodes under ACPI.
23879283Smsmith     */
23979283Smsmith    if (device_get_unit(dev) == 0) {
24079283Smsmith	acpi_sc = acpi_device_get_parent_softc(dev);
24179283Smsmith	sysctl_ctx_init(&acpi_tz_sysctl_ctx);
24279283Smsmith	acpi_tz_sysctl_tree = SYSCTL_ADD_NODE(&acpi_tz_sysctl_ctx,
243119529Snjl			      SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
244119529Snjl			      OID_AUTO, "thermal", CTLFLAG_RD, 0, "");
24585699Siwasaki	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
24685699Siwasaki		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
247159476Snjl		       OID_AUTO, "min_runtime", CTLFLAG_RW,
248119529Snjl		       &acpi_tz_min_runtime, 0,
249119529Snjl		       "minimum cooling run time in sec");
25088420Siwasaki	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
25188420Siwasaki		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
252159476Snjl		       OID_AUTO, "polling_rate", CTLFLAG_RW,
253227642Seadler		       &acpi_tz_polling_rate, 0, "monitor polling interval in seconds");
254160657Snjl	SYSCTL_ADD_INT(&acpi_tz_sysctl_ctx,
255160657Snjl		       SYSCTL_CHILDREN(acpi_tz_sysctl_tree), OID_AUTO,
256160657Snjl		       "user_override", CTLFLAG_RW, &acpi_tz_override, 0,
257160657Snjl		       "allow override of thermal settings");
25879283Smsmith    }
25979283Smsmith    sysctl_ctx_init(&sc->tz_sysctl_ctx);
26079283Smsmith    sprintf(oidname, "tz%d", device_get_unit(dev));
26179283Smsmith    sc->tz_sysctl_tree = SYSCTL_ADD_NODE(&sc->tz_sysctl_ctx,
262119529Snjl					 SYSCTL_CHILDREN(acpi_tz_sysctl_tree),
263119529Snjl					 OID_AUTO, oidname, CTLFLAG_RD, 0, "");
26479375Smsmith    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
265220798Smdf		    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
266220798Smdf		    &sc->tz_temperature, 0, sysctl_handle_int,
267220798Smdf		    "IK", "current thermal zone temperature");
268220798Smdf    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
26979375Smsmith		    OID_AUTO, "active", CTLTYPE_INT | CTLFLAG_RW,
270160657Snjl		    sc, 0, acpi_tz_active_sysctl, "I", "cooling is active");
271148138Sume    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
272148138Sume		    OID_AUTO, "passive_cooling", CTLTYPE_INT | CTLFLAG_RW,
273160657Snjl		    sc, 0, acpi_tz_cooling_sysctl, "I",
274160657Snjl		    "enable passive (speed reduction) cooling");
275148138Sume
27679283Smsmith    SYSCTL_ADD_INT(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
27779375Smsmith		   OID_AUTO, "thermal_flags", CTLFLAG_RD,
27879375Smsmith		   &sc->tz_thflags, 0, "thermal zone flags");
279160657Snjl    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
280160657Snjl		    OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW,
281160657Snjl		    sc, offsetof(struct acpi_tz_softc, tz_zone.psv),
282160657Snjl		    acpi_tz_temp_sysctl, "IK", "passive cooling temp setpoint");
283160657Snjl    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
284160657Snjl		    OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW,
285160657Snjl		    sc, offsetof(struct acpi_tz_softc, tz_zone.hot),
286160657Snjl		    acpi_tz_temp_sysctl, "IK",
287160657Snjl		    "too hot temp setpoint (suspend now)");
288160657Snjl    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
289160657Snjl		    OID_AUTO, "_CRT", CTLTYPE_INT | CTLFLAG_RW,
290160657Snjl		    sc, offsetof(struct acpi_tz_softc, tz_zone.crt),
291160657Snjl		    acpi_tz_temp_sysctl, "IK",
292160657Snjl		    "critical temp setpoint (shutdown now)");
293174889Sume    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
294220798Smdf		    OID_AUTO, "_ACx", CTLTYPE_INT | CTLFLAG_RD,
295220871Smdf		    &sc->tz_zone.ac, sizeof(sc->tz_zone.ac),
296220871Smdf		    sysctl_handle_opaque, "IK", "");
297220798Smdf    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
298174889Sume		    OID_AUTO, "_TC1", CTLTYPE_INT | CTLFLAG_RW,
299174889Sume		    sc, offsetof(struct acpi_tz_softc, tz_zone.tc1),
300174889Sume		    acpi_tz_passive_sysctl, "I",
301174889Sume		    "thermal constant 1 for passive cooling");
302174889Sume    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
303174889Sume		    OID_AUTO, "_TC2", CTLTYPE_INT | CTLFLAG_RW,
304174889Sume		    sc, offsetof(struct acpi_tz_softc, tz_zone.tc2),
305174889Sume		    acpi_tz_passive_sysctl, "I",
306174889Sume		    "thermal constant 2 for passive cooling");
307174889Sume    SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree),
308174889Sume		    OID_AUTO, "_TSP", CTLTYPE_INT | CTLFLAG_RW,
309174889Sume		    sc, offsetof(struct acpi_tz_softc, tz_zone.tsp),
310174889Sume		    acpi_tz_passive_sysctl, "I",
311174889Sume		    "thermal sampling period for passive cooling");
31279283Smsmith
31379283Smsmith    /*
314301518Sjhb     * Register our power profile event handler.
31579375Smsmith     */
316133624Snjl    sc->tz_event = EVENTHANDLER_REGISTER(power_profile_change,
317133624Snjl	acpi_tz_power_profile, sc, 0);
31879375Smsmith
319176329Sume    /*
320301518Sjhb     * Flag the event handler for a manual invocation by our timeout.
321301518Sjhb     * We defer it like this so that the rest of the subsystem has time
322301518Sjhb     * to come up.  Don't bother evaluating/printing the temperature at
323301518Sjhb     * this point; on many systems it'll be bogus until the EC is running.
324301518Sjhb     */
325301518Sjhb    sc->tz_flags |= TZ_FLAG_GETPROFILE;
326301518Sjhb
327301518Sjhb    return_VALUE (0);
328301518Sjhb}
329301518Sjhb
330301518Sjhbstatic void
331301518Sjhbacpi_tz_startup(void *arg __unused)
332301518Sjhb{
333301518Sjhb    struct acpi_tz_softc *sc;
334301518Sjhb    device_t *devs;
335301518Sjhb    int devcount, error, i;
336301518Sjhb
337301518Sjhb    devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
338301562Scem    if (devcount == 0) {
339301562Scem	free(devs, M_TEMP);
340301518Sjhb	return;
341301562Scem    }
342301518Sjhb
343301518Sjhb    /*
344301518Sjhb     * Create thread to service all of the thermal zones.
345301518Sjhb     */
346301518Sjhb    error = kproc_create(acpi_tz_thread, NULL, &acpi_tz_proc, RFHIGHPID, 0,
347301518Sjhb	"acpi_thermal");
348301518Sjhb    if (error != 0)
349301518Sjhb	printf("acpi_tz: could not create thread - %d", error);
350301518Sjhb
351301518Sjhb    /*
352176329Sume     * Create a thread to handle passive cooling for 1st zone which
353176329Sume     * has _PSV, _TSP, _TC1 and _TC2.  Users can enable it for other
354176329Sume     * zones manually for now.
355176329Sume     *
356176329Sume     * XXX We enable only one zone to avoid multiple zones conflict
357176329Sume     * with each other since cpufreq currently sets all CPUs to the
358176329Sume     * given frequency whereas it's possible for different thermal
359176329Sume     * zones to specify independent settings for multiple CPUs.
360176329Sume     */
361301518Sjhb    for (i = 0; i < devcount; i++) {
362301518Sjhb	sc = device_get_softc(devs[i]);
363301518Sjhb	if (acpi_tz_cooling_is_available(sc)) {
364301518Sjhb	    sc->tz_cooling_enabled = TRUE;
365301518Sjhb	    error = acpi_tz_cooling_thread_start(sc);
366301518Sjhb	    if (error != 0) {
367301518Sjhb		sc->tz_cooling_enabled = FALSE;
368301518Sjhb		break;
369301518Sjhb	    }
370301518Sjhb	    acpi_tz_cooling_unit = device_get_unit(devs[i]);
371301518Sjhb	    break;
372176329Sume	}
373148138Sume    }
374301518Sjhb    free(devs, M_TEMP);
37567761Smsmith}
376301518SjhbSYSINIT(acpi_tz, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, acpi_tz_startup, NULL);
37770271Stakawata
37878915Smsmith/*
37978915Smsmith * Parse the current state of this thermal zone and set up to use it.
38078915Smsmith *
38178915Smsmith * Note that we may have previous state, which will have to be discarded.
38278915Smsmith */
38378915Smsmithstatic int
38478915Smsmithacpi_tz_establish(struct acpi_tz_softc *sc)
38578915Smsmith{
38678915Smsmith    ACPI_OBJECT	*obj;
38778915Smsmith    int		i;
38878915Smsmith    char	nbuf[8];
389148138Sume
39096926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
39178915Smsmith
392134909Snjl    /* Erase any existing state. */
39378915Smsmith    for (i = 0; i < TZ_NUMLEVELS; i++)
39479375Smsmith	if (sc->tz_zone.al[i].Pointer != NULL)
39579375Smsmith	    AcpiOsFree(sc->tz_zone.al[i].Pointer);
39679375Smsmith    if (sc->tz_zone.psl.Pointer != NULL)
39779375Smsmith	AcpiOsFree(sc->tz_zone.psl.Pointer);
39878915Smsmith
399149449Sume    /*
400149449Sume     * XXX: We initialize only ACPI_BUFFER to avoid race condition
401149449Sume     * with passive cooling thread which refers psv, tc1, tc2 and tsp.
402149449Sume     */
403149449Sume    bzero(sc->tz_zone.ac, sizeof(sc->tz_zone.ac));
404149449Sume    bzero(sc->tz_zone.al, sizeof(sc->tz_zone.al));
405149449Sume    bzero(&sc->tz_zone.psl, sizeof(sc->tz_zone.psl));
406149449Sume
407119529Snjl    /* Evaluate thermal zone parameters. */
40878915Smsmith    for (i = 0; i < TZ_NUMLEVELS; i++) {
40978915Smsmith	sprintf(nbuf, "_AC%d", i);
41079375Smsmith	acpi_tz_getparam(sc, nbuf, &sc->tz_zone.ac[i]);
41178915Smsmith	sprintf(nbuf, "_AL%d", i);
41291126Smsmith	sc->tz_zone.al[i].Length = ACPI_ALLOCATE_BUFFER;
41391126Smsmith	sc->tz_zone.al[i].Pointer = NULL;
41491126Smsmith	AcpiEvaluateObject(sc->tz_handle, nbuf, NULL, &sc->tz_zone.al[i]);
41579375Smsmith	obj = (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer;
41678915Smsmith	if (obj != NULL) {
417119529Snjl	    /* Should be a package containing a list of power objects */
41878915Smsmith	    if (obj->Type != ACPI_TYPE_PACKAGE) {
419119529Snjl		device_printf(sc->tz_dev, "%s has unknown type %d, rejecting\n",
42078915Smsmith			      nbuf, obj->Type);
421119529Snjl		return_VALUE (ENXIO);
42278915Smsmith	    }
42378915Smsmith	}
42478915Smsmith    }
42579375Smsmith    acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt);
42679375Smsmith    acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot);
42791126Smsmith    sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER;
42891126Smsmith    sc->tz_zone.psl.Pointer = NULL;
42991126Smsmith    AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl);
43079375Smsmith    acpi_tz_getparam(sc, "_PSV", &sc->tz_zone.psv);
43179375Smsmith    acpi_tz_getparam(sc, "_TC1", &sc->tz_zone.tc1);
43279375Smsmith    acpi_tz_getparam(sc, "_TC2", &sc->tz_zone.tc2);
43379375Smsmith    acpi_tz_getparam(sc, "_TSP", &sc->tz_zone.tsp);
43479375Smsmith    acpi_tz_getparam(sc, "_TZP", &sc->tz_zone.tzp);
43578915Smsmith
43678915Smsmith    /*
43779283Smsmith     * Sanity-check the values we've been given.
43879283Smsmith     *
43979283Smsmith     * XXX what do we do about systems that give us the same value for
44079283Smsmith     *     more than one of these setpoints?
44179283Smsmith     */
44279375Smsmith    acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT");
44379375Smsmith    acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT");
44479375Smsmith    acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV");
44579283Smsmith    for (i = 0; i < TZ_NUMLEVELS; i++)
44679375Smsmith	acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx");
44779283Smsmith
448119529Snjl    return_VALUE (0);
44978915Smsmith}
45078915Smsmith
451133624Snjlstatic char *aclevel_string[] = {
452133624Snjl    "NONE", "_AC0", "_AC1", "_AC2", "_AC3", "_AC4",
453133624Snjl    "_AC5", "_AC6", "_AC7", "_AC8", "_AC9"
454133624Snjl};
45585699Siwasaki
45685699Siwasakistatic __inline const char *
45785699Siwasakiacpi_tz_aclevel_string(int active)
45885699Siwasaki{
459133624Snjl    if (active < -1 || active >= TZ_NUMLEVELS)
460133624Snjl	return (aclevel_string[0]);
46185699Siwasaki
462133624Snjl    return (aclevel_string[active + 1]);
46385699Siwasaki}
46485699Siwasaki
46578915Smsmith/*
466149450Sume * Get the current temperature.
467149450Sume */
468149450Sumestatic int
469149450Sumeacpi_tz_get_temperature(struct acpi_tz_softc *sc)
470149450Sume{
471149450Sume    int		temp;
472149450Sume    ACPI_STATUS	status;
473149450Sume
474149482Skan    ACPI_FUNCTION_NAME ("acpi_tz_get_temperature");
475149482Skan
476167249Snjl    /* Evaluate the thermal zone's _TMP method. */
477255077Sdumbbell    status = acpi_GetInteger(sc->tz_handle, acpi_tz_tmp_name, &temp);
478149450Sume    if (ACPI_FAILURE(status)) {
479149450Sume	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
480149450Sume	    "error fetching current temperature -- %s\n",
481149450Sume	     AcpiFormatException(status));
482149450Sume	return (FALSE);
483149450Sume    }
484149450Sume
485167249Snjl    /* Check it for validity. */
486255077Sdumbbell    acpi_tz_sanity(sc, &temp, acpi_tz_tmp_name);
487167249Snjl    if (temp == -1)
488167249Snjl	return (FALSE);
489167249Snjl
490149450Sume    ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "got %d.%dC\n", TZ_KELVTOC(temp)));
491149450Sume    sc->tz_temperature = temp;
492149450Sume    return (TRUE);
493149450Sume}
494149450Sume
495149450Sume/*
49678915Smsmith * Evaluate the condition of a thermal zone, take appropriate actions.
49778915Smsmith */
49871874Smsmithstatic void
499119529Snjlacpi_tz_monitor(void *Context)
50071874Smsmith{
501119529Snjl    struct acpi_tz_softc *sc;
502119529Snjl    struct	timespec curtime;
50379283Smsmith    int		temp;
50478915Smsmith    int		i;
50579283Smsmith    int		newactive, newflags;
50670271Stakawata
50796926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
50870271Stakawata
509119529Snjl    sc = (struct acpi_tz_softc *)Context;
51088420Siwasaki
511119529Snjl    /* Get the current temperature. */
512149450Sume    if (!acpi_tz_get_temperature(sc)) {
51378915Smsmith	/* XXX disable zone? go to max cooling? */
514133624Snjl	return_VOID;
51571874Smsmith    }
516149450Sume    temp = sc->tz_temperature;
51788420Siwasaki
51878915Smsmith    /*
51978915Smsmith     * Work out what we ought to be doing right now.
52079283Smsmith     *
52179283Smsmith     * Note that the _ACx levels sort from hot to cold.
52278915Smsmith     */
52379283Smsmith    newactive = TZ_ACTIVE_NONE;
52479375Smsmith    for (i = TZ_NUMLEVELS - 1; i >= 0; i--) {
525245266Smav	if (sc->tz_zone.ac[i] != -1 && temp >= sc->tz_zone.ac[i])
52679283Smsmith	    newactive = i;
52779375Smsmith    }
52879283Smsmith
52985699Siwasaki    /*
53085699Siwasaki     * We are going to get _ACx level down (colder side), but give a guaranteed
53185699Siwasaki     * minimum cooling run time if requested.
53285699Siwasaki     */
53385699Siwasaki    if (acpi_tz_min_runtime > 0 && sc->tz_active != TZ_ACTIVE_NONE &&
534178506Srpaulo	sc->tz_active != TZ_ACTIVE_UNKNOWN &&
53585699Siwasaki	(newactive == TZ_ACTIVE_NONE || newactive > sc->tz_active)) {
536119529Snjl
53785699Siwasaki	getnanotime(&curtime);
53885699Siwasaki	timespecsub(&curtime, &sc->tz_cooling_started);
539119529Snjl	if (curtime.tv_sec < acpi_tz_min_runtime)
54085699Siwasaki	    newactive = sc->tz_active;
54185699Siwasaki    }
54285699Siwasaki
543119529Snjl    /* Handle user override of active mode */
544176327Srpaulo    if (sc->tz_requested != TZ_ACTIVE_NONE && (newactive == TZ_ACTIVE_NONE
545176327Srpaulo        || sc->tz_requested < newactive))
54679375Smsmith	newactive = sc->tz_requested;
54778915Smsmith
54879375Smsmith    /* update temperature-related flags */
54979375Smsmith    newflags = TZ_THFLAG_NONE;
550124439Snjl    if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv)
55179375Smsmith	newflags |= TZ_THFLAG_PSV;
552124439Snjl    if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot)
55379375Smsmith	newflags |= TZ_THFLAG_HOT;
554124439Snjl    if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt)
55579375Smsmith	newflags |= TZ_THFLAG_CRT;
55679375Smsmith
557119529Snjl    /* If the active cooling state has changed, we have to switch things. */
558178506Srpaulo    if (sc->tz_active == TZ_ACTIVE_UNKNOWN) {
559178506Srpaulo	/*
560178506Srpaulo	 * We don't know which cooling device is on or off,
561178506Srpaulo	 * so stop them all, because we now know which
562178506Srpaulo	 * should be on (if any).
563178506Srpaulo	 */
564178506Srpaulo	for (i = 0; i < TZ_NUMLEVELS; i++) {
565178506Srpaulo	    if (sc->tz_zone.al[i].Pointer != NULL) {
566178506Srpaulo		acpi_ForeachPackageObject(
567178506Srpaulo		    (ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
568178506Srpaulo		    acpi_tz_switch_cooler_off, sc);
569178506Srpaulo	    }
570178506Srpaulo	}
571178506Srpaulo	/* now we know that all devices are off */
572178506Srpaulo	sc->tz_active = TZ_ACTIVE_NONE;
573178506Srpaulo    }
574178506Srpaulo
57579283Smsmith    if (newactive != sc->tz_active) {
576241538Savg	/* Turn off unneeded cooling devices that are on, if any are */
577241538Savg	for (i = TZ_ACTIVE_LEVEL(sc->tz_active);
578241538Savg	     i < TZ_ACTIVE_LEVEL(newactive); i++) {
579119529Snjl	    acpi_ForeachPackageObject(
580241538Savg		(ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
581119529Snjl		acpi_tz_switch_cooler_off, sc);
582241538Savg	}
583119529Snjl	/* Turn on cooling devices that are required, if any are */
584241538Savg	for (i = TZ_ACTIVE_LEVEL(sc->tz_active) - 1;
585241538Savg	     i >= TZ_ACTIVE_LEVEL(newactive); i--) {
586119529Snjl	    acpi_ForeachPackageObject(
587241538Savg		(ACPI_OBJECT *)sc->tz_zone.al[i].Pointer,
588119529Snjl		acpi_tz_switch_cooler_on, sc);
589119529Snjl	}
590241538Savg
59186552Siwasaki	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
592119529Snjl		    "switched from %s to %s: %d.%dC\n",
593119529Snjl		    acpi_tz_aclevel_string(sc->tz_active),
594119529Snjl		    acpi_tz_aclevel_string(newactive), TZ_KELVTOC(temp));
59579283Smsmith	sc->tz_active = newactive;
596142195Snjl	getnanotime(&sc->tz_cooling_started);
59779283Smsmith    }
59878915Smsmith
599119529Snjl    /* XXX (de)activate any passive cooling that may be required. */
60078915Smsmith
60178915Smsmith    /*
602125335Snjl     * If the temperature is at _HOT or _CRT, increment our event count.
603125335Snjl     * If it has occurred enough times, shutdown the system.  This is
604125335Snjl     * needed because some systems will report an invalid high temperature
605125335Snjl     * for one poll cycle.  It is suspected this is due to the embedded
606125335Snjl     * controller timing out.  A typical value is 138C for one cycle on
607125335Snjl     * a system that is otherwise 65C.
608125366Snjl     *
609125366Snjl     * If we're almost at that threshold, notify the user through devd(8).
61078915Smsmith     */
611125335Snjl    if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) {
612125366Snjl	sc->tz_validchecks++;
613125366Snjl	if (sc->tz_validchecks == TZ_VALIDCHECKS) {
614125335Snjl	    device_printf(sc->tz_dev,
615125335Snjl		"WARNING - current temperature (%d.%dC) exceeds safe limits\n",
616125335Snjl		TZ_KELVTOC(sc->tz_temperature));
617125335Snjl	    shutdown_nice(RB_POWEROFF);
618125366Snjl	} else if (sc->tz_validchecks == TZ_NOTIFYCOUNT)
619125366Snjl	    acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL);
620125335Snjl    } else {
621125335Snjl	sc->tz_validchecks = 0;
62278915Smsmith    }
62379375Smsmith    sc->tz_thflags = newflags;
62478915Smsmith
62571874Smsmith    return_VOID;
62671874Smsmith}
62770271Stakawata
62878915Smsmith/*
629148138Sume * Given an object, verify that it's a reference to a device of some sort,
63078915Smsmith * and try to switch it off.
63178915Smsmith */
63278915Smsmithstatic void
63378915Smsmithacpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg)
63478915Smsmith{
635128047Snjl    ACPI_HANDLE			cooler;
63678915Smsmith
63796926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
63878915Smsmith
639128047Snjl    cooler = acpi_GetReference(NULL, obj);
640128047Snjl    if (cooler == NULL) {
641128047Snjl	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
642128047Snjl	return_VOID;
643128047Snjl    }
644102470Siwasaki
645128047Snjl    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s off\n",
646128047Snjl		     acpi_name(cooler)));
647128150Snjl    acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3);
648119529Snjl
64979375Smsmith    return_VOID;
65078915Smsmith}
65178915Smsmith
65278915Smsmith/*
653148138Sume * Given an object, verify that it's a reference to a device of some sort,
65478915Smsmith * and try to switch it on.
65578915Smsmith *
656128047Snjl * XXX replication of off/on function code is bad.
65778915Smsmith */
65878915Smsmithstatic void
65978915Smsmithacpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg)
66078915Smsmith{
66178915Smsmith    struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
66278999Smsmith    ACPI_HANDLE			cooler;
66379375Smsmith    ACPI_STATUS			status;
664148138Sume
66596926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
66678915Smsmith
667128047Snjl    cooler = acpi_GetReference(NULL, obj);
668128047Snjl    if (cooler == NULL) {
669128047Snjl	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get handle\n"));
670128047Snjl	return_VOID;
671128047Snjl    }
672102470Siwasaki
673128047Snjl    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "called to turn %s on\n",
674128047Snjl		     acpi_name(cooler)));
675128047Snjl    status = acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0);
676128047Snjl    if (ACPI_FAILURE(status)) {
677128047Snjl	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
678128047Snjl		    "failed to activate %s - %s\n", acpi_name(cooler),
679128047Snjl		    AcpiFormatException(status));
68078915Smsmith    }
681119529Snjl
682119529Snjl    return_VOID;
68378915Smsmith}
68478915Smsmith
68578915Smsmith/*
68678915Smsmith * Read/debug-print a parameter, default it to -1.
68778915Smsmith */
68878915Smsmithstatic void
68978915Smsmithacpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data)
69078915Smsmith{
69178915Smsmith
69296926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
69378915Smsmith
694126560Snjl    if (ACPI_FAILURE(acpi_GetInteger(sc->tz_handle, node, data))) {
69578915Smsmith	*data = -1;
69678915Smsmith    } else {
697119529Snjl	ACPI_DEBUG_PRINT((ACPI_DB_VALUES, "%s.%s = %d\n",
698119529Snjl			 acpi_name(sc->tz_handle), node, *data));
69978915Smsmith    }
700119529Snjl
701148138Sume    return_VOID;
70278915Smsmith}
70379283Smsmith
70479283Smsmith/*
70579283Smsmith * Sanity-check a temperature value.  Assume that setpoints
706167249Snjl * should be between 0C and 200C.
70779283Smsmith */
70879283Smsmithstatic void
70979283Smsmithacpi_tz_sanity(struct acpi_tz_softc *sc, int *val, char *what)
71079283Smsmith{
711167249Snjl    if (*val != -1 && (*val < TZ_ZEROC || *val > TZ_ZEROC + 2000)) {
712255077Sdumbbell	/*
713255077Sdumbbell	 * If the value we are checking is _TMP, warn the user only
714255077Sdumbbell	 * once. This avoids spamming messages if, for instance, the
715255077Sdumbbell	 * sensor is broken and always returns an invalid temperature.
716255077Sdumbbell	 *
717255077Sdumbbell	 * This is only done for _TMP; other values always emit a
718255077Sdumbbell	 * warning.
719255077Sdumbbell	 */
720255077Sdumbbell	if (what != acpi_tz_tmp_name || !sc->tz_insane_tmp_notified) {
721255077Sdumbbell	    device_printf(sc->tz_dev, "%s value is absurd, ignored (%d.%dC)\n",
722255077Sdumbbell			  what, TZ_KELVTOC(*val));
723255077Sdumbbell
724255077Sdumbbell	    /* Don't warn the user again if the read value doesn't improve. */
725255077Sdumbbell	    if (what == acpi_tz_tmp_name)
726255077Sdumbbell		sc->tz_insane_tmp_notified = 1;
727255077Sdumbbell	}
72879283Smsmith	*val = -1;
729255077Sdumbbell	return;
73079283Smsmith    }
731255077Sdumbbell
732255077Sdumbbell    /* This value is correct. Warn if it's incorrect again. */
733255077Sdumbbell    if (what == acpi_tz_tmp_name)
734255077Sdumbbell	sc->tz_insane_tmp_notified = 0;
73579283Smsmith}
73679375Smsmith
73779375Smsmith/*
73879375Smsmith * Respond to a sysctl on the active state node.
739148138Sume */
74079375Smsmithstatic int
74179375Smsmithacpi_tz_active_sysctl(SYSCTL_HANDLER_ARGS)
74279375Smsmith{
74379375Smsmith    struct acpi_tz_softc	*sc;
74479375Smsmith    int				active;
74579375Smsmith    int		 		error;
74679375Smsmith
74779375Smsmith    sc = (struct acpi_tz_softc *)oidp->oid_arg1;
74879375Smsmith    active = sc->tz_active;
74979375Smsmith    error = sysctl_handle_int(oidp, &active, 0, req);
75079375Smsmith
751119529Snjl    /* Error or no new value */
752119529Snjl    if (error != 0 || req->newptr == NULL)
753133624Snjl	return (error);
754133624Snjl    if (active < -1 || active >= TZ_NUMLEVELS)
755133624Snjl	return (EINVAL);
75679375Smsmith
757119529Snjl    /* Set new preferred level and re-switch */
75879375Smsmith    sc->tz_requested = active;
759133624Snjl    acpi_tz_signal(sc, 0);
760133624Snjl    return (0);
76179375Smsmith}
76279375Smsmith
763148138Sumestatic int
764148138Sumeacpi_tz_cooling_sysctl(SYSCTL_HANDLER_ARGS)
765148138Sume{
766148138Sume    struct acpi_tz_softc *sc;
767148138Sume    int enabled, error;
768148138Sume
769148138Sume    sc = (struct acpi_tz_softc *)oidp->oid_arg1;
770148138Sume    enabled = sc->tz_cooling_enabled;
771148138Sume    error = sysctl_handle_int(oidp, &enabled, 0, req);
772148138Sume
773148138Sume    /* Error or no new value */
774148138Sume    if (error != 0 || req->newptr == NULL)
775148138Sume	return (error);
776148138Sume    if (enabled != TRUE && enabled != FALSE)
777148138Sume	return (EINVAL);
778148138Sume
779148138Sume    if (enabled) {
780148138Sume	if (acpi_tz_cooling_is_available(sc))
781148138Sume	    error = acpi_tz_cooling_thread_start(sc);
782148138Sume	else
783148138Sume	    error = ENODEV;
784148138Sume	if (error)
785148138Sume	    enabled = FALSE;
786148138Sume    }
787148138Sume    sc->tz_cooling_enabled = enabled;
788148138Sume    return (error);
789148138Sume}
790148138Sume
791160657Snjlstatic int
792160657Snjlacpi_tz_temp_sysctl(SYSCTL_HANDLER_ARGS)
793160657Snjl{
794160657Snjl    struct acpi_tz_softc	*sc;
795160657Snjl    int				temp, *temp_ptr;
796160657Snjl    int		 		error;
797160657Snjl
798160657Snjl    sc = oidp->oid_arg1;
799299126Sjkim    temp_ptr = (int *)(void *)(uintptr_t)((uintptr_t)sc + oidp->oid_arg2);
800160657Snjl    temp = *temp_ptr;
801160657Snjl    error = sysctl_handle_int(oidp, &temp, 0, req);
802160657Snjl
803160657Snjl    /* Error or no new value */
804160657Snjl    if (error != 0 || req->newptr == NULL)
805160657Snjl	return (error);
806160657Snjl
807160657Snjl    /* Only allow changing settings if override is set. */
808160657Snjl    if (!acpi_tz_override)
809160657Snjl	return (EPERM);
810160657Snjl
811160657Snjl    /* Check user-supplied value for sanity. */
812160657Snjl    acpi_tz_sanity(sc, &temp, "user-supplied temp");
813160657Snjl    if (temp == -1)
814160657Snjl	return (EINVAL);
815160657Snjl
816160657Snjl    *temp_ptr = temp;
817160657Snjl    return (0);
818160657Snjl}
819160657Snjl
820174889Sumestatic int
821174889Sumeacpi_tz_passive_sysctl(SYSCTL_HANDLER_ARGS)
822174889Sume{
823174889Sume    struct acpi_tz_softc	*sc;
824174889Sume    int				val, *val_ptr;
825174889Sume    int				error;
826174889Sume
827174889Sume    sc = oidp->oid_arg1;
828299126Sjkim    val_ptr = (int *)(void *)(uintptr_t)((uintptr_t)sc + oidp->oid_arg2);
829174889Sume    val = *val_ptr;
830174889Sume    error = sysctl_handle_int(oidp, &val, 0, req);
831174889Sume
832174889Sume    /* Error or no new value */
833174889Sume    if (error != 0 || req->newptr == NULL)
834174889Sume	return (error);
835174889Sume
836174889Sume    /* Only allow changing settings if override is set. */
837174889Sume    if (!acpi_tz_override)
838174889Sume	return (EPERM);
839174889Sume
840174889Sume    *val_ptr = val;
841174889Sume    return (0);
842174889Sume}
843174889Sume
84478915Smsmithstatic void
84571874Smsmithacpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
84671874Smsmith{
84778915Smsmith    struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)context;
84878915Smsmith
84996926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
85070271Stakawata
851133624Snjl    switch (notify) {
85278915Smsmith    case TZ_NOTIFY_TEMPERATURE:
853119529Snjl	/* Temperature change occurred */
854133624Snjl	acpi_tz_signal(sc, 0);
85578915Smsmith	break;
85678915Smsmith    case TZ_NOTIFY_DEVICES:
85778915Smsmith    case TZ_NOTIFY_LEVELS:
858119529Snjl	/* Zone devices/setpoints changed */
859133624Snjl	acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS);
86078915Smsmith	break;
86178915Smsmith    default:
86286552Siwasaki	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
863119529Snjl		    "unknown Notify event 0x%x\n", notify);
86478915Smsmith	break;
86571874Smsmith    }
866119529Snjl
867121493Snjl    acpi_UserNotify("Thermal", h, notify);
868121493Snjl
86971874Smsmith    return_VOID;
87071874Smsmith}
87170271Stakawata
872133624Snjlstatic void
873133624Snjlacpi_tz_signal(struct acpi_tz_softc *sc, int flags)
874133624Snjl{
875133624Snjl    ACPI_LOCK(thermal);
876133624Snjl    sc->tz_flags |= flags;
877133624Snjl    ACPI_UNLOCK(thermal);
878133624Snjl    wakeup(&acpi_tz_proc);
879133624Snjl}
880133624Snjl
88178915Smsmith/*
882134909Snjl * Notifies can be generated asynchronously but have also been seen to be
883134909Snjl * triggered by other thermal methods.  One system generates a notify of
884134909Snjl * 0x81 when the fan is turned on or off.  Another generates it when _SCP
885134909Snjl * is called.  To handle these situations, we check the zone via
886134909Snjl * acpi_tz_monitor() before evaluating changes to setpoints or the cooling
887134909Snjl * policy.
88878915Smsmith */
88978915Smsmithstatic void
890133624Snjlacpi_tz_timeout(struct acpi_tz_softc *sc, int flags)
89178915Smsmith{
892134909Snjl
893134909Snjl    /* Check the current temperature and take action based on it */
894134909Snjl    acpi_tz_monitor(sc);
895134909Snjl
896133624Snjl    /* If requested, get the power profile settings. */
897133624Snjl    if (flags & TZ_FLAG_GETPROFILE)
898133624Snjl	acpi_tz_power_profile(sc);
89979375Smsmith
900134909Snjl    /*
901134909Snjl     * If requested, check for new devices/setpoints.  After finding them,
902134909Snjl     * check if we need to switch fans based on the new values.
903134909Snjl     */
904134909Snjl    if (flags & TZ_FLAG_GETSETTINGS) {
905133624Snjl	acpi_tz_establish(sc);
906134909Snjl	acpi_tz_monitor(sc);
907134909Snjl    }
90878915Smsmith
90978915Smsmith    /* XXX passive cooling actions? */
91078915Smsmith}
91179375Smsmith
91279375Smsmith/*
91379375Smsmith * System power profile may have changed; fetch and notify the
91479375Smsmith * thermal zone accordingly.
91579375Smsmith *
91679375Smsmith * Since this can be called from an arbitrary eventhandler, it needs
91779375Smsmith * to get the ACPI lock itself.
91879375Smsmith */
91979375Smsmithstatic void
92091640Siwasakiacpi_tz_power_profile(void *arg)
92179375Smsmith{
92279375Smsmith    ACPI_STATUS			status;
92379375Smsmith    struct acpi_tz_softc	*sc = (struct acpi_tz_softc *)arg;
92491640Siwasaki    int				state;
92579375Smsmith
92691640Siwasaki    state = power_profile_get_state();
927119529Snjl    if (state != POWER_PROFILE_PERFORMANCE && state != POWER_PROFILE_ECONOMY)
928119529Snjl	return;
92991640Siwasaki
93079375Smsmith    /* check that we haven't decided there's no _SCP method */
931119529Snjl    if ((sc->tz_flags & TZ_FLAG_NO_SCP) == 0) {
93279375Smsmith
933119529Snjl	/* Call _SCP to set the new profile */
934148138Sume	status = acpi_SetInteger(sc->tz_handle, "_SCP",
935126560Snjl	    (state == POWER_PROFILE_PERFORMANCE) ? 0 : 1);
936119529Snjl	if (ACPI_FAILURE(status)) {
93779385Smsmith	    if (status != AE_NOT_FOUND)
938119529Snjl		ACPI_VPRINT(sc->tz_dev,
939119529Snjl			    acpi_device_get_parent_softc(sc->tz_dev),
940119529Snjl			    "can't evaluate %s._SCP - %s\n",
941119529Snjl			    acpi_name(sc->tz_handle),
942119529Snjl			    AcpiFormatException(status));
94379375Smsmith	    sc->tz_flags |= TZ_FLAG_NO_SCP;
94479375Smsmith	} else {
945119529Snjl	    /* We have to re-evaluate the entire zone now */
946133624Snjl	    acpi_tz_signal(sc, TZ_FLAG_GETSETTINGS);
94779375Smsmith	}
94879375Smsmith    }
94979375Smsmith}
95079375Smsmith
95191126Smsmith/*
95291126Smsmith * Thermal zone monitor thread.
95391126Smsmith */
95491126Smsmithstatic void
95591126Smsmithacpi_tz_thread(void *arg)
95691126Smsmith{
95791126Smsmith    device_t	*devs;
95891126Smsmith    int		devcount, i;
959133624Snjl    int		flags;
960133624Snjl    struct acpi_tz_softc **sc;
96191126Smsmith
96296926Speter    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
96391126Smsmith
96491126Smsmith    devs = NULL;
96591126Smsmith    devcount = 0;
966133624Snjl    sc = NULL;
96791126Smsmith
96891126Smsmith    for (;;) {
969133624Snjl	/* If the number of devices has changed, re-evaluate. */
970175014Sjhb	if (devclass_get_count(acpi_tz_devclass) != devcount) {
971133624Snjl	    if (devs != NULL) {
972133624Snjl		free(devs, M_TEMP);
973133624Snjl		free(sc, M_TEMP);
974133624Snjl	    }
975133624Snjl	    devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
976133624Snjl	    sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP,
977133624Snjl			M_WAITOK | M_ZERO);
978133624Snjl	    for (i = 0; i < devcount; i++)
979133624Snjl		sc[i] = device_get_softc(devs[i]);
980133624Snjl	}
98191126Smsmith
982133624Snjl	/* Check for temperature events and act on them. */
983133624Snjl	for (i = 0; i < devcount; i++) {
984133624Snjl	    ACPI_LOCK(thermal);
985133624Snjl	    flags = sc[i]->tz_flags;
986133624Snjl	    sc[i]->tz_flags &= TZ_FLAG_NO_SCP;
987133624Snjl	    ACPI_UNLOCK(thermal);
988133624Snjl	    acpi_tz_timeout(sc[i], flags);
989133624Snjl	}
99091215Smsmith
991133624Snjl	/* If more work to do, don't go to sleep yet. */
992133624Snjl	ACPI_LOCK(thermal);
993133624Snjl	for (i = 0; i < devcount; i++) {
994133624Snjl	    if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP)
995133624Snjl		break;
996133624Snjl	}
99791126Smsmith
998133624Snjl	/*
999133624Snjl	 * If we have no more work, sleep for a while, setting PDROP so that
1000133624Snjl	 * the mutex will not be reacquired.  Otherwise, drop the mutex and
1001133624Snjl	 * loop to handle more events.
1002133624Snjl	 */
1003133624Snjl	if (i == devcount)
1004133624Snjl	    msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll",
1005133624Snjl		hz * acpi_tz_polling_rate);
1006133624Snjl	else
1007133624Snjl	    ACPI_UNLOCK(thermal);
100891126Smsmith    }
100991126Smsmith}
1010148138Sume
1011148138Sumestatic int
1012148138Sumeacpi_tz_cpufreq_restore(struct acpi_tz_softc *sc)
1013148138Sume{
1014148138Sume    device_t dev;
1015148138Sume    int error;
1016148138Sume
1017148138Sume    if (!sc->tz_cooling_updated)
1018148138Sume	return (0);
1019148138Sume    if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL)
1020148138Sume	return (ENXIO);
1021148138Sume    ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
1022149201Sume	"temperature %d.%dC: resuming previous clock speed (%d MHz)\n",
1023149201Sume	TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq);
1024148138Sume    error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN);
1025148138Sume    if (error == 0)
1026148138Sume	sc->tz_cooling_updated = FALSE;
1027148138Sume    return (error);
1028148138Sume}
1029148138Sume
1030148138Sumestatic int
1031148138Sumeacpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req)
1032148138Sume{
1033148138Sume    device_t dev;
1034148138Sume    struct cf_level *levels;
1035148138Sume    int num_levels, error, freq, desired_freq, perf, i;
1036148138Sume
1037148138Sume    levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT);
1038148138Sume    if (levels == NULL)
1039148138Sume	return (ENOMEM);
1040148138Sume
1041148138Sume    /*
1042148138Sume     * Find the main device, cpufreq0.  We don't yet support independent
1043148138Sume     * CPU frequency control on SMP.
1044148138Sume     */
1045148138Sume    if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) {
1046148138Sume	error = ENXIO;
1047148138Sume	goto out;
1048148138Sume    }
1049148138Sume
1050148138Sume    /* Get the current frequency. */
1051148138Sume    error = CPUFREQ_GET(dev, &levels[0]);
1052148138Sume    if (error)
1053148138Sume	goto out;
1054148138Sume    freq = levels[0].total_set.freq;
1055148138Sume
1056148138Sume    /* Get the current available frequency levels. */
1057148138Sume    num_levels = CPUFREQ_MAX_LEVELS;
1058148138Sume    error = CPUFREQ_LEVELS(dev, levels, &num_levels);
1059148138Sume    if (error) {
1060148138Sume	if (error == E2BIG)
1061148138Sume	    printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n");
1062148138Sume	goto out;
1063148138Sume    }
1064148138Sume
1065148138Sume    /* Calculate the desired frequency as a percent of the max frequency. */
1066148138Sume    perf = 100 * freq / levels[0].total_set.freq - req;
1067148138Sume    if (perf < 0)
1068148138Sume	perf = 0;
1069148138Sume    else if (perf > 100)
1070148138Sume	perf = 100;
1071148138Sume    desired_freq = levels[0].total_set.freq * perf / 100;
1072148138Sume
1073149201Sume    if (desired_freq < freq) {
1074148138Sume	/* Find the closest available frequency, rounding down. */
1075148138Sume	for (i = 0; i < num_levels; i++)
1076148138Sume	    if (levels[i].total_set.freq <= desired_freq)
1077148138Sume		break;
1078148138Sume
1079148138Sume	/* If we didn't find a relevant setting, use the lowest. */
1080148138Sume	if (i == num_levels)
1081148138Sume	    i--;
1082148138Sume    } else {
1083149201Sume	/* If we didn't decrease frequency yet, don't increase it. */
1084149201Sume	if (!sc->tz_cooling_updated) {
1085149201Sume	    sc->tz_cooling_active = FALSE;
1086149201Sume	    goto out;
1087149201Sume	}
1088149201Sume
1089149201Sume	/* Use saved cpu frequency as maximum value. */
1090149201Sume	if (desired_freq > sc->tz_cooling_saved_freq)
1091149201Sume	    desired_freq = sc->tz_cooling_saved_freq;
1092149201Sume
1093148138Sume	/* Find the closest available frequency, rounding up. */
1094148138Sume	for (i = num_levels - 1; i >= 0; i--)
1095148138Sume	    if (levels[i].total_set.freq >= desired_freq)
1096148138Sume		break;
1097148138Sume
1098148138Sume	/* If we didn't find a relevant setting, use the highest. */
1099148138Sume	if (i == -1)
1100148138Sume	    i++;
1101148138Sume
1102149201Sume	/* If we're going to the highest frequency, restore the old setting. */
1103149201Sume	if (i == 0 || desired_freq == sc->tz_cooling_saved_freq) {
1104149201Sume	    error = acpi_tz_cpufreq_restore(sc);
1105149201Sume	    if (error == 0)
1106149201Sume		sc->tz_cooling_active = FALSE;
1107149201Sume	    goto out;
1108149201Sume	}
1109148138Sume    }
1110148138Sume
1111148138Sume    /* If we are going to a new frequency, activate it. */
1112148138Sume    if (levels[i].total_set.freq != freq) {
1113148138Sume	ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev),
1114148138Sume	    "temperature %d.%dC: %screasing clock speed "
1115148138Sume	    "from %d MHz to %d MHz\n",
1116148138Sume	    TZ_KELVTOC(sc->tz_temperature),
1117148138Sume	    (freq > levels[i].total_set.freq) ? "de" : "in",
1118148138Sume	    freq, levels[i].total_set.freq);
1119148138Sume	error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN);
1120149201Sume	if (error == 0 && !sc->tz_cooling_updated) {
1121149201Sume	    sc->tz_cooling_saved_freq = freq;
1122148138Sume	    sc->tz_cooling_updated = TRUE;
1123149201Sume	}
1124148138Sume    }
1125148138Sume
1126148138Sumeout:
1127148138Sume    if (levels)
1128148138Sume	free(levels, M_TEMP);
1129148138Sume    return (error);
1130148138Sume}
1131148138Sume
1132148138Sume/*
1133148138Sume * Passive cooling thread; monitors current temperature according to the
1134148138Sume * cooling interval and calculates whether to scale back CPU frequency.
1135148138Sume */
1136148138Sumestatic void
1137148138Sumeacpi_tz_cooling_thread(void *arg)
1138148138Sume{
1139148138Sume    struct acpi_tz_softc *sc;
1140149450Sume    int error, perf, curr_temp, prev_temp;
1141148138Sume
1142148138Sume    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1143148138Sume
1144148138Sume    sc = (struct acpi_tz_softc *)arg;
1145148138Sume
1146149450Sume    prev_temp = sc->tz_temperature;
1147148138Sume    while (sc->tz_cooling_enabled) {
1148149450Sume	if (sc->tz_cooling_active)
1149149450Sume	    (void)acpi_tz_get_temperature(sc);
1150149450Sume	curr_temp = sc->tz_temperature;
1151149450Sume	if (curr_temp >= sc->tz_zone.psv)
1152148138Sume	    sc->tz_cooling_active = TRUE;
1153148138Sume	if (sc->tz_cooling_active) {
1154149450Sume	    perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) +
1155149450Sume		   sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv);
1156148138Sume	    perf /= 10;
1157148138Sume
1158148138Sume	    if (perf != 0) {
1159148138Sume		error = acpi_tz_cpufreq_update(sc, perf);
1160148138Sume
1161148138Sume		/*
1162148138Sume		 * If error and not simply a higher priority setting was
1163148138Sume		 * active, disable cooling.
1164148138Sume		 */
1165148138Sume		if (error != 0 && error != EPERM) {
1166148138Sume		    device_printf(sc->tz_dev,
1167148138Sume			"failed to set new freq, disabling passive cooling\n");
1168148138Sume		    sc->tz_cooling_enabled = FALSE;
1169148138Sume		}
1170148138Sume	    }
1171148138Sume	}
1172149450Sume	prev_temp = curr_temp;
1173148138Sume	tsleep(&sc->tz_cooling_proc, PZERO, "cooling",
1174148138Sume	    hz * sc->tz_zone.tsp / 10);
1175148138Sume    }
1176148138Sume    if (sc->tz_cooling_active) {
1177148138Sume	acpi_tz_cpufreq_restore(sc);
1178148138Sume	sc->tz_cooling_active = FALSE;
1179148138Sume    }
1180148703Sume    sc->tz_cooling_proc = NULL;
1181148138Sume    ACPI_LOCK(thermal);
1182148703Sume    sc->tz_cooling_proc_running = FALSE;
1183148138Sume    ACPI_UNLOCK(thermal);
1184172836Sjulian    kproc_exit(0);
1185148138Sume}
1186148138Sume
1187148138Sume/*
1188148138Sume * TODO: We ignore _PSL (list of cooling devices) since cpufreq enumerates
1189148138Sume * all CPUs for us.  However, it's possible in the future _PSL will
1190148138Sume * reference non-CPU devices so we may want to support it then.
1191148138Sume */
1192148138Sumestatic int
1193148138Sumeacpi_tz_cooling_is_available(struct acpi_tz_softc *sc)
1194148138Sume{
1195148138Sume    return (sc->tz_zone.tc1 != -1 && sc->tz_zone.tc2 != -1 &&
1196148138Sume	sc->tz_zone.tsp != -1 && sc->tz_zone.tsp != 0 &&
1197148138Sume	sc->tz_zone.psv != -1);
1198148138Sume}
1199148138Sume
1200148138Sumestatic int
1201148138Sumeacpi_tz_cooling_thread_start(struct acpi_tz_softc *sc)
1202148138Sume{
1203148138Sume    int error;
1204148138Sume
1205148703Sume    ACPI_LOCK(thermal);
1206148703Sume    if (sc->tz_cooling_proc_running) {
1207148703Sume	ACPI_UNLOCK(thermal);
1208148703Sume	return (0);
1209148703Sume    }
1210148703Sume    sc->tz_cooling_proc_running = TRUE;
1211148703Sume    ACPI_UNLOCK(thermal);
1212148138Sume    error = 0;
1213148138Sume    if (sc->tz_cooling_proc == NULL) {
1214209062Savg	error = kproc_create(acpi_tz_cooling_thread, sc,
1215209062Savg	    &sc->tz_cooling_proc, RFHIGHPID, 0, "acpi_cooling%d",
1216148138Sume	    device_get_unit(sc->tz_dev));
1217148703Sume	if (error != 0) {
1218148138Sume	    device_printf(sc->tz_dev, "could not create thread - %d", error);
1219148703Sume	    ACPI_LOCK(thermal);
1220148703Sume	    sc->tz_cooling_proc_running = FALSE;
1221148703Sume	    ACPI_UNLOCK(thermal);
1222148703Sume	}
1223148138Sume    }
1224148138Sume    return (error);
1225148138Sume}
1226