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 #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
,
53 time_t nextrun
; /* time_uptime */
56 TAILQ_ENTRY(sensor_task
) entry
;
58 TAILQ_HEAD(sensor_tasklist
, sensor_task
);
60 struct sensor_taskthr
{
61 struct sensor_tasklist list
;
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
*,
73 static void sensor_sysctl_deinstall(struct ksensordev
*,
76 static struct sensor_taskthr sensor_task_threads
[MAXCPU
];
77 static int sensor_task_default_cpu
;
80 sensordev_install(struct ksensordev
*sensdev
)
82 struct ksensordev
*v
, *after
= NULL
;
87 TAILQ_FOREACH(v
, &sensordev_list
, list
) {
91 } else if (v
->num
> num
) {
98 KKASSERT(sensdev
->num
== 0);
99 TAILQ_INSERT_HEAD(&sensordev_list
, sensdev
, list
);
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
);
114 sensor_attach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
116 struct ksensor
*v
, *nv
;
117 struct ksensors_head
*sh
;
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;
127 SLIST_INSERT_HEAD(sh
, sens
, list
);
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)))
134 /* sensors of the same type go after each other */
135 if (v
->type
== sens
->type
)
136 sens
->numt
= v
->numt
+ 1;
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
);
156 sensordev_deinstall(struct ksensordev
*sensdev
)
158 struct ksensordev
*last
;
162 TAILQ_REMOVE(&sensordev_list
, sensdev
, list
);
164 /* Adjust max sensor device id */
165 last
= TAILQ_LAST(&sensordev_list
, sensordev_list
);
167 sensordev_idmax
= last
->num
+ 1;
172 * Deinstall sensor device's sysctl node; this also
173 * removes all attached sensors' sysctl nodes.
175 sensordev_sysctl_deinstall(sensdev
);
181 sensor_detach(struct ksensordev
*sensdev
, struct ksensor
*sens
)
183 struct ksensors_head
*sh
;
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
);
203 static struct ksensordev
*
204 sensordev_get(int num
)
206 struct ksensordev
*sd
;
208 SYSCTL_ASSERT_LOCKED();
210 TAILQ_FOREACH(sd
, &sensordev_list
, list
) {
217 static struct ksensor
*
218 sensor_find(struct ksensordev
*sensdev
, enum sensor_type type
, int numt
)
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
)
234 sensor_task_register(void *arg
, void (*func
)(void *), int period
)
236 sensor_task_register2(arg
, func
, period
, -1);
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
)
250 lockmgr(&thr
->lock
, LK_RELEASE
);
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
);
268 lockmgr(&thr
->lock
, LK_RELEASE
);
272 sensor_task_register2(void *arg
, void (*func
)(void *), int period
, int cpu
)
274 struct sensor_taskthr
*thr
;
275 struct sensor_task
*st
;
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
);
293 TAILQ_INSERT_HEAD(&thr
->list
, st
, entry
);
297 lockmgr(&thr
->lock
, LK_RELEASE
);
303 sensor_task_thread(void *xthr
)
305 struct sensor_taskthr
*thr
= xthr
;
306 struct sensor_task
*st
, *nst
;
309 lockmgr(&thr
->lock
, LK_EXCLUSIVE
);
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
)
327 /* take it out while we work on it */
328 TAILQ_REMOVE(&thr
->list
, st
, entry
);
337 /* stick it back in the tasklist */
338 sensor_task_schedule(thr
, st
);
342 lockmgr(&thr
->lock
, LK_RELEASE
);
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
);
362 /* must be an empty list, or at the end of the list */
363 TAILQ_INSERT_TAIL(&thr
->list
, st
, entry
);
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");
382 sensordev_sysctl_install(struct ksensordev
*sensdev
)
384 struct sysctl_ctx_list
*cl
= &sensdev
->clist
;
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
));
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",
402 /* Install sysctl nodes for sensors attached to this sensor device */
403 SLIST_FOREACH(s
, sh
, list
)
404 sensor_sysctl_install(sensdev
, s
);
408 sensor_sysctl_install(struct ksensordev
*sensdev
, struct ksensor
*sens
)
412 SYSCTL_ASSERT_LOCKED();
414 if (sensdev
->oid
== NULL
) {
415 /* Sensor device sysctl node is not installed yet */
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
,
430 sensordev_sysctl_deinstall(struct ksensordev
*sensdev
)
432 SYSCTL_ASSERT_LOCKED();
434 if (sensdev
->oid
!= NULL
) {
435 sysctl_ctx_free(&sensdev
->clist
);
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);
453 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS
)
455 struct ksensordev
*ksd
= arg1
;
456 struct sensordev
*usd
;
462 /* Grab a copy, to clear the kernel pointers */
463 usd
= kmalloc(sizeof(*usd
), M_TEMP
, M_WAITOK
| M_ZERO
);
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
));
476 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS
)
478 struct ksensor
*ks
= arg1
;
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
));
489 us
->value
= ks
->value
;
491 us
->status
= ks
->status
;
493 us
->flags
= ks
->flags
;
495 error
= SYSCTL_OUT(req
, us
, sizeof(struct sensor
));
502 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS
)
505 u_int namelen
= arg2
;
506 struct ksensordev
*ksd
;
509 enum sensor_type type
;
511 if (namelen
!= 1 && namelen
!= 3)
515 if ((ksd
= sensordev_get(dev
)) == NULL
)
519 return (sysctl_handle_sensordev(NULL
, ksd
, 0, req
));
524 if ((ks
= sensor_find(ksd
, type
, numt
)) == NULL
)
526 return (sysctl_handle_sensor(NULL
, ks
, 0, req
));
530 sensor_sysinit(void *arg __unused
)
532 const cpu_node_t
*node
;
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
542 node
= get_cpu_node_by_chipid(0);
543 if (node
!= NULL
&& node
->child_no
> 0)
544 sensor_task_default_cpu
= BSRCPUMASK(node
->members
);
546 sensor_task_default_cpu
= ncpus
- 1;
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
];
556 TAILQ_INIT(&thr
->list
);
557 lockinit(&thr
->lock
, "sensorthr", 0, LK_CANRECURSE
);
559 error
= kthread_create_cpu(sensor_task_thread
, thr
, NULL
, cpu
,
562 panic("sensors kthread on cpu%d failed: %d", cpu
, error
);
565 SYSINIT(sensor
, SI_SUB_PRE_DRIVERS
, SI_ORDER_ANY
, sensor_sysinit
, NULL
);