xref: /inferno-os/os/boot/pc/pci.c (revision 39c35e8d1a4fa90de480fb4882b3a36d76791e04)
1 /*
2  * PCI support code.
3  * To do:
4  *	initialise bridge mappings if the PCI BIOS didn't.
5  */
6 #include "u.h"
7 #include "lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "error.h"
13 
14 enum {					/* configuration mechanism #1 */
15 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
16 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
17 
18 					/* configuration mechanism #2 */
19 	PciCSE		= 0xCF8,	/* configuration space enable */
20 	PciFORWARD	= 0xCFA,	/* which bus */
21 
22 	MaxFNO		= 7,
23 	MaxUBN		= 255,
24 };
25 
26 enum
27 {					/* command register */
28 	IOen		= (1<<0),
29 	MEMen		= (1<<1),
30 	MASen		= (1<<2),
31 	MemWrInv	= (1<<4),
32 	PErrEn		= (1<<6),
33 	SErrEn		= (1<<8),
34 };
35 
36 static Lock pcicfglock;
37 static Lock pcicfginitlock;
38 static int pcicfgmode = -1;
39 static int pcimaxbno = 7;
40 static int pcimaxdno;
41 static Pcidev* pciroot;
42 static Pcidev* pcilist;
43 static Pcidev* pcitail;
44 
45 static int pcicfgrw32(int, int, int, int);
46 static int pcicfgrw8(int, int, int, int);
47 
48 ulong
49 pcibarsize(Pcidev *p, int rno)
50 {
51 	ulong v, size;
52 
53 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
54 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
55 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
56 	if(v & 1)
57 		size |= 0xFFFF0000;
58 	pcicfgrw32(p->tbdf, rno, v, 0);
59 
60 	return -(size & ~0x0F);
61 }
62 
63 int
64 pciscan(int bno, Pcidev** list)
65 {
66 	Pcidev *p, *head, *tail;
67 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
68 
69 	maxubn = bno;
70 	head = nil;
71 	tail = nil;
72 	for(dno = 0; dno <= pcimaxdno; dno++){
73 		maxfno = 0;
74 		for(fno = 0; fno <= maxfno; fno++){
75 			/*
76 			 * For this possible device, form the
77 			 * bus+device+function triplet needed to address it
78 			 * and try to read the vendor and device ID.
79 			 * If successful, allocate a device struct and
80 			 * start to fill it in with some useful information
81 			 * from the device's configuration space.
82 			 */
83 			tbdf = MKBUS(BusPCI, bno, dno, fno);
84 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
85 			if(l == 0xFFFFFFFF || l == 0)
86 				continue;
87 			p = malloc(sizeof(*p));
88 			p->tbdf = tbdf;
89 			p->vid = l;
90 			p->did = l>>16;
91 
92 			if(pcilist != nil)
93 				pcitail->list = p;
94 			else
95 				pcilist = p;
96 			pcitail = p;
97 
98 			p->rid = pcicfgr8(p, PciRID);
99 			p->ccrp = pcicfgr8(p, PciCCRp);
100 			p->ccru = pcicfgr8(p, PciCCRu);
101 			p->ccrb = pcicfgr8(p, PciCCRb);
102 			p->pcr = pcicfgr32(p, PciPCR);
103 
104 			p->intl = pcicfgr8(p, PciINTL);
105 
106 			/*
107 			 * If the device is a multi-function device adjust the
108 			 * loop count so all possible functions are checked.
109 			 */
110 			hdt = pcicfgr8(p, PciHDT);
111 			if(hdt & 0x80)
112 				maxfno = MaxFNO;
113 
114 			/*
115 			 * If appropriate, read the base address registers
116 			 * and work out the sizes.
117 			 */
118 			switch(p->ccrb){
119 
120 			case 0x01:		/* mass storage controller */
121 			case 0x02:		/* network controller */
122 			case 0x03:		/* display controller */
123 			case 0x04:		/* multimedia device */
124 			case 0x07:		/* simple comm. controllers */
125 			case 0x08:		/* base system peripherals */
126 			case 0x09:		/* input devices */
127 			case 0x0A:		/* docking stations */
128 			case 0x0B:		/* processors */
129 			case 0x0C:		/* serial bus controllers */
130 				if((hdt & 0x7F) != 0)
131 					break;
132 				rno = PciBAR0 - 4;
133 				for(i = 0; i < nelem(p->mem); i++){
134 					rno += 4;
135 					p->mem[i].bar = pcicfgr32(p, rno);
136 					p->mem[i].size = pcibarsize(p, rno);
137 				}
138 				break;
139 
140 			case 0x00:
141 			case 0x05:		/* memory controller */
142 			case 0x06:		/* bridge device */
143 			default:
144 				break;
145 			}
146 
147 			if(head != nil)
148 				tail->link = p;
149 			else
150 				head = p;
151 			tail = p;
152 		}
153 	}
154 
155 	*list = head;
156 	for(p = head; p != nil; p = p->link){
157 		/*
158 		 * Find PCI-PCI and PCI-Cardbus bridges
159 		 * and recursively descend the tree.
160 		 */
161 		if(p->ccrb != 0x06 || p->ccru != 0x04)
162 			continue;
163 
164 		/*
165 		 * If the secondary or subordinate bus number is not
166 		 * initialised try to do what the PCI BIOS should have
167 		 * done and fill in the numbers as the tree is descended.
168 		 * On the way down the subordinate bus number is set to
169 		 * the maximum as it's not known how many buses are behind
170 		 * this one; the final value is set on the way back up.
171 		 */
172 		ubn = pcicfgr8(p, PciUBN);
173 		sbn = pcicfgr8(p, PciSBN);
174 
175 		if(sbn == 0 || ubn == 0){
176 			sbn = maxubn+1;
177 			/*
178 			 * Make sure memory, I/O and master enables are
179 			 * off, set the primary, secondary and subordinate
180 			 * bus numbers and clear the secondary status before
181 			 * attempting to scan the secondary bus.
182 			 *
183 			 * Initialisation of the bridge should be done here.
184 			 */
185 			pcicfgw32(p, PciPCR, 0xFFFF0000);
186 			l = (MaxUBN<<16)|(sbn<<8)|bno;
187 			pcicfgw32(p, PciPBN, l);
188 			pcicfgw16(p, PciSPSR, 0xFFFF);
189 			maxubn = pciscan(sbn, &p->bridge);
190 			l = (maxubn<<16)|(sbn<<8)|bno;
191 
192 			pcicfgw32(p, PciPBN, l);
193 		}
194 		else{
195 			/*
196 			 * You can't go back.
197 			 * This shouldn't be possible, but the
198 			 * Iwill DK8-HTX seems to have subordinate
199 			 * bus numbers which get smaller on the
200 			 * way down. Need to look more closely at
201 			 * this.
202 			 */
203 			if(ubn > maxubn)
204 				maxubn = ubn;
205 			pciscan(sbn, &p->bridge);
206 		}
207 	}
208 
209 	return maxubn;
210 }
211 
212 static uchar
213 null_link(Pcidev *, uchar )
214 {
215 	return 0;
216 }
217 
218 static void
219 null_init(Pcidev *, uchar , uchar )
220 {
221 }
222 
223 static uchar
224 pIIx_link(Pcidev *router, uchar link)
225 {
226 	uchar pirq;
227 
228 	/* link should be 0x60, 0x61, 0x62, 0x63 */
229 	pirq = pcicfgr8(router, link);
230 	return (pirq < 16)? pirq: 0;
231 }
232 
233 static void
234 pIIx_init(Pcidev *router, uchar link, uchar irq)
235 {
236 	pcicfgw8(router, link, irq);
237 }
238 
239 static uchar
240 via_link(Pcidev *router, uchar link)
241 {
242 	uchar pirq;
243 
244 	/* link should be 1, 2, 3, 5 */
245 	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
246 
247 	return (link & 1)? (pirq >> 4): (pirq & 15);
248 }
249 
250 static void
251 via_init(Pcidev *router, uchar link, uchar irq)
252 {
253 	uchar pirq;
254 
255 	pirq = pcicfgr8(router, 0x55 + (link >> 1));
256 	pirq &= (link & 1)? 0x0f: 0xf0;
257 	pirq |= (link & 1)? (irq << 4): (irq & 15);
258 	pcicfgw8(router, 0x55 + (link>>1), pirq);
259 }
260 
261 static uchar
262 opti_link(Pcidev *router, uchar link)
263 {
264 	uchar pirq = 0;
265 
266 	/* link should be 0x02, 0x12, 0x22, 0x32 */
267 	if ((link & 0xcf) == 0x02)
268 		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
269 	return (link & 0x10)? (pirq >> 4): (pirq & 15);
270 }
271 
272 static void
273 opti_init(Pcidev *router, uchar link, uchar irq)
274 {
275 	uchar pirq;
276 
277 	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
278     	pirq &= (link & 0x10)? 0x0f : 0xf0;
279     	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
280 	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
281 }
282 
283 static uchar
284 ali_link(Pcidev *router, uchar link)
285 {
286 	/* No, you're not dreaming */
287 	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
288 	uchar pirq;
289 
290 	/* link should be 0x01..0x08 */
291 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
292 	return (link & 1)? map[pirq&15]: map[pirq>>4];
293 }
294 
295 static void
296 ali_init(Pcidev *router, uchar link, uchar irq)
297 {
298 	/* Inverse of map in ali_link */
299 	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
300 	uchar pirq;
301 
302 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
303 	pirq &= (link & 1)? 0x0f: 0xf0;
304 	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
305 	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
306 }
307 
308 static uchar
309 cyrix_link(Pcidev *router, uchar link)
310 {
311 	uchar pirq;
312 
313 	/* link should be 1, 2, 3, 4 */
314 	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
315 	return ((link & 1)? pirq >> 4: pirq & 15);
316 }
317 
318 static void
319 cyrix_init(Pcidev *router, uchar link, uchar irq)
320 {
321 	uchar pirq;
322 
323 	pirq = pcicfgr8(router, 0x5c + (link>>1));
324 	pirq &= (link & 1)? 0x0f: 0xf0;
325 	pirq |= (link & 1)? (irq << 4): (irq & 15);
326 	pcicfgw8(router, 0x5c + (link>>1), pirq);
327 }
328 
329 typedef struct {
330 	ushort	sb_vid, sb_did;
331 	uchar	(*sb_translate)(Pcidev *, uchar);
332 	void	(*sb_initialize)(Pcidev *, uchar, uchar);
333 } bridge_t;
334 
335 static bridge_t southbridges[] = {
336 	{ 0x8086, 0x122e, pIIx_link, pIIx_init },	// Intel 82371FB
337 	{ 0x8086, 0x1234, pIIx_link, pIIx_init },	// Intel 82371MX
338 	{ 0x8086, 0x7000, pIIx_link, pIIx_init },	// Intel 82371SB
339 	{ 0x8086, 0x7110, pIIx_link, pIIx_init },	// Intel 82371AB
340 	{ 0x8086, 0x7198, pIIx_link, pIIx_init },	// Intel 82443MX (fn 1)
341 	{ 0x8086, 0x2410, pIIx_link, pIIx_init },	// Intel 82801AA
342 	{ 0x8086, 0x2420, pIIx_link, pIIx_init },	// Intel 82801AB
343 	{ 0x8086, 0x2440, pIIx_link, pIIx_init },	// Intel 82801BA
344 	{ 0x8086, 0x244c, pIIx_link, pIIx_init },	// Intel 82801BAM
345 	{ 0x8086, 0x2480, pIIx_link, pIIx_init },	// Intel 82801CA
346 	{ 0x8086, 0x248c, pIIx_link, pIIx_init },	// Intel 82801CAM
347 	{ 0x8086, 0x24c0, pIIx_link, pIIx_init },	// Intel 82801DBL
348 	{ 0x8086, 0x24cc, pIIx_link, pIIx_init },	// Intel 82801DBM
349 	{ 0x8086, 0x24d0, pIIx_link, pIIx_init },	// Intel 82801EB
350 	{ 0x8086, 0x2640, pIIx_link, pIIx_init },	// Intel 82801FB
351 	{ 0x8086, 0x27b8, pIIx_link, pIIx_init },	// Intel 82801GB
352 	{ 0x8086, 0x27b9, pIIx_link, pIIx_init },	// Intel 82801GBM
353 	{ 0x1106, 0x0586, via_link, via_init },		// Viatech 82C586
354 	{ 0x1106, 0x0596, via_link, via_init },		// Viatech 82C596
355 	{ 0x1106, 0x0686, via_link, via_init },		// Viatech 82C686
356 	{ 0x1106, 0x3227, via_link, via_init },		// Viatech VT8237
357 	{ 0x1045, 0xc700, opti_link, opti_init },	// Opti 82C700
358 	{ 0x10b9, 0x1533, ali_link, ali_init },		// Al M1533
359 	{ 0x1039, 0x0008, pIIx_link, pIIx_init },	// SI 503
360 	{ 0x1039, 0x0496, pIIx_link, pIIx_init },	// SI 496
361 	{ 0x1078, 0x0100, cyrix_link, cyrix_init },	// Cyrix 5530 Legacy
362 
363 	{ 0x1002, 0x4377, nil, nil },		// ATI Radeon Xpress 200M
364 	{ 0x1002, 0x4372, nil, nil },		// ATI SB400
365 	{ 0x1022, 0x746B, nil, nil },		// AMD 8111
366 	{ 0x10DE, 0x00D1, nil, nil },		// NVIDIA nForce 3
367 	{ 0x10DE, 0x00E0, nil, nil },		// NVIDIA nForce 3 250 Series
368 	{ 0x1166, 0x0200, nil, nil },		// ServerWorks ServerSet III LE
369 };
370 
371 typedef struct {
372 	uchar	e_bus;			// Pci bus number
373 	uchar	e_dev;			// Pci device number
374 	uchar	e_maps[12];		// Avoid structs!  Link and mask.
375 	uchar	e_slot;			// Add-in/built-in slot
376 	uchar	e_reserved;
377 } slot_t;
378 
379 typedef struct {
380 	uchar	rt_signature[4];	// Routing table signature
381 	uchar	rt_version[2];		// Version number
382 	uchar	rt_size[2];			// Total table size
383 	uchar	rt_bus;			// Interrupt router bus number
384 	uchar	rt_devfn;			// Router's devfunc
385 	uchar	rt_pciirqs[2];		// Exclusive PCI irqs
386 	uchar	rt_compat[4];		// Compatible PCI interrupt router
387 	uchar	rt_miniport[4];		// Miniport data
388 	uchar	rt_reserved[11];
389 	uchar	rt_checksum;
390 } router_t;
391 
392 static ushort pciirqs;			// Exclusive PCI irqs
393 static bridge_t *southbridge;	// Which southbridge to use.
394 
395 static void
396 pcirouting(void)
397 {
398 	uchar *p, pin, irq;
399 	ulong tbdf, vdid;
400 	ushort vid, did;
401 	router_t *r;
402 	slot_t *e;
403 	int size, i, fn;
404 	Pcidev *sbpci, *pci;
405 
406 	// Peek in the BIOS
407 	for (p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
408 		if (p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
409 			break;
410 
411 	if (p >= (uchar *)KADDR(0xfffff))
412 		return;
413 
414 	r = (router_t *)p;
415 
416 	// print("PCI interrupt routing table version %d.%d at %.6uX\n",
417 	// 	r->rt_version[0], r->rt_version[1], (ulong)r & 0xfffff);
418 
419 	tbdf = (BusPCI << 24)|(r->rt_bus << 16)|(r->rt_devfn << 8);
420 	vdid = pcicfgrw32(tbdf, PciVID, 0, 1);
421 	vid = vdid;
422 	did = vdid >> 16;
423 
424 	for (i = 0; i != nelem(southbridges); i++)
425 		if (vid == southbridges[i].sb_vid && did == southbridges[i].sb_did)
426 			break;
427 
428 	if (i == nelem(southbridges)) {
429 		print("pcirouting: South bridge %.4uX, %.4uX not found\n", vid, did);
430 		return;
431 	}
432 	southbridge = &southbridges[i];
433 
434 	if ((sbpci = pcimatch(nil, vid, did)) == nil) {
435 		print("pcirouting: Cannot match south bridge %.4uX, %.4uX\n",
436 			  vid, did);
437 		return;
438 	}
439 
440 	pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0];
441 
442 	size = (r->rt_size[1] << 8)|r->rt_size[0];
443 	for (e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) {
444 		// print("%.2uX/%.2uX %.2uX: ", e->e_bus, e->e_dev, e->e_slot);
445 		// for (i = 0; i != 4; i++) {
446 		// 	uchar *m = &e->e_maps[i * 3];
447 		// 	print("[%d] %.2uX %.4uX ",
448 		// 		i, m[0], (m[2] << 8)|m[1]);
449 		// }
450 		// print("\n");
451 
452 		for (fn = 0; fn != 8; fn++) {
453 			uchar *m;
454 
455 			// Retrieve the did and vid through the devfn before
456 			// obtaining the Pcidev structure.
457 			tbdf = (BusPCI << 24)|(e->e_bus << 16)|((e->e_dev | fn) << 8);
458 			vdid = pcicfgrw32(tbdf, PciVID, 0, 1);
459 			if (vdid == 0xFFFFFFFF || vdid == 0)
460 				continue;
461 
462 			vid = vdid;
463 			did = vdid >> 16;
464 
465 			pci = nil;
466 			while ((pci = pcimatch(pci, vid, did)) != nil) {
467 
468 				if (pci->intl != 0 && pci->intl != 0xFF)
469 					continue;
470 
471 				pin = pcicfgr8(pci, PciINTP);
472 				if (pin == 0 || pin == 0xff)
473 					continue;
474 
475 				m = &e->e_maps[(pin - 1) * 3];
476 				irq = southbridge->sb_translate(sbpci, m[0]);
477 				if (irq) {
478 					print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n",
479 						  vid, did, pin, irq);
480 					pcicfgw8(pci, PciINTL, irq);
481 					pci->intl = irq;
482 				}
483 			}
484 		}
485 	}
486 }
487 
488 static void
489 pcicfginit(void)
490 {
491 	char *p;
492 	int bno, n;
493 	Pcidev **list;
494 
495 	lock(&pcicfginitlock);
496 	if(pcicfgmode != -1)
497 		goto out;
498 
499 	/*
500 	 * Try to determine which PCI configuration mode is implemented.
501 	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
502 	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
503 	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
504 	 * a device behind these addresses so if Mode1 accesses fail try
505 	 * for Mode2 (Mode2 is deprecated).
506 	 */
507 
508 	/*
509 	 * Bits [30:24] of PciADDR must be 0,
510 	 * according to the spec.
511 	 */
512 	n = inl(PciADDR);
513 	if(!(n & 0x7FF00000)){
514 		outl(PciADDR, 0x80000000);
515 		outb(PciADDR+3, 0);
516 		if(inl(PciADDR) & 0x80000000){
517 			pcicfgmode = 1;
518 			pcimaxdno = 31;
519 		}
520 	}
521 	outl(PciADDR, n);
522 
523 	if(pcicfgmode < 0){
524 		/*
525 		 * The 'key' part of PciCSE should be 0.
526 		 */
527 		n = inb(PciCSE);
528 		if(!(n & 0xF0)){
529 			outb(PciCSE, 0x0E);
530 			if(inb(PciCSE) == 0x0E){
531 				pcicfgmode = 2;
532 				pcimaxdno = 15;
533 			}
534 		}
535 		outb(PciCSE, n);
536 	}
537 
538 	if(pcicfgmode < 0)
539 		goto out;
540 
541 
542 	if(p = getconf("*pcimaxbno"))
543 		pcimaxbno = strtoul(p, 0, 0);
544 	if(p = getconf("*pcimaxdno"))
545 		pcimaxdno = strtoul(p, 0, 0);
546 
547 	list = &pciroot;
548 	for(bno = 0; bno <= pcimaxbno; bno++) {
549 		bno = pciscan(bno, list);
550 		while(*list)
551 			list = &(*list)->link;
552 	}
553 
554 	pcirouting();
555 
556 out:
557 	unlock(&pcicfginitlock);
558 
559 	if(getconf("*pcihinv"))
560 		pcihinv(nil);
561 }
562 
563 
564 static int
565 pcicfgrw8(int tbdf, int rno, int data, int read)
566 {
567 	int o, type, x;
568 
569 	if(pcicfgmode == -1)
570 		pcicfginit();
571 
572 	if(BUSBNO(tbdf))
573 		type = 0x01;
574 	else
575 		type = 0x00;
576 	x = -1;
577 	if(BUSDNO(tbdf) > pcimaxdno)
578 		return x;
579 
580 	lock(&pcicfglock);
581 	switch(pcicfgmode){
582 
583 	case 1:
584 		o = rno & 0x03;
585 		rno &= ~0x03;
586 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
587 		if(read)
588 			x = inb(PciDATA+o);
589 		else
590 			outb(PciDATA+o, data);
591 		outl(PciADDR, 0);
592 		break;
593 
594 	case 2:
595 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
596 		outb(PciFORWARD, BUSBNO(tbdf));
597 		if(read)
598 			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
599 		else
600 			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
601 		outb(PciCSE, 0);
602 		break;
603 	}
604 	unlock(&pcicfglock);
605 
606 	return x;
607 }
608 
609 int
610 pcicfgr8(Pcidev* pcidev, int rno)
611 {
612 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
613 }
614 
615 void
616 pcicfgw8(Pcidev* pcidev, int rno, int data)
617 {
618 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
619 }
620 
621 static int
622 pcicfgrw16(int tbdf, int rno, int data, int read)
623 {
624 	int o, type, x;
625 
626 	if(pcicfgmode == -1)
627 		pcicfginit();
628 
629 	if(BUSBNO(tbdf))
630 		type = 0x01;
631 	else
632 		type = 0x00;
633 	x = -1;
634 	if(BUSDNO(tbdf) > pcimaxdno)
635 		return x;
636 
637 	lock(&pcicfglock);
638 	switch(pcicfgmode){
639 
640 	case 1:
641 		o = rno & 0x02;
642 		rno &= ~0x03;
643 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
644 		if(read)
645 			x = ins(PciDATA+o);
646 		else
647 			outs(PciDATA+o, data);
648 		outl(PciADDR, 0);
649 		break;
650 
651 	case 2:
652 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
653 		outb(PciFORWARD, BUSBNO(tbdf));
654 		if(read)
655 			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
656 		else
657 			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
658 		outb(PciCSE, 0);
659 		break;
660 	}
661 	unlock(&pcicfglock);
662 
663 	return x;
664 }
665 
666 int
667 pcicfgr16(Pcidev* pcidev, int rno)
668 {
669 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
670 }
671 
672 void
673 pcicfgw16(Pcidev* pcidev, int rno, int data)
674 {
675 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
676 }
677 
678 static int
679 pcicfgrw32(int tbdf, int rno, int data, int read)
680 {
681 	int type, x;
682 
683 	if(pcicfgmode == -1)
684 		pcicfginit();
685 
686 	if(BUSBNO(tbdf))
687 		type = 0x01;
688 	else
689 		type = 0x00;
690 	x = -1;
691 	if(BUSDNO(tbdf) > pcimaxdno)
692 		return x;
693 
694 	lock(&pcicfglock);
695 	switch(pcicfgmode){
696 
697 	case 1:
698 		rno &= ~0x03;
699 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
700 		if(read)
701 			x = inl(PciDATA);
702 		else
703 			outl(PciDATA, data);
704 		outl(PciADDR, 0);
705 		break;
706 
707 	case 2:
708 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
709 		outb(PciFORWARD, BUSBNO(tbdf));
710 		if(read)
711 			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
712 		else
713 			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
714 		outb(PciCSE, 0);
715 		break;
716 	}
717 	unlock(&pcicfglock);
718 
719 	return x;
720 }
721 
722 int
723 pcicfgr32(Pcidev* pcidev, int rno)
724 {
725 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
726 }
727 
728 void
729 pcicfgw32(Pcidev* pcidev, int rno, int data)
730 {
731 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
732 }
733 
734 Pcidev*
735 pcimatch(Pcidev* prev, int vid, int did)
736 {
737 	if(pcicfgmode == -1)
738 		pcicfginit();
739 
740 	if(prev == nil)
741 		prev = pcilist;
742 	else
743 		prev = prev->list;
744 
745 	while(prev != nil) {
746 		if((vid == 0 || prev->vid == vid)
747 		&& (did == 0 || prev->did == did))
748 			break;
749 		prev = prev->list;
750 	}
751 	return prev;
752 }
753 
754 uchar
755 pciipin(Pcidev *pci, uchar pin)
756 {
757 	if (pci == nil)
758 		pci = pcilist;
759 
760 	while (pci) {
761 		uchar intl;
762 
763 		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
764 			return pci->intl;
765 
766 		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
767 			return intl;
768 
769 		pci = pci->list;
770 	}
771 	return 0;
772 }
773 
774 static ushort
775 pciimask(Pcidev *pci)
776 {
777 	ushort imask;
778 
779 	imask = 0;
780 	while (pci) {
781 		if (pcicfgr8(pci, PciINTP) && pci->intl < 16)
782 			imask |= 1 << pci->intl;
783 
784 		if (pci->bridge)
785 			imask |= pciimask(pci->bridge);
786 
787 		pci = pci->list;
788 	}
789 	return imask;
790 }
791 
792 uchar
793 pciintl(Pcidev *pci)
794 {
795 	ushort imask;
796 	int i;
797 
798 	if (pci == nil)
799 		pci = pcilist;
800 
801 	imask = pciimask(pci) | 1;
802 	for (i = 0; i != 16; i++)
803 		if ((imask & (1 << i)) == 0)
804 			return i;
805 	return 0;
806 }
807 
808 void
809 pcihinv(Pcidev* p)
810 {
811 	int i;
812 	Pcidev *t;
813 
814 	if(pcicfgmode == -1)
815 		pcicfginit();
816 
817 	if(p == nil) {
818 		p = pciroot;
819 		print("bus dev type vid  did intl memory\n");
820 	}
821 	for(t = p; t != nil; t = t->link) {
822 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
823 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
824 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
825 
826 		for(i = 0; i < nelem(p->mem); i++) {
827 			if(t->mem[i].size == 0)
828 				continue;
829 			print("%d:%.8lux %d ", i,
830 				t->mem[i].bar, t->mem[i].size);
831 		}
832 		print("\n");
833 	}
834 	while(p != nil) {
835 		if(p->bridge != nil)
836 			pcihinv(p->bridge);
837 		p = p->link;
838 	}
839 }
840 
841 void
842 pcireset(void)
843 {
844 	Pcidev *p;
845 	int pcr;
846 
847 	if(pcicfgmode == -1)
848 		pcicfginit();
849 
850 	for(p = pcilist; p != nil; p = p->list){
851 		pcr = pcicfgr16(p, PciPSR);
852 		pcicfgw16(p, PciPSR, pcr & ~0x04);
853 	}
854 }
855 
856 void
857 pcisetioe(Pcidev* p)
858 {
859 	p->pcr |= IOen;
860 	pcicfgw16(p, PciPCR, p->pcr);
861 }
862 
863 void
864 pciclrioe(Pcidev* p)
865 {
866 	p->pcr &= ~IOen;
867 	pcicfgw16(p, PciPCR, p->pcr);
868 }
869 
870 void
871 pcisetbme(Pcidev* p)
872 {
873 	p->pcr |= MASen;
874 	pcicfgw16(p, PciPCR, p->pcr);
875 }
876 
877 void
878 pciclrbme(Pcidev* p)
879 {
880 	p->pcr &= ~MASen;
881 	pcicfgw16(p, PciPCR, p->pcr);
882 }
883 
884 void
885 pcisetmwi(Pcidev* p)
886 {
887 	p->pcr |= MemWrInv;
888 	pcicfgw16(p, PciPCR, p->pcr);
889 }
890 
891 void
892 pciclrmwi(Pcidev* p)
893 {
894 	p->pcr &= ~MemWrInv;
895 	pcicfgw16(p, PciPCR, p->pcr);
896 }
897 
898 static int
899 pcigetpmrb(Pcidev* p)
900 {
901 	int ptr;
902 
903 	if(p->pmrb != 0)
904 		return p->pmrb;
905 	p->pmrb = -1;
906 
907 	/*
908 	 * If there are no extended capabilities implemented,
909 	 * (bit 4 in the status register) assume there's no standard
910 	 * power management method.
911 	 * Find the capabilities pointer based on PCI header type.
912 	 */
913 	if(!(pcicfgr16(p, PciPSR) & 0x0010))
914 		return -1;
915 	switch(pcicfgr8(p, PciHDT)){
916 	default:
917 		return -1;
918 	case 0:					/* all other */
919 	case 1:					/* PCI to PCI bridge */
920 		ptr = 0x34;
921 		break;
922 	case 2:					/* CardBus bridge */
923 		ptr = 0x14;
924 		break;
925 	}
926 	ptr = pcicfgr32(p, ptr);
927 
928 	while(ptr != 0){
929 		/*
930 		 * Check for validity.
931 		 * Can't be in standard header and must be double
932 		 * word aligned.
933 		 */
934 		if(ptr < 0x40 || (ptr & ~0xFC))
935 			return -1;
936 		if(pcicfgr8(p, ptr) == 0x01){
937 			p->pmrb = ptr;
938 			return ptr;
939 		}
940 
941 		ptr = pcicfgr8(p, ptr+1);
942 	}
943 
944 	return -1;
945 }
946 
947 int
948 pcigetpms(Pcidev* p)
949 {
950 	int pmcsr, ptr;
951 
952 	if((ptr = pcigetpmrb(p)) == -1)
953 		return -1;
954 
955 	/*
956 	 * Power Management Register Block:
957 	 *  offset 0:	Capability ID
958 	 *	   1:	next item pointer
959 	 *	   2:	capabilities
960 	 *	   4:	control/status
961 	 *	   6:	bridge support extensions
962 	 *	   7:	data
963 	 */
964 	pmcsr = pcicfgr16(p, ptr+4);
965 
966 	return pmcsr & 0x0003;
967 }
968 
969 int
970 pcisetpms(Pcidev* p, int state)
971 {
972 	int ostate, pmc, pmcsr, ptr;
973 
974 	if((ptr = pcigetpmrb(p)) == -1)
975 		return -1;
976 
977 	pmc = pcicfgr16(p, ptr+2);
978 	pmcsr = pcicfgr16(p, ptr+4);
979 	ostate = pmcsr & 0x0003;
980 	pmcsr &= ~0x0003;
981 
982 	switch(state){
983 	default:
984 		return -1;
985 	case 0:
986 		break;
987 	case 1:
988 		if(!(pmc & 0x0200))
989 			return -1;
990 		break;
991 	case 2:
992 		if(!(pmc & 0x0400))
993 			return -1;
994 		break;
995 	case 3:
996 		break;
997 	}
998 	pmcsr |= state;
999 	pcicfgw16(p, ptr+4, pmcsr);
1000 
1001 	return ostate;
1002 }
1003