xref: /netbsd-src/sys/arch/arc/arc/timer.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /* $NetBSD: timer.c,v 1.11 2012/10/27 17:17:35 chs Exp $ */
2 /* NetBSD: clock.c,v 1.31 2001/05/27 13:53:24 sommerfeld Exp  */
3 
4 /*
5  * Copyright (c) 1988 University of Utah.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * the Systems Programming Group of the University of Utah Computer
11  * Science Department and Ralph Campbell.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  * from: Utah Hdr: clock.c 1.18 91/01/21
38  *
39  *	@(#)clock.c	8.1 (Berkeley) 6/10/93
40  */
41 
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: timer.c,v 1.11 2012/10/27 17:17:35 chs Exp $");
44 
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 
49 #include <mips/locore.h>
50 #include <mips/mips3_clock.h>
51 
52 #include <arc/arc/timervar.h>
53 
54 device_t timerdev;
55 const struct timerfns *timerfns;
56 int timerinitted;
57 uint32_t last_cp0_count;
58 
59 #ifdef ENABLE_INT5_STATCLOCK
60 /*
61  * Statistics clock variance, in usec.  Variance must be a
62  * power of two.  Since this gives us an even number, not an odd number,
63  * we discard one case and compensate.  That is, a variance of 1024 would
64  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
65  * This is symmetric about the point 512, or statvar/2, and thus averages
66  * to that value (assuming uniform random numbers).
67  */
68 static const uint32_t statvar = 1024;
69 static uint32_t statint;	/* number of clock ticks for stathz */
70 static uint32_t statmin;	/* minimum stat clock count in ticks */
71 static uint32_t statprev;/* last value of we set statclock to */
72 static u_int statcountperusec;	/* number of ticks per usec at current stathz */
73 #endif
74 
75 void
76 timerattach(device_t dev, const struct timerfns *fns)
77 {
78 
79 	/*
80 	 * Just bookkeeping.
81 	 */
82 
83 	if (timerfns != NULL)
84 		panic("timerattach: multiple timers");
85 	timerdev = dev;
86 	timerfns = fns;
87 }
88 
89 /*
90  * Machine-dependent clock routines.
91  */
92 
93 /*
94  * Start the real-time and statistics clocks. Leave stathz 0 since there
95  * are no other timers available.
96  */
97 void
98 cpu_initclocks(void)
99 {
100 
101 #ifdef ENABLE_INT5_STATCLOCK
102 	if (stathz == 0)
103 		stathz = hz;
104 
105 	if (profhz == 0)
106 		profhz = hz * 5;
107 
108 	setstatclockrate(stathz);
109 #endif
110 
111 	if (timerfns == NULL)
112 		panic("cpu_initclocks: no timer attached");
113 
114 	/*
115 	 * Get the clock started.
116 	 */
117 	(*timerfns->tf_init)(timerdev);
118 
119 	/* init timecounter */
120 	mips3_init_tc();
121 
122 #ifdef ENABLE_INT5_STATCLOCK
123 	/* enable interrupts including CPU INT 5 */
124 	_splnone();
125 #endif
126 }
127 
128 /*
129  * We assume newhz is either stathz or profhz, and that neither will
130  * change after being set up above.  Could recalculate intervals here
131  * but that would be a drag.
132  */
133 void
134 setstatclockrate(int newhz)
135 {
136 #ifdef ENABLE_INT5_STATCLOCK
137 	uint32_t countpersecond, statvarticks;
138 
139 	statprev = mips3_cp0_count_read();
140 
141 	statint = ((curcpu()->ci_cpu_freq + newhz / 2) / newhz) / 2;
142 
143 	/* Get the total ticks a second */
144 	countpersecond = statint * newhz;
145 
146 	/* now work out how many ticks per usec */
147 	statcountperusec = countpersecond / 1000000;
148 
149 	/* calculate a variance range of statvar */
150 	statvarticks = statcountperusec * statvar;
151 
152 	/* minimum is statint - 50% of variant */
153 	statmin = statint - (statvarticks / 2);
154 
155 	mips3_cp0_compare_write(statprev + statint);
156 #endif
157 }
158 
159 #ifdef ENABLE_INT5_STATCLOCK
160 void
161 statclockintr(struct clockframe *cfp)
162 {
163 	uint32_t curcount, statnext, delta, r;
164 	int lost;
165 
166 	lost = 0;
167 
168 	do {
169 		r = (uint32_t)random() & (statvar - 1);
170 	} while (r == 0);
171 	statnext = statprev + statmin + (r * statcountperusec);
172 
173 	mips3_cp0_compare_write(statnext);
174 	curcount = mips3_cp0_count_read();
175 	delta = statnext - curcount;
176 
177 	while (__predict_false((int32_t)delta < 0)) {
178 		lost++;
179 		delta += statint;
180 	}
181 	if (__predict_false(lost > 0)) {
182 		statnext = curcount + delta;
183 		mips3_cp0_compare_write(statnext);
184 		for (; lost > 0; lost--)
185 			statclock(cfp);
186 	}
187 	statclock(cfp);
188 
189 	statprev = statnext;
190 }
191 #endif
192