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