コード例 #1
0
ファイル: pci.c プロジェクト: Harvey-OS/harvey
static int
tbdffmt(Fmt* fmt)
{
	char *p;
	int l, r;
	uint type, tbdf;

	if((p = malloc(READSTR)) == nil)
		return fmtstrcpy(fmt, "(tbdfconv)");

	switch(fmt->r){
	case 'T':
		tbdf = va_arg(fmt->args, uint);
		type = BUSTYPE(tbdf);
		if(type < nelem(bustypes))
			l = snprint(p, READSTR, bustypes[type]);
		else
			l = snprint(p, READSTR, "%d", type);
		snprint(p+l, READSTR-l, ".%d.%d.%d",
			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
		break;

	default:
		snprint(p, READSTR, "(tbdfconv)");
		break;
	}
	r = fmtstrcpy(fmt, p);
	free(p);

	return r;
}
コード例 #2
0
ファイル: pci.c プロジェクト: Harvey-OS/harvey
void
pcishowdev(Pcidev* t)
{
	int i;
	char intpin = 'x';
	/* intpin numbers can range from 1 to 8. */
	intpin = "xABCDEFGHxxxxxxx"[t->intp&0xf];
	print("%d  %2d/%d %.2x %.2x %.2x %.4x %.4x %c %3d  ",
	      BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
	      t->ccrb, t->ccru, t->ccrp, t->vid, t->did, intpin, t->intl);

	for(i = 0; i < nelem(t->mem); i++) {
		if(t->mem[i].size == 0)
			continue;
		print("%d:%.8llx %d ", i, t->mem[i].bar, t->mem[i].size);
	}
	if(t->ioa.bar || t->ioa.size)
		print("ioa:%.8llx %d ", t->ioa.bar, t->ioa.size);
	if(t->mema.bar || t->mema.size)

	if(t->bridge)
		print("->%d", BUSBNO(t->bridge->tbdf));
	print("\n");
}
コード例 #3
0
ファイル: mp.c プロジェクト: Earnestly/plan9
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;
}
コード例 #4
0
ファイル: pci.c プロジェクト: Harvey-OS/harvey
static int
pcilscan(int bno, char *path, Pcidev** list)
{
	Pcidev *p, *head, *tail;
	int dno, fno, i, hdt, l, maxfno, maxubn, sbn, tbdf, ubn, capoff;

	maxubn = bno;
	head = nil;
	tail = nil;
	for(dno = 0; dno <= Maxdev; dno++){
		maxfno = 0;
		for(fno = 0; fno <= maxfno; fno++){
			/*
			 * For this possible device, form the
			 * bus+device+function triplet needed to address it
			 * and try to read the vendor and device ID.
			 * If successful, allocate a device struct and
			 * start to fill it in with some useful information
			 * from the device's configuration space.
			 */
			tbdf = MKBUS(BusPCI, bno, dno, fno);
			l = pcicfgrw(tbdf, PciVID, 0, Read, 4);
			if(l == 0xFFFFFFFF || l == 0)
				continue;
			p = malloc(sizeof(*p));
			p->caplist = nil;
			p->capidx = nil;
			p->capcnt = 0;
			p->tbdf = tbdf;
			p->vid = l;
			p->did = l>>16;
			p->path = path;

			if(pcilist != nil)
				pcitail->list = p;
			else
				pcilist = p;
			pcitail = p;

			p->pcr = pcicfgr16(p, PciPCR);
			p->rid = pcicfgr8(p, PciRID);
			p->ccrp = pcicfgr8(p, PciCCRp);
			p->ccru = pcicfgr8(p, PciCCRu);
			p->ccrb = pcicfgr8(p, PciCCRb);
			p->cls = pcicfgr8(p, PciCLS);
			p->ltr = pcicfgr8(p, PciLTR);

			p->intl = pcicfgr8(p, PciINTL);
			p->intp = pcicfgr8(p, PciINTP);

			/*
			 * If the device is a multi-function device adjust the
			 * loop count so all possible functions are checked.
			 */
			hdt = pcicfgr8(p, PciHDT);
			if(hdt & 0x80)
				maxfno = Maxfn;

			/*
			 * If appropriate, read the base address registers
			 * and work out the sizes.
			 */
			switch(p->ccrb) {
			default:
				if((hdt & 0x7F) != 0)
					break;
				for(i = 0; i < nelem(p->mem); i++) {
					p->mem[i].bar = pcicfgr32(p, PciBAR0+4*i);
					p->mem[i].size = pcibarsize(p, PciBAR0+4*i);
				}
				break;

			/*
			 * Some virtio-pci devices have ccrb == 0x00, their BARs and
			 * sizes also should be picked here.
			 */

			case 0x05:		/* memory controller */
			case 0x06:		/* bridge device */
				break;
			}

			/*
			 * Try to gather PCI capabilities. If the offset of capabilities
			 * in the config area cannot be found, skip this step. For simplicity,
			 * capabilities will be linked in a LIFO so we don't deal with list
			 * heads and tails.
			 */

			capoff = pcicapoff(p);
			int off = capoff;
			while(capoff != -1) {
				off = pcicfgr8(p, off);
				if((off < 0x40) || (off & 3))
					break;
				off &= ~3;
				Pcicap *c = malloc(sizeof(*c));
				c->dev = p;
				c->link = p->caplist;
				p->caplist = c;
				p->capcnt++;
				c->vndr = pcicfgr8(p, off + PciCapVndr);
				c->caplen = pcicfgr8(p, off + PciCapLen);
				c->type = pcicfgr8(p, off + PciCapType);
				c->bar = pcicfgr8(p, off + PciCapBar);
				c->offset = pcicfgr32(p, off + PciCapOff);
				c->length = pcicfgr32(p, off + PciCapLength);
				off++;
			}

			if(p->capcnt > 0) {
				p->capidx = malloc(p->capcnt * sizeof(Pcicap *));
				Pcicap *pcp = p->caplist;
				for(int pix = 0; ; pix++) {
					p->capidx[pix] = pcp;
					pcp = pcp->link;
					if(pcp == nil)
						break;
				}
			}
			if(head != nil)
				tail->link = p;
			else
				head = p;
			tail = p;
		}
	}

	*list = head;
	for(p = head; p != nil; p = p->link) {
		/*
		 * Find PCI-PCI bridges and recursively descend the tree.
		 */
		if(p->ccrb != 0x06 || p->ccru != 0x04)
			continue;

		/*
		 * If the secondary or subordinate bus number is not
		 * initialised try to do what the PCI BIOS should have
		 * done and fill in the numbers as the tree is descended.
		 * On the way down the subordinate bus number is set to
		 * the maximum as it's not known how many buses are behind
		 * this one; the final value is set on the way back up.
		 */
		sbn = pcicfgr8(p, PciSBN);
		ubn = pcicfgr8(p, PciUBN);

		if(sbn == 0 || ubn == 0) {
			print("%T: unconfigured bridge\n", p->tbdf);

			sbn = maxubn+1;
			/*
			 * Make sure memory, I/O and master enables are
			 * off, set the primary, secondary and subordinate
			 * bus numbers and clear the secondary status before
			 * attempting to scan the secondary bus.
			 *
			 * Initialisation of the bridge should be done here.
			 */
			pcicfgw32(p, PciPCR, 0xFFFF0000);
			pcicfgw32(p, PciPBN, Maxbus<<16 | sbn<<8 | bno);
			pcicfgw16(p, PciSPSR, 0xFFFF);
			char *bus = mallocz(256, 1);
			snprint(bus, 256, "%s/%d.%d.0", path, BUSBNO(p->tbdf), BUSDNO(p->tbdf));
			maxubn = pcilscan(sbn, bus, &p->bridge);
			pcicfgw32(p, PciPBN, maxubn<<16 | sbn<<8 | bno);
		}
		else {
			/*
			 * You can't go back.
			 * This shouldn't be possible, but the
			 * Iwill DK8-HTX seems to have subordinate
			 * bus numbers which get smaller on the
			 * way down. Need to look more closely at
			 * this.
			 */
			if(ubn > maxubn) {
				maxubn = ubn;
			}
			char *bus = mallocz(256, 1);
			snprint(bus, 256, "%s/%d.%d.0", path, BUSBNO(p->tbdf), BUSDNO(p->tbdf));
			pcilscan(sbn, bus, &p->bridge);
		}
	}

	return maxubn;
}