1 /* $OpenBSD: clock.c,v 1.14 2023/09/17 14:50:51 cheloha Exp $ */
2
3 /*
4 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
5 * Copyright (c) 2003 Dale Rahn <drahn@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/param.h>
21 #include <sys/kernel.h>
22 #include <sys/systm.h>
23 #include <sys/clockintr.h>
24 #include <sys/evcount.h>
25 #include <sys/stdint.h>
26 #include <sys/timetc.h>
27
28 #include <machine/cpufunc.h>
29
30 extern uint64_t tb_freq; /* cpu.c */
31 uint64_t dec_nsec_cycle_ratio;
32 uint64_t dec_nsec_max;
33
34 struct evcount clock_count;
35
36 void dec_rearm(void *, uint64_t);
37 void dec_trigger(void *);
38
39 const struct intrclock dec_intrclock = {
40 .ic_rearm = dec_rearm,
41 .ic_trigger = dec_trigger
42 };
43
44 u_int tb_get_timecount(struct timecounter *);
45
46 static struct timecounter tb_timecounter = {
47 .tc_get_timecount = tb_get_timecount,
48 .tc_counter_mask = 0xffffffff,
49 .tc_frequency = 0,
50 .tc_name = "tb",
51 .tc_quality = 0,
52 .tc_priv = NULL,
53 .tc_user = TC_TB,
54 };
55
56 void
dec_rearm(void * unused,uint64_t nsecs)57 dec_rearm(void *unused, uint64_t nsecs)
58 {
59 uint32_t cycles;
60
61 if (nsecs > dec_nsec_max)
62 nsecs = dec_nsec_max;
63 cycles = (nsecs * dec_nsec_cycle_ratio) >> 32;
64 if (cycles > UINT32_MAX >> 1)
65 cycles = UINT32_MAX >> 1;
66 mtdec(cycles);
67 }
68
69 void
dec_trigger(void * unused)70 dec_trigger(void *unused)
71 {
72 u_long s;
73
74 s = intr_disable();
75 mtdec(0);
76 mtdec(UINT32_MAX);
77 intr_restore(s);
78 }
79
80 u_int
tb_get_timecount(struct timecounter * tc)81 tb_get_timecount(struct timecounter *tc)
82 {
83 return mftb();
84 }
85
86 void
cpu_initclocks(void)87 cpu_initclocks(void)
88 {
89 tb_timecounter.tc_frequency = tb_freq;
90 tc_init(&tb_timecounter);
91
92 dec_nsec_cycle_ratio = tb_freq * (1ULL << 32) / 1000000000;
93 dec_nsec_max = UINT64_MAX / dec_nsec_cycle_ratio;
94
95 stathz = hz;
96 profhz = stathz * 10;
97 statclock_is_randomized = 1;
98
99 evcount_attach(&clock_count, "clock", NULL);
100 }
101
102 void
cpu_startclock(void)103 cpu_startclock(void)
104 {
105 clockintr_cpu_init(&dec_intrclock);
106 clockintr_trigger();
107 intr_enable();
108 }
109
110 void
decr_intr(struct trapframe * frame)111 decr_intr(struct trapframe *frame)
112 {
113 struct cpu_info *ci = curcpu();
114 int s;
115
116 clock_count.ec_count++;
117
118 mtdec(UINT32_MAX >> 1); /* clear DEC exception */
119
120 /*
121 * If the clock interrupt is masked, postpone all work until
122 * it is unmasked in splx(9).
123 */
124 if (ci->ci_cpl >= IPL_CLOCK) {
125 ci->ci_dec_deferred = 1;
126 return;
127 }
128 ci->ci_dec_deferred = 0;
129
130 s = splclock();
131 intr_enable();
132 clockintr_dispatch(frame);
133 intr_disable();
134 splx(s);
135 }
136
137 void
setstatclockrate(int newhz)138 setstatclockrate(int newhz)
139 {
140 }
141
142 void
delay(u_int us)143 delay(u_int us)
144 {
145 uint64_t tb;
146
147 tb = mftb();
148 tb += (us * tb_freq + 999999) / 1000000;
149 while (tb > mftb())
150 continue;
151 }
152