Esempio n. 1
0
static uint32_t
pcibarsize(Pcidev *p, int rno)
{
	uint32_t v, size;

	v = pcicfgr32(p, rno);
	pcicfgw32(p, rno, 0xFFFFFFF0);
	size = pcicfgr32(p, rno);
	if(v & 1)
		size |= 0xFFFF0000;
	pcicfgw32(p, rno, v);

	return -(size & ~0x0F);
}
Esempio n. 2
0
static uint32_t
cfgget32(uintptr_t p, void* r)
{
	Reg *ro = r;
	Pcidev d;

	d.tbdf = ro->tbdf;
	return pcicfgr32(&d, p);
}
Esempio n. 3
0
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;
}