/* * UART Interrupt Handler */ static void uarttxintr(Ureg*, void* arg) { Uart *p = arg; intrclear(UARTTXbit(p->port), 0); p->inters++; p->winters++; uartxmit(p); }
static void uartrxintr(Ureg*, void* arg) { Uart *p = arg; intrclear(UARTRXbit(p->port), 0); p->inters++; p->rinters++; uartrecv(p); }
static void clockintr(Ureg*, void*) { Clock0link *lp; m->ticks++; checkalarms(); if(canlock(&clock0lock)){ for(lp = clock0link; lp; lp = lp->link) if (lp->clock) lp->clock(); unlock(&clock0lock); } intrclear(TIMERbit(0), 0); }
static void interrupt(Ureg*, void *arg) { ulong irq, irqe, handled; Ether *ether = arg; Ctlr *ctlr = ether->ctlr; Gbereg *reg = ctlr->reg; handled = 0; irq = reg->irq; irqe = reg->irqe; reg->irqe = 0; /* extinguish intr causes */ reg->irq = 0; /* extinguish intr causes */ ethercheck(ether); if(irq & (Irx | Irxbufferq(Qno))) { /* * letting a kproc process the input takes far less real time * than doing it all at interrupt level. */ ctlr->haveinput = 1; wakeup(&ctlr->rrendez); irq &= ~(Irx | Irxbufferq(Qno)); handled++; } else rxkick(ctlr); if(irq & Itxendq(Qno)) { /* transmit ring empty? */ reg->irqmask &= ~Itxendq(Qno); /* prevent more interrupts */ reg->irqemask &= ~(IEtxerrq(Qno) | IEtxunderrun); transmit(ether); irq &= ~Itxendq(Qno); handled++; } if(irqe & IEsum) { /* * IElinkchg appears to only be set when unplugging. * autonegotiation is likely not done yet, so linkup not valid, * thus we note the link change here, and check for * that and autonegotiation done below. */ if(irqe & IEphystschg) { ether->link = (reg->ps0 & PS0linkup) != 0; ether->linkchg = 1; } if(irqe & IEtxerrq(Qno)) ether->oerrs++; if(irqe & IErxoverrun) ether->overflows++; if(irqe & IEtxunderrun) ctlr->txunderrun++; if(irqe & (IEphystschg | IEtxerrq(Qno) | IErxoverrun | IEtxunderrun)) handled++; } if (irq & Isum) { if (irq & Irxerr) { /* nil desc. ptr. or desc. owned by cpu */ ether->buffs++; /* approx. error */ /* if the input ring is full, drain it */ ctlr->haveinput = 1; wakeup(&ctlr->rrendez); } if(irq & (Irxerr | Irxerrq(Qno))) handled++; irq &= ~(Irxerr | Irxerrq(Qno)); } if(ether->linkchg && (reg->ps1 & PS1an_done)) { handled++; ether->link = (reg->ps0 & PS0linkup) != 0; ether->linkchg = 0; } ctlr->newintrs++; if (!handled) { irq &= ~Isum; irqe &= ~IEtxbufferq(Qno); if (irq == 0 && irqe == 0) { /* seems to be triggered by continuous output */ // iprint("ether1116: spurious interrupt\n"); } else iprint("ether1116: interrupt cause unknown; " "irq %#lux irqe %#lux\n", irq, irqe); } intrclear(Irqlo, ether->irq); }