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