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