1 /* $NetBSD: sysmon_envsys_events.c,v 1.118 2015/10/15 13:35:30 bouyer Exp $ */ 2 3 /*- 4 * Copyright (c) 2007, 2008 Juan Romero Pardines. 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. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * sysmon_envsys(9) events framework. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: sysmon_envsys_events.c,v 1.118 2015/10/15 13:35:30 bouyer Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/conf.h> 38 #include <sys/errno.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 #include <sys/proc.h> 42 #include <sys/mutex.h> 43 #include <sys/kmem.h> 44 #include <sys/callout.h> 45 #include <sys/syslog.h> 46 47 #include <dev/sysmon/sysmonvar.h> 48 #include <dev/sysmon/sysmon_envsysvar.h> 49 50 struct sme_sensor_event { 51 int state; 52 int event; 53 }; 54 55 static const struct sme_sensor_event sme_sensor_event[] = { 56 { ENVSYS_SVALID, PENVSYS_EVENT_NORMAL }, 57 { ENVSYS_SCRITOVER, PENVSYS_EVENT_CRITOVER }, 58 { ENVSYS_SCRITUNDER, PENVSYS_EVENT_CRITUNDER }, 59 { ENVSYS_SWARNOVER, PENVSYS_EVENT_WARNOVER }, 60 { ENVSYS_SWARNUNDER, PENVSYS_EVENT_WARNUNDER }, 61 { ENVSYS_BATTERY_CAPACITY_NORMAL, PENVSYS_EVENT_NORMAL }, 62 { ENVSYS_BATTERY_CAPACITY_WARNING, PENVSYS_EVENT_BATT_WARN }, 63 { ENVSYS_BATTERY_CAPACITY_CRITICAL, PENVSYS_EVENT_BATT_CRIT }, 64 { ENVSYS_BATTERY_CAPACITY_HIGH, PENVSYS_EVENT_BATT_HIGH }, 65 { ENVSYS_BATTERY_CAPACITY_MAX, PENVSYS_EVENT_BATT_MAX }, 66 { -1, -1 } 67 }; 68 69 static const struct op_t { 70 const char *name; 71 enum envsys_lims idx; 72 uint32_t prop; 73 } limit_ops[] = { 74 /* Value-based limits */ 75 { "critical-max", ENVSYS_LIM_CRITMAX, PROP_CRITMAX }, 76 { "warning-max", ENVSYS_LIM_WARNMAX, PROP_WARNMAX }, 77 { "warning-min", ENVSYS_LIM_WARNMIN, PROP_WARNMIN }, 78 { "critical-min", ENVSYS_LIM_CRITMIN, PROP_CRITMIN }, 79 80 /* %Capacity-based limits */ 81 { "maximum-capacity", ENVSYS_LIM_CRITMAX, PROP_BATTMAX }, 82 { "high-capacity", ENVSYS_LIM_WARNMAX, PROP_BATTHIGH }, 83 { "warning-capacity", ENVSYS_LIM_WARNMIN, PROP_BATTWARN }, 84 { "critical-capacity", ENVSYS_LIM_CRITMIN, PROP_BATTCAP }, 85 { NULL, 0, 0 } 86 }; 87 88 static const struct ev_reg_t { 89 uint32_t crittype; 90 uint32_t powertype; 91 const char *name; 92 } reg_events[] = { 93 { ENVSYS_FMONCRITICAL, PENVSYS_EVENT_CRITICAL, "critical" }, 94 { ENVSYS_FMONSTCHANGED, PENVSYS_EVENT_STATE_CHANGED, "state-changed" }, 95 { ENVSYS_FMONLIMITS, PENVSYS_EVENT_LIMITS, "hw-range-limits" }, 96 { ENVSYS_FHAS_ENTROPY, PENVSYS_EVENT_NULL, "refresh-event" }, 97 { 0, 0, NULL } 98 }; 99 100 static bool sysmon_low_power; 101 102 #define SME_EVTIMO (SME_EVENTS_DEFTIMEOUT * hz) 103 104 static bool sme_event_check_low_power(void); 105 static bool sme_battery_check(void); 106 static bool sme_battery_critical(envsys_data_t *); 107 static bool sme_acadapter_check(void); 108 109 static void sme_remove_event(sme_event_t *, struct sysmon_envsys *); 110 111 /* 112 * sme_event_register: 113 * 114 * + Registers a new sysmon envsys event or updates any event 115 * already in the queue. 116 */ 117 int 118 sme_event_register(prop_dictionary_t sdict, envsys_data_t *edata, 119 struct sysmon_envsys *sme, sysmon_envsys_lim_t *lims, 120 uint32_t props, int crittype, int powertype) 121 { 122 sme_event_t *see = NULL, *osee = NULL; 123 prop_object_t obj; 124 int error = 0; 125 const char *objkey; 126 const struct op_t *op; 127 128 KASSERT(sdict != NULL); 129 KASSERT(edata != NULL); 130 KASSERT(sme != NULL); 131 KASSERT(lims != NULL); 132 133 /* 134 * Some validation first for limit-checking events 135 * 136 * 1. Limits are not permitted if the units is ENVSYS_INDICATOR 137 * or ENVSYS_BATTERY_CHARGE. 138 * 139 * 2. Capacity limits are permitted only if the sensor has the 140 * ENVSYS_FPERCENT flag set and value_max is set. 141 * 142 * 3. It is not permissible for both capacity and value limits 143 * to coexist. 144 * 145 * Note that it permissible for a sensor to have value limits 146 * even if its ENVSYS_FPERCENT flag and value_max are set. 147 */ 148 149 DPRINTF(("%s: units %d props 0x%04x upropset 0x%04x max_val %d" 150 " edata-flags 0x%04x\n", __func__, edata->units, props, 151 edata->upropset, edata->value_max, edata->flags)); 152 153 if (props) 154 if (edata->units == ENVSYS_INDICATOR || 155 edata->units == ENVSYS_BATTERY_CHARGE) 156 return ENOTSUP; 157 158 if ((props & PROP_CAP_LIMITS) && 159 ((edata->value_max == 0) || 160 !(edata->flags & ENVSYS_FPERCENT) || 161 (props & PROP_VAL_LIMITS) || 162 (edata->upropset & PROP_VAL_LIMITS))) 163 props = 0; 164 165 if ((props & PROP_VAL_LIMITS) && (edata->upropset & PROP_CAP_LIMITS)) 166 props = 0; 167 168 /* 169 * check if the event is already on the list and return 170 * EEXIST if value provided hasn't been changed. 171 */ 172 mutex_enter(&sme->sme_mtx); 173 LIST_FOREACH(osee, &sme->sme_events_list, see_list) { 174 if (strcmp(edata->desc, osee->see_pes.pes_sensname) != 0) 175 continue; 176 if (crittype != osee->see_type && 177 osee->see_type != PENVSYS_EVENT_NULL) 178 continue; 179 180 /* 181 * We found an existing event for this sensor. Make 182 * sure it references the correct edata 183 */ 184 KASSERT(edata == osee->see_edata); 185 186 DPRINTF(("%s: dev %s sensor %s: event type %d exists\n", 187 __func__, sme->sme_name, edata->desc, crittype)); 188 189 see = osee; 190 if (props & edata->upropset & (PROP_CRITMAX | PROP_BATTMAX)) { 191 if (lims->sel_critmax == edata->limits.sel_critmax) { 192 DPRINTF(("%s: critmax exists\n", __func__)); 193 error = EEXIST; 194 props &= ~(PROP_CRITMAX | PROP_BATTMAX); 195 } 196 } 197 if (props & edata->upropset & (PROP_WARNMAX | PROP_BATTHIGH)) { 198 if (lims->sel_warnmax == edata->limits.sel_warnmax) { 199 DPRINTF(("%s: warnmax exists\n", __func__)); 200 error = EEXIST; 201 props &= ~(PROP_WARNMAX | PROP_BATTHIGH); 202 } 203 } 204 if (props & edata->upropset & (PROP_WARNMIN | PROP_BATTWARN)) { 205 if (lims->sel_warnmin == edata->limits.sel_warnmin) { 206 DPRINTF(("%s: warnmin exists\n", __func__)); 207 error = EEXIST; 208 props &= ~(PROP_WARNMIN | PROP_BATTWARN); 209 } 210 } 211 if (props & edata->upropset & (PROP_CRITMIN | PROP_BATTCAP)) { 212 if (lims->sel_critmin == edata->limits.sel_critmin) { 213 DPRINTF(("%s: critmin exists\n", __func__)); 214 error = EEXIST; 215 props &= ~(PROP_CRITMIN | PROP_BATTCAP); 216 } 217 } 218 if (props && see->see_type == PENVSYS_EVENT_NULL) 219 see->see_type = crittype; 220 221 break; 222 } 223 if (crittype == PENVSYS_EVENT_NULL && see != NULL) { 224 mutex_exit(&sme->sme_mtx); 225 return EEXIST; 226 } 227 228 if (see == NULL) { 229 /* 230 * New event requested - allocate a sysmon_envsys event. 231 */ 232 see = kmem_zalloc(sizeof(*see), KM_SLEEP); 233 if (see == NULL) 234 return ENOMEM; 235 236 DPRINTF(("%s: dev %s sensor %s: new event\n", 237 __func__, sme->sme_name, edata->desc)); 238 239 see->see_type = crittype; 240 see->see_sme = sme; 241 see->see_edata = edata; 242 243 /* Initialize sensor type and previously-sent state */ 244 245 see->see_pes.pes_type = powertype; 246 247 switch (crittype) { 248 case PENVSYS_EVENT_CAPACITY: 249 see->see_evstate = ENVSYS_BATTERY_CAPACITY_NORMAL; 250 break; 251 case PENVSYS_EVENT_STATE_CHANGED: 252 if (edata->units == ENVSYS_BATTERY_CAPACITY) 253 see->see_evstate = 254 ENVSYS_BATTERY_CAPACITY_NORMAL; 255 else if (edata->units == ENVSYS_DRIVE) 256 see->see_evstate = ENVSYS_DRIVE_EMPTY; 257 else if (edata->units == ENVSYS_INDICATOR) 258 see->see_evstate = ENVSYS_SVALID; 259 else 260 panic("%s: bad units for " 261 "PENVSYS_EVENT_STATE_CHANGED", __func__); 262 break; 263 case PENVSYS_EVENT_CRITICAL: 264 case PENVSYS_EVENT_LIMITS: 265 default: 266 see->see_evstate = ENVSYS_SVALID; 267 break; 268 } 269 see->see_evvalue = 0; 270 271 (void)strlcpy(see->see_pes.pes_dvname, sme->sme_name, 272 sizeof(see->see_pes.pes_dvname)); 273 (void)strlcpy(see->see_pes.pes_sensname, edata->desc, 274 sizeof(see->see_pes.pes_sensname)); 275 } 276 277 /* 278 * Limit operation requested. 279 */ 280 for (op = limit_ops; op->name != NULL; op++) { 281 if (props & op->prop) { 282 objkey = op->name; 283 obj = prop_dictionary_get(sdict, objkey); 284 if (obj != NULL && 285 prop_object_type(obj) != PROP_TYPE_NUMBER) { 286 DPRINTF(("%s: (%s) %s object not TYPE_NUMBER\n", 287 __func__, sme->sme_name, objkey)); 288 error = ENOTSUP; 289 } else { 290 edata->limits.sel_limit_list[op->idx] = 291 lims->sel_limit_list[op->idx]; 292 error = sme_sensor_upint32(sdict, objkey, 293 lims->sel_limit_list[op->idx]); 294 DPRINTF(("%s: (%s) event [sensor=%s type=%d] " 295 "(%s updated)\n", __func__, sme->sme_name, 296 edata->desc, crittype, objkey)); 297 } 298 if (error && error != EEXIST) 299 goto out; 300 edata->upropset |= op->prop; 301 } 302 } 303 304 if (props & PROP_DRIVER_LIMITS) 305 edata->upropset |= PROP_DRIVER_LIMITS; 306 else 307 edata->upropset &= ~PROP_DRIVER_LIMITS; 308 309 DPRINTF(("%s: (%s) event registered (sensor=%s snum=%d type=%d " 310 "critmin=%" PRIu32 " warnmin=%" PRIu32 " warnmax=%" PRIu32 311 " critmax=%" PRIu32 " props 0x%04x)\n", __func__, 312 see->see_sme->sme_name, see->see_pes.pes_sensname, 313 edata->sensor, see->see_type, edata->limits.sel_critmin, 314 edata->limits.sel_warnmin, edata->limits.sel_warnmax, 315 edata->limits.sel_critmax, edata->upropset)); 316 /* 317 * Initialize the events framework if it wasn't initialized before. 318 */ 319 if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0) 320 error = sme_events_init(sme); 321 322 /* 323 * If driver requested notification, advise it of new 324 * limit values 325 */ 326 if (sme->sme_set_limits) 327 (*sme->sme_set_limits)(sme, edata, &(edata->limits), 328 &(edata->upropset)); 329 330 out: 331 if ((error == 0 || error == EEXIST) && osee == NULL) 332 LIST_INSERT_HEAD(&sme->sme_events_list, see, see_list); 333 334 mutex_exit(&sme->sme_mtx); 335 336 return error; 337 } 338 339 /* 340 * sme_event_unregister_all: 341 * 342 * + Unregisters all events associated with a sysmon envsys device. 343 */ 344 void 345 sme_event_unregister_all(struct sysmon_envsys *sme) 346 { 347 sme_event_t *see; 348 int evcounter = 0; 349 bool destroy = false; 350 351 KASSERT(sme != NULL); 352 353 mutex_enter(&sme->sme_mtx); 354 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 355 while (see->see_flags & SEE_EVENT_WORKING) 356 cv_wait(&sme->sme_condvar, &sme->sme_mtx); 357 358 if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0) 359 evcounter++; 360 } 361 362 DPRINTF(("%s: total events %d (%s)\n", __func__, 363 evcounter, sme->sme_name)); 364 365 while ((see = LIST_FIRST(&sme->sme_events_list))) { 366 if (evcounter == 0) 367 break; 368 369 if (strcmp(see->see_pes.pes_dvname, sme->sme_name) == 0) { 370 DPRINTF(("%s: event %s %d removed (%s)\n", __func__, 371 see->see_pes.pes_sensname, see->see_type, 372 sme->sme_name)); 373 sme_remove_event(see, sme); 374 375 evcounter--; 376 } 377 } 378 379 if (LIST_EMPTY(&sme->sme_events_list) && 380 sme->sme_flags & SME_CALLOUT_INITIALIZED) { 381 sme_events_halt_callout(sme); 382 destroy = true; 383 } 384 mutex_exit(&sme->sme_mtx); 385 386 if (destroy) 387 sme_events_destroy(sme); 388 } 389 390 /* 391 * sme_event_unregister: 392 * 393 * + Unregisters an event from the specified sysmon envsys device. 394 */ 395 int 396 sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type) 397 { 398 sme_event_t *see; 399 bool found = false; 400 bool destroy = false; 401 402 KASSERT(sensor != NULL); 403 404 mutex_enter(&sme->sme_mtx); 405 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 406 if (strcmp(see->see_pes.pes_sensname, sensor) == 0) { 407 if (see->see_type == type) { 408 found = true; 409 break; 410 } 411 } 412 } 413 414 if (!found) { 415 mutex_exit(&sme->sme_mtx); 416 return EINVAL; 417 } 418 419 /* 420 * Wait for the event to finish its work, remove it from the list 421 * and release resources. 422 */ 423 while (see->see_flags & SEE_EVENT_WORKING) 424 cv_wait(&sme->sme_condvar, &sme->sme_mtx); 425 426 DPRINTF(("%s: removed dev=%s sensor=%s type=%d\n", 427 __func__, see->see_pes.pes_dvname, sensor, type)); 428 429 sme_remove_event(see, sme); 430 431 if (LIST_EMPTY(&sme->sme_events_list)) { 432 sme_events_halt_callout(sme); 433 destroy = true; 434 } 435 mutex_exit(&sme->sme_mtx); 436 437 if (destroy) 438 sme_events_destroy(sme); 439 440 return 0; 441 } 442 443 /* 444 * sme_event_unregister_sensor: 445 * 446 * + Unregisters any event associated with a specific sensor 447 * The caller must already own the sme_mtx. 448 */ 449 int 450 sme_event_unregister_sensor(struct sysmon_envsys *sme, envsys_data_t *edata) 451 { 452 sme_event_t *see; 453 bool found = false; 454 455 KASSERT(mutex_owned(&sme->sme_mtx)); 456 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 457 if (see->see_edata == edata) { 458 found = true; 459 break; 460 } 461 } 462 if (!found) 463 return EINVAL; 464 465 /* 466 * Wait for the event to finish its work, remove it from the list 467 * and release resources. 468 */ 469 while (see->see_flags & SEE_EVENT_WORKING) 470 cv_wait(&sme->sme_condvar, &sme->sme_mtx); 471 472 DPRINTF(("%s: removed dev=%s sensor=%s\n", 473 __func__, see->see_pes.pes_dvname, edata->desc)); 474 475 sme_remove_event(see, sme); 476 477 return 0; 478 } 479 480 static void 481 sme_remove_event(sme_event_t *see, struct sysmon_envsys *sme) 482 { 483 484 KASSERT(mutex_owned(&sme->sme_mtx)); 485 486 if (see->see_edata->flags & ENVSYS_FHAS_ENTROPY) 487 rnd_detach_source(&see->see_edata->rnd_src); 488 LIST_REMOVE(see, see_list); 489 kmem_free(see, sizeof(*see)); 490 } 491 492 /* 493 * sme_event_drvadd: 494 * 495 * + Registers a new event for a device that had enabled any of 496 * the monitoring flags in the driver. 497 */ 498 void 499 sme_event_drvadd(void *arg) 500 { 501 sme_event_drv_t *sed_t = arg; 502 sysmon_envsys_lim_t lims; 503 uint32_t props; 504 int error = 0; 505 const struct ev_reg_t *reg; 506 507 KASSERT(sed_t != NULL); 508 509 /* 510 * If driver provides a method to retrieve its internal limit 511 * values, call it and use those returned values as initial 512 * limits for event monitoring. 513 */ 514 props = 0; 515 if (sed_t->sed_edata->flags & ENVSYS_FMONLIMITS) 516 if (sed_t->sed_sme->sme_get_limits) 517 (*sed_t->sed_sme->sme_get_limits)(sed_t->sed_sme, 518 sed_t->sed_edata, 519 &lims, &props); 520 /* 521 * If driver doesn't provide a way to "absorb" user-specified 522 * limit values, we must monitor all limits ourselves 523 */ 524 if (sed_t->sed_sme->sme_set_limits == NULL) 525 props &= ~PROP_DRIVER_LIMITS; 526 527 /* Register the events that were specified */ 528 529 for (reg = reg_events; reg->name != NULL; reg++) { 530 if (sed_t->sed_edata->flags & reg->crittype) { 531 532 error = sme_event_register(sed_t->sed_sdict, 533 sed_t->sed_edata, 534 sed_t->sed_sme, 535 &lims, props, 536 reg->powertype, 537 sed_t->sed_powertype); 538 if (error && error != EEXIST) 539 printf("%s: failed to add event! " 540 "error=%d sensor=%s event=%s\n", 541 __func__, error, 542 sed_t->sed_edata->desc, reg->name); 543 else { 544 char str[ENVSYS_DESCLEN] = "monitoring-state-"; 545 (void)strlcat(str, reg->name, sizeof(str)); 546 prop_dictionary_set_bool(sed_t->sed_sdict, 547 str, true); 548 } 549 } 550 } 551 552 /* 553 * we are done, free memory now. 554 */ 555 kmem_free(sed_t, sizeof(*sed_t)); 556 } 557 558 /* 559 * sme_events_init: 560 * 561 * + Initialize the events framework for this device. 562 */ 563 int 564 sme_events_init(struct sysmon_envsys *sme) 565 { 566 int error = 0; 567 568 KASSERT(sme != NULL); 569 KASSERT(mutex_owned(&sme->sme_mtx)); 570 571 error = workqueue_create(&sme->sme_wq, sme->sme_name, 572 sme_events_worker, sme, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE); 573 if (error) 574 return error; 575 576 callout_init(&sme->sme_callout, CALLOUT_MPSAFE); 577 callout_setfunc(&sme->sme_callout, sme_events_check, sme); 578 sme->sme_flags |= SME_CALLOUT_INITIALIZED; 579 sme_schedule_callout(sme); 580 DPRINTF(("%s: events framework initialized for '%s'\n", 581 __func__, sme->sme_name)); 582 583 return error; 584 } 585 586 /* 587 * sme_schedule_callout 588 * 589 * (Re)-schedule the device's callout timer 590 */ 591 void 592 sme_schedule_callout(struct sysmon_envsys *sme) 593 { 594 uint64_t timo; 595 596 KASSERT(sme != NULL); 597 598 if ((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0) 599 return; 600 601 if (sme->sme_events_timeout) 602 timo = sme->sme_events_timeout * hz; 603 else 604 timo = SME_EVTIMO; 605 606 callout_stop(&sme->sme_callout); 607 callout_schedule(&sme->sme_callout, timo); 608 } 609 610 /* 611 * sme_events_halt_callout: 612 * 613 * + Halt the callout of the event framework for this device. 614 */ 615 void 616 sme_events_halt_callout(struct sysmon_envsys *sme) 617 { 618 KASSERT(mutex_owned(&sme->sme_mtx)); 619 620 /* 621 * Unset before callout_halt to ensure callout is not scheduled again 622 * during callout_halt. 623 */ 624 sme->sme_flags &= ~SME_CALLOUT_INITIALIZED; 625 626 callout_halt(&sme->sme_callout, &sme->sme_mtx); 627 } 628 629 /* 630 * sme_events_destroy: 631 * 632 * + Destroy the callout and the workqueue of the event framework 633 * for this device. 634 */ 635 void 636 sme_events_destroy(struct sysmon_envsys *sme) 637 { 638 KASSERT(!mutex_owned(&sme->sme_mtx)); 639 KASSERT((sme->sme_flags & SME_CALLOUT_INITIALIZED) == 0); 640 641 callout_destroy(&sme->sme_callout); 642 workqueue_destroy(sme->sme_wq); 643 644 DPRINTF(("%s: events framework destroyed for '%s'\n", 645 __func__, sme->sme_name)); 646 } 647 648 /* 649 * sysmon_envsys_update_limits 650 * 651 * + If a driver needs to update the limits that it is providing, 652 * we need to update the dictionary data as well as the limits. 653 * This only makes sense if the driver is capable of providing 654 * its limits, and if there is a limits event-monitor. 655 */ 656 int 657 sysmon_envsys_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata) 658 { 659 int err; 660 661 sysmon_envsys_acquire(sme, false); 662 if (sme->sme_get_limits == NULL || 663 (edata->flags & ENVSYS_FMONLIMITS) == 0) 664 err = EINVAL; 665 else 666 err = sme_update_limits(sme, edata); 667 sysmon_envsys_release(sme, false); 668 669 return err; 670 } 671 672 /* 673 * sme_update_limits 674 * 675 * + Internal version of sysmon_envsys_update_limits() to be used 676 * when the device has already been sysmon_envsys_acquire()d. 677 */ 678 679 int 680 sme_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata) 681 { 682 prop_dictionary_t sdict = NULL; 683 prop_array_t array = NULL; 684 sysmon_envsys_lim_t lims; 685 sme_event_t *see; 686 uint32_t props = 0; 687 688 /* Find the dictionary for this sensor */ 689 array = prop_dictionary_get(sme_propd, sme->sme_name); 690 if (array == NULL || 691 prop_object_type(array) != PROP_TYPE_ARRAY) { 692 DPRINTF(("%s: array device failed\n", __func__)); 693 return EINVAL; 694 } 695 696 sdict = prop_array_get(array, edata->sensor); 697 if (sdict == NULL) { 698 return EINVAL; 699 } 700 701 /* Find the event definition to get its powertype */ 702 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 703 if (edata == see->see_edata && 704 see->see_type == PENVSYS_EVENT_LIMITS) 705 break; 706 } 707 if (see == NULL) 708 return EINVAL; 709 710 /* Update limit values from driver if possible */ 711 if (sme->sme_get_limits != NULL) 712 (*sme->sme_get_limits)(sme, edata, &lims, &props); 713 714 /* Update event and dictionary */ 715 sme_event_register(sdict, edata, sme, &lims, props, 716 PENVSYS_EVENT_LIMITS, see->see_pes.pes_type); 717 718 return 0; 719 } 720 721 /* 722 * sme_events_check: 723 * 724 * + Passes the events to the workqueue thread and stops 725 * the callout if the 'low-power' condition is triggered. 726 */ 727 void 728 sme_events_check(void *arg) 729 { 730 struct sysmon_envsys *sme = arg; 731 sme_event_t *see; 732 733 KASSERT(sme != NULL); 734 735 mutex_enter(&sme->sme_work_mtx); 736 if (sme->sme_busy > 0) { 737 log(LOG_WARNING, "%s: workqueue busy: updates stopped\n", 738 sme->sme_name); 739 mutex_exit(&sme->sme_work_mtx); 740 return; 741 } 742 if (!mutex_tryenter(&sme->sme_mtx)) { 743 /* can't get lock - try again later */ 744 if (!sysmon_low_power) 745 sme_schedule_callout(sme); 746 mutex_exit(&sme->sme_work_mtx); 747 return; 748 } 749 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 750 workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL); 751 see->see_edata->flags |= ENVSYS_FNEED_REFRESH; 752 sme->sme_busy++; 753 } 754 if (!sysmon_low_power) 755 sme_schedule_callout(sme); 756 mutex_exit(&sme->sme_work_mtx); 757 mutex_exit(&sme->sme_mtx); 758 } 759 760 /* 761 * sme_events_worker: 762 * 763 * + workqueue thread that checks if there's a critical condition 764 * and sends an event if it was triggered. 765 */ 766 void 767 sme_events_worker(struct work *wk, void *arg) 768 { 769 sme_event_t *see = (void *)wk; 770 struct sysmon_envsys *sme = see->see_sme; 771 envsys_data_t *edata = see->see_edata; 772 773 KASSERT(wk == &see->see_wk); 774 KASSERT(sme != NULL); 775 KASSERT(edata != NULL); 776 777 mutex_enter(&sme->sme_mtx); 778 see->see_flags |= SEE_EVENT_WORKING; 779 /* 780 * sme_events_check marks the sensors to make us refresh them here. 781 * sme_envsys_refresh_sensor will not call the driver if the driver 782 * does its own setting of the sensor value. 783 */ 784 if ((edata->flags & ENVSYS_FNEED_REFRESH) != 0) { 785 /* refresh sensor in device */ 786 sysmon_envsys_refresh_sensor(sme, edata); 787 edata->flags &= ~ENVSYS_FNEED_REFRESH; 788 } 789 790 DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d type=%d state=%d units=%d " 791 "value_cur=%d upropset=0x%04x\n", __func__, sme->sme_name, edata->desc, 792 edata->sensor, see->see_type, edata->state, edata->units, 793 edata->value_cur, edata->upropset)); 794 795 /* skip the event if current sensor is in invalid state */ 796 if (edata->state == ENVSYS_SINVALID) 797 goto out; 798 799 /* 800 * For range limits, if the driver claims responsibility for 801 * limit/range checking, just user driver-supplied status. 802 * Else calculate our own status. Note that driver must 803 * relinquish responsibility for ALL limits if there is even 804 * one limit that it cannot handle! 805 * 806 * If this is a CAPACITY monitor, but the sensor's max_value 807 * is not set, treat it as though the monitor does not exist. 808 */ 809 if ((see->see_type == PENVSYS_EVENT_LIMITS || 810 see->see_type == PENVSYS_EVENT_CAPACITY) && 811 (edata->upropset & PROP_DRIVER_LIMITS) == 0) { 812 if ((see->see_type == PENVSYS_EVENT_CAPACITY) && 813 (edata->value_max == 0)) 814 edata->state = ENVSYS_SVALID; 815 else if ((edata->upropset & (PROP_CRITMIN | PROP_BATTCAP)) && 816 (edata->value_cur < edata->limits.sel_critmin)) 817 edata->state = ENVSYS_SCRITUNDER; 818 else if ((edata->upropset & (PROP_WARNMIN | PROP_BATTWARN)) && 819 (edata->value_cur < edata->limits.sel_warnmin)) 820 edata->state = ENVSYS_SWARNUNDER; 821 else if ((edata->upropset & (PROP_CRITMAX | PROP_BATTMAX)) && 822 (edata->value_cur > edata->limits.sel_critmax)) 823 edata->state = ENVSYS_SCRITOVER; 824 else if ((edata->upropset & (PROP_WARNMAX | PROP_BATTHIGH)) && 825 (edata->value_cur > edata->limits.sel_warnmax)) 826 edata->state = ENVSYS_SWARNOVER; 827 else 828 edata->state = ENVSYS_SVALID; 829 } 830 sme_deliver_event(see); 831 832 out: 833 see->see_flags &= ~SEE_EVENT_WORKING; 834 cv_broadcast(&sme->sme_condvar); 835 mutex_enter(&sme->sme_work_mtx); 836 KASSERT(sme->sme_busy > 0); 837 sme->sme_busy--; 838 mutex_exit(&sme->sme_work_mtx); 839 mutex_exit(&sme->sme_mtx); 840 } 841 842 /* 843 * sysmon_envsys_sensor_event 844 * 845 * + Find the monitor event of a particular type for a given sensor 846 * on a device and deliver the event if one is required. If 847 * no event type is specified, deliver all events for the sensor. 848 */ 849 void 850 sysmon_envsys_sensor_event(struct sysmon_envsys *sme, envsys_data_t *edata, 851 int ev_type) 852 { 853 sme_event_t *see; 854 855 mutex_enter(&sme->sme_mtx); 856 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 857 if (edata != see->see_edata) 858 continue; 859 if (ev_type == 0 || 860 ev_type == see->see_type) { 861 sme_deliver_event(see); 862 if (ev_type != 0) 863 break; 864 } 865 } 866 mutex_exit(&sme->sme_mtx); 867 } 868 869 /* 870 * sme_deliver_event: 871 * 872 * + If new sensor state requires it, send an event to powerd 873 * 874 * Must be called with the device's sysmon mutex held 875 * see->see_sme->sme_mtx 876 */ 877 void 878 sme_deliver_event(sme_event_t *see) 879 { 880 envsys_data_t *edata = see->see_edata; 881 const struct sme_descr_entry *sdt = NULL; 882 const struct sme_sensor_event *sse = sme_sensor_event; 883 int i, state = 0; 884 885 switch (see->see_type) { 886 case PENVSYS_EVENT_LIMITS: 887 case PENVSYS_EVENT_CAPACITY: 888 /* 889 * Send event if state has changed 890 */ 891 if (edata->state == see->see_evstate) 892 break; 893 894 for (i = 0; sse[i].state != -1; i++) 895 if (sse[i].state == edata->state) 896 break; 897 898 if (sse[i].state == -1) 899 break; 900 901 if (edata->state == ENVSYS_SVALID) 902 sysmon_penvsys_event(&see->see_pes, 903 PENVSYS_EVENT_NORMAL); 904 else 905 sysmon_penvsys_event(&see->see_pes, sse[i].event); 906 907 see->see_evstate = edata->state; 908 DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d state=%d send_ev=%d\n", 909 __func__, see->see_sme->sme_name, edata->desc, 910 edata->sensor, edata->state, 911 (edata->state == ENVSYS_SVALID) ? PENVSYS_EVENT_NORMAL : 912 sse[i].event)); 913 914 break; 915 916 /* 917 * Send PENVSYS_EVENT_CRITICAL event if: 918 * State has gone from non-CRITICAL to CRITICAL, 919 * State remains CRITICAL and value has changed, or 920 * State has returned from CRITICAL to non-CRITICAL 921 */ 922 case PENVSYS_EVENT_CRITICAL: 923 DPRINTF(("%s: CRITICAL: old/new state %d/%d, old/new value " 924 "%d/%d\n", __func__, see->see_evstate, edata->state, 925 see->see_evvalue, edata->value_cur)); 926 if (edata->state == ENVSYS_SVALID && 927 see->see_evstate != ENVSYS_SVALID) { 928 sysmon_penvsys_event(&see->see_pes, 929 PENVSYS_EVENT_NORMAL); 930 see->see_evstate = ENVSYS_SVALID; 931 break; 932 } else if (edata->state != ENVSYS_SCRITICAL) 933 break; 934 if (see->see_evstate != ENVSYS_SCRITICAL || 935 see->see_evvalue != edata->value_cur) { 936 sysmon_penvsys_event(&see->see_pes, 937 PENVSYS_EVENT_CRITICAL); 938 see->see_evstate = ENVSYS_SCRITICAL; 939 } 940 see->see_evvalue = edata->value_cur; 941 break; 942 943 /* 944 * if value_cur is not normal (battery) or online (drive), 945 * send the event... 946 */ 947 case PENVSYS_EVENT_STATE_CHANGED: 948 /* 949 * the state has not been changed, just ignore the event. 950 */ 951 if (edata->value_cur == see->see_evvalue) 952 break; 953 954 switch (edata->units) { 955 case ENVSYS_DRIVE: 956 sdt = sme_find_table_entry(SME_DESC_DRIVE_STATES, 957 edata->value_cur); 958 state = ENVSYS_DRIVE_ONLINE; 959 break; 960 case ENVSYS_BATTERY_CAPACITY: 961 sdt = sme_find_table_entry(SME_DESC_BATTERY_CAPACITY, 962 edata->value_cur); 963 state = ENVSYS_BATTERY_CAPACITY_NORMAL; 964 break; 965 case ENVSYS_INDICATOR: 966 sdt = sme_find_table_entry(SME_DESC_INDICATOR, 967 edata->value_cur); 968 state = see->see_evvalue; /* force state change */ 969 break; 970 default: 971 panic("%s: bad units for PENVSYS_EVENT_STATE_CHANGED", 972 __func__); 973 } 974 975 if (sdt->type == -1) 976 break; 977 978 /* 979 * copy current state description. 980 */ 981 (void)strlcpy(see->see_pes.pes_statedesc, sdt->desc, 982 sizeof(see->see_pes.pes_statedesc)); 983 984 if (edata->value_cur == state) 985 /* 986 * state returned to normal condition 987 */ 988 sysmon_penvsys_event(&see->see_pes, 989 PENVSYS_EVENT_NORMAL); 990 else 991 /* 992 * state changed to abnormal condition 993 */ 994 sysmon_penvsys_event(&see->see_pes, see->see_type); 995 996 see->see_evvalue = edata->value_cur; 997 998 /* 999 * There's no need to continue if it's a drive sensor. 1000 */ 1001 if (edata->units == ENVSYS_DRIVE) 1002 break; 1003 1004 /* 1005 * Check if the system is running in low power and send the 1006 * event to powerd (if running) or shutdown the system 1007 * otherwise. 1008 */ 1009 if (!sysmon_low_power && sme_event_check_low_power()) { 1010 struct penvsys_state pes; 1011 1012 /* 1013 * Stop the callout and send the 'low-power' event. 1014 */ 1015 sysmon_low_power = true; 1016 callout_stop(&see->see_sme->sme_callout); 1017 pes.pes_type = PENVSYS_TYPE_BATTERY; 1018 sysmon_penvsys_event(&pes, PENVSYS_EVENT_LOW_POWER); 1019 } 1020 break; 1021 case PENVSYS_EVENT_NULL: 1022 break; 1023 default: 1024 panic("%s: invalid event type %d", __func__, see->see_type); 1025 } 1026 } 1027 1028 /* 1029 * Returns true if the system is in low power state: an AC adapter 1030 * is OFF and all batteries are in LOW/CRITICAL state. 1031 */ 1032 static bool 1033 sme_event_check_low_power(void) 1034 { 1035 if (!sme_acadapter_check()) 1036 return false; 1037 1038 return sme_battery_check(); 1039 } 1040 1041 /* 1042 * Called with the sysmon_envsys device mtx held through the 1043 * workqueue thread. 1044 */ 1045 static bool 1046 sme_acadapter_check(void) 1047 { 1048 struct sysmon_envsys *sme; 1049 envsys_data_t *edata; 1050 bool dev = false, sensor = false; 1051 1052 LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) { 1053 if (sme->sme_class == SME_CLASS_ACADAPTER) { 1054 dev = true; 1055 break; 1056 } 1057 } 1058 1059 /* 1060 * No AC Adapter devices were found. 1061 */ 1062 if (!dev) 1063 return false; 1064 1065 /* 1066 * Check if there's an AC adapter device connected. 1067 */ 1068 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1069 if (edata->units == ENVSYS_INDICATOR) { 1070 sensor = true; 1071 /* refresh current sensor */ 1072 sysmon_envsys_refresh_sensor(sme, edata); 1073 1074 if (edata->value_cur) 1075 return false; 1076 } 1077 } 1078 1079 if (!sensor) 1080 return false; 1081 1082 /* 1083 * AC adapter found and not connected. 1084 */ 1085 return true; 1086 } 1087 1088 /* 1089 * Called with the sysmon_envsys device mtx held through the 1090 * workqueue thread. 1091 */ 1092 static bool 1093 sme_battery_check(void) 1094 { 1095 struct sysmon_envsys *sme; 1096 envsys_data_t *edata; 1097 int batteriesfound = 0; 1098 bool present, batterycap, batterycharge; 1099 1100 /* 1101 * Check for battery devices and its state. 1102 */ 1103 LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) { 1104 if (sme->sme_class != SME_CLASS_BATTERY) 1105 continue; 1106 1107 present = true; 1108 1109 /* 1110 * XXX 1111 * this assumes that the first valid ENVSYS_INDICATOR is the 1112 * presence indicator 1113 */ 1114 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1115 if ((edata->units == ENVSYS_INDICATOR) && 1116 (edata->state == ENVSYS_SVALID)) { 1117 present = edata->value_cur; 1118 break; 1119 } 1120 } 1121 if (!present) 1122 continue; 1123 /* 1124 * We've found a battery device... 1125 */ 1126 batteriesfound++; 1127 batterycap = batterycharge = false; 1128 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1129 /* no need to even look at sensors that aren't valid */ 1130 if (edata->state != ENVSYS_SVALID) 1131 continue; 1132 if (edata->units == ENVSYS_BATTERY_CAPACITY) { 1133 batterycap = true; 1134 if (!sme_battery_critical(edata)) 1135 return false; 1136 } else if (edata->units == ENVSYS_BATTERY_CHARGE) { 1137 batterycharge = true; 1138 if (edata->value_cur) 1139 return false; 1140 } 1141 } 1142 if (!batterycap || !batterycharge) 1143 return false; 1144 } 1145 1146 if (!batteriesfound) 1147 return false; 1148 1149 /* 1150 * All batteries in low/critical capacity and discharging. 1151 */ 1152 return true; 1153 } 1154 1155 static bool 1156 sme_battery_critical(envsys_data_t *edata) 1157 { 1158 if (edata->value_cur == ENVSYS_BATTERY_CAPACITY_CRITICAL || 1159 edata->value_cur == ENVSYS_BATTERY_CAPACITY_LOW) 1160 return true; 1161 1162 return false; 1163 } 1164