2 #include "../port/lib.h"
10 #include "apbootstrap.h"
12 /* filled in by pcmpinit or acpiinit */
17 Apic *mpioapic[MaxAPICNO+1];
18 Apic *mpapic[MaxAPICNO+1];
21 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/)
26 * Parse an I/O or Local APIC interrupt table entry and
27 * return the encoded vector.
31 po = intr->flags & PcmpPOMASK;
32 el = intr->flags & PcmpELMASK;
35 default: /* PcmpINT */
36 v |= ApicFIXED; /* no-op */
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.
68 if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){
76 else if(po != PcmpHIGH){
77 print("mpintrinit: bad polarity 0x%uX\n", po);
85 else if(el != PcmpEDGE){
86 print("mpintrinit: bad trigger 0x%uX\n", el);
99 cycles(&m->tscticks); /* Uses the rdtsc instruction */
108 if(arch->fastclock != tscticks)
115 x = MACHP(0)->tscticks;
116 while(x == MACHP(0)->tscticks)
118 wrmsr(0x10, MACHP(0)->tscticks);
119 cycles(&m->tscticks);
133 if(getconf("*apicdebug")){
138 for(i=0; i<=MaxAPICNO; i++){
140 print("LAPIC%d: pa=%lux va=%#p flags=%x\n",
141 i, apic->paddr, apic->addr, apic->flags);
142 if(apic = mpioapic[i])
143 print("IOAPIC%d: pa=%lux va=%#p flags=%x gsibase=%d mre=%d\n",
144 i, apic->paddr, apic->addr, apic->flags, apic->gsibase, apic->mre);
146 for(b = mpbus; b; b = b->next){
147 print("BUS%d type=%d flags=%x\n", b->busno, b->type, b->po|b->el);
148 for(ai = b->aintr; ai; ai = ai->next){
150 print("\ttype=%d irq=%d (%d [%c]) apic=%d intin=%d flags=%x\n",
151 pi->type, pi->irq, pi->irq>>2, "ABCD"[pi->irq&3],
152 pi->apicno, pi->intin, pi->flags);
158 for(i=0; i<=MaxAPICNO; i++){
161 if(mpapic[i]->flags & PcmpBP){
168 panic("mpinit: no bootstrap processor");
176 * These interrupts are local to the processor
177 * and do not appear in the I/O APIC so it is OK
180 intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock");
181 intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
182 intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
186 * Initialise the application processors.
188 if(cp = getconf("*ncpu")){
189 ncpu = strtol(cp, 0, 0);
192 else if(ncpu > MAXMACH)
197 memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));
198 for(i=0; i<nelem(mpapic); i++){
199 if((apic = mpapic[i]) == nil || apic->machno == 0 || apic->machno >= MAXMACH)
203 if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN){
209 print("LAPIC%d: cpu%d did not startup\n", i, apic->machno);
213 /* update tscticks for ap's syncclock() */
214 while(!active.machs[apic->machno]){
215 if(arch->fastclock == tscticks)
216 cycles(&m->tscticks);
222 * we don't really know the number of processors till
225 * set conf.copymode here if nmach > 1.
226 * Should look for an ExtINT line and enable it.
228 if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)
235 static Lock physidlock;
240 * The bulk of this code was written ~1995, when there was
241 * one architecture and one generation of hardware, the number
242 * of CPUs was up to 4(8) and the choices for interrupt routing
243 * were physical, or flat logical (optionally with lowest
244 * priority interrupt). Logical mode hasn't scaled well with
245 * the increasing number of packages/cores/threads, so the
246 * fall-back is to physical mode, which works across all processor
247 * generations, both AMD and Intel, using the APIC and xAPIC.
249 * Interrupt routing policy can be set here.
250 * Currently, just assign each interrupt to a different CPU on
251 * a round-robin basis. Some idea of the packages/cores/thread
252 * topology would be useful here, e.g. to not assign interrupts
253 * to more than one thread in a core, or to use a "noise" core.
254 * But, as usual, Intel make that an onerous task.
259 if(physid >= nelem(mpapic))
263 if(mpapic[i]->online)
268 return mpapic[i]->apicno;
272 * With the APIC a unique vector can be assigned to each
273 * request to enable an interrupt. There are two reasons this
275 * 1) to prevent lost interrupts, no more than 2 interrupts
276 * should be assigned per block of 16 vectors (there is an
277 * in-service entry and a holding entry for each priority
278 * level and there is one priority level per block of 16
280 * 2) each input pin on the IOAPIC will receive a different
281 * vector regardless of whether the devices on that pin use
282 * the same IRQ as devices on another pin.
287 static int round = 0, num = 0;
292 vno = VectorAPIC + num;
293 if(vno < MaxVectorAPIC-7)
302 mpintrenablex(Vctl* v, int tbdf)
308 int bno, dno, pin, hi, irq, lo, n, type, vno;
310 type = BUSTYPE(tbdf);
317 if(pcidev = pcimatchtbdf(tbdf))
318 pin = pcicfgr8(pcidev, PciINTP);
319 } else if(type == BusISA)
323 for(bus = mpbus; bus != nil; bus = bus->next){
324 if(bus->type != type)
326 if(bus->busno == bno)
332 * if the PCI device is behind a PCI-PCI bridge thats not described
333 * by the MP or ACPI tables then walk up the bus translating interrupt
336 if(pcidev && pcidev->parent && pin > 0){
337 pin = ((dno+(pin-1))%4)+1;
338 pcidev = pcidev->parent;
339 bno = BUSBNO(pcidev->tbdf);
340 dno = BUSDNO(pcidev->tbdf);
343 print("mpintrenable: can't find bus type %d, number %d\n", type, bno);
348 * For PCI devices the interrupt pin (INT[ABCD]) and device
349 * number are encoded into the entry irq field, so create something
352 if(bus->type == BusPCI){
354 irq = (dno<<2)|(pin-1);
362 * Find a matching interrupt entry from the list of interrupts
363 * attached to this bus.
365 for(aintr = bus->aintr; aintr; aintr = aintr->next){
366 if(aintr->intr->irq != irq)
369 PCMPintr* p = aintr->intr;
370 print("mpintrenablex: bus %d intin %d irq %d\n",
371 p->busno, p->intin, p->irq);
374 * Check if already enabled. Multifunction devices may share
375 * INT[A-D]# so, if already enabled, check the polarity matches
376 * and the trigger is level.
378 * Should check the devices differ only in the function number,
379 * but that can wait for the planned enable/disable rewrite.
380 * The RDT read here is safe for now as currently interrupts
381 * are never disabled once enabled.
384 ioapicrdtr(apic, aintr->intr->intin, 0, &lo);
385 if(!(lo & ApicIMASK)){
387 if(0) print("%s vector %d (!imask)\n", v->name, vno);
388 n = mpintrinit(bus, aintr->intr, vno, v->irq);
389 n |= ApicPHYSICAL; /* no-op */
390 lo &= ~(ApicRemoteIRR|ApicDELIVS);
392 print("mpintrenable: multiple botch irq %d, tbdf %uX, lo %8.8uX, n %8.8uX\n",
393 v->irq, tbdf, lo, n);
402 hi = mpintrcpu()<<24;
403 lo = mpintrinit(bus, aintr->intr, vno, v->irq);
404 lo |= ApicPHYSICAL; /* no-op */
406 print("mpintrenable: disabled irq %d, tbdf %uX, lo %8.8uX, hi %8.8uX\n",
407 v->irq, tbdf, lo, hi);
410 if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC)
411 ioapicrdtw(apic, aintr->intr->intin, hi, lo);
422 MSICtrl = 0x02, /* message control register (16 bit) */
423 MSIAddr = 0x04, /* message address register (64 bit) */
424 MSIData32 = 0x08, /* message data register for 32 bit MSI (16 bit) */
425 MSIData64 = 0x0C, /* message data register for 64 bit MSI (16 bit) */
435 htmsicapenable(Pcidev *p)
439 if((cap = pcihtcap(p, HTMSIMapping)) <= 0)
441 flags = pcicfgr8(p, cap + HTMSIFlags);
442 if((flags & HTMSIFlagsEn) == 0)
443 pcicfgw8(p, cap + HTMSIFlags, flags | HTMSIFlagsEn);
448 htmsienable(Pcidev *pdev)
453 while((p = pcimatch(p, 0x1022, 0)) != nil)
454 if(p->did == 0x1103 || p->did == 0x1203)
458 return 0; /* not hypertransport platform */
461 while((p = pcimatch(p, 0x10de, 0)) != nil){
463 case 0x02f0: /* NVIDIA NFORCE C51 MEMC0 */
464 case 0x02f1: /* NVIDIA NFORCE C51 MEMC1 */
465 case 0x02f2: /* NVIDIA NFORCE C51 MEMC2 */
466 case 0x02f3: /* NVIDIA NFORCE C51 MEMC3 */
467 case 0x02f4: /* NVIDIA NFORCE C51 MEMC4 */
468 case 0x02f5: /* NVIDIA NFORCE C51 MEMC5 */
469 case 0x02f6: /* NVIDIA NFORCE C51 MEMC6 */
470 case 0x02f7: /* NVIDIA NFORCE C51 MEMC7 */
471 case 0x0369: /* NVIDIA NFORCE MCP55 MEMC */
477 if(htmsicapenable(pdev) == 0)
480 for(p = pdev->parent; p != nil; p = p->parent)
481 if(htmsicapenable(p) == 0)
488 msiintrenable(Vctl *v)
490 int tbdf, vno, cap, cpu, ok64;
493 if(getconf("*nomsi") != nil)
496 if(tbdf == BUSUNKNOWN || BUSTYPE(tbdf) != BusPCI)
498 pci = pcimatchtbdf(tbdf);
500 print("msiintrenable: could not find Pcidev for tbdf %uX\n", tbdf);
503 if(htmsienable(pci) < 0)
505 cap = pcicap(pci, PciCapMSI);
510 ok64 = (pcicfgr16(pci, cap + MSICtrl) & (1<<7)) != 0;
511 pcicfgw32(pci, cap + MSIAddr, (0xFEE << 20) | (cpu << 12));
512 if(ok64) pcicfgw32(pci, cap + MSIAddr + 4, 0);
513 pcicfgw16(pci, cap + (ok64 ? MSIData64 : MSIData32), vno | (1<<14));
514 pcicfgw16(pci, cap + MSICtrl, 1);
521 mpintrenable(Vctl* v)
525 vno = msiintrenable(v);
530 * If the bus is known, try it.
531 * BUSUNKNOWN is given both by [E]ISA devices and by
532 * interrupts local to the processor (local APIC, coprocessor
533 * breakpoint and page-fault).
536 if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
540 if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
541 if(irq != IrqSPURIOUS)
543 return VectorPIC+irq;
545 if(irq < 0 || irq > MaxIrqPIC){
546 print("mpintrenable: irq %d out of range\n", irq);
551 * Either didn't find it or have to try the default buses
552 * (ISA and EISA). This hack is due to either over-zealousness
553 * or laziness on the part of some manufacturers.
555 * The MP configuration table on some older systems
556 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
557 * but none for ISA. It also has the interrupt type and
558 * polarity set to 'default for this bus' which wouldn't
559 * be compatible with ISA.
562 vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
567 vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
571 print("mpintrenable: out of choices eisa %d isa %d tbdf %uX irq %d\n",
572 mpeisabus, mpisabus, v->tbdf, v->irq);
580 * Park application processors.
591 * INIT all excluding self.
593 lapicicrw(0, 0x000C0000|ApicINIT);