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