xref: /netbsd-src/sys/arch/arm/xscale/becc_icu.c (revision a30f264f2a5f410ffefcc55600a9238b3a0c935c)
1 /*	$NetBSD: becc_icu.c,v 1.6 2005/12/24 20:06:52 perry Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
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 for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Interrupt support for the ADI Engineering Big Endian Companion Chip.
40  */
41 
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: becc_icu.c,v 1.6 2005/12/24 20:06:52 perry Exp $");
44 
45 #ifndef EVBARM_SPL_NOINLINE
46 #define	EVBARM_SPL_NOINLINE
47 #endif
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/malloc.h>
52 
53 #include <uvm/uvm_extern.h>
54 
55 #include <machine/bus.h>
56 #include <machine/intr.h>
57 
58 #include <arm/cpufunc.h>
59 
60 #include <arm/xscale/beccreg.h>
61 #include <arm/xscale/beccvar.h>
62 
63 #include <arm/xscale/i80200reg.h>
64 #include <arm/xscale/i80200var.h>
65 
66 /* Interrupt handler queues. */
67 struct intrq intrq[NIRQ];
68 
69 /* Interrupts to mask at each level. */
70 uint32_t becc_imask[NIPL];
71 
72 /* Current interrupt priority level. */
73 volatile uint32_t current_spl_level;
74 
75 /* Interrupts pending. */
76 volatile uint32_t becc_ipending;
77 volatile uint32_t becc_sipending;
78 
79 /* Software copy of the IRQs we have enabled. */
80 volatile uint32_t intr_enabled;
81 
82 /* Mask if interrupts steered to FIQs. */
83 uint32_t intr_steer;
84 
85 /*
86  * Interrupt bit names.
87  * XXX Some of these are BRH-centric.
88  */
89 const char *becc_irqnames[] = {
90 	"soft",
91 	"timer A",
92 	"timer B",
93 	"irq 3",
94 	"irq 4",
95 	"irq 5",
96 	"irq 6",
97 	"diagerr",
98 	"DMA EOT",
99 	"DMA PERR",
100 	"DMA TABT",
101 	"DMA MABT",
102 	"irq 12",
103 	"irq 13",
104 	"irq 14",
105 	"irq 15",
106 	"PCI PERR",
107 	"irq 17",
108 	"irq 18",
109 	"PCI SERR",
110 	"PCI OAPE",
111 	"PCI OATA",
112 	"PCI OAMA",
113 	"irq 23",
114 	"irq 24",
115 	"irq 25",
116 	"irq 26",	/* PCI INTA */
117 	"irq 27",	/* PCI INTB */
118 	"irq 28",	/* PCI INTC */
119 	"irq 29",	/* PCI INTD */
120 	"pushbutton",
121 	"irq 31",
122 };
123 
124 void	becc_intr_dispatch(struct irqframe *frame);
125 
126 static inline uint32_t
127 becc_icsr_read(void)
128 {
129 	uint32_t icsr;
130 
131 	icsr = BECC_CSR_READ(BECC_ICSR);
132 
133 	/*
134 	 * The ICSR register shows bits that are active even if they are
135 	 * masked in ICMR, so we have to mask them off with the interrupts
136 	 * we consider enabled.
137 	 */
138 	return (icsr & intr_enabled);
139 }
140 
141 static inline void
142 becc_set_intrsteer(void)
143 {
144 
145 	BECC_CSR_WRITE(BECC_ICSTR, intr_steer & ICU_VALID_MASK);
146 	(void) BECC_CSR_READ(BECC_ICSTR);
147 }
148 
149 static inline void
150 becc_enable_irq(int irq)
151 {
152 
153 	intr_enabled |= (1U << irq);
154 	becc_set_intrmask();
155 }
156 
157 static inline void
158 becc_disable_irq(int irq)
159 {
160 
161 	intr_enabled &= ~(1U << irq);
162 	becc_set_intrmask();
163 }
164 
165 /*
166  * NOTE: This routine must be called with interrupts disabled in the CPSR.
167  */
168 static void
169 becc_intr_calculate_masks(void)
170 {
171 	struct intrq *iq;
172 	struct intrhand *ih;
173 	int irq, ipl;
174 
175 	/* First, figure out which IPLs each IRQ has. */
176 	for (irq = 0; irq < NIRQ; irq++) {
177 		int levels = 0;
178 		iq = &intrq[irq];
179 		becc_disable_irq(irq);
180 		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
181 		     ih = TAILQ_NEXT(ih, ih_list))
182 			levels |= (1U << ih->ih_ipl);
183 		iq->iq_levels = levels;
184 	}
185 
186 	/* Next, figure out which IRQs are used by each IPL. */
187 	for (ipl = 0; ipl < NIPL; ipl++) {
188 		int irqs = 0;
189 		for (irq = 0; irq < NIRQ; irq++) {
190 			if (intrq[irq].iq_levels & (1U << ipl))
191 				irqs |= (1U << irq);
192 		}
193 		becc_imask[ipl] = irqs;
194 	}
195 
196 	becc_imask[IPL_NONE] = 0;
197 
198 	/*
199 	 * Initialize the soft interrupt masks to block themselves.
200 	 * Note they all come in at the same physical IRQ.
201 	 */
202 	becc_imask[IPL_SOFT] = (1U << ICU_SOFT);
203 	becc_imask[IPL_SOFTCLOCK] = (1U << ICU_SOFT);
204 	becc_imask[IPL_SOFTNET] = (1U << ICU_SOFT);
205 	becc_imask[IPL_SOFTSERIAL] = (1U << ICU_SOFT);
206 
207 	/*
208 	 * splsoftclock() is the only interface that users of the
209 	 * generic software interrupt facility have to block their
210 	 * soft intrs, so splsoftclock() must also block IPL_SOFT.
211 	 */
212 	becc_imask[IPL_SOFTCLOCK] |= becc_imask[IPL_SOFT];
213 
214 	/*
215 	 * splsoftnet() must also block splsoftclock(), since we don't
216 	 * want timer-driven network events to occur while we're
217 	 * processing incoming packets.
218 	 */
219 	becc_imask[IPL_SOFTNET] |= becc_imask[IPL_SOFTCLOCK];
220 
221 	/*
222 	 * Enforce a heirarchy that gives "slow" device (or devices with
223 	 * limited input buffer space/"real-time" requirements) a better
224 	 * chance at not dropping data.
225 	 */
226 	becc_imask[IPL_BIO] |= becc_imask[IPL_SOFTNET];
227 	becc_imask[IPL_NET] |= becc_imask[IPL_BIO];
228 	becc_imask[IPL_SOFTSERIAL] |= becc_imask[IPL_NET];
229 	becc_imask[IPL_TTY] |= becc_imask[IPL_SOFTSERIAL];
230 
231 	/*
232 	 * splvm() blocks all interrupts that use the kernel memory
233 	 * allocation facilities.
234 	 */
235 	becc_imask[IPL_VM] |= becc_imask[IPL_TTY];
236 
237 	/*
238 	 * Audio devices are not allowed to perform memory allocation
239 	 * in their interrupt routines, and they have fairly "real-time"
240 	 * requirements, so give them a high interrupt priority.
241 	 */
242 	becc_imask[IPL_AUDIO] |= becc_imask[IPL_VM];
243 
244 	/*
245 	 * splclock() must block anything that uses the scheduler.
246 	 */
247 	becc_imask[IPL_CLOCK] |= becc_imask[IPL_AUDIO];
248 
249 	/*
250 	 * No separate statclock on the IQ80310.
251 	 */
252 	becc_imask[IPL_STATCLOCK] |= becc_imask[IPL_CLOCK];
253 
254 	/*
255 	 * splhigh() must block "everything".
256 	 */
257 	becc_imask[IPL_HIGH] |= becc_imask[IPL_STATCLOCK];
258 
259 	/*
260 	 * XXX We need serial drivers to run at the absolute highest priority
261 	 * in order to avoid overruns, so serial > high.
262 	 */
263 	becc_imask[IPL_SERIAL] |= becc_imask[IPL_HIGH];
264 
265 	/*
266 	 * Now compute which IRQs must be blocked when servicing any
267 	 * given IRQ.
268 	 */
269 	for (irq = 0; irq < NIRQ; irq++) {
270 		int irqs = (1U << irq);
271 		iq = &intrq[irq];
272 		if (TAILQ_FIRST(&iq->iq_list) != NULL)
273 			becc_enable_irq(irq);
274 		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
275 		     ih = TAILQ_NEXT(ih, ih_list))
276 			irqs |= becc_imask[ih->ih_ipl];
277 		iq->iq_mask = irqs;
278 	}
279 }
280 
281 void
282 splx(int new)
283 {
284 
285 	becc_splx(new);
286 }
287 
288 int
289 _spllower(int ipl)
290 {
291 
292 	return (becc_spllower(ipl));
293 }
294 
295 int
296 _splraise(int ipl)
297 {
298 
299 	return (becc_splraise(ipl));
300 }
301 
302 void
303 _setsoftintr(int si)
304 {
305 
306 	becc_setsoftintr(si);
307 }
308 
309 static const int si_to_ipl[SI_NQUEUES] = {
310 	IPL_SOFT,		/* SI_SOFT */
311 	IPL_SOFTCLOCK,		/* SI_SOFTCLOCK */
312 	IPL_SOFTNET,		/* SI_SOFTNET */
313 	IPL_SOFTSERIAL,		/* SI_SOFTSERIAL */
314 };
315 
316 int
317 becc_softint(void *arg)
318 {
319 	static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED;
320 	uint32_t	new, oldirqstate;
321 
322 	/* Clear interrupt */
323 	BECC_CSR_WRITE(BECC_ICSR, 0);
324 
325 	if (__cpu_simple_lock_try(&processing) == 0)
326 		return 0;
327 
328 	oldirqstate = disable_interrupts(I32_bit);
329 
330 	new = current_spl_level;
331 
332 #define DO_SOFTINT(si)							\
333 	if (becc_sipending & (1 << (si))) {				\
334 		becc_sipending &= ~(1 << (si));				\
335 		current_spl_level |= becc_imask[si_to_ipl[(si)]];	\
336 		restore_interrupts(oldirqstate);			\
337 		softintr_dispatch(si);					\
338 		oldirqstate = disable_interrupts(I32_bit);		\
339 		current_spl_level = new;				\
340 	}
341 
342 	DO_SOFTINT(SI_SOFTSERIAL);
343 	DO_SOFTINT(SI_SOFTNET);
344 	DO_SOFTINT(SI_SOFTCLOCK);
345 	DO_SOFTINT(SI_SOFT);
346 
347 	__cpu_simple_unlock(&processing);
348 
349 	restore_interrupts(oldirqstate);
350 
351 	return 1;
352 }
353 
354 /*
355  * becc_icu_init:
356  *
357  *	Initialize the BECC ICU.  Called early in bootstrap
358  *	to make sure the ICU is in a pristine state.
359  */
360 void
361 becc_icu_init(void)
362 {
363 
364 	intr_enabled = 0;	/* All interrupts disabled */
365 	becc_set_intrmask();
366 
367 	intr_steer = 0;		/* All interrupts steered to IRQ */
368 	becc_set_intrsteer();
369 
370 	i80200_extirq_dispatch = becc_intr_dispatch;
371 
372 	i80200_intr_enable(INTCTL_IM);
373 }
374 
375 /*
376  * becc_intr_init:
377  *
378  *	Initialize the rest of the interrupt subsystem, making it
379  *	ready to handle interrupts from devices.
380  */
381 void
382 becc_intr_init(void)
383 {
384 	struct intrq *iq;
385 	int i;
386 
387 	intr_enabled = 0;
388 
389 	for (i = 0; i < NIRQ; i++) {
390 		iq = &intrq[i];
391 		TAILQ_INIT(&iq->iq_list);
392 
393 		evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
394 		    NULL, "becc", becc_irqnames[i]);
395 	}
396 
397 	becc_intr_calculate_masks();
398 
399 	/* Enable IRQs (don't yet use FIQs). */
400 	enable_interrupts(I32_bit);
401 }
402 
403 void *
404 becc_intr_establish(int irq, int ipl, int (*func)(void *), void *arg)
405 {
406 	struct intrq *iq;
407 	struct intrhand *ih;
408 	uint32_t oldirqstate;
409 
410 	if (irq < 0 || irq > NIRQ)
411 		panic("becc_intr_establish: IRQ %d out of range", irq);
412 
413 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
414 	if (ih == NULL)
415 		return (NULL);
416 
417 	ih->ih_func = func;
418 	ih->ih_arg = arg;
419 	ih->ih_ipl = ipl;
420 	ih->ih_irq = irq;
421 
422 	iq = &intrq[irq];
423 
424 	/* All BECC interrupts are level-triggered. */
425 	iq->iq_ist = IST_LEVEL;
426 
427 	oldirqstate = disable_interrupts(I32_bit);
428 
429 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
430 
431 	becc_intr_calculate_masks();
432 
433 	restore_interrupts(oldirqstate);
434 
435 	return (ih);
436 }
437 
438 void
439 becc_intr_disestablish(void *cookie)
440 {
441 	struct intrhand *ih = cookie;
442 	struct intrq *iq = &intrq[ih->ih_irq];
443 	uint32_t oldirqstate;
444 
445 	oldirqstate = disable_interrupts(I32_bit);
446 
447 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
448 
449 	becc_intr_calculate_masks();
450 
451 	restore_interrupts(oldirqstate);
452 }
453 
454 void
455 becc_intr_dispatch(struct irqframe *frame)
456 {
457 	struct intrq *iq;
458 	struct intrhand *ih;
459 	uint32_t oldirqstate, pcpl, irq, ibit, hwpend;
460 
461 	pcpl = current_spl_level;
462 
463 	hwpend = becc_icsr_read();
464 
465 	/*
466 	 * Disable all the interrupts that are pending.  We will
467 	 * reenable them once they are processed and not masked.
468 	 */
469 	intr_enabled &= ~hwpend;
470 	becc_set_intrmask();
471 
472 	while (hwpend != 0) {
473 		irq = ffs(hwpend) - 1;
474 		ibit = (1U << irq);
475 
476 		hwpend &= ~ibit;
477 
478 		if (pcpl & ibit) {
479 			/*
480 			 * IRQ is masked; mark it as pending and check
481 			 * the next one.  Note: the IRQ is already disabled.
482 			 */
483 			becc_ipending |= ibit;
484 			continue;
485 		}
486 
487 		becc_ipending &= ~ibit;
488 
489 		iq = &intrq[irq];
490 		iq->iq_ev.ev_count++;
491 		uvmexp.intrs++;
492 		current_spl_level |= iq->iq_mask;
493 		oldirqstate = enable_interrupts(I32_bit);
494 		for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
495 		     ih = TAILQ_NEXT(ih, ih_list)) {
496 			(void) (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
497 		}
498 		restore_interrupts(oldirqstate);
499 
500 		current_spl_level = pcpl;
501 
502 		/* Re-enable this interrupt now that's it's cleared. */
503 		intr_enabled |= ibit;
504 		becc_set_intrmask();
505 	}
506 
507 	if (becc_ipending & ~pcpl) {
508 		intr_enabled |= (becc_ipending & ~pcpl);
509 		becc_set_intrmask();
510 	}
511 }
512