1 /* $NetBSD: clock.c,v 1.14 2005/12/24 22:45:36 perry 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.14 2005/12/24 22:45:36 perry Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/systm.h> 41 #include <sys/properties.h> 42 43 #include <machine/cpu.h> 44 45 #include <powerpc/spr.h> 46 47 /* 48 * Initially we assume a processor with a bus frequency of 12.5 MHz. 49 */ 50 static u_long ticks_per_sec; 51 static u_long ns_per_tick; 52 static long ticks_per_intr; 53 static volatile u_long lasttb, lasttb2; 54 static u_long ticksmissed; 55 static volatile int tickspending; 56 57 void decr_intr(struct clockframe *); /* called from trap_subr.S */ 58 void stat_intr(struct clockframe *); /* called from trap_subr.S */ 59 60 #ifdef FAST_STAT_CLOCK 61 /* Stat clock runs at ~ 1.5KHz */ 62 #define PERIOD_POWER 17 63 #define TCR_PERIOD TCR_FP_2_17 64 #else 65 /* Stat clock runs at ~ 95Hz */ 66 #define PERIOD_POWER 21 67 #define TCR_PERIOD TCR_FP_2_21 68 #endif 69 70 71 void 72 stat_intr(struct clockframe *frame) 73 { 74 extern u_long intrcnt[]; 75 76 mtspr(SPR_TSR, TSR_FIS); /* Clear TSR[FIS] */ 77 intrcnt[CNT_STATCLOCK]++; 78 statclock(frame); 79 } 80 81 void 82 decr_intr(struct clockframe *frame) 83 { 84 int pri; 85 long tbtick, xticks; 86 int nticks; 87 extern u_long intrcnt[]; 88 /* 89 * Check whether we are initialized. 90 */ 91 if (!ticks_per_intr) 92 return; 93 94 tbtick = mftbl(); 95 mtspr(SPR_TSR, TSR_PIS); /* Clear TSR[PIS] */ 96 97 xticks = tbtick - lasttb2; /* Number of TLB cycles since last exception */ 98 for (nticks = 0; xticks > ticks_per_intr; nticks++) 99 xticks -= ticks_per_intr; 100 lasttb2 = tbtick - xticks; 101 102 intrcnt[CNT_CLOCK]++; 103 pri = splclock(); 104 if (pri & SPL_CLOCK) { 105 tickspending += nticks; 106 ticksmissed+= nticks; 107 } else { 108 nticks += tickspending; 109 tickspending = 0; 110 111 /* 112 * lasttb is used during microtime. Set it to the virtual 113 * start of this tick interval. 114 */ 115 lasttb = lasttb2; 116 117 /* 118 * Reenable interrupts 119 */ 120 __asm volatile ("wrteei 1"); 121 122 /* 123 * Do standard timer interrupt stuff. 124 * Do softclock stuff only on the last iteration. 125 */ 126 frame->pri = pri | SINT_CLOCK; 127 while (--nticks > 0) 128 hardclock(frame); 129 frame->pri = pri; 130 hardclock(frame); 131 } 132 splx(pri); 133 } 134 135 void 136 cpu_initclocks(void) 137 { 138 139 ticks_per_intr = ticks_per_sec / hz; 140 stathz = profhz = ticks_per_sec / (1 << PERIOD_POWER); 141 printf("Setting PIT to %ld/%d = %ld\n", ticks_per_sec, hz, ticks_per_intr); 142 lasttb2 = lasttb = mftbl(); 143 mtspr(SPR_PIT, ticks_per_intr); 144 /* Enable PIT & FIT(2^17c = 0.655ms) interrupts and auto-reload */ 145 mtspr(SPR_TCR, TCR_PIE | TCR_ARE | TCR_FIE | TCR_PERIOD); 146 } 147 148 void 149 calc_delayconst(void) 150 { 151 unsigned int processor_freq; 152 153 if (board_info_get("processor-frequency", 154 &processor_freq, sizeof(processor_freq)) == -1) 155 panic("no processor-frequency"); 156 157 ticks_per_sec = processor_freq; 158 ns_per_tick = 1000000000 / ticks_per_sec; 159 } 160 161 /* 162 * Fill in *tvp with current time with microsecond resolution. 163 */ 164 void 165 microtime(struct timeval *tvp) 166 { 167 u_long tb; 168 u_long ticks; 169 int msr; 170 171 __asm volatile ("mfmsr %0; wrteei 0" : "=r"(msr) :); 172 173 tb = mftbl(); 174 ticks = ((tb - lasttb) * 1000000ULL) / ticks_per_sec; 175 176 *tvp = time; 177 tvp->tv_usec += ticks; 178 while (tvp->tv_usec >= 1000000) { 179 tvp->tv_usec -= 1000000; 180 tvp->tv_sec++; 181 } 182 183 __asm volatile ("mtmsr %0" :: "r"(msr)); 184 } 185 186 /* 187 * Wait for about n microseconds (at least!). 188 */ 189 void 190 delay(unsigned int n) 191 { 192 u_quad_t tb; 193 u_long tbh, tbl, scratch; 194 195 tb = mftb(); 196 /* use 1000ULL to force 64 bit math to avoid 32 bit overflows */ 197 tb += (n * 1000ULL + ns_per_tick - 1) / ns_per_tick; 198 tbh = tb >> 32; 199 tbl = tb; 200 __asm volatile ( 201 #ifdef PPC_IBM403 202 "1: mftbhi %0 \n" 203 #else 204 "1: mftbu %0 \n" 205 #endif 206 " cmplw %0,%1 \n" 207 " blt 1b \n" 208 " bgt 2f \n" 209 #ifdef PPC_IBM403 210 " mftblo %0 \n" 211 #else 212 " mftb %0 \n" 213 #endif 214 " cmplw %0,%2 \n" 215 " blt 1b \n" 216 "2: \n" 217 : "=&r"(scratch) : "r"(tbh), "r"(tbl) : "cr0"); 218 } 219 220 /* 221 * Nothing to do. 222 */ 223 void 224 setstatclockrate(int arg) 225 { 226 227 /* Do nothing */ 228 } 229