xref: /dflybsd-src/sys/kern/kern_sensors.c (revision e9a2e4da6a6e12849337a6b7d04c2f3c62865759)
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 
34 #include <sys/sysctl.h>
35 #include <sys/sensors.h>
36 
37 #include <sys/mplock2.h>
38 
39 /*
40  * Default to the last cpu's sensor thread
41  */
42 #define SENSOR_TASK_DEFCPU	(ncpus - 1)
43 
44 static int		sensordev_idmax;
45 static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list =
46     TAILQ_HEAD_INITIALIZER(sensordev_list);
47 
48 static struct ksensordev *sensordev_get(int);
49 static struct ksensor	*sensor_find(struct ksensordev *, enum sensor_type,
50 			    int);
51 
52 struct sensor_task {
53 	void				*arg;
54 	void				(*func)(void *);
55 
56 	int				period;
57 	time_t				nextrun;	/* time_uptime */
58 	int				running;
59 	int				cpuid;
60 	TAILQ_ENTRY(sensor_task)	entry;
61 };
62 TAILQ_HEAD(sensor_tasklist, sensor_task);
63 
64 struct sensor_taskthr {
65 	struct sensor_tasklist		list;
66 	struct lock			lock;
67 };
68 
69 static void		sensor_task_thread(void *);
70 static void		sensor_task_schedule(struct sensor_taskthr *,
71 			    struct sensor_task *);
72 
73 static void		sensordev_sysctl_install(struct ksensordev *);
74 static void		sensordev_sysctl_deinstall(struct ksensordev *);
75 static void		sensor_sysctl_install(struct ksensordev *,
76 			    struct ksensor *);
77 static void		sensor_sysctl_deinstall(struct ksensordev *,
78 			    struct ksensor *);
79 
80 static struct sensor_taskthr sensor_task_threads[MAXCPU];
81 
82 void
83 sensordev_install(struct ksensordev *sensdev)
84 {
85 	struct ksensordev *v, *after = NULL;
86 	int num = 0;
87 
88 	SYSCTL_XLOCK();
89 
90 	TAILQ_FOREACH(v, &sensordev_list, list) {
91 		if (v->num == num) {
92 			++num;
93 			after = v;
94 		} else if (v->num > num) {
95 			break;
96 		}
97 	}
98 
99 	sensdev->num = num;
100 	if (after == NULL) {
101 		KKASSERT(sensdev->num == 0);
102 		TAILQ_INSERT_HEAD(&sensordev_list, sensdev, list);
103 	} else {
104 		TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list);
105 	}
106 
107 	/* Save max sensor device id */
108 	sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1;
109 
110 	/* Install sysctl node for this sensor device */
111 	sensordev_sysctl_install(sensdev);
112 
113 	SYSCTL_XUNLOCK();
114 }
115 
116 void
117 sensor_attach(struct ksensordev *sensdev, struct ksensor *sens)
118 {
119 	struct ksensor *v, *nv;
120 	struct ksensors_head *sh;
121 	int i;
122 
123 	SYSCTL_XLOCK();
124 
125 	sh = &sensdev->sensors_list;
126 	if (sensdev->sensors_count == 0) {
127 		for (i = 0; i < SENSOR_MAX_TYPES; i++)
128 			sensdev->maxnumt[i] = 0;
129 		sens->numt = 0;
130 		SLIST_INSERT_HEAD(sh, sens, list);
131 	} else {
132 		for (v = SLIST_FIRST(sh);
133 		    (nv = SLIST_NEXT(v, list)) != NULL; v = nv)
134 			if (v->type == sens->type && (v->type != nv->type ||
135 			    (v->type == nv->type && nv->numt - v->numt > 1)))
136 				break;
137 		/* sensors of the same type go after each other */
138 		if (v->type == sens->type)
139 			sens->numt = v->numt + 1;
140 		else
141 			sens->numt = 0;
142 		SLIST_INSERT_AFTER(v, sens, list);
143 	}
144 	/*
145 	 * We only increment maxnumt[] if the sensor was added
146 	 * to the last position of sensors of this type
147 	 */
148 	if (sensdev->maxnumt[sens->type] == sens->numt)
149 		sensdev->maxnumt[sens->type]++;
150 	sensdev->sensors_count++;
151 
152 	/* Install sysctl node for this sensor */
153 	sensor_sysctl_install(sensdev, sens);
154 
155 	SYSCTL_XUNLOCK();
156 }
157 
158 void
159 sensordev_deinstall(struct ksensordev *sensdev)
160 {
161 	struct ksensordev *last;
162 
163 	SYSCTL_XLOCK();
164 
165 	TAILQ_REMOVE(&sensordev_list, sensdev, list);
166 
167 	/* Adjust max sensor device id */
168 	last = TAILQ_LAST(&sensordev_list, sensordev_list);
169 	if (last != NULL)
170 		sensordev_idmax = last->num + 1;
171 	else
172 		sensordev_idmax = 0;
173 
174 	/*
175 	 * Deinstall sensor device's sysctl node; this also
176 	 * removes all attached sensors' sysctl nodes.
177 	 */
178 	sensordev_sysctl_deinstall(sensdev);
179 
180 	SYSCTL_XUNLOCK();
181 }
182 
183 void
184 sensor_detach(struct ksensordev *sensdev, struct ksensor *sens)
185 {
186 	struct ksensors_head *sh;
187 
188 	SYSCTL_XLOCK();
189 
190 	sh = &sensdev->sensors_list;
191 	sensdev->sensors_count--;
192 	SLIST_REMOVE(sh, sens, ksensor, list);
193 	/*
194 	 * We only decrement maxnumt[] if this is the tail
195 	 * sensor of this type
196 	 */
197 	if (sens->numt == sensdev->maxnumt[sens->type] - 1)
198 		sensdev->maxnumt[sens->type]--;
199 
200 	/* Deinstall sensor's sysctl node */
201 	sensor_sysctl_deinstall(sensdev, sens);
202 
203 	SYSCTL_XUNLOCK();
204 }
205 
206 static struct ksensordev *
207 sensordev_get(int num)
208 {
209 	struct ksensordev *sd;
210 
211 	SYSCTL_ASSERT_XLOCKED();
212 
213 	TAILQ_FOREACH(sd, &sensordev_list, list) {
214 		if (sd->num == num)
215 			return (sd);
216 	}
217 	return (NULL);
218 }
219 
220 static struct ksensor *
221 sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt)
222 {
223 	struct ksensor *s;
224 	struct ksensors_head *sh;
225 
226 	SYSCTL_ASSERT_XLOCKED();
227 
228 	sh = &sensdev->sensors_list;
229 	SLIST_FOREACH(s, sh, list) {
230 		if (s->type == type && s->numt == numt)
231 			return (s);
232 	}
233 	return (NULL);
234 }
235 
236 void
237 sensor_task_register(void *arg, void (*func)(void *), int period)
238 {
239 	sensor_task_register2(arg, func, period, -1);
240 }
241 
242 void
243 sensor_task_unregister(void *arg)
244 {
245 	struct sensor_taskthr	*thr = &sensor_task_threads[SENSOR_TASK_DEFCPU];
246 	struct sensor_task	*st;
247 
248 	lockmgr(&thr->lock, LK_EXCLUSIVE);
249 	TAILQ_FOREACH(st, &thr->list, entry)
250 		if (st->arg == arg)
251 			st->running = 0;
252 	lockmgr(&thr->lock, LK_RELEASE);
253 }
254 
255 void
256 sensor_task_unregister2(struct sensor_task *st)
257 {
258 	struct sensor_taskthr *thr;
259 
260 	KASSERT(st->cpuid >= 0 && st->cpuid < ncpus,
261 	    ("invalid task cpuid %d", st->cpuid));
262 	thr = &sensor_task_threads[st->cpuid];
263 
264 	/*
265 	 * Hold the lock then zero-out running, so upon returning
266 	 * to the caller, the task will no longer run.
267 	 */
268 	lockmgr(&thr->lock, LK_EXCLUSIVE);
269 	st->running = 0;
270 	lockmgr(&thr->lock, LK_RELEASE);
271 }
272 
273 struct sensor_task *
274 sensor_task_register2(void *arg, void (*func)(void *), int period, int cpu)
275 {
276 	struct sensor_taskthr	*thr;
277 	struct sensor_task	*st;
278 
279 	if (cpu < 0)
280 		cpu = SENSOR_TASK_DEFCPU;
281 	KASSERT(cpu >= 0 && cpu < ncpus, ("invalid cpuid %d", cpu));
282 	thr = &sensor_task_threads[cpu];
283 
284 	st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK);
285 
286 	lockmgr(&thr->lock, LK_EXCLUSIVE);
287 	st->arg = arg;
288 	st->func = func;
289 	st->period = period;
290 	st->cpuid = cpu;
291 
292 	st->running = 1;
293 
294 	st->nextrun = 0;
295 	TAILQ_INSERT_HEAD(&thr->list, st, entry);
296 
297 	wakeup(&thr->list);
298 
299 	lockmgr(&thr->lock, LK_RELEASE);
300 
301 	return st;
302 }
303 
304 static void
305 sensor_task_thread(void *xthr)
306 {
307 	struct sensor_taskthr	*thr = xthr;
308 	struct sensor_task	*st, *nst;
309 	time_t			now;
310 
311 	lockmgr(&thr->lock, LK_EXCLUSIVE);
312 
313 	for (;;) {
314 		while (TAILQ_EMPTY(&thr->list))
315 			lksleep(&thr->list, &thr->lock, 0, "waittask", 0);
316 
317 		while ((nst = TAILQ_FIRST(&thr->list))->nextrun >
318 		    (now = time_uptime)) {
319 			lksleep(&thr->list, &thr->lock, 0,
320 			    "timeout", (nst->nextrun - now) * hz);
321 		}
322 
323 		while ((st = nst) != NULL) {
324 			nst = TAILQ_NEXT(st, entry);
325 
326 			if (st->nextrun > now)
327 				break;
328 
329 			/* take it out while we work on it */
330 			TAILQ_REMOVE(&thr->list, st, entry);
331 
332 			if (!st->running) {
333 				kfree(st, M_DEVBUF);
334 				continue;
335 			}
336 
337 			/* run the task */
338 			st->func(st->arg);
339 			/* stick it back in the tasklist */
340 			sensor_task_schedule(thr, st);
341 		}
342 	}
343 
344 	lockmgr(&thr->lock, LK_RELEASE);
345 }
346 
347 static void
348 sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st)
349 {
350 	struct sensor_task 	*cst;
351 
352 	KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE,
353 	    ("sensor task lock is not held"));
354 
355 	st->nextrun = time_uptime + st->period;
356 
357 	TAILQ_FOREACH(cst, &thr->list, entry) {
358 		if (cst->nextrun > st->nextrun) {
359 			TAILQ_INSERT_BEFORE(cst, st, entry);
360 			return;
361 		}
362 	}
363 
364 	/* must be an empty list, or at the end of the list */
365 	TAILQ_INSERT_TAIL(&thr->list, st, entry);
366 }
367 
368 /*
369  * sysctl glue code
370  */
371 static int	sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS);
372 static int	sysctl_handle_sensor(SYSCTL_HANDLER_ARGS);
373 static int	sysctl_sensors_handler(SYSCTL_HANDLER_ARGS);
374 
375 SYSCTL_NODE(_hw, OID_AUTO, sensors, CTLFLAG_RD, NULL,
376     "Hardware Sensors sysctl internal magic");
377 SYSCTL_NODE(_hw, HW_SENSORS, _sensors, CTLFLAG_RD, sysctl_sensors_handler,
378     "Hardware Sensors XP MIB interface");
379 
380 SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD,
381     &sensordev_idmax, 0, "Max sensor device id");
382 
383 static void
384 sensordev_sysctl_install(struct ksensordev *sensdev)
385 {
386 	struct sysctl_ctx_list *cl = &sensdev->clist;
387 	struct ksensor *s;
388 	struct ksensors_head *sh = &sensdev->sensors_list;
389 
390 	SYSCTL_ASSERT_XLOCKED();
391 
392 	KASSERT(sensdev->oid == NULL,
393 	    ("sensor device %s sysctl node already installed", sensdev->xname));
394 
395 	sysctl_ctx_init(cl);
396 	sensdev->oid = SYSCTL_ADD_NODE(cl, SYSCTL_STATIC_CHILDREN(_hw_sensors),
397 	    sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, "");
398 	if (sensdev->oid == NULL) {
399 		kprintf("sensor: add sysctl tree for %s failed\n",
400 		    sensdev->xname);
401 		return;
402 	}
403 
404 	/* Install sysctl nodes for sensors attached to this sensor device */
405 	SLIST_FOREACH(s, sh, list)
406 		sensor_sysctl_install(sensdev, s);
407 }
408 
409 static void
410 sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens)
411 {
412 	char n[32];
413 
414 	SYSCTL_ASSERT_XLOCKED();
415 
416 	if (sensdev->oid == NULL) {
417 		/* Sensor device sysctl node is not installed yet */
418 		return;
419 	}
420 
421 	ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[sens->type], sens->numt);
422 	KASSERT(sens->oid == NULL,
423 	    ("sensor %s:%s sysctl node already installed", sensdev->xname, n));
424 
425 	sens->oid = SYSCTL_ADD_PROC(&sensdev->clist,
426 	    SYSCTL_CHILDREN(sensdev->oid), OID_AUTO, n,
427 	    CTLTYPE_STRUCT | CTLFLAG_RD, sens, 0, sysctl_handle_sensor,
428 	    "S,sensor", "");
429 }
430 
431 static void
432 sensordev_sysctl_deinstall(struct ksensordev *sensdev)
433 {
434 	SYSCTL_ASSERT_XLOCKED();
435 
436 	if (sensdev->oid != NULL) {
437 		sysctl_ctx_free(&sensdev->clist);
438 		sensdev->oid = NULL;
439 	}
440 }
441 
442 static void
443 sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens)
444 {
445 	SYSCTL_ASSERT_XLOCKED();
446 
447 	if (sensdev->oid != NULL && sens->oid != NULL) {
448 		sysctl_ctx_entry_del(&sensdev->clist, sens->oid);
449 		sysctl_remove_oid(sens->oid, 1, 0);
450 	}
451 	sens->oid = NULL;
452 }
453 
454 static int
455 sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS)
456 {
457 	struct ksensordev *ksd = arg1;
458 	struct sensordev *usd;
459 	int error;
460 
461 	if (req->newptr)
462 		return (EPERM);
463 
464 	/* Grab a copy, to clear the kernel pointers */
465 	usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO);
466 	usd->num = ksd->num;
467 	strlcpy(usd->xname, ksd->xname, sizeof(usd->xname));
468 	memcpy(usd->maxnumt, ksd->maxnumt, sizeof(usd->maxnumt));
469 	usd->sensors_count = ksd->sensors_count;
470 
471 	error = SYSCTL_OUT(req, usd, sizeof(struct sensordev));
472 
473 	kfree(usd, M_TEMP);
474 	return (error);
475 }
476 
477 static int
478 sysctl_handle_sensor(SYSCTL_HANDLER_ARGS)
479 {
480 	struct ksensor *ks = arg1;
481 	struct sensor *us;
482 	int error;
483 
484 	if (req->newptr)
485 		return (EPERM);
486 
487 	/* Grab a copy, to clear the kernel pointers */
488 	us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO);
489 	memcpy(us->desc, ks->desc, sizeof(ks->desc));
490 	us->tv = ks->tv;
491 	us->value = ks->value;
492 	us->type = ks->type;
493 	us->status = ks->status;
494 	us->numt = ks->numt;
495 	us->flags = ks->flags;
496 
497 	error = SYSCTL_OUT(req, us, sizeof(struct sensor));
498 
499 	kfree(us, M_TEMP);
500 	return (error);
501 }
502 
503 static int
504 sysctl_sensors_handler(SYSCTL_HANDLER_ARGS)
505 {
506 	int *name = arg1;
507 	u_int namelen = arg2;
508 	struct ksensordev *ksd;
509 	struct ksensor *ks;
510 	int dev, numt;
511 	enum sensor_type type;
512 
513 	if (namelen != 1 && namelen != 3)
514 		return (ENOTDIR);
515 
516 	dev = name[0];
517 	if ((ksd = sensordev_get(dev)) == NULL)
518 		return (ENOENT);
519 
520 	if (namelen == 1)
521 		return (sysctl_handle_sensordev(NULL, ksd, 0, req));
522 
523 	type = name[1];
524 	numt = name[2];
525 
526 	if ((ks = sensor_find(ksd, type, numt)) == NULL)
527 		return (ENOENT);
528 	return (sysctl_handle_sensor(NULL, ks, 0, req));
529 }
530 
531 static void
532 sensor_sysinit(void *arg __unused)
533 {
534 	int cpu;
535 
536 	for (cpu = 0; cpu < ncpus; ++cpu) {
537 		struct sensor_taskthr *thr = &sensor_task_threads[cpu];
538 		int error;
539 
540 		TAILQ_INIT(&thr->list);
541 		lockinit(&thr->lock, "sensorthr", 0, LK_CANRECURSE);
542 
543 		error = kthread_create_cpu(sensor_task_thread, thr, NULL, cpu,
544 		    "sensors %d", cpu);
545 		if (error)
546 			panic("sensors kthread on cpu%d failed: %d", cpu, error);
547 	}
548 }
549 SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL);
550