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