Commit | Line | Data |
---|---|---|
eb3a3472 | 1 | /* $OpenBSD: kern_sensors.c,v 1.19 2007/06/04 18:42:05 deraadt Exp $ */ |
eb3a3472 HT |
2 | |
3 | /* | |
bce291d6 AH |
4 | * (MPSAFE) |
5 | * | |
eb3a3472 HT |
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 | ||
eb3a3472 HT |
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> | |
bce291d6 AH |
30 | #include <sys/spinlock.h> |
31 | #include <sys/spinlock2.h> | |
eb3a3472 | 32 | #include <sys/lock.h> |
a6f507cc | 33 | #include <sys/cpu_topology.h> |
eb3a3472 HT |
34 | |
35 | #include <sys/sysctl.h> | |
36 | #include <sys/sensors.h> | |
37 | ||
2dc01a00 SZ |
38 | static int sensordev_idmax; |
39 | static TAILQ_HEAD(sensordev_list, ksensordev) sensordev_list = | |
27305eac | 40 | TAILQ_HEAD_INITIALIZER(sensordev_list); |
eb3a3472 | 41 | |
8ef41b85 SZ |
42 | static struct ksensordev *sensordev_get(int); |
43 | static struct ksensor *sensor_find(struct ksensordev *, enum sensor_type, | |
44 | int); | |
eb3a3472 HT |
45 | |
46 | struct sensor_task { | |
47 | void *arg; | |
48 | void (*func)(void *); | |
49 | ||
50 | int period; | |
cec73927 | 51 | time_t nextrun; /* time_uptime */ |
72a4f168 | 52 | int running; |
f95d9b17 | 53 | int cpuid; |
eb3a3472 HT |
54 | TAILQ_ENTRY(sensor_task) entry; |
55 | }; | |
f95d9b17 | 56 | TAILQ_HEAD(sensor_tasklist, sensor_task); |
eb3a3472 | 57 | |
f95d9b17 SZ |
58 | struct sensor_taskthr { |
59 | struct sensor_tasklist list; | |
60 | struct lock lock; | |
61 | }; | |
eb3a3472 | 62 | |
f95d9b17 SZ |
63 | static void sensor_task_thread(void *); |
64 | static void sensor_task_schedule(struct sensor_taskthr *, | |
65 | struct sensor_task *); | |
8dc374fa | 66 | |
dfb94396 SZ |
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 *); | |
eb3a3472 | 73 | |
f95d9b17 | 74 | static struct sensor_taskthr sensor_task_threads[MAXCPU]; |
a6f507cc | 75 | static int sensor_task_default_cpu; |
f95d9b17 | 76 | |
eb3a3472 HT |
77 | void |
78 | sensordev_install(struct ksensordev *sensdev) | |
79 | { | |
27305eac SZ |
80 | struct ksensordev *v, *after = NULL; |
81 | int num = 0; | |
eb3a3472 | 82 | |
e50eb75e SZ |
83 | SYSCTL_XLOCK(); |
84 | ||
27305eac SZ |
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); | |
eb3a3472 | 98 | } else { |
27305eac | 99 | TAILQ_INSERT_AFTER(&sensordev_list, after, sensdev, list); |
eb3a3472 | 100 | } |
eb3a3472 | 101 | |
2dc01a00 SZ |
102 | /* Save max sensor device id */ |
103 | sensordev_idmax = TAILQ_LAST(&sensordev_list, sensordev_list)->num + 1; | |
104 | ||
dfb94396 SZ |
105 | /* Install sysctl node for this sensor device */ |
106 | sensordev_sysctl_install(sensdev); | |
e50eb75e SZ |
107 | |
108 | SYSCTL_XUNLOCK(); | |
eb3a3472 HT |
109 | } |
110 | ||
111 | void | |
112 | sensor_attach(struct ksensordev *sensdev, struct ksensor *sens) | |
113 | { | |
114 | struct ksensor *v, *nv; | |
115 | struct ksensors_head *sh; | |
116 | int i; | |
117 | ||
e50eb75e SZ |
118 | SYSCTL_XLOCK(); |
119 | ||
eb3a3472 HT |
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) | |
d314b0e9 SW |
129 | if (v->type == sens->type && |
130 | (v->type != nv->type || nv->numt - v->numt > 1)) | |
eb3a3472 HT |
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 | } | |
e50eb75e SZ |
139 | /* |
140 | * We only increment maxnumt[] if the sensor was added | |
eb3a3472 HT |
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++; | |
e50eb75e | 146 | |
dfb94396 SZ |
147 | /* Install sysctl node for this sensor */ |
148 | sensor_sysctl_install(sensdev, sens); | |
149 | ||
e50eb75e | 150 | SYSCTL_XUNLOCK(); |
eb3a3472 HT |
151 | } |
152 | ||
153 | void | |
154 | sensordev_deinstall(struct ksensordev *sensdev) | |
155 | { | |
2dc01a00 SZ |
156 | struct ksensordev *last; |
157 | ||
e50eb75e SZ |
158 | SYSCTL_XLOCK(); |
159 | ||
27305eac | 160 | TAILQ_REMOVE(&sensordev_list, sensdev, list); |
eb3a3472 | 161 | |
2dc01a00 SZ |
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 | ||
dfb94396 SZ |
169 | /* |
170 | * Deinstall sensor device's sysctl node; this also | |
171 | * removes all attached sensors' sysctl nodes. | |
172 | */ | |
173 | sensordev_sysctl_deinstall(sensdev); | |
e50eb75e SZ |
174 | |
175 | SYSCTL_XUNLOCK(); | |
eb3a3472 HT |
176 | } |
177 | ||
178 | void | |
179 | sensor_detach(struct ksensordev *sensdev, struct ksensor *sens) | |
180 | { | |
181 | struct ksensors_head *sh; | |
182 | ||
e50eb75e SZ |
183 | SYSCTL_XLOCK(); |
184 | ||
eb3a3472 HT |
185 | sh = &sensdev->sensors_list; |
186 | sensdev->sensors_count--; | |
187 | SLIST_REMOVE(sh, sens, ksensor, list); | |
e50eb75e SZ |
188 | /* |
189 | * We only decrement maxnumt[] if this is the tail | |
eb3a3472 HT |
190 | * sensor of this type |
191 | */ | |
192 | if (sens->numt == sensdev->maxnumt[sens->type] - 1) | |
193 | sensdev->maxnumt[sens->type]--; | |
e50eb75e | 194 | |
dfb94396 SZ |
195 | /* Deinstall sensor's sysctl node */ |
196 | sensor_sysctl_deinstall(sensdev, sens); | |
197 | ||
e50eb75e | 198 | SYSCTL_XUNLOCK(); |
eb3a3472 HT |
199 | } |
200 | ||
8ef41b85 | 201 | static struct ksensordev * |
eb3a3472 HT |
202 | sensordev_get(int num) |
203 | { | |
204 | struct ksensordev *sd; | |
205 | ||
b750642b | 206 | SYSCTL_ASSERT_LOCKED(); |
eb3a3472 | 207 | |
27305eac | 208 | TAILQ_FOREACH(sd, &sensordev_list, list) { |
e50eb75e SZ |
209 | if (sd->num == num) |
210 | return (sd); | |
211 | } | |
eb3a3472 HT |
212 | return (NULL); |
213 | } | |
214 | ||
8ef41b85 | 215 | static struct ksensor * |
eb3a3472 HT |
216 | sensor_find(struct ksensordev *sensdev, enum sensor_type type, int numt) |
217 | { | |
218 | struct ksensor *s; | |
219 | struct ksensors_head *sh; | |
220 | ||
b750642b | 221 | SYSCTL_ASSERT_LOCKED(); |
e50eb75e | 222 | |
eb3a3472 | 223 | sh = &sensdev->sensors_list; |
bce291d6 | 224 | SLIST_FOREACH(s, sh, list) { |
e50eb75e | 225 | if (s->type == type && s->numt == numt) |
eb3a3472 | 226 | return (s); |
bce291d6 | 227 | } |
eb3a3472 HT |
228 | return (NULL); |
229 | } | |
230 | ||
1bedd63a | 231 | void |
eb3a3472 HT |
232 | sensor_task_register(void *arg, void (*func)(void *), int period) |
233 | { | |
f8f01153 | 234 | sensor_task_register2(arg, func, period, -1); |
f95d9b17 SZ |
235 | } |
236 | ||
237 | void | |
238 | sensor_task_unregister(void *arg) | |
239 | { | |
a6f507cc | 240 | struct sensor_taskthr *thr; |
eb3a3472 | 241 | struct sensor_task *st; |
eb3a3472 | 242 | |
a6f507cc | 243 | thr = &sensor_task_threads[sensor_task_default_cpu]; |
f95d9b17 SZ |
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 | |
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 * | |
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 | ||
f8f01153 | 275 | if (cpu < 0) |
a6f507cc | 276 | cpu = sensor_task_default_cpu; |
f95d9b17 SZ |
277 | KASSERT(cpu >= 0 && cpu < ncpus, ("invalid cpuid %d", cpu)); |
278 | thr = &sensor_task_threads[cpu]; | |
279 | ||
1bedd63a | 280 | st = kmalloc(sizeof(struct sensor_task), M_DEVBUF, M_WAITOK); |
eb3a3472 | 281 | |
f95d9b17 | 282 | lockmgr(&thr->lock, LK_EXCLUSIVE); |
eb3a3472 HT |
283 | st->arg = arg; |
284 | st->func = func; | |
285 | st->period = period; | |
f95d9b17 | 286 | st->cpuid = cpu; |
eb3a3472 HT |
287 | |
288 | st->running = 1; | |
289 | ||
eb3a3472 | 290 | st->nextrun = 0; |
f95d9b17 | 291 | TAILQ_INSERT_HEAD(&thr->list, st, entry); |
eb3a3472 | 292 | |
f95d9b17 | 293 | wakeup(&thr->list); |
eb3a3472 | 294 | |
f95d9b17 | 295 | lockmgr(&thr->lock, LK_RELEASE); |
eb3a3472 | 296 | |
f95d9b17 | 297 | return st; |
eb3a3472 HT |
298 | } |
299 | ||
8ef41b85 | 300 | static void |
f95d9b17 | 301 | sensor_task_thread(void *xthr) |
eb3a3472 | 302 | { |
f95d9b17 | 303 | struct sensor_taskthr *thr = xthr; |
eb3a3472 HT |
304 | struct sensor_task *st, *nst; |
305 | time_t now; | |
306 | ||
f95d9b17 | 307 | lockmgr(&thr->lock, LK_EXCLUSIVE); |
cd8ab232 | 308 | |
8dc374fa | 309 | for (;;) { |
f95d9b17 SZ |
310 | while (TAILQ_EMPTY(&thr->list)) |
311 | lksleep(&thr->list, &thr->lock, 0, "waittask", 0); | |
8dc374fa | 312 | |
f95d9b17 | 313 | while ((nst = TAILQ_FIRST(&thr->list))->nextrun > |
a6a80759 | 314 | (now = time_uptime)) { |
f95d9b17 | 315 | lksleep(&thr->list, &thr->lock, 0, |
a6a80759 SZ |
316 | "timeout", (nst->nextrun - now) * hz); |
317 | } | |
eb3a3472 HT |
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 */ | |
f95d9b17 | 326 | TAILQ_REMOVE(&thr->list, st, entry); |
eb3a3472 HT |
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 */ | |
f95d9b17 | 336 | sensor_task_schedule(thr, st); |
eb3a3472 HT |
337 | } |
338 | } | |
339 | ||
f95d9b17 | 340 | lockmgr(&thr->lock, LK_RELEASE); |
eb3a3472 HT |
341 | } |
342 | ||
8ef41b85 | 343 | static void |
f95d9b17 | 344 | sensor_task_schedule(struct sensor_taskthr *thr, struct sensor_task *st) |
eb3a3472 HT |
345 | { |
346 | struct sensor_task *cst; | |
347 | ||
f95d9b17 | 348 | KASSERT(lockstatus(&thr->lock, curthread) == LK_EXCLUSIVE, |
c1bc662c SZ |
349 | ("sensor task lock is not held")); |
350 | ||
cec73927 | 351 | st->nextrun = time_uptime + st->period; |
eb3a3472 | 352 | |
f95d9b17 | 353 | TAILQ_FOREACH(cst, &thr->list, entry) { |
eb3a3472 HT |
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 */ | |
f95d9b17 | 361 | TAILQ_INSERT_TAIL(&thr->list, st, entry); |
eb3a3472 HT |
362 | } |
363 | ||
364 | /* | |
365 | * sysctl glue code | |
366 | */ | |
8ef41b85 SZ |
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); | |
eb3a3472 | 370 | |
eb3a3472 HT |
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 | ||
2dc01a00 SZ |
376 | SYSCTL_INT(_hw_sensors, OID_AUTO, dev_idmax, CTLFLAG_RD, |
377 | &sensordev_idmax, 0, "Max sensor device id"); | |
378 | ||
8ef41b85 | 379 | static void |
dfb94396 | 380 | sensordev_sysctl_install(struct ksensordev *sensdev) |
eb3a3472 | 381 | { |
eb3a3472 HT |
382 | struct sysctl_ctx_list *cl = &sensdev->clist; |
383 | struct ksensor *s; | |
384 | struct ksensors_head *sh = &sensdev->sensors_list; | |
385 | ||
b750642b | 386 | SYSCTL_ASSERT_LOCKED(); |
e50eb75e | 387 | |
dfb94396 SZ |
388 | KASSERT(sensdev->oid == NULL, |
389 | ("sensor device %s sysctl node already installed", sensdev->xname)); | |
390 | ||
eb3a3472 | 391 | sysctl_ctx_init(cl); |
2ce2b389 SZ |
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 | ||
dfb94396 SZ |
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 | |
406 | sensor_sysctl_install(struct ksensordev *sensdev, struct ksensor *sens) | |
407 | { | |
408 | char n[32]; | |
409 | ||
b750642b | 410 | SYSCTL_ASSERT_LOCKED(); |
eb3a3472 | 411 | |
dfb94396 SZ |
412 | if (sensdev->oid == NULL) { |
413 | /* Sensor device sysctl node is not installed yet */ | |
414 | return; | |
eb3a3472 | 415 | } |
dfb94396 SZ |
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", ""); | |
eb3a3472 HT |
425 | } |
426 | ||
8ef41b85 | 427 | static void |
dfb94396 | 428 | sensordev_sysctl_deinstall(struct ksensordev *sensdev) |
eb3a3472 | 429 | { |
b750642b | 430 | SYSCTL_ASSERT_LOCKED(); |
e50eb75e | 431 | |
dfb94396 | 432 | if (sensdev->oid != NULL) { |
2ce2b389 | 433 | sysctl_ctx_free(&sensdev->clist); |
dfb94396 SZ |
434 | sensdev->oid = NULL; |
435 | } | |
436 | } | |
437 | ||
438 | static void | |
439 | sensor_sysctl_deinstall(struct ksensordev *sensdev, struct ksensor *sens) | |
440 | { | |
b750642b | 441 | SYSCTL_ASSERT_LOCKED(); |
dfb94396 SZ |
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; | |
eb3a3472 HT |
448 | } |
449 | ||
8ef41b85 | 450 | static int |
eb3a3472 HT |
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 */ | |
e7b4468c | 461 | usd = kmalloc(sizeof(*usd), M_TEMP, M_WAITOK | M_ZERO); |
eb3a3472 HT |
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); | |
eb3a3472 HT |
471 | } |
472 | ||
8ef41b85 | 473 | static int |
eb3a3472 HT |
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 */ | |
e7b4468c | 484 | us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO); |
eb3a3472 HT |
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 | ||
8ef41b85 | 499 | static int |
eb3a3472 HT |
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 | } | |
8dc374fa SZ |
526 | |
527 | static void | |
528 | sensor_sysinit(void *arg __unused) | |
529 | { | |
a6f507cc | 530 | const cpu_node_t *node; |
f95d9b17 SZ |
531 | int cpu; |
532 | ||
a6f507cc SZ |
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 | ||
f95d9b17 SZ |
550 | for (cpu = 0; cpu < ncpus; ++cpu) { |
551 | struct sensor_taskthr *thr = &sensor_task_threads[cpu]; | |
552 | int error; | |
8dc374fa | 553 | |
f95d9b17 SZ |
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 | } | |
8dc374fa SZ |
562 | } |
563 | SYSINIT(sensor, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, sensor_sysinit, NULL); |