xref: /plan9-contrib/sys/src/9/loongson/pci.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1*a81c3ea0SDavid du Colombier /*
2*a81c3ea0SDavid du Colombier  *	PCI support code.
3*a81c3ea0SDavid du Colombier  */
4*a81c3ea0SDavid du Colombier 
5*a81c3ea0SDavid du Colombier #include "u.h"
6*a81c3ea0SDavid du Colombier #include "../port/lib.h"
7*a81c3ea0SDavid du Colombier #include "mem.h"
8*a81c3ea0SDavid du Colombier #include "dat.h"
9*a81c3ea0SDavid du Colombier #include "fns.h"
10*a81c3ea0SDavid du Colombier #include "io.h"
11*a81c3ea0SDavid du Colombier 
12*a81c3ea0SDavid du Colombier typedef struct Pci Pci;
13*a81c3ea0SDavid du Colombier 
14*a81c3ea0SDavid du Colombier struct Pci {
15*a81c3ea0SDavid du Colombier 	ulong	id;
16*a81c3ea0SDavid du Colombier 	ulong	cs;
17*a81c3ea0SDavid du Colombier 	ulong	revclass;
18*a81c3ea0SDavid du Colombier 	ulong	misc;	/* cache line size, latency timer, header type, bist */
19*a81c3ea0SDavid du Colombier 	ulong	base[6];	/* base addr regs */
20*a81c3ea0SDavid du Colombier 	ulong	unused[5];
21*a81c3ea0SDavid du Colombier 	ulong	intr;
22*a81c3ea0SDavid du Colombier 	ulong	mask[6];
23*a81c3ea0SDavid du Colombier 	ulong	trans[6];
24*a81c3ea0SDavid du Colombier };
25*a81c3ea0SDavid du Colombier 
26*a81c3ea0SDavid du Colombier enum {
27*a81c3ea0SDavid du Colombier 	/* cs bits */
28*a81c3ea0SDavid du Colombier 	CIoEn		= (1<<0),
29*a81c3ea0SDavid du Colombier 	CMemEn		= (1<<1),
30*a81c3ea0SDavid du Colombier 	CMasEn		= (1<<2),
31*a81c3ea0SDavid du Colombier 	CSpcEn		= (1<<4),
32*a81c3ea0SDavid du Colombier 	CParEn		= (1<<6),
33*a81c3ea0SDavid du Colombier 	CSErrEn		= (1<<8),
34*a81c3ea0SDavid du Colombier 
35*a81c3ea0SDavid du Colombier 	SMasTgtAb	= (1<<24),	/* master target abort */
36*a81c3ea0SDavid du Colombier 	SMasAb		= (1<<25),	/* master abort */
37*a81c3ea0SDavid du Colombier };
38*a81c3ea0SDavid du Colombier 
39*a81c3ea0SDavid du Colombier enum {
40*a81c3ea0SDavid du Colombier 	MaxFNO		= 7,
41*a81c3ea0SDavid du Colombier 	MaxUBN		= 255,
42*a81c3ea0SDavid du Colombier };
43*a81c3ea0SDavid du Colombier 
44*a81c3ea0SDavid du Colombier enum
45*a81c3ea0SDavid du Colombier {					/* command register */
46*a81c3ea0SDavid du Colombier 	IOen		= (1<<0),
47*a81c3ea0SDavid du Colombier 	MEMen		= (1<<1),
48*a81c3ea0SDavid du Colombier 	MASen		= (1<<2),
49*a81c3ea0SDavid du Colombier 	MemWrInv	= (1<<4),
50*a81c3ea0SDavid du Colombier 	PErrEn		= (1<<6),
51*a81c3ea0SDavid du Colombier 	SErrEn		= (1<<8),
52*a81c3ea0SDavid du Colombier };
53*a81c3ea0SDavid du Colombier 
54*a81c3ea0SDavid du Colombier static Lock pcicfglock;
55*a81c3ea0SDavid du Colombier static Lock pcicfginitlock;
56*a81c3ea0SDavid du Colombier static int pcicfgmode = -1;
57*a81c3ea0SDavid du Colombier static int pcimaxbno = 0;
58*a81c3ea0SDavid du Colombier static int pcimaxdno;
59*a81c3ea0SDavid du Colombier static Pcidev *pciroot;
60*a81c3ea0SDavid du Colombier static Pcidev *pcilist;
61*a81c3ea0SDavid du Colombier static Pcidev *pcitail;
62*a81c3ea0SDavid du Colombier static Pci *pci = (Pci*)PCICFG;
63*a81c3ea0SDavid du Colombier 
64*a81c3ea0SDavid du Colombier static int pcicfgrw8(int, int, int, int);
65*a81c3ea0SDavid du Colombier static int pcicfgrw16(int, int, int, int);
66*a81c3ea0SDavid du Colombier static int pcicfgrw32(int, int, int, int);
67*a81c3ea0SDavid du Colombier 
68*a81c3ea0SDavid du Colombier static char* bustypes[] = {
69*a81c3ea0SDavid du Colombier 	"CBUSI",
70*a81c3ea0SDavid du Colombier 	"CBUSII",
71*a81c3ea0SDavid du Colombier 	"EISA",
72*a81c3ea0SDavid du Colombier 	"FUTURE",
73*a81c3ea0SDavid du Colombier 	"INTERN",
74*a81c3ea0SDavid du Colombier 	"ISA",
75*a81c3ea0SDavid du Colombier 	"MBI",
76*a81c3ea0SDavid du Colombier 	"MBII",
77*a81c3ea0SDavid du Colombier 	"MCA",
78*a81c3ea0SDavid du Colombier 	"MPI",
79*a81c3ea0SDavid du Colombier 	"MPSA",
80*a81c3ea0SDavid du Colombier 	"NUBUS",
81*a81c3ea0SDavid du Colombier 	"PCI",
82*a81c3ea0SDavid du Colombier 	"PCMCIA",
83*a81c3ea0SDavid du Colombier 	"TC",
84*a81c3ea0SDavid du Colombier 	"VL",
85*a81c3ea0SDavid du Colombier 	"VME",
86*a81c3ea0SDavid du Colombier 	"XPRESS",
87*a81c3ea0SDavid du Colombier };
88*a81c3ea0SDavid du Colombier 
89*a81c3ea0SDavid du Colombier static int
tbdffmt(Fmt * fmt)90*a81c3ea0SDavid du Colombier tbdffmt(Fmt* fmt)
91*a81c3ea0SDavid du Colombier {
92*a81c3ea0SDavid du Colombier 	char *p;
93*a81c3ea0SDavid du Colombier 	int l, r;
94*a81c3ea0SDavid du Colombier 	uint type, tbdf;
95*a81c3ea0SDavid du Colombier 
96*a81c3ea0SDavid du Colombier 	if((p = malloc(READSTR)) == nil)
97*a81c3ea0SDavid du Colombier 		return fmtstrcpy(fmt, "(tbdfconv)");
98*a81c3ea0SDavid du Colombier 
99*a81c3ea0SDavid du Colombier 	switch(fmt->r){
100*a81c3ea0SDavid du Colombier 	case 'T':
101*a81c3ea0SDavid du Colombier 		tbdf = va_arg(fmt->args, int);
102*a81c3ea0SDavid du Colombier 		if(tbdf == BUSUNKNOWN)
103*a81c3ea0SDavid du Colombier 			snprint(p, READSTR, "unknown");
104*a81c3ea0SDavid du Colombier 		else{
105*a81c3ea0SDavid du Colombier 			type = BUSTYPE(tbdf);
106*a81c3ea0SDavid du Colombier 			if(type < nelem(bustypes))
107*a81c3ea0SDavid du Colombier 				l = snprint(p, READSTR, bustypes[type]);
108*a81c3ea0SDavid du Colombier 			else
109*a81c3ea0SDavid du Colombier 				l = snprint(p, READSTR, "%d", type);
110*a81c3ea0SDavid du Colombier 			snprint(p+l, READSTR-l, ".%d.%d.%d",
111*a81c3ea0SDavid du Colombier 				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
112*a81c3ea0SDavid du Colombier 		}
113*a81c3ea0SDavid du Colombier 		break;
114*a81c3ea0SDavid du Colombier 
115*a81c3ea0SDavid du Colombier 	default:
116*a81c3ea0SDavid du Colombier 		snprint(p, READSTR, "(tbdfconv)");
117*a81c3ea0SDavid du Colombier 		break;
118*a81c3ea0SDavid du Colombier 	}
119*a81c3ea0SDavid du Colombier 	r = fmtstrcpy(fmt, p);
120*a81c3ea0SDavid du Colombier 	free(p);
121*a81c3ea0SDavid du Colombier 
122*a81c3ea0SDavid du Colombier 	return r;
123*a81c3ea0SDavid du Colombier }
124*a81c3ea0SDavid du Colombier 
125*a81c3ea0SDavid du Colombier ulong
pcibarsize(Pcidev * p,int rno)126*a81c3ea0SDavid du Colombier pcibarsize(Pcidev *p, int rno)
127*a81c3ea0SDavid du Colombier {
128*a81c3ea0SDavid du Colombier 	ulong v, size;
129*a81c3ea0SDavid du Colombier 
130*a81c3ea0SDavid du Colombier 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
131*a81c3ea0SDavid du Colombier 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
132*a81c3ea0SDavid du Colombier 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
133*a81c3ea0SDavid du Colombier 	if(v & 1)
134*a81c3ea0SDavid du Colombier 		size |= 0xFFFF0000;
135*a81c3ea0SDavid du Colombier 	pcicfgrw32(p->tbdf, rno, v, 0);
136*a81c3ea0SDavid du Colombier 
137*a81c3ea0SDavid du Colombier 	return -(size & ~0x0F);
138*a81c3ea0SDavid du Colombier }
139*a81c3ea0SDavid du Colombier 
140*a81c3ea0SDavid du Colombier static int
pcilscan(int bno,Pcidev ** list)141*a81c3ea0SDavid du Colombier pcilscan(int bno, Pcidev** list)
142*a81c3ea0SDavid du Colombier {
143*a81c3ea0SDavid du Colombier 	Pcidev *p, *head, *tail;
144*a81c3ea0SDavid du Colombier 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
145*a81c3ea0SDavid du Colombier 
146*a81c3ea0SDavid du Colombier 	maxubn = bno;
147*a81c3ea0SDavid du Colombier 	head = nil;
148*a81c3ea0SDavid du Colombier 	tail = nil;
149*a81c3ea0SDavid du Colombier 	/* dno from 5 due to its address mode */
150*a81c3ea0SDavid du Colombier 	for(dno = 5; dno <= pcimaxdno; dno++){
151*a81c3ea0SDavid du Colombier 		maxfno = 0;
152*a81c3ea0SDavid du Colombier 		for(fno = 0; fno <= maxfno; fno++){
153*a81c3ea0SDavid du Colombier 			/*
154*a81c3ea0SDavid du Colombier 			 * For this possible device, form the
155*a81c3ea0SDavid du Colombier 			 * bus+device+function triplet needed to address it
156*a81c3ea0SDavid du Colombier 			 * and try to read the vendor and device ID.
157*a81c3ea0SDavid du Colombier 			 * If successful, allocate a device struct and
158*a81c3ea0SDavid du Colombier 			 * start to fill it in with some useful information
159*a81c3ea0SDavid du Colombier 			 * from the device's configuration space.
160*a81c3ea0SDavid du Colombier 			 */
161*a81c3ea0SDavid du Colombier 			tbdf = MKBUS(BusPCI, bno, dno, fno);
162*a81c3ea0SDavid du Colombier 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
163*a81c3ea0SDavid du Colombier 			if(l == 0xFFFFFFFF || l == 0)
164*a81c3ea0SDavid du Colombier 				continue;
165*a81c3ea0SDavid du Colombier 			p = malloc(sizeof(*p));
166*a81c3ea0SDavid du Colombier 			if(p == nil)
167*a81c3ea0SDavid du Colombier 				panic("pcilscan: no memory");
168*a81c3ea0SDavid du Colombier 			p->tbdf = tbdf;
169*a81c3ea0SDavid du Colombier 			p->vid = l;
170*a81c3ea0SDavid du Colombier 			p->did = l>>16;
171*a81c3ea0SDavid du Colombier 
172*a81c3ea0SDavid du Colombier 			if(pcilist != nil)
173*a81c3ea0SDavid du Colombier 				pcitail->list = p;
174*a81c3ea0SDavid du Colombier 			else
175*a81c3ea0SDavid du Colombier 				pcilist = p;
176*a81c3ea0SDavid du Colombier 			pcitail = p;
177*a81c3ea0SDavid du Colombier 
178*a81c3ea0SDavid du Colombier 			p->pcr = pcicfgr16(p, PciPCR);
179*a81c3ea0SDavid du Colombier 			p->rid = pcicfgr8(p, PciRID);
180*a81c3ea0SDavid du Colombier 			p->ccrp = pcicfgr8(p, PciCCRp);
181*a81c3ea0SDavid du Colombier 			p->ccru = pcicfgr8(p, PciCCRu);
182*a81c3ea0SDavid du Colombier 			p->ccrb = pcicfgr8(p, PciCCRb);
183*a81c3ea0SDavid du Colombier 			p->cls = pcicfgr8(p, PciCLS);
184*a81c3ea0SDavid du Colombier 			p->ltr = pcicfgr8(p, PciLTR);
185*a81c3ea0SDavid du Colombier 
186*a81c3ea0SDavid du Colombier 			p->intl = pcicfgr8(p, PciINTL);
187*a81c3ea0SDavid du Colombier 			p->intp = pcicfgr8(p, PciINTP);
188*a81c3ea0SDavid du Colombier 
189*a81c3ea0SDavid du Colombier 			/*
190*a81c3ea0SDavid du Colombier 			 * If the device is a multi-function device adjust the
191*a81c3ea0SDavid du Colombier 			 * loop count so all possible functions are checked.
192*a81c3ea0SDavid du Colombier 			 */
193*a81c3ea0SDavid du Colombier 			hdt = pcicfgr8(p, PciHDT);
194*a81c3ea0SDavid du Colombier 			if(hdt & 0x80)
195*a81c3ea0SDavid du Colombier 				maxfno = MaxFNO;
196*a81c3ea0SDavid du Colombier 
197*a81c3ea0SDavid du Colombier 			/*
198*a81c3ea0SDavid du Colombier 			 * If appropriate, read the base address registers
199*a81c3ea0SDavid du Colombier 			 * and work out the sizes.
200*a81c3ea0SDavid du Colombier 			 */
201*a81c3ea0SDavid du Colombier 			switch(p->ccrb) {
202*a81c3ea0SDavid du Colombier 			case 0x03:		/* display controller */
203*a81c3ea0SDavid du Colombier 				/* fall through */
204*a81c3ea0SDavid du Colombier 			case 0x01:		/* mass storage controller */
205*a81c3ea0SDavid du Colombier 			case 0x02:		/* network controller */
206*a81c3ea0SDavid du Colombier 			case 0x04:		/* multimedia device */
207*a81c3ea0SDavid du Colombier 			case 0x07:		/* simple comm. controllers */
208*a81c3ea0SDavid du Colombier 			case 0x08:		/* base system peripherals */
209*a81c3ea0SDavid du Colombier 			case 0x09:		/* input devices */
210*a81c3ea0SDavid du Colombier 			case 0x0A:		/* docking stations */
211*a81c3ea0SDavid du Colombier 			case 0x0B:		/* processors */
212*a81c3ea0SDavid du Colombier 			case 0x0C:		/* serial bus controllers */
213*a81c3ea0SDavid du Colombier 				if((hdt & 0x7F) != 0)
214*a81c3ea0SDavid du Colombier 					break;
215*a81c3ea0SDavid du Colombier 				rno = PciBAR0 - 4;
216*a81c3ea0SDavid du Colombier 				for(i = 0; i < nelem(p->mem); i++) {
217*a81c3ea0SDavid du Colombier 					rno += 4;
218*a81c3ea0SDavid du Colombier 					p->mem[i].bar = pcicfgr32(p, rno);
219*a81c3ea0SDavid du Colombier 					p->mem[i].size = pcibarsize(p, rno);
220*a81c3ea0SDavid du Colombier 				}
221*a81c3ea0SDavid du Colombier 				break;
222*a81c3ea0SDavid du Colombier 
223*a81c3ea0SDavid du Colombier 			case 0x00:
224*a81c3ea0SDavid du Colombier 			case 0x05:		/* memory controller */
225*a81c3ea0SDavid du Colombier 			case 0x06:		/* bridge device */
226*a81c3ea0SDavid du Colombier 			default:
227*a81c3ea0SDavid du Colombier 				break;
228*a81c3ea0SDavid du Colombier 			}
229*a81c3ea0SDavid du Colombier 
230*a81c3ea0SDavid du Colombier 			if(head != nil)
231*a81c3ea0SDavid du Colombier 				tail->link = p;
232*a81c3ea0SDavid du Colombier 			else
233*a81c3ea0SDavid du Colombier 				head = p;
234*a81c3ea0SDavid du Colombier 			tail = p;
235*a81c3ea0SDavid du Colombier 		}
236*a81c3ea0SDavid du Colombier 	}
237*a81c3ea0SDavid du Colombier 
238*a81c3ea0SDavid du Colombier 	*list = head;
239*a81c3ea0SDavid du Colombier 	for(p = head; p != nil; p = p->link){
240*a81c3ea0SDavid du Colombier 		/*
241*a81c3ea0SDavid du Colombier 		 * Find PCI-PCI bridges and recursively descend the tree.
242*a81c3ea0SDavid du Colombier 		 */
243*a81c3ea0SDavid du Colombier 		if(p->ccrb != 0x06 || p->ccru != 0x04)
244*a81c3ea0SDavid du Colombier 			continue;
245*a81c3ea0SDavid du Colombier 
246*a81c3ea0SDavid du Colombier 		/*
247*a81c3ea0SDavid du Colombier 		 * If the secondary or subordinate bus number is not
248*a81c3ea0SDavid du Colombier 		 * initialised try to do what the PCI BIOS should have
249*a81c3ea0SDavid du Colombier 		 * done and fill in the numbers as the tree is descended.
250*a81c3ea0SDavid du Colombier 		 * On the way down the subordinate bus number is set to
251*a81c3ea0SDavid du Colombier 		 * the maximum as it's not known how many buses are behind
252*a81c3ea0SDavid du Colombier 		 * this one; the final value is set on the way back up.
253*a81c3ea0SDavid du Colombier 		 */
254*a81c3ea0SDavid du Colombier 		sbn = pcicfgr8(p, PciSBN);
255*a81c3ea0SDavid du Colombier 		ubn = pcicfgr8(p, PciUBN);
256*a81c3ea0SDavid du Colombier 
257*a81c3ea0SDavid du Colombier 		if(sbn == 0 || ubn == 0) {
258*a81c3ea0SDavid du Colombier 			sbn = maxubn+1;
259*a81c3ea0SDavid du Colombier 			/*
260*a81c3ea0SDavid du Colombier 			 * Make sure memory, I/O and master enables are
261*a81c3ea0SDavid du Colombier 			 * off, set the primary, secondary and subordinate
262*a81c3ea0SDavid du Colombier 			 * bus numbers and clear the secondary status before
263*a81c3ea0SDavid du Colombier 			 * attempting to scan the secondary bus.
264*a81c3ea0SDavid du Colombier 			 *
265*a81c3ea0SDavid du Colombier 			 * Initialisation of the bridge should be done here.
266*a81c3ea0SDavid du Colombier 			 */
267*a81c3ea0SDavid du Colombier 			pcicfgw32(p, PciPCR, 0xFFFF0000);
268*a81c3ea0SDavid du Colombier 			l = (MaxUBN<<16)|(sbn<<8)|bno;
269*a81c3ea0SDavid du Colombier 			pcicfgw32(p, PciPBN, l);
270*a81c3ea0SDavid du Colombier 			pcicfgw16(p, PciSPSR, 0xFFFF);
271*a81c3ea0SDavid du Colombier 			maxubn = pcilscan(sbn, &p->bridge);
272*a81c3ea0SDavid du Colombier 			l = (maxubn<<16)|(sbn<<8)|bno;
273*a81c3ea0SDavid du Colombier 
274*a81c3ea0SDavid du Colombier 			pcicfgw32(p, PciPBN, l);
275*a81c3ea0SDavid du Colombier 		}
276*a81c3ea0SDavid du Colombier 		else {
277*a81c3ea0SDavid du Colombier 			if(ubn > maxubn)
278*a81c3ea0SDavid du Colombier 				maxubn = ubn;
279*a81c3ea0SDavid du Colombier 			pcilscan(sbn, &p->bridge);
280*a81c3ea0SDavid du Colombier 		}
281*a81c3ea0SDavid du Colombier 	}
282*a81c3ea0SDavid du Colombier 
283*a81c3ea0SDavid du Colombier 	return maxubn;
284*a81c3ea0SDavid du Colombier }
285*a81c3ea0SDavid du Colombier 
286*a81c3ea0SDavid du Colombier static void
pcicfginit(void)287*a81c3ea0SDavid du Colombier pcicfginit(void)
288*a81c3ea0SDavid du Colombier {
289*a81c3ea0SDavid du Colombier 	char *p;
290*a81c3ea0SDavid du Colombier 	int n, bno;
291*a81c3ea0SDavid du Colombier 	Pcidev **list;
292*a81c3ea0SDavid du Colombier 
293*a81c3ea0SDavid du Colombier 	lock(&pcicfginitlock);
294*a81c3ea0SDavid du Colombier 	if(pcicfgmode != -1) {
295*a81c3ea0SDavid du Colombier 		unlock(&pcicfginitlock);
296*a81c3ea0SDavid du Colombier 		return;
297*a81c3ea0SDavid du Colombier 	}
298*a81c3ea0SDavid du Colombier 
299*a81c3ea0SDavid du Colombier 	pcicfgmode = 1;
300*a81c3ea0SDavid du Colombier 	pcimaxdno = 19;
301*a81c3ea0SDavid du Colombier 
302*a81c3ea0SDavid du Colombier 	fmtinstall('T', tbdffmt);
303*a81c3ea0SDavid du Colombier 
304*a81c3ea0SDavid du Colombier 	if(p = getconf("*pcimaxbno")){
305*a81c3ea0SDavid du Colombier 		n = strtoul(p, 0, 0);
306*a81c3ea0SDavid du Colombier 		if(n < pcimaxbno)
307*a81c3ea0SDavid du Colombier 			pcimaxbno = n;
308*a81c3ea0SDavid du Colombier 	}
309*a81c3ea0SDavid du Colombier 	if(p = getconf("*pcimaxdno")){
310*a81c3ea0SDavid du Colombier 		n = strtoul(p, 0, 0);
311*a81c3ea0SDavid du Colombier 		if(n < pcimaxdno)
312*a81c3ea0SDavid du Colombier 			pcimaxdno = n;
313*a81c3ea0SDavid du Colombier 	}
314*a81c3ea0SDavid du Colombier 
315*a81c3ea0SDavid du Colombier 	list = &pciroot;
316*a81c3ea0SDavid du Colombier 	for(bno = 0; bno <= pcimaxbno; bno++){
317*a81c3ea0SDavid du Colombier 		bno = pcilscan(bno, list);
318*a81c3ea0SDavid du Colombier 		while(*list)
319*a81c3ea0SDavid du Colombier 			list = &(*list)->link;
320*a81c3ea0SDavid du Colombier 	}
321*a81c3ea0SDavid du Colombier 	unlock(&pcicfginitlock);
322*a81c3ea0SDavid du Colombier }
323*a81c3ea0SDavid du Colombier 
324*a81c3ea0SDavid du Colombier /* map the devince's cfg space and calculate the address */
325*a81c3ea0SDavid du Colombier static void*
pcidevcfgaddr(int tbdf,int rno)326*a81c3ea0SDavid du Colombier pcidevcfgaddr(int tbdf, int rno)
327*a81c3ea0SDavid du Colombier {
328*a81c3ea0SDavid du Colombier 	ulong addr;
329*a81c3ea0SDavid du Colombier 	ulong b, d, f, type;
330*a81c3ea0SDavid du Colombier 
331*a81c3ea0SDavid du Colombier 	b = BUSBNO(tbdf);
332*a81c3ea0SDavid du Colombier 	d = BUSDNO(tbdf);
333*a81c3ea0SDavid du Colombier 	f = BUSFNO(tbdf);
334*a81c3ea0SDavid du Colombier     if(b == 0) {
335*a81c3ea0SDavid du Colombier         /* Type 0 configuration on onboard PCI bus */
336*a81c3ea0SDavid du Colombier         addr = (1<<(d+11))|(f<<8)|rno;
337*a81c3ea0SDavid du Colombier         type = 0x00000;
338*a81c3ea0SDavid du Colombier     } else {
339*a81c3ea0SDavid du Colombier         /* Type 1 configuration on offboard PCI bus */
340*a81c3ea0SDavid du Colombier         addr = (b<<16)|(d<<11)|(f<<8)|rno;
341*a81c3ea0SDavid du Colombier         type = 0x10000;
342*a81c3ea0SDavid du Colombier     }
343*a81c3ea0SDavid du Colombier 
344*a81c3ea0SDavid du Colombier     /* clear aborts */
345*a81c3ea0SDavid du Colombier     pci->cs |= SMasAb | SMasTgtAb;
346*a81c3ea0SDavid du Colombier 
347*a81c3ea0SDavid du Colombier 	/* config map cfg reg to map the device's cfg space */
348*a81c3ea0SDavid du Colombier     *Pcimapcfg = (addr>>16)|type;
349*a81c3ea0SDavid du Colombier 
350*a81c3ea0SDavid du Colombier 	return (void*)(PCIDEVCFG+(addr&0xffff));
351*a81c3ea0SDavid du Colombier }
352*a81c3ea0SDavid du Colombier 
353*a81c3ea0SDavid du Colombier static int
pcicfgrw8(int tbdf,int rno,int data,int read)354*a81c3ea0SDavid du Colombier pcicfgrw8(int tbdf, int rno, int data, int read)
355*a81c3ea0SDavid du Colombier {
356*a81c3ea0SDavid du Colombier 	int x;
357*a81c3ea0SDavid du Colombier 	void *addr;
358*a81c3ea0SDavid du Colombier 
359*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
360*a81c3ea0SDavid du Colombier 		pcicfginit();
361*a81c3ea0SDavid du Colombier 
362*a81c3ea0SDavid du Colombier 	x = -1;
363*a81c3ea0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
364*a81c3ea0SDavid du Colombier 		return x;
365*a81c3ea0SDavid du Colombier 
366*a81c3ea0SDavid du Colombier 	lock(&pcicfglock);
367*a81c3ea0SDavid du Colombier 	addr = pcidevcfgaddr(tbdf, rno);
368*a81c3ea0SDavid du Colombier 	if(read)
369*a81c3ea0SDavid du Colombier 		x = *(uchar*)addr;
370*a81c3ea0SDavid du Colombier 	else
371*a81c3ea0SDavid du Colombier 		*(uchar*)addr = data;
372*a81c3ea0SDavid du Colombier 	unlock(&pcicfglock);
373*a81c3ea0SDavid du Colombier 
374*a81c3ea0SDavid du Colombier 	return x;
375*a81c3ea0SDavid du Colombier }
376*a81c3ea0SDavid du Colombier 
377*a81c3ea0SDavid du Colombier int
pcicfgr8(Pcidev * pcidev,int rno)378*a81c3ea0SDavid du Colombier pcicfgr8(Pcidev* pcidev, int rno)
379*a81c3ea0SDavid du Colombier {
380*a81c3ea0SDavid du Colombier 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
381*a81c3ea0SDavid du Colombier }
382*a81c3ea0SDavid du Colombier 
383*a81c3ea0SDavid du Colombier void
pcicfgw8(Pcidev * pcidev,int rno,int data)384*a81c3ea0SDavid du Colombier pcicfgw8(Pcidev* pcidev, int rno, int data)
385*a81c3ea0SDavid du Colombier {
386*a81c3ea0SDavid du Colombier 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
387*a81c3ea0SDavid du Colombier }
388*a81c3ea0SDavid du Colombier 
389*a81c3ea0SDavid du Colombier static int
pcicfgrw16(int tbdf,int rno,int data,int read)390*a81c3ea0SDavid du Colombier pcicfgrw16(int tbdf, int rno, int data, int read)
391*a81c3ea0SDavid du Colombier {
392*a81c3ea0SDavid du Colombier 	int x;
393*a81c3ea0SDavid du Colombier 	void *addr;
394*a81c3ea0SDavid du Colombier 
395*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
396*a81c3ea0SDavid du Colombier 		pcicfginit();
397*a81c3ea0SDavid du Colombier 
398*a81c3ea0SDavid du Colombier 	x = -1;
399*a81c3ea0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
400*a81c3ea0SDavid du Colombier 		return x;
401*a81c3ea0SDavid du Colombier 
402*a81c3ea0SDavid du Colombier 	lock(&pcicfglock);
403*a81c3ea0SDavid du Colombier 	addr = pcidevcfgaddr(tbdf, rno);
404*a81c3ea0SDavid du Colombier 	if(read)
405*a81c3ea0SDavid du Colombier 		x = *(ushort*)addr;
406*a81c3ea0SDavid du Colombier 	else
407*a81c3ea0SDavid du Colombier 		*(ushort*)addr = data;
408*a81c3ea0SDavid du Colombier 	unlock(&pcicfglock);
409*a81c3ea0SDavid du Colombier 
410*a81c3ea0SDavid du Colombier 	return x;
411*a81c3ea0SDavid du Colombier }
412*a81c3ea0SDavid du Colombier 
413*a81c3ea0SDavid du Colombier int
pcicfgr16(Pcidev * pcidev,int rno)414*a81c3ea0SDavid du Colombier pcicfgr16(Pcidev* pcidev, int rno)
415*a81c3ea0SDavid du Colombier {
416*a81c3ea0SDavid du Colombier 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
417*a81c3ea0SDavid du Colombier }
418*a81c3ea0SDavid du Colombier 
419*a81c3ea0SDavid du Colombier void
pcicfgw16(Pcidev * pcidev,int rno,int data)420*a81c3ea0SDavid du Colombier pcicfgw16(Pcidev* pcidev, int rno, int data)
421*a81c3ea0SDavid du Colombier {
422*a81c3ea0SDavid du Colombier 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
423*a81c3ea0SDavid du Colombier }
424*a81c3ea0SDavid du Colombier 
425*a81c3ea0SDavid du Colombier static int
pcicfgrw32(int tbdf,int rno,int data,int read)426*a81c3ea0SDavid du Colombier pcicfgrw32(int tbdf, int rno, int data, int read)
427*a81c3ea0SDavid du Colombier {
428*a81c3ea0SDavid du Colombier 	int x;
429*a81c3ea0SDavid du Colombier 	void *addr;
430*a81c3ea0SDavid du Colombier 
431*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
432*a81c3ea0SDavid du Colombier 		pcicfginit();
433*a81c3ea0SDavid du Colombier 
434*a81c3ea0SDavid du Colombier 	x = -1;
435*a81c3ea0SDavid du Colombier 	if(BUSDNO(tbdf) > pcimaxdno)
436*a81c3ea0SDavid du Colombier 		return x;
437*a81c3ea0SDavid du Colombier 
438*a81c3ea0SDavid du Colombier 	lock(&pcicfglock);
439*a81c3ea0SDavid du Colombier 	addr = pcidevcfgaddr(tbdf, rno);
440*a81c3ea0SDavid du Colombier 	if(read)
441*a81c3ea0SDavid du Colombier 		x = *(ulong*)addr;
442*a81c3ea0SDavid du Colombier 	else
443*a81c3ea0SDavid du Colombier 		*(ulong*)addr = data;
444*a81c3ea0SDavid du Colombier 	unlock(&pcicfglock);
445*a81c3ea0SDavid du Colombier 
446*a81c3ea0SDavid du Colombier 	return x;
447*a81c3ea0SDavid du Colombier }
448*a81c3ea0SDavid du Colombier 
449*a81c3ea0SDavid du Colombier int
pcicfgr32(Pcidev * pcidev,int rno)450*a81c3ea0SDavid du Colombier pcicfgr32(Pcidev* pcidev, int rno)
451*a81c3ea0SDavid du Colombier {
452*a81c3ea0SDavid du Colombier 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
453*a81c3ea0SDavid du Colombier }
454*a81c3ea0SDavid du Colombier 
455*a81c3ea0SDavid du Colombier void
pcicfgw32(Pcidev * pcidev,int rno,int data)456*a81c3ea0SDavid du Colombier pcicfgw32(Pcidev* pcidev, int rno, int data)
457*a81c3ea0SDavid du Colombier {
458*a81c3ea0SDavid du Colombier 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
459*a81c3ea0SDavid du Colombier }
460*a81c3ea0SDavid du Colombier 
461*a81c3ea0SDavid du Colombier Pcidev*
pcimatch(Pcidev * prev,int vid,int did)462*a81c3ea0SDavid du Colombier pcimatch(Pcidev* prev, int vid, int did)
463*a81c3ea0SDavid du Colombier {
464*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
465*a81c3ea0SDavid du Colombier 		pcicfginit();
466*a81c3ea0SDavid du Colombier 
467*a81c3ea0SDavid du Colombier 	if(prev == nil)
468*a81c3ea0SDavid du Colombier 		prev = pcilist;
469*a81c3ea0SDavid du Colombier 	else
470*a81c3ea0SDavid du Colombier 		prev = prev->list;
471*a81c3ea0SDavid du Colombier 
472*a81c3ea0SDavid du Colombier 	while(prev != nil){
473*a81c3ea0SDavid du Colombier 		if((vid == 0 || prev->vid == vid)
474*a81c3ea0SDavid du Colombier 		&& (did == 0 || prev->did == did))
475*a81c3ea0SDavid du Colombier 			break;
476*a81c3ea0SDavid du Colombier 		prev = prev->list;
477*a81c3ea0SDavid du Colombier 	}
478*a81c3ea0SDavid du Colombier 	return prev;
479*a81c3ea0SDavid du Colombier }
480*a81c3ea0SDavid du Colombier 
481*a81c3ea0SDavid du Colombier Pcidev*
pcimatchtbdf(int tbdf)482*a81c3ea0SDavid du Colombier pcimatchtbdf(int tbdf)
483*a81c3ea0SDavid du Colombier {
484*a81c3ea0SDavid du Colombier 	Pcidev *pcidev;
485*a81c3ea0SDavid du Colombier 
486*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
487*a81c3ea0SDavid du Colombier 		pcicfginit();
488*a81c3ea0SDavid du Colombier 
489*a81c3ea0SDavid du Colombier 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
490*a81c3ea0SDavid du Colombier 		if(pcidev->tbdf == tbdf)
491*a81c3ea0SDavid du Colombier 			break;
492*a81c3ea0SDavid du Colombier 	}
493*a81c3ea0SDavid du Colombier 	return pcidev;
494*a81c3ea0SDavid du Colombier }
495*a81c3ea0SDavid du Colombier 
496*a81c3ea0SDavid du Colombier void
pcireset(void)497*a81c3ea0SDavid du Colombier pcireset(void)
498*a81c3ea0SDavid du Colombier {
499*a81c3ea0SDavid du Colombier 	Pcidev *p;
500*a81c3ea0SDavid du Colombier 
501*a81c3ea0SDavid du Colombier 	if(pcicfgmode == -1)
502*a81c3ea0SDavid du Colombier 		pcicfginit();
503*a81c3ea0SDavid du Colombier 
504*a81c3ea0SDavid du Colombier 	for(p = pcilist; p != nil; p = p->list) {
505*a81c3ea0SDavid du Colombier 		/* don't mess with the bridges */
506*a81c3ea0SDavid du Colombier 		if(p->ccrb == 0x06)
507*a81c3ea0SDavid du Colombier 			continue;
508*a81c3ea0SDavid du Colombier 		pciclrbme(p);
509*a81c3ea0SDavid du Colombier 	}
510*a81c3ea0SDavid du Colombier }
511*a81c3ea0SDavid du Colombier 
512*a81c3ea0SDavid du Colombier void
pcisetioe(Pcidev * p)513*a81c3ea0SDavid du Colombier pcisetioe(Pcidev* p)
514*a81c3ea0SDavid du Colombier {
515*a81c3ea0SDavid du Colombier 	p->pcr |= IOen;
516*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
517*a81c3ea0SDavid du Colombier }
518*a81c3ea0SDavid du Colombier 
519*a81c3ea0SDavid du Colombier void
pciclrioe(Pcidev * p)520*a81c3ea0SDavid du Colombier pciclrioe(Pcidev* p)
521*a81c3ea0SDavid du Colombier {
522*a81c3ea0SDavid du Colombier 	p->pcr &= ~IOen;
523*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
524*a81c3ea0SDavid du Colombier }
525*a81c3ea0SDavid du Colombier 
526*a81c3ea0SDavid du Colombier void
pcisetbme(Pcidev * p)527*a81c3ea0SDavid du Colombier pcisetbme(Pcidev* p)
528*a81c3ea0SDavid du Colombier {
529*a81c3ea0SDavid du Colombier 	p->pcr |= MASen;
530*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
531*a81c3ea0SDavid du Colombier }
532*a81c3ea0SDavid du Colombier 
533*a81c3ea0SDavid du Colombier void
pciclrbme(Pcidev * p)534*a81c3ea0SDavid du Colombier pciclrbme(Pcidev* p)
535*a81c3ea0SDavid du Colombier {
536*a81c3ea0SDavid du Colombier 	p->pcr &= ~MASen;
537*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
538*a81c3ea0SDavid du Colombier }
539*a81c3ea0SDavid du Colombier 
540*a81c3ea0SDavid du Colombier void
pcisetmwi(Pcidev * p)541*a81c3ea0SDavid du Colombier pcisetmwi(Pcidev* p)
542*a81c3ea0SDavid du Colombier {
543*a81c3ea0SDavid du Colombier 	p->pcr |= MemWrInv;
544*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
545*a81c3ea0SDavid du Colombier }
546*a81c3ea0SDavid du Colombier 
547*a81c3ea0SDavid du Colombier void
pciclrmwi(Pcidev * p)548*a81c3ea0SDavid du Colombier pciclrmwi(Pcidev* p)
549*a81c3ea0SDavid du Colombier {
550*a81c3ea0SDavid du Colombier 	p->pcr &= ~MemWrInv;
551*a81c3ea0SDavid du Colombier 	pcicfgw16(p, PciPCR, p->pcr);
552*a81c3ea0SDavid du Colombier }
553*a81c3ea0SDavid du Colombier 
554*a81c3ea0SDavid du Colombier static int
pcigetpmrb(Pcidev * p)555*a81c3ea0SDavid du Colombier pcigetpmrb(Pcidev* p)
556*a81c3ea0SDavid du Colombier {
557*a81c3ea0SDavid du Colombier 	int ptr;
558*a81c3ea0SDavid du Colombier 
559*a81c3ea0SDavid du Colombier 	if(p->pmrb != 0)
560*a81c3ea0SDavid du Colombier 		return p->pmrb;
561*a81c3ea0SDavid du Colombier 	p->pmrb = -1;
562*a81c3ea0SDavid du Colombier 
563*a81c3ea0SDavid du Colombier 	/*
564*a81c3ea0SDavid du Colombier 	 * If there are no extended capabilities implemented,
565*a81c3ea0SDavid du Colombier 	 * (bit 4 in the status register) assume there's no standard
566*a81c3ea0SDavid du Colombier 	 * power management method.
567*a81c3ea0SDavid du Colombier 	 * Find the capabilities pointer based on PCI header type.
568*a81c3ea0SDavid du Colombier 	 */
569*a81c3ea0SDavid du Colombier 	if(!(pcicfgr16(p, PciPSR) & 0x0010))
570*a81c3ea0SDavid du Colombier 		return -1;
571*a81c3ea0SDavid du Colombier 	switch(pcicfgr8(p, PciHDT)){
572*a81c3ea0SDavid du Colombier 	default:
573*a81c3ea0SDavid du Colombier 		return -1;
574*a81c3ea0SDavid du Colombier 	case 0:					/* all other */
575*a81c3ea0SDavid du Colombier 	case 1:					/* PCI to PCI bridge */
576*a81c3ea0SDavid du Colombier 		ptr = 0x34;
577*a81c3ea0SDavid du Colombier 		break;
578*a81c3ea0SDavid du Colombier 	case 2:					/* CardBus bridge */
579*a81c3ea0SDavid du Colombier 		ptr = 0x14;
580*a81c3ea0SDavid du Colombier 		break;
581*a81c3ea0SDavid du Colombier 	}
582*a81c3ea0SDavid du Colombier 	ptr = pcicfgr32(p, ptr);
583*a81c3ea0SDavid du Colombier 
584*a81c3ea0SDavid du Colombier 	while(ptr != 0){
585*a81c3ea0SDavid du Colombier 		/*
586*a81c3ea0SDavid du Colombier 		 * Check for validity.
587*a81c3ea0SDavid du Colombier 		 * Can't be in standard header and must be double
588*a81c3ea0SDavid du Colombier 		 * word aligned.
589*a81c3ea0SDavid du Colombier 		 */
590*a81c3ea0SDavid du Colombier 		if(ptr < 0x40 || (ptr & ~0xFC))
591*a81c3ea0SDavid du Colombier 			return -1;
592*a81c3ea0SDavid du Colombier 		if(pcicfgr8(p, ptr) == 0x01){
593*a81c3ea0SDavid du Colombier 			p->pmrb = ptr;
594*a81c3ea0SDavid du Colombier 			return ptr;
595*a81c3ea0SDavid du Colombier 		}
596*a81c3ea0SDavid du Colombier 
597*a81c3ea0SDavid du Colombier 		ptr = pcicfgr8(p, ptr+1);
598*a81c3ea0SDavid du Colombier 	}
599*a81c3ea0SDavid du Colombier 
600*a81c3ea0SDavid du Colombier 	return -1;
601*a81c3ea0SDavid du Colombier }
602*a81c3ea0SDavid du Colombier 
603*a81c3ea0SDavid du Colombier int
pcigetpms(Pcidev * p)604*a81c3ea0SDavid du Colombier pcigetpms(Pcidev* p)
605*a81c3ea0SDavid du Colombier {
606*a81c3ea0SDavid du Colombier 	int pmcsr, ptr;
607*a81c3ea0SDavid du Colombier 
608*a81c3ea0SDavid du Colombier 	if((ptr = pcigetpmrb(p)) == -1)
609*a81c3ea0SDavid du Colombier 		return -1;
610*a81c3ea0SDavid du Colombier 
611*a81c3ea0SDavid du Colombier 	/*
612*a81c3ea0SDavid du Colombier 	 * Power Management Register Block:
613*a81c3ea0SDavid du Colombier 	 *  offset 0:	Capability ID
614*a81c3ea0SDavid du Colombier 	 *	   1:	next item pointer
615*a81c3ea0SDavid du Colombier 	 *	   2:	capabilities
616*a81c3ea0SDavid du Colombier 	 *	   4:	control/status
617*a81c3ea0SDavid du Colombier 	 *	   6:	bridge support extensions
618*a81c3ea0SDavid du Colombier 	 *	   7:	data
619*a81c3ea0SDavid du Colombier 	 */
620*a81c3ea0SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
621*a81c3ea0SDavid du Colombier 
622*a81c3ea0SDavid du Colombier 	return pmcsr & 0x0003;
623*a81c3ea0SDavid du Colombier }
624*a81c3ea0SDavid du Colombier 
625*a81c3ea0SDavid du Colombier int
pcisetpms(Pcidev * p,int state)626*a81c3ea0SDavid du Colombier pcisetpms(Pcidev* p, int state)
627*a81c3ea0SDavid du Colombier {
628*a81c3ea0SDavid du Colombier 	int ostate, pmc, pmcsr, ptr;
629*a81c3ea0SDavid du Colombier 
630*a81c3ea0SDavid du Colombier 	if((ptr = pcigetpmrb(p)) == -1)
631*a81c3ea0SDavid du Colombier 		return -1;
632*a81c3ea0SDavid du Colombier 
633*a81c3ea0SDavid du Colombier 	pmc = pcicfgr16(p, ptr+2);
634*a81c3ea0SDavid du Colombier 	pmcsr = pcicfgr16(p, ptr+4);
635*a81c3ea0SDavid du Colombier 	ostate = pmcsr & 0x0003;
636*a81c3ea0SDavid du Colombier 	pmcsr &= ~0x0003;
637*a81c3ea0SDavid du Colombier 
638*a81c3ea0SDavid du Colombier 	switch(state){
639*a81c3ea0SDavid du Colombier 	default:
640*a81c3ea0SDavid du Colombier 		return -1;
641*a81c3ea0SDavid du Colombier 	case 0:
642*a81c3ea0SDavid du Colombier 		break;
643*a81c3ea0SDavid du Colombier 	case 1:
644*a81c3ea0SDavid du Colombier 		if(!(pmc & 0x0200))
645*a81c3ea0SDavid du Colombier 			return -1;
646*a81c3ea0SDavid du Colombier 		break;
647*a81c3ea0SDavid du Colombier 	case 2:
648*a81c3ea0SDavid du Colombier 		if(!(pmc & 0x0400))
649*a81c3ea0SDavid du Colombier 			return -1;
650*a81c3ea0SDavid du Colombier 		break;
651*a81c3ea0SDavid du Colombier 	case 3:
652*a81c3ea0SDavid du Colombier 		break;
653*a81c3ea0SDavid du Colombier 	}
654*a81c3ea0SDavid du Colombier 	pmcsr |= state;
655*a81c3ea0SDavid du Colombier 	pcicfgw16(p, ptr+4, pmcsr);
656*a81c3ea0SDavid du Colombier 
657*a81c3ea0SDavid du Colombier 	return ostate;
658*a81c3ea0SDavid du Colombier }
659*a81c3ea0SDavid du Colombier 
660*a81c3ea0SDavid du Colombier int
pcisubirq(int tbdf)661*a81c3ea0SDavid du Colombier pcisubirq(int tbdf)
662*a81c3ea0SDavid du Colombier {
663*a81c3ea0SDavid du Colombier 	return Pciintrbase + pcicfgrw8(tbdf, PciINTP, 0, 1);
664*a81c3ea0SDavid du Colombier }
665