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