xref: /plan9-contrib/sys/src/9/pc/pci.c (revision 0336b12d315e4ce24bb920e2a5131c6ddd983e8f)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * PCI support code.
3e569ccb5SDavid du Colombier  * Needs a massive rewrite.
47dd7cddfSDavid du Colombier  */
57dd7cddfSDavid du Colombier #include "u.h"
67dd7cddfSDavid du Colombier #include "../port/lib.h"
77dd7cddfSDavid du Colombier #include "mem.h"
87dd7cddfSDavid du Colombier #include "dat.h"
97dd7cddfSDavid du Colombier #include "fns.h"
107dd7cddfSDavid du Colombier #include "io.h"
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier #define DBG	if(0) pcilog
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier struct
157dd7cddfSDavid du Colombier {
16cc162d66SDavid du Colombier 	char	output[PCICONSSIZE];
177dd7cddfSDavid du Colombier 	int	ptr;
187dd7cddfSDavid du Colombier }PCICONS;
197dd7cddfSDavid du Colombier 
202210c76eSDavid du Colombier int pcivga;
212210c76eSDavid du Colombier 
227dd7cddfSDavid du Colombier int
pcilog(char * fmt,...)237dd7cddfSDavid du Colombier pcilog(char *fmt, ...)
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	int n;
267dd7cddfSDavid du Colombier 	va_list arg;
277dd7cddfSDavid du Colombier 	char buf[PRINTSIZE];
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	va_start(arg, fmt);
309a747e4fSDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
317dd7cddfSDavid du Colombier 	va_end(arg);
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier 	memmove(PCICONS.output+PCICONS.ptr, buf, n);
347dd7cddfSDavid du Colombier 	PCICONS.ptr += n;
357dd7cddfSDavid du Colombier 	return n;
367dd7cddfSDavid du Colombier }
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier enum
397dd7cddfSDavid du Colombier {					/* configuration mechanism #1 */
407dd7cddfSDavid du Colombier 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
417dd7cddfSDavid du Colombier 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 					/* configuration mechanism #2 */
447dd7cddfSDavid du Colombier 	PciCSE		= 0xCF8,	/* configuration space enable */
457dd7cddfSDavid du Colombier 	PciFORWARD	= 0xCFA,	/* which bus */
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	MaxFNO		= 7,
487dd7cddfSDavid du Colombier 	MaxUBN		= 255,
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier enum
527dd7cddfSDavid du Colombier {					/* command register */
537dd7cddfSDavid du Colombier 	IOen		= (1<<0),
547dd7cddfSDavid du Colombier 	MEMen		= (1<<1),
557dd7cddfSDavid du Colombier 	MASen		= (1<<2),
567dd7cddfSDavid du Colombier 	MemWrInv	= (1<<4),
577dd7cddfSDavid du Colombier 	PErrEn		= (1<<6),
587dd7cddfSDavid du Colombier 	SErrEn		= (1<<8),
597dd7cddfSDavid du Colombier };
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier static Lock pcicfglock;
627dd7cddfSDavid du Colombier static Lock pcicfginitlock;
637dd7cddfSDavid du Colombier static int pcicfgmode = -1;
6459cc4ca5SDavid du Colombier static int pcimaxbno = 7;
657dd7cddfSDavid du Colombier static int pcimaxdno;
667dd7cddfSDavid du Colombier static Pcidev* pciroot;
677dd7cddfSDavid du Colombier static Pcidev* pcilist;
687dd7cddfSDavid du Colombier static Pcidev* pcitail;
693ff48bf5SDavid du Colombier static int nobios, nopcirouting;
704fafed5dSDavid du Colombier static BIOS32si* pcibiossi;
717dd7cddfSDavid du Colombier 
724fafed5dSDavid du Colombier static int pcicfgrw8raw(int, int, int, int);
734fafed5dSDavid du Colombier static int pcicfgrw16raw(int, int, int, int);
744fafed5dSDavid du Colombier static int pcicfgrw32raw(int, int, int, int);
754fafed5dSDavid du Colombier 
764fafed5dSDavid du Colombier static int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw;
774fafed5dSDavid du Colombier static int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw;
784fafed5dSDavid du Colombier static int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw;
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier static char* bustypes[] = {
817dd7cddfSDavid du Colombier 	"CBUSI",
827dd7cddfSDavid du Colombier 	"CBUSII",
837dd7cddfSDavid du Colombier 	"EISA",
847dd7cddfSDavid du Colombier 	"FUTURE",
857dd7cddfSDavid du Colombier 	"INTERN",
867dd7cddfSDavid du Colombier 	"ISA",
877dd7cddfSDavid du Colombier 	"MBI",
887dd7cddfSDavid du Colombier 	"MBII",
897dd7cddfSDavid du Colombier 	"MCA",
907dd7cddfSDavid du Colombier 	"MPI",
917dd7cddfSDavid du Colombier 	"MPSA",
927dd7cddfSDavid du Colombier 	"NUBUS",
937dd7cddfSDavid du Colombier 	"PCI",
947dd7cddfSDavid du Colombier 	"PCMCIA",
957dd7cddfSDavid du Colombier 	"TC",
967dd7cddfSDavid du Colombier 	"VL",
977dd7cddfSDavid du Colombier 	"VME",
987dd7cddfSDavid du Colombier 	"XPRESS",
997dd7cddfSDavid du Colombier };
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier static int
tbdffmt(Fmt * fmt)1029a747e4fSDavid du Colombier tbdffmt(Fmt* fmt)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	char *p;
10525fc6993SDavid du Colombier 	int l, r;
10625fc6993SDavid du Colombier 	uint type, tbdf;
1077dd7cddfSDavid du Colombier 
1089a747e4fSDavid du Colombier 	if((p = malloc(READSTR)) == nil)
1099a747e4fSDavid du Colombier 		return fmtstrcpy(fmt, "(tbdfconv)");
1107dd7cddfSDavid du Colombier 
1119a747e4fSDavid du Colombier 	switch(fmt->r){
1127dd7cddfSDavid du Colombier 	case 'T':
1139a747e4fSDavid du Colombier 		tbdf = va_arg(fmt->args, int);
11425fc6993SDavid du Colombier 		if(tbdf == BUSUNKNOWN)
11525fc6993SDavid du Colombier 			snprint(p, READSTR, "unknown");
11625fc6993SDavid du Colombier 		else{
1177dd7cddfSDavid du Colombier 			type = BUSTYPE(tbdf);
1187dd7cddfSDavid du Colombier 			if(type < nelem(bustypes))
1197dd7cddfSDavid du Colombier 				l = snprint(p, READSTR, bustypes[type]);
1207dd7cddfSDavid du Colombier 			else
1217dd7cddfSDavid du Colombier 				l = snprint(p, READSTR, "%d", type);
1227dd7cddfSDavid du Colombier 			snprint(p+l, READSTR-l, ".%d.%d.%d",
1237dd7cddfSDavid du Colombier 				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
12425fc6993SDavid du Colombier 		}
1257dd7cddfSDavid du Colombier 		break;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	default:
1287dd7cddfSDavid du Colombier 		snprint(p, READSTR, "(tbdfconv)");
1297dd7cddfSDavid du Colombier 		break;
1307dd7cddfSDavid du Colombier 	}
1319a747e4fSDavid du Colombier 	r = fmtstrcpy(fmt, p);
1327dd7cddfSDavid du Colombier 	free(p);
1337dd7cddfSDavid du Colombier 
1349a747e4fSDavid du Colombier 	return r;
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)1387dd7cddfSDavid du Colombier pcibarsize(Pcidev *p, int rno)
1397dd7cddfSDavid du Colombier {
1407dd7cddfSDavid du Colombier 	ulong v, size;
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
1437dd7cddfSDavid du Colombier 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
1447dd7cddfSDavid du Colombier 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
1457dd7cddfSDavid du Colombier 	if(v & 1)
1467dd7cddfSDavid du Colombier 		size |= 0xFFFF0000;
1477dd7cddfSDavid du Colombier 	pcicfgrw32(p->tbdf, rno, v, 0);
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 	return -(size & ~0x0F);
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier static int
pcisizcmp(void * a,void * b)1537dd7cddfSDavid du Colombier pcisizcmp(void *a, void *b)
1547dd7cddfSDavid du Colombier {
1557dd7cddfSDavid du Colombier 	Pcisiz *aa, *bb;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	aa = a;
1587dd7cddfSDavid du Colombier 	bb = b;
1597dd7cddfSDavid du Colombier 	return aa->siz - bb->siz;
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier static ulong
pcimask(ulong v)1637dd7cddfSDavid du Colombier pcimask(ulong v)
1647dd7cddfSDavid du Colombier {
1657dd7cddfSDavid du Colombier 	ulong m;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	m = BI2BY*sizeof(v);
1687dd7cddfSDavid du Colombier 	for(m = 1<<(m-1); m != 0; m >>= 1) {
1697dd7cddfSDavid du Colombier 		if(m & v)
1707dd7cddfSDavid du Colombier 			break;
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	m--;
1747dd7cddfSDavid du Colombier 	if((v & m) == 0)
1757dd7cddfSDavid du Colombier 		return v;
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier 	v |= m;
1787dd7cddfSDavid du Colombier 	return v+1;
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier static void
pcibusmap(Pcidev * root,ulong * pmema,ulong * pioa,int wrreg)1827dd7cddfSDavid du Colombier pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
1837dd7cddfSDavid du Colombier {
1847dd7cddfSDavid du Colombier 	Pcidev *p;
1857dd7cddfSDavid du Colombier 	int ntb, i, size, rno, hole;
1867dd7cddfSDavid du Colombier 	ulong v, mema, ioa, sioa, smema, base, limit;
1877dd7cddfSDavid du Colombier 	Pcisiz *table, *tptr, *mtb, *itb;
1887dd7cddfSDavid du Colombier 
1894fafed5dSDavid du Colombier 	if(!nobios)
1904fafed5dSDavid du Colombier 		return;
1914fafed5dSDavid du Colombier 
1927dd7cddfSDavid du Colombier 	ioa = *pioa;
1937dd7cddfSDavid du Colombier 	mema = *pmema;
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 	DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n",
1967dd7cddfSDavid du Colombier 		wrreg, root->tbdf, mema, ioa);
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	ntb = 0;
1997dd7cddfSDavid du Colombier 	for(p = root; p != nil; p = p->link)
2007dd7cddfSDavid du Colombier 		ntb++;
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier 	ntb *= (PciCIS-PciBAR0)/4;
2037dd7cddfSDavid du Colombier 	table = malloc(2*ntb*sizeof(Pcisiz));
204aa72973aSDavid du Colombier 	if(table == nil)
20540ff3dfeSDavid du Colombier 		panic("pcibusmap: no memory");
2067dd7cddfSDavid du Colombier 	itb = table;
2077dd7cddfSDavid du Colombier 	mtb = table+ntb;
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	/*
2107dd7cddfSDavid du Colombier 	 * Build a table of sizes
2117dd7cddfSDavid du Colombier 	 */
2127dd7cddfSDavid du Colombier 	for(p = root; p != nil; p = p->link) {
2137dd7cddfSDavid du Colombier 		if(p->ccrb == 0x06) {
2147dd7cddfSDavid du Colombier 			if(p->ccru != 0x04 || p->bridge == nil) {
2157dd7cddfSDavid du Colombier //				DBG("pci: ignored bridge %T\n", p->tbdf);
2167dd7cddfSDavid du Colombier 				continue;
2177dd7cddfSDavid du Colombier 			}
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 			sioa = ioa;
2207dd7cddfSDavid du Colombier 			smema = mema;
2217dd7cddfSDavid du Colombier 			pcibusmap(p->bridge, &smema, &sioa, 0);
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 			hole = pcimask(smema-mema);
2247dd7cddfSDavid du Colombier 			if(hole < (1<<20))
2257dd7cddfSDavid du Colombier 				hole = 1<<20;
2267dd7cddfSDavid du Colombier 			p->mema.size = hole;
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 			hole = pcimask(sioa-ioa);
2297dd7cddfSDavid du Colombier 			if(hole < (1<<12))
2307dd7cddfSDavid du Colombier 				hole = 1<<12;
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 			p->ioa.size = hole;
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 			itb->dev = p;
2357dd7cddfSDavid du Colombier 			itb->bar = -1;
2367dd7cddfSDavid du Colombier 			itb->siz = p->ioa.size;
2377dd7cddfSDavid du Colombier 			itb++;
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 			mtb->dev = p;
2407dd7cddfSDavid du Colombier 			mtb->bar = -1;
2417dd7cddfSDavid du Colombier 			mtb->siz = p->mema.size;
2427dd7cddfSDavid du Colombier 			mtb++;
2437dd7cddfSDavid du Colombier 			continue;
2447dd7cddfSDavid du Colombier 		}
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 		for(i = 0; i <= 5; i++) {
2477dd7cddfSDavid du Colombier 			rno = PciBAR0 + i*4;
2487dd7cddfSDavid du Colombier 			v = pcicfgrw32(p->tbdf, rno, 0, 1);
2497dd7cddfSDavid du Colombier 			size = pcibarsize(p, rno);
2507dd7cddfSDavid du Colombier 			if(size == 0)
2517dd7cddfSDavid du Colombier 				continue;
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 			if(v & 1) {
2547dd7cddfSDavid du Colombier 				itb->dev = p;
2557dd7cddfSDavid du Colombier 				itb->bar = i;
2567dd7cddfSDavid du Colombier 				itb->siz = size;
2577dd7cddfSDavid du Colombier 				itb++;
2587dd7cddfSDavid du Colombier 			}
2597dd7cddfSDavid du Colombier 			else {
2607dd7cddfSDavid du Colombier 				mtb->dev = p;
2617dd7cddfSDavid du Colombier 				mtb->bar = i;
2627dd7cddfSDavid du Colombier 				mtb->siz = size;
2637dd7cddfSDavid du Colombier 				mtb++;
2647dd7cddfSDavid du Colombier 			}
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 			p->mem[i].size = size;
2677dd7cddfSDavid du Colombier 		}
2687dd7cddfSDavid du Colombier 	}
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	/*
2717dd7cddfSDavid du Colombier 	 * Sort both tables IO smallest first, Memory largest
2727dd7cddfSDavid du Colombier 	 */
2737dd7cddfSDavid du Colombier 	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
2747dd7cddfSDavid du Colombier 	tptr = table+ntb;
2757dd7cddfSDavid du Colombier 	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier 	/*
2787dd7cddfSDavid du Colombier 	 * Allocate IO address space on this bus
2797dd7cddfSDavid du Colombier 	 */
2807dd7cddfSDavid du Colombier 	for(tptr = table; tptr < itb; tptr++) {
2817dd7cddfSDavid du Colombier 		hole = tptr->siz;
2827dd7cddfSDavid du Colombier 		if(tptr->bar == -1)
2837dd7cddfSDavid du Colombier 			hole = 1<<12;
2847dd7cddfSDavid du Colombier 		ioa = (ioa+hole-1) & ~(hole-1);
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 		p = tptr->dev;
2877dd7cddfSDavid du Colombier 		if(tptr->bar == -1)
2887dd7cddfSDavid du Colombier 			p->ioa.bar = ioa;
2897dd7cddfSDavid du Colombier 		else {
2907dd7cddfSDavid du Colombier 			p->pcr |= IOen;
2917dd7cddfSDavid du Colombier 			p->mem[tptr->bar].bar = ioa|1;
2927dd7cddfSDavid du Colombier 			if(wrreg)
2937dd7cddfSDavid du Colombier 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
2947dd7cddfSDavid du Colombier 		}
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 		ioa += tptr->siz;
2977dd7cddfSDavid du Colombier 	}
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	/*
3007dd7cddfSDavid du Colombier 	 * Allocate Memory address space on this bus
3017dd7cddfSDavid du Colombier 	 */
3027dd7cddfSDavid du Colombier 	for(tptr = table+ntb; tptr < mtb; tptr++) {
3037dd7cddfSDavid du Colombier 		hole = tptr->siz;
3047dd7cddfSDavid du Colombier 		if(tptr->bar == -1)
3057dd7cddfSDavid du Colombier 			hole = 1<<20;
3067dd7cddfSDavid du Colombier 		mema = (mema+hole-1) & ~(hole-1);
3077dd7cddfSDavid du Colombier 
3087dd7cddfSDavid du Colombier 		p = tptr->dev;
3097dd7cddfSDavid du Colombier 		if(tptr->bar == -1)
3107dd7cddfSDavid du Colombier 			p->mema.bar = mema;
3117dd7cddfSDavid du Colombier 		else {
3127dd7cddfSDavid du Colombier 			p->pcr |= MEMen;
3137dd7cddfSDavid du Colombier 			p->mem[tptr->bar].bar = mema;
3147dd7cddfSDavid du Colombier 			if(wrreg)
3157dd7cddfSDavid du Colombier 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
3167dd7cddfSDavid du Colombier 		}
3177dd7cddfSDavid du Colombier 		mema += tptr->siz;
3187dd7cddfSDavid du Colombier 	}
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	*pmema = mema;
3217dd7cddfSDavid du Colombier 	*pioa = ioa;
3227dd7cddfSDavid du Colombier 	free(table);
3237dd7cddfSDavid du Colombier 
3247dd7cddfSDavid du Colombier 	if(wrreg == 0)
3257dd7cddfSDavid du Colombier 		return;
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	/*
3287dd7cddfSDavid du Colombier 	 * Finally set all the bridge addresses & registers
3297dd7cddfSDavid du Colombier 	 */
3307dd7cddfSDavid du Colombier 	for(p = root; p != nil; p = p->link) {
3317dd7cddfSDavid du Colombier 		if(p->bridge == nil) {
3327dd7cddfSDavid du Colombier 			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3337dd7cddfSDavid du Colombier 
3347dd7cddfSDavid du Colombier 			p->pcr |= MASen;
335e569ccb5SDavid du Colombier 			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
3367dd7cddfSDavid du Colombier 			continue;
3377dd7cddfSDavid du Colombier 		}
3387dd7cddfSDavid du Colombier 
3397dd7cddfSDavid du Colombier 		base = p->ioa.bar;
3407dd7cddfSDavid du Colombier 		limit = base+p->ioa.size-1;
341d0f3faacSDavid du Colombier 		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
3427dd7cddfSDavid du Colombier 		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
343d0f3faacSDavid du Colombier 		pcicfgrw32(p->tbdf, PciIBR, v, 0);
3447dd7cddfSDavid du Colombier 		v = (limit & 0xFFFF0000)|(base>>16);
345d0f3faacSDavid du Colombier 		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 		base = p->mema.bar;
3487dd7cddfSDavid du Colombier 		limit = base+p->mema.size-1;
3497dd7cddfSDavid du Colombier 		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
350d0f3faacSDavid du Colombier 		pcicfgrw32(p->tbdf, PciMBR, v, 0);
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 		/*
3537dd7cddfSDavid du Colombier 		 * Disable memory prefetch
3547dd7cddfSDavid du Colombier 		 */
355d0f3faacSDavid du Colombier 		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
3567dd7cddfSDavid du Colombier 		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
3577dd7cddfSDavid du Colombier 
3587dd7cddfSDavid du Colombier 		/*
3597dd7cddfSDavid du Colombier 		 * Enable the bridge
3607dd7cddfSDavid du Colombier 		 */
361e569ccb5SDavid du Colombier 		p->pcr |= IOen|MEMen|MASen;
362e569ccb5SDavid du Colombier 		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier 		sioa = p->ioa.bar;
3657dd7cddfSDavid du Colombier 		smema = p->mema.bar;
3667dd7cddfSDavid du Colombier 		pcibusmap(p->bridge, &smema, &sioa, 1);
3677dd7cddfSDavid du Colombier 	}
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3702210c76eSDavid du Colombier /* side effect: if a video controller is seen, set pcivga non-zero */
3717dd7cddfSDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)3729a747e4fSDavid du Colombier pcilscan(int bno, Pcidev** list)
3737dd7cddfSDavid du Colombier {
3747dd7cddfSDavid du Colombier 	Pcidev *p, *head, *tail;
3757dd7cddfSDavid du Colombier 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	maxubn = bno;
3787dd7cddfSDavid du Colombier 	head = nil;
3797dd7cddfSDavid du Colombier 	tail = nil;
3807dd7cddfSDavid du Colombier 	for(dno = 0; dno <= pcimaxdno; dno++){
3817dd7cddfSDavid du Colombier 		maxfno = 0;
3827dd7cddfSDavid du Colombier 		for(fno = 0; fno <= maxfno; fno++){
3837dd7cddfSDavid du Colombier 			/*
3847dd7cddfSDavid du Colombier 			 * For this possible device, form the
3857dd7cddfSDavid du Colombier 			 * bus+device+function triplet needed to address it
3867dd7cddfSDavid du Colombier 			 * and try to read the vendor and device ID.
3877dd7cddfSDavid du Colombier 			 * If successful, allocate a device struct and
3887dd7cddfSDavid du Colombier 			 * start to fill it in with some useful information
3897dd7cddfSDavid du Colombier 			 * from the device's configuration space.
3907dd7cddfSDavid du Colombier 			 */
3917dd7cddfSDavid du Colombier 			tbdf = MKBUS(BusPCI, bno, dno, fno);
3927dd7cddfSDavid du Colombier 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
3937dd7cddfSDavid du Colombier 			if(l == 0xFFFFFFFF || l == 0)
3947dd7cddfSDavid du Colombier 				continue;
3957dd7cddfSDavid du Colombier 			p = malloc(sizeof(*p));
396aa72973aSDavid du Colombier 			if(p == nil)
39740ff3dfeSDavid du Colombier 				panic("pcilscan: no memory");
3987dd7cddfSDavid du Colombier 			p->tbdf = tbdf;
3997dd7cddfSDavid du Colombier 			p->vid = l;
4007dd7cddfSDavid du Colombier 			p->did = l>>16;
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier 			if(pcilist != nil)
4037dd7cddfSDavid du Colombier 				pcitail->list = p;
4047dd7cddfSDavid du Colombier 			else
4057dd7cddfSDavid du Colombier 				pcilist = p;
4067dd7cddfSDavid du Colombier 			pcitail = p;
4077dd7cddfSDavid du Colombier 
408e569ccb5SDavid du Colombier 			p->pcr = pcicfgr16(p, PciPCR);
4097dd7cddfSDavid du Colombier 			p->rid = pcicfgr8(p, PciRID);
4107dd7cddfSDavid du Colombier 			p->ccrp = pcicfgr8(p, PciCCRp);
4117dd7cddfSDavid du Colombier 			p->ccru = pcicfgr8(p, PciCCRu);
4127dd7cddfSDavid du Colombier 			p->ccrb = pcicfgr8(p, PciCCRb);
413e569ccb5SDavid du Colombier 			p->cls = pcicfgr8(p, PciCLS);
414e569ccb5SDavid du Colombier 			p->ltr = pcicfgr8(p, PciLTR);
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 			p->intl = pcicfgr8(p, PciINTL);
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 			/*
4197dd7cddfSDavid du Colombier 			 * If the device is a multi-function device adjust the
4207dd7cddfSDavid du Colombier 			 * loop count so all possible functions are checked.
4217dd7cddfSDavid du Colombier 			 */
4227dd7cddfSDavid du Colombier 			hdt = pcicfgr8(p, PciHDT);
4237dd7cddfSDavid du Colombier 			if(hdt & 0x80)
4247dd7cddfSDavid du Colombier 				maxfno = MaxFNO;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 			/*
4277dd7cddfSDavid du Colombier 			 * If appropriate, read the base address registers
4287dd7cddfSDavid du Colombier 			 * and work out the sizes.
4297dd7cddfSDavid du Colombier 			 */
4307dd7cddfSDavid du Colombier 			switch(p->ccrb) {
4312210c76eSDavid du Colombier 			case 0x03:		/* display controller */
4322210c76eSDavid du Colombier 				pcivga = 1;
4332210c76eSDavid du Colombier 				/* fall through */
4347dd7cddfSDavid du Colombier 			case 0x01:		/* mass storage controller */
4357dd7cddfSDavid du Colombier 			case 0x02:		/* network controller */
4367dd7cddfSDavid du Colombier 			case 0x04:		/* multimedia device */
4377dd7cddfSDavid du Colombier 			case 0x07:		/* simple comm. controllers */
4387dd7cddfSDavid du Colombier 			case 0x08:		/* base system peripherals */
4397dd7cddfSDavid du Colombier 			case 0x09:		/* input devices */
4407dd7cddfSDavid du Colombier 			case 0x0A:		/* docking stations */
4417dd7cddfSDavid du Colombier 			case 0x0B:		/* processors */
4427dd7cddfSDavid du Colombier 			case 0x0C:		/* serial bus controllers */
4437dd7cddfSDavid du Colombier 				if((hdt & 0x7F) != 0)
4447dd7cddfSDavid du Colombier 					break;
4457dd7cddfSDavid du Colombier 				rno = PciBAR0 - 4;
4467dd7cddfSDavid du Colombier 				for(i = 0; i < nelem(p->mem); i++) {
4477dd7cddfSDavid du Colombier 					rno += 4;
4487dd7cddfSDavid du Colombier 					p->mem[i].bar = pcicfgr32(p, rno);
4497dd7cddfSDavid du Colombier 					p->mem[i].size = pcibarsize(p, rno);
4507dd7cddfSDavid du Colombier 				}
4517dd7cddfSDavid du Colombier 				break;
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 			case 0x00:
4547dd7cddfSDavid du Colombier 			case 0x05:		/* memory controller */
4557dd7cddfSDavid du Colombier 			case 0x06:		/* bridge device */
4567dd7cddfSDavid du Colombier 			default:
4577dd7cddfSDavid du Colombier 				break;
4587dd7cddfSDavid du Colombier 			}
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 			if(head != nil)
4617dd7cddfSDavid du Colombier 				tail->link = p;
4627dd7cddfSDavid du Colombier 			else
4637dd7cddfSDavid du Colombier 				head = p;
4647dd7cddfSDavid du Colombier 			tail = p;
4657dd7cddfSDavid du Colombier 		}
4667dd7cddfSDavid du Colombier 	}
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	*list = head;
4697dd7cddfSDavid du Colombier 	for(p = head; p != nil; p = p->link){
4707dd7cddfSDavid du Colombier 		/*
4717dd7cddfSDavid du Colombier 		 * Find PCI-PCI bridges and recursively descend the tree.
4727dd7cddfSDavid du Colombier 		 */
4737dd7cddfSDavid du Colombier 		if(p->ccrb != 0x06 || p->ccru != 0x04)
4747dd7cddfSDavid du Colombier 			continue;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 		/*
4777dd7cddfSDavid du Colombier 		 * If the secondary or subordinate bus number is not
4787dd7cddfSDavid du Colombier 		 * initialised try to do what the PCI BIOS should have
4797dd7cddfSDavid du Colombier 		 * done and fill in the numbers as the tree is descended.
4807dd7cddfSDavid du Colombier 		 * On the way down the subordinate bus number is set to
4817dd7cddfSDavid du Colombier 		 * the maximum as it's not known how many buses are behind
4827dd7cddfSDavid du Colombier 		 * this one; the final value is set on the way back up.
4837dd7cddfSDavid du Colombier 		 */
4847dd7cddfSDavid du Colombier 		sbn = pcicfgr8(p, PciSBN);
4857dd7cddfSDavid du Colombier 		ubn = pcicfgr8(p, PciUBN);
4867dd7cddfSDavid du Colombier 
48780ee5cbfSDavid du Colombier 		if(sbn == 0 || ubn == 0 || nobios) {
4887dd7cddfSDavid du Colombier 			sbn = maxubn+1;
4897dd7cddfSDavid du Colombier 			/*
4907dd7cddfSDavid du Colombier 			 * Make sure memory, I/O and master enables are
4917dd7cddfSDavid du Colombier 			 * off, set the primary, secondary and subordinate
4927dd7cddfSDavid du Colombier 			 * bus numbers and clear the secondary status before
4937dd7cddfSDavid du Colombier 			 * attempting to scan the secondary bus.
4947dd7cddfSDavid du Colombier 			 *
4957dd7cddfSDavid du Colombier 			 * Initialisation of the bridge should be done here.
4967dd7cddfSDavid du Colombier 			 */
4977dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPCR, 0xFFFF0000);
4987dd7cddfSDavid du Colombier 			l = (MaxUBN<<16)|(sbn<<8)|bno;
4997dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
5007dd7cddfSDavid du Colombier 			pcicfgw16(p, PciSPSR, 0xFFFF);
5019a747e4fSDavid du Colombier 			maxubn = pcilscan(sbn, &p->bridge);
5027dd7cddfSDavid du Colombier 			l = (maxubn<<16)|(sbn<<8)|bno;
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
5057dd7cddfSDavid du Colombier 		}
5067dd7cddfSDavid du Colombier 		else {
507e569ccb5SDavid du Colombier 			if(ubn > maxubn)
5087dd7cddfSDavid du Colombier 				maxubn = ubn;
5099a747e4fSDavid du Colombier 			pcilscan(sbn, &p->bridge);
5107dd7cddfSDavid du Colombier 		}
5117dd7cddfSDavid du Colombier 	}
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier 	return maxubn;
5147dd7cddfSDavid du Colombier }
5157dd7cddfSDavid du Colombier 
5169a747e4fSDavid du Colombier int
pciscan(int bno,Pcidev ** list)5179a747e4fSDavid du Colombier pciscan(int bno, Pcidev **list)
5189a747e4fSDavid du Colombier {
5199a747e4fSDavid du Colombier 	int ubn;
5209a747e4fSDavid du Colombier 
5219a747e4fSDavid du Colombier 	lock(&pcicfginitlock);
5229a747e4fSDavid du Colombier 	ubn = pcilscan(bno, list);
5239a747e4fSDavid du Colombier 	unlock(&pcicfginitlock);
5249a747e4fSDavid du Colombier 	return ubn;
5259a747e4fSDavid du Colombier }
5269a747e4fSDavid du Colombier 
5279a747e4fSDavid du Colombier static uchar
pIIxget(Pcidev * router,uchar link)52859c21d95SDavid du Colombier pIIxget(Pcidev *router, uchar link)
5299a747e4fSDavid du Colombier {
5309a747e4fSDavid du Colombier 	uchar pirq;
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier 	/* link should be 0x60, 0x61, 0x62, 0x63 */
5339a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, link);
5349a747e4fSDavid du Colombier 	return (pirq < 16)? pirq: 0;
5359a747e4fSDavid du Colombier }
5369a747e4fSDavid du Colombier 
5379a747e4fSDavid du Colombier static void
pIIxset(Pcidev * router,uchar link,uchar irq)53859c21d95SDavid du Colombier pIIxset(Pcidev *router, uchar link, uchar irq)
5399a747e4fSDavid du Colombier {
5409a747e4fSDavid du Colombier 	pcicfgw8(router, link, irq);
5419a747e4fSDavid du Colombier }
5429a747e4fSDavid du Colombier 
5439a747e4fSDavid du Colombier static uchar
viaget(Pcidev * router,uchar link)54459c21d95SDavid du Colombier viaget(Pcidev *router, uchar link)
5459a747e4fSDavid du Colombier {
5469a747e4fSDavid du Colombier 	uchar pirq;
5479a747e4fSDavid du Colombier 
5489a747e4fSDavid du Colombier 	/* link should be 1, 2, 3, 5 */
5499a747e4fSDavid du Colombier 	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
5509a747e4fSDavid du Colombier 
5519a747e4fSDavid du Colombier 	return (link & 1)? (pirq >> 4): (pirq & 15);
5529a747e4fSDavid du Colombier }
5539a747e4fSDavid du Colombier 
5549a747e4fSDavid du Colombier static void
viaset(Pcidev * router,uchar link,uchar irq)55559c21d95SDavid du Colombier viaset(Pcidev *router, uchar link, uchar irq)
5569a747e4fSDavid du Colombier {
5579a747e4fSDavid du Colombier 	uchar pirq;
5589a747e4fSDavid du Colombier 
5599a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0x55 + (link >> 1));
5609a747e4fSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
5619a747e4fSDavid du Colombier 	pirq |= (link & 1)? (irq << 4): (irq & 15);
5629a747e4fSDavid du Colombier 	pcicfgw8(router, 0x55 + (link>>1), pirq);
5639a747e4fSDavid du Colombier }
5649a747e4fSDavid du Colombier 
5659a747e4fSDavid du Colombier static uchar
optiget(Pcidev * router,uchar link)56659c21d95SDavid du Colombier optiget(Pcidev *router, uchar link)
5679a747e4fSDavid du Colombier {
5689a747e4fSDavid du Colombier 	uchar pirq = 0;
5699a747e4fSDavid du Colombier 
5709a747e4fSDavid du Colombier 	/* link should be 0x02, 0x12, 0x22, 0x32 */
5719a747e4fSDavid du Colombier 	if ((link & 0xcf) == 0x02)
5729a747e4fSDavid du Colombier 		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5739a747e4fSDavid du Colombier 	return (link & 0x10)? (pirq >> 4): (pirq & 15);
5749a747e4fSDavid du Colombier }
5759a747e4fSDavid du Colombier 
5769a747e4fSDavid du Colombier static void
optiset(Pcidev * router,uchar link,uchar irq)57759c21d95SDavid du Colombier optiset(Pcidev *router, uchar link, uchar irq)
5789a747e4fSDavid du Colombier {
5799a747e4fSDavid du Colombier 	uchar pirq;
5809a747e4fSDavid du Colombier 
5819a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
5829a747e4fSDavid du Colombier     	pirq &= (link & 0x10)? 0x0f : 0xf0;
5839a747e4fSDavid du Colombier     	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
5849a747e4fSDavid du Colombier 	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
5859a747e4fSDavid du Colombier }
5869a747e4fSDavid du Colombier 
5879a747e4fSDavid du Colombier static uchar
aliget(Pcidev * router,uchar link)58859c21d95SDavid du Colombier aliget(Pcidev *router, uchar link)
5899a747e4fSDavid du Colombier {
5909a747e4fSDavid du Colombier 	/* No, you're not dreaming */
5919a747e4fSDavid du Colombier 	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
5929a747e4fSDavid du Colombier 	uchar pirq;
5939a747e4fSDavid du Colombier 
5949a747e4fSDavid du Colombier 	/* link should be 0x01..0x08 */
5959a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
5969a747e4fSDavid du Colombier 	return (link & 1)? map[pirq&15]: map[pirq>>4];
5979a747e4fSDavid du Colombier }
5989a747e4fSDavid du Colombier 
5999a747e4fSDavid du Colombier static void
aliset(Pcidev * router,uchar link,uchar irq)60059c21d95SDavid du Colombier aliset(Pcidev *router, uchar link, uchar irq)
6019a747e4fSDavid du Colombier {
60259c21d95SDavid du Colombier 	/* Inverse of map in aliget */
6039a747e4fSDavid du Colombier 	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
6049a747e4fSDavid du Colombier 	uchar pirq;
6059a747e4fSDavid du Colombier 
6069a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
6079a747e4fSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
6089a747e4fSDavid du Colombier 	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
6099a747e4fSDavid du Colombier 	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
6109a747e4fSDavid du Colombier }
6119a747e4fSDavid du Colombier 
6129a747e4fSDavid du Colombier static uchar
cyrixget(Pcidev * router,uchar link)61359c21d95SDavid du Colombier cyrixget(Pcidev *router, uchar link)
6149a747e4fSDavid du Colombier {
6159a747e4fSDavid du Colombier 	uchar pirq;
6169a747e4fSDavid du Colombier 
6179a747e4fSDavid du Colombier 	/* link should be 1, 2, 3, 4 */
6189a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
6199a747e4fSDavid du Colombier 	return ((link & 1)? pirq >> 4: pirq & 15);
6209a747e4fSDavid du Colombier }
6219a747e4fSDavid du Colombier 
6229a747e4fSDavid du Colombier static void
cyrixset(Pcidev * router,uchar link,uchar irq)62359c21d95SDavid du Colombier cyrixset(Pcidev *router, uchar link, uchar irq)
6249a747e4fSDavid du Colombier {
6259a747e4fSDavid du Colombier 	uchar pirq;
6269a747e4fSDavid du Colombier 
6279a747e4fSDavid du Colombier 	pirq = pcicfgr8(router, 0x5c + (link>>1));
6289a747e4fSDavid du Colombier 	pirq &= (link & 1)? 0x0f: 0xf0;
6299a747e4fSDavid du Colombier 	pirq |= (link & 1)? (irq << 4): (irq & 15);
6309a747e4fSDavid du Colombier 	pcicfgw8(router, 0x5c + (link>>1), pirq);
6319a747e4fSDavid du Colombier }
6329a747e4fSDavid du Colombier 
63359c21d95SDavid du Colombier typedef struct Bridge Bridge;
63459c21d95SDavid du Colombier struct Bridge
6359a747e4fSDavid du Colombier {
6369a747e4fSDavid du Colombier 	ushort	vid;
6379a747e4fSDavid du Colombier 	ushort	did;
6389a747e4fSDavid du Colombier 	uchar	(*get)(Pcidev *, uchar);
6399a747e4fSDavid du Colombier 	void	(*set)(Pcidev *, uchar, uchar);
6409a747e4fSDavid du Colombier };
6419a747e4fSDavid du Colombier 
64259c21d95SDavid du Colombier static Bridge southbridges[] = {
64341dd6b47SDavid du Colombier 	{ 0x8086, 0x122e, pIIxget, pIIxset },	/* Intel 82371FB */
64441dd6b47SDavid du Colombier 	{ 0x8086, 0x1234, pIIxget, pIIxset },	/* Intel 82371MX */
64541dd6b47SDavid du Colombier 	{ 0x8086, 0x7000, pIIxget, pIIxset },	/* Intel 82371SB */
64641dd6b47SDavid du Colombier 	{ 0x8086, 0x7110, pIIxget, pIIxset },	/* Intel 82371AB */
64741dd6b47SDavid du Colombier 	{ 0x8086, 0x7198, pIIxget, pIIxset },	/* Intel 82443MX (fn 1) */
64841dd6b47SDavid du Colombier 	{ 0x8086, 0x2410, pIIxget, pIIxset },	/* Intel 82801AA */
64941dd6b47SDavid du Colombier 	{ 0x8086, 0x2420, pIIxget, pIIxset },	/* Intel 82801AB */
65041dd6b47SDavid du Colombier 	{ 0x8086, 0x2440, pIIxget, pIIxset },	/* Intel 82801BA */
651d8cd2beaSDavid du Colombier 	{ 0x8086, 0x2448, pIIxget, pIIxset },	/* Intel 82801BAM/CAM/DBM */
65241dd6b47SDavid du Colombier 	{ 0x8086, 0x244c, pIIxget, pIIxset },	/* Intel 82801BAM */
653d8cd2beaSDavid du Colombier 	{ 0x8086, 0x244e, pIIxget, pIIxset },	/* Intel 82801 */
65441dd6b47SDavid du Colombier 	{ 0x8086, 0x2480, pIIxget, pIIxset },	/* Intel 82801CA */
65541dd6b47SDavid du Colombier 	{ 0x8086, 0x248c, pIIxget, pIIxset },	/* Intel 82801CAM */
65641dd6b47SDavid du Colombier 	{ 0x8086, 0x24c0, pIIxget, pIIxset },	/* Intel 82801DBL */
65741dd6b47SDavid du Colombier 	{ 0x8086, 0x24cc, pIIxget, pIIxset },	/* Intel 82801DBM */
65841dd6b47SDavid du Colombier 	{ 0x8086, 0x24d0, pIIxget, pIIxset },	/* Intel 82801EB */
6591c9e5a6cSDavid du Colombier 	{ 0x8086, 0x25a1, pIIxget, pIIxset },	/* Intel 6300ESB */
66041dd6b47SDavid du Colombier 	{ 0x8086, 0x2640, pIIxget, pIIxset },	/* Intel 82801FB */
661add6b5c5SDavid du Colombier 	{ 0x8086, 0x2641, pIIxget, pIIxset },	/* Intel 82801FBM */
66241dd6b47SDavid du Colombier 	{ 0x8086, 0x27b8, pIIxget, pIIxset },	/* Intel 82801GB */
66341dd6b47SDavid du Colombier 	{ 0x8086, 0x27b9, pIIxget, pIIxset },	/* Intel 82801GBM */
664194f7e8cSDavid du Colombier 	{ 0x8086, 0x27bd, pIIxget, pIIxset },	/* Intel 82801GB/GR */
665d8cd2beaSDavid du Colombier 	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801JIR */
666d8cd2beaSDavid du Colombier 	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801JI */
667d8cd2beaSDavid du Colombier 	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801JI */
668d8cd2beaSDavid du Colombier 	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801JI */
669aef37788SDavid du Colombier 	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801? */
6706f8e93f6SDavid du Colombier 	{ 0x8086, 0x1c02, pIIxget, pIIxset },	/* Intel 6 Series/C200 */
67128684b1dSDavid du Colombier 	{ 0x8086, 0x1c44, pIIxget, pIIxset },	/* Intel 6 Series/Z68 Express */
6728c242bd4SDavid du Colombier 	{ 0x8086, 0x1e53, pIIxget, pIIxset },	/* Intel 7 Series/C216 */
67341dd6b47SDavid du Colombier 	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
67441dd6b47SDavid du Colombier 	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
67541dd6b47SDavid du Colombier 	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
676a0db15f5SDavid du Colombier 	{ 0x1106, 0x3177, viaget, viaset },	/* Viatech VT8235 */
67741dd6b47SDavid du Colombier 	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
678a0db15f5SDavid du Colombier 	{ 0x1106, 0x3287, viaget, viaset },	/* Viatech VT8251 */
67941dd6b47SDavid du Colombier 	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
68041dd6b47SDavid du Colombier 	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
68141dd6b47SDavid du Colombier 	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
68241dd6b47SDavid du Colombier 	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
68341dd6b47SDavid du Colombier 	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
6845000fddeSDavid du Colombier 
68541dd6b47SDavid du Colombier 	{ 0x1022, 0x746B, nil, nil },		/* AMD 8111 */
68641dd6b47SDavid du Colombier 	{ 0x10DE, 0x00D1, nil, nil },		/* NVIDIA nForce 3 */
68741ac1ab6SDavid du Colombier 	{ 0x10DE, 0x00E0, nil, nil },		/* NVIDIA nForce 3 250 Series */
688b8a11165SDavid du Colombier 	{ 0x10DE, 0x00E1, nil, nil },		/* NVIDIA nForce 3 250 Series */
68941dd6b47SDavid du Colombier 	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
69041dd6b47SDavid du Colombier 	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
69141dd6b47SDavid du Colombier 	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
69259c21d95SDavid du Colombier };
6939a747e4fSDavid du Colombier 
69459c21d95SDavid du Colombier typedef struct Slot Slot;
69559c21d95SDavid du Colombier struct Slot {
69641dd6b47SDavid du Colombier 	uchar	bus;		/* Pci bus number */
69741dd6b47SDavid du Colombier 	uchar	dev;		/* Pci device number */
69841dd6b47SDavid du Colombier 	uchar	maps[12];	/* Avoid structs!  Link and mask. */
69941dd6b47SDavid du Colombier 	uchar	slot;		/* Add-in/built-in slot */
70059c21d95SDavid du Colombier 	uchar	reserved;
70159c21d95SDavid du Colombier };
70259c21d95SDavid du Colombier 
70359c21d95SDavid du Colombier typedef struct Router Router;
70459c21d95SDavid du Colombier struct Router {
70541dd6b47SDavid du Colombier 	uchar	signature[4];	/* Routing table signature */
70641dd6b47SDavid du Colombier 	uchar	version[2];	/* Version number */
70741dd6b47SDavid du Colombier 	uchar	size[2];	/* Total table size */
70841dd6b47SDavid du Colombier 	uchar	bus;		/* Interrupt router bus number */
70941dd6b47SDavid du Colombier 	uchar	devfn;		/* Router's devfunc */
71041dd6b47SDavid du Colombier 	uchar	pciirqs[2];	/* Exclusive PCI irqs */
71141dd6b47SDavid du Colombier 	uchar	compat[4];	/* Compatible PCI interrupt router */
71241dd6b47SDavid du Colombier 	uchar	miniport[4];	/* Miniport data */
71359c21d95SDavid du Colombier 	uchar	reserved[11];
71459c21d95SDavid du Colombier 	uchar	checksum;
71559c21d95SDavid du Colombier };
7169a747e4fSDavid du Colombier 
71741dd6b47SDavid du Colombier static ushort pciirqs;		/* Exclusive PCI irqs */
71841dd6b47SDavid du Colombier static Bridge *southbridge;	/* Which southbridge to use. */
7199a747e4fSDavid du Colombier 
7209a747e4fSDavid du Colombier static void
pcirouting(void)7219a747e4fSDavid du Colombier pcirouting(void)
7229a747e4fSDavid du Colombier {
72359c21d95SDavid du Colombier 	Slot *e;
72459c21d95SDavid du Colombier 	Router *r;
7259a747e4fSDavid du Colombier 	int size, i, fn, tbdf;
7269a747e4fSDavid du Colombier 	Pcidev *sbpci, *pci;
7275000fddeSDavid du Colombier 	uchar *p, pin, irq, link, *map;
7289a747e4fSDavid du Colombier 
72941dd6b47SDavid du Colombier 	/* Search for PCI interrupt routing table in BIOS */
7309a747e4fSDavid du Colombier 	for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
7319a747e4fSDavid du Colombier 		if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
7329a747e4fSDavid du Colombier 			break;
7339a747e4fSDavid du Colombier 
7342210c76eSDavid du Colombier 	if(p >= (uchar *)KADDR(0xfffff)) {
7353d8d68ddSDavid du Colombier 		// print("no PCI intr routing table found\n");
7369a747e4fSDavid du Colombier 		return;
7372210c76eSDavid du Colombier 	}
7389a747e4fSDavid du Colombier 
73959c21d95SDavid du Colombier 	r = (Router *)p;
7409a747e4fSDavid du Colombier 
7412210c76eSDavid du Colombier 	if (0)
7422210c76eSDavid du Colombier 		print("PCI interrupt routing table version %d.%d at %#.6luX\n",
7432210c76eSDavid du Colombier 			r->version[0], r->version[1], (ulong)r & 0xfffff);
7449a747e4fSDavid du Colombier 
74559c21d95SDavid du Colombier 	tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8);
7469a747e4fSDavid du Colombier 	sbpci = pcimatchtbdf(tbdf);
7479a747e4fSDavid du Colombier 	if(sbpci == nil) {
7489a747e4fSDavid du Colombier 		print("pcirouting: Cannot find south bridge %T\n", tbdf);
7499a747e4fSDavid du Colombier 		return;
7509a747e4fSDavid du Colombier 	}
7519a747e4fSDavid du Colombier 
7529a747e4fSDavid du Colombier 	for(i = 0; i != nelem(southbridges); i++)
7539a747e4fSDavid du Colombier 		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
7549a747e4fSDavid du Colombier 			break;
7559a747e4fSDavid du Colombier 
7569a747e4fSDavid du Colombier 	if(i == nelem(southbridges)) {
7573ff48bf5SDavid du Colombier 		print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did);
7589a747e4fSDavid du Colombier 		return;
7599a747e4fSDavid du Colombier 	}
7609a747e4fSDavid du Colombier 	southbridge = &southbridges[i];
7615000fddeSDavid du Colombier 	if(southbridge->get == nil || southbridge->set == nil)
7625000fddeSDavid du Colombier 		return;
7639a747e4fSDavid du Colombier 
76459c21d95SDavid du Colombier 	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
7659a747e4fSDavid du Colombier 
76659c21d95SDavid du Colombier 	size = (r->size[1] << 8)|r->size[0];
76759c21d95SDavid du Colombier 	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
76841dd6b47SDavid du Colombier 		if (0) {
76941dd6b47SDavid du Colombier 			print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot);
77041dd6b47SDavid du Colombier 			for (i = 0; i != 4; i++) {
77141dd6b47SDavid du Colombier 				uchar *m = &e->maps[i * 3];
77241dd6b47SDavid du Colombier 				print("[%d] %.2uX %.4uX ",
77341dd6b47SDavid du Colombier 					i, m[0], (m[2] << 8)|m[1]);
77441dd6b47SDavid du Colombier 			}
77541dd6b47SDavid du Colombier 			print("\n");
77641dd6b47SDavid du Colombier 		}
7779a747e4fSDavid du Colombier 		for(fn = 0; fn != 8; fn++) {
77859c21d95SDavid du Colombier 			tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
7799a747e4fSDavid du Colombier 			pci = pcimatchtbdf(tbdf);
7809a747e4fSDavid du Colombier 			if(pci == nil)
7819a747e4fSDavid du Colombier 				continue;
7829a747e4fSDavid du Colombier 			pin = pcicfgr8(pci, PciINTP);
7839a747e4fSDavid du Colombier 			if(pin == 0 || pin == 0xff)
7849a747e4fSDavid du Colombier 				continue;
7859a747e4fSDavid du Colombier 
7865000fddeSDavid du Colombier 			map = &e->maps[(pin - 1) * 3];
7875000fddeSDavid du Colombier 			link = map[0];
7883ff48bf5SDavid du Colombier 			irq = southbridge->get(sbpci, link);
7899a747e4fSDavid du Colombier 			if(irq == 0 || irq == pci->intl)
7909a747e4fSDavid du Colombier 				continue;
7919a747e4fSDavid du Colombier 			if(pci->intl != 0 && pci->intl != 0xFF) {
7923ff48bf5SDavid du Colombier 				print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
7933ff48bf5SDavid du Colombier 					  tbdf, pin, link, irq, pci->intl);
7943ff48bf5SDavid du Colombier 				southbridge->set(sbpci, link, pci->intl);
7959a747e4fSDavid du Colombier 				continue;
7969a747e4fSDavid du Colombier 			}
7973ff48bf5SDavid du Colombier 			print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
7989a747e4fSDavid du Colombier 			pcicfgw8(pci, PciINTL, irq);
7999a747e4fSDavid du Colombier 			pci->intl = irq;
8009a747e4fSDavid du Colombier 		}
8019a747e4fSDavid du Colombier 	}
8029a747e4fSDavid du Colombier }
8039a747e4fSDavid du Colombier 
8044de34a7eSDavid du Colombier static void pcireservemem(void);
8054de34a7eSDavid du Colombier 
8064fafed5dSDavid du Colombier static int
pcicfgrw8bios(int tbdf,int rno,int data,int read)8074fafed5dSDavid du Colombier pcicfgrw8bios(int tbdf, int rno, int data, int read)
8084fafed5dSDavid du Colombier {
8094fafed5dSDavid du Colombier 	BIOS32ci ci;
8104fafed5dSDavid du Colombier 
8114fafed5dSDavid du Colombier 	if(pcibiossi == nil)
8124fafed5dSDavid du Colombier 		return -1;
8134fafed5dSDavid du Colombier 
8144fafed5dSDavid du Colombier 	memset(&ci, 0, sizeof(BIOS32ci));
8154fafed5dSDavid du Colombier 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
8164fafed5dSDavid du Colombier 	ci.edi = rno;
8174fafed5dSDavid du Colombier 	if(read){
8184fafed5dSDavid du Colombier 		ci.eax = 0xB108;
8194fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8204fafed5dSDavid du Colombier 			return ci.ecx & 0xFF;
8214fafed5dSDavid du Colombier 	}
8224fafed5dSDavid du Colombier 	else{
8234fafed5dSDavid du Colombier 		ci.eax = 0xB10B;
8244fafed5dSDavid du Colombier 		ci.ecx = data & 0xFF;
8254fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8264fafed5dSDavid du Colombier 			return 0;
8274fafed5dSDavid du Colombier 	}
8284fafed5dSDavid du Colombier 
8294fafed5dSDavid du Colombier 	return -1;
8304fafed5dSDavid du Colombier }
8314fafed5dSDavid du Colombier 
8324fafed5dSDavid du Colombier static int
pcicfgrw16bios(int tbdf,int rno,int data,int read)8334fafed5dSDavid du Colombier pcicfgrw16bios(int tbdf, int rno, int data, int read)
8344fafed5dSDavid du Colombier {
8354fafed5dSDavid du Colombier 	BIOS32ci ci;
8364fafed5dSDavid du Colombier 
8374fafed5dSDavid du Colombier 	if(pcibiossi == nil)
8384fafed5dSDavid du Colombier 		return -1;
8394fafed5dSDavid du Colombier 
8404fafed5dSDavid du Colombier 	memset(&ci, 0, sizeof(BIOS32ci));
8414fafed5dSDavid du Colombier 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
8424fafed5dSDavid du Colombier 	ci.edi = rno;
8434fafed5dSDavid du Colombier 	if(read){
8444fafed5dSDavid du Colombier 		ci.eax = 0xB109;
8454fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8464fafed5dSDavid du Colombier 			return ci.ecx & 0xFFFF;
8474fafed5dSDavid du Colombier 	}
8484fafed5dSDavid du Colombier 	else{
8494fafed5dSDavid du Colombier 		ci.eax = 0xB10C;
8504fafed5dSDavid du Colombier 		ci.ecx = data & 0xFFFF;
8514fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8524fafed5dSDavid du Colombier 			return 0;
8534fafed5dSDavid du Colombier 	}
8544fafed5dSDavid du Colombier 
8554fafed5dSDavid du Colombier 	return -1;
8564fafed5dSDavid du Colombier }
8574fafed5dSDavid du Colombier 
8584fafed5dSDavid du Colombier static int
pcicfgrw32bios(int tbdf,int rno,int data,int read)8594fafed5dSDavid du Colombier pcicfgrw32bios(int tbdf, int rno, int data, int read)
8604fafed5dSDavid du Colombier {
8614fafed5dSDavid du Colombier 	BIOS32ci ci;
8624fafed5dSDavid du Colombier 
8634fafed5dSDavid du Colombier 	if(pcibiossi == nil)
8644fafed5dSDavid du Colombier 		return -1;
8654fafed5dSDavid du Colombier 
8664fafed5dSDavid du Colombier 	memset(&ci, 0, sizeof(BIOS32ci));
8674fafed5dSDavid du Colombier 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
8684fafed5dSDavid du Colombier 	ci.edi = rno;
8694fafed5dSDavid du Colombier 	if(read){
8704fafed5dSDavid du Colombier 		ci.eax = 0xB10A;
8714fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8724fafed5dSDavid du Colombier 			return ci.ecx;
8734fafed5dSDavid du Colombier 	}
8744fafed5dSDavid du Colombier 	else{
8754fafed5dSDavid du Colombier 		ci.eax = 0xB10D;
8764fafed5dSDavid du Colombier 		ci.ecx = data;
8774fafed5dSDavid du Colombier 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
8784fafed5dSDavid du Colombier 			return 0;
8794fafed5dSDavid du Colombier 	}
8804fafed5dSDavid du Colombier 
8814fafed5dSDavid du Colombier 	return -1;
8824fafed5dSDavid du Colombier }
8834fafed5dSDavid du Colombier 
8844fafed5dSDavid du Colombier static BIOS32si*
pcibiosinit(void)8854fafed5dSDavid du Colombier pcibiosinit(void)
8864fafed5dSDavid du Colombier {
8874fafed5dSDavid du Colombier 	BIOS32ci ci;
8884fafed5dSDavid du Colombier 	BIOS32si *si;
8894fafed5dSDavid du Colombier 
8904fafed5dSDavid du Colombier 	if((si = bios32open("$PCI")) == nil)
8914fafed5dSDavid du Colombier 		return nil;
8924fafed5dSDavid du Colombier 
8934fafed5dSDavid du Colombier 	memset(&ci, 0, sizeof(BIOS32ci));
8944fafed5dSDavid du Colombier 	ci.eax = 0xB101;
8954fafed5dSDavid du Colombier 	if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){
8964fafed5dSDavid du Colombier 		free(si);
8974fafed5dSDavid du Colombier 		return nil;
8984fafed5dSDavid du Colombier 	}
8994fafed5dSDavid du Colombier 	if(ci.eax & 0x01)
9004fafed5dSDavid du Colombier 		pcimaxdno = 31;
9014fafed5dSDavid du Colombier 	else
9024fafed5dSDavid du Colombier 		pcimaxdno = 15;
9034fafed5dSDavid du Colombier 	pcimaxbno = ci.ecx & 0xff;
9044fafed5dSDavid du Colombier 
9054fafed5dSDavid du Colombier 	return si;
9064fafed5dSDavid du Colombier }
9074fafed5dSDavid du Colombier 
908c91329d7SDavid du Colombier void
pcibussize(Pcidev * root,ulong * msize,ulong * iosize)909c91329d7SDavid du Colombier pcibussize(Pcidev *root, ulong *msize, ulong *iosize)
910c91329d7SDavid du Colombier {
911c91329d7SDavid du Colombier 	*msize = 0;
912c91329d7SDavid du Colombier 	*iosize = 0;
913c91329d7SDavid du Colombier 	pcibusmap(root, msize, iosize, 0);
914c91329d7SDavid du Colombier }
915c91329d7SDavid du Colombier 
9167dd7cddfSDavid du Colombier static void
pcicfginit(void)9177dd7cddfSDavid du Colombier pcicfginit(void)
9187dd7cddfSDavid du Colombier {
9197dd7cddfSDavid du Colombier 	char *p;
9207dd7cddfSDavid du Colombier 	Pcidev **list;
9217dd7cddfSDavid du Colombier 	ulong mema, ioa;
922becaf2abSDavid du Colombier 	int bno, n, pcibios;
9237dd7cddfSDavid du Colombier 
9247dd7cddfSDavid du Colombier 	lock(&pcicfginitlock);
9257dd7cddfSDavid du Colombier 	if(pcicfgmode != -1)
9267dd7cddfSDavid du Colombier 		goto out;
9277dd7cddfSDavid du Colombier 
928becaf2abSDavid du Colombier 	pcibios = 0;
92980ee5cbfSDavid du Colombier 	if(getconf("*nobios"))
93080ee5cbfSDavid du Colombier 		nobios = 1;
931becaf2abSDavid du Colombier 	else if(getconf("*pcibios"))
932becaf2abSDavid du Colombier 		pcibios = 1;
9333ff48bf5SDavid du Colombier 	if(getconf("*nopcirouting"))
9343ff48bf5SDavid du Colombier 		nopcirouting = 1;
9353ff48bf5SDavid du Colombier 
9367dd7cddfSDavid du Colombier 	/*
9377dd7cddfSDavid du Colombier 	 * Try to determine which PCI configuration mode is implemented.
9387dd7cddfSDavid du Colombier 	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
9397dd7cddfSDavid du Colombier 	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
9407dd7cddfSDavid du Colombier 	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
9413ff48bf5SDavid du Colombier 	 * a device behind these addresses so if Mode1 accesses fail try
9423ff48bf5SDavid du Colombier 	 * for Mode2 (Mode2 is deprecated).
9437dd7cddfSDavid du Colombier 	 */
944becaf2abSDavid du Colombier 	if(!pcibios){
945becaf2abSDavid du Colombier 		/*
946becaf2abSDavid du Colombier 		 * Bits [30:24] of PciADDR must be 0,
947becaf2abSDavid du Colombier 		 * according to the spec.
948becaf2abSDavid du Colombier 		 */
949becaf2abSDavid du Colombier 		n = inl(PciADDR);
9506e712d44SDavid du Colombier 		if(!(n & 0x7F000000)){
951becaf2abSDavid du Colombier 			outl(PciADDR, 0x80000000);
952becaf2abSDavid du Colombier 			outb(PciADDR+3, 0);
953becaf2abSDavid du Colombier 			if(inl(PciADDR) & 0x80000000){
9547dd7cddfSDavid du Colombier 				pcicfgmode = 1;
9557dd7cddfSDavid du Colombier 				pcimaxdno = 31;
9567dd7cddfSDavid du Colombier 			}
957becaf2abSDavid du Colombier 		}
958becaf2abSDavid du Colombier 		outl(PciADDR, n);
959becaf2abSDavid du Colombier 
960becaf2abSDavid du Colombier 		if(pcicfgmode < 0){
961becaf2abSDavid du Colombier 			/*
962becaf2abSDavid du Colombier 			 * The 'key' part of PciCSE should be 0.
963becaf2abSDavid du Colombier 			 */
964becaf2abSDavid du Colombier 			n = inb(PciCSE);
965becaf2abSDavid du Colombier 			if(!(n & 0xF0)){
966becaf2abSDavid du Colombier 				outb(PciCSE, 0x0E);
967becaf2abSDavid du Colombier 				if(inb(PciCSE) == 0x0E){
9683ff48bf5SDavid du Colombier 					pcicfgmode = 2;
9693ff48bf5SDavid du Colombier 					pcimaxdno = 15;
9703ff48bf5SDavid du Colombier 				}
9717dd7cddfSDavid du Colombier 			}
972becaf2abSDavid du Colombier 			outb(PciCSE, n);
973becaf2abSDavid du Colombier 		}
974becaf2abSDavid du Colombier 	}
9757dd7cddfSDavid du Colombier 
9764fafed5dSDavid du Colombier 	if(pcicfgmode < 0 || pcibios) {
9774fafed5dSDavid du Colombier 		if((pcibiossi = pcibiosinit()) == nil)
9787dd7cddfSDavid du Colombier 			goto out;
9794fafed5dSDavid du Colombier 		pcicfgrw8 = pcicfgrw8bios;
9804fafed5dSDavid du Colombier 		pcicfgrw16 = pcicfgrw16bios;
9814fafed5dSDavid du Colombier 		pcicfgrw32 = pcicfgrw32bios;
9824fafed5dSDavid du Colombier 		pcicfgmode = 3;
9834fafed5dSDavid du Colombier 	}
9847dd7cddfSDavid du Colombier 
9859a747e4fSDavid du Colombier 	fmtinstall('T', tbdffmt);
9867dd7cddfSDavid du Colombier 
987becaf2abSDavid du Colombier 	if(p = getconf("*pcimaxbno")){
988becaf2abSDavid du Colombier 		n = strtoul(p, 0, 0);
989becaf2abSDavid du Colombier 		if(n < pcimaxbno)
990becaf2abSDavid du Colombier 			pcimaxbno = n;
991becaf2abSDavid du Colombier 	}
992becaf2abSDavid du Colombier 	if(p = getconf("*pcimaxdno")){
993becaf2abSDavid du Colombier 		n = strtoul(p, 0, 0);
994becaf2abSDavid du Colombier 		if(n < pcimaxdno)
995becaf2abSDavid du Colombier 			pcimaxdno = n;
996becaf2abSDavid du Colombier 	}
9977dd7cddfSDavid du Colombier 
9987dd7cddfSDavid du Colombier 	list = &pciroot;
999223a736eSDavid du Colombier 	for(bno = 0; bno <= pcimaxbno; bno++) {
10009a747e4fSDavid du Colombier 		int sbno = bno;
10019a747e4fSDavid du Colombier 		bno = pcilscan(bno, list);
10029a747e4fSDavid du Colombier 
10037dd7cddfSDavid du Colombier 		while(*list)
10047dd7cddfSDavid du Colombier 			list = &(*list)->link;
10059a747e4fSDavid du Colombier 
10069a747e4fSDavid du Colombier 		if (sbno == 0) {
10079a747e4fSDavid du Colombier 			Pcidev *pci;
10089a747e4fSDavid du Colombier 
10099a747e4fSDavid du Colombier 			/*
10109a747e4fSDavid du Colombier 			  * If we have found a PCI-to-Cardbus bridge, make sure
10119a747e4fSDavid du Colombier 			  * it has no valid mappings anymore.
10129a747e4fSDavid du Colombier 			  */
1013c91329d7SDavid du Colombier 			for(pci = pciroot; pci != nil; pci = pci->link){
10149a747e4fSDavid du Colombier 				if (pci->ccrb == 6 && pci->ccru == 7) {
10159a747e4fSDavid du Colombier 					ushort bcr;
10169a747e4fSDavid du Colombier 
10179a747e4fSDavid du Colombier 					/* reset the cardbus */
10189a747e4fSDavid du Colombier 					bcr = pcicfgr16(pci, PciBCR);
10199a747e4fSDavid du Colombier 					pcicfgw16(pci, PciBCR, 0x40 | bcr);
10209a747e4fSDavid du Colombier 					delay(50);
10219a747e4fSDavid du Colombier 				}
10229a747e4fSDavid du Colombier 			}
10239a747e4fSDavid du Colombier 		}
10247dd7cddfSDavid du Colombier 	}
10257dd7cddfSDavid du Colombier 
10267dd7cddfSDavid du Colombier 	if(pciroot == nil)
10277dd7cddfSDavid du Colombier 		goto out;
10287dd7cddfSDavid du Colombier 
102980ee5cbfSDavid du Colombier 	if(nobios) {
10307dd7cddfSDavid du Colombier 		/*
10317dd7cddfSDavid du Colombier 		 * Work out how big the top bus is
10327dd7cddfSDavid du Colombier 		 */
1033c91329d7SDavid du Colombier 		pcibussize(pciroot, &mema, &ioa);
10347dd7cddfSDavid du Colombier 
10357dd7cddfSDavid du Colombier 		/*
10367dd7cddfSDavid du Colombier 		 * Align the windows and map it
10377dd7cddfSDavid du Colombier 		 */
10387dd7cddfSDavid du Colombier 		ioa = 0x1000;
10397dd7cddfSDavid du Colombier 		mema = 0x90000000;
10407dd7cddfSDavid du Colombier 
10417dd7cddfSDavid du Colombier 		pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
10427dd7cddfSDavid du Colombier 
10437dd7cddfSDavid du Colombier 		pcibusmap(pciroot, &mema, &ioa, 1);
10447dd7cddfSDavid du Colombier 		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
10457dd7cddfSDavid du Colombier 
10467dd7cddfSDavid du Colombier 		unlock(&pcicfginitlock);
10477dd7cddfSDavid du Colombier 		return;
10487dd7cddfSDavid du Colombier 	}
10499a747e4fSDavid du Colombier 
10503ff48bf5SDavid du Colombier 	if (!nopcirouting)
10519a747e4fSDavid du Colombier 		pcirouting();
10529a747e4fSDavid du Colombier 
10537dd7cddfSDavid du Colombier out:
10544de34a7eSDavid du Colombier 	pcireservemem();
10557dd7cddfSDavid du Colombier 	unlock(&pcicfginitlock);
10569a747e4fSDavid du Colombier 
10573ff48bf5SDavid du Colombier 	if(getconf("*pcihinv"))
10583ff48bf5SDavid du Colombier 		pcihinv(nil);
10597dd7cddfSDavid du Colombier }
10607dd7cddfSDavid du Colombier 
10614de34a7eSDavid du Colombier static void
pcireservemem(void)10624de34a7eSDavid du Colombier pcireservemem(void)
10634de34a7eSDavid du Colombier {
10644de34a7eSDavid du Colombier 	int i;
10654de34a7eSDavid du Colombier 	Pcidev *p;
10664de34a7eSDavid du Colombier 
10674de34a7eSDavid du Colombier 	/*
10684de34a7eSDavid du Colombier 	 * mark all the physical address space claimed by pci devices
10694de34a7eSDavid du Colombier 	 * as in use, so that upaalloc doesn't give it out.
10704de34a7eSDavid du Colombier 	 */
10714de34a7eSDavid du Colombier 	for(p=pciroot; p; p=p->list)
10724de34a7eSDavid du Colombier 		for(i=0; i<nelem(p->mem); i++)
10734de34a7eSDavid du Colombier 			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
10744de34a7eSDavid du Colombier 				upareserve(p->mem[i].bar&~0x0F, p->mem[i].size);
10754de34a7eSDavid du Colombier }
10764de34a7eSDavid du Colombier 
10777dd7cddfSDavid du Colombier static int
pcicfgrw8raw(int tbdf,int rno,int data,int read)10784fafed5dSDavid du Colombier pcicfgrw8raw(int tbdf, int rno, int data, int read)
10797dd7cddfSDavid du Colombier {
10807dd7cddfSDavid du Colombier 	int o, type, x;
10817dd7cddfSDavid du Colombier 
10827dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
10837dd7cddfSDavid du Colombier 		pcicfginit();
10847dd7cddfSDavid du Colombier 
10857dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
10867dd7cddfSDavid du Colombier 		type = 0x01;
10877dd7cddfSDavid du Colombier 	else
10887dd7cddfSDavid du Colombier 		type = 0x00;
10897dd7cddfSDavid du Colombier 	x = -1;
10907dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
10917dd7cddfSDavid du Colombier 		return x;
10927dd7cddfSDavid du Colombier 
10937dd7cddfSDavid du Colombier 	lock(&pcicfglock);
10947dd7cddfSDavid du Colombier 	switch(pcicfgmode){
10957dd7cddfSDavid du Colombier 
10967dd7cddfSDavid du Colombier 	case 1:
10977dd7cddfSDavid du Colombier 		o = rno & 0x03;
10987dd7cddfSDavid du Colombier 		rno &= ~0x03;
10997dd7cddfSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
11007dd7cddfSDavid du Colombier 		if(read)
11017dd7cddfSDavid du Colombier 			x = inb(PciDATA+o);
11027dd7cddfSDavid du Colombier 		else
11037dd7cddfSDavid du Colombier 			outb(PciDATA+o, data);
11047dd7cddfSDavid du Colombier 		outl(PciADDR, 0);
11057dd7cddfSDavid du Colombier 		break;
11067dd7cddfSDavid du Colombier 
11077dd7cddfSDavid du Colombier 	case 2:
11087dd7cddfSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
11097dd7cddfSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
11107dd7cddfSDavid du Colombier 		if(read)
11117dd7cddfSDavid du Colombier 			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
11127dd7cddfSDavid du Colombier 		else
11137dd7cddfSDavid du Colombier 			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
11147dd7cddfSDavid du Colombier 		outb(PciCSE, 0);
11157dd7cddfSDavid du Colombier 		break;
11167dd7cddfSDavid du Colombier 	}
11177dd7cddfSDavid du Colombier 	unlock(&pcicfglock);
11187dd7cddfSDavid du Colombier 
11197dd7cddfSDavid du Colombier 	return x;
11207dd7cddfSDavid du Colombier }
11217dd7cddfSDavid du Colombier 
11227dd7cddfSDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)11237dd7cddfSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
11247dd7cddfSDavid du Colombier {
11257dd7cddfSDavid du Colombier 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
11267dd7cddfSDavid du Colombier }
11277dd7cddfSDavid du Colombier 
11287dd7cddfSDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)11297dd7cddfSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
11307dd7cddfSDavid du Colombier {
11317dd7cddfSDavid du Colombier 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
11327dd7cddfSDavid du Colombier }
11337dd7cddfSDavid du Colombier 
11347dd7cddfSDavid du Colombier static int
pcicfgrw16raw(int tbdf,int rno,int data,int read)11354fafed5dSDavid du Colombier pcicfgrw16raw(int tbdf, int rno, int data, int read)
11367dd7cddfSDavid du Colombier {
11377dd7cddfSDavid du Colombier 	int o, type, x;
11387dd7cddfSDavid du Colombier 
11397dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
11407dd7cddfSDavid du Colombier 		pcicfginit();
11417dd7cddfSDavid du Colombier 
11427dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
11437dd7cddfSDavid du Colombier 		type = 0x01;
11447dd7cddfSDavid du Colombier 	else
11457dd7cddfSDavid du Colombier 		type = 0x00;
11467dd7cddfSDavid du Colombier 	x = -1;
11477dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
11487dd7cddfSDavid du Colombier 		return x;
11497dd7cddfSDavid du Colombier 
11507dd7cddfSDavid du Colombier 	lock(&pcicfglock);
11517dd7cddfSDavid du Colombier 	switch(pcicfgmode){
11527dd7cddfSDavid du Colombier 
11537dd7cddfSDavid du Colombier 	case 1:
11547dd7cddfSDavid du Colombier 		o = rno & 0x02;
11557dd7cddfSDavid du Colombier 		rno &= ~0x03;
11567dd7cddfSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
11577dd7cddfSDavid du Colombier 		if(read)
11587dd7cddfSDavid du Colombier 			x = ins(PciDATA+o);
11597dd7cddfSDavid du Colombier 		else
11607dd7cddfSDavid du Colombier 			outs(PciDATA+o, data);
11617dd7cddfSDavid du Colombier 		outl(PciADDR, 0);
11627dd7cddfSDavid du Colombier 		break;
11637dd7cddfSDavid du Colombier 
11647dd7cddfSDavid du Colombier 	case 2:
11657dd7cddfSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
11667dd7cddfSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
11677dd7cddfSDavid du Colombier 		if(read)
11687dd7cddfSDavid du Colombier 			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
11697dd7cddfSDavid du Colombier 		else
11707dd7cddfSDavid du Colombier 			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
11717dd7cddfSDavid du Colombier 		outb(PciCSE, 0);
11727dd7cddfSDavid du Colombier 		break;
11737dd7cddfSDavid du Colombier 	}
11747dd7cddfSDavid du Colombier 	unlock(&pcicfglock);
11757dd7cddfSDavid du Colombier 
11767dd7cddfSDavid du Colombier 	return x;
11777dd7cddfSDavid du Colombier }
11787dd7cddfSDavid du Colombier 
11797dd7cddfSDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)11807dd7cddfSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
11817dd7cddfSDavid du Colombier {
11827dd7cddfSDavid du Colombier 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
11837dd7cddfSDavid du Colombier }
11847dd7cddfSDavid du Colombier 
11857dd7cddfSDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)11867dd7cddfSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
11877dd7cddfSDavid du Colombier {
11887dd7cddfSDavid du Colombier 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
11897dd7cddfSDavid du Colombier }
11907dd7cddfSDavid du Colombier 
11917dd7cddfSDavid du Colombier static int
pcicfgrw32raw(int tbdf,int rno,int data,int read)11924fafed5dSDavid du Colombier pcicfgrw32raw(int tbdf, int rno, int data, int read)
11937dd7cddfSDavid du Colombier {
11947dd7cddfSDavid du Colombier 	int type, x;
11957dd7cddfSDavid du Colombier 
11967dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
11977dd7cddfSDavid du Colombier 		pcicfginit();
11987dd7cddfSDavid du Colombier 
11997dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
12007dd7cddfSDavid du Colombier 		type = 0x01;
12017dd7cddfSDavid du Colombier 	else
12027dd7cddfSDavid du Colombier 		type = 0x00;
12037dd7cddfSDavid du Colombier 	x = -1;
12047dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
12057dd7cddfSDavid du Colombier 		return x;
12067dd7cddfSDavid du Colombier 
12077dd7cddfSDavid du Colombier 	lock(&pcicfglock);
12087dd7cddfSDavid du Colombier 	switch(pcicfgmode){
12097dd7cddfSDavid du Colombier 
12107dd7cddfSDavid du Colombier 	case 1:
12117dd7cddfSDavid du Colombier 		rno &= ~0x03;
12127dd7cddfSDavid du Colombier 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
12137dd7cddfSDavid du Colombier 		if(read)
12147dd7cddfSDavid du Colombier 			x = inl(PciDATA);
12157dd7cddfSDavid du Colombier 		else
12167dd7cddfSDavid du Colombier 			outl(PciDATA, data);
12177dd7cddfSDavid du Colombier 		outl(PciADDR, 0);
12187dd7cddfSDavid du Colombier 		break;
12197dd7cddfSDavid du Colombier 
12207dd7cddfSDavid du Colombier 	case 2:
12217dd7cddfSDavid du Colombier 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
12227dd7cddfSDavid du Colombier 		outb(PciFORWARD, BUSBNO(tbdf));
12237dd7cddfSDavid du Colombier 		if(read)
12247dd7cddfSDavid du Colombier 			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
12257dd7cddfSDavid du Colombier 		else
12267dd7cddfSDavid du Colombier 			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
12277dd7cddfSDavid du Colombier 		outb(PciCSE, 0);
12287dd7cddfSDavid du Colombier 		break;
12297dd7cddfSDavid du Colombier 	}
12307dd7cddfSDavid du Colombier 	unlock(&pcicfglock);
12317dd7cddfSDavid du Colombier 
12327dd7cddfSDavid du Colombier 	return x;
12337dd7cddfSDavid du Colombier }
12347dd7cddfSDavid du Colombier 
12357dd7cddfSDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)12367dd7cddfSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
12377dd7cddfSDavid du Colombier {
12387dd7cddfSDavid du Colombier 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
12397dd7cddfSDavid du Colombier }
12407dd7cddfSDavid du Colombier 
12417dd7cddfSDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)12427dd7cddfSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
12437dd7cddfSDavid du Colombier {
12447dd7cddfSDavid du Colombier 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
12457dd7cddfSDavid du Colombier }
12467dd7cddfSDavid du Colombier 
12477dd7cddfSDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)12487dd7cddfSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
12497dd7cddfSDavid du Colombier {
12507dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
12517dd7cddfSDavid du Colombier 		pcicfginit();
12527dd7cddfSDavid du Colombier 
12537dd7cddfSDavid du Colombier 	if(prev == nil)
12547dd7cddfSDavid du Colombier 		prev = pcilist;
12557dd7cddfSDavid du Colombier 	else
12567dd7cddfSDavid du Colombier 		prev = prev->list;
12577dd7cddfSDavid du Colombier 
12587dd7cddfSDavid du Colombier 	while(prev != nil){
12597dd7cddfSDavid du Colombier 		if((vid == 0 || prev->vid == vid)
12607dd7cddfSDavid du Colombier 		&& (did == 0 || prev->did == did))
12617dd7cddfSDavid du Colombier 			break;
12627dd7cddfSDavid du Colombier 		prev = prev->list;
12637dd7cddfSDavid du Colombier 	}
12647dd7cddfSDavid du Colombier 	return prev;
12657dd7cddfSDavid du Colombier }
12667dd7cddfSDavid du Colombier 
12677dd7cddfSDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)12687dd7cddfSDavid du Colombier pcimatchtbdf(int tbdf)
12697dd7cddfSDavid du Colombier {
12707dd7cddfSDavid du Colombier 	Pcidev *pcidev;
12717dd7cddfSDavid du Colombier 
12727dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
12737dd7cddfSDavid du Colombier 		pcicfginit();
12747dd7cddfSDavid du Colombier 
12757dd7cddfSDavid du Colombier 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
12767dd7cddfSDavid du Colombier 		if(pcidev->tbdf == tbdf)
12777dd7cddfSDavid du Colombier 			break;
12787dd7cddfSDavid du Colombier 	}
12797dd7cddfSDavid du Colombier 	return pcidev;
12807dd7cddfSDavid du Colombier }
12817dd7cddfSDavid du Colombier 
12829a747e4fSDavid du Colombier uchar
pciipin(Pcidev * pci,uchar pin)12839a747e4fSDavid du Colombier pciipin(Pcidev *pci, uchar pin)
12849a747e4fSDavid du Colombier {
12859a747e4fSDavid du Colombier 	if (pci == nil)
12869a747e4fSDavid du Colombier 		pci = pcilist;
12879a747e4fSDavid du Colombier 
12889a747e4fSDavid du Colombier 	while (pci) {
12899a747e4fSDavid du Colombier 		uchar intl;
12909a747e4fSDavid du Colombier 
12919a747e4fSDavid du Colombier 		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
12929a747e4fSDavid du Colombier 			return pci->intl;
12939a747e4fSDavid du Colombier 
12949a747e4fSDavid du Colombier 		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
12959a747e4fSDavid du Colombier 			return intl;
12969a747e4fSDavid du Colombier 
12979a747e4fSDavid du Colombier 		pci = pci->list;
12989a747e4fSDavid du Colombier 	}
12999a747e4fSDavid du Colombier 	return 0;
13009a747e4fSDavid du Colombier }
13019a747e4fSDavid du Colombier 
13029a747e4fSDavid du Colombier static void
pcilhinv(Pcidev * p)13039a747e4fSDavid du Colombier pcilhinv(Pcidev* p)
13047dd7cddfSDavid du Colombier {
13057dd7cddfSDavid du Colombier 	int i;
13067dd7cddfSDavid du Colombier 	Pcidev *t;
13077dd7cddfSDavid du Colombier 
13087dd7cddfSDavid du Colombier 	if(p == nil) {
13097dd7cddfSDavid du Colombier 		putstrn(PCICONS.output, PCICONS.ptr);
13107dd7cddfSDavid du Colombier 		p = pciroot;
13117dd7cddfSDavid du Colombier 		print("bus dev type vid  did intl memory\n");
13127dd7cddfSDavid du Colombier 	}
13137dd7cddfSDavid du Colombier 	for(t = p; t != nil; t = t->link) {
13147dd7cddfSDavid du Colombier 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
13157dd7cddfSDavid du Colombier 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
13167dd7cddfSDavid du Colombier 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
13177dd7cddfSDavid du Colombier 
13187dd7cddfSDavid du Colombier 		for(i = 0; i < nelem(p->mem); i++) {
13197dd7cddfSDavid du Colombier 			if(t->mem[i].size == 0)
13207dd7cddfSDavid du Colombier 				continue;
13217dd7cddfSDavid du Colombier 			print("%d:%.8lux %d ", i,
13227dd7cddfSDavid du Colombier 				t->mem[i].bar, t->mem[i].size);
13237dd7cddfSDavid du Colombier 		}
13247dd7cddfSDavid du Colombier 		if(t->ioa.bar || t->ioa.size)
13257dd7cddfSDavid du Colombier 			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
13267dd7cddfSDavid du Colombier 		if(t->mema.bar || t->mema.size)
13277dd7cddfSDavid du Colombier 			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
13287dd7cddfSDavid du Colombier 		if(t->bridge)
13297dd7cddfSDavid du Colombier 			print("->%d", BUSBNO(t->bridge->tbdf));
13307dd7cddfSDavid du Colombier 		print("\n");
13317dd7cddfSDavid du Colombier 	}
13327dd7cddfSDavid du Colombier 	while(p != nil) {
13337dd7cddfSDavid du Colombier 		if(p->bridge != nil)
13349a747e4fSDavid du Colombier 			pcilhinv(p->bridge);
13357dd7cddfSDavid du Colombier 		p = p->link;
13367dd7cddfSDavid du Colombier 	}
13377dd7cddfSDavid du Colombier }
13387dd7cddfSDavid du Colombier 
13397dd7cddfSDavid du Colombier void
pcihinv(Pcidev * p)13409a747e4fSDavid du Colombier pcihinv(Pcidev* p)
13419a747e4fSDavid du Colombier {
13429a747e4fSDavid du Colombier 	if(pcicfgmode == -1)
13439a747e4fSDavid du Colombier 		pcicfginit();
13449a747e4fSDavid du Colombier 	lock(&pcicfginitlock);
13459a747e4fSDavid du Colombier 	pcilhinv(p);
13469a747e4fSDavid du Colombier 	unlock(&pcicfginitlock);
13479a747e4fSDavid du Colombier }
13489a747e4fSDavid du Colombier 
13499a747e4fSDavid du Colombier void
pcireset(void)13507dd7cddfSDavid du Colombier pcireset(void)
13517dd7cddfSDavid du Colombier {
13527dd7cddfSDavid du Colombier 	Pcidev *p;
13537dd7cddfSDavid du Colombier 
13547dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
13557dd7cddfSDavid du Colombier 		pcicfginit();
13567dd7cddfSDavid du Colombier 
13577dd7cddfSDavid du Colombier 	for(p = pcilist; p != nil; p = p->list) {
13589a747e4fSDavid du Colombier 		/* don't mess with the bridges */
13599a747e4fSDavid du Colombier 		if(p->ccrb == 0x06)
13609a747e4fSDavid du Colombier 			continue;
13619a747e4fSDavid du Colombier 		pciclrbme(p);
13627dd7cddfSDavid du Colombier 	}
13637dd7cddfSDavid du Colombier }
13647dd7cddfSDavid du Colombier 
13657dd7cddfSDavid du Colombier void
pcisetioe(Pcidev * p)1366220e960cSDavid du Colombier pcisetioe(Pcidev* p)
1367220e960cSDavid du Colombier {
1368e569ccb5SDavid du Colombier 	p->pcr |= IOen;
1369e569ccb5SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
1370220e960cSDavid du Colombier }
1371220e960cSDavid du Colombier 
1372220e960cSDavid du Colombier void
pciclrioe(Pcidev * p)1373220e960cSDavid du Colombier pciclrioe(Pcidev* p)
1374220e960cSDavid du Colombier {
1375e569ccb5SDavid du Colombier 	p->pcr &= ~IOen;
1376e569ccb5SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
1377220e960cSDavid du Colombier }
1378220e960cSDavid du Colombier 
1379220e960cSDavid du Colombier void
pcisetbme(Pcidev * p)13807dd7cddfSDavid du Colombier pcisetbme(Pcidev* p)
13817dd7cddfSDavid du Colombier {
1382e569ccb5SDavid du Colombier 	p->pcr |= MASen;
1383e569ccb5SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
13847dd7cddfSDavid du Colombier }
13859a747e4fSDavid du Colombier 
13869a747e4fSDavid du Colombier void
pciclrbme(Pcidev * p)13879a747e4fSDavid du Colombier pciclrbme(Pcidev* p)
13889a747e4fSDavid du Colombier {
1389e569ccb5SDavid du Colombier 	p->pcr &= ~MASen;
1390e569ccb5SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
1391e569ccb5SDavid du Colombier }
13929a747e4fSDavid du Colombier 
1393d8f3f65eSDavid du Colombier void
pcisetmwi(Pcidev * p)1394d8f3f65eSDavid du Colombier pcisetmwi(Pcidev* p)
1395d8f3f65eSDavid du Colombier {
1396d8f3f65eSDavid du Colombier 	p->pcr |= MemWrInv;
1397d8f3f65eSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
1398d8f3f65eSDavid du Colombier }
1399d8f3f65eSDavid du Colombier 
1400d8f3f65eSDavid du Colombier void
pciclrmwi(Pcidev * p)1401d8f3f65eSDavid du Colombier pciclrmwi(Pcidev* p)
1402d8f3f65eSDavid du Colombier {
1403d8f3f65eSDavid du Colombier 	p->pcr &= ~MemWrInv;
1404d8f3f65eSDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
1405d8f3f65eSDavid du Colombier }
1406d8f3f65eSDavid du Colombier 
1407ee52d9b2SDavid du Colombier int
pcienumcaps(Pcidev * p,int (* fmatch)(Pcidev *,int,int,int),int arg)1408*0336b12dSDavid du Colombier pcienumcaps(Pcidev* p, int (*fmatch)(Pcidev*, int, int, int), int arg)
1409e569ccb5SDavid du Colombier {
1410*0336b12dSDavid du Colombier 	int i, r, cap, off;
1411e569ccb5SDavid du Colombier 
1412ee52d9b2SDavid du Colombier 	/* status register bit 4 has capabilities */
1413ee52d9b2SDavid du Colombier 	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
1414e569ccb5SDavid du Colombier 		return -1;
1415ee52d9b2SDavid du Colombier 	switch(pcicfgr8(p, PciHDT) & 0x7f){
1416e569ccb5SDavid du Colombier 	default:
1417e569ccb5SDavid du Colombier 		return -1;
1418e569ccb5SDavid du Colombier 	case 0:					/* all other */
1419e569ccb5SDavid du Colombier 	case 1:					/* PCI to PCI bridge */
1420ee52d9b2SDavid du Colombier 		off = 0x34;
1421e569ccb5SDavid du Colombier 		break;
1422e569ccb5SDavid du Colombier 	case 2:					/* CardBus bridge */
1423ee52d9b2SDavid du Colombier 		off = 0x14;
1424e569ccb5SDavid du Colombier 		break;
1425e569ccb5SDavid du Colombier 	}
1426ee52d9b2SDavid du Colombier 	for(i = 48; i--;){
1427ee52d9b2SDavid du Colombier 		off = pcicfgr8(p, off);
1428ee52d9b2SDavid du Colombier 		if(off < 0x40 || (off & 3))
1429ee52d9b2SDavid du Colombier 			break;
1430ee52d9b2SDavid du Colombier 		off &= ~3;
1431*0336b12dSDavid du Colombier 		cap = pcicfgr8(p, off);
1432*0336b12dSDavid du Colombier 		if(cap == 0xff)
1433ee52d9b2SDavid du Colombier 			break;
1434*0336b12dSDavid du Colombier 		r = (*fmatch)(p, cap, off, arg);
1435*0336b12dSDavid du Colombier 		if(r < 0)
1436*0336b12dSDavid du Colombier 			break;
1437*0336b12dSDavid du Colombier 		if(r == 0)
1438ee52d9b2SDavid du Colombier 			return off;
1439ee52d9b2SDavid du Colombier 		off++;
1440e569ccb5SDavid du Colombier 	}
1441e569ccb5SDavid du Colombier 
1442e569ccb5SDavid du Colombier 	return -1;
1443e569ccb5SDavid du Colombier }
1444e569ccb5SDavid du Colombier 
1445*0336b12dSDavid du Colombier static int
matchcap(Pcidev *,int cap,int,int arg)1446*0336b12dSDavid du Colombier matchcap(Pcidev*, int cap, int, int arg)
1447*0336b12dSDavid du Colombier {
1448*0336b12dSDavid du Colombier 	return cap != arg;
1449*0336b12dSDavid du Colombier }
1450*0336b12dSDavid du Colombier 
1451*0336b12dSDavid du Colombier static int
matchhtcap(Pcidev * p,int cap,int off,int arg)1452*0336b12dSDavid du Colombier matchhtcap(Pcidev* p, int cap, int off, int arg)
1453*0336b12dSDavid du Colombier {
1454*0336b12dSDavid du Colombier 	int mask;
1455*0336b12dSDavid du Colombier 
1456*0336b12dSDavid du Colombier 	if(cap != PciCapHTC)
1457*0336b12dSDavid du Colombier 		return 1;
1458*0336b12dSDavid du Colombier 	if(arg == 0x00 || arg == 0x20)
1459*0336b12dSDavid du Colombier 		mask = 0xE0;
1460*0336b12dSDavid du Colombier 	else
1461*0336b12dSDavid du Colombier 		mask = 0xF8;
1462*0336b12dSDavid du Colombier 	cap = pcicfgr8(p, off+3);
1463*0336b12dSDavid du Colombier 	return (cap & mask) != arg;
1464*0336b12dSDavid du Colombier }
1465*0336b12dSDavid du Colombier 
1466*0336b12dSDavid du Colombier int
pcicap(Pcidev * p,int cap)1467*0336b12dSDavid du Colombier pcicap(Pcidev* p, int cap)
1468*0336b12dSDavid du Colombier {
1469*0336b12dSDavid du Colombier 	return pcienumcaps(p, matchcap, cap);
1470*0336b12dSDavid du Colombier }
1471*0336b12dSDavid du Colombier 
1472*0336b12dSDavid du Colombier int
pcihtcap(Pcidev * p,int cap)1473*0336b12dSDavid du Colombier pcihtcap(Pcidev* p, int cap)
1474*0336b12dSDavid du Colombier {
1475*0336b12dSDavid du Colombier 	return pcienumcaps(p, matchhtcap, cap);
1476*0336b12dSDavid du Colombier }
1477*0336b12dSDavid du Colombier 
1478e569ccb5SDavid du Colombier int
pcigetpms(Pcidev * p)1479e569ccb5SDavid du Colombier pcigetpms(Pcidev* p)
1480e569ccb5SDavid du Colombier {
1481e569ccb5SDavid du Colombier 	int pmcsr, ptr;
1482e569ccb5SDavid du Colombier 
1483ee52d9b2SDavid du Colombier 	if((ptr = pcicap(p, PciCapPMG)) == -1)
1484e569ccb5SDavid du Colombier 		return -1;
1485e569ccb5SDavid du Colombier 
1486e569ccb5SDavid du Colombier 	/*
1487e569ccb5SDavid du Colombier 	 * Power Management Register Block:
1488e569ccb5SDavid du Colombier 	 *  offset 0:	Capability ID
1489e569ccb5SDavid du Colombier 	 *	   1:	next item pointer
1490e569ccb5SDavid du Colombier 	 *	   2:	capabilities
1491e569ccb5SDavid du Colombier 	 *	   4:	control/status
1492e569ccb5SDavid du Colombier 	 *	   6:	bridge support extensions
1493e569ccb5SDavid du Colombier 	 *	   7:	data
1494e569ccb5SDavid du Colombier 	 */
1495e569ccb5SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
1496e569ccb5SDavid du Colombier 
1497e569ccb5SDavid du Colombier 	return pmcsr & 0x0003;
1498e569ccb5SDavid du Colombier }
1499e569ccb5SDavid du Colombier 
1500e569ccb5SDavid du Colombier int
pcisetpms(Pcidev * p,int state)1501e569ccb5SDavid du Colombier pcisetpms(Pcidev* p, int state)
1502e569ccb5SDavid du Colombier {
1503e569ccb5SDavid du Colombier 	int ostate, pmc, pmcsr, ptr;
1504e569ccb5SDavid du Colombier 
1505ee52d9b2SDavid du Colombier 	if((ptr = pcicap(p, PciCapPMG)) == -1)
1506e569ccb5SDavid du Colombier 		return -1;
1507e569ccb5SDavid du Colombier 
1508e569ccb5SDavid du Colombier 	pmc = pcicfgr16(p, ptr+2);
1509e569ccb5SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
1510e569ccb5SDavid du Colombier 	ostate = pmcsr & 0x0003;
1511e569ccb5SDavid du Colombier 	pmcsr &= ~0x0003;
1512e569ccb5SDavid du Colombier 
1513e569ccb5SDavid du Colombier 	switch(state){
1514e569ccb5SDavid du Colombier 	default:
1515e569ccb5SDavid du Colombier 		return -1;
1516e569ccb5SDavid du Colombier 	case 0:
1517e569ccb5SDavid du Colombier 		break;
1518e569ccb5SDavid du Colombier 	case 1:
1519e569ccb5SDavid du Colombier 		if(!(pmc & 0x0200))
1520e569ccb5SDavid du Colombier 			return -1;
1521e569ccb5SDavid du Colombier 		break;
1522e569ccb5SDavid du Colombier 	case 2:
1523e569ccb5SDavid du Colombier 		if(!(pmc & 0x0400))
1524e569ccb5SDavid du Colombier 			return -1;
1525e569ccb5SDavid du Colombier 		break;
1526e569ccb5SDavid du Colombier 	case 3:
1527e569ccb5SDavid du Colombier 		break;
1528e569ccb5SDavid du Colombier 	}
1529e569ccb5SDavid du Colombier 	pmcsr |= state;
1530e569ccb5SDavid du Colombier 	pcicfgw16(p, ptr+4, pmcsr);
1531e569ccb5SDavid du Colombier 
1532e569ccb5SDavid du Colombier 	return ostate;
15339a747e4fSDavid du Colombier }
1534