xref: /dflybsd-src/sys/kern/kern_sensors.c (revision a9660653ed54a7af1cb6e46ab910a8e2be16c031)
1eb3a3472SHasso Tepper /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */
2eb3a3472SHasso Tepper 
3eb3a3472SHasso Tepper /*
4bce291d6SAlex Hornung  * (MPSAFE)
5bce291d6SAlex Hornung  *
6eb3a3472SHasso Tepper  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
7eb3a3472SHasso Tepper  * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
8eb3a3472SHasso Tepper  *
9eb3a3472SHasso Tepper  * Permission to use, copy, modify, and distribute this software for any
10eb3a3472SHasso Tepper  * purpose with or without fee is hereby granted, provided that the above
11eb3a3472SHasso Tepper  * copyright notice and this permission notice appear in all copies.
12eb3a3472SHasso Tepper  *
13eb3a3472SHasso Tepper  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14eb3a3472SHasso Tepper  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15eb3a3472SHasso Tepper  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16eb3a3472SHasso Tepper  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17eb3a3472SHasso Tepper  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18eb3a3472SHasso Tepper  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19eb3a3472SHasso Tepper  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20eb3a3472SHasso Tepper  */
21eb3a3472SHasso Tepper 
22eb3a3472SHasso Tepper #include <sys/param.h>
23eb3a3472SHasso Tepper #include <sys/systm.h>
24eb3a3472SHasso Tepper #include <sys/kernel.h>
25eb3a3472SHasso Tepper #include <sys/malloc.h>
26eb3a3472SHasso Tepper #include <sys/kthread.h>
27eb3a3472SHasso Tepper #include <sys/queue.h>
28eb3a3472SHasso Tepper #include <sys/types.h>
29eb3a3472SHasso Tepper #include <sys/time.h>
30bce291d6SAlex Hornung #include <sys/spinlock.h>
31bce291d6SAlex Hornung #include <sys/spinlock2.h>
32eb3a3472SHasso Tepper #include <sys/lock.h>
33a6f507ccSSepherosa Ziehau #include <sys/cpu_topology.h>
34eb3a3472SHasso Tepper 
35eb3a3472SHasso Tepper #include <sys/sysctl.h>
36eb3a3472SHasso Tepper #include <sys/sensors.h>
37eb3a3472SHasso Tepper 
382dc01a00SSepherosa Ziehau static int		sensordev_idmax;
392dc01a00SSepherosa Ziehau static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
4027305eacSSepherosa Ziehau     TAILQ_HEAD_INITIALIZER(sensordev_list);
41eb3a3472SHasso Tepper 
428ef41b85SSepherosa Ziehau static struct ksensordev *sensordev_get(int);
438ef41b85SSepherosa Ziehau static struct ksensor	*sensor_find(struct ksensordev *, enum sensor_type,
448ef41b85SSepherosa Ziehau 			    int);
45eb3a3472SHasso Tepper 
46eb3a3472SHasso Tepper struct sensor_task {
47eb3a3472SHasso Tepper 	void				*arg;
48eb3a3472SHasso Tepper 	void				(*func)(void *);
49eb3a3472SHasso Tepper 
50eb3a3472SHasso Tepper 	int				period;
51cec73927SMatthew Dillon 	time_t				nextrun;	/* time_uptime */
5272a4f168SSepherosa Ziehau 	int				running;
53f95d9b17SSepherosa Ziehau 	int				cpuid;
54eb3a3472SHasso Tepper 	TAILQ_ENTRY(sensor_task)	entry;
55eb3a3472SHasso Tepper };
56f95d9b17SSepherosa Ziehau TAILQ_HEAD(sensor_tasklist, sensor_task);
57f95d9b17SSepherosa Ziehau 
58f95d9b17SSepherosa Ziehau struct sensor_taskthr {
59f95d9b17SSepherosa Ziehau 	struct sensor_tasklist		list;
60f95d9b17SSepherosa Ziehau 	struct lock			lock;
61f95d9b17SSepherosa Ziehau };
62eb3a3472SHasso Tepper 
638ef41b85SSepherosa Ziehau static void		sensor_task_thread(void *);
64f95d9b17SSepherosa Ziehau static void		sensor_task_schedule(struct sensor_taskthr *,
65f95d9b17SSepherosa Ziehau 			    struct sensor_task *);
668dc374faSSepherosa Ziehau 
67dfb94396SSepherosa Ziehau static void		sensordev_sysctl_install(struct ksensordev *);
68dfb94396SSepherosa Ziehau static void		sensordev_sysctl_deinstall(struct ksensordev *);
69dfb94396SSepherosa Ziehau static void		sensor_sysctl_install(struct ksensordev *,
70dfb94396SSepherosa Ziehau 			    struct ksensor *);
71dfb94396SSepherosa Ziehau static void		sensor_sysctl_deinstall(struct ksensordev *,
72dfb94396SSepherosa Ziehau 			    struct ksensor *);
73eb3a3472SHasso Tepper 
74f95d9b17SSepherosa Ziehau static struct sensor_taskthr sensor_task_threads[MAXCPU];
75a6f507ccSSepherosa Ziehau static int		sensor_task_default_cpu;
76f95d9b17SSepherosa Ziehau 
77eb3a3472SHasso Tepper void
sensordev_install(struct ksensordev * sensdev)78eb3a3472SHasso Tepper sensordev_install(struct ksensordev *sensdev)
79eb3a3472SHasso Tepper {
8027305eacSSepherosa Ziehau 	struct ksensordev *v, *after = NULL;
8127305eacSSepherosa Ziehau 	int num = 0;
82eb3a3472SHasso Tepper 
83e50eb75eSSepherosa Ziehau 	SYSCTL_XLOCK();
84e50eb75eSSepherosa Ziehau 
8527305eacSSepherosa Ziehau 	TAILQ_FOREACH(v, &sensordev_list, list) {
8627305eacSSepherosa Ziehau 		if (v->num == num) {
8727305eacSSepherosa Ziehau 			++num;
8827305eacSSepherosa Ziehau 			after = v;
8927305eacSSepherosa Ziehau 		} else if (v->num > num) {
90eb3a3472SHasso Tepper 			break;
91eb3a3472SHasso Tepper 		}
9227305eacSSepherosa Ziehau 	}
9327305eacSSepherosa Ziehau 
9427305eacSSepherosa Ziehau 	sensdev->num = num;
9527305eacSSepherosa Ziehau 	if (after == NULL) {
9627305eacSSepherosa Ziehau 		KKASSERT(sensdev->num == 0);
9727305eacSSepherosa Ziehau 		TAILQ_INSERT_HEAD(&sensordev_list, sensdev, list);
9827305eacSSepherosa Ziehau 	} else {
9927305eacSSepherosa Ziehau 		TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list);
10027305eacSSepherosa Ziehau 	}
101eb3a3472SHasso Tepper 
1022dc01a00SSepherosa Ziehau 	/* Save max sensor device id */
1032dc01a00SSepherosa Ziehau 	sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
1042dc01a00SSepherosa Ziehau 
105dfb94396SSepherosa Ziehau 	/* Install sysctl node for this sensor device */
106dfb94396SSepherosa Ziehau 	sensordev_sysctl_install(sensdev);
107e50eb75eSSepherosa Ziehau 
108e50eb75eSSepherosa Ziehau 	SYSCTL_XUNLOCK();
109eb3a3472SHasso Tepper }
110eb3a3472SHasso Tepper 
111eb3a3472SHasso Tepper void
sensor_attach(struct ksensordev * sensdev,struct ksensor * sens)112eb3a3472SHasso Tepper sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
113eb3a3472SHasso Tepper {
114eb3a3472SHasso Tepper 	struct ksensor *v, *nv;
115eb3a3472SHasso Tepper 	struct ksensors_head *sh;
116eb3a3472SHasso Tepper 	int i;
117eb3a3472SHasso Tepper 
118e50eb75eSSepherosa Ziehau 	SYSCTL_XLOCK();
119e50eb75eSSepherosa Ziehau 
120eb3a3472SHasso Tepper 	sh = &sensdev->sensors_list;
121eb3a3472SHasso Tepper 	if (sensdev->sensors_count == 0) {
122eb3a3472SHasso Tepper 		for (i = 0; i < SENSOR_MAX_TYPES; i++)
123eb3a3472SHasso Tepper 			sensdev->maxnumt[i] = 0;
124eb3a3472SHasso Tepper 		sens->numt = 0;
125eb3a3472SHasso Tepper 		SLIST_INSERT_HEAD(sh, sens, list);
126eb3a3472SHasso Tepper 	} else {
127eb3a3472SHasso Tepper 		for (v = SLIST_FIRST(sh);
128eb3a3472SHasso Tepper 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
129*d314b0e9SSascha Wildner 			if (v->type == sens->type &&
130*d314b0e9SSascha Wildner 			    (v->type != nv->type || nv->numt - v->numt > 1))
131eb3a3472SHasso Tepper 				break;
132eb3a3472SHasso Tepper 		/* sensors of the same type go after each other */
133eb3a3472SHasso Tepper 		if (v->type == sens->type)
134eb3a3472SHasso Tepper 			sens->numt = v->numt + 1;
135eb3a3472SHasso Tepper 		else
136eb3a3472SHasso Tepper 			sens->numt = 0;
137eb3a3472SHasso Tepper 		SLIST_INSERT_AFTER(v, sens, list);
138eb3a3472SHasso Tepper 	}
139e50eb75eSSepherosa Ziehau 	/*
140e50eb75eSSepherosa Ziehau 	 * We only increment maxnumt[] if the sensor was added
141eb3a3472SHasso Tepper 	 * to the last position of sensors of this type
142eb3a3472SHasso Tepper 	 */
143eb3a3472SHasso Tepper 	if (sensdev->maxnumt[sens->type] == sens->numt)
144eb3a3472SHasso Tepper 		sensdev->maxnumt[sens->type]++;
145eb3a3472SHasso Tepper 	sensdev->sensors_count++;
146e50eb75eSSepherosa Ziehau 
147dfb94396SSepherosa Ziehau 	/* Install sysctl node for this sensor */
148dfb94396SSepherosa Ziehau 	sensor_sysctl_install(sensdev, sens);
149dfb94396SSepherosa Ziehau 
150e50eb75eSSepherosa Ziehau 	SYSCTL_XUNLOCK();
151eb3a3472SHasso Tepper }
152eb3a3472SHasso Tepper 
153eb3a3472SHasso Tepper void
sensordev_deinstall(struct ksensordev * sensdev)154eb3a3472SHasso Tepper sensordev_deinstall(struct ksensordev *sensdev)
155eb3a3472SHasso Tepper {
1562dc01a00SSepherosa Ziehau 	struct ksensordev *last;
1572dc01a00SSepherosa Ziehau 
158e50eb75eSSepherosa Ziehau 	SYSCTL_XLOCK();
159e50eb75eSSepherosa Ziehau 
16027305eacSSepherosa Ziehau 	TAILQ_REMOVE(&sensordev_list, sensdev, list);
161eb3a3472SHasso Tepper 
1622dc01a00SSepherosa Ziehau 	/* Adjust max sensor device id */
1632dc01a00SSepherosa Ziehau 	last = TAILQ_LAST(&sensordev_list, sensordev_list);
1642dc01a00SSepherosa Ziehau 	if (last != NULL)
1652dc01a00SSepherosa Ziehau 		sensordev_idmax = last->num + 1;
1662dc01a00SSepherosa Ziehau 	else
1672dc01a00SSepherosa Ziehau 		sensordev_idmax = 0;
1682dc01a00SSepherosa Ziehau 
169dfb94396SSepherosa Ziehau 	/*
170dfb94396SSepherosa Ziehau 	 * Deinstall sensor device's sysctl node; this also
171dfb94396SSepherosa Ziehau 	 * removes all attached sensors' sysctl nodes.
172dfb94396SSepherosa Ziehau 	 */
173dfb94396SSepherosa Ziehau 	sensordev_sysctl_deinstall(sensdev);
174e50eb75eSSepherosa Ziehau 
175e50eb75eSSepherosa Ziehau 	SYSCTL_XUNLOCK();
176eb3a3472SHasso Tepper }
177eb3a3472SHasso Tepper 
178eb3a3472SHasso Tepper void
sensor_detach(struct ksensordev * sensdev,struct ksensor * sens)179eb3a3472SHasso Tepper sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
180eb3a3472SHasso Tepper {
181eb3a3472SHasso Tepper 	struct ksensors_head *sh;
182eb3a3472SHasso Tepper 
183e50eb75eSSepherosa Ziehau 	SYSCTL_XLOCK();
184e50eb75eSSepherosa Ziehau 
185eb3a3472SHasso Tepper 	sh = &sensdev->sensors_list;
186eb3a3472SHasso Tepper 	sensdev->sensors_count--;
187eb3a3472SHasso Tepper 	SLIST_REMOVE(sh, sens, ksensor, list);
188e50eb75eSSepherosa Ziehau 	/*
189e50eb75eSSepherosa Ziehau 	 * We only decrement maxnumt[] if this is the tail
190eb3a3472SHasso Tepper 	 * sensor of this type
191eb3a3472SHasso Tepper 	 */
192eb3a3472SHasso Tepper 	if (sens->numt == sensdev->maxnumt[sens->type] - 1)
193eb3a3472SHasso Tepper 		sensdev->maxnumt[sens->type]--;
194e50eb75eSSepherosa Ziehau 
195dfb94396SSepherosa Ziehau 	/* Deinstall sensor's sysctl node */
196dfb94396SSepherosa Ziehau 	sensor_sysctl_deinstall(sensdev, sens);
197dfb94396SSepherosa Ziehau 
198e50eb75eSSepherosa Ziehau 	SYSCTL_XUNLOCK();
199eb3a3472SHasso Tepper }
200eb3a3472SHasso Tepper 
2018ef41b85SSepherosa Ziehau static struct ksensordev *
sensordev_get(int num)202eb3a3472SHasso Tepper sensordev_get(int num)
203eb3a3472SHasso Tepper {
204eb3a3472SHasso Tepper 	struct ksensordev *sd;
205eb3a3472SHasso Tepper 
206b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
207e50eb75eSSepherosa Ziehau 
20827305eacSSepherosa Ziehau 	TAILQ_FOREACH(sd, &sensordev_list, list) {
209e50eb75eSSepherosa Ziehau 		if (sd->num == num)
210eb3a3472SHasso Tepper 			return (sd);
211bce291d6SAlex Hornung 	}
212eb3a3472SHasso Tepper 	return (NULL);
213eb3a3472SHasso Tepper }
214eb3a3472SHasso Tepper 
2158ef41b85SSepherosa Ziehau static struct ksensor *
sensor_find(struct ksensordev * sensdev,enum sensor_type type,int numt)216eb3a3472SHasso Tepper sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
217eb3a3472SHasso Tepper {
218eb3a3472SHasso Tepper 	struct ksensor *s;
219eb3a3472SHasso Tepper 	struct ksensors_head *sh;
220eb3a3472SHasso Tepper 
221b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
222e50eb75eSSepherosa Ziehau 
223eb3a3472SHasso Tepper 	sh = &sensdev->sensors_list;
224bce291d6SAlex Hornung 	SLIST_FOREACH(s, sh, list) {
225e50eb75eSSepherosa Ziehau 		if (s->type == type && s->numt == numt)
226eb3a3472SHasso Tepper 			return (s);
227bce291d6SAlex Hornung 	}
228eb3a3472SHasso Tepper 	return (NULL);
229eb3a3472SHasso Tepper }
230eb3a3472SHasso Tepper 
2311bedd63aSSepherosa Ziehau void
sensor_task_register(void * arg,void (* func)(void *),int period)232eb3a3472SHasso Tepper sensor_task_register(void *arg, void (*func)(void *), int period)
233eb3a3472SHasso Tepper {
234f8f01153SSepherosa Ziehau 	sensor_task_register2(arg, func, period, -1);
235eb3a3472SHasso Tepper }
236eb3a3472SHasso Tepper 
237eb3a3472SHasso Tepper void
sensor_task_unregister(void * arg)238eb3a3472SHasso Tepper sensor_task_unregister(void *arg)
239eb3a3472SHasso Tepper {
240a6f507ccSSepherosa Ziehau 	struct sensor_taskthr	*thr;
241eb3a3472SHasso Tepper 	struct sensor_task	*st;
242eb3a3472SHasso Tepper 
243a6f507ccSSepherosa Ziehau 	thr = &sensor_task_threads[sensor_task_default_cpu];
244f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_EXCLUSIVE);
245f95d9b17SSepherosa Ziehau 	TAILQ_FOREACH(st, &thr->list, entry)
246eb3a3472SHasso Tepper 		if (st->arg == arg)
247eb3a3472SHasso Tepper 			st->running = 0;
248f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_RELEASE);
249f95d9b17SSepherosa Ziehau }
250f95d9b17SSepherosa Ziehau 
251f95d9b17SSepherosa Ziehau void
sensor_task_unregister2(struct sensor_task * st)252f95d9b17SSepherosa Ziehau sensor_task_unregister2(struct sensor_task *st)
253f95d9b17SSepherosa Ziehau {
254f95d9b17SSepherosa Ziehau 	struct sensor_taskthr *thr;
255f95d9b17SSepherosa Ziehau 
256f95d9b17SSepherosa Ziehau 	KASSERT(st->cpuid >= 0 && st->cpuid < ncpus,
257f95d9b17SSepherosa Ziehau 	    ("invalid task cpuid %d", st->cpuid));
258f95d9b17SSepherosa Ziehau 	thr = &sensor_task_threads[st->cpuid];
259f95d9b17SSepherosa Ziehau 
260f95d9b17SSepherosa Ziehau 	/*
261f95d9b17SSepherosa Ziehau 	 * Hold the lock then zero-out running, so upon returning
262f95d9b17SSepherosa Ziehau 	 * to the caller, the task will no longer run.
263f95d9b17SSepherosa Ziehau 	 */
264f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_EXCLUSIVE);
265f95d9b17SSepherosa Ziehau 	st->running = 0;
266f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_RELEASE);
267f95d9b17SSepherosa Ziehau }
268f95d9b17SSepherosa Ziehau 
269f95d9b17SSepherosa Ziehau struct sensor_task *
sensor_task_register2(void * arg,void (* func)(void *),int period,int cpu)270f95d9b17SSepherosa Ziehau sensor_task_register2(void *arg, void (*func)(void *), int period, int cpu)
271f95d9b17SSepherosa Ziehau {
272f95d9b17SSepherosa Ziehau 	struct sensor_taskthr	*thr;
273f95d9b17SSepherosa Ziehau 	struct sensor_task	*st;
274f95d9b17SSepherosa Ziehau 
275f8f01153SSepherosa Ziehau 	if (cpu < 0)
276a6f507ccSSepherosa Ziehau 		cpu = sensor_task_default_cpu;
277f95d9b17SSepherosa Ziehau 	KASSERT(cpu >= 0 && cpu < ncpus, ("invalid cpuid %d", cpu));
278f95d9b17SSepherosa Ziehau 	thr = &sensor_task_threads[cpu];
279f95d9b17SSepherosa Ziehau 
280f95d9b17SSepherosa Ziehau 	st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
281f95d9b17SSepherosa Ziehau 
282f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_EXCLUSIVE);
283f95d9b17SSepherosa Ziehau 	st->arg = arg;
284f95d9b17SSepherosa Ziehau 	st->func = func;
285f95d9b17SSepherosa Ziehau 	st->period = period;
286f95d9b17SSepherosa Ziehau 	st->cpuid = cpu;
287f95d9b17SSepherosa Ziehau 
288f95d9b17SSepherosa Ziehau 	st->running = 1;
289f95d9b17SSepherosa Ziehau 
290f95d9b17SSepherosa Ziehau 	st->nextrun = 0;
291f95d9b17SSepherosa Ziehau 	TAILQ_INSERT_HEAD(&thr->list, st, entry);
292f95d9b17SSepherosa Ziehau 
293f95d9b17SSepherosa Ziehau 	wakeup(&thr->list);
294f95d9b17SSepherosa Ziehau 
295f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_RELEASE);
296f95d9b17SSepherosa Ziehau 
297f95d9b17SSepherosa Ziehau 	return st;
298eb3a3472SHasso Tepper }
299eb3a3472SHasso Tepper 
3008ef41b85SSepherosa Ziehau static void
sensor_task_thread(void * xthr)301f95d9b17SSepherosa Ziehau sensor_task_thread(void *xthr)
302eb3a3472SHasso Tepper {
303f95d9b17SSepherosa Ziehau 	struct sensor_taskthr	*thr = xthr;
304eb3a3472SHasso Tepper 	struct sensor_task	*st, *nst;
305eb3a3472SHasso Tepper 	time_t			now;
306eb3a3472SHasso Tepper 
307f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_EXCLUSIVE);
308cd8ab232SMatthew Dillon 
3098dc374faSSepherosa Ziehau 	for (;;) {
310f95d9b17SSepherosa Ziehau 		while (TAILQ_EMPTY(&thr->list))
311f95d9b17SSepherosa Ziehau 			lksleep(&thr->list, &thr->lock, 0, "waittask", 0);
3128dc374faSSepherosa Ziehau 
313f95d9b17SSepherosa Ziehau 		while ((nst = TAILQ_FIRST(&thr->list))->nextrun >
314a6a80759SSepherosa Ziehau 		    (now = time_uptime)) {
315f95d9b17SSepherosa Ziehau 			lksleep(&thr->list, &thr->lock, 0,
316a6a80759SSepherosa Ziehau 			    "timeout", (nst->nextrun - now) * hz);
317a6a80759SSepherosa Ziehau 		}
318eb3a3472SHasso Tepper 
319eb3a3472SHasso Tepper 		while ((st = nst) != NULL) {
320eb3a3472SHasso Tepper 			nst = TAILQ_NEXT(st, entry);
321eb3a3472SHasso Tepper 
322eb3a3472SHasso Tepper 			if (st->nextrun > now)
323eb3a3472SHasso Tepper 				break;
324eb3a3472SHasso Tepper 
325eb3a3472SHasso Tepper 			/* take it out while we work on it */
326f95d9b17SSepherosa Ziehau 			TAILQ_REMOVE(&thr->list, st, entry);
327eb3a3472SHasso Tepper 
328eb3a3472SHasso Tepper 			if (!st->running) {
329eb3a3472SHasso Tepper 				kfree(st, M_DEVBUF);
330eb3a3472SHasso Tepper 				continue;
331eb3a3472SHasso Tepper 			}
332eb3a3472SHasso Tepper 
333eb3a3472SHasso Tepper 			/* run the task */
334eb3a3472SHasso Tepper 			st->func(st->arg);
335eb3a3472SHasso Tepper 			/* stick it back in the tasklist */
336f95d9b17SSepherosa Ziehau 			sensor_task_schedule(thr, st);
337eb3a3472SHasso Tepper 		}
338eb3a3472SHasso Tepper 	}
339eb3a3472SHasso Tepper 
340f95d9b17SSepherosa Ziehau 	lockmgr(&thr->lock, LK_RELEASE);
341eb3a3472SHasso Tepper }
342eb3a3472SHasso Tepper 
3438ef41b85SSepherosa Ziehau static void
sensor_task_schedule(struct sensor_taskthr * thr,struct sensor_task * st)344f95d9b17SSepherosa Ziehau sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st)
345eb3a3472SHasso Tepper {
346eb3a3472SHasso Tepper 	struct sensor_task 	*cst;
347eb3a3472SHasso Tepper 
348f95d9b17SSepherosa Ziehau 	KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE,
349c1bc662cSSepherosa Ziehau 	    ("sensor task lock is not held"));
350c1bc662cSSepherosa Ziehau 
351cec73927SMatthew Dillon 	st->nextrun = time_uptime + st->period;
352eb3a3472SHasso Tepper 
353f95d9b17SSepherosa Ziehau 	TAILQ_FOREACH(cst, &thr->list, entry) {
354eb3a3472SHasso Tepper 		if (cst->nextrun > st->nextrun) {
355eb3a3472SHasso Tepper 			TAILQ_INSERT_BEFORE(cst, st, entry);
356eb3a3472SHasso Tepper 			return;
357eb3a3472SHasso Tepper 		}
358eb3a3472SHasso Tepper 	}
359eb3a3472SHasso Tepper 
360eb3a3472SHasso Tepper 	/* must be an empty list, or at the end of the list */
361f95d9b17SSepherosa Ziehau 	TAILQ_INSERT_TAIL(&thr->list, st, entry);
362eb3a3472SHasso Tepper }
363eb3a3472SHasso Tepper 
364eb3a3472SHasso Tepper /*
365eb3a3472SHasso Tepper  * sysctl glue code
366eb3a3472SHasso Tepper  */
3678ef41b85SSepherosa Ziehau static int	sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
3688ef41b85SSepherosa Ziehau static int	sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
3698ef41b85SSepherosa Ziehau static int	sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
370eb3a3472SHasso Tepper 
371eb3a3472SHasso Tepper SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
372eb3a3472SHasso Tepper     "Hardware Sensors sysctl internal magic");
373eb3a3472SHasso Tepper SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
374eb3a3472SHasso Tepper     "Hardware Sensors XP MIB interface");
375eb3a3472SHasso Tepper 
3762dc01a00SSepherosa Ziehau SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
3772dc01a00SSepherosa Ziehau     &sensordev_idmax, 0, "Max sensor device id");
3782dc01a00SSepherosa Ziehau 
3798ef41b85SSepherosa Ziehau static void
sensordev_sysctl_install(struct ksensordev * sensdev)380dfb94396SSepherosa Ziehau sensordev_sysctl_install(struct ksensordev *sensdev)
381eb3a3472SHasso Tepper {
382eb3a3472SHasso Tepper 	struct sysctl_ctx_list *cl = &sensdev->clist;
383eb3a3472SHasso Tepper 	struct ksensor *s;
384eb3a3472SHasso Tepper 	struct ksensors_head *sh = &sensdev->sensors_list;
385eb3a3472SHasso Tepper 
386b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
387e50eb75eSSepherosa Ziehau 
388dfb94396SSepherosa Ziehau 	KASSERT(sensdev->oid == NULL,
389dfb94396SSepherosa Ziehau 	    ("sensor device %s sysctl node already installed", sensdev->xname));
390dfb94396SSepherosa Ziehau 
391eb3a3472SHasso Tepper 	sysctl_ctx_init(cl);
3922ce2b389SSepherosa Ziehau 	sensdev->oid = SYSCTL_ADD_NODE(cl, SYSCTL_STATIC_CHILDREN(_hw_sensors),
3932ce2b389SSepherosa Ziehau 	    sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, "");
3942ce2b389SSepherosa Ziehau 	if (sensdev->oid == NULL) {
3952ce2b389SSepherosa Ziehau 		kprintf("sensor: add sysctl tree for %s failed\n",
3962ce2b389SSepherosa Ziehau 		    sensdev->xname);
3972ce2b389SSepherosa Ziehau 		return;
3982ce2b389SSepherosa Ziehau 	}
3992ce2b389SSepherosa Ziehau 
400dfb94396SSepherosa Ziehau 	/* Install sysctl nodes for sensors attached to this sensor device */
401dfb94396SSepherosa Ziehau 	SLIST_FOREACH(s, sh, list)
402dfb94396SSepherosa Ziehau 		sensor_sysctl_install(sensdev, s);
403dfb94396SSepherosa Ziehau }
404dfb94396SSepherosa Ziehau 
405dfb94396SSepherosa Ziehau static void
sensor_sysctl_install(struct ksensordev * sensdev,struct ksensor * sens)406dfb94396SSepherosa Ziehau sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
407dfb94396SSepherosa Ziehau {
408eb3a3472SHasso Tepper 	char n[32];
409eb3a3472SHasso Tepper 
410b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
411dfb94396SSepherosa Ziehau 
412dfb94396SSepherosa Ziehau 	if (sensdev->oid == NULL) {
413dfb94396SSepherosa Ziehau 		/* Sensor device sysctl node is not installed yet */
414dfb94396SSepherosa Ziehau 		return;
415dfb94396SSepherosa Ziehau 	}
416dfb94396SSepherosa Ziehau 
417dfb94396SSepherosa Ziehau 	ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[sens->type], sens->numt);
418dfb94396SSepherosa Ziehau 	KASSERT(sens->oid == NULL,
419dfb94396SSepherosa Ziehau 	    ("sensor %s:%s sysctl node already installed", sensdev->xname, n));
420dfb94396SSepherosa Ziehau 
421dfb94396SSepherosa Ziehau 	sens->oid = SYSCTL_ADD_PROC(&sensdev->clist,
422dfb94396SSepherosa Ziehau 	    SYSCTL_CHILDREN(sensdev->oid), OID_AUTO, n,
423dfb94396SSepherosa Ziehau 	    CTLTYPE_STRUCT | CTLFLAG_RD, sens, 0, sysctl_handle_sensor,
424dfb94396SSepherosa Ziehau 	    "S,sensor", "");
425dfb94396SSepherosa Ziehau }
426dfb94396SSepherosa Ziehau 
427dfb94396SSepherosa Ziehau static void
sensordev_sysctl_deinstall(struct ksensordev * sensdev)428dfb94396SSepherosa Ziehau sensordev_sysctl_deinstall(struct ksensordev *sensdev)
429dfb94396SSepherosa Ziehau {
430b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
431dfb94396SSepherosa Ziehau 
432dfb94396SSepherosa Ziehau 	if (sensdev->oid != NULL) {
433dfb94396SSepherosa Ziehau 		sysctl_ctx_free(&sensdev->clist);
434dfb94396SSepherosa Ziehau 		sensdev->oid = NULL;
435eb3a3472SHasso Tepper 	}
436eb3a3472SHasso Tepper }
437eb3a3472SHasso Tepper 
4388ef41b85SSepherosa Ziehau static void
sensor_sysctl_deinstall(struct ksensordev * sensdev,struct ksensor * sens)439dfb94396SSepherosa Ziehau sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
440eb3a3472SHasso Tepper {
441b750642bSSascha Wildner 	SYSCTL_ASSERT_LOCKED();
442e50eb75eSSepherosa Ziehau 
443dfb94396SSepherosa Ziehau 	if (sensdev->oid != NULL && sens->oid != NULL) {
444dfb94396SSepherosa Ziehau 		sysctl_ctx_entry_del(&sensdev->clist, sens->oid);
445dfb94396SSepherosa Ziehau 		sysctl_remove_oid(sens->oid, 1, 0);
446dfb94396SSepherosa Ziehau 	}
447dfb94396SSepherosa Ziehau 	sens->oid = NULL;
448eb3a3472SHasso Tepper }
449eb3a3472SHasso Tepper 
4508ef41b85SSepherosa Ziehau static int
sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)451eb3a3472SHasso Tepper sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
452eb3a3472SHasso Tepper {
453eb3a3472SHasso Tepper 	struct ksensordev *ksd = arg1;
454eb3a3472SHasso Tepper 	struct sensordev *usd;
455eb3a3472SHasso Tepper 	int error;
456eb3a3472SHasso Tepper 
457eb3a3472SHasso Tepper 	if (req->newptr)
458eb3a3472SHasso Tepper 		return (EPERM);
459eb3a3472SHasso Tepper 
460eb3a3472SHasso Tepper 	/* Grab a copy, to clear the kernel pointers */
461e7b4468cSSascha Wildner 	usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
462eb3a3472SHasso Tepper 	usd->num = ksd->num;
463eb3a3472SHasso Tepper 	strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
464eb3a3472SHasso Tepper 	memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
465eb3a3472SHasso Tepper 	usd->sensors_count = ksd->sensors_count;
466eb3a3472SHasso Tepper 
467eb3a3472SHasso Tepper 	error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
468eb3a3472SHasso Tepper 
469eb3a3472SHasso Tepper 	kfree(usd, M_TEMP);
470eb3a3472SHasso Tepper 	return (error);
471eb3a3472SHasso Tepper }
472eb3a3472SHasso Tepper 
4738ef41b85SSepherosa Ziehau static int
sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)474eb3a3472SHasso Tepper sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
475eb3a3472SHasso Tepper {
476eb3a3472SHasso Tepper 	struct ksensor *ks = arg1;
477eb3a3472SHasso Tepper 	struct sensor *us;
478eb3a3472SHasso Tepper 	int error;
479eb3a3472SHasso Tepper 
480eb3a3472SHasso Tepper 	if (req->newptr)
481eb3a3472SHasso Tepper 		return (EPERM);
482eb3a3472SHasso Tepper 
483eb3a3472SHasso Tepper 	/* Grab a copy, to clear the kernel pointers */
484e7b4468cSSascha Wildner 	us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
485eb3a3472SHasso Tepper 	memcpy(us->desc, ks->desc, sizeof(ks->desc));
486eb3a3472SHasso Tepper 	us->tv = ks->tv;
487eb3a3472SHasso Tepper 	us->value = ks->value;
488eb3a3472SHasso Tepper 	us->type = ks->type;
489eb3a3472SHasso Tepper 	us->status = ks->status;
490eb3a3472SHasso Tepper 	us->numt = ks->numt;
491eb3a3472SHasso Tepper 	us->flags = ks->flags;
492eb3a3472SHasso Tepper 
493eb3a3472SHasso Tepper 	error = SYSCTL_OUT(req, us, sizeof(struct sensor));
494eb3a3472SHasso Tepper 
495eb3a3472SHasso Tepper 	kfree(us, M_TEMP);
496eb3a3472SHasso Tepper 	return (error);
497eb3a3472SHasso Tepper }
498eb3a3472SHasso Tepper 
4998ef41b85SSepherosa Ziehau static int
sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)500eb3a3472SHasso Tepper sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
501eb3a3472SHasso Tepper {
502eb3a3472SHasso Tepper 	int *name = arg1;
503eb3a3472SHasso Tepper 	u_int namelen = arg2;
504eb3a3472SHasso Tepper 	struct ksensordev *ksd;
505eb3a3472SHasso Tepper 	struct ksensor *ks;
506eb3a3472SHasso Tepper 	int dev, numt;
507eb3a3472SHasso Tepper 	enum sensor_type type;
508eb3a3472SHasso Tepper 
509eb3a3472SHasso Tepper 	if (namelen != 1 && namelen != 3)
510eb3a3472SHasso Tepper 		return (ENOTDIR);
511eb3a3472SHasso Tepper 
512eb3a3472SHasso Tepper 	dev = name[0];
513eb3a3472SHasso Tepper 	if ((ksd = sensordev_get(dev)) == NULL)
514eb3a3472SHasso Tepper 		return (ENOENT);
515eb3a3472SHasso Tepper 
516eb3a3472SHasso Tepper 	if (namelen == 1)
517eb3a3472SHasso Tepper 		return (sysctl_handle_sensordev(NULL, ksd, 0, req));
518eb3a3472SHasso Tepper 
519eb3a3472SHasso Tepper 	type = name[1];
520eb3a3472SHasso Tepper 	numt = name[2];
521eb3a3472SHasso Tepper 
522eb3a3472SHasso Tepper 	if ((ks = sensor_find(ksd, type, numt)) == NULL)
523eb3a3472SHasso Tepper 		return (ENOENT);
524eb3a3472SHasso Tepper 	return (sysctl_handle_sensor(NULL, ks, 0, req));
525eb3a3472SHasso Tepper }
5268dc374faSSepherosa Ziehau 
5278dc374faSSepherosa Ziehau static void
sensor_sysinit(void * arg __unused)5288dc374faSSepherosa Ziehau sensor_sysinit(void *arg __unused)
5298dc374faSSepherosa Ziehau {
530a6f507ccSSepherosa Ziehau 	const cpu_node_t *node;
531f95d9b17SSepherosa Ziehau 	int cpu;
5328dc374faSSepherosa Ziehau 
533a6f507ccSSepherosa Ziehau 	/*
534a6f507ccSSepherosa Ziehau 	 * By default, stick sensor tasks to the cpu belonging to
535a6f507ccSSepherosa Ziehau 	 * the first cpu package, since most of the time accessing
536a6f507ccSSepherosa Ziehau 	 * sensor devices from the first cpu package will be faster,
537a6f507ccSSepherosa Ziehau 	 * e.g. through DMI or DMI2 on Intel CPUs; no QPI will be
538a6f507ccSSepherosa Ziehau 	 * generated.
539a6f507ccSSepherosa Ziehau 	 */
540a6f507ccSSepherosa Ziehau 	node = get_cpu_node_by_chipid(0);
541a6f507ccSSepherosa Ziehau 	if (node != NULL && node->child_no > 0)
542a6f507ccSSepherosa Ziehau 		sensor_task_default_cpu = BSRCPUMASK(node->members);
543a6f507ccSSepherosa Ziehau 	else
544a6f507ccSSepherosa Ziehau 		sensor_task_default_cpu = ncpus - 1;
545a6f507ccSSepherosa Ziehau 	if (bootverbose) {
546a6f507ccSSepherosa Ziehau 		kprintf("sensors: tasks default to cpu%d\n",
547a6f507ccSSepherosa Ziehau 		    sensor_task_default_cpu);
548a6f507ccSSepherosa Ziehau 	}
549a6f507ccSSepherosa Ziehau 
550f95d9b17SSepherosa Ziehau 	for (cpu = 0; cpu < ncpus; ++cpu) {
551f95d9b17SSepherosa Ziehau 		struct sensor_taskthr *thr = &sensor_task_threads[cpu];
552f95d9b17SSepherosa Ziehau 		int error;
553f95d9b17SSepherosa Ziehau 
554f95d9b17SSepherosa Ziehau 		TAILQ_INIT(&thr->list);
555f95d9b17SSepherosa Ziehau 		lockinit(&thr->lock, "sensorthr", 0, LK_CANRECURSE);
556f95d9b17SSepherosa Ziehau 
557f95d9b17SSepherosa Ziehau 		error = kthread_create_cpu(sensor_task_thread, thr, NULL, cpu,
558f95d9b17SSepherosa Ziehau 		    "sensors %d", cpu);
5598dc374faSSepherosa Ziehau 		if (error)
5601c05a629SSepherosa Ziehau 			panic("sensors kthread on cpu%d failed: %d", cpu, error);
5618dc374faSSepherosa Ziehau 	}
562f95d9b17SSepherosa Ziehau }
5638dc374faSSepherosa Ziehau SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);
564