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