1 /* $NetBSD: clock.c,v 1.18 2006/09/27 09:11:47 freza Exp $ */ 2 /* $OpenBSD: clock.c,v 1.3 1997/10/13 13:42:53 pefo Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.18 2006/09/27 09:11:47 freza Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 42 #include <prop/proplib.h> 43 44 #include <machine/cpu.h> 45 46 #include <powerpc/spr.h> 47 48 /* 49 * Initially we assume a processor with a bus frequency of 12.5 MHz. 50 */ 51 static u_long ticks_per_sec; 52 static u_long ns_per_tick; 53 static long ticks_per_intr; 54 static volatile u_long lasttb, lasttb2; 55 static u_long ticksmissed; 56 static volatile int tickspending; 57 58 void decr_intr(struct clockframe *); /* called from trap_subr.S */ 59 void stat_intr(struct clockframe *); /* called from trap_subr.S */ 60 61 #ifdef FAST_STAT_CLOCK 62 /* Stat clock runs at ~ 1.5 kHz */ 63 #define PERIOD_POWER 17 64 #define TCR_PERIOD TCR_FP_2_17 65 #else 66 /* Stat clock runs at ~ 95Hz */ 67 #define PERIOD_POWER 21 68 #define TCR_PERIOD TCR_FP_2_21 69 #endif 70 71 72 void 73 stat_intr(struct clockframe *frame) 74 { 75 mtspr(SPR_TSR, TSR_FIS); /* Clear TSR[FIS] */ 76 curcpu()->ci_ev_statclock.ev_count++; 77 78 /* Nobody can interrupt us, but see if we're allowed to run. */ 79 if (! (curcpu()->ci_cpl & mask_statclock)) 80 statclock(frame); 81 } 82 83 void 84 decr_intr(struct clockframe *frame) 85 { 86 int pri; 87 long tbtick, xticks; 88 int nticks; 89 90 /* 91 * Check whether we are initialized. 92 */ 93 if (!ticks_per_intr) 94 return; 95 96 tbtick = mftbl(); 97 mtspr(SPR_TSR, TSR_PIS); /* Clear TSR[PIS] */ 98 99 xticks = tbtick - lasttb2; /* Number of TLB cycles since last exception */ 100 for (nticks = 0; xticks > ticks_per_intr; nticks++) 101 xticks -= ticks_per_intr; 102 lasttb2 = tbtick - xticks; 103 104 curcpu()->ci_ev_clock.ev_count++; 105 pri = splclock(); 106 if (pri & mask_clock) { 107 tickspending += nticks; 108 ticksmissed += nticks; 109 } else { 110 nticks += tickspending; 111 tickspending = 0; 112 113 /* 114 * lasttb is used during microtime. Set it to the virtual 115 * start of this tick interval. 116 */ 117 lasttb = lasttb2; 118 119 /* 120 * Reenable interrupts 121 */ 122 __asm volatile ("wrteei 1"); 123 124 /* 125 * Do standard timer interrupt stuff. 126 * Do softclock stuff only on the last iteration. 127 */ 128 frame->pri = pri | mask_clock; 129 while (--nticks > 0) 130 hardclock(frame); 131 frame->pri = pri; 132 hardclock(frame); 133 } 134 splx(pri); 135 } 136 137 void 138 cpu_initclocks(void) 139 { 140 /* Initialized in powerpc/ibm4xx/cpu.c */ 141 evcnt_attach_static(&curcpu()->ci_ev_clock); 142 evcnt_attach_static(&curcpu()->ci_ev_statclock); 143 144 ticks_per_intr = ticks_per_sec / hz; 145 stathz = profhz = ticks_per_sec / (1 << PERIOD_POWER); 146 147 printf("Setting PIT to %ld/%d = %ld\n", ticks_per_sec, hz, 148 ticks_per_intr); 149 150 lasttb2 = lasttb = mftbl(); 151 mtspr(SPR_PIT, ticks_per_intr); 152 153 /* Enable PIT & FIT(2^17c = 0.655ms) interrupts and auto-reload */ 154 mtspr(SPR_TCR, TCR_PIE | TCR_ARE | TCR_FIE | TCR_PERIOD); 155 } 156 157 void 158 calc_delayconst(void) 159 { 160 prop_number_t freq; 161 162 freq = prop_dictionary_get(board_properties, "processor-frequency"); 163 KASSERT(freq != NULL); 164 165 ticks_per_sec = (u_long) prop_number_integer_value(freq); 166 ns_per_tick = 1000000000 / ticks_per_sec; 167 } 168 169 /* 170 * Fill in *tvp with current time with microsecond resolution. 171 */ 172 void 173 microtime(struct timeval *tvp) 174 { 175 u_long tb; 176 u_long ticks; 177 int msr; 178 179 __asm volatile ("mfmsr %0; wrteei 0" : "=r"(msr) :); 180 181 tb = mftbl(); 182 ticks = ((tb - lasttb) * 1000000ULL) / ticks_per_sec; 183 184 *tvp = time; 185 tvp->tv_usec += ticks; 186 while (tvp->tv_usec >= 1000000) { 187 tvp->tv_usec -= 1000000; 188 tvp->tv_sec++; 189 } 190 191 __asm volatile ("mtmsr %0" :: "r"(msr)); 192 } 193 194 /* 195 * Wait for about n microseconds (at least!). 196 */ 197 void 198 delay(unsigned int n) 199 { 200 u_quad_t tb; 201 u_long tbh, tbl, scratch; 202 203 tb = mftb(); 204 /* use 1000ULL to force 64 bit math to avoid 32 bit overflows */ 205 tb += (n * 1000ULL + ns_per_tick - 1) / ns_per_tick; 206 tbh = tb >> 32; 207 tbl = tb; 208 __asm volatile ( 209 #ifdef PPC_IBM403 210 "1: mftbhi %0 \n" 211 #else 212 "1: mftbu %0 \n" 213 #endif 214 " cmplw %0,%1 \n" 215 " blt 1b \n" 216 " bgt 2f \n" 217 #ifdef PPC_IBM403 218 " mftblo %0 \n" 219 #else 220 " mftb %0 \n" 221 #endif 222 " cmplw %0,%2 \n" 223 " blt 1b \n" 224 "2: \n" 225 : "=&r"(scratch) : "r"(tbh), "r"(tbl) : "cr0"); 226 } 227 228 /* 229 * Nothing to do. 230 */ 231 void 232 setstatclockrate(int arg) 233 { 234 235 /* Do nothing */ 236 } 237