acpi_thermal.c (78662) | acpi_thermal.c (78915) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 2000 Michael Smith | 2 * Copyright (c) 2000, 2001 Michael Smith |
3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. --- 8 unchanged lines hidden (view full) --- 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, 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 * | 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. --- 8 unchanged lines hidden (view full) --- 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, 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 * $FreeBSD: head/sys/dev/acpica/acpi_thermal.c 78662 2001-06-23 10:38:25Z iwasaki $ | 27 * $FreeBSD: head/sys/dev/acpica/acpi_thermal.c 78915 2001-06-28 06:17:16Z msmith $ |
28 */ 29 30#include "opt_acpi.h" 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/bus.h> | 28 */ 29 30#include "opt_acpi.h" 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/bus.h> |
34#include <sys/reboot.h> |
|
34 35#include "acpi.h" 36 37#include <dev/acpica/acpivar.h> 38 39/* 40 * Hooks for the ACPI CA debugging infrastructure 41 */ 42#define _COMPONENT ACPI_THERMAL_ZONE 43MODULE_NAME("THERMAL") 44 45#define TZ_ZEROC 2732 46#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 47 | 35 36#include "acpi.h" 37 38#include <dev/acpica/acpivar.h> 39 40/* 41 * Hooks for the ACPI CA debugging infrastructure 42 */ 43#define _COMPONENT ACPI_THERMAL_ZONE 44MODULE_NAME("THERMAL") 45 46#define TZ_ZEROC 2732 47#define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) 48 |
49#define TZ_NOTIFY_TEMPERATURE 0x80 50#define TZ_NOTIFY_DEVICES 0x81 51#define TZ_NOTIFY_LEVELS 0x82 52 53#define TZ_POLLRATE (hz * 10) /* every ten seconds */ 54 55#define TZ_NUMLEVELS 10 /* defined by ACPI spec */ 56struct acpi_tz_state { 57 int ac[TZ_NUMLEVELS]; 58 ACPI_BUFFER al[TZ_NUMLEVELS]; 59 int crt; 60 int hot; 61 ACPI_BUFFER psl; 62 int psv; 63 int tc1; 64 int tc2; 65 int tsp; 66 int tzp; 67}; 68 69 |
|
48struct acpi_tz_softc { | 70struct acpi_tz_softc { |
49 device_t tz_dev; 50 ACPI_HANDLE tz_handle; 51 int tz_tmp; | 71 device_t tz_dev; 72 ACPI_HANDLE tz_handle; 73 struct callout_handle tz_timeout; 74 int tz_current; 75#define TZ_STATE_NONE 0 76#define TZ_STATE_PSV 1 77#define TZ_STATE_AC0 2 78#define TZ_STATE_HOT (TZ_STATE_AC0 + TZ_NUMLEVELS) 79#define TZ_STATE_CRT (TZ_STATE_AC0 + TZ_NUMLEVELS + 1) 80 81 struct acpi_tz_state tz_state; |
52}; 53 54static int acpi_tz_probe(device_t dev); 55static int acpi_tz_attach(device_t dev); | 82}; 83 84static int acpi_tz_probe(device_t dev); 85static int acpi_tz_attach(device_t dev); |
56static void acpi_tz_check_tripping_point(void *context); | 86static int acpi_tz_establish(struct acpi_tz_softc *sc); 87static void acpi_tz_all_off(struct acpi_tz_softc *sc); 88static void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); 89static void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); 90static void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data); |
57static void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); | 91static void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); |
92static void acpi_tz_timeout(void *arg); |
|
58 59static device_method_t acpi_tz_methods[] = { 60 /* Device interface */ 61 DEVMETHOD(device_probe, acpi_tz_probe), 62 DEVMETHOD(device_attach, acpi_tz_attach), 63 64 {0, 0} 65}; 66 67static driver_t acpi_tz_driver = { 68 "acpi_tz", 69 acpi_tz_methods, 70 sizeof(struct acpi_tz_softc), 71}; 72 73devclass_t acpi_tz_devclass; 74DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 75 | 93 94static device_method_t acpi_tz_methods[] = { 95 /* Device interface */ 96 DEVMETHOD(device_probe, acpi_tz_probe), 97 DEVMETHOD(device_attach, acpi_tz_attach), 98 99 {0, 0} 100}; 101 102static driver_t acpi_tz_driver = { 103 "acpi_tz", 104 acpi_tz_methods, 105 sizeof(struct acpi_tz_softc), 106}; 107 108devclass_t acpi_tz_devclass; 109DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); 110 |
111/* 112 * Match an ACPI thermal zone. 113 */ |
|
76static int 77acpi_tz_probe(device_t dev) 78{ 79 | 114static int 115acpi_tz_probe(device_t dev) 116{ 117 |
80 FUNCTION_TRACE(__func__); | 118 /* no FUNCTION_TRACE - too noisy */ |
81 82 if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && 83 !acpi_disabled("thermal")) { 84 device_set_desc(dev, "thermal zone"); | 119 120 if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && 121 !acpi_disabled("thermal")) { 122 device_set_desc(dev, "thermal zone"); |
85 return_VALUE(0); | 123 return(-10); |
86 } | 124 } |
87 return_VALUE(ENXIO); | 125 return(ENXIO); |
88} 89 | 126} 127 |
128/* 129 * Attach to an ACPI thermal zone. 130 */ |
|
90static int 91acpi_tz_attach(device_t dev) 92{ 93 struct acpi_tz_softc *sc; | 131static int 132acpi_tz_attach(device_t dev) 133{ 134 struct acpi_tz_softc *sc; |
94 struct acpi_softc *acpi_sc; | 135 int error; |
95 96 FUNCTION_TRACE(__func__); 97 98 sc = device_get_softc(dev); 99 sc->tz_dev = dev; 100 sc->tz_handle = acpi_get_handle(dev); 101 | 136 137 FUNCTION_TRACE(__func__); 138 139 sc = device_get_softc(dev); 140 sc->tz_dev = dev; 141 sc->tz_handle = acpi_get_handle(dev); 142 |
143 /* 144 * Parse the current state of the thermal zone and build control 145 * structures. 146 */ 147 if ((error = acpi_tz_establish(sc)) != 0) 148 return_VALUE(error); 149 150 /* 151 * Register for any Notify events sent to this zone. 152 */ |
|
102 AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 103 acpi_tz_notify_handler, dev); 104 | 153 AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, 154 acpi_tz_notify_handler, dev); 155 |
105 if (device_get_unit(dev) == 0) { 106 acpi_sc = acpi_device_get_parent_softc(dev); 107 SYSCTL_ADD_UINT(&acpi_sc->acpi_sysctl_ctx, 108 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 109 OID_AUTO, "temperature", CTLFLAG_RD, 110 &sc->tz_tmp, 0, ""); 111 } 112 | |
113 /* 114 * Don't bother evaluating/printing the temperature at this point; 115 * on many systems it'll be bogus until the EC is running. 116 */ 117 return_VALUE(0); 118} 119 | 156 /* 157 * Don't bother evaluating/printing the temperature at this point; 158 * on many systems it'll be bogus until the EC is running. 159 */ 160 return_VALUE(0); 161} 162 |
163/* 164 * Parse the current state of this thermal zone and set up to use it. 165 * 166 * Note that we may have previous state, which will have to be discarded. 167 */ 168static int 169acpi_tz_establish(struct acpi_tz_softc *sc) 170{ 171 ACPI_OBJECT *obj; 172 int i; 173 char nbuf[8]; 174 175 FUNCTION_TRACE(__func__); 176 177 /* 178 * Power everything off and erase any existing state. 179 */ 180 acpi_tz_all_off(sc); 181 for (i = 0; i < TZ_NUMLEVELS; i++) 182 if (sc->tz_state.al[i].Pointer != NULL) 183 AcpiOsFree(sc->tz_state.al[i].Pointer); 184 if (sc->tz_state.psl.Pointer != NULL) 185 AcpiOsFree(sc->tz_state.psl.Pointer); 186 bzero(&sc->tz_state, sizeof(sc->tz_state)); 187 188 /* kill the timeout (harmless if not running */ 189 untimeout(acpi_tz_timeout, sc, sc->tz_timeout); 190 191 /* 192 * Evaluate thermal zone parameters. 193 */ 194 for (i = 0; i < TZ_NUMLEVELS; i++) { 195 sprintf(nbuf, "_AC%d", i); 196 acpi_tz_getparam(sc, nbuf, &sc->tz_state.ac[i]); 197 sprintf(nbuf, "_AL%d", i); 198 acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_state.al[i]); 199 obj = (ACPI_OBJECT *)sc->tz_state.al[i].Pointer; 200 if (obj != NULL) { 201 /* should be a package containing a list of power objects */ 202 if (obj->Type != ACPI_TYPE_PACKAGE) { 203 device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n", 204 nbuf, obj->Type); 205 return_VALUE(ENXIO); 206 } 207 } 208 } 209 acpi_tz_getparam(sc, "_CRT", &sc->tz_state.crt); 210 acpi_tz_getparam(sc, "_HOT", &sc->tz_state.hot); 211 acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_state.psl); 212 acpi_tz_getparam(sc, "_PSV", &sc->tz_state.psv); 213 acpi_tz_getparam(sc, "_TC1", &sc->tz_state.tc1); 214 acpi_tz_getparam(sc, "_TC2", &sc->tz_state.tc2); 215 acpi_tz_getparam(sc, "_TSP", &sc->tz_state.tsp); 216 acpi_tz_getparam(sc, "_TZP", &sc->tz_state.tzp); 217 218 /* 219 * Power off everything that we've just been given. 220 */ 221 acpi_tz_all_off(sc); 222 223 /* 224 * Do we need to poll the thermal zone? Ignore the suggested 225 * rate. 226 */ 227 if (sc->tz_state.tzp != 0) 228 sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 229 230 231 return_VALUE(0); 232} 233 234/* 235 * Evaluate the condition of a thermal zone, take appropriate actions. 236 */ |
|
120static void | 237static void |
121acpi_tz_check_tripping_point(void *context) | 238acpi_tz_monitor(struct acpi_tz_softc *sc) |
122{ | 239{ |
123 struct acpi_tz_softc *sc; 124 device_t dev = context; 125 ACPI_STATUS status; 126 int tp; | 240 int temp, new; 241 int i; |
127 128 FUNCTION_TRACE(__func__); 129 | 242 243 FUNCTION_TRACE(__func__); 244 |
130 sc = device_get_softc(dev); 131 if ((status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &tp)) != AE_OK) { 132 device_printf(dev, "can't evaluate _TMP method - %s\n", acpi_strerror(status)); | 245 /* 246 * Get the current temperature. 247 */ 248 if ((acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) { 249 device_printf(sc->tz_dev, "error fetching current temperature\n"); 250 /* XXX disable zone? go to max cooling? */ |
133 return_VOID; 134 } | 251 return_VOID; 252 } |
253 254 /* 255 * Work out what we ought to be doing right now. 256 */ 257 new = TZ_STATE_NONE; 258 if ((sc->tz_state.psv != -1) && (temp > sc->tz_state.psv)) 259 new = TZ_STATE_PSV; 260 for (i = 0; i < TZ_NUMLEVELS; i++) 261 if ((sc->tz_state.ac[i] != -1) && (temp > sc->tz_state.ac[i])) 262 new = TZ_STATE_AC0 + i; 263 if ((sc->tz_state.hot != -1) && (temp > sc->tz_state.hot)) 264 new = TZ_STATE_HOT; 265 if ((sc->tz_state.crt != -1) && (temp > sc->tz_state.crt)) 266 new = TZ_STATE_CRT; 267 268 /* 269 * If our state has not changed, do nothing. 270 */ 271 if (new == sc->tz_current) 272 return_VOID; |
|
135 | 273 |
136 sc->tz_tmp = (tp - TZ_ZEROC) / 10; 137 if (bootverbose) { 138 device_printf(dev, "%dC\n", sc->tz_tmp); | 274 /* 275 * XXX if we're in a passive-cooling mode, revert to full-speed operation. 276 */ 277 if (sc->tz_current == TZ_STATE_PSV) { 278 /* XXX implement */ |
139 } | 279 } |
280 281 /* 282 * If we're in an active-cooling mode, turn off the current cooler(s). 283 */ 284 if ((sc->tz_current >= TZ_STATE_AC0) && (sc->tz_current < (TZ_STATE_AC0 + TZ_NUMLEVELS))) 285 acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[sc->tz_current - TZ_STATE_AC0].Pointer, 286 acpi_tz_switch_cooler_off, sc); 287 288 /* 289 * XXX If the new mode is passive-cooling, make appropriate adjustments. 290 */ 291 292 /* 293 * If the new mode is an active-cooling mode, turn on the new cooler(s). 294 */ 295 if ((new >= TZ_STATE_AC0) && (new < (TZ_STATE_AC0 + TZ_NUMLEVELS))) 296 acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[new - TZ_STATE_AC0].Pointer, 297 acpi_tz_switch_cooler_on, sc); 298 299 /* 300 * If we're _HOT or _CRT, shut down now! 301 */ 302 if ((new == TZ_STATE_HOT) || (new == TZ_STATE_CRT)) { 303 device_printf(sc->tz_dev, "WARNING - emergency thermal shutdown in progress.\n"); 304 shutdown_nice(RB_POWEROFF); 305 } 306 307 /* gone to new state */ 308 sc->tz_current = new; 309 |
|
140 return_VOID; 141} 142 | 310 return_VOID; 311} 312 |
143#define ACPI_TZ_STATUS_CHANGE 0x80 144#define ACPI_TZ_TRIPPOINT_CHANGE 0x81 | 313/* 314 * Turn off all the cooling devices. 315 */ |
145static void | 316static void |
317acpi_tz_all_off(struct acpi_tz_softc *sc) 318{ 319 int i; 320 321 FUNCTION_TRACE(__func__); 322 323 /* 324 * Scan all the _AL objects, and turn them all off. 325 */ 326 for (i = 0; i < TZ_NUMLEVELS; i++) { 327 if (sc->tz_state.al[i].Pointer == NULL) 328 continue; 329 acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[i].Pointer, 330 acpi_tz_switch_cooler_off, sc); 331 } 332 333 /* 334 * XXX revert any passive-cooling options. 335 */ 336 337 sc->tz_current = TZ_STATE_NONE; 338 return_VOID; 339} 340 341/* 342 * Given an object, verify that it's a reference to a device of some sort, 343 * and try to switch it off. 344 */ 345static void 346acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) 347{ 348 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 349 ACPI_HANDLE cooler; 350 351 FUNCTION_TRACE(__func__); 352 353 switch(obj->Type) { 354 case ACPI_TYPE_STRING: 355 DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s off\n", obj->String.Pointer)); 356 357 /* 358 * Find the handle for the device and turn it off. 359 * The String object here seems to contain a fully-qualified path, so we 360 * don't have to search for it in our parents. 361 * 362 * XXX This may not always be the case. 363 */ 364 if (AcpiGetHandle(obj->String.Pointer, NULL, &cooler) == AE_OK) 365 acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); 366 break; 367 368 default: 369 DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", 370 obj->Type)); 371 break; 372 } 373 return_VOID; 374} 375 376/* 377 * Given an object, verify that it's a reference to a device of some sort, 378 * and try to switch it on. 379 * 380 * XXX replication of off/on function code is bad, mmmkay? 381 */ 382static void 383acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) 384{ 385 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 386 ACPI_HANDLE cooler, parent; 387 388 FUNCTION_TRACE(__func__); 389 390 switch(obj->Type) { 391 case ACPI_TYPE_STRING: 392 DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s off\n", obj->String.Pointer)); 393 394 /* find the handle for the device and turn it off */ 395 if (acpi_GetHandleInScope(sc->tz_handle, obj->String.Pointer, &cooler) == AE_OK) 396 acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); 397 break; 398 399 default: 400 DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", 401 obj->Type)); 402 break; 403 } 404 return_VOID; 405} 406 407/* 408 * Read/debug-print a parameter, default it to -1. 409 */ 410static void 411acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) 412{ 413 414 FUNCTION_TRACE(__func__); 415 416 if (acpi_EvaluateInteger(sc->tz_handle, node, data) != AE_OK) { 417 *data = -1; 418 } else { 419 DEBUG_PRINT(TRACE_VALUES, ("%s.%s = %d\n", acpi_name(sc->tz_handle), 420 node, *data)); 421 } 422 return_VOID; 423} 424 425/* 426 * Respond to a Notify event sent to the zone. 427 */ 428static void |
|
146acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 147{ | 429acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 430{ |
431 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; 432 |
|
148 FUNCTION_TRACE(__func__); 149 | 433 FUNCTION_TRACE(__func__); 434 |
150 switch(notify){ 151 case ACPI_TZ_STATUS_CHANGE: 152 case ACPI_TZ_TRIPPOINT_CHANGE: 153 /*Check trip point*/ 154 AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_tz_check_tripping_point, context); 155 break; | 435 switch(notify) { 436 case TZ_NOTIFY_TEMPERATURE: 437 acpi_tz_monitor(sc); /* temperature change occurred */ 438 break; 439 case TZ_NOTIFY_DEVICES: 440 case TZ_NOTIFY_LEVELS: 441 acpi_tz_establish(sc); /* zone devices/setpoints changed */ 442 break; 443 default: 444 device_printf(sc->tz_dev, "unknown Notify event 0x%x\n", notify); 445 break; |
156 } 157 return_VOID; 158} 159 | 446 } 447 return_VOID; 448} 449 |
450/* 451 * Poll the thermal zone. 452 */ 453static void 454acpi_tz_timeout(void *arg) 455{ 456 struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; 457 458 /* check temperature, take action */ 459 acpi_tz_monitor(sc); 460 461 /* XXX passive cooling actions? */ 462 463 /* re-register ourself */ 464 sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); 465} |
|