Exemple #1
0
int
mpintrenable(Vctl* v)
{
	int irq, tbdf, vno;

	/*
	 * If the bus is known, try it.
	 * BUSUNKNOWN is given both by [E]ISA devices and by
	 * interrupts local to the processor (local APIC, coprocessor
	 * breakpoint and page-fault).
	 */
	tbdf = v->tbdf;
	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)
		return vno;

	irq = v->irq;
	if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){
		if(irq != IrqSPURIOUS)
			v->isr = lapiceoi;
		return VectorPIC+irq;
	}
	if(irq < 0 || irq > MaxIrqPIC){
		print("mpintrenable: irq %d out of range\n", irq);
		return -1;
	}

	/*
	 * Either didn't find it or have to try the default buses
	 * (ISA and EISA). This hack is due to either over-zealousness 
	 * or laziness on the part of some manufacturers.
	 *
	 * The MP configuration table on some older systems
	 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus
	 * but none for ISA. It also has the interrupt type and
	 * polarity set to 'default for this bus' which wouldn't
	 * be compatible with ISA.
	 */
	if(mpeisabus != -1){
		vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));
		if(vno != -1)
			return vno;
	}
	if(mpisabus != -1){
		vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));
		if(vno != -1)
			return vno;
	}
	print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n",
		mpeisabus, mpisabus, v->tbdf, v->irq);
	return -1;
}
Exemple #2
0
static int32_t
irqmapwrite(Chan* c, void *buf, int32_t n, int64_t offset)
{
    int acpiirq(uint32_t tbdf, int irq);
    int t, b, d, f, irq;
    int *p[] = {&t, &b, &d, &f, &irq};
    Cmdbuf *cb;

    cb = parsecmd(buf, n);
    if (cb->nf < nelem(p))
        error("iprqmapwrite t b d f irq");
    for(int i = 0; i < nelem(p); i++)
        *p[i] = strtoul(cb->f[i], 0, 0);

    acpiirq(MKBUS(t, b, d, f), irq);
    return -1;
}
Exemple #3
0
static int32_t
acpiwrite(Chan *c, void *a, int32_t n, int64_t off)
{
	Mach *m = machp();
	Cmdtab *ct;
	Cmdbuf *cb;
	Reg *r;
	uint rno, fun, dev, bus, i;

	if(c->qid.path == Qio){
		if(reg == nil)
			error("region not configured");
		return regio(reg, a, n, off, 1);
	}
	if(c->qid.path != Qctl)
		error(Eperm);

	cb = parsecmd(a, n);
	if(waserror()){
		free(cb);
		nexterror();
	}
	ct = lookupcmd(cb, ctls, nelem(ctls));
	DBG("acpi ctl %s\n", cb->f[0]);
	switch(ct->index){
	case CMregion:
		r = reg;
		if(r == nil){
			r = smalloc(sizeof(Reg));
			r->name = nil;
		}
		kstrdup(&r->name, cb->f[1]);
		r->spc = acpiregid(cb->f[2]);
		if(r->spc < 0){
			free(r);
			reg = nil;
			error("bad region type");
		}
		if(r->spc == Rpcicfg || r->spc == Rpcibar){
			rno = r->base>>Rpciregshift & Rpciregmask;
			fun = r->base>>Rpcifunshift & Rpcifunmask;
			dev = r->base>>Rpcidevshift & Rpcidevmask;
			bus = r->base>>Rpcibusshift & Rpcibusmask;
			r->tbdf = MKBUS(BusPCI, bus, dev, fun);
			r->base = rno;	/* register ~ our base addr */
		}
		r->base = strtoull(cb->f[3], nil, 0);
		r->len = strtoull(cb->f[4], nil, 0);
		r->accsz = strtoul(cb->f[5], nil, 0);
		if(r->accsz < 1 || r->accsz > 4){
			free(r);
			reg = nil;
			error("bad region access size");
		}
		reg = r;
		DBG("region %s %s %llux %llux sz%d",
			r->name, acpiregstr(r->spc), r->base, r->len, r->accsz);
		break;
	case CMgpe:
		i = strtoul(cb->f[1], nil, 0);
		if(i >= ngpes)
			error("gpe out of range");
		kstrdup(&gpes[i].obj, cb->f[2]);
		DBG("gpe %d %s\n", i, gpes[i].obj);
		setgpeen(i, 1);
		break;
	default:
		panic("acpi: unknown ctl");
	}
Exemple #4
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;
}
Exemple #5
0
static void
pcicfginit(void)
{
	int fd, i, j, n, bno, dno, fno;
	char buf[1024], *base, *s;
	Pcidev *p;
	Dir *d;

	trace("pcicfginit\n");
	if((fd = open(base = "/dev/pci", OREAD)) < 0)
		if((fd = open(base = "#$/pci", OREAD)) < 0)
			return;
	n = dirreadall(fd, &d);
	close(fd);
	
	for(i=0; i<n; i++) {
		if(strstr(d[i].name, "ctl") == nil)
			continue;

		strncpy(buf, d[i].name, sizeof(buf));
		bno = strtoul(buf, &s, 10);
		dno = strtoul(s+1, &s, 10);
		fno = strtoul(s+1, nil, 10);
	
		p = mallocz(sizeof(*p), 1);
		p->tbdf = MKBUS(BusPCI, bno, dno, fno);
		sprint(buf, "%s/%d.%d.%draw", base, bno, dno, fno);
		if((p->rawfd = open(buf, ORDWR)) < 0){
			free(p);
			continue;
		}
		sprint(buf, "%s/%d.%d.%dctl", base, bno, dno, fno);
		if((fd = open(buf, OREAD)) < 0){
			close(p->rawfd);
			free(p);
			continue;
		}
		if((j = read(fd, buf, sizeof(buf)-1)) <= 0){
			close(p->rawfd);
			close(fd);
			free(p);
			continue;
		}
		buf[j] = 0;
		close(fd);

		p->ccrb = strtol(buf, nil, 16);
		p->ccru = strtol(buf + 3, nil, 16);
		p->vid = strtol(buf + 9, &s, 16);
		p->did = strtol(s + 1, &s, 16);
		p->intl = strtol(s + 1, &s, 10);

		p->rid = pcicfgr8(p, PciRID);

		trace("%d.%d.%d: did=%X vid=%X rid=%X intl=%d ccru=%X\n",
			bno, dno, fno, p->did, p->vid, p->rid, p->intl, p->ccru);

		while(*s == ' '){
			j = strtol(s+1, &s, 10);
			if(j < 0 || j >= nelem(p->mem))
				break;
			p->mem[j].bar = strtoul(s+1, &s, 16);
			p->mem[j].size = strtoul(s+1, &s, 10);
			trace("\tmem[%d] = %p %d\n", j, p->mem[j].bar, p->mem[j].size);
		}

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