xref: /plan9/sys/src/9/teg2/pci.c (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
1*3de6a9c0SDavid du Colombier /*
2*3de6a9c0SDavid du Colombier  * PCI support code.
3*3de6a9c0SDavid du Colombier  * Needs a massive rewrite.
4*3de6a9c0SDavid du Colombier  */
5*3de6a9c0SDavid du Colombier #include "u.h"
6*3de6a9c0SDavid du Colombier #include "../port/lib.h"
7*3de6a9c0SDavid du Colombier #include "mem.h"
8*3de6a9c0SDavid du Colombier #include "dat.h"
9*3de6a9c0SDavid du Colombier #include "fns.h"
10*3de6a9c0SDavid du Colombier #include "io.h"
11*3de6a9c0SDavid du Colombier 
12*3de6a9c0SDavid du Colombier #define DBG	if(0) pcilog
13*3de6a9c0SDavid du Colombier 
14*3de6a9c0SDavid du Colombier typedef struct Pci Pci;
15*3de6a9c0SDavid du Colombier 
16*3de6a9c0SDavid du Colombier struct
17*3de6a9c0SDavid du Colombier {
18*3de6a9c0SDavid du Colombier 	char	output[PCICONSSIZE];
19*3de6a9c0SDavid du Colombier 	int	ptr;
20*3de6a9c0SDavid du Colombier }PCICONS;
21*3de6a9c0SDavid du Colombier 
22*3de6a9c0SDavid du Colombier int
pcilog(char * fmt,...)23*3de6a9c0SDavid du Colombier pcilog(char *fmt, ...)
24*3de6a9c0SDavid du Colombier {
25*3de6a9c0SDavid du Colombier 	int n;
26*3de6a9c0SDavid du Colombier 	va_list arg;
27*3de6a9c0SDavid du Colombier 	char buf[PRINTSIZE];
28*3de6a9c0SDavid du Colombier 
29*3de6a9c0SDavid du Colombier 	va_start(arg, fmt);
30*3de6a9c0SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
31*3de6a9c0SDavid du Colombier 	va_end(arg);
32*3de6a9c0SDavid du Colombier 
33*3de6a9c0SDavid du Colombier 	memmove(PCICONS.output+PCICONS.ptr, buf, n);
34*3de6a9c0SDavid du Colombier 	PCICONS.ptr += n;
35*3de6a9c0SDavid du Colombier 	return n;
36*3de6a9c0SDavid du Colombier }
37*3de6a9c0SDavid du Colombier 
38*3de6a9c0SDavid du Colombier enum
39*3de6a9c0SDavid du Colombier {
40*3de6a9c0SDavid du Colombier 	MaxFNO		= 7,
41*3de6a9c0SDavid du Colombier 	MaxUBN		= 255,
42*3de6a9c0SDavid du Colombier };
43*3de6a9c0SDavid du Colombier 
44*3de6a9c0SDavid du Colombier enum
45*3de6a9c0SDavid du Colombier {					/* command register */
46*3de6a9c0SDavid du Colombier 	IOen		= (1<<0),
47*3de6a9c0SDavid du Colombier 	MEMen		= (1<<1),
48*3de6a9c0SDavid du Colombier 	MASen		= (1<<2),
49*3de6a9c0SDavid du Colombier 	MemWrInv	= (1<<4),
50*3de6a9c0SDavid du Colombier 	PErrEn		= (1<<6),
51*3de6a9c0SDavid du Colombier 	SErrEn		= (1<<8),
52*3de6a9c0SDavid du Colombier };
53*3de6a9c0SDavid du Colombier 
54*3de6a9c0SDavid du Colombier typedef struct {
55*3de6a9c0SDavid du Colombier 	ulong	cap;
56*3de6a9c0SDavid du Colombier 	ulong	ctl;
57*3de6a9c0SDavid du Colombier } Capctl;
58*3de6a9c0SDavid du Colombier typedef struct {
59*3de6a9c0SDavid du Colombier 	Capctl	dev;
60*3de6a9c0SDavid du Colombier 	Capctl	link;
61*3de6a9c0SDavid du Colombier 	Capctl	slot;
62*3de6a9c0SDavid du Colombier } Devlinkslot;
63*3de6a9c0SDavid du Colombier 
64*3de6a9c0SDavid du Colombier /* capability list id 0x10 is pci-e */
65*3de6a9c0SDavid du Colombier struct Pci {
66*3de6a9c0SDavid du Colombier 	/* pci-compatible config */
67*3de6a9c0SDavid du Colombier 	/* what io.h calls type 0 & type 1 pre-defined header */
68*3de6a9c0SDavid du Colombier 	ulong	id;
69*3de6a9c0SDavid du Colombier 	ulong	cs;
70*3de6a9c0SDavid du Colombier 	ulong	revclass;
71*3de6a9c0SDavid du Colombier 	ulong	misc;	/* cache line size, latency timer, header type, bist */
72*3de6a9c0SDavid du Colombier 	ulong	bar[2];		/* always 0 on tegra 2 */
73*3de6a9c0SDavid du Colombier 
74*3de6a9c0SDavid du Colombier 	/* types 1 & 2 pre-defined header */
75*3de6a9c0SDavid du Colombier 	ulong	bus;
76*3de6a9c0SDavid du Colombier 	ulong	ioaddrs;
77*3de6a9c0SDavid du Colombier 	ulong	memaddrs;
78*3de6a9c0SDavid du Colombier 	ulong	prefmem;
79*3de6a9c0SDavid du Colombier 	ulong	prefbasehi;
80*3de6a9c0SDavid du Colombier 	ulong	preflimhi;
81*3de6a9c0SDavid du Colombier 	/* type 2 pre-defined header only */
82*3de6a9c0SDavid du Colombier 	ulong	ioaddrhi;
83*3de6a9c0SDavid du Colombier 	ulong	cfgcapoff;	/* offset in cfg. space to cap. list (0x40) */
84*3de6a9c0SDavid du Colombier 	ulong	rom;
85*3de6a9c0SDavid du Colombier 	ulong	intr;		/* PciINT[LP] */
86*3de6a9c0SDavid du Colombier 	/* subsystem capability regs */
87*3de6a9c0SDavid du Colombier 	ulong	subsysid;
88*3de6a9c0SDavid du Colombier 	ulong	subsyscap;
89*3de6a9c0SDavid du Colombier 	/* */
90*3de6a9c0SDavid du Colombier 
91*3de6a9c0SDavid du Colombier 	Capctl	pwrmgmt;
92*3de6a9c0SDavid du Colombier 
93*3de6a9c0SDavid du Colombier 	/* msi */
94*3de6a9c0SDavid du Colombier 	ulong	msictlcap;
95*3de6a9c0SDavid du Colombier 	ulong	msimsgaddr[2];	/* little-endian */
96*3de6a9c0SDavid du Colombier 	ulong	msimsgdata;
97*3de6a9c0SDavid du Colombier 
98*3de6a9c0SDavid du Colombier 	/* pci-e cap. */
99*3de6a9c0SDavid du Colombier 	uchar	_pad0[0x80-0x60];
100*3de6a9c0SDavid du Colombier 	ulong	pciecap;
101*3de6a9c0SDavid du Colombier 	Devlinkslot port0;
102*3de6a9c0SDavid du Colombier 	ulong	rootctl;
103*3de6a9c0SDavid du Colombier 	ulong	rootsts;
104*3de6a9c0SDavid du Colombier 	Devlinkslot port1;
105*3de6a9c0SDavid du Colombier 
106*3de6a9c0SDavid du Colombier 	/* 0xbc */
107*3de6a9c0SDavid du Colombier 
108*3de6a9c0SDavid du Colombier };
109*3de6a9c0SDavid du Colombier 
110*3de6a9c0SDavid du Colombier enum {
111*3de6a9c0SDavid du Colombier 	/* offsets from soc.pci */
112*3de6a9c0SDavid du Colombier 	Port0		= 0,
113*3de6a9c0SDavid du Colombier 	Port1		= 0x1000,
114*3de6a9c0SDavid du Colombier 	Pads		= 0x3000,
115*3de6a9c0SDavid du Colombier 	Afi		= 0x3800,
116*3de6a9c0SDavid du Colombier 	Aficfg		= Afi + 0xac,
117*3de6a9c0SDavid du Colombier 	Cfgspace	= 0x4000,
118*3de6a9c0SDavid du Colombier 	Ecfgspace	= 0x104000,
119*3de6a9c0SDavid du Colombier 
120*3de6a9c0SDavid du Colombier 	/* cs bits */
121*3de6a9c0SDavid du Colombier 	Iospace		= 1<<0,
122*3de6a9c0SDavid du Colombier 	Memspace	= 1<<1,
123*3de6a9c0SDavid du Colombier 	Busmaster	= 1<<2,
124*3de6a9c0SDavid du Colombier 
125*3de6a9c0SDavid du Colombier 	/* Aficfg bits */
126*3de6a9c0SDavid du Colombier 	Fpcion		= 1<<0,
127*3de6a9c0SDavid du Colombier };
128*3de6a9c0SDavid du Colombier 
129*3de6a9c0SDavid du Colombier struct Pcictlr {
130*3de6a9c0SDavid du Colombier 	union {
131*3de6a9c0SDavid du Colombier 		uchar	_padpci[0x1000];
132*3de6a9c0SDavid du Colombier 		Pci;
133*3de6a9c0SDavid du Colombier 	} ports[2];
134*3de6a9c0SDavid du Colombier 	uchar	_padpads[0x1000];
135*3de6a9c0SDavid du Colombier 	uchar	pads[0x800];
136*3de6a9c0SDavid du Colombier 	uchar	afi[0x800];
137*3de6a9c0SDavid du Colombier 	ulong	cfg[0x1000];
138*3de6a9c0SDavid du Colombier 	ulong	extcfg[0x1000];
139*3de6a9c0SDavid du Colombier };
140*3de6a9c0SDavid du Colombier 
141*3de6a9c0SDavid du Colombier static Lock pcicfglock;
142*3de6a9c0SDavid du Colombier static Lock pcicfginitlock;
143*3de6a9c0SDavid du Colombier static int pcicfgmode = -1;
144*3de6a9c0SDavid du Colombier static int pcimaxbno = 1;  /* was 7; only 2 pci buses; touching 3rd hangs */
145*3de6a9c0SDavid du Colombier static int pcimaxdno;
146*3de6a9c0SDavid du Colombier static Pcidev* pciroot;
147*3de6a9c0SDavid du Colombier static Pcidev* pcilist;
148*3de6a9c0SDavid du Colombier static Pcidev* pcitail;
149*3de6a9c0SDavid du Colombier 
150*3de6a9c0SDavid du Colombier static int pcicfgrw8(int, int, int, int);
151*3de6a9c0SDavid du Colombier static int pcicfgrw16(int, int, int, int);
152*3de6a9c0SDavid du Colombier static int pcicfgrw32(int, int, int, int);
153*3de6a9c0SDavid du Colombier 
154*3de6a9c0SDavid du Colombier static char* bustypes[] = {
155*3de6a9c0SDavid du Colombier 	"CBUSI",
156*3de6a9c0SDavid du Colombier 	"CBUSII",
157*3de6a9c0SDavid du Colombier 	"EISA",
158*3de6a9c0SDavid du Colombier 	"FUTURE",
159*3de6a9c0SDavid du Colombier 	"INTERN",
160*3de6a9c0SDavid du Colombier 	"ISA",
161*3de6a9c0SDavid du Colombier 	"MBI",
162*3de6a9c0SDavid du Colombier 	"MBII",
163*3de6a9c0SDavid du Colombier 	"MCA",
164*3de6a9c0SDavid du Colombier 	"MPI",
165*3de6a9c0SDavid du Colombier 	"MPSA",
166*3de6a9c0SDavid du Colombier 	"NUBUS",
167*3de6a9c0SDavid du Colombier 	"PCI",
168*3de6a9c0SDavid du Colombier 	"PCMCIA",
169*3de6a9c0SDavid du Colombier 	"TC",
170*3de6a9c0SDavid du Colombier 	"VL",
171*3de6a9c0SDavid du Colombier 	"VME",
172*3de6a9c0SDavid du Colombier 	"XPRESS",
173*3de6a9c0SDavid du Colombier };
174*3de6a9c0SDavid du Colombier 
175*3de6a9c0SDavid du Colombier static int
tbdffmt(Fmt * fmt)176*3de6a9c0SDavid du Colombier tbdffmt(Fmt* fmt)
177*3de6a9c0SDavid du Colombier {
178*3de6a9c0SDavid du Colombier 	char *p;
179*3de6a9c0SDavid du Colombier 	int l, r;
180*3de6a9c0SDavid du Colombier 	uint type, tbdf;
181*3de6a9c0SDavid du Colombier 
182*3de6a9c0SDavid du Colombier 	if((p = malloc(READSTR)) == nil)
183*3de6a9c0SDavid du Colombier 		return fmtstrcpy(fmt, "(tbdfconv)");
184*3de6a9c0SDavid du Colombier 
185*3de6a9c0SDavid du Colombier 	switch(fmt->r){
186*3de6a9c0SDavid du Colombier 	case 'T':
187*3de6a9c0SDavid du Colombier 		tbdf = va_arg(fmt->args, int);
188*3de6a9c0SDavid du Colombier 		if(tbdf == BUSUNKNOWN)
189*3de6a9c0SDavid du Colombier 			snprint(p, READSTR, "unknown");
190*3de6a9c0SDavid du Colombier 		else{
191*3de6a9c0SDavid du Colombier 			type = BUSTYPE(tbdf);
192*3de6a9c0SDavid du Colombier 			if(type < nelem(bustypes))
193*3de6a9c0SDavid du Colombier 				l = snprint(p, READSTR, bustypes[type]);
194*3de6a9c0SDavid du Colombier 			else
195*3de6a9c0SDavid du Colombier 				l = snprint(p, READSTR, "%d", type);
196*3de6a9c0SDavid du Colombier 			snprint(p+l, READSTR-l, ".%d.%d.%d",
197*3de6a9c0SDavid du Colombier 				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
198*3de6a9c0SDavid du Colombier 		}
199*3de6a9c0SDavid du Colombier 		break;
200*3de6a9c0SDavid du Colombier 
201*3de6a9c0SDavid du Colombier 	default:
202*3de6a9c0SDavid du Colombier 		snprint(p, READSTR, "(tbdfconv)");
203*3de6a9c0SDavid du Colombier 		break;
204*3de6a9c0SDavid du Colombier 	}
205*3de6a9c0SDavid du Colombier 	r = fmtstrcpy(fmt, p);
206*3de6a9c0SDavid du Colombier 	free(p);
207*3de6a9c0SDavid du Colombier 
208*3de6a9c0SDavid du Colombier 	return r;
209*3de6a9c0SDavid du Colombier }
210*3de6a9c0SDavid du Colombier 
211*3de6a9c0SDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)212*3de6a9c0SDavid du Colombier pcibarsize(Pcidev *p, int rno)
213*3de6a9c0SDavid du Colombier {
214*3de6a9c0SDavid du Colombier 	ulong v, size;
215*3de6a9c0SDavid du Colombier 
216*3de6a9c0SDavid du Colombier 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
217*3de6a9c0SDavid du Colombier 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
218*3de6a9c0SDavid du Colombier 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
219*3de6a9c0SDavid du Colombier 	if(v & 1)
220*3de6a9c0SDavid du Colombier 		size |= 0xFFFF0000;
221*3de6a9c0SDavid du Colombier 	pcicfgrw32(p->tbdf, rno, v, 0);
222*3de6a9c0SDavid du Colombier 
223*3de6a9c0SDavid du Colombier 	return -(size & ~0x0F);
224*3de6a9c0SDavid du Colombier }
225*3de6a9c0SDavid du Colombier 
226*3de6a9c0SDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)227*3de6a9c0SDavid du Colombier pcilscan(int bno, Pcidev** list)
228*3de6a9c0SDavid du Colombier {
229*3de6a9c0SDavid du Colombier 	Pcidev *p, *head, *tail;
230*3de6a9c0SDavid du Colombier 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
231*3de6a9c0SDavid du Colombier 
232*3de6a9c0SDavid du Colombier 	maxubn = bno;
233*3de6a9c0SDavid du Colombier 	head = nil;
234*3de6a9c0SDavid du Colombier 	tail = nil;
235*3de6a9c0SDavid du Colombier 	for(dno = 0; dno <= pcimaxdno; dno++){
236*3de6a9c0SDavid du Colombier 		maxfno = 0;
237*3de6a9c0SDavid du Colombier 		for(fno = 0; fno <= maxfno; fno++){
238*3de6a9c0SDavid du Colombier 			/*
239*3de6a9c0SDavid du Colombier 			 * For this possible device, form the
240*3de6a9c0SDavid du Colombier 			 * bus+device+function triplet needed to address it
241*3de6a9c0SDavid du Colombier 			 * and try to read the vendor and device ID.
242*3de6a9c0SDavid du Colombier 			 * If successful, allocate a device struct and
243*3de6a9c0SDavid du Colombier 			 * start to fill it in with some useful information
244*3de6a9c0SDavid du Colombier 			 * from the device's configuration space.
245*3de6a9c0SDavid du Colombier 			 */
246*3de6a9c0SDavid du Colombier 			tbdf = MKBUS(BusPCI, bno, dno, fno);
247*3de6a9c0SDavid du Colombier 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
248*3de6a9c0SDavid du Colombier 			if(l == 0xFFFFFFFF || l == 0)
249*3de6a9c0SDavid du Colombier 				continue;
250*3de6a9c0SDavid du Colombier 			p = malloc(sizeof(*p));
251*3de6a9c0SDavid du Colombier 			if(p == nil)
252*3de6a9c0SDavid du Colombier 				panic("pcilscan: no memory");
253*3de6a9c0SDavid du Colombier 			p->tbdf = tbdf;
254*3de6a9c0SDavid du Colombier 			p->vid = l;
255*3de6a9c0SDavid du Colombier 			p->did = l>>16;
256*3de6a9c0SDavid du Colombier 
257*3de6a9c0SDavid du Colombier 			if(pcilist != nil)
258*3de6a9c0SDavid du Colombier 				pcitail->list = p;
259*3de6a9c0SDavid du Colombier 			else
260*3de6a9c0SDavid du Colombier 				pcilist = p;
261*3de6a9c0SDavid du Colombier 			pcitail = p;
262*3de6a9c0SDavid du Colombier 
263*3de6a9c0SDavid du Colombier 			p->pcr = pcicfgr16(p, PciPCR);
264*3de6a9c0SDavid du Colombier 			p->rid = pcicfgr8(p, PciRID);
265*3de6a9c0SDavid du Colombier 			p->ccrp = pcicfgr8(p, PciCCRp);
266*3de6a9c0SDavid du Colombier 			p->ccru = pcicfgr8(p, PciCCRu);
267*3de6a9c0SDavid du Colombier 			p->ccrb = pcicfgr8(p, PciCCRb);
268*3de6a9c0SDavid du Colombier 			p->cls = pcicfgr8(p, PciCLS);
269*3de6a9c0SDavid du Colombier 			p->ltr = pcicfgr8(p, PciLTR);
270*3de6a9c0SDavid du Colombier 
271*3de6a9c0SDavid du Colombier 			p->intl = pcicfgr8(p, PciINTL);
272*3de6a9c0SDavid du Colombier 
273*3de6a9c0SDavid du Colombier 			/*
274*3de6a9c0SDavid du Colombier 			 * If the device is a multi-function device adjust the
275*3de6a9c0SDavid du Colombier 			 * loop count so all possible functions are checked.
276*3de6a9c0SDavid du Colombier 			 */
277*3de6a9c0SDavid du Colombier 			hdt = pcicfgr8(p, PciHDT);
278*3de6a9c0SDavid du Colombier 			if(hdt & 0x80)
279*3de6a9c0SDavid du Colombier 				maxfno = MaxFNO;
280*3de6a9c0SDavid du Colombier 
281*3de6a9c0SDavid du Colombier 			/*
282*3de6a9c0SDavid du Colombier 			 * If appropriate, read the base address registers
283*3de6a9c0SDavid du Colombier 			 * and work out the sizes.
284*3de6a9c0SDavid du Colombier 			 */
285*3de6a9c0SDavid du Colombier 			switch(p->ccrb) {
286*3de6a9c0SDavid du Colombier 			case 0x03:		/* display controller */
287*3de6a9c0SDavid du Colombier 				/* fall through */
288*3de6a9c0SDavid du Colombier 			case 0x01:		/* mass storage controller */
289*3de6a9c0SDavid du Colombier 			case 0x02:		/* network controller */
290*3de6a9c0SDavid du Colombier 			case 0x04:		/* multimedia device */
291*3de6a9c0SDavid du Colombier 			case 0x07:		/* simple comm. controllers */
292*3de6a9c0SDavid du Colombier 			case 0x08:		/* base system peripherals */
293*3de6a9c0SDavid du Colombier 			case 0x09:		/* input devices */
294*3de6a9c0SDavid du Colombier 			case 0x0A:		/* docking stations */
295*3de6a9c0SDavid du Colombier 			case 0x0B:		/* processors */
296*3de6a9c0SDavid du Colombier 			case 0x0C:		/* serial bus controllers */
297*3de6a9c0SDavid du Colombier 				if((hdt & 0x7F) != 0)
298*3de6a9c0SDavid du Colombier 					break;
299*3de6a9c0SDavid du Colombier 				rno = PciBAR0 - 4;
300*3de6a9c0SDavid du Colombier 				for(i = 0; i < nelem(p->mem); i++) {
301*3de6a9c0SDavid du Colombier 					rno += 4;
302*3de6a9c0SDavid du Colombier 					p->mem[i].bar = pcicfgr32(p, rno);
303*3de6a9c0SDavid du Colombier 					p->mem[i].size = pcibarsize(p, rno);
304*3de6a9c0SDavid du Colombier 				}
305*3de6a9c0SDavid du Colombier 				break;
306*3de6a9c0SDavid du Colombier 
307*3de6a9c0SDavid du Colombier 			case 0x00:
308*3de6a9c0SDavid du Colombier 			case 0x05:		/* memory controller */
309*3de6a9c0SDavid du Colombier 			case 0x06:		/* bridge device */
310*3de6a9c0SDavid du Colombier 			default:
311*3de6a9c0SDavid du Colombier 				break;
312*3de6a9c0SDavid du Colombier 			}
313*3de6a9c0SDavid du Colombier 
314*3de6a9c0SDavid du Colombier 			if(head != nil)
315*3de6a9c0SDavid du Colombier 				tail->link = p;
316*3de6a9c0SDavid du Colombier 			else
317*3de6a9c0SDavid du Colombier 				head = p;
318*3de6a9c0SDavid du Colombier 			tail = p;
319*3de6a9c0SDavid du Colombier 		}
320*3de6a9c0SDavid du Colombier 	}
321*3de6a9c0SDavid du Colombier 
322*3de6a9c0SDavid du Colombier 	*list = head;
323*3de6a9c0SDavid du Colombier 	for(p = head; p != nil; p = p->link){
324*3de6a9c0SDavid du Colombier 		/*
325*3de6a9c0SDavid du Colombier 		 * Find PCI-PCI bridges and recursively descend the tree.
326*3de6a9c0SDavid du Colombier 		 */
327*3de6a9c0SDavid du Colombier 		if(p->ccrb != 0x06 || p->ccru != 0x04)
328*3de6a9c0SDavid du Colombier 			continue;
329*3de6a9c0SDavid du Colombier 
330*3de6a9c0SDavid du Colombier 		/*
331*3de6a9c0SDavid du Colombier 		 * If the secondary or subordinate bus number is not
332*3de6a9c0SDavid du Colombier 		 * initialised try to do what the PCI BIOS should have
333*3de6a9c0SDavid du Colombier 		 * done and fill in the numbers as the tree is descended.
334*3de6a9c0SDavid du Colombier 		 * On the way down the subordinate bus number is set to
335*3de6a9c0SDavid du Colombier 		 * the maximum as it's not known how many buses are behind
336*3de6a9c0SDavid du Colombier 		 * this one; the final value is set on the way back up.
337*3de6a9c0SDavid du Colombier 		 */
338*3de6a9c0SDavid du Colombier 		sbn = pcicfgr8(p, PciSBN);
339*3de6a9c0SDavid du Colombier 		ubn = pcicfgr8(p, PciUBN);
340*3de6a9c0SDavid du Colombier 
341*3de6a9c0SDavid du Colombier 		if(sbn == 0 || ubn == 0) {
342*3de6a9c0SDavid du Colombier 			sbn = maxubn+1;
343*3de6a9c0SDavid du Colombier 			/*
344*3de6a9c0SDavid du Colombier 			 * Make sure memory, I/O and master enables are
345*3de6a9c0SDavid du Colombier 			 * off, set the primary, secondary and subordinate
346*3de6a9c0SDavid du Colombier 			 * bus numbers and clear the secondary status before
347*3de6a9c0SDavid du Colombier 			 * attempting to scan the secondary bus.
348*3de6a9c0SDavid du Colombier 			 *
349*3de6a9c0SDavid du Colombier 			 * Initialisation of the bridge should be done here.
350*3de6a9c0SDavid du Colombier 			 */
351*3de6a9c0SDavid du Colombier 			pcicfgw32(p, PciPCR, 0xFFFF0000);
352*3de6a9c0SDavid du Colombier 			l = (MaxUBN<<16)|(sbn<<8)|bno;
353*3de6a9c0SDavid du Colombier 			pcicfgw32(p, PciPBN, l);
354*3de6a9c0SDavid du Colombier 			pcicfgw16(p, PciSPSR, 0xFFFF);
355*3de6a9c0SDavid du Colombier 			maxubn = pcilscan(sbn, &p->bridge);
356*3de6a9c0SDavid du Colombier 			l = (maxubn<<16)|(sbn<<8)|bno;
357*3de6a9c0SDavid du Colombier 
358*3de6a9c0SDavid du Colombier 			pcicfgw32(p, PciPBN, l);
359*3de6a9c0SDavid du Colombier 		}
360*3de6a9c0SDavid du Colombier 		else {
361*3de6a9c0SDavid du Colombier 			if(ubn > maxubn)
362*3de6a9c0SDavid du Colombier 				maxubn = ubn;
363*3de6a9c0SDavid du Colombier 			pcilscan(sbn, &p->bridge);
364*3de6a9c0SDavid du Colombier 		}
365*3de6a9c0SDavid du Colombier 	}
366*3de6a9c0SDavid du Colombier 
367*3de6a9c0SDavid du Colombier 	return maxubn;
368*3de6a9c0SDavid du Colombier }
369*3de6a9c0SDavid du Colombier 
370*3de6a9c0SDavid du Colombier extern void rtl8169interrupt(Ureg*, void* arg);
371*3de6a9c0SDavid du Colombier 
372*3de6a9c0SDavid du Colombier /* not used yet */
373*3de6a9c0SDavid du Colombier static void
pciintr(Ureg * ureg,void * p)374*3de6a9c0SDavid du Colombier pciintr(Ureg *ureg, void *p)
375*3de6a9c0SDavid du Colombier {
376*3de6a9c0SDavid du Colombier 	rtl8169interrupt(ureg, p);		/* HACK */
377*3de6a9c0SDavid du Colombier }
378*3de6a9c0SDavid du Colombier 
379*3de6a9c0SDavid du Colombier static void
pcicfginit(void)380*3de6a9c0SDavid du Colombier pcicfginit(void)
381*3de6a9c0SDavid du Colombier {
382*3de6a9c0SDavid du Colombier 	char *p;
383*3de6a9c0SDavid du Colombier 	Pci *pci = (Pci *)soc.pci;
384*3de6a9c0SDavid du Colombier 	Pcidev **list;
385*3de6a9c0SDavid du Colombier 	int bno, n;
386*3de6a9c0SDavid du Colombier 
387*3de6a9c0SDavid du Colombier 	lock(&pcicfginitlock);
388*3de6a9c0SDavid du Colombier 	if(pcicfgmode != -1) {
389*3de6a9c0SDavid du Colombier 		unlock(&pcicfginitlock);
390*3de6a9c0SDavid du Colombier 		return;
391*3de6a9c0SDavid du Colombier 	}
392*3de6a9c0SDavid du Colombier 
393*3de6a9c0SDavid du Colombier 	/*
394*3de6a9c0SDavid du Colombier 	 * TrimSlice # pci 0 1
395*3de6a9c0SDavid du Colombier 	 * Scanning PCI devices on bus 0 1
396*3de6a9c0SDavid du Colombier 	 * BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
397*3de6a9c0SDavid du Colombier 	 * _____________________________________________________________
398*3de6a9c0SDavid du Colombier 	 * 00.00.00   0x10de     0x0bf0     Bridge device           0x04
399*3de6a9c0SDavid du Colombier 	 * 01.00.00   0x10ec     0x8168     Network controller      0x00
400*3de6a9c0SDavid du Colombier 	 *
401*3de6a9c0SDavid du Colombier 	 * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
402*3de6a9c0SDavid du Colombier 	 * and pci bus 1 has the realtek 8169 on it:
403*3de6a9c0SDavid du Colombier 	 *
404*3de6a9c0SDavid du Colombier 	 * TrimSlice # pci 1 long
405*3de6a9c0SDavid du Colombier 	 * Scanning PCI devices on bus 1
406*3de6a9c0SDavid du Colombier 	 *
407*3de6a9c0SDavid du Colombier 	 * Found PCI device 01.00.00:
408*3de6a9c0SDavid du Colombier 	 *   vendor ID =                   0x10ec
409*3de6a9c0SDavid du Colombier 	 *   device ID =                   0x8168
410*3de6a9c0SDavid du Colombier 	 *   command register =            0x0007
411*3de6a9c0SDavid du Colombier 	 *   status register =             0x0010
412*3de6a9c0SDavid du Colombier 	 *   revision ID =                 0x03
413*3de6a9c0SDavid du Colombier 	 *   class code =                  0x02 (Network controller)
414*3de6a9c0SDavid du Colombier 	 *   sub class code =              0x00
415*3de6a9c0SDavid du Colombier 	 *   programming interface =       0x00
416*3de6a9c0SDavid du Colombier 	 *   cache line =                  0x08
417*3de6a9c0SDavid du Colombier 	 *   base address 0 =              0x80400001		config
418*3de6a9c0SDavid du Colombier 	 *   base address 1 =              0x00000000		(ext. config)
419*3de6a9c0SDavid du Colombier 	 *   base address 2 =              0xa000000c		"downstream"
420*3de6a9c0SDavid du Colombier 	 *   base address 3 =              0x00000000		(prefetchable)
421*3de6a9c0SDavid du Colombier 	 *   base address 4 =              0xa000400c		not "
422*3de6a9c0SDavid du Colombier 	 *   base address 5 =              0x00000000		(unused)
423*3de6a9c0SDavid du Colombier 	 */
424*3de6a9c0SDavid du Colombier 	n = pci->id >> 16;
425*3de6a9c0SDavid du Colombier 	if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
426*3de6a9c0SDavid du Colombier 	     (pci->id & MASK(16)) != Vrealtek) {
427*3de6a9c0SDavid du Colombier 		print("no pci controller at %#p\n", pci);
428*3de6a9c0SDavid du Colombier 		unlock(&pcicfginitlock);
429*3de6a9c0SDavid du Colombier 		return;
430*3de6a9c0SDavid du Colombier 	}
431*3de6a9c0SDavid du Colombier 	if (0)
432*3de6a9c0SDavid du Colombier 		iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
433*3de6a9c0SDavid du Colombier 			pci, (uchar)pci->revclass, pci->revclass >> 8,
434*3de6a9c0SDavid du Colombier 			pci->misc);
435*3de6a9c0SDavid du Colombier 
436*3de6a9c0SDavid du Colombier 	pci->cs &= Iospace;
437*3de6a9c0SDavid du Colombier 	pci->cs |= Memspace | Busmaster;
438*3de6a9c0SDavid du Colombier 	coherence();
439*3de6a9c0SDavid du Colombier 
440*3de6a9c0SDavid du Colombier 	pcicfgmode = 1;
441*3de6a9c0SDavid du Colombier //	pcimaxdno = 31;
442*3de6a9c0SDavid du Colombier 	pcimaxdno = 15;			/* for trimslice */
443*3de6a9c0SDavid du Colombier 
444*3de6a9c0SDavid du Colombier 	fmtinstall('T', tbdffmt);
445*3de6a9c0SDavid du Colombier 
446*3de6a9c0SDavid du Colombier 	if(p = getconf("*pcimaxbno")){
447*3de6a9c0SDavid du Colombier 		n = strtoul(p, 0, 0);
448*3de6a9c0SDavid du Colombier 		if(n < pcimaxbno)
449*3de6a9c0SDavid du Colombier 			pcimaxbno = n;
450*3de6a9c0SDavid du Colombier 	}
451*3de6a9c0SDavid du Colombier 	if(p = getconf("*pcimaxdno")){
452*3de6a9c0SDavid du Colombier 		n = strtoul(p, 0, 0);
453*3de6a9c0SDavid du Colombier 		if(n < pcimaxdno)
454*3de6a9c0SDavid du Colombier 			pcimaxdno = n;
455*3de6a9c0SDavid du Colombier 	}
456*3de6a9c0SDavid du Colombier 
457*3de6a9c0SDavid du Colombier 	list = &pciroot;
458*3de6a9c0SDavid du Colombier 	/* was bno = 0; trimslice needs to start at 1 */
459*3de6a9c0SDavid du Colombier 	for(bno = 1; bno <= pcimaxbno; bno++) {
460*3de6a9c0SDavid du Colombier 		bno = pcilscan(bno, list);
461*3de6a9c0SDavid du Colombier 		while(*list)
462*3de6a9c0SDavid du Colombier 			list = &(*list)->link;
463*3de6a9c0SDavid du Colombier 	}
464*3de6a9c0SDavid du Colombier 	unlock(&pcicfginitlock);
465*3de6a9c0SDavid du Colombier 
466*3de6a9c0SDavid du Colombier 	if(getconf("*pcihinv"))
467*3de6a9c0SDavid du Colombier 		pcihinv(nil);
468*3de6a9c0SDavid du Colombier }
469*3de6a9c0SDavid du Colombier 
470*3de6a9c0SDavid du Colombier enum {
471*3de6a9c0SDavid du Colombier 	Afiintrcode	= 0xb8,
472*3de6a9c0SDavid du Colombier };
473*3de6a9c0SDavid du Colombier 
474*3de6a9c0SDavid du Colombier void
pcieintrdone(void)475*3de6a9c0SDavid du Colombier pcieintrdone(void)				/* dismiss pci-e intr */
476*3de6a9c0SDavid du Colombier {
477*3de6a9c0SDavid du Colombier 	ulong *afi;
478*3de6a9c0SDavid du Colombier 
479*3de6a9c0SDavid du Colombier 	afi = (ulong *)(soc.pci + Afi);
480*3de6a9c0SDavid du Colombier 	afi[Afiintrcode/sizeof *afi] = 0;	/* magic */
481*3de6a9c0SDavid du Colombier 	coherence();
482*3de6a9c0SDavid du Colombier }
483*3de6a9c0SDavid du Colombier 
484*3de6a9c0SDavid du Colombier /*
485*3de6a9c0SDavid du Colombier  * whole config space for tbdf should be at (return address - rno).
486*3de6a9c0SDavid du Colombier  */
487*3de6a9c0SDavid du Colombier static void *
tegracfgaddr(int tbdf,int rno)488*3de6a9c0SDavid du Colombier tegracfgaddr(int tbdf, int rno)
489*3de6a9c0SDavid du Colombier {
490*3de6a9c0SDavid du Colombier 	uintptr addr;
491*3de6a9c0SDavid du Colombier 
492*3de6a9c0SDavid du Colombier 	addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
493*3de6a9c0SDavid du Colombier //	if (BUSBNO(tbdf) == 1)
494*3de6a9c0SDavid du Colombier //		addr += Port1;
495*3de6a9c0SDavid du Colombier 	return (void *)addr;
496*3de6a9c0SDavid du Colombier }
497*3de6a9c0SDavid du Colombier 
498*3de6a9c0SDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)499*3de6a9c0SDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
500*3de6a9c0SDavid du Colombier {
501*3de6a9c0SDavid du Colombier 	int x;
502*3de6a9c0SDavid du Colombier 	void *addr;
503*3de6a9c0SDavid du Colombier 
504*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
505*3de6a9c0SDavid du Colombier 		pcicfginit();
506*3de6a9c0SDavid du Colombier 
507*3de6a9c0SDavid du Colombier 	x = -1;
508*3de6a9c0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
509*3de6a9c0SDavid du Colombier 		return x;
510*3de6a9c0SDavid du Colombier 
511*3de6a9c0SDavid du Colombier 	addr = tegracfgaddr(tbdf, rno);
512*3de6a9c0SDavid du Colombier 
513*3de6a9c0SDavid du Colombier 	lock(&pcicfglock);
514*3de6a9c0SDavid du Colombier 	if(read)
515*3de6a9c0SDavid du Colombier 		x = *(uchar *)addr;
516*3de6a9c0SDavid du Colombier 	else
517*3de6a9c0SDavid du Colombier 		*(uchar *)addr = data;
518*3de6a9c0SDavid du Colombier 	unlock(&pcicfglock);
519*3de6a9c0SDavid du Colombier 
520*3de6a9c0SDavid du Colombier 	return x;
521*3de6a9c0SDavid du Colombier }
522*3de6a9c0SDavid du Colombier 
523*3de6a9c0SDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)524*3de6a9c0SDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
525*3de6a9c0SDavid du Colombier {
526*3de6a9c0SDavid du Colombier 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
527*3de6a9c0SDavid du Colombier }
528*3de6a9c0SDavid du Colombier 
529*3de6a9c0SDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)530*3de6a9c0SDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
531*3de6a9c0SDavid du Colombier {
532*3de6a9c0SDavid du Colombier 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
533*3de6a9c0SDavid du Colombier }
534*3de6a9c0SDavid du Colombier 
535*3de6a9c0SDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)536*3de6a9c0SDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
537*3de6a9c0SDavid du Colombier {
538*3de6a9c0SDavid du Colombier 	int x;
539*3de6a9c0SDavid du Colombier 	void *addr;
540*3de6a9c0SDavid du Colombier 
541*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
542*3de6a9c0SDavid du Colombier 		pcicfginit();
543*3de6a9c0SDavid du Colombier 
544*3de6a9c0SDavid du Colombier 	x = -1;
545*3de6a9c0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
546*3de6a9c0SDavid du Colombier 		return x;
547*3de6a9c0SDavid du Colombier 
548*3de6a9c0SDavid du Colombier 	addr = tegracfgaddr(tbdf, rno);
549*3de6a9c0SDavid du Colombier 
550*3de6a9c0SDavid du Colombier 	lock(&pcicfglock);
551*3de6a9c0SDavid du Colombier 	if(read)
552*3de6a9c0SDavid du Colombier 		x = *(ushort *)addr;
553*3de6a9c0SDavid du Colombier 	else
554*3de6a9c0SDavid du Colombier 		*(ushort *)addr = data;
555*3de6a9c0SDavid du Colombier 	unlock(&pcicfglock);
556*3de6a9c0SDavid du Colombier 
557*3de6a9c0SDavid du Colombier 	return x;
558*3de6a9c0SDavid du Colombier }
559*3de6a9c0SDavid du Colombier 
560*3de6a9c0SDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)561*3de6a9c0SDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
562*3de6a9c0SDavid du Colombier {
563*3de6a9c0SDavid du Colombier 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
564*3de6a9c0SDavid du Colombier }
565*3de6a9c0SDavid du Colombier 
566*3de6a9c0SDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)567*3de6a9c0SDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
568*3de6a9c0SDavid du Colombier {
569*3de6a9c0SDavid du Colombier 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
570*3de6a9c0SDavid du Colombier }
571*3de6a9c0SDavid du Colombier 
572*3de6a9c0SDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)573*3de6a9c0SDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
574*3de6a9c0SDavid du Colombier {
575*3de6a9c0SDavid du Colombier 	int x;
576*3de6a9c0SDavid du Colombier 	vlong v;
577*3de6a9c0SDavid du Colombier 	void *addr;
578*3de6a9c0SDavid du Colombier 
579*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
580*3de6a9c0SDavid du Colombier 		pcicfginit();
581*3de6a9c0SDavid du Colombier 
582*3de6a9c0SDavid du Colombier 	x = -1;
583*3de6a9c0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
584*3de6a9c0SDavid du Colombier 		return x;
585*3de6a9c0SDavid du Colombier 
586*3de6a9c0SDavid du Colombier 	addr = tegracfgaddr(tbdf, rno);
587*3de6a9c0SDavid du Colombier 	v = probeaddr((uintptr)addr);
588*3de6a9c0SDavid du Colombier 	if (v < 0)
589*3de6a9c0SDavid du Colombier 		return -1;
590*3de6a9c0SDavid du Colombier 
591*3de6a9c0SDavid du Colombier 	lock(&pcicfglock);
592*3de6a9c0SDavid du Colombier 	if(read)
593*3de6a9c0SDavid du Colombier 		x = *(ulong *)addr;
594*3de6a9c0SDavid du Colombier 	else
595*3de6a9c0SDavid du Colombier 		*(ulong *)addr = data;
596*3de6a9c0SDavid du Colombier 	unlock(&pcicfglock);
597*3de6a9c0SDavid du Colombier 
598*3de6a9c0SDavid du Colombier 	return x;
599*3de6a9c0SDavid du Colombier }
600*3de6a9c0SDavid du Colombier 
601*3de6a9c0SDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)602*3de6a9c0SDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
603*3de6a9c0SDavid du Colombier {
604*3de6a9c0SDavid du Colombier 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
605*3de6a9c0SDavid du Colombier }
606*3de6a9c0SDavid du Colombier 
607*3de6a9c0SDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)608*3de6a9c0SDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
609*3de6a9c0SDavid du Colombier {
610*3de6a9c0SDavid du Colombier 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
611*3de6a9c0SDavid du Colombier }
612*3de6a9c0SDavid du Colombier 
613*3de6a9c0SDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)614*3de6a9c0SDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
615*3de6a9c0SDavid du Colombier {
616*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
617*3de6a9c0SDavid du Colombier 		pcicfginit();
618*3de6a9c0SDavid du Colombier 
619*3de6a9c0SDavid du Colombier 	if(prev == nil)
620*3de6a9c0SDavid du Colombier 		prev = pcilist;
621*3de6a9c0SDavid du Colombier 	else
622*3de6a9c0SDavid du Colombier 		prev = prev->list;
623*3de6a9c0SDavid du Colombier 
624*3de6a9c0SDavid du Colombier 	while(prev != nil){
625*3de6a9c0SDavid du Colombier 		if((vid == 0 || prev->vid == vid)
626*3de6a9c0SDavid du Colombier 		&& (did == 0 || prev->did == did))
627*3de6a9c0SDavid du Colombier 			break;
628*3de6a9c0SDavid du Colombier 		prev = prev->list;
629*3de6a9c0SDavid du Colombier 	}
630*3de6a9c0SDavid du Colombier 	return prev;
631*3de6a9c0SDavid du Colombier }
632*3de6a9c0SDavid du Colombier 
633*3de6a9c0SDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)634*3de6a9c0SDavid du Colombier pcimatchtbdf(int tbdf)
635*3de6a9c0SDavid du Colombier {
636*3de6a9c0SDavid du Colombier 	Pcidev *pcidev;
637*3de6a9c0SDavid du Colombier 
638*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
639*3de6a9c0SDavid du Colombier 		pcicfginit();
640*3de6a9c0SDavid du Colombier 
641*3de6a9c0SDavid du Colombier 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
642*3de6a9c0SDavid du Colombier 		if(pcidev->tbdf == tbdf)
643*3de6a9c0SDavid du Colombier 			break;
644*3de6a9c0SDavid du Colombier 	}
645*3de6a9c0SDavid du Colombier 	return pcidev;
646*3de6a9c0SDavid du Colombier }
647*3de6a9c0SDavid du Colombier 
648*3de6a9c0SDavid du Colombier static void
pcilhinv(Pcidev * p)649*3de6a9c0SDavid du Colombier pcilhinv(Pcidev* p)
650*3de6a9c0SDavid du Colombier {
651*3de6a9c0SDavid du Colombier 	int i;
652*3de6a9c0SDavid du Colombier 	Pcidev *t;
653*3de6a9c0SDavid du Colombier 
654*3de6a9c0SDavid du Colombier 	if(p == nil) {
655*3de6a9c0SDavid du Colombier 		putstrn(PCICONS.output, PCICONS.ptr);
656*3de6a9c0SDavid du Colombier 		p = pciroot;
657*3de6a9c0SDavid du Colombier 		print("bus dev type vid  did intl memory\n");
658*3de6a9c0SDavid du Colombier 	}
659*3de6a9c0SDavid du Colombier 	for(t = p; t != nil; t = t->link) {
660*3de6a9c0SDavid du Colombier 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
661*3de6a9c0SDavid du Colombier 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
662*3de6a9c0SDavid du Colombier 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
663*3de6a9c0SDavid du Colombier 
664*3de6a9c0SDavid du Colombier 		for(i = 0; i < nelem(p->mem); i++) {
665*3de6a9c0SDavid du Colombier 			if(t->mem[i].size == 0)
666*3de6a9c0SDavid du Colombier 				continue;
667*3de6a9c0SDavid du Colombier 			print("%d:%.8lux %d ", i,
668*3de6a9c0SDavid du Colombier 				t->mem[i].bar, t->mem[i].size);
669*3de6a9c0SDavid du Colombier 		}
670*3de6a9c0SDavid du Colombier 		if(t->bridge)
671*3de6a9c0SDavid du Colombier 			print("->%d", BUSBNO(t->bridge->tbdf));
672*3de6a9c0SDavid du Colombier 		print("\n");
673*3de6a9c0SDavid du Colombier 	}
674*3de6a9c0SDavid du Colombier 	while(p != nil) {
675*3de6a9c0SDavid du Colombier 		if(p->bridge != nil)
676*3de6a9c0SDavid du Colombier 			pcilhinv(p->bridge);
677*3de6a9c0SDavid du Colombier 		p = p->link;
678*3de6a9c0SDavid du Colombier 	}
679*3de6a9c0SDavid du Colombier }
680*3de6a9c0SDavid du Colombier 
681*3de6a9c0SDavid du Colombier void
pcihinv(Pcidev * p)682*3de6a9c0SDavid du Colombier pcihinv(Pcidev* p)
683*3de6a9c0SDavid du Colombier {
684*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
685*3de6a9c0SDavid du Colombier 		pcicfginit();
686*3de6a9c0SDavid du Colombier 	lock(&pcicfginitlock);
687*3de6a9c0SDavid du Colombier 	pcilhinv(p);
688*3de6a9c0SDavid du Colombier 	unlock(&pcicfginitlock);
689*3de6a9c0SDavid du Colombier }
690*3de6a9c0SDavid du Colombier 
691*3de6a9c0SDavid du Colombier void
pcireset(void)692*3de6a9c0SDavid du Colombier pcireset(void)
693*3de6a9c0SDavid du Colombier {
694*3de6a9c0SDavid du Colombier 	Pcidev *p;
695*3de6a9c0SDavid du Colombier 
696*3de6a9c0SDavid du Colombier 	if(pcicfgmode == -1)
697*3de6a9c0SDavid du Colombier 		pcicfginit();
698*3de6a9c0SDavid du Colombier 
699*3de6a9c0SDavid du Colombier 	for(p = pcilist; p != nil; p = p->list) {
700*3de6a9c0SDavid du Colombier 		/* don't mess with the bridges */
701*3de6a9c0SDavid du Colombier 		if(p->ccrb == 0x06)
702*3de6a9c0SDavid du Colombier 			continue;
703*3de6a9c0SDavid du Colombier 		pciclrbme(p);
704*3de6a9c0SDavid du Colombier 	}
705*3de6a9c0SDavid du Colombier }
706*3de6a9c0SDavid du Colombier 
707*3de6a9c0SDavid du Colombier void
pcisetioe(Pcidev * p)708*3de6a9c0SDavid du Colombier pcisetioe(Pcidev* p)
709*3de6a9c0SDavid du Colombier {
710*3de6a9c0SDavid du Colombier 	p->pcr |= IOen;
711*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
712*3de6a9c0SDavid du Colombier }
713*3de6a9c0SDavid du Colombier 
714*3de6a9c0SDavid du Colombier void
pciclrioe(Pcidev * p)715*3de6a9c0SDavid du Colombier pciclrioe(Pcidev* p)
716*3de6a9c0SDavid du Colombier {
717*3de6a9c0SDavid du Colombier 	p->pcr &= ~IOen;
718*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
719*3de6a9c0SDavid du Colombier }
720*3de6a9c0SDavid du Colombier 
721*3de6a9c0SDavid du Colombier void
pcisetbme(Pcidev * p)722*3de6a9c0SDavid du Colombier pcisetbme(Pcidev* p)
723*3de6a9c0SDavid du Colombier {
724*3de6a9c0SDavid du Colombier 	p->pcr |= MASen;
725*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
726*3de6a9c0SDavid du Colombier }
727*3de6a9c0SDavid du Colombier 
728*3de6a9c0SDavid du Colombier void
pciclrbme(Pcidev * p)729*3de6a9c0SDavid du Colombier pciclrbme(Pcidev* p)
730*3de6a9c0SDavid du Colombier {
731*3de6a9c0SDavid du Colombier 	p->pcr &= ~MASen;
732*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
733*3de6a9c0SDavid du Colombier }
734*3de6a9c0SDavid du Colombier 
735*3de6a9c0SDavid du Colombier void
pcisetmwi(Pcidev * p)736*3de6a9c0SDavid du Colombier pcisetmwi(Pcidev* p)
737*3de6a9c0SDavid du Colombier {
738*3de6a9c0SDavid du Colombier 	p->pcr |= MemWrInv;
739*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
740*3de6a9c0SDavid du Colombier }
741*3de6a9c0SDavid du Colombier 
742*3de6a9c0SDavid du Colombier void
pciclrmwi(Pcidev * p)743*3de6a9c0SDavid du Colombier pciclrmwi(Pcidev* p)
744*3de6a9c0SDavid du Colombier {
745*3de6a9c0SDavid du Colombier 	p->pcr &= ~MemWrInv;
746*3de6a9c0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
747*3de6a9c0SDavid du Colombier }
748*3de6a9c0SDavid du Colombier 
749*3de6a9c0SDavid du Colombier static int
pcigetpmrb(Pcidev * p)750*3de6a9c0SDavid du Colombier pcigetpmrb(Pcidev* p)
751*3de6a9c0SDavid du Colombier {
752*3de6a9c0SDavid du Colombier 	int ptr;
753*3de6a9c0SDavid du Colombier 
754*3de6a9c0SDavid du Colombier 	if(p->pmrb != 0)
755*3de6a9c0SDavid du Colombier 		return p->pmrb;
756*3de6a9c0SDavid du Colombier 	p->pmrb = -1;
757*3de6a9c0SDavid du Colombier 
758*3de6a9c0SDavid du Colombier 	/*
759*3de6a9c0SDavid du Colombier 	 * If there are no extended capabilities implemented,
760*3de6a9c0SDavid du Colombier 	 * (bit 4 in the status register) assume there's no standard
761*3de6a9c0SDavid du Colombier 	 * power management method.
762*3de6a9c0SDavid du Colombier 	 * Find the capabilities pointer based on PCI header type.
763*3de6a9c0SDavid du Colombier 	 */
764*3de6a9c0SDavid du Colombier 	if(!(pcicfgr16(p, PciPSR) & 0x0010))
765*3de6a9c0SDavid du Colombier 		return -1;
766*3de6a9c0SDavid du Colombier 	switch(pcicfgr8(p, PciHDT)){
767*3de6a9c0SDavid du Colombier 	default:
768*3de6a9c0SDavid du Colombier 		return -1;
769*3de6a9c0SDavid du Colombier 	case 0:					/* all other */
770*3de6a9c0SDavid du Colombier 	case 1:					/* PCI to PCI bridge */
771*3de6a9c0SDavid du Colombier 		ptr = 0x34;
772*3de6a9c0SDavid du Colombier 		break;
773*3de6a9c0SDavid du Colombier 	case 2:					/* CardBus bridge */
774*3de6a9c0SDavid du Colombier 		ptr = 0x14;
775*3de6a9c0SDavid du Colombier 		break;
776*3de6a9c0SDavid du Colombier 	}
777*3de6a9c0SDavid du Colombier 	ptr = pcicfgr32(p, ptr);
778*3de6a9c0SDavid du Colombier 
779*3de6a9c0SDavid du Colombier 	while(ptr != 0){
780*3de6a9c0SDavid du Colombier 		/*
781*3de6a9c0SDavid du Colombier 		 * Check for validity.
782*3de6a9c0SDavid du Colombier 		 * Can't be in standard header and must be double
783*3de6a9c0SDavid du Colombier 		 * word aligned.
784*3de6a9c0SDavid du Colombier 		 */
785*3de6a9c0SDavid du Colombier 		if(ptr < 0x40 || (ptr & ~0xFC))
786*3de6a9c0SDavid du Colombier 			return -1;
787*3de6a9c0SDavid du Colombier 		if(pcicfgr8(p, ptr) == 0x01){
788*3de6a9c0SDavid du Colombier 			p->pmrb = ptr;
789*3de6a9c0SDavid du Colombier 			return ptr;
790*3de6a9c0SDavid du Colombier 		}
791*3de6a9c0SDavid du Colombier 
792*3de6a9c0SDavid du Colombier 		ptr = pcicfgr8(p, ptr+1);
793*3de6a9c0SDavid du Colombier 	}
794*3de6a9c0SDavid du Colombier 
795*3de6a9c0SDavid du Colombier 	return -1;
796*3de6a9c0SDavid du Colombier }
797*3de6a9c0SDavid du Colombier 
798*3de6a9c0SDavid du Colombier int
pcigetpms(Pcidev * p)799*3de6a9c0SDavid du Colombier pcigetpms(Pcidev* p)
800*3de6a9c0SDavid du Colombier {
801*3de6a9c0SDavid du Colombier 	int pmcsr, ptr;
802*3de6a9c0SDavid du Colombier 
803*3de6a9c0SDavid du Colombier 	if((ptr = pcigetpmrb(p)) == -1)
804*3de6a9c0SDavid du Colombier 		return -1;
805*3de6a9c0SDavid du Colombier 
806*3de6a9c0SDavid du Colombier 	/*
807*3de6a9c0SDavid du Colombier 	 * Power Management Register Block:
808*3de6a9c0SDavid du Colombier 	 *  offset 0:	Capability ID
809*3de6a9c0SDavid du Colombier 	 *	   1:	next item pointer
810*3de6a9c0SDavid du Colombier 	 *	   2:	capabilities
811*3de6a9c0SDavid du Colombier 	 *	   4:	control/status
812*3de6a9c0SDavid du Colombier 	 *	   6:	bridge support extensions
813*3de6a9c0SDavid du Colombier 	 *	   7:	data
814*3de6a9c0SDavid du Colombier 	 */
815*3de6a9c0SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
816*3de6a9c0SDavid du Colombier 
817*3de6a9c0SDavid du Colombier 	return pmcsr & 0x0003;
818*3de6a9c0SDavid du Colombier }
819*3de6a9c0SDavid du Colombier 
820*3de6a9c0SDavid du Colombier int
pcisetpms(Pcidev * p,int state)821*3de6a9c0SDavid du Colombier pcisetpms(Pcidev* p, int state)
822*3de6a9c0SDavid du Colombier {
823*3de6a9c0SDavid du Colombier 	int ostate, pmc, pmcsr, ptr;
824*3de6a9c0SDavid du Colombier 
825*3de6a9c0SDavid du Colombier 	if((ptr = pcigetpmrb(p)) == -1)
826*3de6a9c0SDavid du Colombier 		return -1;
827*3de6a9c0SDavid du Colombier 
828*3de6a9c0SDavid du Colombier 	pmc = pcicfgr16(p, ptr+2);
829*3de6a9c0SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
830*3de6a9c0SDavid du Colombier 	ostate = pmcsr & 0x0003;
831*3de6a9c0SDavid du Colombier 	pmcsr &= ~0x0003;
832*3de6a9c0SDavid du Colombier 
833*3de6a9c0SDavid du Colombier 	switch(state){
834*3de6a9c0SDavid du Colombier 	default:
835*3de6a9c0SDavid du Colombier 		return -1;
836*3de6a9c0SDavid du Colombier 	case 0:
837*3de6a9c0SDavid du Colombier 		break;
838*3de6a9c0SDavid du Colombier 	case 1:
839*3de6a9c0SDavid du Colombier 		if(!(pmc & 0x0200))
840*3de6a9c0SDavid du Colombier 			return -1;
841*3de6a9c0SDavid du Colombier 		break;
842*3de6a9c0SDavid du Colombier 	case 2:
843*3de6a9c0SDavid du Colombier 		if(!(pmc & 0x0400))
844*3de6a9c0SDavid du Colombier 			return -1;
845*3de6a9c0SDavid du Colombier 		break;
846*3de6a9c0SDavid du Colombier 	case 3:
847*3de6a9c0SDavid du Colombier 		break;
848*3de6a9c0SDavid du Colombier 	}
849*3de6a9c0SDavid du Colombier 	pmcsr |= state;
850*3de6a9c0SDavid du Colombier 	pcicfgw16(p, ptr+4, pmcsr);
851*3de6a9c0SDavid du Colombier 
852*3de6a9c0SDavid du Colombier 	return ostate;
853*3de6a9c0SDavid du Colombier }
854