1 /* $NetBSD: clock.c,v 1.17 2006/06/30 17:54:51 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.17 2006/06/30 17:54:51 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 statclock(frame); 78 } 79 80 void 81 decr_intr(struct clockframe *frame) 82 { 83 int pri; 84 long tbtick, xticks; 85 int nticks; 86 87 /* 88 * Check whether we are initialized. 89 */ 90 if (!ticks_per_intr) 91 return; 92 93 tbtick = mftbl(); 94 mtspr(SPR_TSR, TSR_PIS); /* Clear TSR[PIS] */ 95 96 xticks = tbtick - lasttb2; /* Number of TLB cycles since last exception */ 97 for (nticks = 0; xticks > ticks_per_intr; nticks++) 98 xticks -= ticks_per_intr; 99 lasttb2 = tbtick - xticks; 100 101 curcpu()->ci_ev_clock.ev_count++; 102 pri = splclock(); 103 if (pri & mask_clock) { 104 tickspending += nticks; 105 ticksmissed += nticks; 106 } else { 107 nticks += tickspending; 108 tickspending = 0; 109 110 /* 111 * lasttb is used during microtime. Set it to the virtual 112 * start of this tick interval. 113 */ 114 lasttb = lasttb2; 115 116 /* 117 * Reenable interrupts 118 */ 119 __asm volatile ("wrteei 1"); 120 121 /* 122 * Do standard timer interrupt stuff. 123 * Do softclock stuff only on the last iteration. 124 */ 125 frame->pri = pri | mask_clock; 126 while (--nticks > 0) 127 hardclock(frame); 128 frame->pri = pri; 129 hardclock(frame); 130 } 131 splx(pri); 132 } 133 134 void 135 cpu_initclocks(void) 136 { 137 /* Initialized in powerpc/ibm4xx/cpu.c */ 138 evcnt_attach_static(&curcpu()->ci_ev_clock); 139 evcnt_attach_static(&curcpu()->ci_ev_statclock); 140 141 ticks_per_intr = ticks_per_sec / hz; 142 stathz = profhz = ticks_per_sec / (1 << PERIOD_POWER); 143 144 printf("Setting PIT to %ld/%d = %ld\n", ticks_per_sec, hz, 145 ticks_per_intr); 146 147 lasttb2 = lasttb = mftbl(); 148 mtspr(SPR_PIT, ticks_per_intr); 149 150 /* Enable PIT & FIT(2^17c = 0.655ms) interrupts and auto-reload */ 151 mtspr(SPR_TCR, TCR_PIE | TCR_ARE | TCR_FIE | TCR_PERIOD); 152 } 153 154 void 155 calc_delayconst(void) 156 { 157 prop_number_t freq; 158 159 freq = prop_dictionary_get(board_properties, "processor-frequency"); 160 KASSERT(freq != NULL); 161 162 ticks_per_sec = (u_long) prop_number_integer_value(freq); 163 ns_per_tick = 1000000000 / ticks_per_sec; 164 } 165 166 /* 167 * Fill in *tvp with current time with microsecond resolution. 168 */ 169 void 170 microtime(struct timeval *tvp) 171 { 172 u_long tb; 173 u_long ticks; 174 int msr; 175 176 __asm volatile ("mfmsr %0; wrteei 0" : "=r"(msr) :); 177 178 tb = mftbl(); 179 ticks = ((tb - lasttb) * 1000000ULL) / ticks_per_sec; 180 181 *tvp = time; 182 tvp->tv_usec += ticks; 183 while (tvp->tv_usec >= 1000000) { 184 tvp->tv_usec -= 1000000; 185 tvp->tv_sec++; 186 } 187 188 __asm volatile ("mtmsr %0" :: "r"(msr)); 189 } 190 191 /* 192 * Wait for about n microseconds (at least!). 193 */ 194 void 195 delay(unsigned int n) 196 { 197 u_quad_t tb; 198 u_long tbh, tbl, scratch; 199 200 tb = mftb(); 201 /* use 1000ULL to force 64 bit math to avoid 32 bit overflows */ 202 tb += (n * 1000ULL + ns_per_tick - 1) / ns_per_tick; 203 tbh = tb >> 32; 204 tbl = tb; 205 __asm volatile ( 206 #ifdef PPC_IBM403 207 "1: mftbhi %0 \n" 208 #else 209 "1: mftbu %0 \n" 210 #endif 211 " cmplw %0,%1 \n" 212 " blt 1b \n" 213 " bgt 2f \n" 214 #ifdef PPC_IBM403 215 " mftblo %0 \n" 216 #else 217 " mftb %0 \n" 218 #endif 219 " cmplw %0,%2 \n" 220 " blt 1b \n" 221 "2: \n" 222 : "=&r"(scratch) : "r"(tbh), "r"(tbl) : "cr0"); 223 } 224 225 /* 226 * Nothing to do. 227 */ 228 void 229 setstatclockrate(int arg) 230 { 231 232 /* Do nothing */ 233 } 234