1 /* $NetBSD: sysmon_envsys_events.c,v 1.123 2021/12/31 14:30:04 riastradh 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.123 2021/12/31 14:30:04 riastradh 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 DPRINTF(("%s: dev %s sensor %s: new event\n", 234 __func__, sme->sme_name, edata->desc)); 235 236 see->see_type = crittype; 237 see->see_sme = sme; 238 see->see_edata = edata; 239 240 /* Initialize sensor type and previously-sent state */ 241 242 see->see_pes.pes_type = powertype; 243 244 switch (crittype) { 245 case PENVSYS_EVENT_CAPACITY: 246 see->see_evstate = ENVSYS_BATTERY_CAPACITY_NORMAL; 247 break; 248 case PENVSYS_EVENT_STATE_CHANGED: 249 if (edata->units == ENVSYS_BATTERY_CAPACITY) 250 see->see_evstate = 251 ENVSYS_BATTERY_CAPACITY_NORMAL; 252 else if (edata->units == ENVSYS_DRIVE) 253 see->see_evstate = ENVSYS_DRIVE_EMPTY; 254 else if (edata->units == ENVSYS_INDICATOR) 255 see->see_evstate = ENVSYS_SVALID; 256 else 257 panic("%s: bad units for " 258 "PENVSYS_EVENT_STATE_CHANGED", __func__); 259 break; 260 case PENVSYS_EVENT_CRITICAL: 261 case PENVSYS_EVENT_LIMITS: 262 default: 263 see->see_evstate = ENVSYS_SVALID; 264 break; 265 } 266 see->see_evvalue = 0; 267 268 (void)strlcpy(see->see_pes.pes_dvname, sme->sme_name, 269 sizeof(see->see_pes.pes_dvname)); 270 (void)strlcpy(see->see_pes.pes_sensname, edata->desc, 271 sizeof(see->see_pes.pes_sensname)); 272 } 273 274 /* 275 * Limit operation requested. 276 */ 277 for (op = limit_ops; op->name != NULL; op++) { 278 if (props & op->prop) { 279 objkey = op->name; 280 obj = prop_dictionary_get(sdict, objkey); 281 if (obj != NULL && 282 prop_object_type(obj) != PROP_TYPE_NUMBER) { 283 DPRINTF(("%s: (%s) %s object not TYPE_NUMBER\n", 284 __func__, sme->sme_name, objkey)); 285 error = ENOTSUP; 286 } else { 287 edata->limits.sel_limit_list[op->idx] = 288 lims->sel_limit_list[op->idx]; 289 error = sme_sensor_upint32(sdict, objkey, 290 lims->sel_limit_list[op->idx]); 291 DPRINTF(("%s: (%s) event [sensor=%s type=%d] " 292 "(%s updated)\n", __func__, sme->sme_name, 293 edata->desc, crittype, objkey)); 294 } 295 if (error && error != EEXIST) 296 goto out; 297 edata->upropset |= op->prop; 298 } 299 } 300 301 if (props & PROP_DRIVER_LIMITS) 302 edata->upropset |= PROP_DRIVER_LIMITS; 303 else 304 edata->upropset &= ~PROP_DRIVER_LIMITS; 305 306 DPRINTF(("%s: (%s) event registered (sensor=%s snum=%d type=%d " 307 "critmin=%" PRIu32 " warnmin=%" PRIu32 " warnmax=%" PRIu32 308 " critmax=%" PRIu32 " props 0x%04x)\n", __func__, 309 see->see_sme->sme_name, see->see_pes.pes_sensname, 310 edata->sensor, see->see_type, edata->limits.sel_critmin, 311 edata->limits.sel_warnmin, edata->limits.sel_warnmax, 312 edata->limits.sel_critmax, edata->upropset)); 313 /* 314 * Initialize the events framework if it wasn't initialized before. 315 */ 316 if (sme->sme_callout_state == SME_CALLOUT_INVALID) 317 error = sme_events_init(sme); 318 319 /* 320 * If driver requested notification, advise it of new 321 * limit values 322 */ 323 if (sme->sme_set_limits) 324 (*sme->sme_set_limits)(sme, edata, &(edata->limits), 325 &(edata->upropset)); 326 327 out: 328 if ((error == 0 || error == EEXIST) && osee == NULL) { 329 mutex_enter(&sme->sme_work_mtx); 330 LIST_INSERT_HEAD(&sme->sme_events_list, see, see_list); 331 mutex_exit(&sme->sme_work_mtx); 332 } 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 mutex_enter(&sme->sme_work_mtx); 380 if (LIST_EMPTY(&sme->sme_events_list) && 381 sme->sme_callout_state == SME_CALLOUT_READY) { 382 sme_events_halt_callout(sme); 383 destroy = true; 384 } 385 mutex_exit(&sme->sme_work_mtx); 386 mutex_exit(&sme->sme_mtx); 387 388 if (destroy) 389 sme_events_destroy(sme); 390 } 391 392 /* 393 * sme_event_unregister: 394 * 395 * + Unregisters an event from the specified sysmon envsys device. 396 */ 397 int 398 sme_event_unregister(struct sysmon_envsys *sme, const char *sensor, int type) 399 { 400 sme_event_t *see; 401 bool found = false; 402 bool destroy = false; 403 404 KASSERT(sensor != NULL); 405 406 mutex_enter(&sme->sme_mtx); 407 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 408 if (strcmp(see->see_pes.pes_sensname, sensor) == 0) { 409 if (see->see_type == type) { 410 found = true; 411 break; 412 } 413 } 414 } 415 416 if (!found) { 417 mutex_exit(&sme->sme_mtx); 418 return EINVAL; 419 } 420 421 /* 422 * Wait for the event to finish its work, remove it from the list 423 * and release resources. 424 */ 425 while (see->see_flags & SEE_EVENT_WORKING) 426 cv_wait(&sme->sme_condvar, &sme->sme_mtx); 427 428 DPRINTF(("%s: removed dev=%s sensor=%s type=%d\n", 429 __func__, see->see_pes.pes_dvname, sensor, type)); 430 431 sme_remove_event(see, sme); 432 433 mutex_enter(&sme->sme_work_mtx); 434 if (LIST_EMPTY(&sme->sme_events_list)) { 435 sme_events_halt_callout(sme); 436 destroy = true; 437 } 438 mutex_exit(&sme->sme_work_mtx); 439 mutex_exit(&sme->sme_mtx); 440 441 if (destroy) 442 sme_events_destroy(sme); 443 444 return 0; 445 } 446 447 /* 448 * sme_event_unregister_sensor: 449 * 450 * + Unregisters any event associated with a specific sensor 451 * The caller must already own the sme_mtx. 452 */ 453 int 454 sme_event_unregister_sensor(struct sysmon_envsys *sme, envsys_data_t *edata) 455 { 456 sme_event_t *see; 457 bool found = false; 458 459 KASSERT(mutex_owned(&sme->sme_mtx)); 460 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 461 if (see->see_edata == edata) { 462 found = true; 463 break; 464 } 465 } 466 if (!found) 467 return EINVAL; 468 469 /* 470 * Wait for the event to finish its work, remove it from the list 471 * and release resources. 472 */ 473 while (see->see_flags & SEE_EVENT_WORKING) 474 cv_wait(&sme->sme_condvar, &sme->sme_mtx); 475 476 DPRINTF(("%s: removed dev=%s sensor=%s\n", 477 __func__, see->see_pes.pes_dvname, edata->desc)); 478 479 sme_remove_event(see, sme); 480 481 return 0; 482 } 483 484 static void 485 sme_remove_event(sme_event_t *see, struct sysmon_envsys *sme) 486 { 487 488 KASSERT(mutex_owned(&sme->sme_mtx)); 489 490 mutex_enter(&sme->sme_work_mtx); 491 LIST_REMOVE(see, see_list); 492 mutex_exit(&sme->sme_work_mtx); 493 494 kmem_free(see, sizeof(*see)); 495 } 496 497 /* 498 * sme_event_drvadd: 499 * 500 * + Registers a new event for a device that had enabled any of 501 * the monitoring flags in the driver. 502 */ 503 void 504 sme_event_drvadd(void *arg) 505 { 506 sme_event_drv_t *sed_t = arg; 507 sysmon_envsys_lim_t lims; 508 uint32_t props; 509 int error = 0; 510 const struct ev_reg_t *reg; 511 512 KASSERT(sed_t != NULL); 513 514 /* 515 * If driver provides a method to retrieve its internal limit 516 * values, call it and use those returned values as initial 517 * limits for event monitoring. 518 */ 519 props = 0; 520 if (sed_t->sed_edata->flags & ENVSYS_FMONLIMITS) 521 if (sed_t->sed_sme->sme_get_limits) 522 (*sed_t->sed_sme->sme_get_limits)(sed_t->sed_sme, 523 sed_t->sed_edata, 524 &lims, &props); 525 /* 526 * If driver doesn't provide a way to "absorb" user-specified 527 * limit values, we must monitor all limits ourselves 528 */ 529 if (sed_t->sed_sme->sme_set_limits == NULL) 530 props &= ~PROP_DRIVER_LIMITS; 531 532 /* Register the events that were specified */ 533 534 for (reg = reg_events; reg->name != NULL; reg++) { 535 if (sed_t->sed_edata->flags & reg->crittype) { 536 537 error = sme_event_register(sed_t->sed_sdict, 538 sed_t->sed_edata, 539 sed_t->sed_sme, 540 &lims, props, 541 reg->powertype, 542 sed_t->sed_powertype); 543 if (error && error != EEXIST) 544 printf("%s: failed to add event! " 545 "error=%d sensor=%s event=%s\n", 546 __func__, error, 547 sed_t->sed_edata->desc, reg->name); 548 else { 549 char str[ENVSYS_DESCLEN] = "monitoring-state-"; 550 (void)strlcat(str, reg->name, sizeof(str)); 551 prop_dictionary_set_bool(sed_t->sed_sdict, 552 str, true); 553 } 554 } 555 } 556 557 /* 558 * we are done, free memory now. 559 */ 560 kmem_free(sed_t, sizeof(*sed_t)); 561 } 562 563 /* 564 * sme_events_init: 565 * 566 * + Initialize the events framework for this device. 567 */ 568 int 569 sme_events_init(struct sysmon_envsys *sme) 570 { 571 int error = 0; 572 573 KASSERT(sme != NULL); 574 KASSERT(mutex_owned(&sme->sme_mtx)); 575 576 error = workqueue_create(&sme->sme_wq, sme->sme_name, 577 sme_events_worker, sme, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE); 578 if (error) 579 return error; 580 581 callout_init(&sme->sme_callout, CALLOUT_MPSAFE); 582 callout_setfunc(&sme->sme_callout, sme_events_check, sme); 583 584 mutex_enter(&sme->sme_work_mtx); 585 sme->sme_callout_state = SME_CALLOUT_READY; 586 sme_schedule_callout(sme); 587 mutex_exit(&sme->sme_work_mtx); 588 589 DPRINTF(("%s: events framework initialized for '%s'\n", 590 __func__, sme->sme_name)); 591 592 return error; 593 } 594 595 /* 596 * sme_schedule_callout 597 * 598 * (Re)-schedule the device's callout timer 599 */ 600 void 601 sme_schedule_callout(struct sysmon_envsys *sme) 602 { 603 uint64_t timo; 604 605 KASSERT(sme != NULL); 606 KASSERT(mutex_owned(&sme->sme_work_mtx)); 607 608 if (sme->sme_callout_state != SME_CALLOUT_READY) 609 return; 610 611 if (sme->sme_events_timeout) 612 timo = sme->sme_events_timeout * hz; 613 else 614 timo = SME_EVTIMO; 615 616 callout_schedule(&sme->sme_callout, timo); 617 } 618 619 /* 620 * sme_events_halt_callout: 621 * 622 * + Halt the callout of the event framework for this device. 623 */ 624 void 625 sme_events_halt_callout(struct sysmon_envsys *sme) 626 { 627 628 KASSERT(mutex_owned(&sme->sme_mtx)); 629 KASSERT(sme->sme_callout_state == SME_CALLOUT_READY); 630 631 /* 632 * Set HALTED before callout_halt to ensure callout is not 633 * scheduled again during callout_halt. (callout_halt() 634 * can potentially release the mutex, so an active callout 635 * could reschedule itself if it grabs the mutex.) 636 */ 637 638 sme->sme_callout_state = SME_CALLOUT_HALTED; 639 callout_halt(&sme->sme_callout, &sme->sme_mtx); 640 } 641 642 /* 643 * sme_events_destroy: 644 * 645 * + Destroy the callout and the workqueue of the event framework 646 * for this device. 647 */ 648 void 649 sme_events_destroy(struct sysmon_envsys *sme) 650 { 651 652 KASSERT(!mutex_owned(&sme->sme_mtx)); 653 654 if (sme->sme_callout_state == SME_CALLOUT_HALTED) { 655 callout_destroy(&sme->sme_callout); 656 sme->sme_callout_state = SME_CALLOUT_INVALID; 657 workqueue_destroy(sme->sme_wq); 658 } 659 KASSERT(sme->sme_callout_state == SME_CALLOUT_INVALID); 660 661 DPRINTF(("%s: events framework destroyed for '%s'\n", 662 __func__, sme->sme_name)); 663 } 664 665 /* 666 * sysmon_envsys_update_limits 667 * 668 * + If a driver needs to update the limits that it is providing, 669 * we need to update the dictionary data as well as the limits. 670 * This only makes sense if the driver is capable of providing 671 * its limits, and if there is a limits event-monitor. 672 */ 673 int 674 sysmon_envsys_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata) 675 { 676 int err; 677 678 sysmon_envsys_acquire(sme, false); 679 if (sme->sme_get_limits == NULL || 680 (edata->flags & ENVSYS_FMONLIMITS) == 0) 681 err = EINVAL; 682 else 683 err = sme_update_limits(sme, edata); 684 sysmon_envsys_release(sme, false); 685 686 return err; 687 } 688 689 /* 690 * sme_update_limits 691 * 692 * + Internal version of sysmon_envsys_update_limits() to be used 693 * when the device has already been sysmon_envsys_acquire()d. 694 */ 695 696 int 697 sme_update_limits(struct sysmon_envsys *sme, envsys_data_t *edata) 698 { 699 prop_dictionary_t sdict = NULL; 700 prop_array_t array = NULL; 701 sysmon_envsys_lim_t lims; 702 sme_event_t *see; 703 uint32_t props = 0; 704 705 /* Find the dictionary for this sensor */ 706 array = prop_dictionary_get(sme_propd, sme->sme_name); 707 if (array == NULL || 708 prop_object_type(array) != PROP_TYPE_ARRAY) { 709 DPRINTF(("%s: array device failed\n", __func__)); 710 return EINVAL; 711 } 712 713 sdict = prop_array_get(array, edata->sensor); 714 if (sdict == NULL) { 715 return EINVAL; 716 } 717 718 /* Find the event definition to get its powertype */ 719 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 720 if (edata == see->see_edata && 721 see->see_type == PENVSYS_EVENT_LIMITS) 722 break; 723 } 724 if (see == NULL) 725 return EINVAL; 726 727 /* Update limit values from driver if possible */ 728 if (sme->sme_get_limits != NULL) 729 (*sme->sme_get_limits)(sme, edata, &lims, &props); 730 731 /* Update event and dictionary */ 732 sme_event_register(sdict, edata, sme, &lims, props, 733 PENVSYS_EVENT_LIMITS, see->see_pes.pes_type); 734 735 return 0; 736 } 737 738 /* 739 * sme_events_check: 740 * 741 * + Passes the events to the workqueue thread and stops 742 * the callout if the 'low-power' condition is triggered. 743 */ 744 void 745 sme_events_check(void *arg) 746 { 747 struct sysmon_envsys *sme = arg; 748 sme_event_t *see; 749 750 KASSERT(sme != NULL); 751 752 mutex_enter(&sme->sme_work_mtx); 753 if (sme->sme_busy > 0) { 754 log(LOG_WARNING, "%s: workqueue busy: updates stopped\n", 755 sme->sme_name); 756 mutex_exit(&sme->sme_work_mtx); 757 return; 758 } 759 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 760 workqueue_enqueue(sme->sme_wq, &see->see_wk, NULL); 761 see->see_edata->flags |= ENVSYS_FNEED_REFRESH; 762 sme->sme_busy++; 763 } 764 if (!sysmon_low_power) 765 sme_schedule_callout(sme); 766 mutex_exit(&sme->sme_work_mtx); 767 } 768 769 /* 770 * sme_events_worker: 771 * 772 * + workqueue thread that checks if there's a critical condition 773 * and sends an event if it was triggered. 774 */ 775 void 776 sme_events_worker(struct work *wk, void *arg) 777 { 778 sme_event_t *see = (void *)wk; 779 struct sysmon_envsys *sme = see->see_sme; 780 envsys_data_t *edata = see->see_edata; 781 782 KASSERT(wk == &see->see_wk); 783 KASSERT(sme != NULL); 784 KASSERT(edata != NULL); 785 786 mutex_enter(&sme->sme_mtx); 787 see->see_flags |= SEE_EVENT_WORKING; 788 /* 789 * sme_events_check marks the sensors to make us refresh them here. 790 * sme_envsys_refresh_sensor will not call the driver if the driver 791 * does its own setting of the sensor value. 792 */ 793 mutex_enter(&sme->sme_work_mtx); 794 if ((edata->flags & ENVSYS_FNEED_REFRESH) != 0) { 795 /* refresh sensor in device */ 796 mutex_exit(&sme->sme_work_mtx); 797 sysmon_envsys_refresh_sensor(sme, edata); 798 mutex_enter(&sme->sme_work_mtx); 799 edata->flags &= ~ENVSYS_FNEED_REFRESH; 800 } 801 mutex_exit(&sme->sme_work_mtx); 802 803 DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d type=%d state=%d units=%d " 804 "value_cur=%d upropset=0x%04x\n", __func__, sme->sme_name, edata->desc, 805 edata->sensor, see->see_type, edata->state, edata->units, 806 edata->value_cur, edata->upropset)); 807 808 /* skip the event if current sensor is in invalid state */ 809 if (edata->state == ENVSYS_SINVALID) 810 goto out; 811 812 /* 813 * For range limits, if the driver claims responsibility for 814 * limit/range checking, just user driver-supplied status. 815 * Else calculate our own status. Note that driver must 816 * relinquish responsibility for ALL limits if there is even 817 * one limit that it cannot handle! 818 * 819 * If this is a CAPACITY monitor, but the sensor's max_value 820 * is not set, treat it as though the monitor does not exist. 821 */ 822 if ((see->see_type == PENVSYS_EVENT_LIMITS || 823 see->see_type == PENVSYS_EVENT_CAPACITY) && 824 (edata->upropset & PROP_DRIVER_LIMITS) == 0) { 825 if ((see->see_type == PENVSYS_EVENT_CAPACITY) && 826 (edata->value_max == 0)) 827 edata->state = ENVSYS_SVALID; 828 else if ((edata->upropset & (PROP_CRITMIN | PROP_BATTCAP)) && 829 (edata->value_cur < edata->limits.sel_critmin)) 830 edata->state = ENVSYS_SCRITUNDER; 831 else if ((edata->upropset & (PROP_WARNMIN | PROP_BATTWARN)) && 832 (edata->value_cur < edata->limits.sel_warnmin)) 833 edata->state = ENVSYS_SWARNUNDER; 834 else if ((edata->upropset & (PROP_CRITMAX | PROP_BATTMAX)) && 835 (edata->value_cur > edata->limits.sel_critmax)) 836 edata->state = ENVSYS_SCRITOVER; 837 else if ((edata->upropset & (PROP_WARNMAX | PROP_BATTHIGH)) && 838 (edata->value_cur > edata->limits.sel_warnmax)) 839 edata->state = ENVSYS_SWARNOVER; 840 else 841 edata->state = ENVSYS_SVALID; 842 } 843 sme_deliver_event(see); 844 845 out: 846 see->see_flags &= ~SEE_EVENT_WORKING; 847 cv_broadcast(&sme->sme_condvar); 848 mutex_enter(&sme->sme_work_mtx); 849 KASSERT(sme->sme_busy > 0); 850 sme->sme_busy--; 851 mutex_exit(&sme->sme_work_mtx); 852 mutex_exit(&sme->sme_mtx); 853 } 854 855 /* 856 * sysmon_envsys_sensor_event 857 * 858 * + Find the monitor event of a particular type for a given sensor 859 * on a device and deliver the event if one is required. If 860 * no event type is specified, deliver all events for the sensor. 861 */ 862 void 863 sysmon_envsys_sensor_event(struct sysmon_envsys *sme, envsys_data_t *edata, 864 int ev_type) 865 { 866 sme_event_t *see; 867 868 mutex_enter(&sme->sme_mtx); 869 LIST_FOREACH(see, &sme->sme_events_list, see_list) { 870 if (edata != see->see_edata) 871 continue; 872 if (ev_type == 0 || 873 ev_type == see->see_type) { 874 sme_deliver_event(see); 875 if (ev_type != 0) 876 break; 877 } 878 } 879 mutex_exit(&sme->sme_mtx); 880 } 881 882 /* 883 * sme_deliver_event: 884 * 885 * + If new sensor state requires it, send an event to powerd 886 * 887 * Must be called with the device's sysmon mutex held 888 * see->see_sme->sme_mtx 889 */ 890 void 891 sme_deliver_event(sme_event_t *see) 892 { 893 envsys_data_t *edata = see->see_edata; 894 const struct sme_descr_entry *sdt = NULL; 895 const struct sme_sensor_event *sse = sme_sensor_event; 896 int i, state = 0; 897 898 switch (see->see_type) { 899 case PENVSYS_EVENT_LIMITS: 900 case PENVSYS_EVENT_CAPACITY: 901 /* 902 * Send event if state has changed 903 */ 904 if (edata->state == see->see_evstate) 905 break; 906 907 for (i = 0; sse[i].state != -1; i++) 908 if (sse[i].state == edata->state) 909 break; 910 911 if (sse[i].state == -1) 912 break; 913 914 if (edata->state == ENVSYS_SVALID) 915 sysmon_penvsys_event(&see->see_pes, 916 PENVSYS_EVENT_NORMAL); 917 else 918 sysmon_penvsys_event(&see->see_pes, sse[i].event); 919 920 see->see_evstate = edata->state; 921 DPRINTFOBJ(("%s: (%s) desc=%s sensor=%d state=%d send_ev=%d\n", 922 __func__, see->see_sme->sme_name, edata->desc, 923 edata->sensor, edata->state, 924 (edata->state == ENVSYS_SVALID) ? PENVSYS_EVENT_NORMAL : 925 sse[i].event)); 926 927 break; 928 929 /* 930 * Send PENVSYS_EVENT_CRITICAL event if: 931 * State has gone from non-CRITICAL to CRITICAL, 932 * State remains CRITICAL and value has changed, or 933 * State has returned from CRITICAL to non-CRITICAL 934 */ 935 case PENVSYS_EVENT_CRITICAL: 936 DPRINTF(("%s: CRITICAL: old/new state %d/%d, old/new value " 937 "%d/%d\n", __func__, see->see_evstate, edata->state, 938 see->see_evvalue, edata->value_cur)); 939 if (edata->state == ENVSYS_SVALID && 940 see->see_evstate != ENVSYS_SVALID) { 941 sysmon_penvsys_event(&see->see_pes, 942 PENVSYS_EVENT_NORMAL); 943 see->see_evstate = ENVSYS_SVALID; 944 break; 945 } else if (edata->state != ENVSYS_SCRITICAL) 946 break; 947 if (see->see_evstate != ENVSYS_SCRITICAL || 948 see->see_evvalue != edata->value_cur) { 949 sysmon_penvsys_event(&see->see_pes, 950 PENVSYS_EVENT_CRITICAL); 951 see->see_evstate = ENVSYS_SCRITICAL; 952 } 953 see->see_evvalue = edata->value_cur; 954 break; 955 956 /* 957 * if value_cur is not normal (battery) or online (drive), 958 * send the event... 959 */ 960 case PENVSYS_EVENT_STATE_CHANGED: 961 /* 962 * the state has not been changed, just ignore the event. 963 */ 964 if (edata->value_cur == see->see_evvalue) 965 break; 966 967 switch (edata->units) { 968 case ENVSYS_DRIVE: 969 sdt = sme_find_table_entry(SME_DESC_DRIVE_STATES, 970 edata->value_cur); 971 state = ENVSYS_DRIVE_ONLINE; 972 break; 973 case ENVSYS_BATTERY_CAPACITY: 974 sdt = sme_find_table_entry(SME_DESC_BATTERY_CAPACITY, 975 edata->value_cur); 976 state = ENVSYS_BATTERY_CAPACITY_NORMAL; 977 break; 978 case ENVSYS_INDICATOR: 979 sdt = sme_find_table_entry(SME_DESC_INDICATOR, 980 edata->value_cur); 981 state = see->see_evvalue; /* force state change */ 982 break; 983 default: 984 panic("%s: bad units for PENVSYS_EVENT_STATE_CHANGED", 985 __func__); 986 } 987 988 if (sdt->type == -1) 989 break; 990 991 /* 992 * copy current state description. 993 */ 994 (void)strlcpy(see->see_pes.pes_statedesc, sdt->desc, 995 sizeof(see->see_pes.pes_statedesc)); 996 997 if (edata->value_cur == state) 998 /* 999 * state returned to normal condition 1000 */ 1001 sysmon_penvsys_event(&see->see_pes, 1002 PENVSYS_EVENT_NORMAL); 1003 else 1004 /* 1005 * state changed to abnormal condition 1006 */ 1007 sysmon_penvsys_event(&see->see_pes, see->see_type); 1008 1009 see->see_evvalue = edata->value_cur; 1010 1011 /* 1012 * There's no need to continue if it's a drive sensor. 1013 */ 1014 if (edata->units == ENVSYS_DRIVE) 1015 break; 1016 1017 /* 1018 * Check if the system is running in low power and send the 1019 * event to powerd (if running) or shutdown the system 1020 * otherwise. 1021 */ 1022 if (!sysmon_low_power && sme_event_check_low_power()) { 1023 struct penvsys_state pes; 1024 struct sysmon_envsys *sme = see->see_sme; 1025 1026 /* 1027 * Stop the callout and send the 'low-power' event. 1028 */ 1029 sysmon_low_power = true; 1030 KASSERT(mutex_owned(&sme->sme_mtx)); 1031 KASSERT(sme->sme_callout_state == SME_CALLOUT_READY); 1032 callout_stop(&sme->sme_callout); 1033 sme->sme_callout_state = SME_CALLOUT_HALTED; 1034 pes.pes_type = PENVSYS_TYPE_BATTERY; 1035 sysmon_penvsys_event(&pes, PENVSYS_EVENT_LOW_POWER); 1036 } 1037 break; 1038 case PENVSYS_EVENT_NULL: 1039 break; 1040 default: 1041 panic("%s: invalid event type %d", __func__, see->see_type); 1042 } 1043 } 1044 1045 /* 1046 * Returns true if the system is in low power state: an AC adapter 1047 * is OFF and all batteries are in LOW/CRITICAL state. 1048 */ 1049 static bool 1050 sme_event_check_low_power(void) 1051 { 1052 if (!sme_acadapter_check()) 1053 return false; 1054 1055 return sme_battery_check(); 1056 } 1057 1058 /* 1059 * Called with the sysmon_envsys device mtx held through the 1060 * workqueue thread. 1061 */ 1062 static bool 1063 sme_acadapter_check(void) 1064 { 1065 struct sysmon_envsys *sme; 1066 envsys_data_t *edata; 1067 bool dev = false, sensor = false; 1068 1069 LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) { 1070 if (sme->sme_class == SME_CLASS_ACADAPTER) { 1071 dev = true; 1072 break; 1073 } 1074 } 1075 1076 /* 1077 * No AC Adapter devices were found. 1078 */ 1079 if (!dev) 1080 return false; 1081 1082 /* 1083 * Check if there's an AC adapter device connected. 1084 */ 1085 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1086 if (edata->units == ENVSYS_INDICATOR) { 1087 sensor = true; 1088 /* refresh current sensor */ 1089 sysmon_envsys_refresh_sensor(sme, edata); 1090 1091 if (edata->value_cur) 1092 return false; 1093 } 1094 } 1095 1096 if (!sensor) 1097 return false; 1098 1099 /* 1100 * AC adapter found and not connected. 1101 */ 1102 return true; 1103 } 1104 1105 /* 1106 * Called with the sysmon_envsys device mtx held through the 1107 * workqueue thread. 1108 */ 1109 static bool 1110 sme_battery_check(void) 1111 { 1112 struct sysmon_envsys *sme; 1113 envsys_data_t *edata; 1114 int batteriesfound = 0; 1115 bool present, batterycap, batterycharge; 1116 1117 /* 1118 * Check for battery devices and its state. 1119 */ 1120 LIST_FOREACH(sme, &sysmon_envsys_list, sme_list) { 1121 if (sme->sme_class != SME_CLASS_BATTERY) 1122 continue; 1123 1124 present = true; 1125 1126 /* 1127 * XXX 1128 * this assumes that the first valid ENVSYS_INDICATOR is the 1129 * presence indicator 1130 */ 1131 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1132 if ((edata->units == ENVSYS_INDICATOR) && 1133 (edata->state == ENVSYS_SVALID)) { 1134 present = edata->value_cur; 1135 break; 1136 } 1137 } 1138 if (!present) 1139 continue; 1140 /* 1141 * We've found a battery device... 1142 */ 1143 batteriesfound++; 1144 batterycap = batterycharge = false; 1145 TAILQ_FOREACH(edata, &sme->sme_sensors_list, sensors_head) { 1146 /* no need to even look at sensors that aren't valid */ 1147 if (edata->state != ENVSYS_SVALID) 1148 continue; 1149 if (edata->units == ENVSYS_BATTERY_CAPACITY) { 1150 batterycap = true; 1151 if (!sme_battery_critical(edata)) 1152 return false; 1153 } else if (edata->units == ENVSYS_BATTERY_CHARGE) { 1154 batterycharge = true; 1155 if (edata->value_cur) 1156 return false; 1157 } 1158 } 1159 if (!batterycap || !batterycharge) 1160 return false; 1161 } 1162 1163 if (!batteriesfound) 1164 return false; 1165 1166 /* 1167 * All batteries in low/critical capacity and discharging. 1168 */ 1169 return true; 1170 } 1171 1172 static bool 1173 sme_battery_critical(envsys_data_t *edata) 1174 { 1175 if (edata->value_cur == ENVSYS_BATTERY_CAPACITY_CRITICAL || 1176 edata->value_cur == ENVSYS_BATTERY_CAPACITY_LOW) 1177 return true; 1178 1179 return false; 1180 } 1181