1 /* $NetBSD: timer_sun4m.c,v 1.33 2023/06/02 08:51:47 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1994 Gordon W. Ross 7 * Copyright (c) 1993 Adam Glass 8 * Copyright (c) 1996 Paul Kranenburg 9 * Copyright (c) 1996 10 * The President and Fellows of Harvard College. All rights reserved. 11 * 12 * This software was developed by the Computer Systems Engineering group 13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 * contributed to Berkeley. 15 * 16 * All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Harvard University. 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by the University of 34 * California, Berkeley and its contributors. 35 * This product includes software developed by Paul Kranenburg. 36 * This product includes software developed by Harvard University. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)clock.c 8.1 (Berkeley) 6/11/93 54 */ 55 56 /* 57 * Sun4m timer support. 58 */ 59 60 #include <sys/cdefs.h> 61 __KERNEL_RCSID(0, "$NetBSD: timer_sun4m.c,v 1.33 2023/06/02 08:51:47 andvar Exp $"); 62 63 #include <sys/param.h> 64 #include <sys/kernel.h> 65 #include <sys/device.h> 66 #include <sys/systm.h> 67 #include <sys/cpu.h> 68 69 #include <machine/autoconf.h> 70 #include <sys/bus.h> 71 72 #include <sparc/sparc/vaddrs.h> 73 #include <sparc/sparc/cpuvar.h> 74 #include <sparc/sparc/timerreg.h> 75 #include <sparc/sparc/timervar.h> 76 77 static struct timer_4m *timerreg4m; 78 #define counterreg4m cpuinfo.counterreg_4m 79 80 /* 81 * SMP hardclock handler. 82 */ 83 #define IPL_HARDCLOCK 10 84 85 /* 86 * Set up the real-time and statistics clocks. 87 * Leave stathz 0 only if no alternative timer is available. 88 * 89 * The frequencies of these clocks must be an even number of microseconds. 90 */ 91 void 92 timer_init_4m(void) 93 { 94 struct cpu_info *cpi; 95 CPU_INFO_ITERATOR n; 96 97 timerreg4m->t_limit = tmr_ustolim4m(tick); 98 for (CPU_INFO_FOREACH(n, cpi)) { 99 cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint); 100 } 101 icr_si_bic(SINTR_T); 102 } 103 104 #ifdef MULTIPROCESSOR 105 /* 106 * Handle SMP hardclock() calling for this CPU. 107 */ 108 static void 109 hardclock_ipi(void *cap) 110 { 111 int s = splsched(); 112 113 hardclock((struct clockframe *)cap); 114 splx(s); 115 } 116 #endif 117 118 /* 119 * Call hardclock on all CPUs. 120 */ 121 static void 122 handle_hardclock(struct clockframe *cap) 123 { 124 int s; 125 #ifdef MULTIPROCESSOR 126 struct cpu_info *cpi; 127 CPU_INFO_ITERATOR n; 128 129 for (CPU_INFO_FOREACH(n, cpi)) { 130 if (cpi == cpuinfo.ci_self) { 131 KASSERT(CPU_IS_PRIMARY(cpi)); 132 continue; 133 } 134 135 raise_ipi(cpi, IPL_HARDCLOCK); 136 } 137 #endif 138 s = splsched(); 139 hardclock(cap); 140 splx(s); 141 } 142 143 /* 144 * Level 10 (clock) interrupts from system counter. 145 */ 146 int 147 clockintr_4m(void *cap) 148 { 149 150 /* 151 * XXX this needs to be fixed in a more general way 152 * problem is that the kernel enables interrupts and THEN 153 * sets up clocks. In between there's an opportunity to catch 154 * a timer interrupt - if we call hardclock() at that point we'll 155 * panic 156 * so for now just bail when cold 157 * 158 * For MP, we defer calling hardclock() to the schedintr so 159 * that we call it on all cpus. 160 */ 161 if (cold) 162 return 0; 163 164 kpreempt_disable(); 165 166 /* Read the limit register to clear the interrupt. */ 167 *((volatile int *)&timerreg4m->t_limit); 168 169 /* Update the timecounter offset. */ 170 tickle_tc(); 171 172 /* 173 * We don't have a system-clock per-cpu, and we'd like to keep 174 * the per-cpu timer for the statclock, so, send an IPI to 175 * everyone to call hardclock. 176 */ 177 handle_hardclock(cap); 178 179 kpreempt_enable(); 180 return (1); 181 } 182 183 /* 184 * Level 14 (stat clock) interrupts from processor counter. 185 */ 186 int 187 statintr_4m(void *cap) 188 { 189 struct clockframe *frame = cap; 190 u_long newint; 191 192 kpreempt_disable(); 193 194 /* read the limit register to clear the interrupt */ 195 *((volatile int *)&counterreg4m->t_limit); 196 197 statclock(frame); 198 199 /* 200 * Compute new randomized interval. 201 */ 202 newint = new_interval(); 203 204 /* 205 * Use the `non-resetting' limit register, so we don't 206 * lose the counter ticks that happened since this 207 * interrupt was raised. 208 */ 209 counterreg4m->t_limit_nr = tmr_ustolim4m(newint); 210 211 /* 212 * The factor 8 is only valid for stathz==100. 213 * See also clock.c 214 */ 215 if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0) { 216 if (CLKF_LOPRI(frame, IPL_SCHED)) { 217 /* No need to schedule a soft interrupt */ 218 spllowerschedclock(); 219 schedintr(cap); 220 } else { 221 /* 222 * We're interrupting a thread that may have the 223 * scheduler lock; run schedintr() on this CPU later. 224 */ 225 raise_ipi(&cpuinfo, IPL_SCHED); /* sched_cookie->pil */ 226 } 227 } 228 kpreempt_enable(); 229 230 return (1); 231 } 232 233 void 234 timerattach_obio_4m(device_t parent, device_t self, void *aux) 235 { 236 union obio_attach_args *uoba = aux; 237 struct sbus_attach_args *sa = &uoba->uoba_sbus; 238 struct cpu_info *cpi; 239 bus_space_handle_t bh; 240 int i; 241 CPU_INFO_ITERATOR n; 242 243 if (sa->sa_nreg < 2) { 244 printf(": only %d register sets\n", sa->sa_nreg); 245 return; 246 } 247 248 /* Map the system timer */ 249 i = sa->sa_nreg - 1; 250 if (bus_space_map2(sa->sa_bustag, 251 BUS_ADDR(sa->sa_reg[i].oa_space, 252 sa->sa_reg[i].oa_base), 253 sizeof(struct timer_4m), 254 BUS_SPACE_MAP_LINEAR, 255 TIMERREG_VA, &bh) != 0) { 256 printf(": can't map registers\n"); 257 return; 258 } 259 timerreg4m = (struct timer_4m *)TIMERREG_VA; 260 261 /* Map each CPU's counter */ 262 for (i = 0; i < sa->sa_nreg - 1; i++) { 263 /* 264 * Check whether the CPU corresponding to this timer 265 * register is installed. 266 */ 267 for (CPU_INFO_FOREACH(n, cpi)) { 268 if ((i == 0 && sparc_ncpus == 1) || cpi->mid == i + 8) { 269 /* We got a corresponding MID. */ 270 break; 271 } 272 cpi = NULL; 273 } 274 if (cpi == NULL) 275 continue; 276 277 if (sbus_bus_map(sa->sa_bustag, 278 sa->sa_reg[i].oa_space, 279 sa->sa_reg[i].oa_base, 280 sizeof(struct timer_4m), 281 BUS_SPACE_MAP_LINEAR, 282 &bh) != 0) { 283 printf(": can't map CPU counter %d\n", i); 284 return; 285 } 286 cpi->counterreg_4m = (struct counter_4m *)bh; 287 } 288 289 #if defined(MULTIPROCESSOR) 290 if (sparc_ncpus > 1) { 291 /* 292 * Note that we don't actually use this cookie after checking 293 * it was established, we call directly via raise_ipi() on 294 * IPL_HARDCLOCK. 295 */ 296 void *hardclock_cookie; 297 298 hardclock_cookie = sparc_softintr_establish(IPL_HARDCLOCK, 299 hardclock_ipi, NULL); 300 if (hardclock_cookie == NULL) 301 panic("timerattach: cannot establish hardclock_intr"); 302 } 303 #endif 304 305 /* Put processor counter in "timer" mode */ 306 timerreg4m->t_cfg = 0; 307 308 timerattach(&timerreg4m->t_counter, &timerreg4m->t_limit); 309 } 310