xref: /plan9-contrib/sys/src/9k/386/pci.c (revision da317bb81ef206f889122f8664a27371f63545f4)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  * PCI support code.
39ef1f84bSDavid du Colombier  * Needs a massive rewrite.
49ef1f84bSDavid du Colombier  */
59ef1f84bSDavid du Colombier #include "u.h"
69ef1f84bSDavid du Colombier #include "../port/lib.h"
79ef1f84bSDavid du Colombier #include "mem.h"
89ef1f84bSDavid du Colombier #include "dat.h"
99ef1f84bSDavid du Colombier #include "fns.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier #include "io.h"
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier struct
149ef1f84bSDavid du Colombier {
159ef1f84bSDavid du Colombier 	char	output[16384];
169ef1f84bSDavid du Colombier 	int	ptr;
179ef1f84bSDavid du Colombier }PCICONS;
189ef1f84bSDavid du Colombier 
19277b6efdSDavid du Colombier int pcivga;
20277b6efdSDavid du Colombier 
219ef1f84bSDavid du Colombier int
pcilog(char * fmt,...)229ef1f84bSDavid du Colombier pcilog(char *fmt, ...)
239ef1f84bSDavid du Colombier {
249ef1f84bSDavid du Colombier 	int n;
259ef1f84bSDavid du Colombier 	va_list arg;
269ef1f84bSDavid du Colombier 	char buf[PRINTSIZE];
279ef1f84bSDavid du Colombier 
289ef1f84bSDavid du Colombier 	va_start(arg, fmt);
299ef1f84bSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
309ef1f84bSDavid du Colombier 	va_end(arg);
319ef1f84bSDavid du Colombier 
329ef1f84bSDavid du Colombier 	memmove(PCICONS.output+PCICONS.ptr, buf, n);
339ef1f84bSDavid du Colombier 	PCICONS.ptr += n;
349ef1f84bSDavid du Colombier 	return n;
359ef1f84bSDavid du Colombier }
369ef1f84bSDavid du Colombier 
379ef1f84bSDavid du Colombier enum
389ef1f84bSDavid du Colombier {					/* configuration mechanism #1 */
399ef1f84bSDavid du Colombier 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
409ef1f84bSDavid du Colombier 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier 					/* configuration mechanism #2 */
439ef1f84bSDavid du Colombier 	PciCSE		= 0xCF8,	/* configuration space enable */
449ef1f84bSDavid du Colombier 	PciFORWARD	= 0xCFA,	/* which bus */
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier 	MaxFNO		= 7,
479ef1f84bSDavid du Colombier 	MaxUBN		= 255,
489ef1f84bSDavid du Colombier };
499ef1f84bSDavid du Colombier 
509ef1f84bSDavid du Colombier enum
519ef1f84bSDavid du Colombier {					/* command register */
529ef1f84bSDavid du Colombier 	IOen		= (1<<0),
539ef1f84bSDavid du Colombier 	MEMen		= (1<<1),
549ef1f84bSDavid du Colombier 	MASen		= (1<<2),
559ef1f84bSDavid du Colombier 	MemWrInv	= (1<<4),
569ef1f84bSDavid du Colombier 	PErrEn		= (1<<6),
579ef1f84bSDavid du Colombier 	SErrEn		= (1<<8),
589ef1f84bSDavid du Colombier };
599ef1f84bSDavid du Colombier 
609ef1f84bSDavid du Colombier static Lock pcicfglock;
619ef1f84bSDavid du Colombier static Lock pcicfginitlock;
629ef1f84bSDavid du Colombier static int pcicfgmode = -1;
639ef1f84bSDavid du Colombier static int pcimaxbno = 7;
649ef1f84bSDavid du Colombier static int pcimaxdno;
659ef1f84bSDavid du Colombier static Pcidev* pciroot;
669ef1f84bSDavid du Colombier static Pcidev* pcilist;
679ef1f84bSDavid du Colombier static Pcidev* pcitail;
689ef1f84bSDavid du Colombier static int nobios, nopcirouting;
699ef1f84bSDavid du Colombier 
709ef1f84bSDavid du Colombier static int pcicfgrw32(int, int, int, int);
719ef1f84bSDavid du Colombier static int pcicfgrw16(int, int, int, int);
729ef1f84bSDavid du Colombier static int pcicfgrw8(int, int, int, int);
739ef1f84bSDavid du Colombier 
749ef1f84bSDavid du Colombier static char* bustypes[] = {
759ef1f84bSDavid du Colombier 	"CBUSI",
769ef1f84bSDavid du Colombier 	"CBUSII",
779ef1f84bSDavid du Colombier 	"EISA",
789ef1f84bSDavid du Colombier 	"FUTURE",
799ef1f84bSDavid du Colombier 	"INTERN",
809ef1f84bSDavid du Colombier 	"ISA",
819ef1f84bSDavid du Colombier 	"MBI",
829ef1f84bSDavid du Colombier 	"MBII",
839ef1f84bSDavid du Colombier 	"MCA",
849ef1f84bSDavid du Colombier 	"MPI",
859ef1f84bSDavid du Colombier 	"MPSA",
869ef1f84bSDavid du Colombier 	"NUBUS",
879ef1f84bSDavid du Colombier 	"PCI",
889ef1f84bSDavid du Colombier 	"PCMCIA",
899ef1f84bSDavid du Colombier 	"TC",
909ef1f84bSDavid du Colombier 	"VL",
919ef1f84bSDavid du Colombier 	"VME",
929ef1f84bSDavid du Colombier 	"XPRESS",
939ef1f84bSDavid du Colombier };
949ef1f84bSDavid du Colombier 
959ef1f84bSDavid du Colombier #pragma	varargck	type	"T"	int
969ef1f84bSDavid du Colombier 
979ef1f84bSDavid du Colombier static int
tbdffmt(Fmt * fmt)989ef1f84bSDavid du Colombier tbdffmt(Fmt* fmt)
999ef1f84bSDavid du Colombier {
1009ef1f84bSDavid du Colombier 	char *p;
1019ef1f84bSDavid du Colombier 	int l, r, type, tbdf;
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier 	if((p = malloc(READSTR)) == nil)
1049ef1f84bSDavid du Colombier 		return fmtstrcpy(fmt, "(tbdfconv)");
1059ef1f84bSDavid du Colombier 
1069ef1f84bSDavid du Colombier 	switch(fmt->r){
1079ef1f84bSDavid du Colombier 	case 'T':
1089ef1f84bSDavid du Colombier 		tbdf = va_arg(fmt->args, int);
1099ef1f84bSDavid du Colombier 		type = BUSTYPE(tbdf);
1109ef1f84bSDavid du Colombier 		if(type < nelem(bustypes))
1119ef1f84bSDavid du Colombier 			l = snprint(p, READSTR, bustypes[type]);
1129ef1f84bSDavid du Colombier 		else
1139ef1f84bSDavid du Colombier 			l = snprint(p, READSTR, "%d", type);
1149ef1f84bSDavid du Colombier 		snprint(p+l, READSTR-l, ".%d.%d.%d",
1159ef1f84bSDavid du Colombier 			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
1169ef1f84bSDavid du Colombier 		break;
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 	default:
1199ef1f84bSDavid du Colombier 		snprint(p, READSTR, "(tbdfconv)");
1209ef1f84bSDavid du Colombier 		break;
1219ef1f84bSDavid du Colombier 	}
1229ef1f84bSDavid du Colombier 	r = fmtstrcpy(fmt, p);
1239ef1f84bSDavid du Colombier 	free(p);
1249ef1f84bSDavid du Colombier 
1259ef1f84bSDavid du Colombier 	return r;
1269ef1f84bSDavid du Colombier }
1279ef1f84bSDavid du Colombier 
1289ef1f84bSDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)1299ef1f84bSDavid du Colombier pcibarsize(Pcidev *p, int rno)
1309ef1f84bSDavid du Colombier {
1319ef1f84bSDavid du Colombier 	ulong v, size;
1329ef1f84bSDavid du Colombier 
1339ef1f84bSDavid du Colombier 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
1349ef1f84bSDavid du Colombier 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
1359ef1f84bSDavid du Colombier 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
1369ef1f84bSDavid du Colombier 	if(v & 1)
1379ef1f84bSDavid du Colombier 		size |= 0xFFFF0000;
1389ef1f84bSDavid du Colombier 	pcicfgrw32(p->tbdf, rno, v, 0);
1399ef1f84bSDavid du Colombier 
1409ef1f84bSDavid du Colombier 	return -(size & ~0x0F);
1419ef1f84bSDavid du Colombier }
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier static int
pcisizcmp(void * a,void * b)1449ef1f84bSDavid du Colombier pcisizcmp(void *a, void *b)
1459ef1f84bSDavid du Colombier {
1469ef1f84bSDavid du Colombier 	Pcisiz *aa, *bb;
1479ef1f84bSDavid du Colombier 
1489ef1f84bSDavid du Colombier 	aa = a;
1499ef1f84bSDavid du Colombier 	bb = b;
1509ef1f84bSDavid du Colombier 	return aa->siz - bb->siz;
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier static ulong
pcimask(ulong v)1549ef1f84bSDavid du Colombier pcimask(ulong v)
1559ef1f84bSDavid du Colombier {
1569ef1f84bSDavid du Colombier 	ulong mask;
1579ef1f84bSDavid du Colombier 
1589ef1f84bSDavid du Colombier 	mask = BI2BY*sizeof(v);
1599ef1f84bSDavid du Colombier 	for(mask = 1<<(mask-1); mask != 0; mask >>= 1) {
1609ef1f84bSDavid du Colombier 		if(mask & v)
1619ef1f84bSDavid du Colombier 			break;
1629ef1f84bSDavid du Colombier 	}
1639ef1f84bSDavid du Colombier 
1649ef1f84bSDavid du Colombier 	mask--;
1659ef1f84bSDavid du Colombier 	if((v & mask) == 0)
1669ef1f84bSDavid du Colombier 		return v;
1679ef1f84bSDavid du Colombier 
1689ef1f84bSDavid du Colombier 	v |= mask;
1699ef1f84bSDavid du Colombier 	return v+1;
1709ef1f84bSDavid du Colombier }
1719ef1f84bSDavid du Colombier 
1729ef1f84bSDavid du Colombier static void
pcibusmap(Pcidev * root,ulong * pmema,ulong * pioa,int wrreg)1739ef1f84bSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
1749ef1f84bSDavid du Colombier {
1759ef1f84bSDavid du Colombier 	Pcidev *p;
1769ef1f84bSDavid du Colombier 	int ntb, i, size, rno, hole;
1779ef1f84bSDavid du Colombier 	ulong v, mema, ioa, sioa, smema, base, limit;
1789ef1f84bSDavid du Colombier 	Pcisiz *table, *tptr, *mtb, *itb;
1799ef1f84bSDavid du Colombier 	extern void qsort(void*, long, long, int (*)(void*, void*));
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	if(!nobios)
1829ef1f84bSDavid du Colombier 		return;
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier 	ioa = *pioa;
1859ef1f84bSDavid du Colombier 	mema = *pmema;
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier 	DBG("pcibusmap wr=%d %T mem=%#lux io=%#lux\n",
1889ef1f84bSDavid du Colombier 		wrreg, root->tbdf, mema, ioa);
1899ef1f84bSDavid du Colombier 
1909ef1f84bSDavid du Colombier 	ntb = 0;
1919ef1f84bSDavid du Colombier 	for(p = root; p != nil; p = p->link)
1929ef1f84bSDavid du Colombier 		ntb++;
1939ef1f84bSDavid du Colombier 
1949ef1f84bSDavid du Colombier 	ntb *= (PciCIS-PciBAR0)/4;
1959ef1f84bSDavid du Colombier 	table = malloc(2*ntb*sizeof(Pcisiz));
196277b6efdSDavid du Colombier 	if(table == nil)
197277b6efdSDavid du Colombier 		panic("pcibusmap: no memory");
1989ef1f84bSDavid du Colombier 	itb = table;
1999ef1f84bSDavid du Colombier 	mtb = table+ntb;
2009ef1f84bSDavid du Colombier 
2019ef1f84bSDavid du Colombier 	/*
2029ef1f84bSDavid du Colombier 	 * Build a table of sizes
2039ef1f84bSDavid du Colombier 	 */
2049ef1f84bSDavid du Colombier 	for(p = root; p != nil; p = p->link) {
2059ef1f84bSDavid du Colombier 		if(p->ccrb == 0x06) {
2069ef1f84bSDavid du Colombier 			if(p->ccru != 0x04 || p->bridge == nil) {
2079ef1f84bSDavid du Colombier //				DBG("pci: ignored bridge %T\n", p->tbdf);
2089ef1f84bSDavid du Colombier 				continue;
2099ef1f84bSDavid du Colombier 			}
2109ef1f84bSDavid du Colombier 
2119ef1f84bSDavid du Colombier 			sioa = ioa;
2129ef1f84bSDavid du Colombier 			smema = mema;
2139ef1f84bSDavid du Colombier 			pcibusmap(p->bridge, &smema, &sioa, 0);
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier 			hole = pcimask(smema-mema);
2169ef1f84bSDavid du Colombier 			if(hole < (1<<20))
2179ef1f84bSDavid du Colombier 				hole = 1<<20;
2189ef1f84bSDavid du Colombier 			p->mema.size = hole;
2199ef1f84bSDavid du Colombier 
2209ef1f84bSDavid du Colombier 			hole = pcimask(sioa-ioa);
2219ef1f84bSDavid du Colombier 			if(hole < (1<<12))
2229ef1f84bSDavid du Colombier 				hole = 1<<12;
2239ef1f84bSDavid du Colombier 
2249ef1f84bSDavid du Colombier 			p->ioa.size = hole;
2259ef1f84bSDavid du Colombier 
2269ef1f84bSDavid du Colombier 			itb->dev = p;
2279ef1f84bSDavid du Colombier 			itb->bar = -1;
2289ef1f84bSDavid du Colombier 			itb->siz = p->ioa.size;
2299ef1f84bSDavid du Colombier 			itb++;
2309ef1f84bSDavid du Colombier 
2319ef1f84bSDavid du Colombier 			mtb->dev = p;
2329ef1f84bSDavid du Colombier 			mtb->bar = -1;
2339ef1f84bSDavid du Colombier 			mtb->siz = p->mema.size;
2349ef1f84bSDavid du Colombier 			mtb++;
2359ef1f84bSDavid du Colombier 			continue;
2369ef1f84bSDavid du Colombier 		}
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier 		for(i = 0; i <= 5; i++) {
2399ef1f84bSDavid du Colombier 			rno = PciBAR0 + i*4;
2409ef1f84bSDavid du Colombier 			v = pcicfgrw32(p->tbdf, rno, 0, 1);
2419ef1f84bSDavid du Colombier 			size = pcibarsize(p, rno);
2429ef1f84bSDavid du Colombier 			if(size == 0)
2439ef1f84bSDavid du Colombier 				continue;
2449ef1f84bSDavid du Colombier 
2459ef1f84bSDavid du Colombier 			if(v & 1) {
2469ef1f84bSDavid du Colombier 				itb->dev = p;
2479ef1f84bSDavid du Colombier 				itb->bar = i;
2489ef1f84bSDavid du Colombier 				itb->siz = size;
2499ef1f84bSDavid du Colombier 				itb++;
2509ef1f84bSDavid du Colombier 			}
2519ef1f84bSDavid du Colombier 			else {
2529ef1f84bSDavid du Colombier 				mtb->dev = p;
2539ef1f84bSDavid du Colombier 				mtb->bar = i;
2549ef1f84bSDavid du Colombier 				mtb->siz = size;
2559ef1f84bSDavid du Colombier 				mtb++;
2569ef1f84bSDavid du Colombier 			}
2579ef1f84bSDavid du Colombier 
2589ef1f84bSDavid du Colombier 			p->mem[i].size = size;
2599ef1f84bSDavid du Colombier 		}
2609ef1f84bSDavid du Colombier 	}
2619ef1f84bSDavid du Colombier 
2629ef1f84bSDavid du Colombier 	/*
2639ef1f84bSDavid du Colombier 	 * Sort both tables IO smallest first, Memory largest
2649ef1f84bSDavid du Colombier 	 */
2659ef1f84bSDavid du Colombier 	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
2669ef1f84bSDavid du Colombier 	tptr = table+ntb;
2679ef1f84bSDavid du Colombier 	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 	/*
2709ef1f84bSDavid du Colombier 	 * Allocate IO address space on this bus
2719ef1f84bSDavid du Colombier 	 */
2729ef1f84bSDavid du Colombier 	for(tptr = table; tptr < itb; tptr++) {
2739ef1f84bSDavid du Colombier 		hole = tptr->siz;
2749ef1f84bSDavid du Colombier 		if(tptr->bar == -1)
2759ef1f84bSDavid du Colombier 			hole = 1<<12;
2769ef1f84bSDavid du Colombier 		ioa = (ioa+hole-1) & ~(hole-1);
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 		p = tptr->dev;
2799ef1f84bSDavid du Colombier 		if(tptr->bar == -1)
2809ef1f84bSDavid du Colombier 			p->ioa.bar = ioa;
2819ef1f84bSDavid du Colombier 		else {
2829ef1f84bSDavid du Colombier 			p->pcr |= IOen;
2839ef1f84bSDavid du Colombier 			p->mem[tptr->bar].bar = ioa|1;
2849ef1f84bSDavid du Colombier 			if(wrreg)
2859ef1f84bSDavid du Colombier 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
2869ef1f84bSDavid du Colombier 		}
2879ef1f84bSDavid du Colombier 
2889ef1f84bSDavid du Colombier 		ioa += tptr->siz;
2899ef1f84bSDavid du Colombier 	}
2909ef1f84bSDavid du Colombier 
2919ef1f84bSDavid du Colombier 	/*
2929ef1f84bSDavid du Colombier 	 * Allocate Memory address space on this bus
2939ef1f84bSDavid du Colombier 	 */
2949ef1f84bSDavid du Colombier 	for(tptr = table+ntb; tptr < mtb; tptr++) {
2959ef1f84bSDavid du Colombier 		hole = tptr->siz;
2969ef1f84bSDavid du Colombier 		if(tptr->bar == -1)
2979ef1f84bSDavid du Colombier 			hole = 1<<20;
2989ef1f84bSDavid du Colombier 		mema = (mema+hole-1) & ~(hole-1);
2999ef1f84bSDavid du Colombier 
3009ef1f84bSDavid du Colombier 		p = tptr->dev;
3019ef1f84bSDavid du Colombier 		if(tptr->bar == -1)
3029ef1f84bSDavid du Colombier 			p->mema.bar = mema;
3039ef1f84bSDavid du Colombier 		else {
3049ef1f84bSDavid du Colombier 			p->pcr |= MEMen;
3059ef1f84bSDavid du Colombier 			p->mem[tptr->bar].bar = mema;
3069ef1f84bSDavid du Colombier 			if(wrreg)
3079ef1f84bSDavid du Colombier 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
3089ef1f84bSDavid du Colombier 		}
3099ef1f84bSDavid du Colombier 		mema += tptr->siz;
3109ef1f84bSDavid du Colombier 	}
3119ef1f84bSDavid du Colombier 
3129ef1f84bSDavid du Colombier 	*pmema = mema;
3139ef1f84bSDavid du Colombier 	*pioa = ioa;
3149ef1f84bSDavid du Colombier 	free(table);
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	if(wrreg == 0)
3179ef1f84bSDavid du Colombier 		return;
3189ef1f84bSDavid du Colombier 
3199ef1f84bSDavid du Colombier 	/*
3209ef1f84bSDavid du Colombier 	 * Finally set all the bridge addresses & registers
3219ef1f84bSDavid du Colombier 	 */
3229ef1f84bSDavid du Colombier 	for(p = root; p != nil; p = p->link) {
3239ef1f84bSDavid du Colombier 		if(p->bridge == nil) {
3249ef1f84bSDavid du Colombier 			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3259ef1f84bSDavid du Colombier 
3269ef1f84bSDavid du Colombier 			p->pcr |= MASen;
3279ef1f84bSDavid du Colombier 			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
3289ef1f84bSDavid du Colombier 			continue;
3299ef1f84bSDavid du Colombier 		}
3309ef1f84bSDavid du Colombier 
3319ef1f84bSDavid du Colombier 		base = p->ioa.bar;
3329ef1f84bSDavid du Colombier 		limit = base+p->ioa.size-1;
3339ef1f84bSDavid du Colombier 		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
3349ef1f84bSDavid du Colombier 		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
3359ef1f84bSDavid du Colombier 		pcicfgrw32(p->tbdf, PciIBR, v, 0);
3369ef1f84bSDavid du Colombier 		v = (limit & 0xFFFF0000)|(base>>16);
3379ef1f84bSDavid du Colombier 		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier 		base = p->mema.bar;
3409ef1f84bSDavid du Colombier 		limit = base+p->mema.size-1;
3419ef1f84bSDavid du Colombier 		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
3429ef1f84bSDavid du Colombier 		pcicfgrw32(p->tbdf, PciMBR, v, 0);
3439ef1f84bSDavid du Colombier 
3449ef1f84bSDavid du Colombier 		/*
3459ef1f84bSDavid du Colombier 		 * Disable memory prefetch
3469ef1f84bSDavid du Colombier 		 */
3479ef1f84bSDavid du Colombier 		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
3489ef1f84bSDavid du Colombier 		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3499ef1f84bSDavid du Colombier 
3509ef1f84bSDavid du Colombier 		/*
3519ef1f84bSDavid du Colombier 		 * Enable the bridge
3529ef1f84bSDavid du Colombier 		 */
3539ef1f84bSDavid du Colombier 		p->pcr |= IOen|MEMen|MASen;
3549ef1f84bSDavid du Colombier 		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
3559ef1f84bSDavid du Colombier 
3569ef1f84bSDavid du Colombier 		sioa = p->ioa.bar;
3579ef1f84bSDavid du Colombier 		smema = p->mema.bar;
3589ef1f84bSDavid du Colombier 		pcibusmap(p->bridge, &smema, &sioa, 1);
3599ef1f84bSDavid du Colombier 	}
3609ef1f84bSDavid du Colombier }
3619ef1f84bSDavid du Colombier 
362277b6efdSDavid du Colombier /* side effect: if a video controller is seen, set pcivga non-zero */
3639ef1f84bSDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)3649ef1f84bSDavid du Colombier pcilscan(int bno, Pcidev** list)
3659ef1f84bSDavid du Colombier {
3669ef1f84bSDavid du Colombier 	Pcidev *p, *head, *tail;
3679ef1f84bSDavid du Colombier 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
3689ef1f84bSDavid du Colombier 
3699ef1f84bSDavid du Colombier 	maxubn = bno;
3709ef1f84bSDavid du Colombier 	head = nil;
3719ef1f84bSDavid du Colombier 	tail = nil;
3729ef1f84bSDavid du Colombier 	for(dno = 0; dno <= pcimaxdno; dno++){
3739ef1f84bSDavid du Colombier 		maxfno = 0;
3749ef1f84bSDavid du Colombier 		for(fno = 0; fno <= maxfno; fno++){
3759ef1f84bSDavid du Colombier 			/*
3769ef1f84bSDavid du Colombier 			 * For this possible device, form the
3779ef1f84bSDavid du Colombier 			 * bus+device+function triplet needed to address it
3789ef1f84bSDavid du Colombier 			 * and try to read the vendor and device ID.
3799ef1f84bSDavid du Colombier 			 * If successful, allocate a device struct and
3809ef1f84bSDavid du Colombier 			 * start to fill it in with some useful information
3819ef1f84bSDavid du Colombier 			 * from the device's configuration space.
3829ef1f84bSDavid du Colombier 			 */
3839ef1f84bSDavid du Colombier 			tbdf = MKBUS(BusPCI, bno, dno, fno);
3849ef1f84bSDavid du Colombier 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
3859ef1f84bSDavid du Colombier 			if(l == 0xFFFFFFFF || l == 0)
3869ef1f84bSDavid du Colombier 				continue;
3879ef1f84bSDavid du Colombier 			p = malloc(sizeof(*p));
388277b6efdSDavid du Colombier 			if(p == nil)
389277b6efdSDavid du Colombier 				panic("pcilscan: no memory");
3909ef1f84bSDavid du Colombier 			p->tbdf = tbdf;
3919ef1f84bSDavid du Colombier 			p->vid = l;
3929ef1f84bSDavid du Colombier 			p->did = l>>16;
3939ef1f84bSDavid du Colombier 
3949ef1f84bSDavid du Colombier 			if(pcilist != nil)
3959ef1f84bSDavid du Colombier 				pcitail->list = p;
3969ef1f84bSDavid du Colombier 			else
3979ef1f84bSDavid du Colombier 				pcilist = p;
3989ef1f84bSDavid du Colombier 			pcitail = p;
3999ef1f84bSDavid du Colombier 
4009ef1f84bSDavid du Colombier 			p->pcr = pcicfgr16(p, PciPCR);
4019ef1f84bSDavid du Colombier 			p->rid = pcicfgr8(p, PciRID);
4029ef1f84bSDavid du Colombier 			p->ccrp = pcicfgr8(p, PciCCRp);
4039ef1f84bSDavid du Colombier 			p->ccru = pcicfgr8(p, PciCCRu);
4049ef1f84bSDavid du Colombier 			p->ccrb = pcicfgr8(p, PciCCRb);
4059ef1f84bSDavid du Colombier 			p->cls = pcicfgr8(p, PciCLS);
4069ef1f84bSDavid du Colombier 			p->ltr = pcicfgr8(p, PciLTR);
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier 			p->intl = pcicfgr8(p, PciINTL);
4099ef1f84bSDavid du Colombier 
4109ef1f84bSDavid du Colombier 			/*
4119ef1f84bSDavid du Colombier 			 * If the device is a multi-function device adjust the
4129ef1f84bSDavid du Colombier 			 * loop count so all possible functions are checked.
4139ef1f84bSDavid du Colombier 			 */
4149ef1f84bSDavid du Colombier 			hdt = pcicfgr8(p, PciHDT);
4159ef1f84bSDavid du Colombier 			if(hdt & 0x80)
4169ef1f84bSDavid du Colombier 				maxfno = MaxFNO;
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 			/*
4199ef1f84bSDavid du Colombier 			 * If appropriate, read the base address registers
4209ef1f84bSDavid du Colombier 			 * and work out the sizes.
4219ef1f84bSDavid du Colombier 			 */
4229ef1f84bSDavid du Colombier 			switch(p->ccrb) {
423277b6efdSDavid du Colombier 			case 0x03:		/* display controller */
424277b6efdSDavid du Colombier 				pcivga = 1;
425277b6efdSDavid du Colombier 				/* fall through */
4269ef1f84bSDavid du Colombier 			case 0x01:		/* mass storage controller */
4279ef1f84bSDavid du Colombier 			case 0x02:		/* network controller */
4289ef1f84bSDavid du Colombier 			case 0x04:		/* multimedia device */
4299ef1f84bSDavid du Colombier 			case 0x07:		/* simple comm. controllers */
4309ef1f84bSDavid du Colombier 			case 0x08:		/* base system peripherals */
4319ef1f84bSDavid du Colombier 			case 0x09:		/* input devices */
4329ef1f84bSDavid du Colombier 			case 0x0A:		/* docking stations */
4339ef1f84bSDavid du Colombier 			case 0x0B:		/* processors */
4349ef1f84bSDavid du Colombier 			case 0x0C:		/* serial bus controllers */
4359ef1f84bSDavid du Colombier 				if((hdt & 0x7F) != 0)
4369ef1f84bSDavid du Colombier 					break;
4379ef1f84bSDavid du Colombier 				rno = PciBAR0 - 4;
4389ef1f84bSDavid du Colombier 				for(i = 0; i < nelem(p->mem); i++) {
4399ef1f84bSDavid du Colombier 					rno += 4;
4409ef1f84bSDavid du Colombier 					p->mem[i].bar = pcicfgr32(p, rno);
4419ef1f84bSDavid du Colombier 					p->mem[i].size = pcibarsize(p, rno);
4429ef1f84bSDavid du Colombier 				}
4439ef1f84bSDavid du Colombier 				break;
4449ef1f84bSDavid du Colombier 
4459ef1f84bSDavid du Colombier 			case 0x00:
4469ef1f84bSDavid du Colombier 			case 0x05:		/* memory controller */
4479ef1f84bSDavid du Colombier 			case 0x06:		/* bridge device */
4489ef1f84bSDavid du Colombier 			default:
4499ef1f84bSDavid du Colombier 				break;
4509ef1f84bSDavid du Colombier 			}
4519ef1f84bSDavid du Colombier 
4529ef1f84bSDavid du Colombier 			if(head != nil)
4539ef1f84bSDavid du Colombier 				tail->link = p;
4549ef1f84bSDavid du Colombier 			else
4559ef1f84bSDavid du Colombier 				head = p;
4569ef1f84bSDavid du Colombier 			tail = p;
4579ef1f84bSDavid du Colombier 		}
4589ef1f84bSDavid du Colombier 	}
4599ef1f84bSDavid du Colombier 
4609ef1f84bSDavid du Colombier 	*list = head;
4619ef1f84bSDavid du Colombier 	for(p = head; p != nil; p = p->link){
4629ef1f84bSDavid du Colombier 		/*
4639ef1f84bSDavid du Colombier 		 * Find PCI-PCI bridges and recursively descend the tree.
4649ef1f84bSDavid du Colombier 		 */
4659ef1f84bSDavid du Colombier 		if(p->ccrb != 0x06 || p->ccru != 0x04)
4669ef1f84bSDavid du Colombier 			continue;
4679ef1f84bSDavid du Colombier 
4689ef1f84bSDavid du Colombier 		/*
4699ef1f84bSDavid du Colombier 		 * If the secondary or subordinate bus number is not
4709ef1f84bSDavid du Colombier 		 * initialised try to do what the PCI BIOS should have
4719ef1f84bSDavid du Colombier 		 * done and fill in the numbers as the tree is descended.
4729ef1f84bSDavid du Colombier 		 * On the way down the subordinate bus number is set to
4739ef1f84bSDavid du Colombier 		 * the maximum as it's not known how many buses are behind
4749ef1f84bSDavid du Colombier 		 * this one; the final value is set on the way back up.
4759ef1f84bSDavid du Colombier 		 */
4769ef1f84bSDavid du Colombier 		sbn = pcicfgr8(p, PciSBN);
4779ef1f84bSDavid du Colombier 		ubn = pcicfgr8(p, PciUBN);
4789ef1f84bSDavid du Colombier 
4799ef1f84bSDavid du Colombier 		if(sbn == 0 || ubn == 0 || nobios) {
4809ef1f84bSDavid du Colombier 			sbn = maxubn+1;
4819ef1f84bSDavid du Colombier 			/*
4829ef1f84bSDavid du Colombier 			 * Make sure memory, I/O and master enables are
4839ef1f84bSDavid du Colombier 			 * off, set the primary, secondary and subordinate
4849ef1f84bSDavid du Colombier 			 * bus numbers and clear the secondary status before
4859ef1f84bSDavid du Colombier 			 * attempting to scan the secondary bus.
4869ef1f84bSDavid du Colombier 			 *
4879ef1f84bSDavid du Colombier 			 * Initialisation of the bridge should be done here.
4889ef1f84bSDavid du Colombier 			 */
4899ef1f84bSDavid du Colombier 			pcicfgw32(p, PciPCR, 0xFFFF0000);
4909ef1f84bSDavid du Colombier 			l = (MaxUBN<<16)|(sbn<<8)|bno;
4919ef1f84bSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
4929ef1f84bSDavid du Colombier 			pcicfgw16(p, PciSPSR, 0xFFFF);
4939ef1f84bSDavid du Colombier 			maxubn = pcilscan(sbn, &p->bridge);
4949ef1f84bSDavid du Colombier 			l = (maxubn<<16)|(sbn<<8)|bno;
4959ef1f84bSDavid du Colombier 
4969ef1f84bSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
4979ef1f84bSDavid du Colombier 		}
4989ef1f84bSDavid du Colombier 		else {
4999ef1f84bSDavid du Colombier 			/*
5009ef1f84bSDavid du Colombier 			 * You can't go back.
5019ef1f84bSDavid du Colombier 			 * This shouldn't be possible, but the
5029ef1f84bSDavid du Colombier 			 * Iwill DK8-HTX seems to have subordinate
5039ef1f84bSDavid du Colombier 			 * bus numbers which get smaller on the
5049ef1f84bSDavid du Colombier 			 * way down. Need to look more closely at
5059ef1f84bSDavid du Colombier 			 * this.
5069ef1f84bSDavid du Colombier 			 */
5079ef1f84bSDavid du Colombier 			if(ubn > maxubn)
5089ef1f84bSDavid du Colombier 				maxubn = ubn;
5099ef1f84bSDavid du Colombier 			pcilscan(sbn, &p->bridge);
5109ef1f84bSDavid du Colombier 		}
5119ef1f84bSDavid du Colombier 	}
5129ef1f84bSDavid du Colombier 
5139ef1f84bSDavid du Colombier 	return maxubn;
5149ef1f84bSDavid du Colombier }
5159ef1f84bSDavid du Colombier 
5169ef1f84bSDavid du Colombier int
pciscan(int bno,Pcidev ** list)5179ef1f84bSDavid du Colombier pciscan(int bno, Pcidev **list)
5189ef1f84bSDavid du Colombier {
5199ef1f84bSDavid du Colombier 	int ubn;
5209ef1f84bSDavid du Colombier 
5219ef1f84bSDavid du Colombier 	lock(&pcicfginitlock);
5229ef1f84bSDavid du Colombier 	ubn = pcilscan(bno, list);
5239ef1f84bSDavid du Colombier 	unlock(&pcicfginitlock);
5249ef1f84bSDavid du Colombier 	return ubn;
5259ef1f84bSDavid du Colombier }
5269ef1f84bSDavid du Colombier 
5279ef1f84bSDavid du Colombier static uchar
pIIxget(Pcidev * router,uchar link)5289ef1f84bSDavid du Colombier pIIxget(Pcidev *router, uchar link)
5299ef1f84bSDavid du Colombier {
5309ef1f84bSDavid du Colombier 	uchar pirq;
5319ef1f84bSDavid du Colombier 
5329ef1f84bSDavid du Colombier 	/* link should be 0x60, 0x61, 0x62, 0x63 */
5339ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, link);
5349ef1f84bSDavid du Colombier 	return (pirq < 16)? pirq: 0;
5359ef1f84bSDavid du Colombier }
5369ef1f84bSDavid du Colombier 
5379ef1f84bSDavid du Colombier static void
pIIxset(Pcidev * router,uchar link,uchar irq)5389ef1f84bSDavid du Colombier pIIxset(Pcidev *router, uchar link, uchar irq)
5399ef1f84bSDavid du Colombier {
5409ef1f84bSDavid du Colombier 	pcicfgw8(router, link, irq);
5419ef1f84bSDavid du Colombier }
5429ef1f84bSDavid du Colombier 
5439ef1f84bSDavid du Colombier static uchar
viaget(Pcidev * router,uchar link)5449ef1f84bSDavid du Colombier viaget(Pcidev *router, uchar link)
5459ef1f84bSDavid du Colombier {
5469ef1f84bSDavid du Colombier 	uchar pirq;
5479ef1f84bSDavid du Colombier 
5489ef1f84bSDavid du Colombier 	/* link should be 1, 2, 3, 5 */
5499ef1f84bSDavid du Colombier 	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier 	return (link & 1)? (pirq >> 4): (pirq & 15);
5529ef1f84bSDavid du Colombier }
5539ef1f84bSDavid du Colombier 
5549ef1f84bSDavid du Colombier static void
viaset(Pcidev * router,uchar link,uchar irq)5559ef1f84bSDavid du Colombier viaset(Pcidev *router, uchar link, uchar irq)
5569ef1f84bSDavid du Colombier {
5579ef1f84bSDavid du Colombier 	uchar pirq;
5589ef1f84bSDavid du Colombier 
5599ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0x55 + (link >> 1));
5609ef1f84bSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
5619ef1f84bSDavid du Colombier 	pirq |= (link & 1)? (irq << 4): (irq & 15);
5629ef1f84bSDavid du Colombier 	pcicfgw8(router, 0x55 + (link>>1), pirq);
5639ef1f84bSDavid du Colombier }
5649ef1f84bSDavid du Colombier 
5659ef1f84bSDavid du Colombier static uchar
optiget(Pcidev * router,uchar link)5669ef1f84bSDavid du Colombier optiget(Pcidev *router, uchar link)
5679ef1f84bSDavid du Colombier {
5689ef1f84bSDavid du Colombier 	uchar pirq = 0;
5699ef1f84bSDavid du Colombier 
5709ef1f84bSDavid du Colombier 	/* link should be 0x02, 0x12, 0x22, 0x32 */
5719ef1f84bSDavid du Colombier 	if ((link & 0xcf) == 0x02)
5729ef1f84bSDavid du Colombier 		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5739ef1f84bSDavid du Colombier 	return (link & 0x10)? (pirq >> 4): (pirq & 15);
5749ef1f84bSDavid du Colombier }
5759ef1f84bSDavid du Colombier 
5769ef1f84bSDavid du Colombier static void
optiset(Pcidev * router,uchar link,uchar irq)5779ef1f84bSDavid du Colombier optiset(Pcidev *router, uchar link, uchar irq)
5789ef1f84bSDavid du Colombier {
5799ef1f84bSDavid du Colombier 	uchar pirq;
5809ef1f84bSDavid du Colombier 
5819ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5829ef1f84bSDavid du Colombier 	pirq &= (link & 0x10)? 0x0f : 0xf0;
5839ef1f84bSDavid du Colombier 	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
5849ef1f84bSDavid du Colombier 	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
5859ef1f84bSDavid du Colombier }
5869ef1f84bSDavid du Colombier 
5879ef1f84bSDavid du Colombier static uchar
aliget(Pcidev * router,uchar link)5889ef1f84bSDavid du Colombier aliget(Pcidev *router, uchar link)
5899ef1f84bSDavid du Colombier {
5909ef1f84bSDavid du Colombier 	/* No, you're not dreaming */
5919ef1f84bSDavid du Colombier 	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
5929ef1f84bSDavid du Colombier 	uchar pirq;
5939ef1f84bSDavid du Colombier 
5949ef1f84bSDavid du Colombier 	/* link should be 0x01..0x08 */
5959ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
5969ef1f84bSDavid du Colombier 	return (link & 1)? map[pirq&15]: map[pirq>>4];
5979ef1f84bSDavid du Colombier }
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier static void
aliset(Pcidev * router,uchar link,uchar irq)6009ef1f84bSDavid du Colombier aliset(Pcidev *router, uchar link, uchar irq)
6019ef1f84bSDavid du Colombier {
6029ef1f84bSDavid du Colombier 	/* Inverse of map in aliget */
6039ef1f84bSDavid du Colombier 	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
6049ef1f84bSDavid du Colombier 	uchar pirq;
6059ef1f84bSDavid du Colombier 
6069ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
6079ef1f84bSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
6089ef1f84bSDavid du Colombier 	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
6099ef1f84bSDavid du Colombier 	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
6109ef1f84bSDavid du Colombier }
6119ef1f84bSDavid du Colombier 
6129ef1f84bSDavid du Colombier static uchar
cyrixget(Pcidev * router,uchar link)6139ef1f84bSDavid du Colombier cyrixget(Pcidev *router, uchar link)
6149ef1f84bSDavid du Colombier {
6159ef1f84bSDavid du Colombier 	uchar pirq;
6169ef1f84bSDavid du Colombier 
6179ef1f84bSDavid du Colombier 	/* link should be 1, 2, 3, 4 */
6189ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
6199ef1f84bSDavid du Colombier 	return ((link & 1)? pirq >> 4: pirq & 15);
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier 
6229ef1f84bSDavid du Colombier static void
cyrixset(Pcidev * router,uchar link,uchar irq)6239ef1f84bSDavid du Colombier cyrixset(Pcidev *router, uchar link, uchar irq)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier 	uchar pirq;
6269ef1f84bSDavid du Colombier 
6279ef1f84bSDavid du Colombier 	pirq = pcicfgr8(router, 0x5c + (link>>1));
6289ef1f84bSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
6299ef1f84bSDavid du Colombier 	pirq |= (link & 1)? (irq << 4): (irq & 15);
6309ef1f84bSDavid du Colombier 	pcicfgw8(router, 0x5c + (link>>1), pirq);
6319ef1f84bSDavid du Colombier }
6329ef1f84bSDavid du Colombier 
6339ef1f84bSDavid du Colombier typedef struct Bridge Bridge;
6349ef1f84bSDavid du Colombier struct Bridge
6359ef1f84bSDavid du Colombier {
6369ef1f84bSDavid du Colombier 	ushort	vid;
6379ef1f84bSDavid du Colombier 	ushort	did;
6389ef1f84bSDavid du Colombier 	uchar	(*get)(Pcidev *, uchar);
6399ef1f84bSDavid du Colombier 	void	(*set)(Pcidev *, uchar, uchar);
6409ef1f84bSDavid du Colombier };
6419ef1f84bSDavid du Colombier 
6429ef1f84bSDavid du Colombier static Bridge southbridges[] = {
6439ef1f84bSDavid du Colombier 	{ 0x8086, 0x122e, pIIxget, pIIxset },	/* Intel 82371FB */
6449ef1f84bSDavid du Colombier 	{ 0x8086, 0x1234, pIIxget, pIIxset },	/* Intel 82371MX */
6459ef1f84bSDavid du Colombier 	{ 0x8086, 0x7000, pIIxget, pIIxset },	/* Intel 82371SB */
6469ef1f84bSDavid du Colombier 	{ 0x8086, 0x7110, pIIxget, pIIxset },	/* Intel 82371AB */
6479ef1f84bSDavid du Colombier 	{ 0x8086, 0x7198, pIIxget, pIIxset },	/* Intel 82443MX (fn 1) */
6489ef1f84bSDavid du Colombier 	{ 0x8086, 0x2410, pIIxget, pIIxset },	/* Intel 82801AA */
6499ef1f84bSDavid du Colombier 	{ 0x8086, 0x2420, pIIxget, pIIxset },	/* Intel 82801AB */
6509ef1f84bSDavid du Colombier 	{ 0x8086, 0x2440, pIIxget, pIIxset },	/* Intel 82801BA */
6519ef1f84bSDavid du Colombier 	{ 0x8086, 0x2448, pIIxget, pIIxset },	/* Intel 82801BAM/CAM/DBM */
6529ef1f84bSDavid du Colombier 	{ 0x8086, 0x244c, pIIxget, pIIxset },	/* Intel 82801BAM */
6539ef1f84bSDavid du Colombier 	{ 0x8086, 0x244e, pIIxget, pIIxset },	/* Intel 82801 */
6549ef1f84bSDavid du Colombier 	{ 0x8086, 0x2480, pIIxget, pIIxset },	/* Intel 82801CA */
6559ef1f84bSDavid du Colombier 	{ 0x8086, 0x248c, pIIxget, pIIxset },	/* Intel 82801CAM */
6569ef1f84bSDavid du Colombier 	{ 0x8086, 0x24c0, pIIxget, pIIxset },	/* Intel 82801DBL */
6579ef1f84bSDavid du Colombier 	{ 0x8086, 0x24cc, pIIxget, pIIxset },	/* Intel 82801DBM */
6589ef1f84bSDavid du Colombier 	{ 0x8086, 0x24d0, pIIxget, pIIxset },	/* Intel 82801EB */
6599ef1f84bSDavid du Colombier 	{ 0x8086, 0x25a1, pIIxget, pIIxset },	/* Intel 6300ESB */
6609ef1f84bSDavid du Colombier 	{ 0x8086, 0x2640, pIIxget, pIIxset },	/* Intel 82801FB */
6619ef1f84bSDavid du Colombier 	{ 0x8086, 0x2641, pIIxget, pIIxset },	/* Intel 82801FBM */
6629ef1f84bSDavid du Colombier 	{ 0x8086, 0x27b8, pIIxget, pIIxset },	/* Intel 82801GB */
6639ef1f84bSDavid du Colombier 	{ 0x8086, 0x27b9, pIIxget, pIIxset },	/* Intel 82801GBM */
6649ef1f84bSDavid du Colombier 	{ 0x8086, 0x27bd, pIIxget, pIIxset },	/* Intel 82801GB/GR */
6659ef1f84bSDavid du Colombier 	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801JIR */
6669ef1f84bSDavid du Colombier 	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801JI */
6679ef1f84bSDavid du Colombier 	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801JI */
6689ef1f84bSDavid du Colombier 	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801JI */
6699ef1f84bSDavid du Colombier 	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801? */
6709ef1f84bSDavid du Colombier 	{ 0x8086, 0x1c02, pIIxget, pIIxset },	/* Intel 6 Series/C200 */
671277b6efdSDavid du Colombier 	{ 0x8086, 0x1c44, pIIxget, pIIxset },	/* Intel 6 Series/Z68 Express */
6729ef1f84bSDavid du Colombier 	{ 0x8086, 0x1e53, pIIxget, pIIxset },	/* Intel 7 Series/C216 */
6739ef1f84bSDavid du Colombier 	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
6749ef1f84bSDavid du Colombier 	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
6759ef1f84bSDavid du Colombier 	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
6769ef1f84bSDavid du Colombier 	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
6779ef1f84bSDavid du Colombier 	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
6789ef1f84bSDavid du Colombier 	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
6799ef1f84bSDavid du Colombier 	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
6809ef1f84bSDavid du Colombier 	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
6819ef1f84bSDavid du Colombier 	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
6829ef1f84bSDavid du Colombier 
6839ef1f84bSDavid du Colombier 	{ 0x1022, 0x746B, nil, nil },		/* AMD 8111 */
6849ef1f84bSDavid du Colombier 	{ 0x10DE, 0x00D1, nil, nil },		/* NVIDIA nForce 3 */
6859ef1f84bSDavid du Colombier 	{ 0x10DE, 0x00E0, nil, nil },		/* NVIDIA nForce 3 250 Series */
6869ef1f84bSDavid du Colombier 	{ 0x10DE, 0x00E1, nil, nil },		/* NVIDIA nForce 3 250 Series */
6879ef1f84bSDavid du Colombier 	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
6889ef1f84bSDavid du Colombier 	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
6899ef1f84bSDavid du Colombier 	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
6909ef1f84bSDavid du Colombier };
6919ef1f84bSDavid du Colombier 
6929ef1f84bSDavid du Colombier typedef struct Slot Slot;
6939ef1f84bSDavid du Colombier struct Slot {
6949ef1f84bSDavid du Colombier 	uchar	bus;			// Pci bus number
6959ef1f84bSDavid du Colombier 	uchar	dev;			// Pci device number
6969ef1f84bSDavid du Colombier 	uchar	maps[12];		// Avoid structs!  Link and mask.
6979ef1f84bSDavid du Colombier 	uchar	slot;			// Add-in/built-in slot
6989ef1f84bSDavid du Colombier 	uchar	reserved;
6999ef1f84bSDavid du Colombier };
7009ef1f84bSDavid du Colombier 
7019ef1f84bSDavid du Colombier typedef struct Router Router;
7029ef1f84bSDavid du Colombier struct Router {
7039ef1f84bSDavid du Colombier 	uchar	signature[4];		// Routing table signature
7049ef1f84bSDavid du Colombier 	uchar	version[2];		// Version number
7059ef1f84bSDavid du Colombier 	uchar	size[2];		// Total table size
7069ef1f84bSDavid du Colombier 	uchar	bus;			// Interrupt router bus number
7079ef1f84bSDavid du Colombier 	uchar	devfn;			// Router's devfunc
7089ef1f84bSDavid du Colombier 	uchar	pciirqs[2];		// Exclusive PCI irqs
7099ef1f84bSDavid du Colombier 	uchar	compat[4];		// Compatible PCI interrupt router
7109ef1f84bSDavid du Colombier 	uchar	miniport[4];		// Miniport data
7119ef1f84bSDavid du Colombier 	uchar	reserved[11];
7129ef1f84bSDavid du Colombier 	uchar	checksum;
7139ef1f84bSDavid du Colombier };
7149ef1f84bSDavid du Colombier 
7159ef1f84bSDavid du Colombier static ushort pciirqs;			// Exclusive PCI irqs
7169ef1f84bSDavid du Colombier static Bridge *southbridge;		// Which southbridge to use.
7179ef1f84bSDavid du Colombier 
7189ef1f84bSDavid du Colombier static void
pcirouting(void)7199ef1f84bSDavid du Colombier pcirouting(void)
7209ef1f84bSDavid du Colombier {
7219ef1f84bSDavid du Colombier 	Slot *e;
7229ef1f84bSDavid du Colombier 	Router *r;
7239ef1f84bSDavid du Colombier 	int size, i, fn, tbdf;
7249ef1f84bSDavid du Colombier 	Pcidev *sbpci, *pci;
7259ef1f84bSDavid du Colombier 	uchar *p, pin, irq, link, *map;
7269ef1f84bSDavid du Colombier 
7279ef1f84bSDavid du Colombier 	// Search for PCI interrupt routing table in BIOS
7289ef1f84bSDavid du Colombier 	for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
7299ef1f84bSDavid du Colombier 		if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
7309ef1f84bSDavid du Colombier 			break;
7319ef1f84bSDavid du Colombier 
732277b6efdSDavid du Colombier 	if(p >= (uchar *)KADDR(0xfffff)) {
733277b6efdSDavid du Colombier 		// print("no PCI intr routing table found\n");
7349ef1f84bSDavid du Colombier 		return;
735277b6efdSDavid du Colombier 	}
7369ef1f84bSDavid du Colombier 
7379ef1f84bSDavid du Colombier 	r = (Router *)p;
7389ef1f84bSDavid du Colombier 
739277b6efdSDavid du Colombier 	if (0)
7409ef1f84bSDavid du Colombier 		print("PCI interrupt routing table version %d.%d at %#p\n",
7419ef1f84bSDavid du Colombier 			r->version[0], r->version[1], r);
7429ef1f84bSDavid du Colombier 
7439ef1f84bSDavid du Colombier 	tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8);
7449ef1f84bSDavid du Colombier 	sbpci = pcimatchtbdf(tbdf);
7459ef1f84bSDavid du Colombier 	if(sbpci == nil) {
7469ef1f84bSDavid du Colombier 		print("pcirouting: Cannot find south bridge %T\n", tbdf);
7479ef1f84bSDavid du Colombier 		return;
7489ef1f84bSDavid du Colombier 	}
7499ef1f84bSDavid du Colombier 
7509ef1f84bSDavid du Colombier 	for(i = 0; i != nelem(southbridges); i++)
7519ef1f84bSDavid du Colombier 		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
7529ef1f84bSDavid du Colombier 			break;
7539ef1f84bSDavid du Colombier 
7549ef1f84bSDavid du Colombier 	if(i == nelem(southbridges)) {
7559ef1f84bSDavid du Colombier 		print("pcirouting: ignoring south bridge %T %.4ux/%.4ux\n", tbdf, sbpci->vid, sbpci->did);
7569ef1f84bSDavid du Colombier 		return;
7579ef1f84bSDavid du Colombier 	}
7589ef1f84bSDavid du Colombier 	southbridge = &southbridges[i];
7599ef1f84bSDavid du Colombier 	if(southbridge->get == nil || southbridge->set == nil)
7609ef1f84bSDavid du Colombier 		return;
7619ef1f84bSDavid du Colombier 
7629ef1f84bSDavid du Colombier 	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
7639ef1f84bSDavid du Colombier 
7649ef1f84bSDavid du Colombier 	size = (r->size[1] << 8)|r->size[0];
7659ef1f84bSDavid du Colombier 	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
7669ef1f84bSDavid du Colombier 		// print("%.2ux/%.2ux %.2ux: ", e->bus, e->dev, e->slot);
7679ef1f84bSDavid du Colombier 		// for (i = 0; i != 4; i++) {
7689ef1f84bSDavid du Colombier 		// 	uchar *m = &e->maps[i * 3];
7699ef1f84bSDavid du Colombier 		// 	print("[%d] %.2ux %.4ux ",
7709ef1f84bSDavid du Colombier 		// 		i, m[0], (m[2] << 8)|m[1]);
7719ef1f84bSDavid du Colombier 		// }
7729ef1f84bSDavid du Colombier 		// print("\n");
7739ef1f84bSDavid du Colombier 
7749ef1f84bSDavid du Colombier 		for(fn = 0; fn != 8; fn++) {
7759ef1f84bSDavid du Colombier 			tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
7769ef1f84bSDavid du Colombier 			pci = pcimatchtbdf(tbdf);
7779ef1f84bSDavid du Colombier 			if(pci == nil)
7789ef1f84bSDavid du Colombier 				continue;
7799ef1f84bSDavid du Colombier 			pin = pcicfgr8(pci, PciINTP);
7809ef1f84bSDavid du Colombier 			if(pin == 0 || pin == 0xff)
7819ef1f84bSDavid du Colombier 				continue;
7829ef1f84bSDavid du Colombier 
7839ef1f84bSDavid du Colombier 			map = &e->maps[(pin - 1) * 3];
7849ef1f84bSDavid du Colombier 			link = map[0];
7859ef1f84bSDavid du Colombier 			irq = southbridge->get(sbpci, link);
7869ef1f84bSDavid du Colombier 			if(irq == 0 || irq == pci->intl)
7879ef1f84bSDavid du Colombier 				continue;
7889ef1f84bSDavid du Colombier 			if(pci->intl != 0 && pci->intl != 0xFF) {
7899ef1f84bSDavid du Colombier 				print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
7909ef1f84bSDavid du Colombier 					  tbdf, pin, link, irq, pci->intl);
7919ef1f84bSDavid du Colombier 				southbridge->set(sbpci, link, pci->intl);
7929ef1f84bSDavid du Colombier 				continue;
7939ef1f84bSDavid du Colombier 			}
7949ef1f84bSDavid du Colombier 			print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
7959ef1f84bSDavid du Colombier 			pcicfgw8(pci, PciINTL, irq);
7969ef1f84bSDavid du Colombier 			pci->intl = irq;
7979ef1f84bSDavid du Colombier 		}
7989ef1f84bSDavid du Colombier 	}
7999ef1f84bSDavid du Colombier }
8009ef1f84bSDavid du Colombier 
8019ef1f84bSDavid du Colombier static void pcireservemem(void);
8029ef1f84bSDavid du Colombier 
8039ef1f84bSDavid du Colombier static void
pcicfginit(void)8049ef1f84bSDavid du Colombier pcicfginit(void)
8059ef1f84bSDavid du Colombier {
8069ef1f84bSDavid du Colombier 	char *p;
8079ef1f84bSDavid du Colombier 	Pcidev **list;
8089ef1f84bSDavid du Colombier 	ulong mema, ioa;
8099ef1f84bSDavid du Colombier 	int bno, n;
8109ef1f84bSDavid du Colombier 
8119ef1f84bSDavid du Colombier 	lock(&pcicfginitlock);
8129ef1f84bSDavid du Colombier 	if(pcicfgmode != -1)
8139ef1f84bSDavid du Colombier 		goto out;
8149ef1f84bSDavid du Colombier 
8159ef1f84bSDavid du Colombier 	if(getconf("*nobios"))
8169ef1f84bSDavid du Colombier 		nobios = 1;
8179ef1f84bSDavid du Colombier 	if(getconf("*nopcirouting"))
8189ef1f84bSDavid du Colombier 		nopcirouting = 1;
8199ef1f84bSDavid du Colombier 
8209ef1f84bSDavid du Colombier 	/*
8219ef1f84bSDavid du Colombier 	 * Assume Configuration Mechanism One. Method Two was deprecated
8229ef1f84bSDavid du Colombier 	 * a long time ago and was only for backwards compaibility with the
8239ef1f84bSDavid du Colombier 	 * Intel Saturn and Mercury chip sets. Thank you, QEMU.
8249ef1f84bSDavid du Colombier 	 */
8259ef1f84bSDavid du Colombier 	pcicfgmode = 1;
8269ef1f84bSDavid du Colombier 	pcimaxdno = 31;
8279ef1f84bSDavid du Colombier 
8289ef1f84bSDavid du Colombier 	if(pcicfgmode < 0)
8299ef1f84bSDavid du Colombier 		goto out;
8309ef1f84bSDavid du Colombier 
8319ef1f84bSDavid du Colombier 	fmtinstall('T', tbdffmt);
8329ef1f84bSDavid du Colombier 
8339ef1f84bSDavid du Colombier 	if(p = getconf("*pcimaxbno")){
8349ef1f84bSDavid du Colombier 		n = strtoul(p, 0, 0);
8359ef1f84bSDavid du Colombier 		if(n < pcimaxbno)
8369ef1f84bSDavid du Colombier 			pcimaxbno = n;
8379ef1f84bSDavid du Colombier 	}
8389ef1f84bSDavid du Colombier 	if(p = getconf("*pcimaxdno")){
8399ef1f84bSDavid du Colombier 		n = strtoul(p, 0, 0);
8409ef1f84bSDavid du Colombier 		if(n < pcimaxdno)
8419ef1f84bSDavid du Colombier 			pcimaxdno = n;
8429ef1f84bSDavid du Colombier 	}
8439ef1f84bSDavid du Colombier 
8449ef1f84bSDavid du Colombier 	list = &pciroot;
8459ef1f84bSDavid du Colombier 	for(bno = 0; bno <= pcimaxbno; bno++) {
8469ef1f84bSDavid du Colombier 		int sbno = bno;
8479ef1f84bSDavid du Colombier 		bno = pcilscan(bno, list);
8489ef1f84bSDavid du Colombier 
8499ef1f84bSDavid du Colombier 		while(*list)
8509ef1f84bSDavid du Colombier 			list = &(*list)->link;
8519ef1f84bSDavid du Colombier 
8529ef1f84bSDavid du Colombier 		if (sbno == 0) {
8539ef1f84bSDavid du Colombier 			Pcidev *pci;
8549ef1f84bSDavid du Colombier 
8559ef1f84bSDavid du Colombier 			/*
8569ef1f84bSDavid du Colombier 			  * If we have found a PCI-to-Cardbus bridge, make sure
8579ef1f84bSDavid du Colombier 			  * it has no valid mappings anymore.
8589ef1f84bSDavid du Colombier 			  */
8599ef1f84bSDavid du Colombier 			pci = pciroot;
8609ef1f84bSDavid du Colombier 			while (pci) {
8619ef1f84bSDavid du Colombier 				if (pci->ccrb == 6 && pci->ccru == 7) {
8629ef1f84bSDavid du Colombier 					ushort bcr;
8639ef1f84bSDavid du Colombier 
8649ef1f84bSDavid du Colombier 					/* reset the cardbus */
8659ef1f84bSDavid du Colombier 					bcr = pcicfgr16(pci, PciBCR);
8669ef1f84bSDavid du Colombier 					pcicfgw16(pci, PciBCR, 0x40 | bcr);
8679ef1f84bSDavid du Colombier 					delay(50);
8689ef1f84bSDavid du Colombier 				}
8699ef1f84bSDavid du Colombier 				pci = pci->link;
8709ef1f84bSDavid du Colombier 			}
8719ef1f84bSDavid du Colombier 		}
8729ef1f84bSDavid du Colombier 	}
8739ef1f84bSDavid du Colombier 
8749ef1f84bSDavid du Colombier 	if(pciroot == nil)
8759ef1f84bSDavid du Colombier 		goto out;
8769ef1f84bSDavid du Colombier 
8779ef1f84bSDavid du Colombier 	if(nobios) {
8789ef1f84bSDavid du Colombier 		/*
8799ef1f84bSDavid du Colombier 		 * Work out how big the top bus is
8809ef1f84bSDavid du Colombier 		 */
8819ef1f84bSDavid du Colombier 		mema = 0;
8829ef1f84bSDavid du Colombier 		ioa = 0;
8839ef1f84bSDavid du Colombier 		pcibusmap(pciroot, &mema, &ioa, 0);
8849ef1f84bSDavid du Colombier 
8859ef1f84bSDavid du Colombier 		DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
8869ef1f84bSDavid du Colombier 			mema, pcimask(mema), ioa);
8879ef1f84bSDavid du Colombier 
8889ef1f84bSDavid du Colombier 		/*
8899ef1f84bSDavid du Colombier 		 * Align the windows and map it
8909ef1f84bSDavid du Colombier 		 */
8919ef1f84bSDavid du Colombier 		ioa = 0x1000;
8929ef1f84bSDavid du Colombier 		mema = 0x90000000;
8939ef1f84bSDavid du Colombier 
8949ef1f84bSDavid du Colombier 		pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
8959ef1f84bSDavid du Colombier 
8969ef1f84bSDavid du Colombier 		pcibusmap(pciroot, &mema, &ioa, 1);
8979ef1f84bSDavid du Colombier 		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
8989ef1f84bSDavid du Colombier 
8999ef1f84bSDavid du Colombier 		unlock(&pcicfginitlock);
9009ef1f84bSDavid du Colombier 		return;
9019ef1f84bSDavid du Colombier 	}
9029ef1f84bSDavid du Colombier 
9039ef1f84bSDavid du Colombier 	if (!nopcirouting)
9049ef1f84bSDavid du Colombier 		pcirouting();
9059ef1f84bSDavid du Colombier 
9069ef1f84bSDavid du Colombier out:
9079ef1f84bSDavid du Colombier 	pcireservemem();
9089ef1f84bSDavid du Colombier 	unlock(&pcicfginitlock);
9099ef1f84bSDavid du Colombier 
9109ef1f84bSDavid du Colombier 	if(getconf("*pcihinv"))
9119ef1f84bSDavid du Colombier 		pcihinv(nil);
9129ef1f84bSDavid du Colombier }
9139ef1f84bSDavid du Colombier 
9149ef1f84bSDavid du Colombier static void
pcireservemem(void)9159ef1f84bSDavid du Colombier pcireservemem(void)
9169ef1f84bSDavid du Colombier {
9179ef1f84bSDavid du Colombier 	int i;
9189ef1f84bSDavid du Colombier 	Pcidev *p;
9199ef1f84bSDavid du Colombier 
9209ef1f84bSDavid du Colombier 	/*
9219ef1f84bSDavid du Colombier 	 * mark all the physical address space claimed by pci devices
9229ef1f84bSDavid du Colombier 	 * as in use, so that it's not given out elsewhere.
9239ef1f84bSDavid du Colombier 	 * beware the type and size of 'bar'.
9249ef1f84bSDavid du Colombier 	 */
9259ef1f84bSDavid du Colombier 	for(p=pciroot; p; p=p->list)
9269ef1f84bSDavid du Colombier 		for(i=0; i<nelem(p->mem); i++)
9279ef1f84bSDavid du Colombier 			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
9289ef1f84bSDavid du Colombier 				asmmapinit(p->mem[i].bar&~0x0F, p->mem[i].size, 5);
9299ef1f84bSDavid du Colombier }
9309ef1f84bSDavid du Colombier 
9319ef1f84bSDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)9329ef1f84bSDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
9339ef1f84bSDavid du Colombier {
9349ef1f84bSDavid du Colombier 	int o, type, x;
9359ef1f84bSDavid du Colombier 
9369ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
9379ef1f84bSDavid du Colombier 		pcicfginit();
9389ef1f84bSDavid du Colombier 
9399ef1f84bSDavid du Colombier 	if(BUSBNO(tbdf))
9409ef1f84bSDavid du Colombier 		type = 0x01;
9419ef1f84bSDavid du Colombier 	else
9429ef1f84bSDavid du Colombier 		type = 0x00;
9439ef1f84bSDavid du Colombier 	x = -1;
9449ef1f84bSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
9459ef1f84bSDavid du Colombier 		return x;
9469ef1f84bSDavid du Colombier 
9479ef1f84bSDavid du Colombier 	lock(&pcicfglock);
9489ef1f84bSDavid du Colombier 	switch(pcicfgmode){
9499ef1f84bSDavid du Colombier 
9509ef1f84bSDavid du Colombier 	case 1:
9519ef1f84bSDavid du Colombier 		o = rno & 0x03;
9529ef1f84bSDavid du Colombier 		rno &= ~0x03;
9539ef1f84bSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
9549ef1f84bSDavid du Colombier 		if(read)
9559ef1f84bSDavid du Colombier 			x = inb(PciDATA+o);
9569ef1f84bSDavid du Colombier 		else
9579ef1f84bSDavid du Colombier 			outb(PciDATA+o, data);
9589ef1f84bSDavid du Colombier 		outl(PciADDR, 0);
9599ef1f84bSDavid du Colombier 		break;
9609ef1f84bSDavid du Colombier 
9619ef1f84bSDavid du Colombier 	case 2:
9629ef1f84bSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
9639ef1f84bSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
9649ef1f84bSDavid du Colombier 		if(read)
9659ef1f84bSDavid du Colombier 			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
9669ef1f84bSDavid du Colombier 		else
9679ef1f84bSDavid du Colombier 			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
9689ef1f84bSDavid du Colombier 		outb(PciCSE, 0);
9699ef1f84bSDavid du Colombier 		break;
9709ef1f84bSDavid du Colombier 	}
9719ef1f84bSDavid du Colombier 	unlock(&pcicfglock);
9729ef1f84bSDavid du Colombier 
9739ef1f84bSDavid du Colombier 	return x;
9749ef1f84bSDavid du Colombier }
9759ef1f84bSDavid du Colombier 
9769ef1f84bSDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)9779ef1f84bSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
9789ef1f84bSDavid du Colombier {
9799ef1f84bSDavid du Colombier 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
9809ef1f84bSDavid du Colombier }
9819ef1f84bSDavid du Colombier 
9829ef1f84bSDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)9839ef1f84bSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
9849ef1f84bSDavid du Colombier {
9859ef1f84bSDavid du Colombier 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
9869ef1f84bSDavid du Colombier }
9879ef1f84bSDavid du Colombier 
9889ef1f84bSDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)9899ef1f84bSDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
9909ef1f84bSDavid du Colombier {
9919ef1f84bSDavid du Colombier 	int o, type, x;
9929ef1f84bSDavid du Colombier 
9939ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
9949ef1f84bSDavid du Colombier 		pcicfginit();
9959ef1f84bSDavid du Colombier 
9969ef1f84bSDavid du Colombier 	if(BUSBNO(tbdf))
9979ef1f84bSDavid du Colombier 		type = 0x01;
9989ef1f84bSDavid du Colombier 	else
9999ef1f84bSDavid du Colombier 		type = 0x00;
10009ef1f84bSDavid du Colombier 	x = -1;
10019ef1f84bSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
10029ef1f84bSDavid du Colombier 		return x;
10039ef1f84bSDavid du Colombier 
10049ef1f84bSDavid du Colombier 	lock(&pcicfglock);
10059ef1f84bSDavid du Colombier 	switch(pcicfgmode){
10069ef1f84bSDavid du Colombier 
10079ef1f84bSDavid du Colombier 	case 1:
10089ef1f84bSDavid du Colombier 		o = rno & 0x02;
10099ef1f84bSDavid du Colombier 		rno &= ~0x03;
10109ef1f84bSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
10119ef1f84bSDavid du Colombier 		if(read)
10129ef1f84bSDavid du Colombier 			x = ins(PciDATA+o);
10139ef1f84bSDavid du Colombier 		else
10149ef1f84bSDavid du Colombier 			outs(PciDATA+o, data);
10159ef1f84bSDavid du Colombier 		outl(PciADDR, 0);
10169ef1f84bSDavid du Colombier 		break;
10179ef1f84bSDavid du Colombier 
10189ef1f84bSDavid du Colombier 	case 2:
10199ef1f84bSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
10209ef1f84bSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
10219ef1f84bSDavid du Colombier 		if(read)
10229ef1f84bSDavid du Colombier 			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
10239ef1f84bSDavid du Colombier 		else
10249ef1f84bSDavid du Colombier 			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
10259ef1f84bSDavid du Colombier 		outb(PciCSE, 0);
10269ef1f84bSDavid du Colombier 		break;
10279ef1f84bSDavid du Colombier 	}
10289ef1f84bSDavid du Colombier 	unlock(&pcicfglock);
10299ef1f84bSDavid du Colombier 
10309ef1f84bSDavid du Colombier 	return x;
10319ef1f84bSDavid du Colombier }
10329ef1f84bSDavid du Colombier 
10339ef1f84bSDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)10349ef1f84bSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
10359ef1f84bSDavid du Colombier {
10369ef1f84bSDavid du Colombier 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
10379ef1f84bSDavid du Colombier }
10389ef1f84bSDavid du Colombier 
10399ef1f84bSDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)10409ef1f84bSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
10419ef1f84bSDavid du Colombier {
10429ef1f84bSDavid du Colombier 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
10439ef1f84bSDavid du Colombier }
10449ef1f84bSDavid du Colombier 
10459ef1f84bSDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)10469ef1f84bSDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
10479ef1f84bSDavid du Colombier {
10489ef1f84bSDavid du Colombier 	int type, x;
10499ef1f84bSDavid du Colombier 
10509ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
10519ef1f84bSDavid du Colombier 		pcicfginit();
10529ef1f84bSDavid du Colombier 
10539ef1f84bSDavid du Colombier 	if(BUSBNO(tbdf))
10549ef1f84bSDavid du Colombier 		type = 0x01;
10559ef1f84bSDavid du Colombier 	else
10569ef1f84bSDavid du Colombier 		type = 0x00;
10579ef1f84bSDavid du Colombier 	x = -1;
10589ef1f84bSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
10599ef1f84bSDavid du Colombier 		return x;
10609ef1f84bSDavid du Colombier 
10619ef1f84bSDavid du Colombier 	lock(&pcicfglock);
10629ef1f84bSDavid du Colombier 	switch(pcicfgmode){
10639ef1f84bSDavid du Colombier 
10649ef1f84bSDavid du Colombier 	case 1:
10659ef1f84bSDavid du Colombier 		rno &= ~0x03;
10669ef1f84bSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
10679ef1f84bSDavid du Colombier 		if(read)
10689ef1f84bSDavid du Colombier 			x = inl(PciDATA);
10699ef1f84bSDavid du Colombier 		else
10709ef1f84bSDavid du Colombier 			outl(PciDATA, data);
10719ef1f84bSDavid du Colombier 		outl(PciADDR, 0);
10729ef1f84bSDavid du Colombier 		break;
10739ef1f84bSDavid du Colombier 
10749ef1f84bSDavid du Colombier 	case 2:
10759ef1f84bSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
10769ef1f84bSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
10779ef1f84bSDavid du Colombier 		if(read)
10789ef1f84bSDavid du Colombier 			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
10799ef1f84bSDavid du Colombier 		else
10809ef1f84bSDavid du Colombier 			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
10819ef1f84bSDavid du Colombier 		outb(PciCSE, 0);
10829ef1f84bSDavid du Colombier 		break;
10839ef1f84bSDavid du Colombier 	}
10849ef1f84bSDavid du Colombier 	unlock(&pcicfglock);
10859ef1f84bSDavid du Colombier 
10869ef1f84bSDavid du Colombier 	return x;
10879ef1f84bSDavid du Colombier }
10889ef1f84bSDavid du Colombier 
10899ef1f84bSDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)10909ef1f84bSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
10919ef1f84bSDavid du Colombier {
10929ef1f84bSDavid du Colombier 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
10939ef1f84bSDavid du Colombier }
10949ef1f84bSDavid du Colombier 
10959ef1f84bSDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)10969ef1f84bSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
10979ef1f84bSDavid du Colombier {
10989ef1f84bSDavid du Colombier 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
10999ef1f84bSDavid du Colombier }
11009ef1f84bSDavid du Colombier 
11019ef1f84bSDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)11029ef1f84bSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
11039ef1f84bSDavid du Colombier {
11049ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
11059ef1f84bSDavid du Colombier 		pcicfginit();
11069ef1f84bSDavid du Colombier 
11079ef1f84bSDavid du Colombier 	if(prev == nil)
11089ef1f84bSDavid du Colombier 		prev = pcilist;
11099ef1f84bSDavid du Colombier 	else
11109ef1f84bSDavid du Colombier 		prev = prev->list;
11119ef1f84bSDavid du Colombier 
11129ef1f84bSDavid du Colombier 	while(prev != nil){
11139ef1f84bSDavid du Colombier 		if((vid == 0 || prev->vid == vid)
11149ef1f84bSDavid du Colombier 		&& (did == 0 || prev->did == did))
11159ef1f84bSDavid du Colombier 			break;
11169ef1f84bSDavid du Colombier 		prev = prev->list;
11179ef1f84bSDavid du Colombier 	}
11189ef1f84bSDavid du Colombier 	return prev;
11199ef1f84bSDavid du Colombier }
11209ef1f84bSDavid du Colombier 
11219ef1f84bSDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)11229ef1f84bSDavid du Colombier pcimatchtbdf(int tbdf)
11239ef1f84bSDavid du Colombier {
11249ef1f84bSDavid du Colombier 	Pcidev *pcidev;
11259ef1f84bSDavid du Colombier 
11269ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
11279ef1f84bSDavid du Colombier 		pcicfginit();
11289ef1f84bSDavid du Colombier 
11299ef1f84bSDavid du Colombier 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
11309ef1f84bSDavid du Colombier 		if(pcidev->tbdf == tbdf)
11319ef1f84bSDavid du Colombier 			break;
11329ef1f84bSDavid du Colombier 	}
11339ef1f84bSDavid du Colombier 	return pcidev;
11349ef1f84bSDavid du Colombier }
11359ef1f84bSDavid du Colombier 
11369ef1f84bSDavid du Colombier uchar
pciipin(Pcidev * pci,uchar pin)11379ef1f84bSDavid du Colombier pciipin(Pcidev *pci, uchar pin)
11389ef1f84bSDavid du Colombier {
11399ef1f84bSDavid du Colombier 	if (pci == nil)
11409ef1f84bSDavid du Colombier 		pci = pcilist;
11419ef1f84bSDavid du Colombier 
11429ef1f84bSDavid du Colombier 	while (pci) {
11439ef1f84bSDavid du Colombier 		uchar intl;
11449ef1f84bSDavid du Colombier 
11459ef1f84bSDavid du Colombier 		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
11469ef1f84bSDavid du Colombier 			return pci->intl;
11479ef1f84bSDavid du Colombier 
11489ef1f84bSDavid du Colombier 		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
11499ef1f84bSDavid du Colombier 			return intl;
11509ef1f84bSDavid du Colombier 
11519ef1f84bSDavid du Colombier 		pci = pci->list;
11529ef1f84bSDavid du Colombier 	}
11539ef1f84bSDavid du Colombier 	return 0;
11549ef1f84bSDavid du Colombier }
11559ef1f84bSDavid du Colombier 
11569ef1f84bSDavid du Colombier static void
pcilhinv(Pcidev * p)11579ef1f84bSDavid du Colombier pcilhinv(Pcidev* p)
11589ef1f84bSDavid du Colombier {
11599ef1f84bSDavid du Colombier 	int i;
11609ef1f84bSDavid du Colombier 	Pcidev *t;
11619ef1f84bSDavid du Colombier 
11629ef1f84bSDavid du Colombier 	if(p == nil) {
11639ef1f84bSDavid du Colombier 		putstrn(PCICONS.output, PCICONS.ptr);
11649ef1f84bSDavid du Colombier 		p = pciroot;
11659ef1f84bSDavid du Colombier 		print("bus dev type vid  did intl memory\n");
11669ef1f84bSDavid du Colombier 	}
11679ef1f84bSDavid du Colombier 	for(t = p; t != nil; t = t->link) {
11689ef1f84bSDavid du Colombier 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
11699ef1f84bSDavid du Colombier 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
11709ef1f84bSDavid du Colombier 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
11719ef1f84bSDavid du Colombier 
11729ef1f84bSDavid du Colombier 		for(i = 0; i < nelem(p->mem); i++) {
11739ef1f84bSDavid du Colombier 			if(t->mem[i].size == 0)
11749ef1f84bSDavid du Colombier 				continue;
11759ef1f84bSDavid du Colombier 			print("%d:%.8lux %d ", i,
11769ef1f84bSDavid du Colombier 				t->mem[i].bar, t->mem[i].size);
11779ef1f84bSDavid du Colombier 		}
11789ef1f84bSDavid du Colombier 		if(t->ioa.bar || t->ioa.size)
11799ef1f84bSDavid du Colombier 			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
11809ef1f84bSDavid du Colombier 		if(t->mema.bar || t->mema.size)
11819ef1f84bSDavid du Colombier 			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
11829ef1f84bSDavid du Colombier 		if(t->bridge)
11839ef1f84bSDavid du Colombier 			print("->%d", BUSBNO(t->bridge->tbdf));
11849ef1f84bSDavid du Colombier 		print("\n");
11859ef1f84bSDavid du Colombier 	}
11869ef1f84bSDavid du Colombier 	while(p != nil) {
11879ef1f84bSDavid du Colombier 		if(p->bridge != nil)
11889ef1f84bSDavid du Colombier 			pcilhinv(p->bridge);
11899ef1f84bSDavid du Colombier 		p = p->link;
11909ef1f84bSDavid du Colombier 	}
11919ef1f84bSDavid du Colombier }
11929ef1f84bSDavid du Colombier 
11939ef1f84bSDavid du Colombier void
pcihinv(Pcidev * p)11949ef1f84bSDavid du Colombier pcihinv(Pcidev* p)
11959ef1f84bSDavid du Colombier {
11969ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
11979ef1f84bSDavid du Colombier 		pcicfginit();
11989ef1f84bSDavid du Colombier 	lock(&pcicfginitlock);
11999ef1f84bSDavid du Colombier 	pcilhinv(p);
12009ef1f84bSDavid du Colombier 	unlock(&pcicfginitlock);
12019ef1f84bSDavid du Colombier }
12029ef1f84bSDavid du Colombier 
12039ef1f84bSDavid du Colombier void
pcireset(void)12049ef1f84bSDavid du Colombier pcireset(void)
12059ef1f84bSDavid du Colombier {
12069ef1f84bSDavid du Colombier 	Pcidev *p;
12079ef1f84bSDavid du Colombier 
12089ef1f84bSDavid du Colombier 	if(pcicfgmode == -1)
12099ef1f84bSDavid du Colombier 		pcicfginit();
12109ef1f84bSDavid du Colombier 
12119ef1f84bSDavid du Colombier 	for(p = pcilist; p != nil; p = p->list) {
12129ef1f84bSDavid du Colombier 		/* don't mess with the bridges */
12139ef1f84bSDavid du Colombier 		if(p->ccrb == 0x06)
12149ef1f84bSDavid du Colombier 			continue;
12159ef1f84bSDavid du Colombier 		pciclrbme(p);
12169ef1f84bSDavid du Colombier 	}
12179ef1f84bSDavid du Colombier }
12189ef1f84bSDavid du Colombier 
12199ef1f84bSDavid du Colombier void
pcisetioe(Pcidev * p)12209ef1f84bSDavid du Colombier pcisetioe(Pcidev* p)
12219ef1f84bSDavid du Colombier {
12229ef1f84bSDavid du Colombier 	p->pcr |= IOen;
12239ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12249ef1f84bSDavid du Colombier }
12259ef1f84bSDavid du Colombier 
12269ef1f84bSDavid du Colombier void
pciclrioe(Pcidev * p)12279ef1f84bSDavid du Colombier pciclrioe(Pcidev* p)
12289ef1f84bSDavid du Colombier {
12299ef1f84bSDavid du Colombier 	p->pcr &= ~IOen;
12309ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12319ef1f84bSDavid du Colombier }
12329ef1f84bSDavid du Colombier 
12339ef1f84bSDavid du Colombier void
pcisetbme(Pcidev * p)12349ef1f84bSDavid du Colombier pcisetbme(Pcidev* p)
12359ef1f84bSDavid du Colombier {
12369ef1f84bSDavid du Colombier 	p->pcr |= MASen;
12379ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12389ef1f84bSDavid du Colombier }
12399ef1f84bSDavid du Colombier 
12409ef1f84bSDavid du Colombier void
pciclrbme(Pcidev * p)12419ef1f84bSDavid du Colombier pciclrbme(Pcidev* p)
12429ef1f84bSDavid du Colombier {
12439ef1f84bSDavid du Colombier 	p->pcr &= ~MASen;
12449ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12459ef1f84bSDavid du Colombier }
12469ef1f84bSDavid du Colombier 
12479ef1f84bSDavid du Colombier void
pcisetmwi(Pcidev * p)12489ef1f84bSDavid du Colombier pcisetmwi(Pcidev* p)
12499ef1f84bSDavid du Colombier {
12509ef1f84bSDavid du Colombier 	p->pcr |= MemWrInv;
12519ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12529ef1f84bSDavid du Colombier }
12539ef1f84bSDavid du Colombier 
12549ef1f84bSDavid du Colombier void
pciclrmwi(Pcidev * p)12559ef1f84bSDavid du Colombier pciclrmwi(Pcidev* p)
12569ef1f84bSDavid du Colombier {
12579ef1f84bSDavid du Colombier 	p->pcr &= ~MemWrInv;
12589ef1f84bSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
12599ef1f84bSDavid du Colombier }
12609ef1f84bSDavid du Colombier 
12618547cd99SDavid du Colombier int
pcienumcaps(Pcidev * p,int (* fmatch)(Pcidev *,int,int,int),int arg)1262*da317bb8SDavid du Colombier pcienumcaps(Pcidev* p, int (*fmatch)(Pcidev*, int, int, int), int arg)
12639ef1f84bSDavid du Colombier {
1264*da317bb8SDavid du Colombier 	int i, r, cap, off;
12659ef1f84bSDavid du Colombier 
12668547cd99SDavid du Colombier 	/* status register bit 4 has capabilities */
12678547cd99SDavid du Colombier 	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
12689ef1f84bSDavid du Colombier 		return -1;
12698547cd99SDavid du Colombier 	switch(pcicfgr8(p, PciHDT) & 0x7f){
12709ef1f84bSDavid du Colombier 	default:
12719ef1f84bSDavid du Colombier 		return -1;
12729ef1f84bSDavid du Colombier 	case 0:					/* all other */
12739ef1f84bSDavid du Colombier 	case 1:					/* PCI to PCI bridge */
12748547cd99SDavid du Colombier 		off = PciCP;
12759ef1f84bSDavid du Colombier 		break;
12769ef1f84bSDavid du Colombier 	case 2:					/* CardBus bridge */
12778547cd99SDavid du Colombier 		off = 0x14;
12789ef1f84bSDavid du Colombier 		break;
12799ef1f84bSDavid du Colombier 	}
12808547cd99SDavid du Colombier 	for(i = 48; i--;){
12818547cd99SDavid du Colombier 		off = pcicfgr8(p, off);
12828547cd99SDavid du Colombier 		if(off < 0x40 || (off & 3))
12838547cd99SDavid du Colombier 			break;
12848547cd99SDavid du Colombier 		off &= ~3;
1285*da317bb8SDavid du Colombier 		cap = pcicfgr8(p, off);
1286*da317bb8SDavid du Colombier 		if(cap == 0xff)
12878547cd99SDavid du Colombier 			break;
1288*da317bb8SDavid du Colombier 		r = (*fmatch)(p, cap, off, arg);
1289*da317bb8SDavid du Colombier 		if(r < 0)
1290*da317bb8SDavid du Colombier 			break;
1291*da317bb8SDavid du Colombier 		if(r == 0)
12928547cd99SDavid du Colombier 			return off;
12938547cd99SDavid du Colombier 		off++;
12949ef1f84bSDavid du Colombier 	}
12959ef1f84bSDavid du Colombier 
12969ef1f84bSDavid du Colombier 	return -1;
12979ef1f84bSDavid du Colombier }
12989ef1f84bSDavid du Colombier 
1299*da317bb8SDavid du Colombier static int
matchcap(Pcidev *,int cap,int,int arg)1300*da317bb8SDavid du Colombier matchcap(Pcidev*, int cap, int, int arg)
1301*da317bb8SDavid du Colombier {
1302*da317bb8SDavid du Colombier 	return cap != arg;
1303*da317bb8SDavid du Colombier }
1304*da317bb8SDavid du Colombier 
1305*da317bb8SDavid du Colombier static int
matchhtcap(Pcidev * p,int cap,int off,int arg)1306*da317bb8SDavid du Colombier matchhtcap(Pcidev* p, int cap, int off, int arg)
1307*da317bb8SDavid du Colombier {
1308*da317bb8SDavid du Colombier 	int mask;
1309*da317bb8SDavid du Colombier 
1310*da317bb8SDavid du Colombier 	if(cap != PciCapHTC)
1311*da317bb8SDavid du Colombier 		return 1;
1312*da317bb8SDavid du Colombier 	if(arg == 0x00 || arg == 0x20)
1313*da317bb8SDavid du Colombier 		mask = 0xE0;
1314*da317bb8SDavid du Colombier 	else
1315*da317bb8SDavid du Colombier 		mask = 0xF8;
1316*da317bb8SDavid du Colombier 	cap = pcicfgr8(p, off+3);
1317*da317bb8SDavid du Colombier 	return (cap & mask) != arg;
1318*da317bb8SDavid du Colombier }
1319*da317bb8SDavid du Colombier 
1320*da317bb8SDavid du Colombier int
pcicap(Pcidev * p,int cap)1321*da317bb8SDavid du Colombier pcicap(Pcidev* p, int cap)
1322*da317bb8SDavid du Colombier {
1323*da317bb8SDavid du Colombier 	return pcienumcaps(p, matchcap, cap);
1324*da317bb8SDavid du Colombier }
1325*da317bb8SDavid du Colombier 
1326*da317bb8SDavid du Colombier int
pcihtcap(Pcidev * p,int cap)1327*da317bb8SDavid du Colombier pcihtcap(Pcidev* p, int cap)
1328*da317bb8SDavid du Colombier {
1329*da317bb8SDavid du Colombier 	return pcienumcaps(p, matchhtcap, cap);
1330*da317bb8SDavid du Colombier }
1331*da317bb8SDavid du Colombier 
13329ef1f84bSDavid du Colombier int
pcigetpms(Pcidev * p)13339ef1f84bSDavid du Colombier pcigetpms(Pcidev* p)
13349ef1f84bSDavid du Colombier {
13359ef1f84bSDavid du Colombier 	int pmcsr, ptr;
13369ef1f84bSDavid du Colombier 
13378547cd99SDavid du Colombier 	if((ptr = pcicap(p, PciCapPMG)) == -1)
13389ef1f84bSDavid du Colombier 		return -1;
13399ef1f84bSDavid du Colombier 
13409ef1f84bSDavid du Colombier 	/*
13419ef1f84bSDavid du Colombier 	 * Power Management Register Block:
13429ef1f84bSDavid du Colombier 	 *  offset 0:	Capability ID
13439ef1f84bSDavid du Colombier 	 *	   1:	next item pointer
13449ef1f84bSDavid du Colombier 	 *	   2:	capabilities
13459ef1f84bSDavid du Colombier 	 *	   4:	control/status
13469ef1f84bSDavid du Colombier 	 *	   6:	bridge support extensions
13479ef1f84bSDavid du Colombier 	 *	   7:	data
13489ef1f84bSDavid du Colombier 	 */
13499ef1f84bSDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
13509ef1f84bSDavid du Colombier 
13519ef1f84bSDavid du Colombier 	return pmcsr & 0x0003;
13529ef1f84bSDavid du Colombier }
13539ef1f84bSDavid du Colombier 
13549ef1f84bSDavid du Colombier int
pcisetpms(Pcidev * p,int state)13559ef1f84bSDavid du Colombier pcisetpms(Pcidev* p, int state)
13569ef1f84bSDavid du Colombier {
13579ef1f84bSDavid du Colombier 	int ostate, pmc, pmcsr, ptr;
13589ef1f84bSDavid du Colombier 
13598547cd99SDavid du Colombier 	if((ptr = pcicap(p, PciCapPMG)) == -1)
13609ef1f84bSDavid du Colombier 		return -1;
13619ef1f84bSDavid du Colombier 
13629ef1f84bSDavid du Colombier 	pmc = pcicfgr16(p, ptr+2);
13639ef1f84bSDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
13649ef1f84bSDavid du Colombier 	ostate = pmcsr & 0x0003;
13659ef1f84bSDavid du Colombier 	pmcsr &= ~0x0003;
13669ef1f84bSDavid du Colombier 
13679ef1f84bSDavid du Colombier 	switch(state){
13689ef1f84bSDavid du Colombier 	default:
13699ef1f84bSDavid du Colombier 		return -1;
13709ef1f84bSDavid du Colombier 	case 0:
13719ef1f84bSDavid du Colombier 		break;
13729ef1f84bSDavid du Colombier 	case 1:
13739ef1f84bSDavid du Colombier 		if(!(pmc & 0x0200))
13749ef1f84bSDavid du Colombier 			return -1;
13759ef1f84bSDavid du Colombier 		break;
13769ef1f84bSDavid du Colombier 	case 2:
13779ef1f84bSDavid du Colombier 		if(!(pmc & 0x0400))
13789ef1f84bSDavid du Colombier 			return -1;
13799ef1f84bSDavid du Colombier 		break;
13809ef1f84bSDavid du Colombier 	case 3:
13819ef1f84bSDavid du Colombier 		break;
13829ef1f84bSDavid du Colombier 	}
13839ef1f84bSDavid du Colombier 	pmcsr |= state;
13849ef1f84bSDavid du Colombier 	pcicfgw16(p, ptr+4, pmcsr);
13859ef1f84bSDavid du Colombier 
13869ef1f84bSDavid du Colombier 	return ostate;
13879ef1f84bSDavid du Colombier }
1388