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