asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); if (pending & STATUSF_IP4) pic_dispatch(); else if (pending & STATUSF_IP7) do_IRQ(PNX833X_TIMER_IRQ); else spurious_interrupt(); }
void pic_deliver_irqs(struct pic_softc *pic, int ipl, void *frame) { const uint32_t ipl_mask = __BIT(ipl); struct intrsource *is; volatile uint32_t *ipending = pic->pic_pending_irqs; volatile uint32_t *iblocked = pic->pic_blocked_irqs; size_t irq_base; #if PIC_MAXSOURCES > 32 size_t irq_count; int poi = 0; /* Possibility of interrupting */ #endif uint32_t pending_irqs; uint32_t blocked_irqs; int irq; bool progress = false; KASSERT(pic->pic_pending_ipls & ipl_mask); irq_base = 0; #if PIC_MAXSOURCES > 32 irq_count = 0; #endif for (;;) { pending_irqs = pic_find_pending_irqs_by_ipl(pic, irq_base, *ipending, ipl); KASSERT((pending_irqs & *ipending) == pending_irqs); KASSERT((pending_irqs & ~(*ipending)) == 0); if (pending_irqs == 0) { #if PIC_MAXSOURCES > 32 irq_count += 32; if (__predict_true(irq_count >= pic->pic_maxsources)) { if (!poi) /*Interrupt at this level was handled.*/ break; irq_base = 0; irq_count = 0; poi = 0; ipending = pic->pic_pending_irqs; iblocked = pic->pic_blocked_irqs; } else { irq_base += 32; ipending++; iblocked++; KASSERT(irq_base <= pic->pic_maxsources); } continue; #else break; #endif } progress = true; blocked_irqs = 0; do { irq = ffs(pending_irqs) - 1; KASSERT(irq >= 0); atomic_and_32(ipending, ~__BIT(irq)); is = pic->pic_sources[irq_base + irq]; if (is != NULL) { cpsie(I32_bit); pic_dispatch(is, frame); cpsid(I32_bit); #if PIC_MAXSOURCES > 32 /* * There is a possibility of interrupting * from cpsie() to cpsid(). */ poi = 1; #endif blocked_irqs |= __BIT(irq); } else { KASSERT(0); } pending_irqs = pic_find_pending_irqs_by_ipl(pic, irq_base, *ipending, ipl); } while (pending_irqs); if (blocked_irqs) { atomic_or_32(iblocked, blocked_irqs); atomic_or_32(&pic_blocked_pics, __BIT(pic->pic_id)); } } KASSERT(progress); /* * Since interrupts are disabled, we don't have to be too careful * about these. */ if (atomic_and_32_nv(&pic->pic_pending_ipls, ~ipl_mask) == 0) atomic_and_32(&pic_pending_pics, ~__BIT(pic->pic_id)); }