xref: /plan9/sys/src/cmd/aux/vga/pci.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier 
57dd7cddfSDavid du Colombier #include "pci.h"
6*9a747e4fSDavid du Colombier #include "vga.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier /*
97dd7cddfSDavid du Colombier  * PCI support code.
107dd7cddfSDavid du Colombier  * There really should be a driver for this, it's not terribly safe
117dd7cddfSDavid du Colombier  * without locks or restrictions on what can be poked (e.g. Axil NX801).
127dd7cddfSDavid du Colombier  */
137dd7cddfSDavid du Colombier enum {					/* configuration mechanism #1 */
147dd7cddfSDavid du Colombier 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
157dd7cddfSDavid du Colombier 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier 					/* configuration mechanism #2 */
187dd7cddfSDavid du Colombier 	PciCSE		= 0xCF8,	/* configuration space enable */
197dd7cddfSDavid du Colombier 	PciFORWARD	= 0xCFA,	/* which bus */
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier 	MaxFNO		= 7,
227dd7cddfSDavid du Colombier 	MaxUBN		= 255,
237dd7cddfSDavid du Colombier };
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier static int pcicfgmode = -1;
267dd7cddfSDavid du Colombier static int pcimaxdno;
277dd7cddfSDavid du Colombier static Pcidev* pciroot;
287dd7cddfSDavid du Colombier static Pcidev* pcilist;
297dd7cddfSDavid du Colombier static Pcidev* pcitail;
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier static int pcicfgrw32(int, int, int, int);
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier static int
pciscan(int bno,Pcidev ** list)347dd7cddfSDavid du Colombier pciscan(int bno, Pcidev** list)
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier 	ulong v;
377dd7cddfSDavid du Colombier 	Pcidev *p, *head, *tail;
387dd7cddfSDavid du Colombier 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier 	maxubn = bno;
417dd7cddfSDavid du Colombier 	head = nil;
427dd7cddfSDavid du Colombier 	tail = nil;
437dd7cddfSDavid du Colombier 	for(dno = 0; dno <= pcimaxdno; dno++){
447dd7cddfSDavid du Colombier 		maxfno = 0;
457dd7cddfSDavid du Colombier 		for(fno = 0; fno <= maxfno; fno++){
467dd7cddfSDavid du Colombier 			/*
477dd7cddfSDavid du Colombier 			 * For this possible device, form the bus+device+function
487dd7cddfSDavid du Colombier 			 * triplet needed to address it and try to read the vendor
497dd7cddfSDavid du Colombier 			 * and device ID. If successful, allocate a device struct
507dd7cddfSDavid du Colombier 			 * and start to fill it in with some useful information from
517dd7cddfSDavid du Colombier 			 * the device's configuration space.
527dd7cddfSDavid du Colombier 			 */
537dd7cddfSDavid du Colombier 			tbdf = MKBUS(BusPCI, bno, dno, fno);
547dd7cddfSDavid du Colombier 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
557dd7cddfSDavid du Colombier 			if(l == 0xFFFFFFFF || l == 0)
567dd7cddfSDavid du Colombier 				continue;
577dd7cddfSDavid du Colombier 			p = mallocz(sizeof(*p), 1);
587dd7cddfSDavid du Colombier 			p->tbdf = tbdf;
597dd7cddfSDavid du Colombier 			p->vid = l;
607dd7cddfSDavid du Colombier 			p->did = l>>16;
61*9a747e4fSDavid du Colombier 			p->rid = pcicfgr8(p, PciRID);
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier 			if(pcilist != nil)
647dd7cddfSDavid du Colombier 				pcitail->list = p;
657dd7cddfSDavid du Colombier 			else
667dd7cddfSDavid du Colombier 				pcilist = p;
677dd7cddfSDavid du Colombier 			pcitail = p;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 			p->intl = pcicfgr8(p, PciINTL);
707dd7cddfSDavid du Colombier 			p->ccru = pcicfgr16(p, PciCCRu);
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier 			/*
737dd7cddfSDavid du Colombier 			 * If the device is a multi-function device adjust the
747dd7cddfSDavid du Colombier 			 * loop count so all possible functions are checked.
757dd7cddfSDavid du Colombier 			 */
767dd7cddfSDavid du Colombier 			hdt = pcicfgr8(p, PciHDT);
777dd7cddfSDavid du Colombier 			if(hdt & 0x80)
787dd7cddfSDavid du Colombier 				maxfno = MaxFNO;
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier 			/*
817dd7cddfSDavid du Colombier 			 * If appropriate, read the base address registers
827dd7cddfSDavid du Colombier 			 * and work out the sizes.
837dd7cddfSDavid du Colombier 			 */
847dd7cddfSDavid du Colombier 			switch(p->ccru>>8){
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier 			case 0x01:		/* mass storage controller */
877dd7cddfSDavid du Colombier 			case 0x02:		/* network controller */
887dd7cddfSDavid du Colombier 			case 0x03:		/* display controller */
897dd7cddfSDavid du Colombier 			case 0x04:		/* multimedia device */
907dd7cddfSDavid du Colombier 			case 0x07:		/* simple communication controllers */
917dd7cddfSDavid du Colombier 			case 0x08:		/* base system peripherals */
927dd7cddfSDavid du Colombier 			case 0x09:		/* input devices */
937dd7cddfSDavid du Colombier 			case 0x0A:		/* docking stations */
947dd7cddfSDavid du Colombier 			case 0x0B:		/* processors */
957dd7cddfSDavid du Colombier 			case 0x0C:		/* serial bus controllers */
967dd7cddfSDavid du Colombier 				if((hdt & 0x7F) != 0)
977dd7cddfSDavid du Colombier 					break;
987dd7cddfSDavid du Colombier 				rno = PciBAR0 - 4;
997dd7cddfSDavid du Colombier 				for(i = 0; i < nelem(p->mem); i++){
1007dd7cddfSDavid du Colombier 					rno += 4;
1017dd7cddfSDavid du Colombier 					p->mem[i].bar = pcicfgr32(p, rno);
1027dd7cddfSDavid du Colombier 					pcicfgw32(p, rno, -1);
1037dd7cddfSDavid du Colombier 					v = pcicfgr32(p, rno);
1047dd7cddfSDavid du Colombier 					pcicfgw32(p, rno, p->mem[i].bar);
1057dd7cddfSDavid du Colombier 					p->mem[i].size = -(v & ~0xF);
1067dd7cddfSDavid du Colombier 				}
1077dd7cddfSDavid du Colombier 				break;
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 			case 0x00:
1107dd7cddfSDavid du Colombier 			case 0x05:		/* memory controller */
1117dd7cddfSDavid du Colombier 			case 0x06:		/* bridge device */
1127dd7cddfSDavid du Colombier 			default:
1137dd7cddfSDavid du Colombier 				break;
1147dd7cddfSDavid du Colombier 			}
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 			if(head != nil)
1177dd7cddfSDavid du Colombier 				tail->link = p;
1187dd7cddfSDavid du Colombier 			else
1197dd7cddfSDavid du Colombier 				head = p;
1207dd7cddfSDavid du Colombier 			tail = p;
1217dd7cddfSDavid du Colombier 		}
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	*list = head;
1257dd7cddfSDavid du Colombier 	for(p = head; p != nil; p = p->link){
1267dd7cddfSDavid du Colombier 		/*
1277dd7cddfSDavid du Colombier 		 * Find PCI-PCI bridges and recursively descend the tree.
1287dd7cddfSDavid du Colombier 		 */
1297dd7cddfSDavid du Colombier 		if(p->ccru != ((0x06<<8)|0x04))
1307dd7cddfSDavid du Colombier 			continue;
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 		/*
1337dd7cddfSDavid du Colombier 		 * If the secondary or subordinate bus number is not initialised
1347dd7cddfSDavid du Colombier 		 * try to do what the PCI BIOS should have done and fill in the
1357dd7cddfSDavid du Colombier 		 * numbers as the tree is descended. On the way down the subordinate
1367dd7cddfSDavid du Colombier 		 * bus number is set to the maximum as it's not known how many
1377dd7cddfSDavid du Colombier 		 * buses are behind this one; the final value is set on the way
1387dd7cddfSDavid du Colombier 		 * back up.
1397dd7cddfSDavid du Colombier 		 */
1407dd7cddfSDavid du Colombier 		sbn = pcicfgr8(p, PciSBN);
1417dd7cddfSDavid du Colombier 		ubn = pcicfgr8(p, PciUBN);
1427dd7cddfSDavid du Colombier 		if(sbn == 0 || ubn == 0){
1437dd7cddfSDavid du Colombier 			sbn = maxubn+1;
1447dd7cddfSDavid du Colombier 			/*
1457dd7cddfSDavid du Colombier 			 * Make sure memory, I/O and master enables are off,
1467dd7cddfSDavid du Colombier 			 * set the primary, secondary and subordinate bus numbers
1477dd7cddfSDavid du Colombier 			 * and clear the secondary status before attempting to
1487dd7cddfSDavid du Colombier 			 * scan the secondary bus.
1497dd7cddfSDavid du Colombier 			 *
1507dd7cddfSDavid du Colombier 			 * Initialisation of the bridge should be done here.
1517dd7cddfSDavid du Colombier 			 */
1527dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPCR, 0xFFFF0000);
1537dd7cddfSDavid du Colombier 			l = (MaxUBN<<16)|(sbn<<8)|bno;
1547dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
1557dd7cddfSDavid du Colombier 			pcicfgw16(p, PciSPSR, 0xFFFF);
1567dd7cddfSDavid du Colombier 			maxubn = pciscan(sbn, &p->bridge);
1577dd7cddfSDavid du Colombier 			l = (maxubn<<16)|(sbn<<8)|bno;
1587dd7cddfSDavid du Colombier 			pcicfgw32(p, PciPBN, l);
1597dd7cddfSDavid du Colombier 		}
1607dd7cddfSDavid du Colombier 		else{
1617dd7cddfSDavid du Colombier 			maxubn = ubn;
1627dd7cddfSDavid du Colombier 			pciscan(sbn, &p->bridge);
1637dd7cddfSDavid du Colombier 		}
1647dd7cddfSDavid du Colombier 	}
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	return maxubn;
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier static void
pcicfginit(void)1707dd7cddfSDavid du Colombier pcicfginit(void)
1717dd7cddfSDavid du Colombier {
1727dd7cddfSDavid du Colombier #ifdef kernel
1737dd7cddfSDavid du Colombier 	char *p;
1747dd7cddfSDavid du Colombier #endif /* kernel */
1757dd7cddfSDavid du Colombier 	int bno;
1767dd7cddfSDavid du Colombier 	Pcidev **list;
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	if(pcicfgmode == -1){
1797dd7cddfSDavid du Colombier 		/*
1807dd7cddfSDavid du Colombier 		 * Try to determine which PCI configuration mode is implemented.
1817dd7cddfSDavid du Colombier 		 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
1827dd7cddfSDavid du Colombier 		 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
1837dd7cddfSDavid du Colombier 		 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
1847dd7cddfSDavid du Colombier 		 * a device behind these addresses so if Mode2 accesses fail try
1857dd7cddfSDavid du Colombier 		 * for Mode1 (which is preferred, Mode2 is deprecated).
1867dd7cddfSDavid du Colombier 		 */
1877dd7cddfSDavid du Colombier 		outportb(PciCSE, 0);
1887dd7cddfSDavid du Colombier 		if(inportb(PciCSE) == 0){
1897dd7cddfSDavid du Colombier 			pcicfgmode = 2;
1907dd7cddfSDavid du Colombier 			pcimaxdno = 15;
1917dd7cddfSDavid du Colombier 		}
1927dd7cddfSDavid du Colombier 		else{
1937dd7cddfSDavid du Colombier 			outportl(PciADDR, 0);
1947dd7cddfSDavid du Colombier 			if(inportl(PciADDR) == 0){
1957dd7cddfSDavid du Colombier 				pcicfgmode = 1;
1967dd7cddfSDavid du Colombier 				pcimaxdno = 31;
1977dd7cddfSDavid du Colombier 			}
1987dd7cddfSDavid du Colombier 		}
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 		if(pcicfgmode > 0){
2017dd7cddfSDavid du Colombier 			list = &pciroot;
2027dd7cddfSDavid du Colombier 			for(bno = 0; bno < 256; bno++){
2037dd7cddfSDavid du Colombier 				bno = pciscan(bno, list);
2047dd7cddfSDavid du Colombier 				while(*list)
2057dd7cddfSDavid du Colombier 					list = &(*list)->link;
2067dd7cddfSDavid du Colombier 			}
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 		}
2097dd7cddfSDavid du Colombier 	}
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)2137dd7cddfSDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
2147dd7cddfSDavid du Colombier {
2157dd7cddfSDavid du Colombier 	int o, type, x;
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
2187dd7cddfSDavid du Colombier 		pcicfginit();
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
2217dd7cddfSDavid du Colombier 		type = 0x01;
2227dd7cddfSDavid du Colombier 	else
2237dd7cddfSDavid du Colombier 		type = 0x00;
2247dd7cddfSDavid du Colombier 	x = -1;
2257dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
2267dd7cddfSDavid du Colombier 		return x;
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 	switch(pcicfgmode){
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier 	case 1:
2317dd7cddfSDavid du Colombier 		o = rno & 0x03;
2327dd7cddfSDavid du Colombier 		rno &= ~0x03;
2337dd7cddfSDavid du Colombier 		outportl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
2347dd7cddfSDavid du Colombier 		if(read)
2357dd7cddfSDavid du Colombier 			x = inportb(PciDATA+o);
2367dd7cddfSDavid du Colombier 		else
2377dd7cddfSDavid du Colombier 			outportb(PciDATA+o, data);
2387dd7cddfSDavid du Colombier 		outportl(PciADDR, 0);
2397dd7cddfSDavid du Colombier 		break;
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	case 2:
2427dd7cddfSDavid du Colombier 		outportb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
2437dd7cddfSDavid du Colombier 		outportb(PciFORWARD, BUSBNO(tbdf));
2447dd7cddfSDavid du Colombier 		if(read)
2457dd7cddfSDavid du Colombier 			x = inportb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
2467dd7cddfSDavid du Colombier 		else
2477dd7cddfSDavid du Colombier 			outportb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
2487dd7cddfSDavid du Colombier 		outportb(PciCSE, 0);
2497dd7cddfSDavid du Colombier 		break;
2507dd7cddfSDavid du Colombier 	}
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	return x;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)2567dd7cddfSDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
2577dd7cddfSDavid du Colombier {
2587dd7cddfSDavid du Colombier 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)2627dd7cddfSDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
2637dd7cddfSDavid du Colombier {
2647dd7cddfSDavid du Colombier 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)2687dd7cddfSDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier 	int o, type, x;
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
2737dd7cddfSDavid du Colombier 		pcicfginit();
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
2767dd7cddfSDavid du Colombier 		type = 0x01;
2777dd7cddfSDavid du Colombier 	else
2787dd7cddfSDavid du Colombier 		type = 0x00;
2797dd7cddfSDavid du Colombier 	x = -1;
2807dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
2817dd7cddfSDavid du Colombier 		return x;
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier 	switch(pcicfgmode){
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	case 1:
2867dd7cddfSDavid du Colombier 		o = rno & 0x02;
2877dd7cddfSDavid du Colombier 		rno &= ~0x03;
2887dd7cddfSDavid du Colombier 		outportl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
2897dd7cddfSDavid du Colombier 		if(read)
2907dd7cddfSDavid du Colombier 			x = inportw(PciDATA+o);
2917dd7cddfSDavid du Colombier 		else
2927dd7cddfSDavid du Colombier 			outportw(PciDATA+o, data);
2937dd7cddfSDavid du Colombier 		outportl(PciADDR, 0);
2947dd7cddfSDavid du Colombier 		break;
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 	case 2:
2977dd7cddfSDavid du Colombier 		outportb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
2987dd7cddfSDavid du Colombier 		outportb(PciFORWARD, BUSBNO(tbdf));
2997dd7cddfSDavid du Colombier 		if(read)
3007dd7cddfSDavid du Colombier 			x = inportw((0xC000|(BUSDNO(tbdf)<<8)) + rno);
3017dd7cddfSDavid du Colombier 		else
3027dd7cddfSDavid du Colombier 			outportw((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
3037dd7cddfSDavid du Colombier 		outportb(PciCSE, 0);
3047dd7cddfSDavid du Colombier 		break;
3057dd7cddfSDavid du Colombier 	}
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 	return x;
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)3117dd7cddfSDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)3177dd7cddfSDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
3187dd7cddfSDavid du Colombier {
3197dd7cddfSDavid du Colombier 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)3237dd7cddfSDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
3247dd7cddfSDavid du Colombier {
3257dd7cddfSDavid du Colombier 	int type, x;
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
3287dd7cddfSDavid du Colombier 		pcicfginit();
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier 	if(BUSBNO(tbdf))
3317dd7cddfSDavid du Colombier 		type = 0x01;
3327dd7cddfSDavid du Colombier 	else
3337dd7cddfSDavid du Colombier 		type = 0x00;
3347dd7cddfSDavid du Colombier 	x = -1;
3357dd7cddfSDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
3367dd7cddfSDavid du Colombier 		return x;
3377dd7cddfSDavid du Colombier 
3387dd7cddfSDavid du Colombier 	switch(pcicfgmode){
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	case 1:
3417dd7cddfSDavid du Colombier 		rno &= ~0x03;
3427dd7cddfSDavid du Colombier 		outportl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
3437dd7cddfSDavid du Colombier 		if(read)
3447dd7cddfSDavid du Colombier 			x = inportl(PciDATA);
3457dd7cddfSDavid du Colombier 		else
3467dd7cddfSDavid du Colombier 			outportl(PciDATA, data);
3477dd7cddfSDavid du Colombier 		outportl(PciADDR, 0);
3487dd7cddfSDavid du Colombier 		break;
3497dd7cddfSDavid du Colombier 
3507dd7cddfSDavid du Colombier 	case 2:
3517dd7cddfSDavid du Colombier 		outportb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
3527dd7cddfSDavid du Colombier 		outportb(PciFORWARD, BUSBNO(tbdf));
3537dd7cddfSDavid du Colombier 		if(read)
3547dd7cddfSDavid du Colombier 			x = inportl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
3557dd7cddfSDavid du Colombier 		else
3567dd7cddfSDavid du Colombier 			outportl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
3577dd7cddfSDavid du Colombier 		outportb(PciCSE, 0);
3587dd7cddfSDavid du Colombier 		break;
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier 	return x;
3627dd7cddfSDavid du Colombier }
3637dd7cddfSDavid du Colombier 
3647dd7cddfSDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)3657dd7cddfSDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
3667dd7cddfSDavid du Colombier {
3677dd7cddfSDavid du Colombier 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier 
3707dd7cddfSDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)3717dd7cddfSDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
3727dd7cddfSDavid du Colombier {
3737dd7cddfSDavid du Colombier 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier 
3767dd7cddfSDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)3777dd7cddfSDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
3787dd7cddfSDavid du Colombier {
3797dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
3807dd7cddfSDavid du Colombier 		pcicfginit();
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier 	if(prev == nil)
3837dd7cddfSDavid du Colombier 		prev = pcilist;
3847dd7cddfSDavid du Colombier 	else
3857dd7cddfSDavid du Colombier 		prev = prev->list;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	while(prev != nil) {
3887dd7cddfSDavid du Colombier 		if(prev->vid == vid && (did == 0 || prev->did == did))
3897dd7cddfSDavid du Colombier 			break;
3907dd7cddfSDavid du Colombier 		prev = prev->list;
3917dd7cddfSDavid du Colombier 	}
3927dd7cddfSDavid du Colombier 	return prev;
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier void
pcihinv(Pcidev * p)3967dd7cddfSDavid du Colombier pcihinv(Pcidev* p)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier 	int i;
3997dd7cddfSDavid du Colombier 	Pcidev *t;
4007dd7cddfSDavid du Colombier 
4017dd7cddfSDavid du Colombier 	if(pcicfgmode == -1)
4027dd7cddfSDavid du Colombier 		pcicfginit();
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	if(p == nil) {
4067dd7cddfSDavid du Colombier 		p = pciroot;
4077dd7cddfSDavid du Colombier 		Bprint(&stdout, "bus dev type vid  did intl memory\n");
4087dd7cddfSDavid du Colombier 	}
4097dd7cddfSDavid du Colombier 	for(t = p; t != nil; t = t->link) {
4107dd7cddfSDavid du Colombier 		Bprint(&stdout, "%d  %2d/%d %.4ux %.4ux %.4ux %2d  ",
4117dd7cddfSDavid du Colombier 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
4127dd7cddfSDavid du Colombier 			t->ccru, t->vid, t->did, t->intl);
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 		for(i = 0; i < nelem(p->mem); i++) {
4157dd7cddfSDavid du Colombier 			if(t->mem[i].size == 0)
4167dd7cddfSDavid du Colombier 				continue;
4177dd7cddfSDavid du Colombier 			Bprint(&stdout, "%d:%.8lux %d ", i,
4187dd7cddfSDavid du Colombier 				t->mem[i].bar, t->mem[i].size);
4197dd7cddfSDavid du Colombier 		}
4207dd7cddfSDavid du Colombier 		Bprint(&stdout, "\n");
4217dd7cddfSDavid du Colombier 	}
4227dd7cddfSDavid du Colombier 	while(p != nil) {
4237dd7cddfSDavid du Colombier 		if(p->bridge != nil)
4247dd7cddfSDavid du Colombier 			pcihinv(p->bridge);
4257dd7cddfSDavid du Colombier 		p = p->link;
4267dd7cddfSDavid du Colombier 	}
4277dd7cddfSDavid du Colombier }
428