xref: /plan9/sys/src/9/pc/mp.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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