interrupt vectors for amd64: a new model the nix kernel has been limping along with an 8259-style view of interrupts. that is, there is one global vector set shared by all processors. it also has the old-fashioned restriction that vectors must be be at a rate of no more than 2 per 16. (this is to deal with priorities) this leaves us with just (255-64)/16*2 = 23 possible interrupt sources. in taking a look at msi-x, where it is common and reasonable for a device to take 10 interrupts, and at a minimum 3 or 4, it doesn't look like we can keep to this model without running out as a common case. and i think it makes sense to deal with the fact that vectors are per lapic (core). the restrictions lifted are only the following - vectors are per core (though they are still virtual in the sense that they use the same idt) - vectors are allocated consecutively. but even this modest change as some significant ramifications. zeroth, without a major reorginization to add a layer of indirection, we are now locked into physical mode delivery for interrupts. i don't see any reason to use logical/lopri or cluster-mode interrupts at this point, so this should not be an issue. first, as should be easy to see, traps also are per core. this means, for example, that there is 1 #PF handler for each core, not one per machine. traps also need to be enabled on a per-machine basis. the timer interrupt, since it's not a trap, is a special case. left to do is a change in the model to handle msi-x and a few special cases. for example, since the timer interrupt acts like a trap, but is actually an interrupt, intrneable was hacked to put the timer interrupt on the local mach. currently a bitmap of vectors per processor is tracked. this may be overkill perhaps a single integer will do. finally, there are a few changes piggybacking on this patch - up is no longer set during interrupts. this spills over into a few changes in the hzsched path (again, because the timer is an interrupt not a trap) - lapictimerset gets the lapicid from m->apicno (sic., should be lapicno) rather than the lapic register. this decreases timer interrupt latency by ~100 cycles. --- here's an example of what /dev/irqalloc looks like. i'm open to suggestions on how to organize this. vector.mach seems odd and perhaps difficult to parse. but in some sence they are a unit. as you can see, mach0 takes about double the traps on this idle machine. i believe this is because it's scheduling more processes. interestingly, mach0 has exactly l-64 device interrupts to service. perhaps we should use the hpet for the timer interrupt and the lapic clock for accurate timing. vector.mach irq/trap count total cycles type name ivey# cat /dev/irqalloc 3.0 0 0 0 trap #BP 3.1 0 0 0 trap #BP 3.2 0 0 0 trap #BP 3.3 0 0 0 trap #BP 3.4 0 0 0 trap #BP 3.5 0 0 0 trap #BP 3.6 0 0 0 trap #BP 3.7 0 0 0 trap #BP 7.0 0 0 0 trap #NM 7.1 0 0 0 trap #NM 7.2 0 0 0 trap #NM 7.3 0 0 0 trap #NM 7.4 0 0 0 trap #NM 7.5 0 0 0 trap #NM 7.6 0 0 0 trap #NM 7.7 0 0 0 trap #NM 8.0 0 0 0 trap #DF 8.1 0 0 0 trap #DF 8.2 0 0 0 trap #DF 8.3 0 0 0 trap #DF 8.4 0 0 0 trap #DF 8.5 0 0 0 trap #DF 8.6 0 0 0 trap #DF 8.7 0 0 0 trap #DF 14.0 0 0 0 trap #PF 14.1 0 0 0 trap #PF 14.2 0 0 0 trap #PF 14.3 0 0 0 trap #PF 14.4 0 0 0 trap #PF 14.5 0 0 0 trap #PF 14.6 0 0 0 trap #PF 14.7 0 0 0 trap #PF 15.0 0 0 0 trap #15 15.1 0 0 0 trap #15 15.2 0 0 0 trap #15 15.3 0 0 0 trap #15 15.4 0 0 0 trap #15 15.5 0 0 0 trap #15 15.6 0 0 0 trap #15 15.7 0 0 0 trap #15 16.0 0 0 0 trap #MF 16.1 0 0 0 trap #MF 16.2 0 0 0 trap #MF 16.3 0 0 0 trap #MF 16.4 0 0 0 trap #MF 16.5 0 0 0 trap #MF 16.6 0 0 0 trap #MF 16.7 0 0 0 trap #MF 19.0 0 0 0 trap #XF 19.1 0 0 0 trap #XF 19.2 0 0 0 trap #XF 19.3 0 0 0 trap #XF 19.4 0 0 0 trap #XF 19.5 0 0 0 trap #XF 19.6 0 0 0 trap #XF 19.7 0 0 0 trap #XF 50.0 50 4382619 4544132676 lapic APIC timer 50.1 50 2021595 2126467256 lapic APIC timer 50.2 50 2021621 2205994664 lapic APIC timer 50.3 50 2021574 2246228556 lapic APIC timer 50.4 50 2021617 3154539960 lapic APIC timer 50.5 50 2021611 2146269188 lapic APIC timer 50.6 50 2021619 2104711168 lapic APIC timer 50.7 50 2021550 2170408416 lapic APIC timer 62.0 0 0 0 trap #IPI 62.1 0 0 0 trap #IPI 62.2 0 0 0 trap #IPI 62.3 0 0 0 trap #IPI 62.4 0 0 0 trap #IPI 62.5 0 0 0 trap #IPI 62.6 0 0 0 trap #IPI 62.7 0 0 0 trap #IPI 65.0 1 1 619800 ioapic kbd 65.1 7 0 0 msi ether1 65.2 4 2957 74609756 ioapic COM1 65.4 11 10384 237413432 msi ether0 65.5 5 38 171344 msi ether2 65.7 9 0 0 ioapic acpi 66.0 5 8 114740 msi sdE (ahci) 66.3 11 142859 754519964 ioapic usbehci 66.6 11 142877 764937656 ioapic usbehci Reference: /n/atom/patch/applied2013/k10vpermach Date: Sat Dec 28 21:53:48 CET 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/port/portclock.c Sat Dec 28 21:53:18 2013 +++ /sys/src/nix/port/portclock.c Sat Dec 28 21:53:19 2013 @@ -152,7 +152,7 @@ m->proc->pc = pc; if(m->mmuflush){ - if(up) + if(m->proc != nil) mmuflush(); m->mmuflush = 0; } @@ -166,15 +166,12 @@ if(m->online == 0) return; - if(active.exiting) { - iprint("someone's exiting\n"); + if(active.exiting) exit(0); - } if(m->machno == 0) checkalarms(); - - if(up && up->state == Running) + if(m->proc != nil && m->proc->state == Running) hzsched(); /* in proc.c */ } --- /sys/src/nix/port/proc.c Sat Dec 28 21:53:21 2013 +++ /sys/src/nix/port/proc.c Sat Dec 28 21:53:23 2013 @@ -266,7 +266,7 @@ int anyhigher(void) { - return m->sch->runvec & ~((1<<(up->priority+1))-1); + return m->sch->runvec & ~((1<<(m->proc->priority+1))-1); } /* @@ -281,9 +281,9 @@ /* unless preempted, get to run for at least 100ms */ if(anyhigher() - || (!up->fixedpri && (long)(m->ticks - m->schedticks) > 0 && anyready())){ + || (!m->proc->fixedpri && (long)(m->ticks - m->schedticks) > 0 && anyready())){ m->readied = nil; /* avoid cooperative scheduling */ - up->delaysched++; + m->proc->delaysched++; } } --- /sys/src/nix/k10/fns.h Sat Dec 28 21:53:24 2013 +++ /sys/src/nix/k10/fns.h Sat Dec 28 21:53:25 2013 @@ -14,7 +14,7 @@ void cgapost(int); void checkpa(char*, uintmem); #define clearmmucache() /* x86 doesn't have one */ -#define coherence() mfence() +#define coherence() mfence() void confsetenv(void); void cpuid(u32int, u32int, u32int[4]); int dbgprint(char*, ...); --- /sys/src/nix/k10/main.c Sat Dec 28 21:53:26 2013 +++ /sys/src/nix/k10/main.c Sat Dec 28 21:53:27 2013 @@ -31,6 +31,7 @@ DBG("Hello Squidboy %d %d\n", apicno, m->machno); + trapinit(); vsvminit(MACHSTKSZ); apmmuinit(); if(!lapiconline()) @@ -112,12 +113,6 @@ vlong hz; memset(edata, 0, end - edata); - - /* - * ilock via i8250enable via i8250console - * needs m->machno, sys->machptr[] set, and - * also 'up' set to nil. - */ cgapost(sizeof(uintptr)*8); memset(m, 0, sizeof(Mach)); @@ -186,9 +181,6 @@ i8259init(32); procinit0(); -// if(getconf("*maxmach") != nil) -// maxmach = atoi(getconf("*maxmach")); -// mpsinit(maxmach); lapiconline(); ioapiconline(); sipi(); --- /sys/src/nix/k10/fpu.c Sat Dec 28 21:53:28 2013 +++ /sys/src/nix/k10/fpu.c Sat Dec 28 21:53:29 2013 @@ -511,13 +511,10 @@ m->mxcsr = (Rn|Pm|Um|Dm) & m->mxcsrmask; _stts(); - if(m->machno != 0) - return; - /* * Set up the exception handlers. */ - trapenable(IdtNM, fpunm, 0, "#NM"); - trapenable(IdtMF, fpumf, 0, "#MF"); - trapenable(IdtXF, fpuxf, 0, "#XF"); + trapenable(IdtNM, fpunm, nil, "#NM"); + trapenable(IdtMF, fpumf, nil, "#MF"); + trapenable(IdtXF, fpuxf, nil, "#XF"); } --- /sys/src/nix/k10/lapic.c Sat Dec 28 21:53:31 2013 +++ /sys/src/nix/k10/lapic.c Sat Dec 28 21:53:32 2013 @@ -374,8 +374,7 @@ */ microdelay((TK2MS(1)*1000/lapmachno) * m->machno); lapicrput(Tic, apic->max); - if(apic->machno == 0) - intrenable(IdtTIMER, timerintr, nil, -1, "APIC timer"); + intrenable(IdtTIMER, timerintr, nil, -1, "APIC timer"); lapicrput(Tlvt, Periodic|IrqTIMER); if(m->machno == 0) lapicrput(Tp, 0); @@ -385,18 +384,17 @@ void lapictimerset(uvlong next) { - Mpl pl; Apic *apic; vlong period; - apic = &xlapic[(lapicrget(Id)>>24) & 0xff]; +// apic = &xlapic[(lapicrget(Id)>>24) & 0xff]; + apic = xlapic + m->apicno; - pl = splhi(); - lock(&m->apictimerlock); + ilock(&m->apictimerlock); period = apic->max; if(next != 0){ - period = next - fastticks(nil); /* fastticks is just rdtsc() */ + period = next - fastticks(nil); period /= apic->div; if(period < apic->min) @@ -406,8 +404,7 @@ } lapicrput(Tic, period); - unlock(&m->apictimerlock); - splx(pl); + iunlock(&m->apictimerlock); } void --- /sys/src/nix/k10/ioapic.c Sat Dec 28 21:53:33 2013 +++ /sys/src/nix/k10/ioapic.c Sat Dec 28 21:53:34 2013 @@ -40,13 +40,10 @@ Ioredtbl = 0x10, /* Redirection Table */ }; -static Rdt rdtarray[Nrdt]; -static int nrdtarray; -static Rbus* rdtbus[Nbus]; -static Rdt* rdtvecno[IdtMAX+1]; - -static Lock idtnolock; -static int idtno = IdtIOAPIC; +static Rdt rdtarray[Nrdt]; +static int nrdtarray; +static Rbus* rdtbus[Nbus]; +static Rdt* rdtvecno[IdtMAX+1]; static Apic xioapic[Napic]; static int isabusno = -1; @@ -350,49 +347,84 @@ ioapicdump(); } -static int -ioapicintrdd(u32int* hi, u32int* lo) +/* + * pick a lapic with an active mach by round-robin + */ +static Mach* +selmach(void) { Apic *lapic; Mach *mach; static int i; - /* - * Set delivery mode (lo) and destination field (hi) - * - * Currently, assign each interrupt to a different CPU - * using physical mode delivery. Using the topology - * (packages/cores/threads) could be helpful. - */ for(;; i = (i+1) % Napic){ if((lapic = lapiclookup(i)) == nil) continue; if((mach = sys->machptr[lapic->machno]) == nil) continue; - if(mach->online) - break; + if(mach->online){ + i++; + return mach; + } } - *hi = i++<<24; - *lo |= Pm|MTf; - return mach->machno; } -int -nextvec(void) +static int +selmachvec(Mach *mach) { + uchar *v; uint vecno; + Lapic *lapic; - lock(&idtnolock); - vecno = idtno; - idtno = (idtno+8) % IdtMAX; - if(idtno < IdtIOAPIC) - idtno += IdtIOAPIC; - unlock(&idtnolock); + lapic = lapiclookup(mach->apicno); + v = lapic->vecalloc; + lock(&lapic->vecalloclk); + for(vecno = IdtIOAPIC; vecno <= IdtMAX; vecno += 8) + if(v[vecno/8] != 0xff) + break; + if(vecno > IdtMAX){ + unlock(&lapic->vecalloclk); + return -1; + } + while((v[vecno/8] & 1<vecalloclk); return vecno; } static int +pickmachvec(Vctl *v, Mach **mach) +{ + uint vno, i; + + if(v->affinity != -1){ + *mach = sys->machptr[v->affinity]; + return selmachvec(*mach); + } + for(i = 0; i < sys->nmach; i++) + if((vno = selmachvec(*mach = selmach())) != -1){ + v->affinity = (*mach)->machno; + return vno; + } + return -1; +} + +int +ioapicphysdd(Vctl *v, u32int* hi, u32int* lo) +{ + Mach *mach; + + if((v->vno = pickmachvec(v, &mach)) == -1) + return -1; + /* Set delivery mode (lo) and destination field (hi) */ + *hi = mach->apicno<<24; + *lo |= v->vno|Pm|MTf; + return 0; +} + +static int msimask(Vkey *v, int mask) { Pcidev *p; @@ -406,28 +438,25 @@ static int intrenablemsi(Vctl* v, Pcidev *p) { - uint vno, lo, hi; - uvlong msivec; + u32int lo, hi; + u64int msivec; - vno = nextvec(); - - lo = IPlow | TMedge | vno; - v->affinity = ioapicintrdd(&hi, &lo); + lo = IPlow | TMedge; + ioapicphysdd(v, &hi, &lo); if(lo & Lm) lo |= MTlp; - msivec = (uvlong)hi<<32 | lo; + msivec = (u64int)hi<<32 | lo; if(pcimsienable(p, msivec) == -1) return -1; v->isr = lapicisr; v->eoi = lapiceoi; - v->vno = vno; v->type = "msi"; v->mask = msimask; - DBG("msiirq: %T: enabling %.16llux %s irq %d vno %d\n", p->tbdf, msivec, v->name, v->irq, vno); - return vno; + DBG("msiirq: %T: enabling %.16llux %s irq %d vno %d\n", p->tbdf, msivec, v->name, v->irq, v->vno); + return v->vno; } int @@ -444,7 +473,7 @@ Rbus *rbus; Rdt *rdt; u32int hi, lo; - int bustype, busno, devno, vecno; + int bustype, busno, devno; if(v->tbdf == BUSUNKNOWN){ if(v->irq >= IrqLINT0 && v->irq <= MaxIrqLAPIC){ @@ -476,8 +505,8 @@ busno = BUSBNO(v->tbdf); if((pcidev = pcimatchtbdf(v->tbdf)) == nil) panic("no PCI dev for tbdf %T", v->tbdf); - if((vecno = intrenablemsi(v, pcidev)) != -1) - return vecno; + if(intrenablemsi(v, pcidev) != -1) + return v->vno; disablemsi(v, pcidev); if((devno = pcicfgr8(pcidev, PciINTP)) == 0) panic("no INTP for tbdf %T", v->tbdf); @@ -524,28 +553,27 @@ */ lock(rdt->apic); DBG("%T: %ld/%d/%d (%d)\n", v->tbdf, rdt->apic - xioapic, rbus->devno, rdt->intin, devno); + + rdt->enabled++; + lo = (rdt->lo & ~Im); + ioapicphysdd(v, &hi, &lo); + if((rdt->lo & 0xff) == 0){ - vecno = nextvec(); - rdt->lo |= vecno; - rdtvecno[vecno] = rdt; + rdt->lo |= lo & 0xff; + rdtvecno[lo&0xff] = rdt; }else DBG("%T: mutiple irq bus %d dev %d\n", v->tbdf, busno, devno); - rdt->enabled++; - lo = (rdt->lo & ~Im); - v->affinity = ioapicintrdd(&hi, &lo); rtblput(rdt->apic, rdt->intin, hi, lo); - vecno = lo & 0xff; unlock(rdt->apic); DBG("busno %d devno %d hi %#.8ux lo %#.8ux vecno %d\n", - busno, devno, hi, lo, vecno); + busno, devno, hi, lo, v->vno); v->isr = lapicisr; v->eoi = lapiceoi; - v->vno = vecno; v->type = "ioapic"; - return vecno; + return v->vno; } int --- /sys/src/nix/k10/trap.c Sat Dec 28 21:53:36 2013 +++ /sys/src/nix/k10/trap.c Sat Dec 28 21:53:37 2013 @@ -9,6 +9,7 @@ #include "ureg.h" #include "io.h" +#include "apic.h" #include "amd64.h" extern int notify(Ureg*); @@ -21,20 +22,13 @@ static void dumpstackwithureg(Ureg*); static Lock vctllock; -static Vctl *vctl[256]; - -typedef struct Intrtime Intrtime; -struct Intrtime { - uvlong count; - uvlong cycles; -}; -static Intrtime intrtimes[256]; +static Vctl *vctl[MACHMAX][256]; void* intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) { int vno; - Vctl *v; + Vctl *v, *old; extern int ioapicintrenable(Vctl*); if(f == nil){ @@ -49,6 +43,10 @@ v->tbdf = tbdf; v->f = f; v->a = a; + v->affinity = -1; + if(f == timerintr) + v->affinity = m->machno; /* hack! */ + strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; @@ -61,28 +59,44 @@ free(v); return nil; } - if(vctl[vno]){ - if(vctl[v->vno]->isr != v->isr || vctl[v->vno]->eoi != v->eoi) + if((old = vctl[v->affinity][vno]) != nil){ + if(old->isr != v->isr || old->eoi != v->eoi) panic("intrenable: handler: %s %s %#p %#p %#p %#p", - vctl[v->vno]->name, v->name, - vctl[v->vno]->isr, v->isr, vctl[v->vno]->eoi, v->eoi); + old->name, v->name, old->isr, v->isr, old->eoi, v->eoi); } v->vno = vno; - v->next = vctl[vno]; - vctl[vno] = v; + v->next = vctl[v->affinity][vno]; + vctl[v->affinity][vno] = v; + iunlock(&vctllock); if(v->mask) v->mask(v, 0); - - /* - * Return the assigned vector so intrdisable can find - * the handler; the IRQ is useless in the wonderful world - * of the IOAPIC. - */ return v; } +void +trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) +{ + Vctl *v; + + if(vno < 0 || vno >= 256) + panic("trapenable: vno %d", vno); + v = malloc(sizeof(Vctl)); + v->type = "trap"; + v->tbdf = BUSUNKNOWN; + v->f = f; + v->a = a; + v->affinity = m->machno; + strncpy(v->name, name, KNAMELEN); + v->name[KNAMELEN-1] = 0; + + ilock(&vctllock); + v->next = vctl[m->machno][vno]; + vctl[m->machno][vno] = v; + iunlock(&vctllock); +} + int intrdisable(void* vector) { @@ -91,9 +105,9 @@ ilock(&vctllock); v = vector; - if(v == nil || vctl[v->vno] != v) + if(v == nil || vctl[v->affinity][v->vno] != v) panic("intrdisable: v %#p", v); - for(ll = vctl+v->vno; x = *ll; ll = &x->next) + for(ll = vctl[v->affinity]+v->vno; x = *ll; ll = &x->next) if(v == x) break; if(x != v) @@ -112,10 +126,9 @@ static long irqallocread(Chan*, void *vbuf, long n, vlong offset) { - char *buf, *p, str[3*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1]; - int m, vno; + char *buf, vnam[11+1], *p, str[2*(11+1)+2*(20+1)+(KNAMELEN+1)+(8+1)+1]; + int m, vno, af; long oldn; - Intrtime *t; Vctl *v; if(n < 0 || offset < 0) @@ -123,55 +136,34 @@ oldn = n; buf = vbuf; - for(vno=0; vnonext){ - t = intrtimes + vno; - m = snprint(str, sizeof str, "%11d %11d %11d %20llud %20llud %-*.*s %.*s\n", - vno, v->irq, v->affinity, t->count, t->cycles, 8, 8, v->type, KNAMELEN, v->name); - if(m <= offset) /* if do not want this, skip entry */ - offset -= m; - else{ - /* skip offset bytes */ - m -= offset; - p = str+offset; - offset = 0; - - /* write at most max(n,m) bytes */ - if(m > n) - m = n; - memmove(buf, p, m); - n -= m; - buf += m; + for(vno=0; vno<256; vno++) + for(af = 0; af < sys->nmach; af++) + for(v=vctl[af][vno]; v; v=v->next){ + snprint(vnam, sizeof vnam, "%d.%d", vno, v->affinity); + m = snprint(str, sizeof str, "%11s %11d %20llud %20llud %-*.*s %.*s\n", + vnam, v->irq, v->count, v->cycles, 8, 8, v->type, KNAMELEN, v->name); + if(m <= offset) /* if do not want this, skip entry */ + offset -= m; + else{ + /* skip offset bytes */ + m -= offset; + p = str+offset; + offset = 0; + + /* write at most max(n,m) bytes */ + if(m > n) + m = n; + memmove(buf, p, m); + n -= m; + buf += m; - if(n == 0) - return oldn; - } + if(n == 0) + return oldn; } } return oldn - n; } -void -trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) -{ - Vctl *v; - - if(vno < 0 || vno >= 256) - panic("trapenable: vno %d", vno); - v = malloc(sizeof(Vctl)); - v->type = "trap"; - v->tbdf = BUSUNKNOWN; - v->f = f; - v->a = a; - strncpy(v->name, name, KNAMELEN); - v->name[KNAMELEN-1] = 0; - - ilock(&vctllock); - v->next = vctl[vno]; - vctl[vno] = v; - iunlock(&vctllock); -} - static void nmienable(void) { @@ -194,18 +186,16 @@ /* * Need to set BPT interrupt gate - here or in vsvminit? */ - /* - * Special traps. - * Syscall() is called directly without going through trap(). - */ - trapenable(VectorBPT, debugbpt, 0, "#BP"); - trapenable(VectorPF, faultamd64, 0, "#PF"); - trapenable(Vector2F, doublefault, 0, "#DF"); - trapenable(Vector15, unexpected, 0, "#15"); - trapenable(IdtIPI, expected, 0, "#IPI"); - nmienable(); - - addarchfile("irqalloc", 0444, irqallocread, nil); + trapenable(VectorBPT, debugbpt, nil, "#BP"); + trapenable(VectorPF, faultamd64, nil, "#PF"); + trapenable(Vector2F, doublefault, nil, "#DF"); + trapenable(Vector15, unexpected, nil, "#15"); + trapenable(IdtIPI, expected, nil, "#IPI"); + + if(m->machno == 0){ + nmienable(); + addarchfile("irqalloc", 0444, irqallocread, nil); + } } static char* excname[32] = { @@ -247,7 +237,7 @@ * keep interrupt service times and counts */ void -intrtime(int vno) +intrtime(Vctl *v) { uvlong diff, x; @@ -259,8 +249,8 @@ if(up == nil && m->perf.inidle > diff) m->perf.inidle -= diff; - intrtimes[vno].cycles += diff; - intrtimes[vno].count++; + v->cycles += diff; + v->count++; } /* go to user space */ @@ -299,6 +289,7 @@ { int clockintr, vno, user; char buf[ERRMAX]; + Proc *oup; Vctl *ctl, *v; vno = ureg->type; @@ -312,30 +303,35 @@ clockintr = 0; - if(ctl = vctl[vno]){ + if(ctl = vctl[m->machno][vno]){ if(ctl->isintr){ m->intr++; - if(vno >= VectorPIC && vno != VectorSYSCALL) - m->lastintr = ctl->irq; - }else - if(up) - up->nqtrap++; - - if(ctl->isr) - ctl->isr(vno); - for(v = ctl; v != nil; v = v->next){ - if(v->f) - v->f(ureg, v->a); - } - if(ctl->eoi) - ctl->eoi(vno); - intrtime(vno); - if(ctl->isintr){ + m->lastintr = ctl->irq; + + oup = up; + up = nil; + if(ctl->isr) + ctl->isr(vno); + for(v = ctl; v != nil; v = v->next){ + if(v->f) + v->f(ureg, v->a); + } + if(ctl->eoi) + ctl->eoi(vno); + up = oup; + intrtime(ctl); if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER) clockintr = 1; - + if(up && !clockintr) preempted(); + }else{ + if(up) + up->nqtrap++; + for(v = ctl; v != nil; v = v->next){ + if(v->f) + v->f(ureg, v->a); + } } } else if(vno < nelem(excname) && user){ @@ -344,32 +340,27 @@ postnote(up, 1, buf, NDebug); } else if(vno >= VectorPIC && vno != VectorSYSCALL){ - /* - * An unknown interrupt. - * Check for a default IRQ7. This can happen when - * the IRQ input goes away before the acknowledge. - * In this case, a 'default IRQ7' is generated, but - * the corresponding bit in the ISR isn't set. - * In fact, just ignore all such interrupts. - */ - - /* clear the interrupt */ - i8259isr(vno); - - iprint("cpu%d: spurious interrupt %d, last %d\n", - m->machno, vno, m->lastintr); - intrtime(vno); + static ulong last; + + /* spurious interrupt. */ + lapiceoi(vno); + if(sys->ticks - last > 20*HZ){ + last = sys->ticks; + iprint("cpu%d: spurious interrupt %d, last %d\n", + m->machno, vno, m->lastintr); + } + // intrtime(vno); if(user) kexit(ureg); return; } else{ if(vno == VectorNMI){ - nmienable(); if(m->machno != 0){ - iprint("cpu%d: PC %#p\n", + iprint("cpu%d: nmi pc %#p\n", m->machno, ureg->ip); - for(;;); + for(;;) + hardhalt(); } } dumpregs(ureg);