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