kernel - Remove mplock from KTRACE paths
[dragonfly.git] / sys / kern / kern_sensors.c
bloba3a4109acb1d737a00004c55c78bb31492a206ae
1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
3 /*
4 * (MPSAFE)
6 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
7 * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
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.
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.
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>
35 #include <sys/sysctl.h>
36 #include <sys/sensors.h>
38 #include <sys/mplock2.h>
40 static int sensordev_idmax;
41 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
42 TAILQ_HEAD_INITIALIZER(sensordev_list);
44 static struct ksensordev *sensordev_get(int);
45 static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type,
46 int);
48 struct sensor_task {
49 void *arg;
50 void (*func)(void *);
52 int period;
53 time_t nextrun; /* time_uptime */
54 int running;
55 int cpuid;
56 TAILQ_ENTRY(sensor_task) entry;
58 TAILQ_HEAD(sensor_tasklist, sensor_task);
60 struct sensor_taskthr {
61 struct sensor_tasklist list;
62 struct lock lock;
65 static void sensor_task_thread(void *);
66 static void sensor_task_schedule(struct sensor_taskthr *,
67 struct sensor_task *);
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 *);
76 static struct sensor_taskthr sensor_task_threads[MAXCPU];
77 static int sensor_task_default_cpu;
79 void
80 sensordev_install(struct ksensordev *sensdev)
82 struct ksensordev *v, *after = NULL;
83 int num = 0;
85 SYSCTL_XLOCK();
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;
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);
104 /* Save max sensor device id */
105 sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
107 /* Install sysctl node for this sensor device */
108 sensordev_sysctl_install(sensdev);
110 SYSCTL_XUNLOCK();
113 void
114 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
116 struct ksensor *v, *nv;
117 struct ksensors_head *sh;
118 int i;
120 SYSCTL_XLOCK();
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);
142 * We only increment maxnumt[] if the sensor was added
143 * to the last position of sensors of this type
145 if (sensdev->maxnumt[sens->type] == sens->numt)
146 sensdev->maxnumt[sens->type]++;
147 sensdev->sensors_count++;
149 /* Install sysctl node for this sensor */
150 sensor_sysctl_install(sensdev, sens);
152 SYSCTL_XUNLOCK();
155 void
156 sensordev_deinstall(struct ksensordev *sensdev)
158 struct ksensordev *last;
160 SYSCTL_XLOCK();
162 TAILQ_REMOVE(&sensordev_list, sensdev, list);
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;
172 * Deinstall sensor device's sysctl node; this also
173 * removes all attached sensors' sysctl nodes.
175 sensordev_sysctl_deinstall(sensdev);
177 SYSCTL_XUNLOCK();
180 void
181 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
183 struct ksensors_head *sh;
185 SYSCTL_XLOCK();
187 sh = &sensdev->sensors_list;
188 sensdev->sensors_count--;
189 SLIST_REMOVE(sh, sens, ksensor, list);
191 * We only decrement maxnumt[] if this is the tail
192 * sensor of this type
194 if (sens->numt == sensdev->maxnumt[sens->type] - 1)
195 sensdev->maxnumt[sens->type]--;
197 /* Deinstall sensor's sysctl node */
198 sensor_sysctl_deinstall(sensdev, sens);
200 SYSCTL_XUNLOCK();
203 static struct ksensordev *
204 sensordev_get(int num)
206 struct ksensordev *sd;
208 SYSCTL_ASSERT_LOCKED();
210 TAILQ_FOREACH(sd, &sensordev_list, list) {
211 if (sd->num == num)
212 return (sd);
214 return (NULL);
217 static struct ksensor *
218 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
220 struct ksensor *s;
221 struct ksensors_head *sh;
223 SYSCTL_ASSERT_LOCKED();
225 sh = &sensdev->sensors_list;
226 SLIST_FOREACH(s, sh, list) {
227 if (s->type == type && s->numt == numt)
228 return (s);
230 return (NULL);
233 void
234 sensor_task_register(void *arg, void (*func)(void *), int period)
236 sensor_task_register2(arg, func, period, -1);
239 void
240 sensor_task_unregister(void *arg)
242 struct sensor_taskthr *thr;
243 struct sensor_task *st;
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);
253 void
254 sensor_task_unregister2(struct sensor_task *st)
256 struct sensor_taskthr *thr;
258 KASSERT(st->cpuid >= 0 && st->cpuid < ncpus,
259 ("invalid task cpuid %d", st->cpuid));
260 thr = &sensor_task_threads[st->cpuid];
263 * Hold the lock then zero-out running, so upon returning
264 * to the caller, the task will no longer run.
266 lockmgr(&thr->lock, LK_EXCLUSIVE);
267 st->running = 0;
268 lockmgr(&thr->lock, LK_RELEASE);
271 struct sensor_task *
272 sensor_task_register2(void *arg, void (*func)(void *), int period, int cpu)
274 struct sensor_taskthr *thr;
275 struct sensor_task *st;
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];
282 st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
284 lockmgr(&thr->lock, LK_EXCLUSIVE);
285 st->arg = arg;
286 st->func = func;
287 st->period = period;
288 st->cpuid = cpu;
290 st->running = 1;
292 st->nextrun = 0;
293 TAILQ_INSERT_HEAD(&thr->list, st, entry);
295 wakeup(&thr->list);
297 lockmgr(&thr->lock, LK_RELEASE);
299 return st;
302 static void
303 sensor_task_thread(void *xthr)
305 struct sensor_taskthr *thr = xthr;
306 struct sensor_task *st, *nst;
307 time_t now;
309 lockmgr(&thr->lock, LK_EXCLUSIVE);
311 for (;;) {
312 while (TAILQ_EMPTY(&thr->list))
313 lksleep(&thr->list, &thr->lock, 0, "waittask", 0);
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);
321 while ((st = nst) != NULL) {
322 nst = TAILQ_NEXT(st, entry);
324 if (st->nextrun > now)
325 break;
327 /* take it out while we work on it */
328 TAILQ_REMOVE(&thr->list, st, entry);
330 if (!st->running) {
331 kfree(st, M_DEVBUF);
332 continue;
335 /* run the task */
336 st->func(st->arg);
337 /* stick it back in the tasklist */
338 sensor_task_schedule(thr, st);
342 lockmgr(&thr->lock, LK_RELEASE);
345 static void
346 sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st)
348 struct sensor_task *cst;
350 KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE,
351 ("sensor task lock is not held"));
353 st->nextrun = time_uptime + st->period;
355 TAILQ_FOREACH(cst, &thr->list, entry) {
356 if (cst->nextrun > st->nextrun) {
357 TAILQ_INSERT_BEFORE(cst, st, entry);
358 return;
362 /* must be an empty list, or at the end of the list */
363 TAILQ_INSERT_TAIL(&thr->list, st, entry);
367 * sysctl glue code
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);
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");
378 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
379 &sensordev_idmax, 0, "Max sensor device id");
381 static void
382 sensordev_sysctl_install(struct ksensordev *sensdev)
384 struct sysctl_ctx_list *cl = &sensdev->clist;
385 struct ksensor *s;
386 struct ksensors_head *sh = &sensdev->sensors_list;
388 SYSCTL_ASSERT_LOCKED();
390 KASSERT(sensdev->oid == NULL,
391 ("sensor device %s sysctl node already installed", sensdev->xname));
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;
402 /* Install sysctl nodes for sensors attached to this sensor device */
403 SLIST_FOREACH(s, sh, list)
404 sensor_sysctl_install(sensdev, s);
407 static void
408 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
410 char n[32];
412 SYSCTL_ASSERT_LOCKED();
414 if (sensdev->oid == NULL) {
415 /* Sensor device sysctl node is not installed yet */
416 return;
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));
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", "");
429 static void
430 sensordev_sysctl_deinstall(struct ksensordev *sensdev)
432 SYSCTL_ASSERT_LOCKED();
434 if (sensdev->oid != NULL) {
435 sysctl_ctx_free(&sensdev->clist);
436 sensdev->oid = NULL;
440 static void
441 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
443 SYSCTL_ASSERT_LOCKED();
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);
449 sens->oid = NULL;
452 static int
453 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
455 struct ksensordev *ksd = arg1;
456 struct sensordev *usd;
457 int error;
459 if (req->newptr)
460 return (EPERM);
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;
469 error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
471 kfree(usd, M_TEMP);
472 return (error);
475 static int
476 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
478 struct ksensor *ks = arg1;
479 struct sensor *us;
480 int error;
482 if (req->newptr)
483 return (EPERM);
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;
495 error = SYSCTL_OUT(req, us, sizeof(struct sensor));
497 kfree(us, M_TEMP);
498 return (error);
501 static int
502 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
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;
511 if (namelen != 1 && namelen != 3)
512 return (ENOTDIR);
514 dev = name[0];
515 if ((ksd = sensordev_get(dev)) == NULL)
516 return (ENOENT);
518 if (namelen == 1)
519 return (sysctl_handle_sensordev(NULL, ksd, 0, req));
521 type = name[1];
522 numt = name[2];
524 if ((ks = sensor_find(ksd, type, numt)) == NULL)
525 return (ENOENT);
526 return (sysctl_handle_sensor(NULL, ks, 0, req));
529 static void
530 sensor_sysinit(void *arg __unused)
532 const cpu_node_t *node;
533 int cpu;
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.
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);
552 for (cpu = 0; cpu < ncpus; ++cpu) {
553 struct sensor_taskthr *thr = &sensor_task_threads[cpu];
554 int error;
556 TAILQ_INIT(&thr->list);
557 lockinit(&thr->lock, "sensorthr", 0, LK_CANRECURSE);
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);
565 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);