inet6: only mark autoconf addresses tentative if detached
[dragonfly.git] / sys / kern / kern_sensors.c
CommitLineData
eb3a3472 1/* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
eb3a3472
HT
2
3/*
bce291d6
AH
4 * (MPSAFE)
5 *
eb3a3472
HT
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
eb3a3472
HT
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>
bce291d6
AH
30#include <sys/spinlock.h>
31#include <sys/spinlock2.h>
eb3a3472 32#include <sys/lock.h>
a6f507cc 33#include <sys/cpu_topology.h>
eb3a3472
HT
34
35#include <sys/sysctl.h>
36#include <sys/sensors.h>
37
2dc01a00
SZ
38static int sensordev_idmax;
39static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
27305eac 40 TAILQ_HEAD_INITIALIZER(sensordev_list);
eb3a3472 41
8ef41b85
SZ
42static struct ksensordev *sensordev_get(int);
43static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type,
44 int);
eb3a3472
HT
45
46struct sensor_task {
47 void *arg;
48 void (*func)(void *);
49
50 int period;
cec73927 51 time_t nextrun; /* time_uptime */
72a4f168 52 int running;
f95d9b17 53 int cpuid;
eb3a3472
HT
54 TAILQ_ENTRY(sensor_task) entry;
55};
f95d9b17 56TAILQ_HEAD(sensor_tasklist, sensor_task);
eb3a3472 57
f95d9b17
SZ
58struct sensor_taskthr {
59 struct sensor_tasklist list;
60 struct lock lock;
61};
eb3a3472 62
f95d9b17
SZ
63static void sensor_task_thread(void *);
64static void sensor_task_schedule(struct sensor_taskthr *,
65 struct sensor_task *);
8dc374fa 66
dfb94396
SZ
67static void sensordev_sysctl_install(struct ksensordev *);
68static void sensordev_sysctl_deinstall(struct ksensordev *);
69static void sensor_sysctl_install(struct ksensordev *,
70 struct ksensor *);
71static void sensor_sysctl_deinstall(struct ksensordev *,
72 struct ksensor *);
eb3a3472 73
f95d9b17 74static struct sensor_taskthr sensor_task_threads[MAXCPU];
a6f507cc 75static int sensor_task_default_cpu;
f95d9b17 76
eb3a3472
HT
77void
78sensordev_install(struct ksensordev *sensdev)
79{
27305eac
SZ
80 struct ksensordev *v, *after = NULL;
81 int num = 0;
eb3a3472 82
e50eb75e
SZ
83 SYSCTL_XLOCK();
84
27305eac
SZ
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);
eb3a3472 98 } else {
27305eac 99 TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list);
eb3a3472 100 }
eb3a3472 101
2dc01a00
SZ
102 /* Save max sensor device id */
103 sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
104
dfb94396
SZ
105 /* Install sysctl node for this sensor device */
106 sensordev_sysctl_install(sensdev);
e50eb75e
SZ
107
108 SYSCTL_XUNLOCK();
eb3a3472
HT
109}
110
111void
112sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
113{
114 struct ksensor *v, *nv;
115 struct ksensors_head *sh;
116 int i;
117
e50eb75e
SZ
118 SYSCTL_XLOCK();
119
eb3a3472
HT
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)
d314b0e9
SW
129 if (v->type == sens->type &&
130 (v->type != nv->type || nv->numt - v->numt > 1))
eb3a3472
HT
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 }
e50eb75e
SZ
139 /*
140 * We only increment maxnumt[] if the sensor was added
eb3a3472
HT
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++;
e50eb75e 146
dfb94396
SZ
147 /* Install sysctl node for this sensor */
148 sensor_sysctl_install(sensdev, sens);
149
e50eb75e 150 SYSCTL_XUNLOCK();
eb3a3472
HT
151}
152
153void
154sensordev_deinstall(struct ksensordev *sensdev)
155{
2dc01a00
SZ
156 struct ksensordev *last;
157
e50eb75e
SZ
158 SYSCTL_XLOCK();
159
27305eac 160 TAILQ_REMOVE(&sensordev_list, sensdev, list);
eb3a3472 161
2dc01a00
SZ
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
dfb94396
SZ
169 /*
170 * Deinstall sensor device's sysctl node; this also
171 * removes all attached sensors' sysctl nodes.
172 */
173 sensordev_sysctl_deinstall(sensdev);
e50eb75e
SZ
174
175 SYSCTL_XUNLOCK();
eb3a3472
HT
176}
177
178void
179sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
180{
181 struct ksensors_head *sh;
182
e50eb75e
SZ
183 SYSCTL_XLOCK();
184
eb3a3472
HT
185 sh = &sensdev->sensors_list;
186 sensdev->sensors_count--;
187 SLIST_REMOVE(sh, sens, ksensor, list);
e50eb75e
SZ
188 /*
189 * We only decrement maxnumt[] if this is the tail
eb3a3472
HT
190 * sensor of this type
191 */
192 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
193 sensdev->maxnumt[sens->type]--;
e50eb75e 194
dfb94396
SZ
195 /* Deinstall sensor's sysctl node */
196 sensor_sysctl_deinstall(sensdev, sens);
197
e50eb75e 198 SYSCTL_XUNLOCK();
eb3a3472
HT
199}
200
8ef41b85 201static struct ksensordev *
eb3a3472
HT
202sensordev_get(int num)
203{
204 struct ksensordev *sd;
205
b750642b 206 SYSCTL_ASSERT_LOCKED();
eb3a3472 207
27305eac 208 TAILQ_FOREACH(sd, &sensordev_list, list) {
e50eb75e
SZ
209 if (sd->num == num)
210 return (sd);
211 }
eb3a3472
HT
212 return (NULL);
213}
214
8ef41b85 215static struct ksensor *
eb3a3472
HT
216sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
217{
218 struct ksensor *s;
219 struct ksensors_head *sh;
220
b750642b 221 SYSCTL_ASSERT_LOCKED();
e50eb75e 222
eb3a3472 223 sh = &sensdev->sensors_list;
bce291d6 224 SLIST_FOREACH(s, sh, list) {
e50eb75e 225 if (s->type == type && s->numt == numt)
eb3a3472 226 return (s);
bce291d6 227 }
eb3a3472
HT
228 return (NULL);
229}
230
1bedd63a 231void
eb3a3472
HT
232sensor_task_register(void *arg, void (*func)(void *), int period)
233{
f8f01153 234 sensor_task_register2(arg, func, period, -1);
f95d9b17
SZ
235}
236
237void
238sensor_task_unregister(void *arg)
239{
a6f507cc 240 struct sensor_taskthr *thr;
eb3a3472 241 struct sensor_task *st;
eb3a3472 242
a6f507cc 243 thr = &sensor_task_threads[sensor_task_default_cpu];
f95d9b17
SZ
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
251void
252sensor_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
269struct sensor_task *
270sensor_task_register2(void *arg, void (*func)(void *), int period, int cpu)
271{
272 struct sensor_taskthr *thr;
273 struct sensor_task *st;
274
f8f01153 275 if (cpu < 0)
a6f507cc 276 cpu = sensor_task_default_cpu;
f95d9b17
SZ
277 KASSERT(cpu >= 0 && cpu < ncpus, ("invalid cpuid %d", cpu));
278 thr = &sensor_task_threads[cpu];
279
1bedd63a 280 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
eb3a3472 281
f95d9b17 282 lockmgr(&thr->lock, LK_EXCLUSIVE);
eb3a3472
HT
283 st->arg = arg;
284 st->func = func;
285 st->period = period;
f95d9b17 286 st->cpuid = cpu;
eb3a3472
HT
287
288 st->running = 1;
289
eb3a3472 290 st->nextrun = 0;
f95d9b17 291 TAILQ_INSERT_HEAD(&thr->list, st, entry);
eb3a3472 292
f95d9b17 293 wakeup(&thr->list);
eb3a3472 294
f95d9b17 295 lockmgr(&thr->lock, LK_RELEASE);
eb3a3472 296
f95d9b17 297 return st;
eb3a3472
HT
298}
299
8ef41b85 300static void
f95d9b17 301sensor_task_thread(void *xthr)
eb3a3472 302{
f95d9b17 303 struct sensor_taskthr *thr = xthr;
eb3a3472
HT
304 struct sensor_task *st, *nst;
305 time_t now;
306
f95d9b17 307 lockmgr(&thr->lock, LK_EXCLUSIVE);
cd8ab232 308
8dc374fa 309 for (;;) {
f95d9b17
SZ
310 while (TAILQ_EMPTY(&thr->list))
311 lksleep(&thr->list, &thr->lock, 0, "waittask", 0);
8dc374fa 312
f95d9b17 313 while ((nst = TAILQ_FIRST(&thr->list))->nextrun >
a6a80759 314 (now = time_uptime)) {
f95d9b17 315 lksleep(&thr->list, &thr->lock, 0,
a6a80759
SZ
316 "timeout", (nst->nextrun - now) * hz);
317 }
eb3a3472
HT
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 */
f95d9b17 326 TAILQ_REMOVE(&thr->list, st, entry);
eb3a3472
HT
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 */
f95d9b17 336 sensor_task_schedule(thr, st);
eb3a3472
HT
337 }
338 }
339
f95d9b17 340 lockmgr(&thr->lock, LK_RELEASE);
eb3a3472
HT
341}
342
8ef41b85 343static void
f95d9b17 344sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st)
eb3a3472
HT
345{
346 struct sensor_task *cst;
347
f95d9b17 348 KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE,
c1bc662c
SZ
349 ("sensor task lock is not held"));
350
cec73927 351 st->nextrun = time_uptime + st->period;
eb3a3472 352
f95d9b17 353 TAILQ_FOREACH(cst, &thr->list, entry) {
eb3a3472
HT
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 */
f95d9b17 361 TAILQ_INSERT_TAIL(&thr->list, st, entry);
eb3a3472
HT
362}
363
364/*
365 * sysctl glue code
366 */
8ef41b85
SZ
367static int sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
368static int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
369static int sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
eb3a3472 370
eb3a3472
HT
371SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
372 "Hardware Sensors sysctl internal magic");
373SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
374 "Hardware Sensors XP MIB interface");
375
2dc01a00
SZ
376SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
377 &sensordev_idmax, 0, "Max sensor device id");
378
8ef41b85 379static void
dfb94396 380sensordev_sysctl_install(struct ksensordev *sensdev)
eb3a3472 381{
eb3a3472
HT
382 struct sysctl_ctx_list *cl = &sensdev->clist;
383 struct ksensor *s;
384 struct ksensors_head *sh = &sensdev->sensors_list;
385
b750642b 386 SYSCTL_ASSERT_LOCKED();
e50eb75e 387
dfb94396
SZ
388 KASSERT(sensdev->oid == NULL,
389 ("sensor device %s sysctl node already installed", sensdev->xname));
390
eb3a3472 391 sysctl_ctx_init(cl);
2ce2b389
SZ
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
dfb94396
SZ
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
405static void
406sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
407{
408 char n[32];
409
b750642b 410 SYSCTL_ASSERT_LOCKED();
eb3a3472 411
dfb94396
SZ
412 if (sensdev->oid == NULL) {
413 /* Sensor device sysctl node is not installed yet */
414 return;
eb3a3472 415 }
dfb94396
SZ
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", "");
eb3a3472
HT
425}
426
8ef41b85 427static void
dfb94396 428sensordev_sysctl_deinstall(struct ksensordev *sensdev)
eb3a3472 429{
b750642b 430 SYSCTL_ASSERT_LOCKED();
e50eb75e 431
dfb94396 432 if (sensdev->oid != NULL) {
2ce2b389 433 sysctl_ctx_free(&sensdev->clist);
dfb94396
SZ
434 sensdev->oid = NULL;
435 }
436}
437
438static void
439sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
440{
b750642b 441 SYSCTL_ASSERT_LOCKED();
dfb94396
SZ
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;
eb3a3472
HT
448}
449
8ef41b85 450static int
eb3a3472
HT
451sysctl_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 */
e7b4468c 461 usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
eb3a3472
HT
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);
eb3a3472
HT
471}
472
8ef41b85 473static int
eb3a3472
HT
474sysctl_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 */
e7b4468c 484 us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
eb3a3472
HT
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
8ef41b85 499static int
eb3a3472
HT
500sysctl_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}
8dc374fa
SZ
526
527static void
528sensor_sysinit(void *arg __unused)
529{
a6f507cc 530 const cpu_node_t *node;
f95d9b17
SZ
531 int cpu;
532
a6f507cc
SZ
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
f95d9b17
SZ
550 for (cpu = 0; cpu < ncpus; ++cpu) {
551 struct sensor_taskthr *thr = &sensor_task_threads[cpu];
552 int error;
8dc374fa 553
f95d9b17
SZ
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 }
8dc374fa
SZ
562}
563SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);