xref: /plan9-contrib/sys/src/9/pc/mp.c (revision b94bb474148e9d24a82a427863d9c9eb4c20f4ae)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 
9 #include "mp.h"
10 #include "apbootstrap.h"
11 
12 #define dprint(...)	if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
13 
14 /* from mpacpi.c */
15 Apic *bootapic;
16 
17 int mpdebug;
18 void (*mpacpifunc)(void);
19 
20 static PCMP* mppcmp;
21 static Bus* mpbus;
22 static Bus* mpbuslast;
23 static int mpisabus = -1;
24 static int mpeisabus = -1;
25 extern int i8259elcr;			/* mask of level-triggered interrupts */
26 /* static */ Apic mpapic[MaxAPICNO+1];
27 /* static */ int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
28 /* static */ Apic ioapic[MaxAPICNO+1];
29 static Ref mpvnoref;			/* unique vector assignment */
30 static int mpmachno = 1;
31 static Lock mpphysidlock;
32 static int mpphysid;
33 
34 static char* buses[] = {
35 	"CBUSI ",
36 	"CBUSII",
37 	"EISA  ",
38 	"FUTURE",
39 	"INTERN",
40 	"ISA   ",
41 	"MBI   ",
42 	"MBII  ",
43 	"MCA   ",
44 	"MPI   ",
45 	"MPSA  ",
46 	"NUBUS ",
47 	"PCI   ",
48 	"PCMCIA",
49 	"TC    ",
50 	"VL    ",
51 	"VME   ",
52 	"XPRESS",
53 	0,
54 };
55 
56 static Apic*
57 mkprocessor(PCMPprocessor* p)
58 {
59 	int apicno;
60 	Apic *apic;
61 
62 	apicno = p->apicno;
63 	if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
64 		return 0;
65 
66 	apic = &mpapic[apicno];
67 	apic->type = PcmpPROCESSOR;
68 	apic->apicno = apicno;
69 	apic->flags = p->flags;
70 	apic->lintr[0] = ApicIMASK;
71 	apic->lintr[1] = ApicIMASK;
72 
73 	if(p->flags & PcmpBP){
74 		machno2apicno[0] = apicno;
75 		apic->machno = 0;
76 	}
77 	else{
78 		machno2apicno[mpmachno] = apicno;
79 		apic->machno = mpmachno;
80 		mpmachno++;
81 	}
82 
83 	return apic;
84 }
85 
86 static Bus*
87 mkbus(PCMPbus* p)
88 {
89 	Bus *bus;
90 	int i;
91 
92 	for(i = 0; buses[i]; i++){
93 		if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
94 			break;
95 	}
96 	if(buses[i] == 0)
97 		return 0;
98 
99 	bus = xalloc(sizeof(Bus));
100 	if(mpbus)
101 		mpbuslast->next = bus;
102 	else
103 		mpbus = bus;
104 	mpbuslast = bus;
105 
106 	bus->type = i;
107 	bus->busno = p->busno;
108 	if(bus->type == BusEISA){
109 		bus->po = PcmpLOW;
110 		bus->el = PcmpLEVEL;
111 		if(mpeisabus != -1)
112 			print("mkbus: more than one EISA bus\n");
113 		mpeisabus = bus->busno;
114 	}
115 	else if(bus->type == BusPCI){
116 		bus->po = PcmpLOW;
117 		bus->el = PcmpLEVEL;
118 	}
119 	else if(bus->type == BusISA){
120 		bus->po = PcmpHIGH;
121 		bus->el = PcmpEDGE;
122 		if(mpisabus != -1)
123 			print("mkbus: more than one ISA bus\n");
124 		mpisabus = bus->busno;
125 	}
126 	else{
127 		bus->po = PcmpHIGH;
128 		bus->el = PcmpEDGE;
129 	}
130 
131 	return bus;
132 }
133 
134 static Bus*
135 mpgetbus(int busno)
136 {
137 	Bus *bus;
138 
139 	for(bus = mpbus; bus; bus = bus->next){
140 		if(bus->busno == busno)
141 			return bus;
142 	}
143 	print("mpgetbus: can't find bus %d\n", busno);
144 
145 	return 0;
146 }
147 
148 static Apic*
149 mkioapic(PCMPioapic* p)
150 {
151 	void *va;
152 	int apicno;
153 	Apic *apic;
154 
155 	apicno = p->apicno;
156 	if(!(p->flags & PcmpEN) || apicno > MaxAPICNO)
157 		return 0;
158 
159 	/*
160 	 * Map the I/O APIC.
161 	 */
162 	if((va = vmap(p->addr, 1024)) == nil)
163 		return 0;
164 
165 	apic = &ioapic[apicno];
166 	apic->type = PcmpIOAPIC;
167 	apic->apicno = apicno;
168 	apic->addr = va;
169 	apic->paddr = p->addr;
170 	apic->flags = p->flags;
171 
172 	return apic;
173 }
174 
175 static Aintr*
176 mkiointr(PCMPintr* p)
177 {
178 	Bus *bus;
179 	Aintr *aintr;
180 	PCMPintr* pcmpintr;
181 
182 	/*
183 	 * According to the MultiProcessor Specification, a destination
184 	 * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
185 	 * It's unclear how that can possibly be correct so treat it as
186 	 * an error for now.
187 	 */
188 	if(p->apicno == 0xFF)
189 		return 0;
190 	if((bus = mpgetbus(p->busno)) == 0)
191 		return 0;
192 
193 	aintr = xalloc(sizeof(Aintr));
194 	aintr->intr = p;
195 
196 	if(0)
197 		dprint("mkiointr: type %d intr type %d flags %#o "
198 			"bus %d irq %d apicno %d intin %d\n",
199 			p->type, p->intr, p->flags,
200 			p->busno, p->irq, p->apicno, p->intin);
201 	/*
202 	 * Hack for Intel SR1520ML motherboard, which BIOS describes
203 	 * the i82575 dual ethernet controllers incorrectly.
204 	 */
205 	if(mppcmp && memcmp(mppcmp->product, "INTEL   X38MLST     ", 20) == 0){
206 		if(p->busno == 1 && p->intin == 16 && p->irq == 1){
207 			pcmpintr = malloc(sizeof(PCMPintr));
208 			if(pcmpintr == nil)
209 				panic("mkiointr: no memory");
210 			memmove(pcmpintr, p, sizeof(PCMPintr));
211 			print("mkiointr: %20.20s bus %d intin %d irq %d\n",
212 				(char*)mppcmp->product,
213 				pcmpintr->busno, pcmpintr->intin,
214 				pcmpintr->irq);
215 			pcmpintr->intin = 17;
216 			aintr->intr = pcmpintr;
217 		}
218 	}
219 	if ((unsigned)p->apicno >= nelem(mpapic))
220 		panic("mkiointr: apic %d out of range", p->apicno);
221 	aintr->apic = &ioapic[p->apicno];
222 	aintr->next = bus->aintr;
223 	bus->aintr = aintr;
224 
225 	return aintr;
226 }
227 
228 static int
229 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
230 {
231 	int el, po, v;
232 
233 	/*
234 	 * Parse an I/O or Local APIC interrupt table entry and
235 	 * return the encoded vector.
236 	 */
237 	v = vno;
238 
239 	po = intr->flags & PcmpPOMASK;
240 	el = intr->flags & PcmpELMASK;
241 
242 	switch(intr->intr){
243 
244 	default:				/* PcmpINT */
245 		v |= ApicFIXED;			/* no-op */
246 		break;
247 
248 	case PcmpNMI:
249 		v |= ApicNMI;
250 		po = PcmpHIGH;
251 		el = PcmpEDGE;
252 		break;
253 
254 	case PcmpSMI:
255 		v |= ApicSMI;
256 		break;
257 
258 	case PcmpExtINT:
259 		v |= ApicExtINT;
260 		/*
261 		 * The AMI Goliath doesn't boot successfully with it's LINTR0
262 		 * entry which decodes to low+level. The PPro manual says ExtINT
263 		 * should be level, whereas the Pentium is edge. Setting the
264 		 * Goliath to edge+high seems to cure the problem. Other PPro
265 		 * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
266 		 * to edge+high, so who knows.
267 		 * Perhaps it would be best just to not set an ExtINT entry at
268 		 * all, it shouldn't be needed for SMP mode.
269 		 */
270 		po = PcmpHIGH;
271 		el = PcmpEDGE;
272 		break;
273 	}
274 
275 	/*
276 	 */
277 	if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
278 		po = PcmpHIGH;
279 		el = PcmpEDGE;
280 	}
281 	if(!po)
282 		po = bus->po;
283 	if(po == PcmpLOW)
284 		v |= ApicLOW;
285 	else if(po != PcmpHIGH){
286 		print("mpintrinit: bad polarity 0x%uX\n", po);
287 		return ApicIMASK;
288 	}
289 
290 	if(!el)
291 		el = bus->el;
292 	if(el == PcmpLEVEL)
293 		v |= ApicLEVEL;
294 	else if(el != PcmpEDGE){
295 		print("mpintrinit: bad trigger 0x%uX\n", el);
296 		return ApicIMASK;
297 	}
298 
299 	return v;
300 }
301 
302 static int
303 mklintr(PCMPintr* p)
304 {
305 	Apic *apic;
306 	Bus *bus;
307 	int intin, v;
308 
309 	/*
310 	 * The offsets of vectors for LINT[01] are known to be
311 	 * 0 and 1 from the local APIC vector space at VectorLAPIC.
312 	 */
313 	if((bus = mpgetbus(p->busno)) == 0)
314 		return 0;
315 	intin = p->intin;
316 
317 	/*
318 	 * Pentium Pros have problems if LINT[01] are set to ExtINT
319 	 * so just bag it, SMP mode shouldn't need ExtINT anyway.
320 	 */
321 	if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
322 		v = ApicIMASK;
323 	else
324 		v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
325 
326 	if(p->apicno == 0xFF){
327 		for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
328 			if((apic->flags & PcmpEN)
329 			&& apic->type == PcmpPROCESSOR)
330 				apic->lintr[intin] = v;
331 		}
332 	}
333 	else{
334 		if ((unsigned)p->apicno >= nelem(mpapic))
335 			panic("mklintr: ioapic %d out of range", p->apicno);
336 		apic = &mpapic[p->apicno];
337 		if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR)
338 			apic->lintr[intin] = v;
339 	}
340 
341 	return v;
342 }
343 
344 static void
345 checkmtrr(void)
346 {
347 	int i, vcnt;
348 	Mach *mach0;
349 
350 	/*
351 	 * If there are MTRR registers, snarf them for validation.
352 	 */
353 	if(!(m->cpuiddx & Mtrr))
354 		return;
355 
356 	rdmsr(0x0FE, &m->mtrrcap);
357 	rdmsr(0x2FF, &m->mtrrdef);
358 	if(m->mtrrcap & 0x0100){
359 		rdmsr(0x250, &m->mtrrfix[0]);
360 		rdmsr(0x258, &m->mtrrfix[1]);
361 		rdmsr(0x259, &m->mtrrfix[2]);
362 		for(i = 0; i < 8; i++)
363 			rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
364 	}
365 	vcnt = m->mtrrcap & 0x00FF;
366 	if(vcnt > nelem(m->mtrrvar))
367 		vcnt = nelem(m->mtrrvar);
368 	for(i = 0; i < vcnt; i++)
369 		rdmsr(0x200+i, &m->mtrrvar[i]);
370 
371 	/*
372 	 * If not the bootstrap processor, compare.
373 	 */
374 	if(m->machno == 0)
375 		return;
376 
377 	mach0 = MACHP(0);
378 	if(mach0->mtrrcap != m->mtrrcap)
379 		print("mtrrcap%d: %lluX %lluX\n",
380 			m->machno, mach0->mtrrcap, m->mtrrcap);
381 	if(mach0->mtrrdef != m->mtrrdef)
382 		print("mtrrdef%d: %lluX %lluX\n",
383 			m->machno, mach0->mtrrdef, m->mtrrdef);
384 	for(i = 0; i < 11; i++){
385 		if(mach0->mtrrfix[i] != m->mtrrfix[i])
386 			print("mtrrfix%d: i%d: %lluX %lluX\n",
387 				m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
388 	}
389 	for(i = 0; i < vcnt; i++){
390 		if(mach0->mtrrvar[i] != m->mtrrvar[i])
391 			print("mtrrvar%d: i%d: %lluX %lluX\n",
392 				m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
393 	}
394 }
395 
396 static void
397 squidboy(Apic* apic)
398 {
399 //	iprint("Hello Squidboy\n");
400 
401 	machinit();
402 	mmuinit();
403 
404 	cpuidentify();
405 	cpuidprint();
406 	checkmtrr();
407 
408 	apic->online = 1;
409 	coherence();
410 
411 	lapicinit(apic);
412 	lapiconline();
413 	syncclock();
414 	timersinit();
415 
416 	fpoff();
417 
418 	lock(&active);
419 	active.machs |= 1<<m->machno;
420 	unlock(&active);
421 
422 	while(!active.thunderbirdsarego)
423 		microdelay(100);
424 
425 	schedinit();
426 }
427 
428 static void
429 mpstartap(Apic* apic)
430 {
431 	ulong *apbootp, *pdb, *pte;
432 	Mach *mach, *mach0;
433 	int i, machno;
434 	uchar *p;
435 
436 	mach0 = MACHP(0);
437 
438 	/*
439 	 * Initialise the AP page-tables and Mach structure. The page-tables
440 	 * are the same as for the bootstrap processor with the exception of
441 	 * the PTE for the Mach structure.
442 	 * Xspanalloc will panic if an allocation can't be made.
443 	 */
444 	p = xspanalloc(4*BY2PG, BY2PG, 0);
445 	pdb = (ulong*)p;
446 	memmove(pdb, mach0->pdb, BY2PG);
447 	p += BY2PG;
448 
449 	if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
450 		return;
451 	memmove(p, KADDR(PPN(*pte)), BY2PG);
452 	*pte = PADDR(p)|PTEWRITE|PTEVALID;
453 	if(mach0->havepge)
454 		*pte |= PTEGLOBAL;
455 	p += BY2PG;
456 
457 	mach = (Mach*)p;
458 	if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
459 		return;
460 	*pte = PADDR(mach)|PTEWRITE|PTEVALID;
461 	if(mach0->havepge)
462 		*pte |= PTEGLOBAL;
463 	p += BY2PG;
464 
465 	machno = apic->machno;
466 	MACHP(machno) = mach;
467 	mach->machno = machno;
468 	mach->pdb = pdb;
469 	mach->gdt = (Segdesc*)p;	/* filled by mmuinit */
470 
471 	/*
472 	 * Tell the AP where its kernel vector and pdb are.
473 	 * The offsets are known in the AP bootstrap code.
474 	 */
475 	apbootp = (ulong*)(APBOOTSTRAP+0x08);
476 	*apbootp++ = (ulong)squidboy;	/* assembler jumps here eventually */
477 	*apbootp++ = PADDR(pdb);
478 	*apbootp = (ulong)apic;
479 
480 	/*
481 	 * Universal Startup Algorithm.
482 	 */
483 	p = KADDR(0x467);		/* warm-reset vector */
484 	*p++ = PADDR(APBOOTSTRAP);
485 	*p++ = PADDR(APBOOTSTRAP)>>8;
486 	i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
487 	/* code assumes i==0 */
488 	if(i != 0)
489 		print("mp: bad APBOOTSTRAP\n");
490 	*p++ = i;
491 	*p = i>>8;
492 
493 	coherence();
494 
495 	nvramwrite(0x0F, 0x0A);	/* shutdown code: warm reset upon init ipi */
496 	lapicstartap(apic, PADDR(APBOOTSTRAP));
497 	for(i = 0; i < 1000; i++){
498 		if(apic->online)
499 			break;
500 		delay(10);
501 	}
502 	nvramwrite(0x0F, 0x00);
503 }
504 
505 static void
506 trympacpi(void)
507 {
508 	if (mpacpifunc != nil) {
509 		print("mpinit: scanning acpi madt for extra cpus\n");
510 		(*mpacpifunc)();
511 	}
512 }
513 
514 void
515 mpinit(void)
516 {
517 	int ncpu, cpuson;
518 	char *cp;
519 	PCMP *pcmp;
520 	uchar *e, *p;
521 	Apic *apic, *bpapic;
522 	void *va;
523 
524 	mpdebug = getconf("*debugmp") != nil;
525 	i8259init();
526 	syncclock();
527 
528 	bpapic = nil;
529 	cpuson = 0;
530 
531 	if(_mp_ == 0) {
532 		/*
533 		 * We can easily get processor info from ACPI, but
534 		 * interrupt routing, etc. would require interpreting AML.
535 		 */
536 		print("mpinit: no mp table found, assuming uniprocessor\n");
537 		archrevert();
538 		return;
539 	}
540 	pcmp = KADDR(_mp_->physaddr);
541 
542 	/*
543 	 * Map the local APIC.
544 	 */
545 	if((va = vmap(pcmp->lapicbase, 1024)) == nil)
546 		return;
547 	mppcmp = pcmp;
548 	print("LAPIC: %#lux %#lux\n", pcmp->lapicbase, (ulong)va);
549 
550 	/*
551 	 * Run through the table saving information needed for starting
552 	 * application processors and initialising any I/O APICs. The table
553 	 * is guaranteed to be in order such that only one pass is necessary.
554 	 */
555 	p = ((uchar*)pcmp)+sizeof(PCMP);
556 	e = ((uchar*)pcmp)+pcmp->length;
557 	while(p < e) switch(*p){
558 
559 	default:
560 		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
561 			*p, e-p);
562 		while(p < e){
563 			print("%uX ", *p);
564 			p++;
565 		}
566 		break;
567 
568 	case PcmpPROCESSOR:
569 		if(apic = mkprocessor((PCMPprocessor*)p)){
570 			/*
571 			 * Must take a note of bootstrap processor APIC
572 			 * now as it will be needed in order to start the
573 			 * application processors later and there's no
574 			 * guarantee that the bootstrap processor appears
575 			 * first in the table before the others.
576 			 */
577 			apic->addr = va;
578 			apic->paddr = pcmp->lapicbase;
579 			if(apic->flags & PcmpBP)
580 				bpapic = apic;
581 			cpuson++;
582 		}
583 		p += sizeof(PCMPprocessor);
584 		continue;
585 
586 	case PcmpBUS:
587 		mkbus((PCMPbus*)p);
588 		p += sizeof(PCMPbus);
589 		continue;
590 
591 	case PcmpIOAPIC:
592 		if(apic = mkioapic((PCMPioapic*)p))
593 			ioapicinit(apic, ((PCMPioapic*)p)->apicno);
594 		p += sizeof(PCMPioapic);
595 		continue;
596 
597 	case PcmpIOINTR:
598 		mkiointr((PCMPintr*)p);
599 		p += sizeof(PCMPintr);
600 		continue;
601 
602 	case PcmpLINTR:
603 		mklintr((PCMPintr*)p);
604 		p += sizeof(PCMPintr);
605 		continue;
606 	}
607 
608 	dprint("mpinit: mp table describes %d cpus\n", cpuson);
609 
610 	/* For now, always scan ACPI's MADT for processors that MP missed. */
611 	trympacpi();
612 
613 	if (bpapic == nil)
614 		bpapic = bootapic;
615 
616 	/*
617 	 * No bootstrap processor, no need to go further.
618 	 */
619 	if(bpapic == 0)
620 		return;
621 	bpapic->online = 1;
622 
623 	lapicinit(bpapic);
624 
625 	/*
626 	 * These interrupts are local to the processor
627 	 * and do not appear in the I/O APIC so it is OK
628 	 * to set them now.
629 	 */
630 	intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
631 	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
632 	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
633 	lapiconline();
634 
635 	checkmtrr();
636 
637 	/*
638 	 * Initialise the application processors.
639 	 */
640 	if(cp = getconf("*ncpu")){
641 		ncpu = strtol(cp, 0, 0);
642 		if(ncpu < 1)
643 			ncpu = 1;
644 		else if(ncpu > MAXMACH)
645 			ncpu = MAXMACH;
646 	}
647 	else
648 		ncpu = MAXMACH;
649 	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
650 	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){
651 		if(ncpu <= 1)
652 			break;
653 		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN
654 		&& apic->type == PcmpPROCESSOR){
655 			mpstartap(apic);
656 			conf.nmach++;
657 			ncpu--;
658 		}
659 	}
660 
661 	/*
662 	 *  we don't really know the number of processors till
663 	 *  here.
664 	 *
665 	 *  set conf.copymode here if nmach > 1.
666 	 *  Should look for an ExtINT line and enable it.
667 	 */
668 	if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
669 		conf.copymode = 1;
670 }
671 
672 static int
673 mpintrcpu(void)
674 {
675 	int i;
676 
677 	/*
678 	 * The bulk of this code was written ~1995, when there was
679 	 * one architecture and one generation of hardware, the number
680 	 * of CPUs was up to 4(8) and the choices for interrupt routing
681 	 * were physical, or flat logical (optionally with lowest
682 	 * priority interrupt). Logical mode hasn't scaled well with
683 	 * the increasing number of packages/cores/threads, so the
684 	 * fall-back is to physical mode, which works across all processor
685 	 * generations, both AMD and Intel, using the APIC and xAPIC.
686 	 *
687 	 * Interrupt routing policy can be set here.
688 	 * Currently, just assign each interrupt to a different CPU on
689 	 * a round-robin basis. Some idea of the packages/cores/thread
690 	 * topology would be useful here, e.g. to not assign interrupts
691 	 * to more than one thread in a core, or to use a "noise" core.
692 	 * But, as usual, Intel make that an onerous task.
693 	 */
694 
695 	/*
696 	 * temporary workaround for many-core intel (non-amd) systems:
697 	 * always use cpu 0.  (TODO)
698 	 */
699 	if(strncmp(m->cpuidid, "AuthenticAMD", 12) != 0 && conf.nmach > 8)
700 		return 0;
701 
702 	lock(&mpphysidlock);
703 	for(;;){
704 		i = mpphysid++;
705 		if(mpphysid >= MaxAPICNO+1)
706 			mpphysid = 0;
707 		if(mpapic[i].online)
708 			break;
709 	}
710 	unlock(&mpphysidlock);
711 
712 	return mpapic[i].apicno;
713 }
714 
715 static int
716 mpintrenablex(Vctl* v, int tbdf)
717 {
718 	Bus *bus;
719 	Aintr *aintr;
720 	Apic *apic;
721 	Pcidev *pcidev;
722 	int bno, dno, hi, irq, lo, n, type, vno;
723 	char *typenm;
724 
725 	/*
726 	 * Find the bus.
727 	 */
728 	type = BUSTYPE(tbdf);
729 	bno = BUSBNO(tbdf);
730 	dno = BUSDNO(tbdf);
731 	if(type == BusISA)
732 		bno = mpisabus;
733 	vno = -1;
734 	for(bus = mpbus; bus != nil; bus = bus->next){
735 		if(bus->type != type)
736 			continue;
737 		if(bus->busno == bno)
738 			break;
739 	}
740 	if(bus == nil){
741 		typenm = type < 0 || type >= nelem(buses)? "": buses[type];
742 		print("mpintrenablex: can't find bus type %d (%s) for irq %d "
743 			"%s busno %d\n", type, typenm, v->irq, v->name, bno);
744 		return -1;
745 	}
746 
747 	/*
748 	 * For PCI devices the interrupt pin (INT[ABCD]) and device
749 	 * number are encoded into the entry irq field, so create something
750 	 * to match on. The interrupt pin used by the device has to be
751 	 * obtained from the PCI config space.
752 	 */
753 	if(bus->type == BusPCI){
754 		pcidev = pcimatchtbdf(tbdf);
755 		if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0)
756 			irq = (dno<<2)|(n-1);
757 		else
758 			irq = -1;
759 		//print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq);
760 	}
761 	else
762 		irq = v->irq;
763 
764 	/*
765 	 * Find a matching interrupt entry from the list of interrupts
766 	 * attached to this bus.
767 	 */
768 	for(aintr = bus->aintr; aintr; aintr = aintr->next){
769 		if(aintr->intr->irq != irq)
770 			continue;
771 		if (0) {
772 			PCMPintr* p = aintr->intr;
773 
774 	   	 	print("mpintrenablex: bus %d intin %d irq %d\n",
775 				p->busno, p->intin, p->irq);
776 		}
777 		/*
778 		 * Check if already enabled. Multifunction devices may share
779 		 * INT[A-D]# so, if already enabled, check the polarity matches
780 		 * and the trigger is level.
781 		 *
782 		 * Should check the devices differ only in the function number,
783 		 * but that can wait for the planned enable/disable rewrite.
784 		 * The RDT read here is safe for now as currently interrupts
785 		 * are never disabled once enabled.
786 		 */
787 		apic = aintr->apic;
788 		ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
789 		if(!(lo & ApicIMASK)){
790 			vno = lo & 0xFF;
791 //print("%s vector %d (!imask)\n", v->name, vno);
792 			n = mpintrinit(bus, aintr->intr, vno, v->irq);
793 			n |= ApicPHYSICAL;		/* no-op */
794 			lo &= ~(ApicRemoteIRR|ApicDELIVS);
795 			if(n != lo || !(n & ApicLEVEL)){
796 				print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
797 					v->irq, tbdf, lo, n);
798 				return -1;
799 			}
800 			break;
801 		}
802 
803 		/*
804 		 * With the APIC a unique vector can be assigned to each
805 		 * request to enable an interrupt. There are two reasons this
806 		 * is a good idea:
807 		 * 1) to prevent lost interrupts, no more than 2 interrupts
808 		 *    should be assigned per block of 16 vectors (there is an
809 		 *    in-service entry and a holding entry for each priority
810 		 *    level and there is one priority level per block of 16
811 		 *    interrupts).
812 		 * 2) each input pin on the IOAPIC will receive a different
813 		 *    vector regardless of whether the devices on that pin use
814 		 *    the same IRQ as devices on another pin.
815 		 */
816 		vno = VectorAPIC + (incref(&mpvnoref)-1)*8;
817 //print("%s vector %d (imask)\n", v->name, vno);
818 		if(vno > MaxVectorAPIC){
819 			print("mpintrenable: vno %d, irq %d, tbdf %uX\n",
820 				vno, v->irq, tbdf);
821 			return -1;
822 		}
823 
824 		hi = mpintrcpu()<<24;
825 		lo = mpintrinit(bus, aintr->intr, vno, v->irq);
826 		//print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n",
827 		//	lo, bus->busno, aintr->intr->irq, vno,
828 		//	v->irq, i8259elcr);
829 		if(lo & ApicIMASK)
830 			return -1;
831 		lo |= ApicPHYSICAL;			/* no-op */
832 
833 		if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
834  			ioapicrdtw(apic, aintr->intr->intin, hi, lo);
835 		//else
836 		//	print("lo not enabled 0x%uX %d\n",
837 		//		apic->flags, apic->type);
838 		break;
839 	}
840 	if (aintr) {
841 		v->isr = lapicisr;
842 		v->eoi = lapiceoi;
843 	}
844 	return vno;
845 }
846 
847 int
848 mpintrenable(Vctl* v)
849 {
850 	int irq, tbdf, vno;
851 
852 	/*
853 	 * If the bus is known, try it.
854 	 * BUSUNKNOWN is given both by [E]ISA devices and by
855 	 * interrupts local to the processor (local APIC, coprocessor
856 	 * breakpoint and page-fault).
857 	 */
858 	tbdf = v->tbdf;
859 	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
860 		return vno;
861 
862 	irq = v->irq;
863 	if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
864 		if(irq != IrqSPURIOUS)
865 			v->isr = lapiceoi;
866 		return VectorPIC+irq;
867 	}
868 	if(irq < 0 || irq > MaxIrqPIC){
869 		print("mpintrenable: irq %d out of range\n", irq);
870 		return -1;
871 	}
872 
873 	/*
874 	 * Either didn't find it or have to try the default buses
875 	 * (ISA and EISA). This hack is due to either over-zealousness
876 	 * or laziness on the part of some manufacturers.
877 	 *
878 	 * The MP configuration table on some older systems
879 	 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
880 	 * but none for ISA. It also has the interrupt type and
881 	 * polarity set to 'default for this bus' which wouldn't
882 	 * be compatible with ISA.
883 	 */
884 	if(mpeisabus != -1){
885 		vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
886 		if(vno != -1)
887 			return vno;
888 	}
889 	if(mpisabus != -1){
890 		vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
891 		if(vno != -1)
892 			return vno;
893 	}
894 	print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
895 		mpeisabus, mpisabus, v->tbdf, v->irq);
896 	return -1;
897 }
898 
899 static Lock mpshutdownlock;
900 
901 void
902 mpshutdown(void)
903 {
904 	/*
905 	 * To be done...
906 	 */
907 	if(!canlock(&mpshutdownlock)){
908 		/*
909 		 * If this processor received the CTRL-ALT-DEL from
910 		 * the keyboard, acknowledge it. Send an INIT to self.
911 		 */
912 #ifdef FIXTHIS
913 		if(lapicisr(VectorKBD))
914 			lapiceoi(VectorKBD);
915 #endif /* FIX THIS */
916 		arch->introff();
917 		idle();
918 	}
919 
920 	if(active.rebooting)
921 		return;
922 	print("apshutdown: active = %#8.8ux\n", active.machs);
923 	delay(1000);
924 	splhi();
925 	arch->resetothers();
926 
927 	pcireset();
928 	i8042reset();
929 
930 	/*
931 	 * Often the BIOS hangs during restart if a conventional 8042
932 	 * warm-boot sequence is tried. The following is Intel specific and
933 	 * seems to perform a cold-boot, but at least it comes back.
934 	 * And sometimes there is no keyboard...
935 	 *
936 	 * The reset register (0xcf9) is usually in one of the bridge
937 	 * chips. The actual location and sequence could be extracted from
938 	 * ACPI but why bother, this is the end of the line anyway.
939 	 */
940 	print("no kbd; trying bios warm boot...");
941 	*(ushort*)KADDR(0x472) = 0x1234;	/* BIOS warm-boot flag */
942 	outb(0xCF9, 0x02);
943 	outb(0xCF9, 0x06);
944 
945 	print("can't reset\n");
946 	for(;;)
947 		idle();
948 }
949