xref: /plan9-contrib/sys/src/9/pc/pci.c (revision 1936bb650459bace06c38a45b60888b47e5cd459)
1 /*
2  * PCI support code.
3  * Needs a massive rewrite.
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "io.h"
11 
12 #define DBG	if(0) pcilog
13 
14 struct
15 {
16 	char	output[PCICONSSIZE];
17 	int	ptr;
18 }PCICONS;
19 
20 int pcivga;
21 
22 int
23 pcilog(char *fmt, ...)
24 {
25 	int n;
26 	va_list arg;
27 	char buf[PRINTSIZE];
28 
29 	va_start(arg, fmt);
30 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
31 	va_end(arg);
32 
33 	memmove(PCICONS.output+PCICONS.ptr, buf, n);
34 	PCICONS.ptr += n;
35 	return n;
36 }
37 
38 enum
39 {					/* configuration mechanism #1 */
40 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
41 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
42 
43 					/* configuration mechanism #2 */
44 	PciCSE		= 0xCF8,	/* configuration space enable */
45 	PciFORWARD	= 0xCFA,	/* which bus */
46 
47 	MaxFNO		= 7,
48 	MaxUBN		= 255,
49 };
50 
51 enum
52 {					/* command register */
53 	IOen		= (1<<0),
54 	MEMen		= (1<<1),
55 	MASen		= (1<<2),
56 	MemWrInv	= (1<<4),
57 	PErrEn		= (1<<6),
58 	SErrEn		= (1<<8),
59 };
60 
61 static Lock pcicfglock;
62 static Lock pcicfginitlock;
63 static int pcicfgmode = -1;
64 static int pcimaxbno = 7;
65 static int pcimaxdno;
66 static Pcidev* pciroot;
67 static Pcidev* pcilist;
68 static Pcidev* pcitail;
69 static int nobios, nopcirouting;
70 static BIOS32si* pcibiossi;
71 
72 static int pcicfgrw8raw(int, int, int, int);
73 static int pcicfgrw16raw(int, int, int, int);
74 static int pcicfgrw32raw(int, int, int, int);
75 
76 static int (*pcicfgrw8)(int, int, int, int) = pcicfgrw8raw;
77 static int (*pcicfgrw16)(int, int, int, int) = pcicfgrw16raw;
78 static int (*pcicfgrw32)(int, int, int, int) = pcicfgrw32raw;
79 
80 static char* bustypes[] = {
81 	"CBUSI",
82 	"CBUSII",
83 	"EISA",
84 	"FUTURE",
85 	"INTERN",
86 	"ISA",
87 	"MBI",
88 	"MBII",
89 	"MCA",
90 	"MPI",
91 	"MPSA",
92 	"NUBUS",
93 	"PCI",
94 	"PCMCIA",
95 	"TC",
96 	"VL",
97 	"VME",
98 	"XPRESS",
99 };
100 
101 static int
102 tbdffmt(Fmt* fmt)
103 {
104 	char *p;
105 	int l, r;
106 	uint type, tbdf;
107 
108 	if((p = malloc(READSTR)) == nil)
109 		return fmtstrcpy(fmt, "(tbdfconv)");
110 
111 	switch(fmt->r){
112 	case 'T':
113 		tbdf = va_arg(fmt->args, int);
114 		if(tbdf == BUSUNKNOWN)
115 			snprint(p, READSTR, "unknown");
116 		else{
117 			type = BUSTYPE(tbdf);
118 			if(type < nelem(bustypes))
119 				l = snprint(p, READSTR, bustypes[type]);
120 			else
121 				l = snprint(p, READSTR, "%d", type);
122 			snprint(p+l, READSTR-l, ".%d.%d.%d",
123 				BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
124 		}
125 		break;
126 
127 	default:
128 		snprint(p, READSTR, "(tbdfconv)");
129 		break;
130 	}
131 	r = fmtstrcpy(fmt, p);
132 	free(p);
133 
134 	return r;
135 }
136 
137 ulong
138 pcibarsize(Pcidev *p, int rno)
139 {
140 	ulong v, size;
141 
142 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
143 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
144 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
145 	if(v & 1)
146 		size |= 0xFFFF0000;
147 	pcicfgrw32(p->tbdf, rno, v, 0);
148 
149 	return -(size & ~0x0F);
150 }
151 
152 static int
153 pcisizcmp(void *a, void *b)
154 {
155 	Pcisiz *aa, *bb;
156 
157 	aa = a;
158 	bb = b;
159 	return aa->siz - bb->siz;
160 }
161 
162 static ulong
163 pcimask(ulong v)
164 {
165 	ulong m;
166 
167 	m = BI2BY*sizeof(v);
168 	for(m = 1<<(m-1); m != 0; m >>= 1) {
169 		if(m & v)
170 			break;
171 	}
172 
173 	m--;
174 	if((v & m) == 0)
175 		return v;
176 
177 	v |= m;
178 	return v+1;
179 }
180 
181 static void
182 pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
183 {
184 	Pcidev *p;
185 	int ntb, i, size, rno, hole;
186 	ulong v, mema, ioa, sioa, smema, base, limit;
187 	Pcisiz *table, *tptr, *mtb, *itb;
188 
189 	if(!nobios)
190 		return;
191 
192 	ioa = *pioa;
193 	mema = *pmema;
194 
195 	DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n",
196 		wrreg, root->tbdf, mema, ioa);
197 
198 	ntb = 0;
199 	for(p = root; p != nil; p = p->link)
200 		ntb++;
201 
202 	ntb *= (PciCIS-PciBAR0)/4;
203 	table = malloc(2*ntb*sizeof(Pcisiz));
204 	if(table == nil)
205 		panic("pcibusmap: no memory");
206 	itb = table;
207 	mtb = table+ntb;
208 
209 	/*
210 	 * Build a table of sizes
211 	 */
212 	for(p = root; p != nil; p = p->link) {
213 		if(p->ccrb == 0x06) {
214 			if(p->ccru != 0x04 || p->bridge == nil) {
215 //				DBG("pci: ignored bridge %T\n", p->tbdf);
216 				continue;
217 			}
218 
219 			sioa = ioa;
220 			smema = mema;
221 			pcibusmap(p->bridge, &smema, &sioa, 0);
222 
223 			hole = pcimask(smema-mema);
224 			if(hole < (1<<20))
225 				hole = 1<<20;
226 			p->mema.size = hole;
227 
228 			hole = pcimask(sioa-ioa);
229 			if(hole < (1<<12))
230 				hole = 1<<12;
231 
232 			p->ioa.size = hole;
233 
234 			itb->dev = p;
235 			itb->bar = -1;
236 			itb->siz = p->ioa.size;
237 			itb++;
238 
239 			mtb->dev = p;
240 			mtb->bar = -1;
241 			mtb->siz = p->mema.size;
242 			mtb++;
243 			continue;
244 		}
245 
246 		for(i = 0; i <= 5; i++) {
247 			rno = PciBAR0 + i*4;
248 			v = pcicfgrw32(p->tbdf, rno, 0, 1);
249 			size = pcibarsize(p, rno);
250 			if(size == 0)
251 				continue;
252 
253 			if(v & 1) {
254 				itb->dev = p;
255 				itb->bar = i;
256 				itb->siz = size;
257 				itb++;
258 			}
259 			else {
260 				mtb->dev = p;
261 				mtb->bar = i;
262 				mtb->siz = size;
263 				mtb++;
264 			}
265 
266 			p->mem[i].size = size;
267 		}
268 	}
269 
270 	/*
271 	 * Sort both tables IO smallest first, Memory largest
272 	 */
273 	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
274 	tptr = table+ntb;
275 	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
276 
277 	/*
278 	 * Allocate IO address space on this bus
279 	 */
280 	for(tptr = table; tptr < itb; tptr++) {
281 		hole = tptr->siz;
282 		if(tptr->bar == -1)
283 			hole = 1<<12;
284 		ioa = (ioa+hole-1) & ~(hole-1);
285 
286 		p = tptr->dev;
287 		if(tptr->bar == -1)
288 			p->ioa.bar = ioa;
289 		else {
290 			p->pcr |= IOen;
291 			p->mem[tptr->bar].bar = ioa|1;
292 			if(wrreg)
293 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
294 		}
295 
296 		ioa += tptr->siz;
297 	}
298 
299 	/*
300 	 * Allocate Memory address space on this bus
301 	 */
302 	for(tptr = table+ntb; tptr < mtb; tptr++) {
303 		hole = tptr->siz;
304 		if(tptr->bar == -1)
305 			hole = 1<<20;
306 		mema = (mema+hole-1) & ~(hole-1);
307 
308 		p = tptr->dev;
309 		if(tptr->bar == -1)
310 			p->mema.bar = mema;
311 		else {
312 			p->pcr |= MEMen;
313 			p->mem[tptr->bar].bar = mema;
314 			if(wrreg)
315 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
316 		}
317 		mema += tptr->siz;
318 	}
319 
320 	*pmema = mema;
321 	*pioa = ioa;
322 	free(table);
323 
324 	if(wrreg == 0)
325 		return;
326 
327 	/*
328 	 * Finally set all the bridge addresses & registers
329 	 */
330 	for(p = root; p != nil; p = p->link) {
331 		if(p->bridge == nil) {
332 			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
333 
334 			p->pcr |= MASen;
335 			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
336 			continue;
337 		}
338 
339 		base = p->ioa.bar;
340 		limit = base+p->ioa.size-1;
341 		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
342 		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
343 		pcicfgrw32(p->tbdf, PciIBR, v, 0);
344 		v = (limit & 0xFFFF0000)|(base>>16);
345 		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
346 
347 		base = p->mema.bar;
348 		limit = base+p->mema.size-1;
349 		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
350 		pcicfgrw32(p->tbdf, PciMBR, v, 0);
351 
352 		/*
353 		 * Disable memory prefetch
354 		 */
355 		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
356 		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
357 
358 		/*
359 		 * Enable the bridge
360 		 */
361 		p->pcr |= IOen|MEMen|MASen;
362 		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
363 
364 		sioa = p->ioa.bar;
365 		smema = p->mema.bar;
366 		pcibusmap(p->bridge, &smema, &sioa, 1);
367 	}
368 }
369 
370 /* side effect: if a video controller is seen, set pcivga non-zero */
371 static int
372 pcilscan(int bno, Pcidev** list)
373 {
374 	Pcidev *p, *head, *tail;
375 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
376 
377 	maxubn = bno;
378 	head = nil;
379 	tail = nil;
380 	for(dno = 0; dno <= pcimaxdno; dno++){
381 		maxfno = 0;
382 		for(fno = 0; fno <= maxfno; fno++){
383 			/*
384 			 * For this possible device, form the
385 			 * bus+device+function triplet needed to address it
386 			 * and try to read the vendor and device ID.
387 			 * If successful, allocate a device struct and
388 			 * start to fill it in with some useful information
389 			 * from the device's configuration space.
390 			 */
391 			tbdf = MKBUS(BusPCI, bno, dno, fno);
392 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
393 			if(l == 0xFFFFFFFF || l == 0)
394 				continue;
395 			p = malloc(sizeof(*p));
396 			if(p == nil)
397 				panic("pcilscan: no memory");
398 			p->tbdf = tbdf;
399 			p->vid = l;
400 			p->did = l>>16;
401 
402 			if(pcilist != nil)
403 				pcitail->list = p;
404 			else
405 				pcilist = p;
406 			pcitail = p;
407 
408 			p->pcr = pcicfgr16(p, PciPCR);
409 			p->rid = pcicfgr8(p, PciRID);
410 			p->ccrp = pcicfgr8(p, PciCCRp);
411 			p->ccru = pcicfgr8(p, PciCCRu);
412 			p->ccrb = pcicfgr8(p, PciCCRb);
413 			p->cls = pcicfgr8(p, PciCLS);
414 			p->ltr = pcicfgr8(p, PciLTR);
415 
416 			p->intl = pcicfgr8(p, PciINTL);
417 
418 			/*
419 			 * If the device is a multi-function device adjust the
420 			 * loop count so all possible functions are checked.
421 			 */
422 			hdt = pcicfgr8(p, PciHDT);
423 			if(hdt & 0x80)
424 				maxfno = MaxFNO;
425 
426 			/*
427 			 * If appropriate, read the base address registers
428 			 * and work out the sizes.
429 			 */
430 			switch(p->ccrb) {
431 			case 0x03:		/* display controller */
432 				pcivga = 1;
433 				/* fall through */
434 			case 0x01:		/* mass storage controller */
435 			case 0x02:		/* network controller */
436 			case 0x04:		/* multimedia device */
437 			case 0x07:		/* simple comm. controllers */
438 			case 0x08:		/* base system peripherals */
439 			case 0x09:		/* input devices */
440 			case 0x0A:		/* docking stations */
441 			case 0x0B:		/* processors */
442 			case 0x0C:		/* serial bus controllers */
443 				if((hdt & 0x7F) != 0)
444 					break;
445 				rno = PciBAR0 - 4;
446 				for(i = 0; i < nelem(p->mem); i++) {
447 					rno += 4;
448 					p->mem[i].bar = pcicfgr32(p, rno);
449 					p->mem[i].size = pcibarsize(p, rno);
450 				}
451 				break;
452 
453 			case 0x00:
454 			case 0x05:		/* memory controller */
455 			case 0x06:		/* bridge device */
456 			default:
457 				break;
458 			}
459 
460 			if(head != nil)
461 				tail->link = p;
462 			else
463 				head = p;
464 			tail = p;
465 		}
466 	}
467 
468 	*list = head;
469 	for(p = head; p != nil; p = p->link){
470 		/*
471 		 * Find PCI-PCI bridges and recursively descend the tree.
472 		 */
473 		if(p->ccrb != 0x06 || p->ccru != 0x04)
474 			continue;
475 
476 		/*
477 		 * If the secondary or subordinate bus number is not
478 		 * initialised try to do what the PCI BIOS should have
479 		 * done and fill in the numbers as the tree is descended.
480 		 * On the way down the subordinate bus number is set to
481 		 * the maximum as it's not known how many buses are behind
482 		 * this one; the final value is set on the way back up.
483 		 */
484 		sbn = pcicfgr8(p, PciSBN);
485 		ubn = pcicfgr8(p, PciUBN);
486 
487 		if(sbn == 0 || ubn == 0 || nobios) {
488 			sbn = maxubn+1;
489 			/*
490 			 * Make sure memory, I/O and master enables are
491 			 * off, set the primary, secondary and subordinate
492 			 * bus numbers and clear the secondary status before
493 			 * attempting to scan the secondary bus.
494 			 *
495 			 * Initialisation of the bridge should be done here.
496 			 */
497 			pcicfgw32(p, PciPCR, 0xFFFF0000);
498 			l = (MaxUBN<<16)|(sbn<<8)|bno;
499 			pcicfgw32(p, PciPBN, l);
500 			pcicfgw16(p, PciSPSR, 0xFFFF);
501 			maxubn = pcilscan(sbn, &p->bridge);
502 			l = (maxubn<<16)|(sbn<<8)|bno;
503 
504 			pcicfgw32(p, PciPBN, l);
505 		}
506 		else {
507 			if(ubn > maxubn)
508 				maxubn = ubn;
509 			pcilscan(sbn, &p->bridge);
510 		}
511 	}
512 
513 	return maxubn;
514 }
515 
516 int
517 pciscan(int bno, Pcidev **list)
518 {
519 	int ubn;
520 
521 	lock(&pcicfginitlock);
522 	ubn = pcilscan(bno, list);
523 	unlock(&pcicfginitlock);
524 	return ubn;
525 }
526 
527 static uchar
528 pIIxget(Pcidev *router, uchar link)
529 {
530 	uchar pirq;
531 
532 	/* link should be 0x60, 0x61, 0x62, 0x63 */
533 	pirq = pcicfgr8(router, link);
534 	return (pirq < 16)? pirq: 0;
535 }
536 
537 static void
538 pIIxset(Pcidev *router, uchar link, uchar irq)
539 {
540 	pcicfgw8(router, link, irq);
541 }
542 
543 static uchar
544 viaget(Pcidev *router, uchar link)
545 {
546 	uchar pirq;
547 
548 	/* link should be 1, 2, 3, 5 */
549 	pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
550 
551 	return (link & 1)? (pirq >> 4): (pirq & 15);
552 }
553 
554 static void
555 viaset(Pcidev *router, uchar link, uchar irq)
556 {
557 	uchar pirq;
558 
559 	pirq = pcicfgr8(router, 0x55 + (link >> 1));
560 	pirq &= (link & 1)? 0x0f: 0xf0;
561 	pirq |= (link & 1)? (irq << 4): (irq & 15);
562 	pcicfgw8(router, 0x55 + (link>>1), pirq);
563 }
564 
565 static uchar
566 optiget(Pcidev *router, uchar link)
567 {
568 	uchar pirq = 0;
569 
570 	/* link should be 0x02, 0x12, 0x22, 0x32 */
571 	if ((link & 0xcf) == 0x02)
572 		pirq = pcicfgr8(router, 0xb8 + (link >> 5));
573 	return (link & 0x10)? (pirq >> 4): (pirq & 15);
574 }
575 
576 static void
577 optiset(Pcidev *router, uchar link, uchar irq)
578 {
579 	uchar pirq;
580 
581 	pirq = pcicfgr8(router, 0xb8 + (link >> 5));
582     	pirq &= (link & 0x10)? 0x0f : 0xf0;
583     	pirq |= (link & 0x10)? (irq << 4): (irq & 15);
584 	pcicfgw8(router, 0xb8 + (link >> 5), pirq);
585 }
586 
587 static uchar
588 aliget(Pcidev *router, uchar link)
589 {
590 	/* No, you're not dreaming */
591 	static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
592 	uchar pirq;
593 
594 	/* link should be 0x01..0x08 */
595 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
596 	return (link & 1)? map[pirq&15]: map[pirq>>4];
597 }
598 
599 static void
600 aliset(Pcidev *router, uchar link, uchar irq)
601 {
602 	/* Inverse of map in aliget */
603 	static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
604 	uchar pirq;
605 
606 	pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
607 	pirq &= (link & 1)? 0x0f: 0xf0;
608 	pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
609 	pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
610 }
611 
612 static uchar
613 cyrixget(Pcidev *router, uchar link)
614 {
615 	uchar pirq;
616 
617 	/* link should be 1, 2, 3, 4 */
618 	pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
619 	return ((link & 1)? pirq >> 4: pirq & 15);
620 }
621 
622 static void
623 cyrixset(Pcidev *router, uchar link, uchar irq)
624 {
625 	uchar pirq;
626 
627 	pirq = pcicfgr8(router, 0x5c + (link>>1));
628 	pirq &= (link & 1)? 0x0f: 0xf0;
629 	pirq |= (link & 1)? (irq << 4): (irq & 15);
630 	pcicfgw8(router, 0x5c + (link>>1), pirq);
631 }
632 
633 typedef struct Bridge Bridge;
634 struct Bridge
635 {
636 	ushort	vid;
637 	ushort	did;
638 	uchar	(*get)(Pcidev *, uchar);
639 	void	(*set)(Pcidev *, uchar, uchar);
640 };
641 
642 static Bridge southbridges[] = {
643 	{ 0x8086, 0x122e, pIIxget, pIIxset },	/* Intel 82371FB */
644 	{ 0x8086, 0x1234, pIIxget, pIIxset },	/* Intel 82371MX */
645 	{ 0x8086, 0x7000, pIIxget, pIIxset },	/* Intel 82371SB */
646 	{ 0x8086, 0x7110, pIIxget, pIIxset },	/* Intel 82371AB */
647 	{ 0x8086, 0x7198, pIIxget, pIIxset },	/* Intel 82443MX (fn 1) */
648 	{ 0x8086, 0x2410, pIIxget, pIIxset },	/* Intel 82801AA */
649 	{ 0x8086, 0x2420, pIIxget, pIIxset },	/* Intel 82801AB */
650 	{ 0x8086, 0x2440, pIIxget, pIIxset },	/* Intel 82801BA */
651 	{ 0x8086, 0x2448, pIIxget, pIIxset },	/* Intel 82801BAM/CAM/DBM */
652 	{ 0x8086, 0x244c, pIIxget, pIIxset },	/* Intel 82801BAM */
653 	{ 0x8086, 0x244e, pIIxget, pIIxset },	/* Intel 82801 */
654 	{ 0x8086, 0x2480, pIIxget, pIIxset },	/* Intel 82801CA */
655 	{ 0x8086, 0x248c, pIIxget, pIIxset },	/* Intel 82801CAM */
656 	{ 0x8086, 0x24c0, pIIxget, pIIxset },	/* Intel 82801DBL */
657 	{ 0x8086, 0x24cc, pIIxget, pIIxset },	/* Intel 82801DBM */
658 	{ 0x8086, 0x24d0, pIIxget, pIIxset },	/* Intel 82801EB */
659 	{ 0x8086, 0x25a1, pIIxget, pIIxset },	/* Intel 6300ESB */
660 	{ 0x8086, 0x2640, pIIxget, pIIxset },	/* Intel 82801FB */
661 	{ 0x8086, 0x2641, pIIxget, pIIxset },	/* Intel 82801FBM */
662 	{ 0x8086, 0x27b8, pIIxget, pIIxset },	/* Intel 82801GB */
663 	{ 0x8086, 0x27b9, pIIxget, pIIxset },	/* Intel 82801GBM */
664 	{ 0x8086, 0x27bd, pIIxget, pIIxset },	/* Intel 82801GB/GR */
665 	{ 0x8086, 0x3a16, pIIxget, pIIxset },	/* Intel 82801JIR */
666 	{ 0x8086, 0x3a40, pIIxget, pIIxset },	/* Intel 82801JI */
667 	{ 0x8086, 0x3a42, pIIxget, pIIxset },	/* Intel 82801JI */
668 	{ 0x8086, 0x3a48, pIIxget, pIIxset },	/* Intel 82801JI */
669 	{ 0x8086, 0x2916, pIIxget, pIIxset },	/* Intel 82801? */
670 	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
671 	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
672 	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
673 	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
674 	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
675 	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
676 	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
677 	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
678 	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
679 
680 	{ 0x1022, 0x746B, nil, nil },		/* AMD 8111 */
681 	{ 0x10DE, 0x00D1, nil, nil },		/* NVIDIA nForce 3 */
682 	{ 0x10DE, 0x00E0, nil, nil },		/* NVIDIA nForce 3 250 Series */
683 	{ 0x10DE, 0x00E1, nil, nil },		/* NVIDIA nForce 3 250 Series */
684 	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
685 	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
686 	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
687 };
688 
689 typedef struct Slot Slot;
690 struct Slot {
691 	uchar	bus;		/* Pci bus number */
692 	uchar	dev;		/* Pci device number */
693 	uchar	maps[12];	/* Avoid structs!  Link and mask. */
694 	uchar	slot;		/* Add-in/built-in slot */
695 	uchar	reserved;
696 };
697 
698 typedef struct Router Router;
699 struct Router {
700 	uchar	signature[4];	/* Routing table signature */
701 	uchar	version[2];	/* Version number */
702 	uchar	size[2];	/* Total table size */
703 	uchar	bus;		/* Interrupt router bus number */
704 	uchar	devfn;		/* Router's devfunc */
705 	uchar	pciirqs[2];	/* Exclusive PCI irqs */
706 	uchar	compat[4];	/* Compatible PCI interrupt router */
707 	uchar	miniport[4];	/* Miniport data */
708 	uchar	reserved[11];
709 	uchar	checksum;
710 };
711 
712 static ushort pciirqs;		/* Exclusive PCI irqs */
713 static Bridge *southbridge;	/* Which southbridge to use. */
714 
715 static void
716 pcirouting(void)
717 {
718 	Slot *e;
719 	Router *r;
720 	int size, i, fn, tbdf;
721 	Pcidev *sbpci, *pci;
722 	uchar *p, pin, irq, link, *map;
723 
724 	/* Search for PCI interrupt routing table in BIOS */
725 	for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
726 		if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
727 			break;
728 
729 	if(p >= (uchar *)KADDR(0xfffff)) {
730 		// print("no PCI intr routing table found\n");
731 		return;
732 	}
733 
734 	r = (Router *)p;
735 
736 	if (0)
737 		print("PCI interrupt routing table version %d.%d at %#.6luX\n",
738 			r->version[0], r->version[1], (ulong)r & 0xfffff);
739 
740 	tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8);
741 	sbpci = pcimatchtbdf(tbdf);
742 	if(sbpci == nil) {
743 		print("pcirouting: Cannot find south bridge %T\n", tbdf);
744 		return;
745 	}
746 
747 	for(i = 0; i != nelem(southbridges); i++)
748 		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
749 			break;
750 
751 	if(i == nelem(southbridges)) {
752 		print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did);
753 		return;
754 	}
755 	southbridge = &southbridges[i];
756 	if(southbridge->get == nil || southbridge->set == nil)
757 		return;
758 
759 	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
760 
761 	size = (r->size[1] << 8)|r->size[0];
762 	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
763 		if (0) {
764 			print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot);
765 			for (i = 0; i != 4; i++) {
766 				uchar *m = &e->maps[i * 3];
767 				print("[%d] %.2uX %.4uX ",
768 					i, m[0], (m[2] << 8)|m[1]);
769 			}
770 			print("\n");
771 		}
772 		for(fn = 0; fn != 8; fn++) {
773 			tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
774 			pci = pcimatchtbdf(tbdf);
775 			if(pci == nil)
776 				continue;
777 			pin = pcicfgr8(pci, PciINTP);
778 			if(pin == 0 || pin == 0xff)
779 				continue;
780 
781 			map = &e->maps[(pin - 1) * 3];
782 			link = map[0];
783 			irq = southbridge->get(sbpci, link);
784 			if(irq == 0 || irq == pci->intl)
785 				continue;
786 			if(pci->intl != 0 && pci->intl != 0xFF) {
787 				print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
788 					  tbdf, pin, link, irq, pci->intl);
789 				southbridge->set(sbpci, link, pci->intl);
790 				continue;
791 			}
792 			print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
793 			pcicfgw8(pci, PciINTL, irq);
794 			pci->intl = irq;
795 		}
796 	}
797 }
798 
799 static void pcireservemem(void);
800 
801 static int
802 pcicfgrw8bios(int tbdf, int rno, int data, int read)
803 {
804 	BIOS32ci ci;
805 
806 	if(pcibiossi == nil)
807 		return -1;
808 
809 	memset(&ci, 0, sizeof(BIOS32ci));
810 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
811 	ci.edi = rno;
812 	if(read){
813 		ci.eax = 0xB108;
814 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
815 			return ci.ecx & 0xFF;
816 	}
817 	else{
818 		ci.eax = 0xB10B;
819 		ci.ecx = data & 0xFF;
820 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
821 			return 0;
822 	}
823 
824 	return -1;
825 }
826 
827 static int
828 pcicfgrw16bios(int tbdf, int rno, int data, int read)
829 {
830 	BIOS32ci ci;
831 
832 	if(pcibiossi == nil)
833 		return -1;
834 
835 	memset(&ci, 0, sizeof(BIOS32ci));
836 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
837 	ci.edi = rno;
838 	if(read){
839 		ci.eax = 0xB109;
840 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
841 			return ci.ecx & 0xFFFF;
842 	}
843 	else{
844 		ci.eax = 0xB10C;
845 		ci.ecx = data & 0xFFFF;
846 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
847 			return 0;
848 	}
849 
850 	return -1;
851 }
852 
853 static int
854 pcicfgrw32bios(int tbdf, int rno, int data, int read)
855 {
856 	BIOS32ci ci;
857 
858 	if(pcibiossi == nil)
859 		return -1;
860 
861 	memset(&ci, 0, sizeof(BIOS32ci));
862 	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
863 	ci.edi = rno;
864 	if(read){
865 		ci.eax = 0xB10A;
866 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
867 			return ci.ecx;
868 	}
869 	else{
870 		ci.eax = 0xB10D;
871 		ci.ecx = data;
872 		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
873 			return 0;
874 	}
875 
876 	return -1;
877 }
878 
879 static BIOS32si*
880 pcibiosinit(void)
881 {
882 	BIOS32ci ci;
883 	BIOS32si *si;
884 
885 	if((si = bios32open("$PCI")) == nil)
886 		return nil;
887 
888 	memset(&ci, 0, sizeof(BIOS32ci));
889 	ci.eax = 0xB101;
890 	if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){
891 		free(si);
892 		return nil;
893 	}
894 	if(ci.eax & 0x01)
895 		pcimaxdno = 31;
896 	else
897 		pcimaxdno = 15;
898 	pcimaxbno = ci.ecx & 0xff;
899 
900 	return si;
901 }
902 
903 void
904 pcibussize(Pcidev *root, ulong *msize, ulong *iosize)
905 {
906 	*msize = 0;
907 	*iosize = 0;
908 	pcibusmap(root, msize, iosize, 0);
909 }
910 
911 static void
912 pcicfginit(void)
913 {
914 	char *p;
915 	Pcidev **list;
916 	ulong mema, ioa;
917 	int bno, n, pcibios;
918 
919 	lock(&pcicfginitlock);
920 	if(pcicfgmode != -1)
921 		goto out;
922 
923 	pcibios = 0;
924 	if(getconf("*nobios"))
925 		nobios = 1;
926 	else if(getconf("*pcibios"))
927 		pcibios = 1;
928 	if(getconf("*nopcirouting"))
929 		nopcirouting = 1;
930 
931 	/*
932 	 * Try to determine which PCI configuration mode is implemented.
933 	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
934 	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
935 	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
936 	 * a device behind these addresses so if Mode1 accesses fail try
937 	 * for Mode2 (Mode2 is deprecated).
938 	 */
939 	if(!pcibios){
940 		/*
941 		 * Bits [30:24] of PciADDR must be 0,
942 		 * according to the spec.
943 		 */
944 		n = inl(PciADDR);
945 		if(!(n & 0x7F000000)){
946 			outl(PciADDR, 0x80000000);
947 			outb(PciADDR+3, 0);
948 			if(inl(PciADDR) & 0x80000000){
949 				pcicfgmode = 1;
950 				pcimaxdno = 31;
951 			}
952 		}
953 		outl(PciADDR, n);
954 
955 		if(pcicfgmode < 0){
956 			/*
957 			 * The 'key' part of PciCSE should be 0.
958 			 */
959 			n = inb(PciCSE);
960 			if(!(n & 0xF0)){
961 				outb(PciCSE, 0x0E);
962 				if(inb(PciCSE) == 0x0E){
963 					pcicfgmode = 2;
964 					pcimaxdno = 15;
965 				}
966 			}
967 			outb(PciCSE, n);
968 		}
969 	}
970 
971 	if(pcicfgmode < 0 || pcibios) {
972 		if((pcibiossi = pcibiosinit()) == nil)
973 			goto out;
974 		pcicfgrw8 = pcicfgrw8bios;
975 		pcicfgrw16 = pcicfgrw16bios;
976 		pcicfgrw32 = pcicfgrw32bios;
977 		pcicfgmode = 3;
978 	}
979 
980 	fmtinstall('T', tbdffmt);
981 
982 	if(p = getconf("*pcimaxbno")){
983 		n = strtoul(p, 0, 0);
984 		if(n < pcimaxbno)
985 			pcimaxbno = n;
986 	}
987 	if(p = getconf("*pcimaxdno")){
988 		n = strtoul(p, 0, 0);
989 		if(n < pcimaxdno)
990 			pcimaxdno = n;
991 	}
992 
993 	list = &pciroot;
994 	for(bno = 0; bno <= pcimaxbno; bno++) {
995 		int sbno = bno;
996 		bno = pcilscan(bno, list);
997 
998 		while(*list)
999 			list = &(*list)->link;
1000 
1001 		if (sbno == 0) {
1002 			Pcidev *pci;
1003 
1004 			/*
1005 			  * If we have found a PCI-to-Cardbus bridge, make sure
1006 			  * it has no valid mappings anymore.
1007 			  */
1008 			for(pci = pciroot; pci != nil; pci = pci->link){
1009 				if (pci->ccrb == 6 && pci->ccru == 7) {
1010 					ushort bcr;
1011 
1012 					/* reset the cardbus */
1013 					bcr = pcicfgr16(pci, PciBCR);
1014 					pcicfgw16(pci, PciBCR, 0x40 | bcr);
1015 					delay(50);
1016 				}
1017 			}
1018 		}
1019 	}
1020 
1021 	if(pciroot == nil)
1022 		goto out;
1023 
1024 	if(nobios) {
1025 		/*
1026 		 * Work out how big the top bus is
1027 		 */
1028 		pcibussize(pciroot, &mema, &ioa);
1029 
1030 		/*
1031 		 * Align the windows and map it
1032 		 */
1033 		ioa = 0x1000;
1034 		mema = 0x90000000;
1035 
1036 		pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
1037 
1038 		pcibusmap(pciroot, &mema, &ioa, 1);
1039 		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
1040 
1041 		unlock(&pcicfginitlock);
1042 		return;
1043 	}
1044 
1045 	if (!nopcirouting)
1046 		pcirouting();
1047 
1048 out:
1049 	pcireservemem();
1050 	unlock(&pcicfginitlock);
1051 
1052 	if(getconf("*pcihinv"))
1053 		pcihinv(nil);
1054 }
1055 
1056 static void
1057 pcireservemem(void)
1058 {
1059 	int i;
1060 	Pcidev *p;
1061 
1062 	/*
1063 	 * mark all the physical address space claimed by pci devices
1064 	 * as in use, so that upaalloc doesn't give it out.
1065 	 */
1066 	for(p=pciroot; p; p=p->list)
1067 		for(i=0; i<nelem(p->mem); i++)
1068 			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
1069 				upareserve(p->mem[i].bar&~0x0F, p->mem[i].size);
1070 }
1071 
1072 static int
1073 pcicfgrw8raw(int tbdf, int rno, int data, int read)
1074 {
1075 	int o, type, x;
1076 
1077 	if(pcicfgmode == -1)
1078 		pcicfginit();
1079 
1080 	if(BUSBNO(tbdf))
1081 		type = 0x01;
1082 	else
1083 		type = 0x00;
1084 	x = -1;
1085 	if(BUSDNO(tbdf) > pcimaxdno)
1086 		return x;
1087 
1088 	lock(&pcicfglock);
1089 	switch(pcicfgmode){
1090 
1091 	case 1:
1092 		o = rno & 0x03;
1093 		rno &= ~0x03;
1094 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1095 		if(read)
1096 			x = inb(PciDATA+o);
1097 		else
1098 			outb(PciDATA+o, data);
1099 		outl(PciADDR, 0);
1100 		break;
1101 
1102 	case 2:
1103 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1104 		outb(PciFORWARD, BUSBNO(tbdf));
1105 		if(read)
1106 			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1107 		else
1108 			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1109 		outb(PciCSE, 0);
1110 		break;
1111 	}
1112 	unlock(&pcicfglock);
1113 
1114 	return x;
1115 }
1116 
1117 int
1118 pcicfgr8(Pcidev* pcidev, int rno)
1119 {
1120 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
1121 }
1122 
1123 void
1124 pcicfgw8(Pcidev* pcidev, int rno, int data)
1125 {
1126 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
1127 }
1128 
1129 static int
1130 pcicfgrw16raw(int tbdf, int rno, int data, int read)
1131 {
1132 	int o, type, x;
1133 
1134 	if(pcicfgmode == -1)
1135 		pcicfginit();
1136 
1137 	if(BUSBNO(tbdf))
1138 		type = 0x01;
1139 	else
1140 		type = 0x00;
1141 	x = -1;
1142 	if(BUSDNO(tbdf) > pcimaxdno)
1143 		return x;
1144 
1145 	lock(&pcicfglock);
1146 	switch(pcicfgmode){
1147 
1148 	case 1:
1149 		o = rno & 0x02;
1150 		rno &= ~0x03;
1151 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1152 		if(read)
1153 			x = ins(PciDATA+o);
1154 		else
1155 			outs(PciDATA+o, data);
1156 		outl(PciADDR, 0);
1157 		break;
1158 
1159 	case 2:
1160 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1161 		outb(PciFORWARD, BUSBNO(tbdf));
1162 		if(read)
1163 			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1164 		else
1165 			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1166 		outb(PciCSE, 0);
1167 		break;
1168 	}
1169 	unlock(&pcicfglock);
1170 
1171 	return x;
1172 }
1173 
1174 int
1175 pcicfgr16(Pcidev* pcidev, int rno)
1176 {
1177 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
1178 }
1179 
1180 void
1181 pcicfgw16(Pcidev* pcidev, int rno, int data)
1182 {
1183 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
1184 }
1185 
1186 static int
1187 pcicfgrw32raw(int tbdf, int rno, int data, int read)
1188 {
1189 	int type, x;
1190 
1191 	if(pcicfgmode == -1)
1192 		pcicfginit();
1193 
1194 	if(BUSBNO(tbdf))
1195 		type = 0x01;
1196 	else
1197 		type = 0x00;
1198 	x = -1;
1199 	if(BUSDNO(tbdf) > pcimaxdno)
1200 		return x;
1201 
1202 	lock(&pcicfglock);
1203 	switch(pcicfgmode){
1204 
1205 	case 1:
1206 		rno &= ~0x03;
1207 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1208 		if(read)
1209 			x = inl(PciDATA);
1210 		else
1211 			outl(PciDATA, data);
1212 		outl(PciADDR, 0);
1213 		break;
1214 
1215 	case 2:
1216 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1217 		outb(PciFORWARD, BUSBNO(tbdf));
1218 		if(read)
1219 			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1220 		else
1221 			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1222 		outb(PciCSE, 0);
1223 		break;
1224 	}
1225 	unlock(&pcicfglock);
1226 
1227 	return x;
1228 }
1229 
1230 int
1231 pcicfgr32(Pcidev* pcidev, int rno)
1232 {
1233 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
1234 }
1235 
1236 void
1237 pcicfgw32(Pcidev* pcidev, int rno, int data)
1238 {
1239 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
1240 }
1241 
1242 Pcidev*
1243 pcimatch(Pcidev* prev, int vid, int did)
1244 {
1245 	if(pcicfgmode == -1)
1246 		pcicfginit();
1247 
1248 	if(prev == nil)
1249 		prev = pcilist;
1250 	else
1251 		prev = prev->list;
1252 
1253 	while(prev != nil){
1254 		if((vid == 0 || prev->vid == vid)
1255 		&& (did == 0 || prev->did == did))
1256 			break;
1257 		prev = prev->list;
1258 	}
1259 	return prev;
1260 }
1261 
1262 Pcidev*
1263 pcimatchtbdf(int tbdf)
1264 {
1265 	Pcidev *pcidev;
1266 
1267 	if(pcicfgmode == -1)
1268 		pcicfginit();
1269 
1270 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
1271 		if(pcidev->tbdf == tbdf)
1272 			break;
1273 	}
1274 	return pcidev;
1275 }
1276 
1277 uchar
1278 pciipin(Pcidev *pci, uchar pin)
1279 {
1280 	if (pci == nil)
1281 		pci = pcilist;
1282 
1283 	while (pci) {
1284 		uchar intl;
1285 
1286 		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
1287 			return pci->intl;
1288 
1289 		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
1290 			return intl;
1291 
1292 		pci = pci->list;
1293 	}
1294 	return 0;
1295 }
1296 
1297 static void
1298 pcilhinv(Pcidev* p)
1299 {
1300 	int i;
1301 	Pcidev *t;
1302 
1303 	if(p == nil) {
1304 		putstrn(PCICONS.output, PCICONS.ptr);
1305 		p = pciroot;
1306 		print("bus dev type vid  did intl memory\n");
1307 	}
1308 	for(t = p; t != nil; t = t->link) {
1309 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
1310 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
1311 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
1312 
1313 		for(i = 0; i < nelem(p->mem); i++) {
1314 			if(t->mem[i].size == 0)
1315 				continue;
1316 			print("%d:%.8lux %d ", i,
1317 				t->mem[i].bar, t->mem[i].size);
1318 		}
1319 		if(t->ioa.bar || t->ioa.size)
1320 			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
1321 		if(t->mema.bar || t->mema.size)
1322 			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
1323 		if(t->bridge)
1324 			print("->%d", BUSBNO(t->bridge->tbdf));
1325 		print("\n");
1326 	}
1327 	while(p != nil) {
1328 		if(p->bridge != nil)
1329 			pcilhinv(p->bridge);
1330 		p = p->link;
1331 	}
1332 }
1333 
1334 void
1335 pcihinv(Pcidev* p)
1336 {
1337 	if(pcicfgmode == -1)
1338 		pcicfginit();
1339 	lock(&pcicfginitlock);
1340 	pcilhinv(p);
1341 	unlock(&pcicfginitlock);
1342 }
1343 
1344 void
1345 pcireset(void)
1346 {
1347 	Pcidev *p;
1348 
1349 	if(pcicfgmode == -1)
1350 		pcicfginit();
1351 
1352 	for(p = pcilist; p != nil; p = p->list) {
1353 		/* don't mess with the bridges */
1354 		if(p->ccrb == 0x06)
1355 			continue;
1356 		pciclrbme(p);
1357 	}
1358 }
1359 
1360 void
1361 pcisetioe(Pcidev* p)
1362 {
1363 	p->pcr |= IOen;
1364 	pcicfgw16(p, PciPCR, p->pcr);
1365 }
1366 
1367 void
1368 pciclrioe(Pcidev* p)
1369 {
1370 	p->pcr &= ~IOen;
1371 	pcicfgw16(p, PciPCR, p->pcr);
1372 }
1373 
1374 void
1375 pcisetbme(Pcidev* p)
1376 {
1377 	p->pcr |= MASen;
1378 	pcicfgw16(p, PciPCR, p->pcr);
1379 }
1380 
1381 void
1382 pciclrbme(Pcidev* p)
1383 {
1384 	p->pcr &= ~MASen;
1385 	pcicfgw16(p, PciPCR, p->pcr);
1386 }
1387 
1388 void
1389 pcisetmwi(Pcidev* p)
1390 {
1391 	p->pcr |= MemWrInv;
1392 	pcicfgw16(p, PciPCR, p->pcr);
1393 }
1394 
1395 void
1396 pciclrmwi(Pcidev* p)
1397 {
1398 	p->pcr &= ~MemWrInv;
1399 	pcicfgw16(p, PciPCR, p->pcr);
1400 }
1401 
1402 static int
1403 pcigetpmrb(Pcidev* p)
1404 {
1405 	int ptr;
1406 
1407 	if(p->pmrb != 0)
1408 		return p->pmrb;
1409 	p->pmrb = -1;
1410 
1411 	/*
1412 	 * If there are no extended capabilities implemented,
1413 	 * (bit 4 in the status register) assume there's no standard
1414 	 * power management method.
1415 	 * Find the capabilities pointer based on PCI header type.
1416 	 */
1417 	if(!(pcicfgr16(p, PciPSR) & 0x0010))
1418 		return -1;
1419 	switch(pcicfgr8(p, PciHDT)){
1420 	default:
1421 		return -1;
1422 	case 0:					/* all other */
1423 	case 1:					/* PCI to PCI bridge */
1424 		ptr = 0x34;
1425 		break;
1426 	case 2:					/* CardBus bridge */
1427 		ptr = 0x14;
1428 		break;
1429 	}
1430 	ptr = pcicfgr32(p, ptr);
1431 
1432 	while(ptr != 0){
1433 		/*
1434 		 * Check for validity.
1435 		 * Can't be in standard header and must be double
1436 		 * word aligned.
1437 		 */
1438 		if(ptr < 0x40 || (ptr & ~0xFC))
1439 			return -1;
1440 		if(pcicfgr8(p, ptr) == 0x01){
1441 			p->pmrb = ptr;
1442 			return ptr;
1443 		}
1444 
1445 		ptr = pcicfgr8(p, ptr+1);
1446 	}
1447 
1448 	return -1;
1449 }
1450 
1451 int
1452 pcigetpms(Pcidev* p)
1453 {
1454 	int pmcsr, ptr;
1455 
1456 	if((ptr = pcigetpmrb(p)) == -1)
1457 		return -1;
1458 
1459 	/*
1460 	 * Power Management Register Block:
1461 	 *  offset 0:	Capability ID
1462 	 *	   1:	next item pointer
1463 	 *	   2:	capabilities
1464 	 *	   4:	control/status
1465 	 *	   6:	bridge support extensions
1466 	 *	   7:	data
1467 	 */
1468 	pmcsr = pcicfgr16(p, ptr+4);
1469 
1470 	return pmcsr & 0x0003;
1471 }
1472 
1473 int
1474 pcisetpms(Pcidev* p, int state)
1475 {
1476 	int ostate, pmc, pmcsr, ptr;
1477 
1478 	if((ptr = pcigetpmrb(p)) == -1)
1479 		return -1;
1480 
1481 	pmc = pcicfgr16(p, ptr+2);
1482 	pmcsr = pcicfgr16(p, ptr+4);
1483 	ostate = pmcsr & 0x0003;
1484 	pmcsr &= ~0x0003;
1485 
1486 	switch(state){
1487 	default:
1488 		return -1;
1489 	case 0:
1490 		break;
1491 	case 1:
1492 		if(!(pmc & 0x0200))
1493 			return -1;
1494 		break;
1495 	case 2:
1496 		if(!(pmc & 0x0400))
1497 			return -1;
1498 		break;
1499 	case 3:
1500 		break;
1501 	}
1502 	pmcsr |= state;
1503 	pcicfgw16(p, ptr+4, pmcsr);
1504 
1505 	return ostate;
1506 }
1507