kernel: Adjust some comments to the unionfs removal.
[dragonfly.git] / sys / kern / kern_sensors.c
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);