Home | History | Annotate | Line # | Download | only in sparc
      1 /*	$NetBSD: timer_msiiep.c,v 1.29 2025/02/25 15:29:00 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  * MicroSPARC-IIep timer support.
     58  */
     59 
     60 #include <sys/cdefs.h>
     61 __KERNEL_RCSID(0, "$NetBSD: timer_msiiep.c,v 1.29 2025/02/25 15:29:00 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/timetc.h>
     68 #include <sys/bus.h>
     69 #include <sys/intr.h>
     70 
     71 #include <sparc/sparc/msiiepreg.h>
     72 #include <sparc/sparc/msiiepvar.h>
     73 
     74 #include <sparc/sparc/timervar.h>
     75 
     76 
     77 static int	timermatch_msiiep(device_t, cfdata_t, void *);
     78 static void	timerattach_msiiep(device_t, device_t, void *);
     79 
     80 CFATTACH_DECL_NEW(timer_msiiep, 0,
     81     timermatch_msiiep, timerattach_msiiep, NULL, NULL);
     82 
     83 
     84 static void	timer_init_msiiep(void);
     85 static int	clockintr_msiiep(void *);
     86 static int	statintr_msiiep(void *);
     87 static u_int	timer_get_timecount(struct timecounter *);
     88 
     89 void*	sched_cookie;
     90 
     91 static struct intrhand level10 = { .ih_fun = clockintr_msiiep };
     92 static struct intrhand level14 = { .ih_fun = statintr_msiiep  };
     93 
     94 /*
     95  * timecounter local state
     96  */
     97 static struct counter {
     98 	u_int limit;		/* limit we count up to */
     99 	u_int offset;		/* accumulated offset due to wraps */
    100 } cntr;
    101 
    102 /*
    103  * define timecounter
    104  */
    105 static struct timecounter counter_timecounter = {
    106 	.tc_get_timecount	= timer_get_timecount,
    107 	.tc_poll_pps		= NULL,
    108 	.tc_counter_mask	= ~0u,
    109 	.tc_frequency		= 25000000, /* Hz */
    110 	.tc_name		= "timer-counter",
    111 	.tc_quality		= 100,
    112 	.tc_priv		= &cntr,
    113 };
    114 
    115 
    116 /*
    117  * ms-IIep counters tick every 4 CPU clocks @100MHz.
    118  * counter is reset to 1 when new limit is written.
    119  */
    120 #define	tmr_ustolimIIep(n)	((n) * 25 + 1)
    121 
    122 
    123 static int
    124 timermatch_msiiep(device_t parent, cfdata_t cf, void *aux)
    125 {
    126 	struct msiiep_attach_args *msa = aux;
    127 
    128 	return (strcmp(msa->msa_name, "timer") == 0);
    129 }
    130 
    131 
    132 /*
    133  * Attach system and processor counters (kernel hard and stat clocks)
    134  * for ms-IIep.  Counters are part of the PCIC and there's no PROM
    135  * node for them.
    136  */
    137 static void
    138 timerattach_msiiep(device_t parent, device_t self, void *aux)
    139 {
    140 
    141 	/* Put processor counter in "counter" mode */
    142 	mspcic_write_1(pcic_pc_ctl, 0); /* stop user timer (just in case) */
    143 	mspcic_write_1(pcic_pc_cfg, 0); /* timer mode disabled */
    144 
    145 	/*
    146 	 * Calibrate delay() by tweaking the magic constant until
    147 	 * delay(100) actually reads (at least) 100 us on the clock.
    148 	 */
    149 	for (timerblurb = 1; ; ++timerblurb) {
    150 		int t;
    151 
    152 		(void)mspcic_read_4(pcic_pclr); /* clear the limit bit */
    153 		mspcic_write_4(pcic_pclr, 0); /* reset to 1, free run */
    154 		delay(100);
    155 		t = mspcic_read_4(pcic_pccr);
    156 		if (t < 0)	/* limit bit set, cannot happen */
    157 			panic("delay calibration");
    158 
    159 		if (t >= 2501) /* (t - 1) / 25 >= 100 us */
    160 			break;
    161 	}
    162 
    163 	printf(": delay constant %d\n", timerblurb);
    164 
    165 	timer_init = timer_init_msiiep;
    166 
    167 	/*
    168 	 * Set counter interrupt priority assignment:
    169 	 * upper 4 bits are for system counter: level 10
    170 	 * lower 4 bits are for processor counter: level 14
    171 	 *
    172 	 * XXX: ensure that interrupt target mask doesn't mask them?
    173 	 */
    174 	mspcic_write_1(pcic_cipar, 0xae);
    175 
    176 	/* link interrupt handlers */
    177 	intr_establish(10, 0, &level10, NULL, false);
    178 	intr_establish(14, 0, &level14, NULL, false);
    179 
    180 	/* Establish a soft interrupt at a lower level for schedclock */
    181 	sched_cookie = sparc_softintr_establish(IPL_SCHED, schedintr, NULL);
    182 	if (sched_cookie == NULL)
    183 		panic("timerattach: cannot establish schedintr");
    184 }
    185 
    186 
    187 /*
    188  * Set up the real-time and statistics clocks.
    189  * Leave stathz 0 only if no alternative timer is available.
    190  *
    191  * The frequencies of these clocks must be an even number of microseconds.
    192  */
    193 static void
    194 timer_init_msiiep(void)
    195 {
    196 
    197 	mspcic_write_4(pcic_sclr, tmr_ustolimIIep(tick));
    198 	mspcic_write_4(pcic_pclr, tmr_ustolimIIep(statint));
    199 
    200 	cntr.limit = tmr_ustolimIIep(tick);
    201 	tc_init(&counter_timecounter);
    202 }
    203 
    204 
    205 /*
    206  * timer_get_timecount provide current counter value
    207  */
    208 static u_int
    209 timer_get_timecount(struct timecounter *tc)
    210 {
    211 	struct counter *ctr = (struct counter *)tc->tc_priv;
    212 	u_int c, res;
    213 	int s;
    214 
    215 	s = splhigh();
    216 
    217 	/* XXX: consider re-reading until increment is detected */
    218 	c = mspcic_read_4(pcic_sccr);
    219 
    220 	res = c & ~MSIIEP_COUNTER_LIMIT;
    221 	if (res != c)
    222 		res += ctr->limit;
    223 
    224 	res += ctr->offset;
    225 
    226 	splx(s);
    227 
    228 	return res;
    229 }
    230 
    231 
    232 /*
    233  * Level 10 (clock) interrupts from system counter.
    234  */
    235 static int
    236 clockintr_msiiep(void *cap)
    237 {
    238 	(void)mspcic_read_4(pcic_sclr); /* clear the interrupt */
    239 
    240 	/*
    241 	 * XXX this needs to be fixed in a more general way
    242 	 * problem is that the kernel enables interrupts and THEN
    243 	 * sets up clocks. In between there's an opportunity to catch
    244 	 * a timer interrupt - if we call hardclock() at that point we'll
    245 	 * panic
    246 	 * so for now just bail when cold
    247 	 */
    248 	if (__predict_false(cold))
    249 		return 0;
    250 
    251 	if (timecounter->tc_get_timecount == timer_get_timecount)
    252 		cntr.offset += cntr.limit;
    253 
    254 	hardclock((struct clockframe *)cap);
    255 	return 1;
    256 }
    257 
    258 
    259 /*
    260  * Level 14 (stat clock) interrupts from processor counter.
    261  */
    262 static int
    263 statintr_msiiep(void *cap)
    264 {
    265 	struct clockframe *frame = cap;
    266 	u_long newint;
    267 
    268 	(void)mspcic_read_4(pcic_pclr); /* clear the interrupt */
    269 
    270 	statclock(frame);
    271 
    272 	/*
    273 	 * Compute new randomized interval.
    274 	 */
    275 	newint = new_interval();
    276 
    277 	/*
    278 	 * Use the `non-resetting' limit register, so that we don't
    279 	 * lose the counter ticks that happened since this interrupt
    280 	 * has been raised.
    281 	 */
    282 	mspcic_write_4(pcic_pclr_nr, tmr_ustolimIIep(newint));
    283 
    284 	/*
    285 	 * The factor 8 is only valid for stathz==100.
    286 	 * See also clock.c
    287 	 */
    288 	if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0) {
    289 		if (CLKF_LOPRI(frame, IPL_SCHED)) {
    290 			/* No need to schedule a soft interrupt */
    291 			spllowerschedclock();
    292 			schedintr(cap);
    293 		} else {
    294 			/*
    295 			 * We're interrupting a thread that may have the
    296 			 * scheduler lock; run schedintr() later.
    297 			 */
    298 			sparc_softintr_schedule(sched_cookie);
    299 		}
    300 	}
    301 
    302 	return 1;
    303 }
    304