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