1 /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
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>
30 #include <sys/spinlock.h>
31 #include <sys/spinlock2.h>
33 #include <sys/cpu_topology.h>
35 #include <sys/sysctl.h>
36 #include <sys/sensors.h>
38 static int sensordev_idmax
;
39 static TAILQ_HEAD(sensordev_list
, ksensordev
) sensordev_list
=
40 TAILQ_HEAD_INITIALIZER(sensordev_list
);
42 static struct ksensordev
*sensordev_get(int);
43 static struct ksensor
*sensor_find(struct ksensordev
*, enum sensor_type
,
51 time_t nextrun
; /* time_uptime */
54 TAILQ_ENTRY(sensor_task
) entry
;
56 TAILQ_HEAD(sensor_tasklist
, sensor_task
);
58 struct sensor_taskthr
{
59 struct sensor_tasklist list
;
63 static void sensor_task_thread(void *);
64 static void sensor_task_schedule(struct sensor_taskthr
*,
65 struct sensor_task
*);
67 static void sensordev_sysctl_install(struct ksensordev
*);
68 static void sensordev_sysctl_deinstall(struct ksensordev
*);
69 static void sensor_sysctl_install(struct ksensordev
*,
71 static void sensor_sysctl_deinstall(struct ksensordev
*,
74 static struct sensor_taskthr sensor_task_threads
[MAXCPU
];
75 static int sensor_task_default_cpu
;
78 sensordev_install(struct ksensordev
*sensdev
)
80 struct ksensordev
*v
, *after
= NULL
;
85 TAILQ_FOREACH(v
, &sensordev_list
, list
) {
89 } else if (v
->num
> num
) {
96 KKASSERT(sensdev
->num
== 0);
97 TAILQ_INSERT_HEAD(&sensordev_list
, sensdev
, list
);
99 TAILQ_INSERT_AFTER(&sensordev_list
, after
, sensdev
, list
);
102 /* Save max sensor device id */
103 sensordev_idmax
= TAILQ_LAST(&sensordev_list
, sensordev_list
)->num
+ 1;
105 /* Install sysctl node for this sensor device */
106 sensordev_sysctl_install(sensdev
);
112 sensor_attach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
114 struct ksensor
*v
, *nv
;
115 struct ksensors_head
*sh
;
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;
125 SLIST_INSERT_HEAD(sh
, sens
, list
);
127 for (v
= SLIST_FIRST(sh
);
128 (nv
= SLIST_NEXT(v
, list
)) != NULL
; v
= nv
)
129 if (v
->type
== sens
->type
&& (v
->type
!= nv
->type
||
130 (v
->type
== nv
->type
&& nv
->numt
- v
->numt
> 1)))
132 /* sensors of the same type go after each other */
133 if (v
->type
== sens
->type
)
134 sens
->numt
= v
->numt
+ 1;
137 SLIST_INSERT_AFTER(v
, sens
, list
);
140 * We only increment maxnumt[] if the sensor was added
141 * to the last position of sensors of this type
143 if (sensdev
->maxnumt
[sens
->type
] == sens
->numt
)
144 sensdev
->maxnumt
[sens
->type
]++;
145 sensdev
->sensors_count
++;
147 /* Install sysctl node for this sensor */
148 sensor_sysctl_install(sensdev
, sens
);
154 sensordev_deinstall(struct ksensordev
*sensdev
)
156 struct ksensordev
*last
;
160 TAILQ_REMOVE(&sensordev_list
, sensdev
, list
);
162 /* Adjust max sensor device id */
163 last
= TAILQ_LAST(&sensordev_list
, sensordev_list
);
165 sensordev_idmax
= last
->num
+ 1;
170 * Deinstall sensor device's sysctl node; this also
171 * removes all attached sensors' sysctl nodes.
173 sensordev_sysctl_deinstall(sensdev
);
179 sensor_detach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
181 struct ksensors_head
*sh
;
185 sh
= &sensdev
->sensors_list
;
186 sensdev
->sensors_count
--;
187 SLIST_REMOVE(sh
, sens
, ksensor
, list
);
189 * We only decrement maxnumt[] if this is the tail
190 * sensor of this type
192 if (sens
->numt
== sensdev
->maxnumt
[sens
->type
] - 1)
193 sensdev
->maxnumt
[sens
->type
]--;
195 /* Deinstall sensor's sysctl node */
196 sensor_sysctl_deinstall(sensdev
, sens
);
201 static struct ksensordev
*
202 sensordev_get(int num
)
204 struct ksensordev
*sd
;
206 SYSCTL_ASSERT_LOCKED();
208 TAILQ_FOREACH(sd
, &sensordev_list
, list
) {
215 static struct ksensor
*
216 sensor_find(struct ksensordev
*sensdev
, enum sensor_type type
, int numt
)
219 struct ksensors_head
*sh
;
221 SYSCTL_ASSERT_LOCKED();
223 sh
= &sensdev
->sensors_list
;
224 SLIST_FOREACH(s
, sh
, list
) {
225 if (s
->type
== type
&& s
->numt
== numt
)
232 sensor_task_register(void *arg
, void (*func
)(void *), int period
)
234 sensor_task_register2(arg
, func
, period
, -1);
238 sensor_task_unregister(void *arg
)
240 struct sensor_taskthr
*thr
;
241 struct sensor_task
*st
;
243 thr
= &sensor_task_threads
[sensor_task_default_cpu
];
244 lockmgr(&thr
->lock
, LK_EXCLUSIVE
);
245 TAILQ_FOREACH(st
, &thr
->list
, entry
)
248 lockmgr(&thr
->lock
, LK_RELEASE
);
252 sensor_task_unregister2(struct sensor_task
*st
)
254 struct sensor_taskthr
*thr
;
256 KASSERT(st
->cpuid
>= 0 && st
->cpuid
< ncpus
,
257 ("invalid task cpuid %d", st
->cpuid
));
258 thr
= &sensor_task_threads
[st
->cpuid
];
261 * Hold the lock then zero-out running, so upon returning
262 * to the caller, the task will no longer run.
264 lockmgr(&thr
->lock
, LK_EXCLUSIVE
);
266 lockmgr(&thr
->lock
, LK_RELEASE
);
270 sensor_task_register2(void *arg
, void (*func
)(void *), int period
, int cpu
)
272 struct sensor_taskthr
*thr
;
273 struct sensor_task
*st
;
276 cpu
= sensor_task_default_cpu
;
277 KASSERT(cpu
>= 0 && cpu
< ncpus
, ("invalid cpuid %d", cpu
));
278 thr
= &sensor_task_threads
[cpu
];
280 st
= kmalloc(sizeof(struct sensor_task
), M_DEVBUF
, M_WAITOK
);
282 lockmgr(&thr
->lock
, LK_EXCLUSIVE
);
291 TAILQ_INSERT_HEAD(&thr
->list
, st
, entry
);
295 lockmgr(&thr
->lock
, LK_RELEASE
);
301 sensor_task_thread(void *xthr
)
303 struct sensor_taskthr
*thr
= xthr
;
304 struct sensor_task
*st
, *nst
;
307 lockmgr(&thr
->lock
, LK_EXCLUSIVE
);
310 while (TAILQ_EMPTY(&thr
->list
))
311 lksleep(&thr
->list
, &thr
->lock
, 0, "waittask", 0);
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
);
319 while ((st
= nst
) != NULL
) {
320 nst
= TAILQ_NEXT(st
, entry
);
322 if (st
->nextrun
> now
)
325 /* take it out while we work on it */
326 TAILQ_REMOVE(&thr
->list
, st
, entry
);
335 /* stick it back in the tasklist */
336 sensor_task_schedule(thr
, st
);
340 lockmgr(&thr
->lock
, LK_RELEASE
);
344 sensor_task_schedule(struct sensor_taskthr
*thr
, struct sensor_task
*st
)
346 struct sensor_task
*cst
;
348 KASSERT(lockstatus(&thr
->lock
, curthread
) == LK_EXCLUSIVE
,
349 ("sensor task lock is not held"));
351 st
->nextrun
= time_uptime
+ st
->period
;
353 TAILQ_FOREACH(cst
, &thr
->list
, entry
) {
354 if (cst
->nextrun
> st
->nextrun
) {
355 TAILQ_INSERT_BEFORE(cst
, st
, entry
);
360 /* must be an empty list, or at the end of the list */
361 TAILQ_INSERT_TAIL(&thr
->list
, st
, entry
);
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
);
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");
376 SYSCTL_INT(_hw_sensors
, OID_AUTO
, dev_idmax
, CTLFLAG_RD
,
377 &sensordev_idmax
, 0, "Max sensor device id");
380 sensordev_sysctl_install(struct ksensordev
*sensdev
)
382 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
384 struct ksensors_head
*sh
= &sensdev
->sensors_list
;
386 SYSCTL_ASSERT_LOCKED();
388 KASSERT(sensdev
->oid
== NULL
,
389 ("sensor device %s sysctl node already installed", sensdev
->xname
));
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",
400 /* Install sysctl nodes for sensors attached to this sensor device */
401 SLIST_FOREACH(s
, sh
, list
)
402 sensor_sysctl_install(sensdev
, s
);
406 sensor_sysctl_install(struct ksensordev
*sensdev
, struct ksensor
*sens
)
410 SYSCTL_ASSERT_LOCKED();
412 if (sensdev
->oid
== NULL
) {
413 /* Sensor device sysctl node is not installed yet */
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
));
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
,
428 sensordev_sysctl_deinstall(struct ksensordev
*sensdev
)
430 SYSCTL_ASSERT_LOCKED();
432 if (sensdev
->oid
!= NULL
) {
433 sysctl_ctx_free(&sensdev
->clist
);
439 sensor_sysctl_deinstall(struct ksensordev
*sensdev
, struct ksensor
*sens
)
441 SYSCTL_ASSERT_LOCKED();
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);
451 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
)
453 struct ksensordev
*ksd
= arg1
;
454 struct sensordev
*usd
;
460 /* Grab a copy, to clear the kernel pointers */
461 usd
= kmalloc(sizeof(*usd
), M_TEMP
, M_WAITOK
| M_ZERO
);
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
;
467 error
= SYSCTL_OUT(req
, usd
, sizeof(struct sensordev
));
474 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
)
476 struct ksensor
*ks
= arg1
;
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
));
487 us
->value
= ks
->value
;
489 us
->status
= ks
->status
;
491 us
->flags
= ks
->flags
;
493 error
= SYSCTL_OUT(req
, us
, sizeof(struct sensor
));
500 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
)
503 u_int namelen
= arg2
;
504 struct ksensordev
*ksd
;
507 enum sensor_type type
;
509 if (namelen
!= 1 && namelen
!= 3)
513 if ((ksd
= sensordev_get(dev
)) == NULL
)
517 return (sysctl_handle_sensordev(NULL
, ksd
, 0, req
));
522 if ((ks
= sensor_find(ksd
, type
, numt
)) == NULL
)
524 return (sysctl_handle_sensor(NULL
, ks
, 0, req
));
528 sensor_sysinit(void *arg __unused
)
530 const cpu_node_t
*node
;
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
540 node
= get_cpu_node_by_chipid(0);
541 if (node
!= NULL
&& node
->child_no
> 0)
542 sensor_task_default_cpu
= BSRCPUMASK(node
->members
);
544 sensor_task_default_cpu
= ncpus
- 1;
546 kprintf("sensors: tasks default to cpu%d\n",
547 sensor_task_default_cpu
);
550 for (cpu
= 0; cpu
< ncpus
; ++cpu
) {
551 struct sensor_taskthr
*thr
= &sensor_task_threads
[cpu
];
554 TAILQ_INIT(&thr
->list
);
555 lockinit(&thr
->lock
, "sensorthr", 0, LK_CANRECURSE
);
557 error
= kthread_create_cpu(sensor_task_thread
, thr
, NULL
, cpu
,
560 panic("sensors kthread on cpu%d failed: %d", cpu
, error
);
563 SYSINIT(sensor
, SI_SUB_PRE_DRIVERS
, SI_ORDER_ANY
, sensor_sysinit
, NULL
);