1 /* $OpenBSD: clock.c,v 1.29 2014/03/29 18:09:29 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 1998-2003 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/timetc.h> 33 34 #include <dev/clock_subr.h> 35 36 #include <machine/pdc.h> 37 #include <machine/iomod.h> 38 #include <machine/psl.h> 39 #include <machine/intr.h> 40 #include <machine/reg.h> 41 #include <machine/cpufunc.h> 42 #include <machine/autoconf.h> 43 44 u_long cpu_hzticks; 45 int timeset; 46 47 int cpu_hardclock(void *); 48 u_int itmr_get_timecount(struct timecounter *); 49 50 struct timecounter itmr_timecounter = { 51 itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL 52 }; 53 54 void 55 cpu_initclocks(void) 56 { 57 struct cpu_info *ci = curcpu(); 58 u_long __itmr; 59 60 cpu_hzticks = (PAGE0->mem_10msec * 100) / hz; 61 62 itmr_timecounter.tc_frequency = PAGE0->mem_10msec * 100; 63 tc_init(&itmr_timecounter); 64 65 mfctl(CR_ITMR, __itmr); 66 ci->ci_itmr = __itmr; 67 __itmr += cpu_hzticks; 68 mtctl(__itmr, CR_ITMR); 69 } 70 71 int 72 cpu_hardclock(void *v) 73 { 74 struct cpu_info *ci = curcpu(); 75 u_long __itmr, delta, eta; 76 int wrap; 77 register_t eiem; 78 79 /* 80 * Invoke hardclock as many times as there has been cpu_hzticks 81 * ticks since the last interrupt. 82 */ 83 for (;;) { 84 mfctl(CR_ITMR, __itmr); 85 delta = __itmr - ci->ci_itmr; 86 if (delta >= cpu_hzticks) { 87 hardclock(v); 88 ci->ci_itmr += cpu_hzticks; 89 } else 90 break; 91 } 92 93 /* 94 * Program the next clock interrupt, making sure it will 95 * indeed happen in the future. This is done with interrupts 96 * disabled to avoid a possible race. 97 */ 98 eta = ci->ci_itmr + cpu_hzticks; 99 wrap = eta < ci->ci_itmr; /* watch out for a wraparound */ 100 __asm volatile("mfctl %%cr15, %0": "=r" (eiem)); 101 __asm volatile("mtctl %r0, %cr15"); 102 mtctl(eta, CR_ITMR); 103 mfctl(CR_ITMR, __itmr); 104 /* 105 * If we were close enough to the next tick interrupt 106 * value, by the time we have programmed itmr, it might 107 * have passed the value, which would cause a complete 108 * cycle until the next interrupt occurs. On slow 109 * models, this would be a disaster (a complete cycle 110 * taking over two minutes on a 715/33). 111 * 112 * We expect that it will only be necessary to postpone 113 * the interrupt once. Thus, there are two cases: 114 * - We are expecting a wraparound: eta < cpu_itmr. 115 * itmr is in tracks if either >= cpu_itmr or < eta. 116 * - We are not wrapping: eta > cpu_itmr. 117 * itmr is in tracks if >= cpu_itmr and < eta (we need 118 * to keep the >= cpu_itmr test because itmr might wrap 119 * before eta does). 120 */ 121 if ((wrap && !(eta > __itmr || __itmr >= ci->ci_itmr)) || 122 (!wrap && !(eta > __itmr && __itmr >= ci->ci_itmr))) { 123 eta += cpu_hzticks; 124 mtctl(eta, CR_ITMR); 125 } 126 __asm volatile("mtctl %0, %%cr15":: "r" (eiem)); 127 128 return (1); 129 } 130 131 /* 132 * initialize the system time from the time of day clock 133 */ 134 void 135 inittodr(time_t t) 136 { 137 struct pdc_tod tod PDC_ALIGNMENT; 138 int error, tbad = 0; 139 struct timespec ts; 140 141 if (t < 12*SECYR) { 142 printf ("WARNING: preposterous time in file system"); 143 t = 6*SECYR + 186*SECDAY + SECDAY/2; 144 tbad = 1; 145 } 146 147 if ((error = pdc_call((iodcio_t)pdc, 148 1, PDC_TOD, PDC_TOD_READ, &tod, 0, 0, 0, 0, 0))) 149 printf("clock: failed to fetch (%d)\n", error); 150 151 ts.tv_sec = tod.sec; 152 ts.tv_nsec = tod.usec * 1000; 153 tc_setclock(&ts); 154 timeset = 1; 155 156 if (!tbad) { 157 u_long dt; 158 159 dt = (tod.sec < t)? t - tod.sec : tod.sec - t; 160 161 if (dt < 2 * SECDAY) 162 return; 163 printf("WARNING: clock %s %ld days", 164 tod.sec < t? "lost" : "gained", dt / SECDAY); 165 } 166 167 printf (" -- CHECK AND RESET THE DATE!\n"); 168 } 169 170 /* 171 * reset the time of day clock to the value in time 172 */ 173 void 174 resettodr() 175 { 176 struct timeval tv; 177 int error; 178 179 /* 180 * We might have been called by boot() due to a crash early 181 * on. Don't reset the clock chip in this case. 182 */ 183 if (!timeset) 184 return; 185 186 microtime(&tv); 187 188 if ((error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_WRITE, 189 tv.tv_sec, tv.tv_usec))) 190 printf("clock: failed to save (%d)\n", error); 191 } 192 193 void 194 setstatclockrate(int newhz) 195 { 196 /* nothing we can do */ 197 } 198 199 u_int 200 itmr_get_timecount(struct timecounter *tc) 201 { 202 u_long __itmr; 203 204 mfctl(CR_ITMR, __itmr); 205 return (__itmr); 206 } 207