]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/mp.c
kernel: cleanup makefile for $CONF.$O target
[plan9front.git] / sys / src / 9 / pc / mp.c
index a83cb19133cc703dbb7a4474c1e00d74e8e3134d..382e247f7a1b592c62a82e22a0ea2c712b7643eb 100644 (file)
 #include "ureg.h"
 
 #include "mp.h"
-#include "apbootstrap.h"
+#include "apbootstrap.i"
 
-static PCMP* mppcmp;
-static Bus* mpbus;
-static Bus* mpbuslast;
-static int mpisabus = -1;
-static int mpeisabus = -1;
-extern int i8259elcr;                  /* mask of level-triggered interrupts */
-static Apic mpapic[MaxAPICNO+1];
-static int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
-static int mpapicremap[MaxAPICNO+1];
-static int mpmachno = 1;
-static Lock mpphysidlock;
-static int mpphysid;
+/* filled in by pcmpinit or acpiinit */
+Bus* mpbus;
+Bus* mpbuslast;
+int mpisabus = -1;
+int mpeisabus = -1;
+Apic *mpioapic[MaxAPICNO+1];
+Apic *mpapic[MaxAPICNO+1];
 
-static char* buses[] = {
-       "CBUSI ",
-       "CBUSII",
-       "EISA  ",
-       "FUTURE",
-       "INTERN",
-       "ISA   ",
-       "MBI   ",
-       "MBII  ",
-       "MCA   ",
-       "MPI   ",
-       "MPSA  ",
-       "NUBUS ",
-       "PCI   ",
-       "PCMCIA",
-       "TC    ",
-       "VL    ",
-       "VME   ",
-       "XPRESS",
-       0,
-};
-
-static Apic*
-mkprocessor(PCMPprocessor* p)
-{
-       int apicno;
-       Apic *apic;
-
-       apicno = p->apicno;
-       if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
-               return 0;
-
-       apic = &mpapic[apicno];
-       apic->type = PcmpPROCESSOR;
-       apic->apicno = apicno;
-       apic->flags = p->flags;
-       apic->lintr[0] = ApicIMASK;
-       apic->lintr[1] = ApicIMASK;
-
-       if(p->flags & PcmpBP){
-               machno2apicno[0] = apicno;
-               apic->machno = 0;
-       }
-       else{
-               machno2apicno[mpmachno] = apicno;
-               apic->machno = mpmachno;
-               mpmachno++;
-       }
-
-       return apic;
-}
-
-static Bus*
-mkbus(PCMPbus* p)
-{
-       Bus *bus;
-       int i;
-
-       for(i = 0; buses[i]; i++){
-               if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
-                       break;
-       }
-       if(buses[i] == 0)
-               return 0;
-
-       if((bus = xalloc(sizeof(Bus))) == nil)
-               panic("mkbus: no memory for Bus");
-       if(mpbus)
-               mpbuslast->next = bus;
-       else
-               mpbus = bus;
-       mpbuslast = bus;
-
-       bus->type = i;
-       bus->busno = p->busno;
-       if(bus->type == BusEISA){
-               bus->po = PcmpLOW;
-               bus->el = PcmpLEVEL;
-               if(mpeisabus != -1)
-                       print("mkbus: more than one EISA bus\n");
-               mpeisabus = bus->busno;
-       }
-       else if(bus->type == BusPCI){
-               bus->po = PcmpLOW;
-               bus->el = PcmpLEVEL;
-       }
-       else if(bus->type == BusISA){
-               bus->po = PcmpHIGH;
-               bus->el = PcmpEDGE;
-               if(mpisabus != -1)
-                       print("mkbus: more than one ISA bus\n");
-               mpisabus = bus->busno;
-       }
-       else{
-               bus->po = PcmpHIGH;
-               bus->el = PcmpEDGE;
-       }
-
-       return bus;
-}
-
-static Bus*
-mpgetbus(int busno)
-{
-       Bus *bus;
-
-       for(bus = mpbus; bus; bus = bus->next){
-               if(bus->busno == busno)
-                       return bus;
-       }
-       print("mpgetbus: can't find bus %d\n", busno);
-
-       return 0;
-}
-
-static int
-freeapicid(void)
-{
-       int i;
-       
-       for(i = 0; i < MaxAPICNO+1; i++)
-               if(mpapic[i].flags == 0)
-                       return i;
-       return -1;
-}
-
-static Apic*
-mkioapic(PCMPioapic* p)
-{
-       void *va;
-       int apicno, new;
-       Apic *apic;
-
-       apicno = p->apicno;
-       if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
-               return 0;
-
-       /*
-        * Map the I/O APIC.
-        */
-       if((va = vmap(p->addr, 1024)) == nil)
-               return 0;
-
-       apic = &mpapic[apicno];
-       if(apic->flags != 0) {
-               new = freeapicid();
-               if(new < 0)
-                       print("mkioapic: out of APIC IDs\n");
-               else {
-                       mpapicremap[p->apicno] = new;
-                       print("mkioapic: APIC ID conflict at %d, remapping to %d\n", p->apicno, new);
-                       p->apicno = apicno = new;
-                       apic = &mpapic[apicno];
-               }
-       } else
-               mpapicremap[p->apicno] = p->apicno;
-       apic->type = PcmpIOAPIC;
-       apic->apicno = apicno;
-       apic->addr = va;
-       apic->paddr = p->addr;
-       apic->flags = p->flags;
-
-       return apic;
-}
-
-static Aintr*
-mkiointr(PCMPintr* p)
-{
-       Bus *bus;
-       Aintr *aintr;
-       PCMPintr* pcmpintr;
-
-       /*
-        * According to the MultiProcessor Specification, a destination
-        * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
-        * It's unclear how that can possibly be correct so treat it as
-        * an error for now.
-        */
-       if(p->apicno > MaxAPICNO)
-               return 0;
-       
-       if(mpapicremap[p->apicno] < 0) {
-               print("iointr: non-existing IOAPIC %d\n", p->apicno);
-               return 0;
-       }
-       p->apicno = mpapicremap[p->apicno];
-       if((bus = mpgetbus(p->busno)) == 0)
-               return 0;
-
-       if((aintr = xalloc(sizeof(Aintr))) == nil)
-               panic("iointr: no memory for Aintr");
-       aintr->intr = p;
-
-       if(0)
-               print("iointr: type %d intr type %d flags %#o "
-                       "bus %d irq %d apicno %d intin %d\n",
-                       p->type, p->intr, p->flags,
-                       p->busno, p->irq, p->apicno, p->intin);
-       /*
-        * Hack for Intel SR1520ML motherboard, which BIOS describes
-        * the i82575 dual ethernet controllers incorrectly.
-        */
-       if(memcmp(mppcmp->product, "INTEL   X38MLST     ", 20) == 0){
-               if(p->busno == 1 && p->intin == 16 && p->irq == 1){
-                       if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
-                               panic("iointr: no memory for PCMPintr");
-                       memmove(pcmpintr, p, sizeof(PCMPintr));
-                       print("mkiointr: %20.20s bus %d intin %d irq %d\n",
-                               (char*)mppcmp->product,
-                               pcmpintr->busno, pcmpintr->intin,
-                               pcmpintr->irq);
-                       pcmpintr->intin = 17;
-                       aintr->intr = pcmpintr;
-               }
-       }
-       aintr->apic = &mpapic[p->apicno];
-       aintr->next = bus->aintr;
-       bus->aintr = aintr;
-
-       return aintr;
-}
-
-static int
+int
 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
 {
        int el, po, v;
@@ -259,7 +32,6 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
        el = intr->flags & PcmpELMASK;
 
        switch(intr->intr){
-
        default:                                /* PcmpINT */
                v |= ApicFIXED;                 /* no-op */
                break;
@@ -318,343 +90,87 @@ mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
        return v;
 }
 
-static int
-mklintr(PCMPintr* p)
-{
-       Apic *apic;
-       Bus *bus;
-       int intin, v;
-
-       /*
-        * The offsets of vectors for LINT[01] are known to be
-        * 0 and 1 from the local APIC vector space at VectorLAPIC.
-        */
-       if((bus = mpgetbus(p->busno)) == 0)
-               return 0;
-       intin = p->intin;
-
-       /*
-        * Pentium Pros have problems if LINT[01] are set to ExtINT
-        * so just bag it, SMP mode shouldn't need ExtINT anyway.
-        */
-       if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
-               v = ApicIMASK;
-       else
-               v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
-
-       if(p->apicno == 0xFF){
-               for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
-                       if((apic->flags & PcmpEN)
-                       && apic->type == PcmpPROCESSOR)
-                               apic->lintr[intin] = v;
-               }
-       }
-       else{
-               apic = &mpapic[p->apicno];
-               if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
-                       apic->lintr[intin] = v;
-       }
-
-       return v;
-}
-
-static void
-checkmtrr(void)
+uvlong
+tscticks(uvlong *hz)
 {
-       int i, vcnt;
-       Mach *mach0;
+       if(hz != nil)
+               *hz = m->cpuhz;
 
-       /*
-        * If there are MTRR registers, snarf them for validation.
-        */
-       if(!(m->cpuiddx & 0x1000))
-               return;
-
-       rdmsr(0x0FE, &m->mtrrcap);
-       rdmsr(0x2FF, &m->mtrrdef);
-       if(m->mtrrcap & 0x0100){
-               rdmsr(0x250, &m->mtrrfix[0]);
-               rdmsr(0x258, &m->mtrrfix[1]);
-               rdmsr(0x259, &m->mtrrfix[2]);
-               for(i = 0; i < 8; i++)
-                       rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
-       }
-       vcnt = m->mtrrcap & 0x00FF;
-       if(vcnt > nelem(m->mtrrvar))
-               vcnt = nelem(m->mtrrvar);
-       for(i = 0; i < vcnt; i++)
-               rdmsr(0x200+i, &m->mtrrvar[i]);
-
-       /*
-        * If not the bootstrap processor, compare.
-        */
-       if(m->machno == 0)
-               return;
-
-       mach0 = MACHP(0);
-       if(mach0->mtrrcap != m->mtrrcap)
-               print("mtrrcap%d: %lluX %lluX\n",
-                       m->machno, mach0->mtrrcap, m->mtrrcap);
-       if(mach0->mtrrdef != m->mtrrdef)
-               print("mtrrdef%d: %lluX %lluX\n",
-                       m->machno, mach0->mtrrdef, m->mtrrdef);
-       for(i = 0; i < 11; i++){
-               if(mach0->mtrrfix[i] != m->mtrrfix[i])
-                       print("mtrrfix%d: i%d: %lluX %lluX\n",
-                               m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
-       }
-       for(i = 0; i < vcnt; i++){
-               if(mach0->mtrrvar[i] != m->mtrrvar[i])
-                       print("mtrrvar%d: i%d: %lluX %lluX\n",
-                               m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
-       }
+       cycles(&m->tscticks);   /* Uses the rdtsc instruction */
+       return m->tscticks;
 }
 
-static void
-squidboy(Apic* apic)
-{
-//     iprint("Hello Squidboy\n");
-
-       machinit();
-       mmuinit();
-
-       cpuidentify();
-       cpuidprint();
-       checkmtrr();
-
-       apic->online = 1;
-
-       lapicinit(apic);
-       lapiconline();
-       syncclock();
-       timersinit();
-
-       fpoff();
-
-       lock(&active);
-       active.machs |= 1<<m->machno;
-       unlock(&active);
-
-       while(!active.thunderbirdsarego)
-               microdelay(100);
-
-       schedinit();
-}
-
-static void
-mpstartap(Apic* apic)
+void
+syncclock(void)
 {
-       ulong *apbootp, *pdb, *pte;
-       Mach *mach, *mach0;
-       int i, machno;
-       uchar *p;
-
-       mach0 = MACHP(0);
-
-       /*
-        * Initialise the AP page-tables and Mach structure. The page-tables
-        * are the same as for the bootstrap processor with the exception of
-        * the PTE for the Mach structure.
-        * Xspanalloc will panic if an allocation can't be made.
-        */
-       p = xspanalloc(4*BY2PG, BY2PG, 0);
-       pdb = (ulong*)p;
-       memmove(pdb, mach0->pdb, BY2PG);
-       p += BY2PG;
-
-       if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
-               return;
-       memmove(p, KADDR(PPN(*pte)), BY2PG);
-       *pte = PADDR(p)|PTEWRITE|PTEVALID;
-       if(mach0->havepge)
-               *pte |= PTEGLOBAL;
-       p += BY2PG;
+       uvlong x;
 
-       mach = (Mach*)p;
-       if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
+       if(arch->fastclock != tscticks)
                return;
-       *pte = PADDR(mach)|PTEWRITE|PTEVALID;
-       if(mach0->havepge)
-               *pte |= PTEGLOBAL;
-       p += BY2PG;
-
-       machno = apic->machno;
-       MACHP(machno) = mach;
-       mach->machno = machno;
-       mach->pdb = pdb;
-       mach->gdt = (Segdesc*)p;        /* filled by mmuinit */
 
-       /*
-        * Tell the AP where its kernel vector and pdb are.
-        * The offsets are known in the AP bootstrap code.
-        */
-       apbootp = (ulong*)(APBOOTSTRAP+0x08);
-       *apbootp++ = (ulong)squidboy;
-       *apbootp++ = PADDR(pdb);
-       *apbootp = (ulong)apic;
-
-       /*
-        * Universal Startup Algorithm.
-        */
-       p = KADDR(0x467);
-       *p++ = PADDR(APBOOTSTRAP);
-       *p++ = PADDR(APBOOTSTRAP)>>8;
-       i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
-       /* code assumes i==0 */
-       if(i != 0)
-               print("mp: bad APBOOTSTRAP\n");
-       *p++ = i;
-       *p = i>>8;
-
-       nvramwrite(0x0F, 0x0A);
-       lapicstartap(apic, PADDR(APBOOTSTRAP));
-       for(i = 0; i < 1000; i++){
-               if(apic->online)
-                       break;
-               delay(10);
-       }
-       nvramwrite(0x0F, 0x00);
-}
-
-static void
-dumpmp(uchar *p, uchar *e)
-{
-       int i;
-
-       for(i = 0; p < e; p++) {
-               if((i % 16) == 0) print("*mp%d=", i/16);
-               print("%.2x ", *p);
-               if((++i % 16) == 0) print("\n");
-       }
-       if((i % 16) != 0) print("\n");
-}
-
-static void
-mpoverride(uchar** newp, uchar** e)
-{
-       int size, i, j;
-       char buf[20];
-       uchar* p;
-       char* s;
-       
-       size = atoi(getconf("*mp"));
-       if(size == 0) panic("mpoverride: invalid size in *mp");
-       *newp = p = xalloc(size);
-       if(p == nil) panic("mpoverride: can't allocate memory");
-       *e = p + size;
-       for(i = 0; ; i++){
-               snprint(buf, sizeof buf, "*mp%d", i);
-               s = getconf(buf);
-               if(s == nil) break;
-               while(*s){
-                       j = strtol(s, &s, 16);
-                       if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
-                       if(p >= *e) panic("mpoverride: overflow in %s", buf);
-                       *p++ = j;
-               }
+       if(m->machno == 0){
+               wrmsr(0x10, 0);
+               m->tscticks = 0;
+       } else {
+               x = MACHP(0)->tscticks;
+               while(x == MACHP(0)->tscticks)
+                       ;
+               wrmsr(0x10, MACHP(0)->tscticks);
+               cycles(&m->tscticks);
        }
-       if(p != *e) panic("mpoverride: size doesn't match");
 }
 
 void
 mpinit(void)
 {
        int ncpu, i;
+       Apic *apic;
        char *cp;
-       PCMP *pcmp;
-       uchar *e, *p;
-       Apic *apic, *bpapic;
-       void *va;
 
        i8259init();
        syncclock();
 
-       if(_mp_ == 0)
-               return;
-       pcmp = KADDR(_mp_->physaddr);
-
-       /*
-        * Map the local APIC.
-        */
-       if((va = vmap(pcmp->lapicbase, 1024)) == nil)
-               return;
-       mppcmp = pcmp;
-       print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
-
-       bpapic = nil;
-       
-       for(i = 0; i <= MaxAPICNO; i++)
-               mpapicremap[i] = -1;
-
-       /*
-        * Run through the table saving information needed for starting
-        * application processors and initialising any I/O APICs. The table
-        * is guaranteed to be in order such that only one pass is necessary.
-        */
-       p = ((uchar*)pcmp)+sizeof(PCMP);
-       e = ((uchar*)pcmp)+pcmp->length;
-       if(getconf("*dumpmp") != nil)
-               dumpmp(p, e);
-       if(getconf("*mp") != nil)
-               mpoverride(&p, &e);
-       while(p < e) switch(*p){
-
-       default:
-               print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
-                       *p, e-p);
-               while(p < e){
-                       print("%uX ", *p);
-                       p++;
+       if(getconf("*apicdebug")){
+               Bus *b;
+               Aintr *ai;
+               PCMPintr *pi;
+
+               for(i=0; i<=MaxAPICNO; i++){
+                       if(apic = mpapic[i])
+                               print("LAPIC%d: pa=%lux va=%#p flags=%x\n",
+                                       i, apic->paddr, apic->addr, apic->flags);
+                       if(apic = mpioapic[i])
+                               print("IOAPIC%d: pa=%lux va=%#p flags=%x gsibase=%d mre=%d\n",
+                                       i, apic->paddr, apic->addr, apic->flags, apic->gsibase, apic->mre);
                }
-               break;
-
-       case PcmpPROCESSOR:
-               if(apic = mkprocessor((PCMPprocessor*)p)){
-                       /*
-                        * Must take a note of bootstrap processor APIC
-                        * now as it will be needed in order to start the
-                        * application processors later and there's no
-                        * guarantee that the bootstrap processor appears
-                        * first in the table before the others.
-                        */
-                       apic->addr = va;
-                       apic->paddr = pcmp->lapicbase;
-                       if(apic->flags & PcmpBP)
-                               bpapic = apic;
+               for(b = mpbus; b; b = b->next){
+                       print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
+                       for(ai = b->aintr; ai; ai = ai->next){
+                               if(pi = ai->intr)
+                                       print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
+                                               pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
+                                               pi->apicno, pi->intin, pi->flags);
+                       }
                }
-               p += sizeof(PCMPprocessor);
-               continue;
-
-       case PcmpBUS:
-               mkbus((PCMPbus*)p);
-               p += sizeof(PCMPbus);
-               continue;
-
-       case PcmpIOAPIC:
-               if(apic = mkioapic((PCMPioapic*)p))
-                       ioapicinit(apic, ((PCMPioapic*)p)->apicno);
-               p += sizeof(PCMPioapic);
-               continue;
-
-       case PcmpIOINTR:
-               mkiointr((PCMPintr*)p);
-               p += sizeof(PCMPintr);
-               continue;
+       }
 
-       case PcmpLINTR:
-               mklintr((PCMPintr*)p);
-               p += sizeof(PCMPintr);
-               continue;
+       apic = nil;
+       for(i=0; i<=MaxAPICNO; i++){
+               if(mpapic[i] == nil)
+                       continue;
+               if(mpapic[i]->flags & PcmpBP){
+                       apic = mpapic[i];
+                       break;
+               }
        }
 
-       /*
-        * No bootstrap processor, no need to go further.
-        */
-       if(bpapic == 0)
+       if(apic == nil){
+               panic("mpinit: no bootstrap processor");
                return;
-       bpapic->online = 1;
+       }
+       apic->online = 1;
 
-       lapicinit(bpapic);
+       lapicinit(apic);
 
        /*
         * These interrupts are local to the processor
@@ -666,8 +182,6 @@ mpinit(void)
        intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
        lapiconline();
 
-       checkmtrr();
-
        /*
         * Initialise the application processors.
         */
@@ -681,11 +195,14 @@ mpinit(void)
        else
                ncpu = MAXMACH;
        memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
-       for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
+       for(i=0; i<nelem(mpapic); i++){
+               if((apic = mpapic[i]) == nil)
+                       continue;
+               if(apic->machno >= MAXMACH)
+                       continue;
                if(ncpu <= 1)
                        break;
-               if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN
-               && apic->type == PcmpPROCESSOR){
+               if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN){
                        mpstartap(apic);
                        conf.nmach++;
                        ncpu--;
@@ -699,13 +216,15 @@ mpinit(void)
         *  set conf.copymode here if nmach > 1.
         *  Should look for an ExtINT line and enable it.
         */
-       if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
+       if(m->cpuidfamily == 3 || conf.nmach > 1)
                conf.copymode = 1;
 }
 
 static int
 mpintrcpu(void)
 {
+       static Lock physidlock;
+       static int physid;
        int i;
 
        /*
@@ -725,33 +244,47 @@ mpintrcpu(void)
         * to more than one thread in a core, or to use a "noise" core.
         * But, as usual, Intel make that an onerous task. 
         */
-       lock(&mpphysidlock);
+       lock(&physidlock);
        for(;;){
-               i = mpphysid++;
-               if(mpphysid >= MaxAPICNO+1)
-                       mpphysid = 0;
-               if(mpapic[i].online)
+               i = physid++;
+               if(physid >= nelem(mpapic))
+                       physid = 0;
+               if(mpapic[i] == nil)
+                       continue;
+               if(mpapic[i]->online)
                        break;
        }
-       unlock(&mpphysidlock);
+       unlock(&physidlock);
 
-       return mpapic[i].apicno;
+       return mpapic[i]->apicno;
 }
 
-/* hardcoded VectorAPIC and stuff. bad. */
+/*
+ * With the APIC a unique vector can be assigned to each
+ * request to enable an interrupt. There are two reasons this
+ * is a good idea:
+ * 1) to prevent lost interrupts, no more than 2 interrupts
+ *    should be assigned per block of 16 vectors (there is an
+ *    in-service entry and a holding entry for each priority
+ *    level and there is one priority level per block of 16
+ *    interrupts).
+ * 2) each input pin on the IOAPIC will receive a different
+ *    vector regardless of whether the devices on that pin use
+ *    the same IRQ as devices on another pin.
+ */
 static int
 allocvector(void)
 {
-       static int round = 0, num = 1;
+       static int round = 0, num = 0;
        static Lock l;
        int vno;
        
        lock(&l);
-       if(num >= 24) {
-               if(++round >= 8) round = 0;
-               num = 1;
-       }
-       vno = 64 + num++ * 8 + round;
+       vno = VectorAPIC + num;
+       if(vno < MaxVectorAPIC-7)
+               num += 8;
+       else
+               num = ++round % 8;
        unlock(&l);
        return vno;
 }
@@ -763,40 +296,55 @@ mpintrenablex(Vctl* v, int tbdf)
        Aintr *aintr;
        Apic *apic;
        Pcidev *pcidev;
-       int bno, dno, hi, irq, lo, n, type, vno;
+       int bno, dno, pin, hi, irq, lo, n, type, vno;
 
-       /*
-        * Find the bus.
-        */
        type = BUSTYPE(tbdf);
        bno = BUSBNO(tbdf);
        dno = BUSDNO(tbdf);
-       if(type == BusISA)
+
+       pin = 0;
+       pcidev = nil;
+       if(type == BusPCI){
+               if(pcidev = pcimatchtbdf(tbdf))
+                       pin = pcicfgr8(pcidev, PciINTP);
+       } else if(type == BusISA)
                bno = mpisabus;
+
+Findbus:
        for(bus = mpbus; bus != nil; bus = bus->next){
                if(bus->type != type)
                        continue;
                if(bus->busno == bno)
                        break;
        }
+
        if(bus == nil){
-               print("ioapicirq: can't find bus type %d, number %d\n", type, bno);
+               /*
+                * if the PCI device is behind a PCI-PCI bridge thats not described
+                * by the MP or ACPI tables then walk up the bus translating interrupt
+                * pin to parent bus.
+                */
+               if(pcidev && pcidev->parent && pin > 0){
+                       pin = ((dno+(pin-1))%4)+1;
+                       pcidev = pcidev->parent;
+                       bno = BUSBNO(pcidev->tbdf);
+                       dno = BUSDNO(pcidev->tbdf);
+                       goto Findbus;
+               }
+               print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
                return -1;
        }
 
        /*
         * For PCI devices the interrupt pin (INT[ABCD]) and device
         * number are encoded into the entry irq field, so create something
-        * to match on. The interrupt pin used by the device has to be
-        * obtained from the PCI config space.
+        * to match on.
         */
        if(bus->type == BusPCI){
-               pcidev = pcimatchtbdf(tbdf);
-               if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
-                       irq = (dno<<2)|(n-1);
+               if(pin > 0)
+                       irq = (dno<<2)|(pin-1);
                else
                        irq = -1;
-               //print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq);
        }
        else
                irq = v->irq;
@@ -808,9 +356,8 @@ mpintrenablex(Vctl* v, int tbdf)
        for(aintr = bus->aintr; aintr; aintr = aintr->next){
                if(aintr->intr->irq != irq)
                        continue;
-               if (0) {
+               if(0){
                        PCMPintr* p = aintr->intr;
-
                        print("mpintrenablex: bus %d intin %d irq %d\n",
                                p->busno, p->intin, p->irq);
                }
@@ -828,55 +375,34 @@ mpintrenablex(Vctl* v, int tbdf)
                ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
                if(!(lo & ApicIMASK)){
                        vno = lo & 0xFF;
-//print("%s vector %d (!imask)\n", v->name, vno);
+                       if(0) print("%s vector %d (!imask)\n", v->name, vno);
                        n = mpintrinit(bus, aintr->intr, vno, v->irq);
                        n |= ApicPHYSICAL;              /* no-op */
                        lo &= ~(ApicRemoteIRR|ApicDELIVS);
-                       if(n != lo || !(n & ApicLEVEL)){
-                               print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
+                       if(n != lo){
+                               print("mpintrenable: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
                                        v->irq, tbdf, lo, n);
                                return -1;
                        }
-
                        v->isr = lapicisr;
                        v->eoi = lapiceoi;
-
                        return vno;
                }
 
-               /*
-                * With the APIC a unique vector can be assigned to each
-                * request to enable an interrupt. There are two reasons this
-                * is a good idea:
-                * 1) to prevent lost interrupts, no more than 2 interrupts
-                *    should be assigned per block of 16 vectors (there is an
-                *    in-service entry and a holding entry for each priority
-                *    level and there is one priority level per block of 16
-                *    interrupts).
-                * 2) each input pin on the IOAPIC will receive a different
-                *    vector regardless of whether the devices on that pin use
-                *    the same IRQ as devices on another pin.
-                */
                vno = allocvector();
                hi = mpintrcpu()<<24;
                lo = mpintrinit(bus, aintr->intr, vno, v->irq);
-               //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
-               //      lo, bus->busno, aintr->intr->irq, vno,
-               //      v->irq, i8259elcr);
-               if(lo & ApicIMASK)
-                       return -1;
-
                lo |= ApicPHYSICAL;                     /* no-op */
-
+               if(lo & ApicIMASK){
+                       print("mpintrenable: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
+                               v->irq, tbdf, lo, hi);
+                       return -1;
+               }
                if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
                        ioapicrdtw(apic, aintr->intr->intin, hi, lo);
-               //else
-               //      print("lo not enabled 0x%uX %d\n",
-               //              apic->flags, apic->type);
 
                v->isr = lapicisr;
                v->eoi = lapiceoi;
-
                return vno;
        }
 
@@ -890,31 +416,86 @@ enum {
        MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
 };
 
+enum {
+       HTMSIMapping    = 0xA8,
+       HTMSIFlags      = 0x02,
+       HTMSIFlagsEn    = 0x01,
+};
+
+static int
+htmsicapenable(Pcidev *p)
+{
+       int cap, flags;
+
+       if((cap = pcihtcap(p, HTMSIMapping)) <= 0)
+               return -1;
+       flags = pcicfgr8(p, cap + HTMSIFlags);
+       if((flags & HTMSIFlagsEn) == 0)
+               pcicfgw8(p, cap + HTMSIFlags, flags | HTMSIFlagsEn);
+       return 0;
+}
+
+static int
+htmsienable(Pcidev *pdev)
+{
+       Pcidev *p;
+
+       p = nil;
+       while((p = pcimatch(p, 0x1022, 0)) != nil)
+               if(p->did == 0x1103 || p->did == 0x1203)
+                       break;
+
+       if(p == nil)
+               return 0;       /* not hypertransport platform */
+
+       p = nil;
+       while((p = pcimatch(p, 0x10de, 0)) != nil){
+               switch(p->did){
+               case 0x02f0:    /* NVIDIA NFORCE C51 MEMC0 */
+               case 0x02f1:    /* NVIDIA NFORCE C51 MEMC1 */
+               case 0x02f2:    /* NVIDIA NFORCE C51 MEMC2 */
+               case 0x02f3:    /* NVIDIA NFORCE C51 MEMC3 */
+               case 0x02f4:    /* NVIDIA NFORCE C51 MEMC4 */
+               case 0x02f5:    /* NVIDIA NFORCE C51 MEMC5 */
+               case 0x02f6:    /* NVIDIA NFORCE C51 MEMC6 */
+               case 0x02f7:    /* NVIDIA NFORCE C51 MEMC7 */
+               case 0x0369:    /* NVIDIA NFORCE MCP55 MEMC */
+                       htmsicapenable(p);
+                       break;
+               }
+       }
+
+       if(htmsicapenable(pdev) == 0)
+               return 0;
+
+       for(p = pdev->parent; p != nil; p = p->parent)
+               if(htmsicapenable(p) == 0)
+                       return 0;
+
+       return -1;
+}
+
 static int
 msiintrenable(Vctl *v)
 {
        int tbdf, vno, cap, cpu, ok64;
        Pcidev *pci;
 
-       if(getconf("*msi") == nil)
+       if(getconf("*nomsi") != nil)
                return -1;
        tbdf = v->tbdf;
        if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
                return -1;
        pci = pcimatchtbdf(tbdf);
        if(pci == nil) {
-               print("msiintrenable: could not find Pcidev for tbdf %.8x\n", tbdf);
+               print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
                return -1;
        }
-       cap = 0;
-       for(;;) {
-               cap = pcinextcap(pci, cap);
-               if(cap == 0)
-                       return -1;
-               if(pcicfgr8(pci, cap) == 0x05) /* MSI block */
-                       break;
-       }
-       
+       if(htmsienable(pci) < 0)
+               return -1;
+       cap = pcicap(pci, PciCapMSI);
+       if(cap < 0)
+               return -1;
        vno = allocvector();
        cpu = mpintrcpu();
        ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
@@ -922,7 +503,6 @@ msiintrenable(Vctl *v)
        if(ok64) pcicfgw32(pci, cap + MSIAddr + 4, 0);
        pcicfgw16(pci, cap + (ok64 ? MSIData64 : MSIData32), vno | (1<<14));
        pcicfgw16(pci, cap + MSICtrl, 1);
-       print("msiintrenable: success with tbdf %.8x, vector %d, cpu %d\n", tbdf, vno, cpu);
        v->isr = lapicisr;
        v->eoi = lapiceoi;
        return vno;
@@ -979,33 +559,22 @@ mpintrenable(Vctl* v)
                if(vno != -1)
                        return vno;
        }
-       print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
+       print("mpintrenable: out of choices eisa %d isa %d tbdf %uX irq %d\n",
                mpeisabus, mpisabus, v->tbdf, v->irq);
        return -1;
 }
 
-static Lock mpshutdownlock;
-
 void
 mpshutdown(void)
 {
        /*
-        * To be done...
+        * Park application processors.
         */
-       if(!canlock(&mpshutdownlock)){
-               /*
-                * If this processor received the CTRL-ALT-DEL from
-                * the keyboard, acknowledge it. Send an INIT to self.
-                */
-#ifdef FIXTHIS
-               if(lapicisr(VectorKBD))
-                       lapiceoi(VectorKBD);
-#endif /* FIX THIS */
+       if(m->machno != 0){
+               splhi();
                arch->introff();
-               idle();
+               for(;;) idle();
        }
-
-       print("apshutdown: active = %#8.8ux\n", active.machs);
        delay(1000);
        splhi();
 
@@ -1015,24 +584,4 @@ mpshutdown(void)
        lapicicrw(0, 0x000C0000|ApicINIT);
 
        pcireset();
-       i8042reset();
-
-       /*
-        * Often the BIOS hangs during restart if a conventional 8042
-        * warm-boot sequence is tried. The following is Intel specific and
-        * seems to perform a cold-boot, but at least it comes back.
-        * And sometimes there is no keyboard...
-        *
-        * The reset register (0xcf9) is usually in one of the bridge
-        * chips. The actual location and sequence could be extracted from
-        * ACPI but why bother, this is the end of the line anyway.
-        */
-       print("no kbd; trying bios warm boot...");
-       *(ushort*)KADDR(0x472) = 0x1234;        /* BIOS warm-boot flag */
-       outb(0xCF9, 0x02);
-       outb(0xCF9, 0x06);
-
-       print("can't reset\n");
-       for(;;)
-               idle();
 }