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