Home | History | Annotate | Line # | Download | only in sparc
      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