1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */ 2 3 /* 4 * (MPSAFE) 5 * 6 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 7 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/kernel.h> 25 #include <sys/malloc.h> 26 #include <sys/kthread.h> 27 #include <sys/queue.h> 28 #include <sys/types.h> 29 #include <sys/time.h> 30 #include <sys/spinlock.h> 31 #include <sys/spinlock2.h> 32 #include <sys/lock.h> 33 34 #include <sys/sysctl.h> 35 #include <sys/sensors.h> 36 37 #include <sys/mplock2.h> 38 39 /* 40 * Default to the last cpu's sensor thread 41 */ 42 #define SENSOR_TASK_DEFCPU (ncpus - 1) 43 44 static int sensordev_idmax; 45 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list = 46 TAILQ_HEAD_INITIALIZER(sensordev_list); 47 48 static struct ksensordev *sensordev_get(int); 49 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, 50 int); 51 52 struct sensor_task { 53 void *arg; 54 void (*func)(void *); 55 56 int period; 57 time_t nextrun; /* time_uptime */ 58 int running; 59 int cpuid; 60 TAILQ_ENTRY(sensor_task) entry; 61 }; 62 TAILQ_HEAD(sensor_tasklist, sensor_task); 63 64 struct sensor_taskthr { 65 struct sensor_tasklist list; 66 struct lock lock; 67 }; 68 69 static void sensor_task_thread(void *); 70 static void sensor_task_schedule(struct sensor_taskthr *, 71 struct sensor_task *); 72 73 static void sensordev_sysctl_install(struct ksensordev *); 74 static void sensordev_sysctl_deinstall(struct ksensordev *); 75 static void sensor_sysctl_install(struct ksensordev *, 76 struct ksensor *); 77 static void sensor_sysctl_deinstall(struct ksensordev *, 78 struct ksensor *); 79 80 static struct sensor_taskthr sensor_task_threads[MAXCPU]; 81 82 void 83 sensordev_install(struct ksensordev *sensdev) 84 { 85 struct ksensordev *v, *after = NULL; 86 int num = 0; 87 88 SYSCTL_XLOCK(); 89 90 TAILQ_FOREACH(v, &sensordev_list, list) { 91 if (v->num == num) { 92 ++num; 93 after = v; 94 } else if (v->num > num) { 95 break; 96 } 97 } 98 99 sensdev->num = num; 100 if (after == NULL) { 101 KKASSERT(sensdev->num == 0); 102 TAILQ_INSERT_HEAD(&sensordev_list, sensdev, list); 103 } else { 104 TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list); 105 } 106 107 /* Save max sensor device id */ 108 sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1; 109 110 /* Install sysctl node for this sensor device */ 111 sensordev_sysctl_install(sensdev); 112 113 SYSCTL_XUNLOCK(); 114 } 115 116 void 117 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens) 118 { 119 struct ksensor *v, *nv; 120 struct ksensors_head *sh; 121 int i; 122 123 SYSCTL_XLOCK(); 124 125 sh = &sensdev->sensors_list; 126 if (sensdev->sensors_count == 0) { 127 for (i = 0; i < SENSOR_MAX_TYPES; i++) 128 sensdev->maxnumt[i] = 0; 129 sens->numt = 0; 130 SLIST_INSERT_HEAD(sh, sens, list); 131 } else { 132 for (v = SLIST_FIRST(sh); 133 (nv = SLIST_NEXT(v, list)) != NULL; v = nv) 134 if (v->type == sens->type && (v->type != nv->type || 135 (v->type == nv->type && nv->numt - v->numt > 1))) 136 break; 137 /* sensors of the same type go after each other */ 138 if (v->type == sens->type) 139 sens->numt = v->numt + 1; 140 else 141 sens->numt = 0; 142 SLIST_INSERT_AFTER(v, sens, list); 143 } 144 /* 145 * We only increment maxnumt[] if the sensor was added 146 * to the last position of sensors of this type 147 */ 148 if (sensdev->maxnumt[sens->type] == sens->numt) 149 sensdev->maxnumt[sens->type]++; 150 sensdev->sensors_count++; 151 152 /* Install sysctl node for this sensor */ 153 sensor_sysctl_install(sensdev, sens); 154 155 SYSCTL_XUNLOCK(); 156 } 157 158 void 159 sensordev_deinstall(struct ksensordev *sensdev) 160 { 161 struct ksensordev *last; 162 163 SYSCTL_XLOCK(); 164 165 TAILQ_REMOVE(&sensordev_list, sensdev, list); 166 167 /* Adjust max sensor device id */ 168 last = TAILQ_LAST(&sensordev_list, sensordev_list); 169 if (last != NULL) 170 sensordev_idmax = last->num + 1; 171 else 172 sensordev_idmax = 0; 173 174 /* 175 * Deinstall sensor device's sysctl node; this also 176 * removes all attached sensors' sysctl nodes. 177 */ 178 sensordev_sysctl_deinstall(sensdev); 179 180 SYSCTL_XUNLOCK(); 181 } 182 183 void 184 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens) 185 { 186 struct ksensors_head *sh; 187 188 SYSCTL_XLOCK(); 189 190 sh = &sensdev->sensors_list; 191 sensdev->sensors_count--; 192 SLIST_REMOVE(sh, sens, ksensor, list); 193 /* 194 * We only decrement maxnumt[] if this is the tail 195 * sensor of this type 196 */ 197 if (sens->numt == sensdev->maxnumt[sens->type] - 1) 198 sensdev->maxnumt[sens->type]--; 199 200 /* Deinstall sensor's sysctl node */ 201 sensor_sysctl_deinstall(sensdev, sens); 202 203 SYSCTL_XUNLOCK(); 204 } 205 206 static struct ksensordev * 207 sensordev_get(int num) 208 { 209 struct ksensordev *sd; 210 211 SYSCTL_ASSERT_XLOCKED(); 212 213 TAILQ_FOREACH(sd, &sensordev_list, list) { 214 if (sd->num == num) 215 return (sd); 216 } 217 return (NULL); 218 } 219 220 static struct ksensor * 221 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt) 222 { 223 struct ksensor *s; 224 struct ksensors_head *sh; 225 226 SYSCTL_ASSERT_XLOCKED(); 227 228 sh = &sensdev->sensors_list; 229 SLIST_FOREACH(s, sh, list) { 230 if (s->type == type && s->numt == numt) 231 return (s); 232 } 233 return (NULL); 234 } 235 236 void 237 sensor_task_register(void *arg, void (*func)(void *), int period) 238 { 239 sensor_task_register2(arg, func, period, -1); 240 } 241 242 void 243 sensor_task_unregister(void *arg) 244 { 245 struct sensor_taskthr *thr = &sensor_task_threads[SENSOR_TASK_DEFCPU]; 246 struct sensor_task *st; 247 248 lockmgr(&thr->lock, LK_EXCLUSIVE); 249 TAILQ_FOREACH(st, &thr->list, entry) 250 if (st->arg == arg) 251 st->running = 0; 252 lockmgr(&thr->lock, LK_RELEASE); 253 } 254 255 void 256 sensor_task_unregister2(struct sensor_task *st) 257 { 258 struct sensor_taskthr *thr; 259 260 KASSERT(st->cpuid >= 0 && st->cpuid < ncpus, 261 ("invalid task cpuid %d", st->cpuid)); 262 thr = &sensor_task_threads[st->cpuid]; 263 264 /* 265 * Hold the lock then zero-out running, so upon returning 266 * to the caller, the task will no longer run. 267 */ 268 lockmgr(&thr->lock, LK_EXCLUSIVE); 269 st->running = 0; 270 lockmgr(&thr->lock, LK_RELEASE); 271 } 272 273 struct sensor_task * 274 sensor_task_register2(void *arg, void (*func)(void *), int period, int cpu) 275 { 276 struct sensor_taskthr *thr; 277 struct sensor_task *st; 278 279 if (cpu < 0) 280 cpu = SENSOR_TASK_DEFCPU; 281 KASSERT(cpu >= 0 && cpu < ncpus, ("invalid cpuid %d", cpu)); 282 thr = &sensor_task_threads[cpu]; 283 284 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK); 285 286 lockmgr(&thr->lock, LK_EXCLUSIVE); 287 st->arg = arg; 288 st->func = func; 289 st->period = period; 290 st->cpuid = cpu; 291 292 st->running = 1; 293 294 st->nextrun = 0; 295 TAILQ_INSERT_HEAD(&thr->list, st, entry); 296 297 wakeup(&thr->list); 298 299 lockmgr(&thr->lock, LK_RELEASE); 300 301 return st; 302 } 303 304 static void 305 sensor_task_thread(void *xthr) 306 { 307 struct sensor_taskthr *thr = xthr; 308 struct sensor_task *st, *nst; 309 time_t now; 310 311 lockmgr(&thr->lock, LK_EXCLUSIVE); 312 313 for (;;) { 314 while (TAILQ_EMPTY(&thr->list)) 315 lksleep(&thr->list, &thr->lock, 0, "waittask", 0); 316 317 while ((nst = TAILQ_FIRST(&thr->list))->nextrun > 318 (now = time_uptime)) { 319 lksleep(&thr->list, &thr->lock, 0, 320 "timeout", (nst->nextrun - now) * hz); 321 } 322 323 while ((st = nst) != NULL) { 324 nst = TAILQ_NEXT(st, entry); 325 326 if (st->nextrun > now) 327 break; 328 329 /* take it out while we work on it */ 330 TAILQ_REMOVE(&thr->list, st, entry); 331 332 if (!st->running) { 333 kfree(st, M_DEVBUF); 334 continue; 335 } 336 337 /* run the task */ 338 st->func(st->arg); 339 /* stick it back in the tasklist */ 340 sensor_task_schedule(thr, st); 341 } 342 } 343 344 lockmgr(&thr->lock, LK_RELEASE); 345 } 346 347 static void 348 sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st) 349 { 350 struct sensor_task *cst; 351 352 KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE, 353 ("sensor task lock is not held")); 354 355 st->nextrun = time_uptime + st->period; 356 357 TAILQ_FOREACH(cst, &thr->list, entry) { 358 if (cst->nextrun > st->nextrun) { 359 TAILQ_INSERT_BEFORE(cst, st, entry); 360 return; 361 } 362 } 363 364 /* must be an empty list, or at the end of the list */ 365 TAILQ_INSERT_TAIL(&thr->list, st, entry); 366 } 367 368 /* 369 * sysctl glue code 370 */ 371 static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS); 372 static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS); 373 static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS); 374 375 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL, 376 "Hardware Sensors sysctl internal magic"); 377 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler, 378 "Hardware Sensors XP MIB interface"); 379 380 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD, 381 &sensordev_idmax, 0, "Max sensor device id"); 382 383 static void 384 sensordev_sysctl_install(struct ksensordev *sensdev) 385 { 386 struct sysctl_ctx_list *cl = &sensdev->clist; 387 struct ksensor *s; 388 struct ksensors_head *sh = &sensdev->sensors_list; 389 390 SYSCTL_ASSERT_XLOCKED(); 391 392 KASSERT(sensdev->oid == NULL, 393 ("sensor device %s sysctl node already installed", sensdev->xname)); 394 395 sysctl_ctx_init(cl); 396 sensdev->oid = SYSCTL_ADD_NODE(cl, SYSCTL_STATIC_CHILDREN(_hw_sensors), 397 sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, ""); 398 if (sensdev->oid == NULL) { 399 kprintf("sensor: add sysctl tree for %s failed\n", 400 sensdev->xname); 401 return; 402 } 403 404 /* Install sysctl nodes for sensors attached to this sensor device */ 405 SLIST_FOREACH(s, sh, list) 406 sensor_sysctl_install(sensdev, s); 407 } 408 409 static void 410 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens) 411 { 412 char n[32]; 413 414 SYSCTL_ASSERT_XLOCKED(); 415 416 if (sensdev->oid == NULL) { 417 /* Sensor device sysctl node is not installed yet */ 418 return; 419 } 420 421 ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[sens->type], sens->numt); 422 KASSERT(sens->oid == NULL, 423 ("sensor %s:%s sysctl node already installed", sensdev->xname, n)); 424 425 sens->oid = SYSCTL_ADD_PROC(&sensdev->clist, 426 SYSCTL_CHILDREN(sensdev->oid), OID_AUTO, n, 427 CTLTYPE_STRUCT | CTLFLAG_RD, sens, 0, sysctl_handle_sensor, 428 "S,sensor", ""); 429 } 430 431 static void 432 sensordev_sysctl_deinstall(struct ksensordev *sensdev) 433 { 434 SYSCTL_ASSERT_XLOCKED(); 435 436 if (sensdev->oid != NULL) { 437 sysctl_ctx_free(&sensdev->clist); 438 sensdev->oid = NULL; 439 } 440 } 441 442 static void 443 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens) 444 { 445 SYSCTL_ASSERT_XLOCKED(); 446 447 if (sensdev->oid != NULL && sens->oid != NULL) { 448 sysctl_ctx_entry_del(&sensdev->clist, sens->oid); 449 sysctl_remove_oid(sens->oid, 1, 0); 450 } 451 sens->oid = NULL; 452 } 453 454 static int 455 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS) 456 { 457 struct ksensordev *ksd = arg1; 458 struct sensordev *usd; 459 int error; 460 461 if (req->newptr) 462 return (EPERM); 463 464 /* Grab a copy, to clear the kernel pointers */ 465 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO); 466 usd->num = ksd->num; 467 strlcpy(usd->xname, ksd->xname, sizeof(usd->xname)); 468 memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt)); 469 usd->sensors_count = ksd->sensors_count; 470 471 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev)); 472 473 kfree(usd, M_TEMP); 474 return (error); 475 } 476 477 static int 478 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS) 479 { 480 struct ksensor *ks = arg1; 481 struct sensor *us; 482 int error; 483 484 if (req->newptr) 485 return (EPERM); 486 487 /* Grab a copy, to clear the kernel pointers */ 488 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO); 489 memcpy(us->desc, ks->desc, sizeof(ks->desc)); 490 us->tv = ks->tv; 491 us->value = ks->value; 492 us->type = ks->type; 493 us->status = ks->status; 494 us->numt = ks->numt; 495 us->flags = ks->flags; 496 497 error = SYSCTL_OUT(req, us, sizeof(struct sensor)); 498 499 kfree(us, M_TEMP); 500 return (error); 501 } 502 503 static int 504 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS) 505 { 506 int *name = arg1; 507 u_int namelen = arg2; 508 struct ksensordev *ksd; 509 struct ksensor *ks; 510 int dev, numt; 511 enum sensor_type type; 512 513 if (namelen != 1 && namelen != 3) 514 return (ENOTDIR); 515 516 dev = name[0]; 517 if ((ksd = sensordev_get(dev)) == NULL) 518 return (ENOENT); 519 520 if (namelen == 1) 521 return (sysctl_handle_sensordev(NULL, ksd, 0, req)); 522 523 type = name[1]; 524 numt = name[2]; 525 526 if ((ks = sensor_find(ksd, type, numt)) == NULL) 527 return (ENOENT); 528 return (sysctl_handle_sensor(NULL, ks, 0, req)); 529 } 530 531 static void 532 sensor_sysinit(void *arg __unused) 533 { 534 int cpu; 535 536 for (cpu = 0; cpu < ncpus; ++cpu) { 537 struct sensor_taskthr *thr = &sensor_task_threads[cpu]; 538 int error; 539 540 TAILQ_INIT(&thr->list); 541 lockinit(&thr->lock, "sensorthr", 0, LK_CANRECURSE); 542 543 error = kthread_create_cpu(sensor_task_thread, thr, NULL, cpu, 544 "sensors %d", cpu); 545 if (error) 546 panic("sensors kthread on cpu%d failed: %d", cpu, error); 547 } 548 } 549 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL); 550