static int mklintr(PCMPintr* p) { Apic *apic; Bus *bus; int intin, v; /* * The offsets of vectors for LINT[01] are known to be * 0 and 1 from the local APIC vector space at VectorLAPIC. */ if((bus = mpgetbus(p->busno)) == 0) return 0; intin = p->intin; /* * Pentium Pros have problems if LINT[01] are set to ExtINT * so just bag it, SMP mode shouldn't need ExtINT anyway. */ if(p->intr == PcmpExtINT || p->intr == PcmpNMI) v = ApicIMASK; else v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq); if(p->apicno == 0xFF){ for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) apic->lintr[intin] = v; } } else{ if ((unsigned)p->apicno >= nelem(mpapic)) panic("mklintr: ioapic %d out of range", p->apicno); apic = &mpapic[p->apicno]; if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) apic->lintr[intin] = v; } return v; }
static int mklintr(PCMPintr* p) { Apic *apic; Bus *bus; int i, intin, v; /* * The offsets of vectors for LINT[01] are known to be * 0 and 1 from the local APIC vector space at VectorLAPIC. */ if((bus = mpgetbus(p->busno)) == 0) return 0; intin = p->intin; /* * Pentium Pros have problems if LINT[01] are set to ExtINT * so just bag it, SMP mode shouldn't need ExtINT anyway. */ if(p->intr == PcmpExtINT || p->intr == PcmpNMI) v = ApicIMASK; else v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq); if(p->apicno == 0xFF){ for(i=0; i<=MaxAPICNO; i++){ if((apic = mpapic[i]) == nil) continue; if(apic->flags & PcmpEN) apic->lintr[intin] = v; } } else{ if(apic = mpapic[p->apicno]) if(apic->flags & PcmpEN) apic->lintr[intin] = v; } return v; }
static int mpintrenablex(Vctl* v, int tbdf) { Bus *bus; Aintr *aintr; Apic *apic; Pcidev *pcidev; int bno, dno, hi, irq, lo, n, type, vno; char *typenm; /* * Find the bus. */ type = BUSTYPE(tbdf); bno = BUSBNO(tbdf); dno = BUSDNO(tbdf); if(type == BusISA) bno = mpisabus; vno = -1; for(bus = mpbus; bus != nil; bus = bus->next){ if(bus->type != type) continue; if(bus->busno == bno) break; } if(bus == nil){ typenm = type < 0 || type >= nelem(buses)? "": buses[type]; print("mpintrenablex: can't find bus type %d (%s) for irq %d " "%s busno %d\n", type, typenm, v->irq, v->name, bno); return -1; } /* * For PCI devices the interrupt pin (INT[ABCD]) and device * number are encoded into the entry irq field, so create something * to match on. The interrupt pin used by the device has to be * obtained from the PCI config space. */ if(bus->type == BusPCI){ pcidev = pcimatchtbdf(tbdf); if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) irq = (dno<<2)|(n-1); else irq = -1; //print("pcidev %#uX: irq %#uX v->irq %#uX\n", tbdf, irq, v->irq); } else irq = v->irq; /* * Find a matching interrupt entry from the list of interrupts * attached to this bus. */ for(aintr = bus->aintr; aintr; aintr = aintr->next){ if(aintr->intr->irq != irq) continue; if (0) { PCMPintr* p = aintr->intr; print("mpintrenablex: bus %d intin %d irq %d\n", p->busno, p->intin, p->irq); } /* * Check if already enabled. Multifunction devices may share * INT[A-D]# so, if already enabled, check the polarity matches * and the trigger is level. * * Should check the devices differ only in the function number, * but that can wait for the planned enable/disable rewrite. * The RDT read here is safe for now as currently interrupts * are never disabled once enabled. */ apic = aintr->apic; ioapicrdtr(apic, aintr->intr->intin, 0, &lo); if(!(lo & ApicIMASK)){ vno = lo & 0xFF; //print("%s vector %d (!imask)\n", v->name, vno); n = mpintrinit(bus, aintr->intr, vno, v->irq); n |= ApicPHYSICAL; /* no-op */ lo &= ~(ApicRemoteIRR|ApicDELIVS); if(n != lo || !(n & ApicLEVEL)){ print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n", v->irq, tbdf, lo, n); return -1; } break; } /* * With the APIC a unique vector can be assigned to each * request to enable an interrupt. There are two reasons this * is a good idea: * 1) to prevent lost interrupts, no more than 2 interrupts * should be assigned per block of 16 vectors (there is an * in-service entry and a holding entry for each priority * level and there is one priority level per block of 16 * interrupts). * 2) each input pin on the IOAPIC will receive a different * vector regardless of whether the devices on that pin use * the same IRQ as devices on another pin. */ vno = VectorAPIC + (incref(&mpvnoref)-1)*8; //print("%s vector %d (imask)\n", v->name, vno); if(vno > MaxVectorAPIC){ print("mpintrenable: vno %d, irq %d, tbdf %uX\n", vno, v->irq, tbdf); return -1; } hi = mpintrcpu()<<24; lo = mpintrinit(bus, aintr->intr, vno, v->irq); //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n", // lo, bus->busno, aintr->intr->irq, vno, // v->irq, i8259elcr); if(lo & ApicIMASK) return -1; lo |= ApicPHYSICAL; /* no-op */ if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC) ioapicrdtw(apic, aintr->intr->intin, hi, lo); //else // print("lo not enabled 0x%uX %d\n", // apic->flags, apic->type); break; } if (aintr) { v->isr = lapicisr; v->eoi = lapiceoi; } return vno; }