kernel: Move semicolon from the definition of SYSINIT() to its invocations.
[dragonfly.git] / sys / kern / kern_cputimer.c
1 /*
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Generic cputimer - access to a reliable, free-running counter.
36  */
37
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/thread.h>
42 #include <sys/globaldata.h>
43 #include <sys/serialize.h>
44 #include <sys/systimer.h>
45 #include <sys/sysctl.h>
46 #include <sys/thread2.h>
47
48 static sysclock_t dummy_cputimer_count(void);
49
50 static struct cputimer dummy_cputimer = {
51     SLIST_ENTRY_INITIALIZER,
52     "dummy",
53     CPUTIMER_PRI_DUMMY,
54     CPUTIMER_DUMMY,
55     dummy_cputimer_count,
56     cputimer_default_fromhz,
57     cputimer_default_fromus,
58     cputimer_default_construct,
59     cputimer_default_destruct,
60     1000000,
61     (1000000LL << 32) / 1000000,
62     (1000000000LL << 32) / 1000000,
63     0
64 };
65
66 struct cputimer *sys_cputimer = &dummy_cputimer;
67 SLIST_HEAD(, cputimer) cputimerhead = SLIST_HEAD_INITIALIZER(&cputimerhead);
68
69 static int      cputimer_intr_ps_reqs;
70 static struct lwkt_serialize cputimer_intr_ps_slize =
71     LWKT_SERIALIZE_INITIALIZER;
72
73 /*
74  * Generic cputimer API
75  */
76 void
77 cputimer_select(struct cputimer *timer, int pri)
78 {
79     sysclock_t oldclock;
80
81     /*
82      * Calculate helper fields
83      */
84     cputimer_set_frequency(timer, timer->freq);
85
86     /*
87      * Install a new cputimer if its priority allows it.  If timer is
88      * passed as NULL we deinstall the current timer and revert to our
89      * dummy.
90      */
91     if (pri == 0)
92         pri = timer->pri;
93     if (timer == NULL || pri >= sys_cputimer->pri) {
94         oldclock = sys_cputimer->count();
95         sys_cputimer->destruct(sys_cputimer);
96         sys_cputimer = &dummy_cputimer;
97         if (timer) {
98             sys_cputimer = timer;
99             timer->construct(timer, oldclock);
100             cputimer_intr_config(timer);
101         }
102     }
103 }
104
105 /*
106  * Register a timer.  If the timer has already been registered, do nothing.
107  */
108 void
109 cputimer_register(struct cputimer *timer)
110 {
111     struct cputimer *scan;
112
113     /*
114      * Initialize dummy_cputimer if the slist is empty, it does not get
115      * registered the normal way.
116      */
117     if (SLIST_EMPTY(&cputimerhead))
118         SLIST_FIRST(&cputimerhead) = &dummy_cputimer;
119     SLIST_FOREACH(scan, &cputimerhead, next) {
120         if (scan == timer)
121             return;
122     }
123     SLIST_INSERT_HEAD(&cputimerhead, timer, next);
124 }
125
126 /*
127  * Deregister a timer.  If the timer has already been deregistered, do nothing.
128  */
129 void
130 cputimer_deregister(struct cputimer *timer)
131 {
132     struct cputimer *scan;
133     struct cputimer *best;
134
135     /*
136      * Locate and remove the timer.  If the timer is our currently active
137      * timer, revert to the dummy timer.
138      */
139     SLIST_FOREACH(scan, &cputimerhead, next) {
140             if (timer == scan) {
141                 if (timer == sys_cputimer)
142                     cputimer_select(&dummy_cputimer, 0x7FFFFFFF);
143                 SLIST_REMOVE(&cputimerhead, timer, cputimer, next);
144                 break;
145             }
146     }
147
148     /*
149      * If sys_cputimer reverted to the dummy, select the best one
150      */
151     if (sys_cputimer == &dummy_cputimer) {
152         best = NULL;
153         SLIST_FOREACH(scan, &cputimerhead, next) {
154             if (best == NULL || scan->pri > best->pri)
155                 best = scan;
156         }
157         if (best)
158             cputimer_select(best, 0x7FFFFFFF);
159     }
160 }
161
162 /*
163  * Calculate usec / tick and nsec / tick, scaled by (1 << 32).
164  *
165  * so e.g. a 3 mhz timer would be 3 usec / tick x (1 << 32),
166  * or 3000 nsec / tick x (1 << 32)
167  */
168 void
169 cputimer_set_frequency(struct cputimer *timer, sysclock_t freq)
170 {
171     timer->freq = freq;
172     timer->freq64_usec = (1000000LL << 32) / freq;
173     timer->freq64_nsec = (1000000000LL << 32) / freq;
174     if (timer == sys_cputimer)
175         cputimer_intr_config(timer);
176 }
177
178 sysclock_t
179 cputimer_default_fromhz(int freq)
180 {
181     return(sys_cputimer->freq / freq + 1);
182 }
183
184 sysclock_t
185 cputimer_default_fromus(int us)
186 {
187     return((int64_t)sys_cputimer->freq * us / 1000000);
188 }
189
190 /*
191  * Dummy counter implementation
192  */
193 static
194 sysclock_t
195 dummy_cputimer_count(void)
196 {
197     return(++dummy_cputimer.base);
198 }
199
200 void
201 cputimer_default_construct(struct cputimer *cputimer, sysclock_t oldclock)
202 {
203     cputimer->base = oldclock;
204 }
205
206 void
207 cputimer_default_destruct(struct cputimer *cputimer)
208 {
209 }
210
211 /************************************************************************
212  *                              SYSCTL SUPPORT                          *
213  ************************************************************************
214  *
215  * Note: the ability to change the systimer is not currently enabled
216  * because it will mess up systimer calculations.  You have to live
217  * with what is configured at boot.
218  */
219 static int
220 sysctl_cputimer_reglist(SYSCTL_HANDLER_ARGS)
221 {
222     struct cputimer *scan;
223     int error = 0;
224     int loop = 0;
225
226     /*
227      * Build a list of available timers
228      */
229     SLIST_FOREACH(scan, &cputimerhead, next) {
230         if (error == 0 && loop)
231             error = SYSCTL_OUT(req, " ", 1);
232         if (error == 0)
233             error = SYSCTL_OUT(req, scan->name, strlen(scan->name));
234         ++loop;
235     }
236     return (error);
237 }
238
239 static int
240 sysctl_cputimer_name(SYSCTL_HANDLER_ARGS)
241 {
242     int error;
243
244     error = SYSCTL_OUT(req, sys_cputimer->name, strlen(sys_cputimer->name));
245     return (error);
246 }
247
248 static int
249 sysctl_cputimer_clock(SYSCTL_HANDLER_ARGS)
250 {
251     sysclock_t clock;
252     int error;
253
254     clock = sys_cputimer->count();
255     error = SYSCTL_OUT(req, &clock, sizeof(clock));
256     return (error);
257 }
258
259 static int
260 sysctl_cputimer_freq(SYSCTL_HANDLER_ARGS)
261 {
262     int error;
263
264     error = SYSCTL_OUT(req, &sys_cputimer->freq, sizeof(sys_cputimer->freq));
265     return (error);
266 }
267
268 SYSCTL_DECL(_kern_cputimer);
269 SYSCTL_NODE(_kern, OID_AUTO, cputimer, CTLFLAG_RW, NULL, "cputimer");
270
271 SYSCTL_PROC(_kern_cputimer, OID_AUTO, select, CTLTYPE_STRING|CTLFLAG_RD,
272             NULL, 0, sysctl_cputimer_reglist, "A", "");
273 SYSCTL_PROC(_kern_cputimer, OID_AUTO, name, CTLTYPE_STRING|CTLFLAG_RD,
274             NULL, 0, sysctl_cputimer_name, "A", "");
275 SYSCTL_PROC(_kern_cputimer, OID_AUTO, clock, CTLTYPE_UINT|CTLFLAG_RD,
276             NULL, 0, sysctl_cputimer_clock, "IU", "");
277 SYSCTL_PROC(_kern_cputimer, OID_AUTO, freq, CTLTYPE_INT|CTLFLAG_RD,
278             NULL, 0, sysctl_cputimer_freq, "I", "");
279
280 static struct cputimer_intr *sys_cputimer_intr;
281 static uint32_t cputimer_intr_caps;
282 SLIST_HEAD(, cputimer_intr) cputimer_intr_head =
283         SLIST_HEAD_INITIALIZER(&cputimer_intr_head);
284
285 void
286 cputimer_intr_register(struct cputimer_intr *cti)
287 {
288     struct cputimer_intr *scan;
289
290     SLIST_FOREACH(scan, &cputimer_intr_head, next) {
291         if (scan == cti)
292             return;
293     }
294     cti->config(cti, sys_cputimer);
295     SLIST_INSERT_HEAD(&cputimer_intr_head, cti, next);
296 }
297
298 void
299 cputimer_intr_deregister(struct cputimer_intr *cti)
300 {
301     KKASSERT(cti != sys_cputimer_intr);
302     SLIST_REMOVE(&cputimer_intr_head, cti, cputimer_intr, next);
303 }
304
305 int
306 cputimer_intr_select(struct cputimer_intr *cti, int prio)
307 {
308     KKASSERT(cti != NULL);
309
310     if (prio == 0)
311         prio = cti->prio;
312
313     if (sys_cputimer_intr == NULL) {
314         KKASSERT(cputimer_intr_caps == 0);
315         sys_cputimer_intr = cti;
316         return 0;
317     }
318
319     if ((cti->caps & cputimer_intr_caps) == cputimer_intr_caps) {
320         if (prio > sys_cputimer_intr->prio) {
321             sys_cputimer_intr = cti;
322             return 0;
323         } else {
324             return EBUSY;
325         }
326     } else {
327         return EOPNOTSUPP;
328     }
329 }
330
331 void
332 cputimer_intr_default_enable(struct cputimer_intr *cti __unused)
333 {
334 }
335
336 void
337 cputimer_intr_default_restart(struct cputimer_intr *cti)
338 {
339     cti->reload(cti, 0);
340 }
341
342 void
343 cputimer_intr_default_config(struct cputimer_intr *cti __unused,
344                              const struct cputimer *timer __unused)
345 {
346 }
347
348 void
349 cputimer_intr_default_pmfixup(struct cputimer_intr *cti __unused)
350 {
351 }
352
353 void
354 cputimer_intr_default_initclock(struct cputimer_intr *cti __unused,
355                                 boolean_t selected __unused)
356 {
357 }
358
359 void
360 cputimer_intr_enable(void)
361 {
362     struct cputimer_intr *cti;
363
364     SLIST_FOREACH(cti, &cputimer_intr_head, next)
365         cti->enable(cti);
366 }
367
368 void
369 cputimer_intr_config(const struct cputimer *timer)
370 {
371     struct cputimer_intr *cti;
372
373     SLIST_FOREACH(cti, &cputimer_intr_head, next)
374         cti->config(cti, timer);
375 }
376
377 void
378 cputimer_intr_pmfixup(void)
379 {
380     struct cputimer_intr *cti;
381
382     SLIST_FOREACH(cti, &cputimer_intr_head, next)
383         cti->pmfixup(cti);
384 }
385
386 void
387 cputimer_intr_reload(sysclock_t reload)
388 {
389     struct cputimer_intr *cti = sys_cputimer_intr;
390
391     cti->reload(cti, reload);
392 }
393
394 void
395 cputimer_intr_restart(void)
396 {
397     struct cputimer_intr *cti = sys_cputimer_intr;
398
399     cti->restart(cti);
400 }
401
402 int
403 cputimer_intr_select_caps(uint32_t caps)
404 {
405     struct cputimer_intr *cti, *maybe;
406     int error;
407
408     maybe = NULL;
409     SLIST_FOREACH(cti, &cputimer_intr_head, next) {
410         if ((cti->caps & caps) == caps) {
411             if (maybe == NULL)
412                 maybe = cti;
413             else if (cti->prio > maybe->prio)
414                 maybe = cti;
415         }
416     }
417     if (maybe == NULL)
418         return ENOENT;
419
420     if (sys_cputimer_intr == maybe)
421         return 0;
422
423     cputimer_intr_caps = caps;
424     error = cputimer_intr_select(maybe, CPUTIMER_INTR_PRIO_MAX);
425     KKASSERT(!error);
426
427     return ERESTART;
428 }
429
430 static void
431 cputimer_intr_initclocks(void)
432 {
433     struct cputimer_intr *cti, *ncti;
434
435     /*
436      * An interrupt cputimer may deregister itself,
437      * so use SLIST_FOREACH_MUTABLE here.
438      */
439     SLIST_FOREACH_MUTABLE(cti, &cputimer_intr_head, next, ncti) {
440         boolean_t selected = FALSE;
441
442         if (cti == sys_cputimer_intr)
443             selected = TRUE;
444         cti->initclock(cti, selected);
445     }
446 }
447 /* NOTE: Must be SECOND to allow platform initialization to go first */
448 SYSINIT(cputimer_intr, SI_BOOT2_CLOCKREG, SI_ORDER_SECOND,
449         cputimer_intr_initclocks, NULL);
450
451 static int
452 sysctl_cputimer_intr_reglist(SYSCTL_HANDLER_ARGS)
453 {
454     struct cputimer_intr *scan;
455     int error = 0;
456     int loop = 0;
457
458     /*
459      * Build a list of available interrupt cputimers
460      */
461     SLIST_FOREACH(scan, &cputimer_intr_head, next) {
462         if (error == 0 && loop)
463             error = SYSCTL_OUT(req, " ", 1);
464         if (error == 0)
465             error = SYSCTL_OUT(req, scan->name, strlen(scan->name));
466         ++loop;
467     }
468     return (error);
469 }
470
471 static int
472 sysctl_cputimer_intr_freq(SYSCTL_HANDLER_ARGS)
473 {
474     int error;
475
476     error = SYSCTL_OUT(req, &sys_cputimer_intr->freq,
477                        sizeof(sys_cputimer_intr->freq));
478     return (error);
479 }
480
481 static int
482 sysctl_cputimer_intr_select(SYSCTL_HANDLER_ARGS)
483 {
484     struct cputimer_intr *cti;
485     char name[32];
486     int error;
487
488     ksnprintf(name, sizeof(name), "%s", sys_cputimer_intr->name);
489     error = sysctl_handle_string(oidp, name, sizeof(name), req);
490     if (error != 0 || req->newptr == NULL)
491         return error;
492
493     SLIST_FOREACH(cti, &cputimer_intr_head, next) {
494         if (strcmp(cti->name, name) == 0)
495             break;
496     }
497     if (cti == NULL)
498         return ENOENT;
499     if (cti == sys_cputimer_intr)
500         return 0;
501
502     error = cputimer_intr_select(cti, CPUTIMER_INTR_PRIO_MAX);
503     if (!error)
504         cputimer_intr_restart();
505     return error;
506 }
507
508 SYSCTL_NODE(_kern_cputimer, OID_AUTO, intr, CTLFLAG_RW, NULL,
509             "interrupt cputimer");
510
511 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, reglist, CTLTYPE_STRING|CTLFLAG_RD,
512             NULL, 0, sysctl_cputimer_intr_reglist, "A", "");
513 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, freq, CTLTYPE_INT|CTLFLAG_RD,
514             NULL, 0, sysctl_cputimer_intr_freq, "I", "");
515 SYSCTL_PROC(_kern_cputimer_intr, OID_AUTO, select, CTLTYPE_STRING|CTLFLAG_RW,
516             NULL, 0, sysctl_cputimer_intr_select, "A", "");
517
518 int
519 cputimer_intr_powersave_addreq(void)
520 {
521     int error = 0;
522
523     lwkt_serialize_enter(&cputimer_intr_ps_slize);
524
525     ++cputimer_intr_ps_reqs;
526     if (cputimer_intr_ps_reqs == 1) {
527         /*
528          * Upon the first power saving request, switch to an one shot
529          * timer, which would not stop in the any power saving state.
530          */
531         error = cputimer_intr_select_caps(CPUTIMER_INTR_CAP_PS);
532         if (error == ERESTART) {
533             error = 0;
534             if (bootverbose)
535                 kprintf("cputimer: first power save request, restart\n");
536             cputimer_intr_restart();
537         } else if (error) {
538             kprintf("no suitable intr cputimer found\n");
539             --cputimer_intr_ps_reqs;
540         } else if (bootverbose) {
541             kprintf("cputimer: first power save request\n");
542         }
543     }
544
545     lwkt_serialize_exit(&cputimer_intr_ps_slize);
546
547     return error;
548 }
549
550 void
551 cputimer_intr_powersave_remreq(void)
552 {
553     lwkt_serialize_enter(&cputimer_intr_ps_slize);
554
555     KASSERT(cputimer_intr_ps_reqs > 0,
556         ("invalid # of powersave reqs %d", cputimer_intr_ps_reqs));
557     --cputimer_intr_ps_reqs;
558     if (cputimer_intr_ps_reqs == 0) {
559         int error;
560
561         /* No one needs power saving, use a better one shot timer. */
562         error = cputimer_intr_select_caps(CPUTIMER_INTR_CAP_NONE);
563         KKASSERT(!error || error == ERESTART);
564         if (error == ERESTART) {
565             if (bootverbose)
566                 kprintf("cputimer: no powser save request, restart\n");
567             cputimer_intr_restart();
568         } else if (bootverbose) {
569             kprintf("cputimer: no power save request\n");
570         }
571     }
572
573     lwkt_serialize_exit(&cputimer_intr_ps_slize);
574 }