void splx(int savedipl) { struct cpu_info * const ci = curcpu(); KASSERT(savedipl < NIPL); if (__predict_false(savedipl == ci->ci_cpl)) { return; } register_t psw = cpsid(I32_bit); KASSERTMSG(panicstr != NULL || savedipl < ci->ci_cpl, "splx(%d) to a higher ipl than %d", savedipl, ci->ci_cpl); ci->ci_intr_depth++; pic_do_pending_ints(psw, savedipl, NULL); ci->ci_intr_depth--; KASSERTMSG(ci->ci_cpl == savedipl, "cpl %d savedipl %d", ci->ci_cpl, savedipl); if ((psw & I32_bit) == 0) cpsie(I32_bit); cpu_dosoftints(); KASSERTMSG(ci->ci_cpl == savedipl, "cpl %d savedipl %d", ci->ci_cpl, savedipl); }
void pic_set_priority(struct cpu_info *ci, int newipl) { register_t psw = cpsid(I32_bit); if (pic_list[0] != NULL) (pic_list[0]->pic_ops->pic_set_priority)(pic_list[0], newipl); ci->ci_cpl = newipl; if ((psw & I32_bit) == 0) cpsie(I32_bit); }
int _spllower(int newipl) { struct cpu_info * const ci = curcpu(); const int oldipl = ci->ci_cpl; KASSERT(panicstr || newipl <= ci->ci_cpl); if (newipl < ci->ci_cpl) { register_t psw = cpsid(I32_bit); ci->ci_intr_depth++; pic_do_pending_ints(psw, newipl, NULL); ci->ci_intr_depth--; if ((psw & I32_bit) == 0 || newipl == IPL_NONE) cpsie(I32_bit); cpu_dosoftints(); } return oldipl; }
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)); }