17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier #include "ureg.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier #include "mp.h"
107dd7cddfSDavid du Colombier #include "apbootstrap.h"
117dd7cddfSDavid du Colombier
12abfa367dSDavid du Colombier #define dprint(...) if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
13abfa367dSDavid du Colombier
14abfa367dSDavid du Colombier /* from mpacpi.c */
15abfa367dSDavid du Colombier Apic *bootapic;
16abfa367dSDavid du Colombier
17abfa367dSDavid du Colombier int mpdebug;
18abfa367dSDavid du Colombier void (*mpacpifunc)(void);
19abfa367dSDavid du Colombier
206891d857SDavid du Colombier static PCMP* mppcmp;
217dd7cddfSDavid du Colombier static Bus* mpbus;
227dd7cddfSDavid du Colombier static Bus* mpbuslast;
237dd7cddfSDavid du Colombier static int mpisabus = -1;
247dd7cddfSDavid du Colombier static int mpeisabus = -1;
257dd7cddfSDavid du Colombier extern int i8259elcr; /* mask of level-triggered interrupts */
26abfa367dSDavid du Colombier /* static */ Apic mpapic[MaxAPICNO+1];
27abfa367dSDavid du Colombier /* static */ int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */
28998526ebSDavid du Colombier /* static */ Apic ioapic[MaxAPICNO+1];
297dd7cddfSDavid du Colombier static Ref mpvnoref; /* unique vector assignment */
30da51d93aSDavid du Colombier static int mpmachno = 1;
31bd2f1373SDavid du Colombier static Lock mpphysidlock;
32bd2f1373SDavid du Colombier static int mpphysid;
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier static char* buses[] = {
357dd7cddfSDavid du Colombier "CBUSI ",
367dd7cddfSDavid du Colombier "CBUSII",
377dd7cddfSDavid du Colombier "EISA ",
387dd7cddfSDavid du Colombier "FUTURE",
397dd7cddfSDavid du Colombier "INTERN",
407dd7cddfSDavid du Colombier "ISA ",
417dd7cddfSDavid du Colombier "MBI ",
427dd7cddfSDavid du Colombier "MBII ",
437dd7cddfSDavid du Colombier "MCA ",
447dd7cddfSDavid du Colombier "MPI ",
457dd7cddfSDavid du Colombier "MPSA ",
467dd7cddfSDavid du Colombier "NUBUS ",
477dd7cddfSDavid du Colombier "PCI ",
487dd7cddfSDavid du Colombier "PCMCIA",
497dd7cddfSDavid du Colombier "TC ",
507dd7cddfSDavid du Colombier "VL ",
517dd7cddfSDavid du Colombier "VME ",
527dd7cddfSDavid du Colombier "XPRESS",
537dd7cddfSDavid du Colombier 0,
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier static Apic*
mkprocessor(PCMPprocessor * p)577dd7cddfSDavid du Colombier mkprocessor(PCMPprocessor* p)
587dd7cddfSDavid du Colombier {
59bd2f1373SDavid du Colombier int apicno;
607dd7cddfSDavid du Colombier Apic *apic;
617dd7cddfSDavid du Colombier
62bd2f1373SDavid du Colombier apicno = p->apicno;
63bd2f1373SDavid du Colombier if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
647dd7cddfSDavid du Colombier return 0;
657dd7cddfSDavid du Colombier
66bd2f1373SDavid du Colombier apic = &mpapic[apicno];
677dd7cddfSDavid du Colombier apic->type = PcmpPROCESSOR;
68bd2f1373SDavid du Colombier apic->apicno = apicno;
697dd7cddfSDavid du Colombier apic->flags = p->flags;
707dd7cddfSDavid du Colombier apic->lintr[0] = ApicIMASK;
717dd7cddfSDavid du Colombier apic->lintr[1] = ApicIMASK;
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier if(p->flags & PcmpBP){
74bd2f1373SDavid du Colombier machno2apicno[0] = apicno;
757dd7cddfSDavid du Colombier apic->machno = 0;
767dd7cddfSDavid du Colombier }
777dd7cddfSDavid du Colombier else{
78bd2f1373SDavid du Colombier machno2apicno[mpmachno] = apicno;
79da51d93aSDavid du Colombier apic->machno = mpmachno;
80da51d93aSDavid du Colombier mpmachno++;
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier return apic;
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier static Bus*
mkbus(PCMPbus * p)877dd7cddfSDavid du Colombier mkbus(PCMPbus* p)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier Bus *bus;
907dd7cddfSDavid du Colombier int i;
917dd7cddfSDavid du Colombier
927dd7cddfSDavid du Colombier for(i = 0; buses[i]; i++){
937dd7cddfSDavid du Colombier if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
947dd7cddfSDavid du Colombier break;
957dd7cddfSDavid du Colombier }
967dd7cddfSDavid du Colombier if(buses[i] == 0)
977dd7cddfSDavid du Colombier return 0;
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier bus = xalloc(sizeof(Bus));
1007dd7cddfSDavid du Colombier if(mpbus)
1017dd7cddfSDavid du Colombier mpbuslast->next = bus;
1027dd7cddfSDavid du Colombier else
1037dd7cddfSDavid du Colombier mpbus = bus;
1047dd7cddfSDavid du Colombier mpbuslast = bus;
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier bus->type = i;
1077dd7cddfSDavid du Colombier bus->busno = p->busno;
1087dd7cddfSDavid du Colombier if(bus->type == BusEISA){
1097dd7cddfSDavid du Colombier bus->po = PcmpLOW;
1107dd7cddfSDavid du Colombier bus->el = PcmpLEVEL;
1117dd7cddfSDavid du Colombier if(mpeisabus != -1)
1127dd7cddfSDavid du Colombier print("mkbus: more than one EISA bus\n");
1137dd7cddfSDavid du Colombier mpeisabus = bus->busno;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier else if(bus->type == BusPCI){
1167dd7cddfSDavid du Colombier bus->po = PcmpLOW;
1177dd7cddfSDavid du Colombier bus->el = PcmpLEVEL;
1187dd7cddfSDavid du Colombier }
1197dd7cddfSDavid du Colombier else if(bus->type == BusISA){
1207dd7cddfSDavid du Colombier bus->po = PcmpHIGH;
1217dd7cddfSDavid du Colombier bus->el = PcmpEDGE;
1227dd7cddfSDavid du Colombier if(mpisabus != -1)
1237dd7cddfSDavid du Colombier print("mkbus: more than one ISA bus\n");
1247dd7cddfSDavid du Colombier mpisabus = bus->busno;
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier else{
1277dd7cddfSDavid du Colombier bus->po = PcmpHIGH;
1287dd7cddfSDavid du Colombier bus->el = PcmpEDGE;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier return bus;
1327dd7cddfSDavid du Colombier }
1337dd7cddfSDavid du Colombier
1347dd7cddfSDavid du Colombier static Bus*
mpgetbus(int busno)1357dd7cddfSDavid du Colombier mpgetbus(int busno)
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier Bus *bus;
1387dd7cddfSDavid du Colombier
1397dd7cddfSDavid du Colombier for(bus = mpbus; bus; bus = bus->next){
1407dd7cddfSDavid du Colombier if(bus->busno == busno)
1417dd7cddfSDavid du Colombier return bus;
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier print("mpgetbus: can't find bus %d\n", busno);
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier return 0;
1467dd7cddfSDavid du Colombier }
1477dd7cddfSDavid du Colombier
1487dd7cddfSDavid du Colombier static Apic*
mkioapic(PCMPioapic * p)1497dd7cddfSDavid du Colombier mkioapic(PCMPioapic* p)
1507dd7cddfSDavid du Colombier {
1514de34a7eSDavid du Colombier void *va;
152bd2f1373SDavid du Colombier int apicno;
153bd2f1373SDavid du Colombier Apic *apic;
1547dd7cddfSDavid du Colombier
155bd2f1373SDavid du Colombier apicno = p->apicno;
156bd2f1373SDavid du Colombier if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
1577dd7cddfSDavid du Colombier return 0;
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier /*
1607dd7cddfSDavid du Colombier * Map the I/O APIC.
1617dd7cddfSDavid du Colombier */
162ea15f0ccSDavid du Colombier if((va = vmap(p->addr, 1024)) == nil)
1637dd7cddfSDavid du Colombier return 0;
1647dd7cddfSDavid du Colombier
165998526ebSDavid du Colombier apic = &ioapic[apicno];
1667dd7cddfSDavid du Colombier apic->type = PcmpIOAPIC;
167bd2f1373SDavid du Colombier apic->apicno = apicno;
1684de34a7eSDavid du Colombier apic->addr = va;
169ea15f0ccSDavid du Colombier apic->paddr = p->addr;
1707dd7cddfSDavid du Colombier apic->flags = p->flags;
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier return apic;
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier static Aintr*
mkiointr(PCMPintr * p)1767dd7cddfSDavid du Colombier mkiointr(PCMPintr* p)
1777dd7cddfSDavid du Colombier {
1787dd7cddfSDavid du Colombier Bus *bus;
1797dd7cddfSDavid du Colombier Aintr *aintr;
1806891d857SDavid du Colombier PCMPintr* pcmpintr;
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier /*
1837dd7cddfSDavid du Colombier * According to the MultiProcessor Specification, a destination
1847dd7cddfSDavid du Colombier * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
1857dd7cddfSDavid du Colombier * It's unclear how that can possibly be correct so treat it as
1867dd7cddfSDavid du Colombier * an error for now.
1877dd7cddfSDavid du Colombier */
1887dd7cddfSDavid du Colombier if(p->apicno == 0xFF)
1897dd7cddfSDavid du Colombier return 0;
1907dd7cddfSDavid du Colombier if((bus = mpgetbus(p->busno)) == 0)
1917dd7cddfSDavid du Colombier return 0;
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier aintr = xalloc(sizeof(Aintr));
1947dd7cddfSDavid du Colombier aintr->intr = p;
1956891d857SDavid du Colombier
1966891d857SDavid du Colombier if(0)
197abfa367dSDavid du Colombier dprint("mkiointr: type %d intr type %d flags %#o "
1986891d857SDavid du Colombier "bus %d irq %d apicno %d intin %d\n",
1996891d857SDavid du Colombier p->type, p->intr, p->flags,
2006891d857SDavid du Colombier p->busno, p->irq, p->apicno, p->intin);
2016891d857SDavid du Colombier /*
2026891d857SDavid du Colombier * Hack for Intel SR1520ML motherboard, which BIOS describes
2036891d857SDavid du Colombier * the i82575 dual ethernet controllers incorrectly.
2046891d857SDavid du Colombier */
205abfa367dSDavid du Colombier if(mppcmp && memcmp(mppcmp->product, "INTEL X38MLST ", 20) == 0){
2066891d857SDavid du Colombier if(p->busno == 1 && p->intin == 16 && p->irq == 1){
2076891d857SDavid du Colombier pcmpintr = malloc(sizeof(PCMPintr));
208aa72973aSDavid du Colombier if(pcmpintr == nil)
209aa72973aSDavid du Colombier panic("mkiointr: no memory");
2106891d857SDavid du Colombier memmove(pcmpintr, p, sizeof(PCMPintr));
2116891d857SDavid du Colombier print("mkiointr: %20.20s bus %d intin %d irq %d\n",
2126891d857SDavid du Colombier (char*)mppcmp->product,
2136891d857SDavid du Colombier pcmpintr->busno, pcmpintr->intin,
2146891d857SDavid du Colombier pcmpintr->irq);
2156891d857SDavid du Colombier pcmpintr->intin = 17;
2166891d857SDavid du Colombier aintr->intr = pcmpintr;
2176891d857SDavid du Colombier }
2186891d857SDavid du Colombier }
219abfa367dSDavid du Colombier if ((unsigned)p->apicno >= nelem(mpapic))
220abfa367dSDavid du Colombier panic("mkiointr: apic %d out of range", p->apicno);
221998526ebSDavid du Colombier aintr->apic = &ioapic[p->apicno];
2227dd7cddfSDavid du Colombier aintr->next = bus->aintr;
2237dd7cddfSDavid du Colombier bus->aintr = aintr;
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier return aintr;
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier static int
mpintrinit(Bus * bus,PCMPintr * intr,int vno,int)2297dd7cddfSDavid du Colombier mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
2307dd7cddfSDavid du Colombier {
2317dd7cddfSDavid du Colombier int el, po, v;
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier /*
2347dd7cddfSDavid du Colombier * Parse an I/O or Local APIC interrupt table entry and
2357dd7cddfSDavid du Colombier * return the encoded vector.
2367dd7cddfSDavid du Colombier */
2377dd7cddfSDavid du Colombier v = vno;
2387dd7cddfSDavid du Colombier
2397dd7cddfSDavid du Colombier po = intr->flags & PcmpPOMASK;
2407dd7cddfSDavid du Colombier el = intr->flags & PcmpELMASK;
2417dd7cddfSDavid du Colombier
2427dd7cddfSDavid du Colombier switch(intr->intr){
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier default: /* PcmpINT */
245bd2f1373SDavid du Colombier v |= ApicFIXED; /* no-op */
2467dd7cddfSDavid du Colombier break;
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier case PcmpNMI:
2497dd7cddfSDavid du Colombier v |= ApicNMI;
2507dd7cddfSDavid du Colombier po = PcmpHIGH;
2517dd7cddfSDavid du Colombier el = PcmpEDGE;
2527dd7cddfSDavid du Colombier break;
2537dd7cddfSDavid du Colombier
2547dd7cddfSDavid du Colombier case PcmpSMI:
2557dd7cddfSDavid du Colombier v |= ApicSMI;
2567dd7cddfSDavid du Colombier break;
2577dd7cddfSDavid du Colombier
2587dd7cddfSDavid du Colombier case PcmpExtINT:
2597dd7cddfSDavid du Colombier v |= ApicExtINT;
2607dd7cddfSDavid du Colombier /*
2617dd7cddfSDavid du Colombier * The AMI Goliath doesn't boot successfully with it's LINTR0
2627dd7cddfSDavid du Colombier * entry which decodes to low+level. The PPro manual says ExtINT
2637dd7cddfSDavid du Colombier * should be level, whereas the Pentium is edge. Setting the
2647dd7cddfSDavid du Colombier * Goliath to edge+high seems to cure the problem. Other PPro
2657dd7cddfSDavid du Colombier * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
2667dd7cddfSDavid du Colombier * to edge+high, so who knows.
2677dd7cddfSDavid du Colombier * Perhaps it would be best just to not set an ExtINT entry at
2687dd7cddfSDavid du Colombier * all, it shouldn't be needed for SMP mode.
2697dd7cddfSDavid du Colombier */
2707dd7cddfSDavid du Colombier po = PcmpHIGH;
2717dd7cddfSDavid du Colombier el = PcmpEDGE;
2727dd7cddfSDavid du Colombier break;
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier
2757dd7cddfSDavid du Colombier /*
2767dd7cddfSDavid du Colombier */
2777dd7cddfSDavid du Colombier if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
2787dd7cddfSDavid du Colombier po = PcmpHIGH;
2797dd7cddfSDavid du Colombier el = PcmpEDGE;
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier if(!po)
2827dd7cddfSDavid du Colombier po = bus->po;
2837dd7cddfSDavid du Colombier if(po == PcmpLOW)
2847dd7cddfSDavid du Colombier v |= ApicLOW;
2857dd7cddfSDavid du Colombier else if(po != PcmpHIGH){
2867dd7cddfSDavid du Colombier print("mpintrinit: bad polarity 0x%uX\n", po);
2877dd7cddfSDavid du Colombier return ApicIMASK;
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier if(!el)
2917dd7cddfSDavid du Colombier el = bus->el;
2927dd7cddfSDavid du Colombier if(el == PcmpLEVEL)
2937dd7cddfSDavid du Colombier v |= ApicLEVEL;
2947dd7cddfSDavid du Colombier else if(el != PcmpEDGE){
2957dd7cddfSDavid du Colombier print("mpintrinit: bad trigger 0x%uX\n", el);
2967dd7cddfSDavid du Colombier return ApicIMASK;
2977dd7cddfSDavid du Colombier }
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier return v;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier
3027dd7cddfSDavid du Colombier static int
mklintr(PCMPintr * p)3037dd7cddfSDavid du Colombier mklintr(PCMPintr* p)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier Apic *apic;
3067dd7cddfSDavid du Colombier Bus *bus;
3077dd7cddfSDavid du Colombier int intin, v;
3087dd7cddfSDavid du Colombier
3097dd7cddfSDavid du Colombier /*
3107dd7cddfSDavid du Colombier * The offsets of vectors for LINT[01] are known to be
3117dd7cddfSDavid du Colombier * 0 and 1 from the local APIC vector space at VectorLAPIC.
3127dd7cddfSDavid du Colombier */
3137dd7cddfSDavid du Colombier if((bus = mpgetbus(p->busno)) == 0)
3147dd7cddfSDavid du Colombier return 0;
3157dd7cddfSDavid du Colombier intin = p->intin;
3167dd7cddfSDavid du Colombier
3177dd7cddfSDavid du Colombier /*
3187dd7cddfSDavid du Colombier * Pentium Pros have problems if LINT[01] are set to ExtINT
3197dd7cddfSDavid du Colombier * so just bag it, SMP mode shouldn't need ExtINT anyway.
3207dd7cddfSDavid du Colombier */
3217dd7cddfSDavid du Colombier if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
3227dd7cddfSDavid du Colombier v = ApicIMASK;
3237dd7cddfSDavid du Colombier else
3247dd7cddfSDavid du Colombier v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
3257dd7cddfSDavid du Colombier
3267dd7cddfSDavid du Colombier if(p->apicno == 0xFF){
3277dd7cddfSDavid du Colombier for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
3287dd7cddfSDavid du Colombier if((apic->flags & PcmpEN)
3297dd7cddfSDavid du Colombier && apic->type == PcmpPROCESSOR)
3307dd7cddfSDavid du Colombier apic->lintr[intin] = v;
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier else{
334abfa367dSDavid du Colombier if ((unsigned)p->apicno >= nelem(mpapic))
335abfa367dSDavid du Colombier panic("mklintr: ioapic %d out of range", p->apicno);
3367dd7cddfSDavid du Colombier apic = &mpapic[p->apicno];
3377dd7cddfSDavid du Colombier if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
3387dd7cddfSDavid du Colombier apic->lintr[intin] = v;
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier
3417dd7cddfSDavid du Colombier return v;
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier
3447dd7cddfSDavid du Colombier static void
checkmtrr(void)3457dd7cddfSDavid du Colombier checkmtrr(void)
3467dd7cddfSDavid du Colombier {
3477dd7cddfSDavid du Colombier int i, vcnt;
3487dd7cddfSDavid du Colombier Mach *mach0;
3497dd7cddfSDavid du Colombier
3507dd7cddfSDavid du Colombier /*
3517dd7cddfSDavid du Colombier * If there are MTRR registers, snarf them for validation.
3527dd7cddfSDavid du Colombier */
35300a4193cSDavid du Colombier if(!(m->cpuiddx & Mtrr))
3547dd7cddfSDavid du Colombier return;
3557dd7cddfSDavid du Colombier
3567dd7cddfSDavid du Colombier rdmsr(0x0FE, &m->mtrrcap);
3577dd7cddfSDavid du Colombier rdmsr(0x2FF, &m->mtrrdef);
3587dd7cddfSDavid du Colombier if(m->mtrrcap & 0x0100){
3597dd7cddfSDavid du Colombier rdmsr(0x250, &m->mtrrfix[0]);
3607dd7cddfSDavid du Colombier rdmsr(0x258, &m->mtrrfix[1]);
3617dd7cddfSDavid du Colombier rdmsr(0x259, &m->mtrrfix[2]);
3627dd7cddfSDavid du Colombier for(i = 0; i < 8; i++)
3637dd7cddfSDavid du Colombier rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier vcnt = m->mtrrcap & 0x00FF;
3667dd7cddfSDavid du Colombier if(vcnt > nelem(m->mtrrvar))
3677dd7cddfSDavid du Colombier vcnt = nelem(m->mtrrvar);
3687dd7cddfSDavid du Colombier for(i = 0; i < vcnt; i++)
3697dd7cddfSDavid du Colombier rdmsr(0x200+i, &m->mtrrvar[i]);
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier /*
3727dd7cddfSDavid du Colombier * If not the bootstrap processor, compare.
3737dd7cddfSDavid du Colombier */
3747dd7cddfSDavid du Colombier if(m->machno == 0)
3757dd7cddfSDavid du Colombier return;
3767dd7cddfSDavid du Colombier
3777dd7cddfSDavid du Colombier mach0 = MACHP(0);
3787dd7cddfSDavid du Colombier if(mach0->mtrrcap != m->mtrrcap)
3797dd7cddfSDavid du Colombier print("mtrrcap%d: %lluX %lluX\n",
3807dd7cddfSDavid du Colombier m->machno, mach0->mtrrcap, m->mtrrcap);
3817dd7cddfSDavid du Colombier if(mach0->mtrrdef != m->mtrrdef)
3827dd7cddfSDavid du Colombier print("mtrrdef%d: %lluX %lluX\n",
3837dd7cddfSDavid du Colombier m->machno, mach0->mtrrdef, m->mtrrdef);
3847dd7cddfSDavid du Colombier for(i = 0; i < 11; i++){
3857dd7cddfSDavid du Colombier if(mach0->mtrrfix[i] != m->mtrrfix[i])
3867dd7cddfSDavid du Colombier print("mtrrfix%d: i%d: %lluX %lluX\n",
3877dd7cddfSDavid du Colombier m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier for(i = 0; i < vcnt; i++){
3907dd7cddfSDavid du Colombier if(mach0->mtrrvar[i] != m->mtrrvar[i])
3917dd7cddfSDavid du Colombier print("mtrrvar%d: i%d: %lluX %lluX\n",
3927dd7cddfSDavid du Colombier m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier }
3957dd7cddfSDavid du Colombier
3967dd7cddfSDavid du Colombier static void
squidboy(Apic * apic)3977dd7cddfSDavid du Colombier squidboy(Apic* apic)
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier // iprint("Hello Squidboy\n");
4007dd7cddfSDavid du Colombier
4017dd7cddfSDavid du Colombier machinit();
402*4e3613abSDavid du Colombier fpsavealloc();
4037dd7cddfSDavid du Colombier mmuinit();
4047dd7cddfSDavid du Colombier
4057dd7cddfSDavid du Colombier cpuidentify();
4067dd7cddfSDavid du Colombier cpuidprint();
4077dd7cddfSDavid du Colombier checkmtrr();
4087dd7cddfSDavid du Colombier
409bd2f1373SDavid du Colombier apic->online = 1;
410f09ab852SDavid du Colombier coherence();
4117dd7cddfSDavid du Colombier
4127dd7cddfSDavid du Colombier lapicinit(apic);
4137dd7cddfSDavid du Colombier lapiconline();
4149a747e4fSDavid du Colombier syncclock();
415aa04d90cSDavid du Colombier timersinit();
4167dd7cddfSDavid du Colombier
417964da602SDavid du Colombier fpoff();
418964da602SDavid du Colombier
4197dd7cddfSDavid du Colombier lock(&active);
4207dd7cddfSDavid du Colombier active.machs |= 1<<m->machno;
4217dd7cddfSDavid du Colombier unlock(&active);
4227dd7cddfSDavid du Colombier
423da51d93aSDavid du Colombier while(!active.thunderbirdsarego)
424da51d93aSDavid du Colombier microdelay(100);
425da51d93aSDavid du Colombier
4267dd7cddfSDavid du Colombier schedinit();
4277dd7cddfSDavid du Colombier }
4287dd7cddfSDavid du Colombier
4297dd7cddfSDavid du Colombier static void
mpstartap(Apic * apic)4307dd7cddfSDavid du Colombier mpstartap(Apic* apic)
4317dd7cddfSDavid du Colombier {
4327dd7cddfSDavid du Colombier ulong *apbootp, *pdb, *pte;
4337dd7cddfSDavid du Colombier Mach *mach, *mach0;
4347dd7cddfSDavid du Colombier int i, machno;
4357dd7cddfSDavid du Colombier uchar *p;
4367dd7cddfSDavid du Colombier
4377dd7cddfSDavid du Colombier mach0 = MACHP(0);
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier /*
4407dd7cddfSDavid du Colombier * Initialise the AP page-tables and Mach structure. The page-tables
4417dd7cddfSDavid du Colombier * are the same as for the bootstrap processor with the exception of
4427dd7cddfSDavid du Colombier * the PTE for the Mach structure.
4437dd7cddfSDavid du Colombier * Xspanalloc will panic if an allocation can't be made.
4447dd7cddfSDavid du Colombier */
4459a747e4fSDavid du Colombier p = xspanalloc(4*BY2PG, BY2PG, 0);
4467dd7cddfSDavid du Colombier pdb = (ulong*)p;
4477dd7cddfSDavid du Colombier memmove(pdb, mach0->pdb, BY2PG);
4487dd7cddfSDavid du Colombier p += BY2PG;
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
4517dd7cddfSDavid du Colombier return;
4527dd7cddfSDavid du Colombier memmove(p, KADDR(PPN(*pte)), BY2PG);
4537dd7cddfSDavid du Colombier *pte = PADDR(p)|PTEWRITE|PTEVALID;
4549a747e4fSDavid du Colombier if(mach0->havepge)
4559a747e4fSDavid du Colombier *pte |= PTEGLOBAL;
4567dd7cddfSDavid du Colombier p += BY2PG;
4577dd7cddfSDavid du Colombier
4587dd7cddfSDavid du Colombier mach = (Mach*)p;
4597dd7cddfSDavid du Colombier if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
4607dd7cddfSDavid du Colombier return;
4617dd7cddfSDavid du Colombier *pte = PADDR(mach)|PTEWRITE|PTEVALID;
4629a747e4fSDavid du Colombier if(mach0->havepge)
4639a747e4fSDavid du Colombier *pte |= PTEGLOBAL;
4649a747e4fSDavid du Colombier p += BY2PG;
4657dd7cddfSDavid du Colombier
4667dd7cddfSDavid du Colombier machno = apic->machno;
4677dd7cddfSDavid du Colombier MACHP(machno) = mach;
4687dd7cddfSDavid du Colombier mach->machno = machno;
4697dd7cddfSDavid du Colombier mach->pdb = pdb;
4709a747e4fSDavid du Colombier mach->gdt = (Segdesc*)p; /* filled by mmuinit */
4717dd7cddfSDavid du Colombier
4727dd7cddfSDavid du Colombier /*
4737dd7cddfSDavid du Colombier * Tell the AP where its kernel vector and pdb are.
4747dd7cddfSDavid du Colombier * The offsets are known in the AP bootstrap code.
4757dd7cddfSDavid du Colombier */
4767dd7cddfSDavid du Colombier apbootp = (ulong*)(APBOOTSTRAP+0x08);
477f09ab852SDavid du Colombier *apbootp++ = (ulong)squidboy; /* assembler jumps here eventually */
4787dd7cddfSDavid du Colombier *apbootp++ = PADDR(pdb);
4797dd7cddfSDavid du Colombier *apbootp = (ulong)apic;
4807dd7cddfSDavid du Colombier
4817dd7cddfSDavid du Colombier /*
4827dd7cddfSDavid du Colombier * Universal Startup Algorithm.
4837dd7cddfSDavid du Colombier */
484f09ab852SDavid du Colombier p = KADDR(0x467); /* warm-reset vector */
4857dd7cddfSDavid du Colombier *p++ = PADDR(APBOOTSTRAP);
4867dd7cddfSDavid du Colombier *p++ = PADDR(APBOOTSTRAP)>>8;
4877dd7cddfSDavid du Colombier i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
4884de34a7eSDavid du Colombier /* code assumes i==0 */
4894de34a7eSDavid du Colombier if(i != 0)
4904de34a7eSDavid du Colombier print("mp: bad APBOOTSTRAP\n");
4917dd7cddfSDavid du Colombier *p++ = i;
4927dd7cddfSDavid du Colombier *p = i>>8;
4937dd7cddfSDavid du Colombier
494f09ab852SDavid du Colombier coherence();
495f09ab852SDavid du Colombier
496f09ab852SDavid du Colombier nvramwrite(0x0F, 0x0A); /* shutdown code: warm reset upon init ipi */
4977dd7cddfSDavid du Colombier lapicstartap(apic, PADDR(APBOOTSTRAP));
498da51d93aSDavid du Colombier for(i = 0; i < 1000; i++){
499bd2f1373SDavid du Colombier if(apic->online)
5007dd7cddfSDavid du Colombier break;
501da51d93aSDavid du Colombier delay(10);
5027dd7cddfSDavid du Colombier }
5037dd7cddfSDavid du Colombier nvramwrite(0x0F, 0x00);
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier
506abfa367dSDavid du Colombier static void
trympacpi(void)507abfa367dSDavid du Colombier trympacpi(void)
508abfa367dSDavid du Colombier {
5096fbfa2f3SDavid du Colombier if (mpacpifunc != nil) {
510abfa367dSDavid du Colombier print("mpinit: scanning acpi madt for extra cpus\n");
511abfa367dSDavid du Colombier (*mpacpifunc)();
512abfa367dSDavid du Colombier }
513abfa367dSDavid du Colombier }
514abfa367dSDavid du Colombier
5157dd7cddfSDavid du Colombier void
mpinit(void)5167dd7cddfSDavid du Colombier mpinit(void)
5177dd7cddfSDavid du Colombier {
518abfa367dSDavid du Colombier int ncpu, cpuson;
51980ee5cbfSDavid du Colombier char *cp;
5207dd7cddfSDavid du Colombier PCMP *pcmp;
5217dd7cddfSDavid du Colombier uchar *e, *p;
5227dd7cddfSDavid du Colombier Apic *apic, *bpapic;
5234de34a7eSDavid du Colombier void *va;
5247dd7cddfSDavid du Colombier
525abfa367dSDavid du Colombier mpdebug = getconf("*debugmp") != nil;
5267dd7cddfSDavid du Colombier i8259init();
5279a747e4fSDavid du Colombier syncclock();
5287dd7cddfSDavid du Colombier
529abfa367dSDavid du Colombier bpapic = nil;
530abfa367dSDavid du Colombier cpuson = 0;
531abfa367dSDavid du Colombier
532abfa367dSDavid du Colombier if(_mp_ == 0) {
533abfa367dSDavid du Colombier /*
534abfa367dSDavid du Colombier * We can easily get processor info from ACPI, but
535abfa367dSDavid du Colombier * interrupt routing, etc. would require interpreting AML.
536abfa367dSDavid du Colombier */
537abfa367dSDavid du Colombier print("mpinit: no mp table found, assuming uniprocessor\n");
538abfa367dSDavid du Colombier archrevert();
5397dd7cddfSDavid du Colombier return;
540abfa367dSDavid du Colombier }
5417dd7cddfSDavid du Colombier pcmp = KADDR(_mp_->physaddr);
5427dd7cddfSDavid du Colombier
5437dd7cddfSDavid du Colombier /*
5447dd7cddfSDavid du Colombier * Map the local APIC.
5457dd7cddfSDavid du Colombier */
5464de34a7eSDavid du Colombier if((va = vmap(pcmp->lapicbase, 1024)) == nil)
5477dd7cddfSDavid du Colombier return;
5486891d857SDavid du Colombier mppcmp = pcmp;
549abfa367dSDavid du Colombier print("LAPIC: %#lux %#lux\n", pcmp->lapicbase, (ulong)va);
5507dd7cddfSDavid du Colombier
5517dd7cddfSDavid du Colombier /*
5527dd7cddfSDavid du Colombier * Run through the table saving information needed for starting
5537dd7cddfSDavid du Colombier * application processors and initialising any I/O APICs. The table
5547dd7cddfSDavid du Colombier * is guaranteed to be in order such that only one pass is necessary.
5557dd7cddfSDavid du Colombier */
5567dd7cddfSDavid du Colombier p = ((uchar*)pcmp)+sizeof(PCMP);
5577dd7cddfSDavid du Colombier e = ((uchar*)pcmp)+pcmp->length;
5587dd7cddfSDavid du Colombier while(p < e) switch(*p){
5597dd7cddfSDavid du Colombier
5607dd7cddfSDavid du Colombier default:
5617dd7cddfSDavid du Colombier print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
5627dd7cddfSDavid du Colombier *p, e-p);
5637dd7cddfSDavid du Colombier while(p < e){
5647dd7cddfSDavid du Colombier print("%uX ", *p);
5657dd7cddfSDavid du Colombier p++;
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier break;
5687dd7cddfSDavid du Colombier
5697dd7cddfSDavid du Colombier case PcmpPROCESSOR:
5707dd7cddfSDavid du Colombier if(apic = mkprocessor((PCMPprocessor*)p)){
5717dd7cddfSDavid du Colombier /*
5727dd7cddfSDavid du Colombier * Must take a note of bootstrap processor APIC
5737dd7cddfSDavid du Colombier * now as it will be needed in order to start the
5747dd7cddfSDavid du Colombier * application processors later and there's no
5757dd7cddfSDavid du Colombier * guarantee that the bootstrap processor appears
5767dd7cddfSDavid du Colombier * first in the table before the others.
5777dd7cddfSDavid du Colombier */
5784de34a7eSDavid du Colombier apic->addr = va;
579ea15f0ccSDavid du Colombier apic->paddr = pcmp->lapicbase;
5807dd7cddfSDavid du Colombier if(apic->flags & PcmpBP)
5817dd7cddfSDavid du Colombier bpapic = apic;
582abfa367dSDavid du Colombier cpuson++;
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier p += sizeof(PCMPprocessor);
5857dd7cddfSDavid du Colombier continue;
5867dd7cddfSDavid du Colombier
5877dd7cddfSDavid du Colombier case PcmpBUS:
5887dd7cddfSDavid du Colombier mkbus((PCMPbus*)p);
5897dd7cddfSDavid du Colombier p += sizeof(PCMPbus);
5907dd7cddfSDavid du Colombier continue;
5917dd7cddfSDavid du Colombier
5927dd7cddfSDavid du Colombier case PcmpIOAPIC:
5937dd7cddfSDavid du Colombier if(apic = mkioapic((PCMPioapic*)p))
5947dd7cddfSDavid du Colombier ioapicinit(apic, ((PCMPioapic*)p)->apicno);
5957dd7cddfSDavid du Colombier p += sizeof(PCMPioapic);
5967dd7cddfSDavid du Colombier continue;
5977dd7cddfSDavid du Colombier
5987dd7cddfSDavid du Colombier case PcmpIOINTR:
5997dd7cddfSDavid du Colombier mkiointr((PCMPintr*)p);
6007dd7cddfSDavid du Colombier p += sizeof(PCMPintr);
6017dd7cddfSDavid du Colombier continue;
6027dd7cddfSDavid du Colombier
6037dd7cddfSDavid du Colombier case PcmpLINTR:
6047dd7cddfSDavid du Colombier mklintr((PCMPintr*)p);
6057dd7cddfSDavid du Colombier p += sizeof(PCMPintr);
6067dd7cddfSDavid du Colombier continue;
6077dd7cddfSDavid du Colombier }
6087dd7cddfSDavid du Colombier
609abfa367dSDavid du Colombier dprint("mpinit: mp table describes %d cpus\n", cpuson);
610abfa367dSDavid du Colombier
611abfa367dSDavid du Colombier /* For now, always scan ACPI's MADT for processors that MP missed. */
612abfa367dSDavid du Colombier trympacpi();
613abfa367dSDavid du Colombier
614abfa367dSDavid du Colombier if (bpapic == nil)
615abfa367dSDavid du Colombier bpapic = bootapic;
616abfa367dSDavid du Colombier
6177dd7cddfSDavid du Colombier /*
6187dd7cddfSDavid du Colombier * No bootstrap processor, no need to go further.
6197dd7cddfSDavid du Colombier */
6207dd7cddfSDavid du Colombier if(bpapic == 0)
6217dd7cddfSDavid du Colombier return;
622bd2f1373SDavid du Colombier bpapic->online = 1;
6237dd7cddfSDavid du Colombier
6247dd7cddfSDavid du Colombier lapicinit(bpapic);
6257dd7cddfSDavid du Colombier
6267dd7cddfSDavid du Colombier /*
6277dd7cddfSDavid du Colombier * These interrupts are local to the processor
6287dd7cddfSDavid du Colombier * and do not appear in the I/O APIC so it is OK
6297dd7cddfSDavid du Colombier * to set them now.
6307dd7cddfSDavid du Colombier */
6319a747e4fSDavid du Colombier intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
6327dd7cddfSDavid du Colombier intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
6337dd7cddfSDavid du Colombier intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
6347dd7cddfSDavid du Colombier lapiconline();
6357dd7cddfSDavid du Colombier
6367dd7cddfSDavid du Colombier checkmtrr();
6377dd7cddfSDavid du Colombier
6387dd7cddfSDavid du Colombier /*
6397dd7cddfSDavid du Colombier * Initialise the application processors.
6407dd7cddfSDavid du Colombier */
64180ee5cbfSDavid du Colombier if(cp = getconf("*ncpu")){
64280ee5cbfSDavid du Colombier ncpu = strtol(cp, 0, 0);
64380ee5cbfSDavid du Colombier if(ncpu < 1)
64480ee5cbfSDavid du Colombier ncpu = 1;
645bd2f1373SDavid du Colombier else if(ncpu > MAXMACH)
646bd2f1373SDavid du Colombier ncpu = MAXMACH;
64780ee5cbfSDavid du Colombier }
64880ee5cbfSDavid du Colombier else
649bd2f1373SDavid du Colombier ncpu = MAXMACH;
6507dd7cddfSDavid du Colombier memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
6517dd7cddfSDavid du Colombier for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
65280ee5cbfSDavid du Colombier if(ncpu <= 1)
65380ee5cbfSDavid du Colombier break;
6547dd7cddfSDavid du Colombier if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN
65580ee5cbfSDavid du Colombier && apic->type == PcmpPROCESSOR){
6567dd7cddfSDavid du Colombier mpstartap(apic);
657da51d93aSDavid du Colombier conf.nmach++;
65880ee5cbfSDavid du Colombier ncpu--;
65980ee5cbfSDavid du Colombier }
6607dd7cddfSDavid du Colombier }
6617dd7cddfSDavid du Colombier
6627dd7cddfSDavid du Colombier /*
6639a747e4fSDavid du Colombier * we don't really know the number of processors till
6649a747e4fSDavid du Colombier * here.
6659a747e4fSDavid du Colombier *
6669a747e4fSDavid du Colombier * set conf.copymode here if nmach > 1.
6677dd7cddfSDavid du Colombier * Should look for an ExtINT line and enable it.
6687dd7cddfSDavid du Colombier */
6699a747e4fSDavid du Colombier if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
6707dd7cddfSDavid du Colombier conf.copymode = 1;
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier
6737dd7cddfSDavid du Colombier static int
mpintrcpu(void)674bd2f1373SDavid du Colombier mpintrcpu(void)
675bd2f1373SDavid du Colombier {
676bd2f1373SDavid du Colombier int i;
677bd2f1373SDavid du Colombier
678bd2f1373SDavid du Colombier /*
679bd2f1373SDavid du Colombier * The bulk of this code was written ~1995, when there was
680bd2f1373SDavid du Colombier * one architecture and one generation of hardware, the number
681bd2f1373SDavid du Colombier * of CPUs was up to 4(8) and the choices for interrupt routing
682bd2f1373SDavid du Colombier * were physical, or flat logical (optionally with lowest
683bd2f1373SDavid du Colombier * priority interrupt). Logical mode hasn't scaled well with
684bd2f1373SDavid du Colombier * the increasing number of packages/cores/threads, so the
685bd2f1373SDavid du Colombier * fall-back is to physical mode, which works across all processor
686bd2f1373SDavid du Colombier * generations, both AMD and Intel, using the APIC and xAPIC.
687bd2f1373SDavid du Colombier *
688bd2f1373SDavid du Colombier * Interrupt routing policy can be set here.
689bd2f1373SDavid du Colombier * Currently, just assign each interrupt to a different CPU on
690bd2f1373SDavid du Colombier * a round-robin basis. Some idea of the packages/cores/thread
691bd2f1373SDavid du Colombier * topology would be useful here, e.g. to not assign interrupts
692bd2f1373SDavid du Colombier * to more than one thread in a core, or to use a "noise" core.
693bd2f1373SDavid du Colombier * But, as usual, Intel make that an onerous task.
694bd2f1373SDavid du Colombier */
695abfa367dSDavid du Colombier
696abfa367dSDavid du Colombier /*
697abfa367dSDavid du Colombier * temporary workaround for many-core intel (non-amd) systems:
6986fbfa2f3SDavid du Colombier * always use cpu 0. (TODO)
699abfa367dSDavid du Colombier */
700abfa367dSDavid du Colombier if(strncmp(m->cpuidid, "AuthenticAMD", 12) != 0 && conf.nmach > 8)
701abfa367dSDavid du Colombier return 0;
702abfa367dSDavid du Colombier
703bd2f1373SDavid du Colombier lock(&mpphysidlock);
704bd2f1373SDavid du Colombier for(;;){
705bd2f1373SDavid du Colombier i = mpphysid++;
706bd2f1373SDavid du Colombier if(mpphysid >= MaxAPICNO+1)
707bd2f1373SDavid du Colombier mpphysid = 0;
708bd2f1373SDavid du Colombier if(mpapic[i].online)
709bd2f1373SDavid du Colombier break;
710bd2f1373SDavid du Colombier }
711bd2f1373SDavid du Colombier unlock(&mpphysidlock);
712bd2f1373SDavid du Colombier
713bd2f1373SDavid du Colombier return mpapic[i].apicno;
714bd2f1373SDavid du Colombier }
715bd2f1373SDavid du Colombier
716bd2f1373SDavid du Colombier static int
mpintrenablex(Vctl * v,int tbdf)7177dd7cddfSDavid du Colombier mpintrenablex(Vctl* v, int tbdf)
7187dd7cddfSDavid du Colombier {
7197dd7cddfSDavid du Colombier Bus *bus;
7207dd7cddfSDavid du Colombier Aintr *aintr;
7217dd7cddfSDavid du Colombier Apic *apic;
7227dd7cddfSDavid du Colombier Pcidev *pcidev;
723bd2f1373SDavid du Colombier int bno, dno, hi, irq, lo, n, type, vno;
724abfa367dSDavid du Colombier char *typenm;
7257dd7cddfSDavid du Colombier
7267dd7cddfSDavid du Colombier /*
7277dd7cddfSDavid du Colombier * Find the bus.
7287dd7cddfSDavid du Colombier */
7297dd7cddfSDavid du Colombier type = BUSTYPE(tbdf);
7307dd7cddfSDavid du Colombier bno = BUSBNO(tbdf);
7317dd7cddfSDavid du Colombier dno = BUSDNO(tbdf);
732bdd62a84SDavid du Colombier if(type == BusISA)
733bdd62a84SDavid du Colombier bno = mpisabus;
734abfa367dSDavid du Colombier vno = -1;
7357dd7cddfSDavid du Colombier for(bus = mpbus; bus != nil; bus = bus->next){
7367dd7cddfSDavid du Colombier if(bus->type != type)
7377dd7cddfSDavid du Colombier continue;
738bdd62a84SDavid du Colombier if(bus->busno == bno)
7397dd7cddfSDavid du Colombier break;
7407dd7cddfSDavid du Colombier }
7417dd7cddfSDavid du Colombier if(bus == nil){
742abfa367dSDavid du Colombier typenm = type < 0 || type >= nelem(buses)? "": buses[type];
743eac5056eSDavid du Colombier print("mpintrenablex: can't find bus type %d (%s) for irq %d "
744eac5056eSDavid du Colombier "%s busno %d\n", type, typenm, v->irq, v->name, bno);
7457dd7cddfSDavid du Colombier return -1;
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier
7487dd7cddfSDavid du Colombier /*
7497dd7cddfSDavid du Colombier * For PCI devices the interrupt pin (INT[ABCD]) and device
7507dd7cddfSDavid du Colombier * number are encoded into the entry irq field, so create something
7517dd7cddfSDavid du Colombier * to match on. The interrupt pin used by the device has to be
7527dd7cddfSDavid du Colombier * obtained from the PCI config space.
7537dd7cddfSDavid du Colombier */
7547dd7cddfSDavid du Colombier if(bus->type == BusPCI){
7557dd7cddfSDavid du Colombier pcidev = pcimatchtbdf(tbdf);
7567dd7cddfSDavid du Colombier if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
7577dd7cddfSDavid du Colombier irq = (dno<<2)|(n-1);
7587dd7cddfSDavid du Colombier else
7597dd7cddfSDavid du Colombier irq = -1;
760abfa367dSDavid du Colombier //print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq);
7617dd7cddfSDavid du Colombier }
7627dd7cddfSDavid du Colombier else
7637dd7cddfSDavid du Colombier irq = v->irq;
7647dd7cddfSDavid du Colombier
7657dd7cddfSDavid du Colombier /*
7667dd7cddfSDavid du Colombier * Find a matching interrupt entry from the list of interrupts
7677dd7cddfSDavid du Colombier * attached to this bus.
7687dd7cddfSDavid du Colombier */
7697dd7cddfSDavid du Colombier for(aintr = bus->aintr; aintr; aintr = aintr->next){
7707dd7cddfSDavid du Colombier if(aintr->intr->irq != irq)
7717dd7cddfSDavid du Colombier continue;
7726891d857SDavid du Colombier if (0) {
7736891d857SDavid du Colombier PCMPintr* p = aintr->intr;
7747dd7cddfSDavid du Colombier
7756891d857SDavid du Colombier print("mpintrenablex: bus %d intin %d irq %d\n",
7766891d857SDavid du Colombier p->busno, p->intin, p->irq);
7776891d857SDavid du Colombier }
7787dd7cddfSDavid du Colombier /*
7799a747e4fSDavid du Colombier * Check if already enabled. Multifunction devices may share
7809a747e4fSDavid du Colombier * INT[A-D]# so, if already enabled, check the polarity matches
7819a747e4fSDavid du Colombier * and the trigger is level.
7829a747e4fSDavid du Colombier *
7839a747e4fSDavid du Colombier * Should check the devices differ only in the function number,
7849a747e4fSDavid du Colombier * but that can wait for the planned enable/disable rewrite.
7859a747e4fSDavid du Colombier * The RDT read here is safe for now as currently interrupts
7869a747e4fSDavid du Colombier * are never disabled once enabled.
7877dd7cddfSDavid du Colombier */
7887dd7cddfSDavid du Colombier apic = aintr->apic;
7897dd7cddfSDavid du Colombier ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
7907dd7cddfSDavid du Colombier if(!(lo & ApicIMASK)){
7919a747e4fSDavid du Colombier vno = lo & 0xFF;
7926891d857SDavid du Colombier //print("%s vector %d (!imask)\n", v->name, vno);
7939a747e4fSDavid du Colombier n = mpintrinit(bus, aintr->intr, vno, v->irq);
794bd2f1373SDavid du Colombier n |= ApicPHYSICAL; /* no-op */
795ea15f0ccSDavid du Colombier lo &= ~(ApicRemoteIRR|ApicDELIVS);
7969a747e4fSDavid du Colombier if(n != lo || !(n & ApicLEVEL)){
7979a747e4fSDavid du Colombier print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
7989a747e4fSDavid du Colombier v->irq, tbdf, lo, n);
7997dd7cddfSDavid du Colombier return -1;
8007dd7cddfSDavid du Colombier }
801abfa367dSDavid du Colombier break;
8029a747e4fSDavid du Colombier }
8039a747e4fSDavid du Colombier
8047dd7cddfSDavid du Colombier /*
8057dd7cddfSDavid du Colombier * With the APIC a unique vector can be assigned to each
8067dd7cddfSDavid du Colombier * request to enable an interrupt. There are two reasons this
8077dd7cddfSDavid du Colombier * is a good idea:
8087dd7cddfSDavid du Colombier * 1) to prevent lost interrupts, no more than 2 interrupts
8097dd7cddfSDavid du Colombier * should be assigned per block of 16 vectors (there is an
8107dd7cddfSDavid du Colombier * in-service entry and a holding entry for each priority
8117dd7cddfSDavid du Colombier * level and there is one priority level per block of 16
8127dd7cddfSDavid du Colombier * interrupts).
8137dd7cddfSDavid du Colombier * 2) each input pin on the IOAPIC will receive a different
8147dd7cddfSDavid du Colombier * vector regardless of whether the devices on that pin use
8157dd7cddfSDavid du Colombier * the same IRQ as devices on another pin.
8167dd7cddfSDavid du Colombier */
8177dd7cddfSDavid du Colombier vno = VectorAPIC + (incref(&mpvnoref)-1)*8;
8186891d857SDavid du Colombier //print("%s vector %d (imask)\n", v->name, vno);
8197dd7cddfSDavid du Colombier if(vno > MaxVectorAPIC){
8207dd7cddfSDavid du Colombier print("mpintrenable: vno %d, irq %d, tbdf %uX\n",
8217dd7cddfSDavid du Colombier vno, v->irq, tbdf);
8227dd7cddfSDavid du Colombier return -1;
8237dd7cddfSDavid du Colombier }
824abfa367dSDavid du Colombier
825bd2f1373SDavid du Colombier hi = mpintrcpu()<<24;
8267dd7cddfSDavid du Colombier lo = mpintrinit(bus, aintr->intr, vno, v->irq);
8277dd7cddfSDavid du Colombier //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
8287dd7cddfSDavid du Colombier // lo, bus->busno, aintr->intr->irq, vno,
8297dd7cddfSDavid du Colombier // v->irq, i8259elcr);
8307dd7cddfSDavid du Colombier if(lo & ApicIMASK)
8317dd7cddfSDavid du Colombier return -1;
832bd2f1373SDavid du Colombier lo |= ApicPHYSICAL; /* no-op */
833bd2f1373SDavid du Colombier
834bd2f1373SDavid du Colombier if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
835bd2f1373SDavid du Colombier ioapicrdtw(apic, aintr->intr->intin, hi, lo);
8367dd7cddfSDavid du Colombier //else
8377dd7cddfSDavid du Colombier // print("lo not enabled 0x%uX %d\n",
8387dd7cddfSDavid du Colombier // apic->flags, apic->type);
839abfa367dSDavid du Colombier break;
840abfa367dSDavid du Colombier }
841abfa367dSDavid du Colombier if (aintr) {
8427dd7cddfSDavid du Colombier v->isr = lapicisr;
8437dd7cddfSDavid du Colombier v->eoi = lapiceoi;
8447dd7cddfSDavid du Colombier }
845abfa367dSDavid du Colombier return vno;
8467dd7cddfSDavid du Colombier }
8477dd7cddfSDavid du Colombier
8487dd7cddfSDavid du Colombier int
mpintrenable(Vctl * v)8497dd7cddfSDavid du Colombier mpintrenable(Vctl* v)
8507dd7cddfSDavid du Colombier {
8517dd7cddfSDavid du Colombier int irq, tbdf, vno;
8527dd7cddfSDavid du Colombier
8537dd7cddfSDavid du Colombier /*
8547dd7cddfSDavid du Colombier * If the bus is known, try it.
8557dd7cddfSDavid du Colombier * BUSUNKNOWN is given both by [E]ISA devices and by
8567dd7cddfSDavid du Colombier * interrupts local to the processor (local APIC, coprocessor
8577dd7cddfSDavid du Colombier * breakpoint and page-fault).
8587dd7cddfSDavid du Colombier */
8597dd7cddfSDavid du Colombier tbdf = v->tbdf;
8607dd7cddfSDavid du Colombier if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
8617dd7cddfSDavid du Colombier return vno;
8627dd7cddfSDavid du Colombier
8637dd7cddfSDavid du Colombier irq = v->irq;
8647dd7cddfSDavid du Colombier if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
8657dd7cddfSDavid du Colombier if(irq != IrqSPURIOUS)
8667dd7cddfSDavid du Colombier v->isr = lapiceoi;
8677dd7cddfSDavid du Colombier return VectorPIC+irq;
8687dd7cddfSDavid du Colombier }
8697dd7cddfSDavid du Colombier if(irq < 0 || irq > MaxIrqPIC){
8707dd7cddfSDavid du Colombier print("mpintrenable: irq %d out of range\n", irq);
8717dd7cddfSDavid du Colombier return -1;
8727dd7cddfSDavid du Colombier }
8737dd7cddfSDavid du Colombier
8747dd7cddfSDavid du Colombier /*
8757dd7cddfSDavid du Colombier * Either didn't find it or have to try the default buses
8767dd7cddfSDavid du Colombier * (ISA and EISA). This hack is due to either over-zealousness
8777dd7cddfSDavid du Colombier * or laziness on the part of some manufacturers.
8787dd7cddfSDavid du Colombier *
8797dd7cddfSDavid du Colombier * The MP configuration table on some older systems
8807dd7cddfSDavid du Colombier * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
8817dd7cddfSDavid du Colombier * but none for ISA. It also has the interrupt type and
8827dd7cddfSDavid du Colombier * polarity set to 'default for this bus' which wouldn't
8837dd7cddfSDavid du Colombier * be compatible with ISA.
8847dd7cddfSDavid du Colombier */
8857dd7cddfSDavid du Colombier if(mpeisabus != -1){
8867dd7cddfSDavid du Colombier vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
8877dd7cddfSDavid du Colombier if(vno != -1)
8887dd7cddfSDavid du Colombier return vno;
8897dd7cddfSDavid du Colombier }
8907dd7cddfSDavid du Colombier if(mpisabus != -1){
8917dd7cddfSDavid du Colombier vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
8927dd7cddfSDavid du Colombier if(vno != -1)
8937dd7cddfSDavid du Colombier return vno;
8947dd7cddfSDavid du Colombier }
895c3ca4b29SDavid du Colombier print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
896c3ca4b29SDavid du Colombier mpeisabus, mpisabus, v->tbdf, v->irq);
8977dd7cddfSDavid du Colombier return -1;
8987dd7cddfSDavid du Colombier }
8997dd7cddfSDavid du Colombier
9007dd7cddfSDavid du Colombier static Lock mpshutdownlock;
9017dd7cddfSDavid du Colombier
9027dd7cddfSDavid du Colombier void
mpshutdown(void)9037dd7cddfSDavid du Colombier mpshutdown(void)
9047dd7cddfSDavid du Colombier {
9057dd7cddfSDavid du Colombier /*
9067dd7cddfSDavid du Colombier * To be done...
9077dd7cddfSDavid du Colombier */
9087dd7cddfSDavid du Colombier if(!canlock(&mpshutdownlock)){
9097dd7cddfSDavid du Colombier /*
9107dd7cddfSDavid du Colombier * If this processor received the CTRL-ALT-DEL from
9117dd7cddfSDavid du Colombier * the keyboard, acknowledge it. Send an INIT to self.
9127dd7cddfSDavid du Colombier */
9137dd7cddfSDavid du Colombier #ifdef FIXTHIS
9147dd7cddfSDavid du Colombier if(lapicisr(VectorKBD))
9157dd7cddfSDavid du Colombier lapiceoi(VectorKBD);
9167dd7cddfSDavid du Colombier #endif /* FIX THIS */
917c8cbc0e9SDavid du Colombier arch->introff();
9187dd7cddfSDavid du Colombier idle();
9197dd7cddfSDavid du Colombier }
9207dd7cddfSDavid du Colombier
921dadaab63SDavid du Colombier if(active.rebooting)
922dadaab63SDavid du Colombier return;
923bd2f1373SDavid du Colombier print("apshutdown: active = %#8.8ux\n", active.machs);
9247dd7cddfSDavid du Colombier delay(1000);
9257dd7cddfSDavid du Colombier splhi();
9261206f3fcSDavid du Colombier arch->resetothers();
9277dd7cddfSDavid du Colombier
928aef37788SDavid du Colombier pcireset();
929aef37788SDavid du Colombier i8042reset();
930aef37788SDavid du Colombier
9317dd7cddfSDavid du Colombier /*
9327dd7cddfSDavid du Colombier * Often the BIOS hangs during restart if a conventional 8042
9337dd7cddfSDavid du Colombier * warm-boot sequence is tried. The following is Intel specific and
9347dd7cddfSDavid du Colombier * seems to perform a cold-boot, but at least it comes back.
935aef37788SDavid du Colombier * And sometimes there is no keyboard...
936aef37788SDavid du Colombier *
937aef37788SDavid du Colombier * The reset register (0xcf9) is usually in one of the bridge
938aef37788SDavid du Colombier * chips. The actual location and sequence could be extracted from
939aef37788SDavid du Colombier * ACPI but why bother, this is the end of the line anyway.
9407dd7cddfSDavid du Colombier */
941aef37788SDavid du Colombier print("no kbd; trying bios warm boot...");
9427dd7cddfSDavid du Colombier *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */
9437dd7cddfSDavid du Colombier outb(0xCF9, 0x02);
9447dd7cddfSDavid du Colombier outb(0xCF9, 0x06);
945aef37788SDavid du Colombier
946aef37788SDavid du Colombier print("can't reset\n");
947aef37788SDavid du Colombier for(;;)
948aef37788SDavid du Colombier idle();
9497dd7cddfSDavid du Colombier }
950