]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/mp.c
merge
[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 /* filled in by pcmpinit or acpiinit */
13 Bus* mpbus;
14 Bus* mpbuslast;
15 int mpisabus = -1;
16 int mpeisabus = -1;
17 Apic *mpioapic[MaxAPICNO+1];
18 Apic *mpapic[MaxAPICNO+1];
19
20 int
21 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
22 {
23         int el, po, v;
24
25         /*
26          * Parse an I/O or Local APIC interrupt table entry and
27          * return the encoded vector.
28          */
29         v = vno;
30
31         po = intr->flags & PcmpPOMASK;
32         el = intr->flags & PcmpELMASK;
33
34         switch(intr->intr){
35         default:                                /* PcmpINT */
36                 v |= ApicFIXED;                 /* no-op */
37                 break;
38
39         case PcmpNMI:
40                 v |= ApicNMI;
41                 po = PcmpHIGH;
42                 el = PcmpEDGE;
43                 break;
44
45         case PcmpSMI:
46                 v |= ApicSMI;
47                 break;
48
49         case PcmpExtINT:
50                 v |= ApicExtINT;
51                 /*
52                  * The AMI Goliath doesn't boot successfully with it's LINTR0
53                  * entry which decodes to low+level. The PPro manual says ExtINT
54                  * should be level, whereas the Pentium is edge. Setting the
55                  * Goliath to edge+high seems to cure the problem. Other PPro
56                  * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes
57                  * to edge+high, so who knows.
58                  * Perhaps it would be best just to not set an ExtINT entry at
59                  * all, it shouldn't be needed for SMP mode.
60                  */
61                 po = PcmpHIGH;
62                 el = PcmpEDGE;
63                 break;
64         }
65
66         /*
67          */
68         if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
69                 po = PcmpHIGH;
70                 el = PcmpEDGE;
71         }
72         if(!po)
73                 po = bus->po;
74         if(po == PcmpLOW)
75                 v |= ApicLOW;
76         else if(po != PcmpHIGH){
77                 print("mpintrinit: bad polarity 0x%uX\n", po);
78                 return ApicIMASK;
79         }
80
81         if(!el)
82                 el = bus->el;
83         if(el == PcmpLEVEL)
84                 v |= ApicLEVEL;
85         else if(el != PcmpEDGE){
86                 print("mpintrinit: bad trigger 0x%uX\n", el);
87                 return ApicIMASK;
88         }
89
90         return v;
91 }
92
93 static void
94 checkmtrr(void)
95 {
96         int i, vcnt;
97         Mach *mach0;
98
99         /*
100          * If there are MTRR registers, snarf them for validation.
101          */
102         if(!(m->cpuiddx & Mtrr))
103                 return;
104
105         rdmsr(0x0FE, &m->mtrrcap);
106         rdmsr(0x2FF, &m->mtrrdef);
107         if(m->mtrrcap & 0x0100){
108                 rdmsr(0x250, &m->mtrrfix[0]);
109                 rdmsr(0x258, &m->mtrrfix[1]);
110                 rdmsr(0x259, &m->mtrrfix[2]);
111                 for(i = 0; i < 8; i++)
112                         rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
113         }
114         vcnt = m->mtrrcap & 0x00FF;
115         if(vcnt > nelem(m->mtrrvar))
116                 vcnt = nelem(m->mtrrvar);
117         for(i = 0; i < vcnt; i++)
118                 rdmsr(0x200+i, &m->mtrrvar[i]);
119
120         /*
121          * If not the bootstrap processor, compare.
122          */
123         if(m->machno == 0)
124                 return;
125
126         mach0 = MACHP(0);
127         if(mach0->mtrrcap != m->mtrrcap)
128                 print("mtrrcap%d: %lluX %lluX\n",
129                         m->machno, mach0->mtrrcap, m->mtrrcap);
130         if(mach0->mtrrdef != m->mtrrdef)
131                 print("mtrrdef%d: %lluX %lluX\n",
132                         m->machno, mach0->mtrrdef, m->mtrrdef);
133         for(i = 0; i < 11; i++){
134                 if(mach0->mtrrfix[i] != m->mtrrfix[i])
135                         print("mtrrfix%d: i%d: %lluX %lluX\n",
136                                 m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
137         }
138         for(i = 0; i < vcnt; i++){
139                 if(mach0->mtrrvar[i] != m->mtrrvar[i])
140                         print("mtrrvar%d: i%d: %lluX %lluX\n",
141                                 m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
142         }
143 }
144
145 uvlong
146 tscticks(uvlong *hz)
147 {
148         if(hz != nil)
149                 *hz = m->cpuhz;
150
151         cycles(&m->tscticks);   /* Uses the rdtsc instruction */
152         return m->tscticks;
153 }
154
155 void
156 syncclock(void)
157 {
158         uvlong x;
159
160         if(arch->fastclock != tscticks)
161                 return;
162
163         if(m->machno == 0){
164                 wrmsr(0x10, 0);
165                 m->tscticks = 0;
166         } else {
167                 x = MACHP(0)->tscticks;
168                 while(x == MACHP(0)->tscticks)
169                         ;
170                 wrmsr(0x10, MACHP(0)->tscticks);
171                 cycles(&m->tscticks);
172         }
173 }
174
175 static void
176 squidboy(Apic* apic)
177 {
178 //      iprint("Hello Squidboy\n");
179
180         machinit();
181         mmuinit();
182
183         cpuidentify();
184         cpuidprint();
185         checkmtrr();
186
187         apic->online = 1;
188         coherence();
189
190         lapicinit(apic);
191         lapiconline();
192         syncclock();
193         timersinit();
194
195         fpoff();
196
197         lock(&active);
198         active.machs |= 1<<m->machno;
199         unlock(&active);
200
201         while(!active.thunderbirdsarego)
202                 microdelay(100);
203
204         schedinit();
205 }
206
207 static void
208 mpstartap(Apic* apic)
209 {
210         ulong *apbootp, *pdb, *pte;
211         Mach *mach, *mach0;
212         int i, machno;
213         uchar *p;
214
215         mach0 = MACHP(0);
216
217         /*
218          * Initialise the AP page-tables and Mach structure. The page-tables
219          * are the same as for the bootstrap processor with the exception of
220          * the PTE for the Mach structure.
221          * Xspanalloc will panic if an allocation can't be made.
222          */
223         p = xspanalloc(4*BY2PG, BY2PG, 0);
224         pdb = (ulong*)p;
225         memmove(pdb, mach0->pdb, BY2PG);
226         p += BY2PG;
227
228         if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil)
229                 return;
230         memmove(p, KADDR(PPN(*pte)), BY2PG);
231         *pte = PADDR(p)|PTEWRITE|PTEVALID;
232         if(mach0->havepge)
233                 *pte |= PTEGLOBAL;
234         p += BY2PG;
235
236         mach = (Mach*)p;
237         if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)
238                 return;
239         *pte = PADDR(mach)|PTEWRITE|PTEVALID;
240         if(mach0->havepge)
241                 *pte |= PTEGLOBAL;
242         p += BY2PG;
243
244         machno = apic->machno;
245         MACHP(machno) = mach;
246         mach->machno = machno;
247         mach->pdb = pdb;
248         mach->gdt = (Segdesc*)p;        /* filled by mmuinit */
249
250         /*
251          * Tell the AP where its kernel vector and pdb are.
252          * The offsets are known in the AP bootstrap code.
253          */
254         apbootp = (ulong*)(APBOOTSTRAP+0x08);
255         *apbootp++ = (ulong)squidboy;   /* assembler jumps here eventually */
256         *apbootp++ = PADDR(pdb);
257         *apbootp = (ulong)apic;
258
259         /*
260          * Universal Startup Algorithm.
261          */
262         p = KADDR(0x467);               /* warm-reset vector */
263         *p++ = PADDR(APBOOTSTRAP);
264         *p++ = PADDR(APBOOTSTRAP)>>8;
265         i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;
266         /* code assumes i==0 */
267         if(i != 0)
268                 print("mp: bad APBOOTSTRAP\n");
269         *p++ = i;
270         *p = i>>8;
271         coherence();
272
273         nvramwrite(0x0F, 0x0A);         /* shutdown code: warm reset upon init ipi */
274         lapicstartap(apic, PADDR(APBOOTSTRAP));
275         for(i = 0; i < 1000; i++){
276                 if(apic->online)
277                         break;
278                 delay(10);
279         }
280         nvramwrite(0x0F, 0x00);
281 }
282
283 void
284 mpinit(void)
285 {
286         int ncpu, i;
287         Apic *apic;
288         char *cp;
289
290         i8259init();
291         syncclock();
292
293         if(getconf("*apicdebug")){
294                 Bus *b;
295                 Aintr *ai;
296                 PCMPintr *pi;
297
298                 for(i=0; i<=MaxAPICNO; i++){
299                         if(apic = mpapic[i])
300                                 print("LAPIC%d: pa=%lux va=%lux flags=%x\n",
301                                         i, apic->paddr, (ulong)apic->addr, apic->flags);
302                         if(apic = mpioapic[i])
303                                 print("IOAPIC%d: pa=%lux va=%lux flags=%x gsibase=%d mre=%d\n",
304                                         i, apic->paddr, (ulong)apic->addr, apic->flags, apic->gsibase, apic->mre);
305                 }
306                 for(b = mpbus; b; b = b->next){
307                         print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
308                         for(ai = b->aintr; ai; ai = ai->next){
309                                 if(pi = ai->intr)
310                                         print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
311                                                 pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
312                                                 pi->apicno, pi->intin, pi->flags);
313                         }
314                 }
315         }
316
317         apic = nil;
318         for(i=0; i<=MaxAPICNO; i++){
319                 if(mpapic[i] == nil)
320                         continue;
321                 if(mpapic[i]->flags & PcmpBP){
322                         apic = mpapic[i];
323                         break;
324                 }
325         }
326
327         if(apic == nil){
328                 panic("mpinit: no bootstrap processor");
329                 return;
330         }
331         apic->online = 1;
332
333         lapicinit(apic);
334
335         /*
336          * These interrupts are local to the processor
337          * and do not appear in the I/O APIC so it is OK
338          * to set them now.
339          */
340         intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
341         intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
342         intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
343         lapiconline();
344
345         checkmtrr();
346
347         /*
348          * Initialise the application processors.
349          */
350         if(cp = getconf("*ncpu")){
351                 ncpu = strtol(cp, 0, 0);
352                 if(ncpu < 1)
353                         ncpu = 1;
354                 else if(ncpu > MAXMACH)
355                         ncpu = MAXMACH;
356         }
357         else
358                 ncpu = MAXMACH;
359         memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
360         for(i=0; i<nelem(mpapic); i++){
361                 if((apic = mpapic[i]) == nil)
362                         continue;
363                 if(ncpu <= 1)
364                         break;
365                 if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN){
366                         mpstartap(apic);
367                         conf.nmach++;
368                         ncpu--;
369                 }
370         }
371
372         /*
373          *  we don't really know the number of processors till
374          *  here.
375          *
376          *  set conf.copymode here if nmach > 1.
377          *  Should look for an ExtINT line and enable it.
378          */
379         if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
380                 conf.copymode = 1;
381 }
382
383 static int
384 mpintrcpu(void)
385 {
386         static Lock physidlock;
387         static int physid;
388         int i;
389
390         /*
391          * The bulk of this code was written ~1995, when there was
392          * one architecture and one generation of hardware, the number
393          * of CPUs was up to 4(8) and the choices for interrupt routing
394          * were physical, or flat logical (optionally with lowest
395          * priority interrupt). Logical mode hasn't scaled well with
396          * the increasing number of packages/cores/threads, so the
397          * fall-back is to physical mode, which works across all processor
398          * generations, both AMD and Intel, using the APIC and xAPIC.
399          *
400          * Interrupt routing policy can be set here.
401          * Currently, just assign each interrupt to a different CPU on
402          * a round-robin basis. Some idea of the packages/cores/thread
403          * topology would be useful here, e.g. to not assign interrupts
404          * to more than one thread in a core, or to use a "noise" core.
405          * But, as usual, Intel make that an onerous task. 
406          */
407         lock(&physidlock);
408         for(;;){
409                 i = physid++;
410                 if(physid >= nelem(mpapic))
411                         physid = 0;
412                 if(mpapic[i] == nil)
413                         continue;
414                 if(mpapic[i]->online)
415                         break;
416         }
417         unlock(&physidlock);
418
419         return mpapic[i]->apicno;
420 }
421
422 /*
423  * With the APIC a unique vector can be assigned to each
424  * request to enable an interrupt. There are two reasons this
425  * is a good idea:
426  * 1) to prevent lost interrupts, no more than 2 interrupts
427  *    should be assigned per block of 16 vectors (there is an
428  *    in-service entry and a holding entry for each priority
429  *    level and there is one priority level per block of 16
430  *    interrupts).
431  * 2) each input pin on the IOAPIC will receive a different
432  *    vector regardless of whether the devices on that pin use
433  *    the same IRQ as devices on another pin.
434  */
435 static int
436 allocvector(void)
437 {
438         static int round = 0, num = 0;
439         static Lock l;
440         int vno;
441         
442         lock(&l);
443         vno = VectorAPIC + num;
444         if(vno < MaxVectorAPIC-7)
445                 num += 8;
446         else
447                 num = ++round % 8;
448         unlock(&l);
449         return vno;
450 }
451
452 static int
453 mpintrenablex(Vctl* v, int tbdf)
454 {
455         Bus *bus;
456         Aintr *aintr;
457         Apic *apic;
458         Pcidev *pcidev;
459         int bno, dno, pin, hi, irq, lo, n, type, vno;
460
461         type = BUSTYPE(tbdf);
462         bno = BUSBNO(tbdf);
463         dno = BUSDNO(tbdf);
464
465         pin = 0;
466         pcidev = nil;
467         if(type == BusPCI){
468                 if(pcidev = pcimatchtbdf(tbdf))
469                         pin = pcicfgr8(pcidev, PciINTP);
470         } else if(type == BusISA)
471                 bno = mpisabus;
472
473 Findbus:
474         for(bus = mpbus; bus != nil; bus = bus->next){
475                 if(bus->type != type)
476                         continue;
477                 if(bus->busno == bno)
478                         break;
479         }
480
481         if(bus == nil){
482                 /*
483                  * if the PCI device is behind a PCI-PCI bridge thats not described
484                  * by the MP or ACPI tables then walk up the bus translating interrupt
485                  * pin to parent bus.
486                  */
487                 if(pcidev && pcidev->parent && pin > 0){
488                         pin = ((dno+(pin-1))%4)+1;
489                         pcidev = pcidev->parent;
490                         bno = BUSBNO(pcidev->tbdf);
491                         dno = BUSDNO(pcidev->tbdf);
492                         goto Findbus;
493                 }
494                 print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
495                 return -1;
496         }
497
498         /*
499          * For PCI devices the interrupt pin (INT[ABCD]) and device
500          * number are encoded into the entry irq field, so create something
501          * to match on.
502          */
503         if(bus->type == BusPCI){
504                 if(pin > 0)
505                         irq = (dno<<2)|(pin-1);
506                 else
507                         irq = -1;
508         }
509         else
510                 irq = v->irq;
511
512         /*
513          * Find a matching interrupt entry from the list of interrupts
514          * attached to this bus.
515          */
516         for(aintr = bus->aintr; aintr; aintr = aintr->next){
517                 if(aintr->intr->irq != irq)
518                         continue;
519                 if(0){
520                         PCMPintr* p = aintr->intr;
521                         print("mpintrenablex: bus %d intin %d irq %d\n",
522                                 p->busno, p->intin, p->irq);
523                 }
524                 /*
525                  * Check if already enabled. Multifunction devices may share
526                  * INT[A-D]# so, if already enabled, check the polarity matches
527                  * and the trigger is level.
528                  *
529                  * Should check the devices differ only in the function number,
530                  * but that can wait for the planned enable/disable rewrite.
531                  * The RDT read here is safe for now as currently interrupts
532                  * are never disabled once enabled.
533                  */
534                 apic = aintr->apic;
535                 ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
536                 if(!(lo & ApicIMASK)){
537                         vno = lo & 0xFF;
538                         if(0) print("%s vector %d (!imask)\n", v->name, vno);
539                         n = mpintrinit(bus, aintr->intr, vno, v->irq);
540                         n |= ApicPHYSICAL;              /* no-op */
541                         lo &= ~(ApicRemoteIRR|ApicDELIVS);
542                         if(n != lo){
543                                 print("mpintrenable: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
544                                         v->irq, tbdf, lo, n);
545                                 return -1;
546                         }
547                         v->isr = lapicisr;
548                         v->eoi = lapiceoi;
549                         return vno;
550                 }
551
552                 vno = allocvector();
553                 hi = mpintrcpu()<<24;
554                 lo = mpintrinit(bus, aintr->intr, vno, v->irq);
555                 lo |= ApicPHYSICAL;                     /* no-op */
556                 if(lo & ApicIMASK){
557                         print("mpintrenable: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
558                                 v->irq, tbdf, lo, hi);
559                         return -1;
560                 }
561                 if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
562                         ioapicrdtw(apic, aintr->intr->intin, hi, lo);
563
564                 v->isr = lapicisr;
565                 v->eoi = lapiceoi;
566                 return vno;
567         }
568
569         return -1;
570 }
571
572 enum {
573         MSICtrl = 0x02, /* message control register (16 bit) */
574         MSIAddr = 0x04, /* message address register (64 bit) */
575         MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
576         MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
577 };
578
579 static int
580 msiintrenable(Vctl *v)
581 {
582         int tbdf, vno, cap, cpu, ok64;
583         Pcidev *pci;
584
585         if(getconf("*nomsi") != nil)
586                 return -1;
587         tbdf = v->tbdf;
588         if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
589                 return -1;
590         pci = pcimatchtbdf(tbdf);
591         if(pci == nil) {
592                 print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
593                 return -1;
594         }
595         cap = pcicap(pci, PciCapMSI);
596         if(cap < 0)
597                 return -1;
598         vno = allocvector();
599         cpu = mpintrcpu();
600         ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
601         pcicfgw32(pci, cap + MSIAddr, (0xFEE << 20) | (cpu << 12));
602         if(ok64) pcicfgw32(pci, cap + MSIAddr + 4, 0);
603         pcicfgw16(pci, cap + (ok64 ? MSIData64 : MSIData32), vno | (1<<14));
604         pcicfgw16(pci, cap + MSICtrl, 1);
605         v->isr = lapicisr;
606         v->eoi = lapiceoi;
607         return vno;
608 }
609
610 int
611 mpintrenable(Vctl* v)
612 {
613         int irq, tbdf, vno;
614
615         vno = msiintrenable(v);
616         if(vno != -1)
617                 return vno;
618
619         /*
620          * If the bus is known, try it.
621          * BUSUNKNOWN is given both by [E]ISA devices and by
622          * interrupts local to the processor (local APIC, coprocessor
623          * breakpoint and page-fault).
624          */
625         tbdf = v->tbdf;
626         if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
627                 return vno;
628
629         irq = v->irq;
630         if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
631                 if(irq != IrqSPURIOUS)
632                         v->isr = lapiceoi;
633                 return VectorPIC+irq;
634         }
635         if(irq < 0 || irq > MaxIrqPIC){
636                 print("mpintrenable: irq %d out of range\n", irq);
637                 return -1;
638         }
639
640         /*
641          * Either didn't find it or have to try the default buses
642          * (ISA and EISA). This hack is due to either over-zealousness 
643          * or laziness on the part of some manufacturers.
644          *
645          * The MP configuration table on some older systems
646          * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
647          * but none for ISA. It also has the interrupt type and
648          * polarity set to 'default for this bus' which wouldn't
649          * be compatible with ISA.
650          */
651         if(mpeisabus != -1){
652                 vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
653                 if(vno != -1)
654                         return vno;
655         }
656         if(mpisabus != -1){
657                 vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
658                 if(vno != -1)
659                         return vno;
660         }
661         print("mpintrenable: out of choices eisa %d isa %d tbdf %uX irq %d\n",
662                 mpeisabus, mpisabus, v->tbdf, v->irq);
663         return -1;
664 }
665
666
667 void
668 mpshutdown(void)
669 {
670         static Lock shutdownlock;
671
672         /*
673          * To be done...
674          */
675         if(!canlock(&shutdownlock)){
676                 /*
677                  * If this processor received the CTRL-ALT-DEL from
678                  * the keyboard, acknowledge it. Send an INIT to self.
679                  */
680 #ifdef FIXTHIS
681                 if(lapicisr(VectorKBD))
682                         lapiceoi(VectorKBD);
683 #endif /* FIX THIS */
684                 arch->introff();
685                 idle();
686         }
687
688         print("apshutdown: active = %#8.8ux\n", active.machs);
689         delay(1000);
690         splhi();
691
692         /*
693          * INIT all excluding self.
694          */
695         lapicicrw(0, 0x000C0000|ApicINIT);
696
697         pcireset();
698         i8042reset();
699
700         /*
701          * Often the BIOS hangs during restart if a conventional 8042
702          * warm-boot sequence is tried. The following is Intel specific and
703          * seems to perform a cold-boot, but at least it comes back.
704          * And sometimes there is no keyboard...
705          *
706          * The reset register (0xcf9) is usually in one of the bridge
707          * chips. The actual location and sequence could be extracted from
708          * ACPI but why bother, this is the end of the line anyway.
709          */
710         print("no kbd; trying bios warm boot...");
711         *(ushort*)KADDR(0x472) = 0x1234;        /* BIOS warm-boot flag */
712         outb(0xCF9, 0x02);
713         outb(0xCF9, 0x06);
714
715         print("can't reset\n");
716         for(;;)
717                 idle();
718 }