xref: /openbsd-src/sys/arch/powerpc64/powerpc64/clock.c (revision 0ed1bf01ac7e45759b65902d0ab711deb359316d)
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