xref: /plan9-contrib/sys/src/9k/386/pci.c (revision da317bb81ef206f889122f8664a27371f63545f4)
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 
11 #include "io.h"
12 
13 struct
14 {
15 	char	output[16384];
16 	int	ptr;
17 }PCICONS;
18 
19 int pcivga;
20 
21 int
pcilog(char * fmt,...)22 pcilog(char *fmt, ...)
23 {
24 	int n;
25 	va_list arg;
26 	char buf[PRINTSIZE];
27 
28 	va_start(arg, fmt);
29 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
30 	va_end(arg);
31 
32 	memmove(PCICONS.output+PCICONS.ptr, buf, n);
33 	PCICONS.ptr += n;
34 	return n;
35 }
36 
37 enum
38 {					/* configuration mechanism #1 */
39 	PciADDR		= 0xCF8,	/* CONFIG_ADDRESS */
40 	PciDATA		= 0xCFC,	/* CONFIG_DATA */
41 
42 					/* configuration mechanism #2 */
43 	PciCSE		= 0xCF8,	/* configuration space enable */
44 	PciFORWARD	= 0xCFA,	/* which bus */
45 
46 	MaxFNO		= 7,
47 	MaxUBN		= 255,
48 };
49 
50 enum
51 {					/* command register */
52 	IOen		= (1<<0),
53 	MEMen		= (1<<1),
54 	MASen		= (1<<2),
55 	MemWrInv	= (1<<4),
56 	PErrEn		= (1<<6),
57 	SErrEn		= (1<<8),
58 };
59 
60 static Lock pcicfglock;
61 static Lock pcicfginitlock;
62 static int pcicfgmode = -1;
63 static int pcimaxbno = 7;
64 static int pcimaxdno;
65 static Pcidev* pciroot;
66 static Pcidev* pcilist;
67 static Pcidev* pcitail;
68 static int nobios, nopcirouting;
69 
70 static int pcicfgrw32(int, int, int, int);
71 static int pcicfgrw16(int, int, int, int);
72 static int pcicfgrw8(int, int, int, int);
73 
74 static char* bustypes[] = {
75 	"CBUSI",
76 	"CBUSII",
77 	"EISA",
78 	"FUTURE",
79 	"INTERN",
80 	"ISA",
81 	"MBI",
82 	"MBII",
83 	"MCA",
84 	"MPI",
85 	"MPSA",
86 	"NUBUS",
87 	"PCI",
88 	"PCMCIA",
89 	"TC",
90 	"VL",
91 	"VME",
92 	"XPRESS",
93 };
94 
95 #pragma	varargck	type	"T"	int
96 
97 static int
tbdffmt(Fmt * fmt)98 tbdffmt(Fmt* fmt)
99 {
100 	char *p;
101 	int l, r, type, tbdf;
102 
103 	if((p = malloc(READSTR)) == nil)
104 		return fmtstrcpy(fmt, "(tbdfconv)");
105 
106 	switch(fmt->r){
107 	case 'T':
108 		tbdf = va_arg(fmt->args, int);
109 		type = BUSTYPE(tbdf);
110 		if(type < nelem(bustypes))
111 			l = snprint(p, READSTR, bustypes[type]);
112 		else
113 			l = snprint(p, READSTR, "%d", type);
114 		snprint(p+l, READSTR-l, ".%d.%d.%d",
115 			BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
116 		break;
117 
118 	default:
119 		snprint(p, READSTR, "(tbdfconv)");
120 		break;
121 	}
122 	r = fmtstrcpy(fmt, p);
123 	free(p);
124 
125 	return r;
126 }
127 
128 ulong
pcibarsize(Pcidev * p,int rno)129 pcibarsize(Pcidev *p, int rno)
130 {
131 	ulong v, size;
132 
133 	v = pcicfgrw32(p->tbdf, rno, 0, 1);
134 	pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
135 	size = pcicfgrw32(p->tbdf, rno, 0, 1);
136 	if(v & 1)
137 		size |= 0xFFFF0000;
138 	pcicfgrw32(p->tbdf, rno, v, 0);
139 
140 	return -(size & ~0x0F);
141 }
142 
143 static int
pcisizcmp(void * a,void * b)144 pcisizcmp(void *a, void *b)
145 {
146 	Pcisiz *aa, *bb;
147 
148 	aa = a;
149 	bb = b;
150 	return aa->siz - bb->siz;
151 }
152 
153 static ulong
pcimask(ulong v)154 pcimask(ulong v)
155 {
156 	ulong mask;
157 
158 	mask = BI2BY*sizeof(v);
159 	for(mask = 1<<(mask-1); mask != 0; mask >>= 1) {
160 		if(mask & v)
161 			break;
162 	}
163 
164 	mask--;
165 	if((v & mask) == 0)
166 		return v;
167 
168 	v |= mask;
169 	return v+1;
170 }
171 
172 static void
pcibusmap(Pcidev * root,ulong * pmema,ulong * pioa,int wrreg)173 pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
174 {
175 	Pcidev *p;
176 	int ntb, i, size, rno, hole;
177 	ulong v, mema, ioa, sioa, smema, base, limit;
178 	Pcisiz *table, *tptr, *mtb, *itb;
179 	extern void qsort(void*, long, long, int (*)(void*, void*));
180 
181 	if(!nobios)
182 		return;
183 
184 	ioa = *pioa;
185 	mema = *pmema;
186 
187 	DBG("pcibusmap wr=%d %T mem=%#lux io=%#lux\n",
188 		wrreg, root->tbdf, mema, ioa);
189 
190 	ntb = 0;
191 	for(p = root; p != nil; p = p->link)
192 		ntb++;
193 
194 	ntb *= (PciCIS-PciBAR0)/4;
195 	table = malloc(2*ntb*sizeof(Pcisiz));
196 	if(table == nil)
197 		panic("pcibusmap: no memory");
198 	itb = table;
199 	mtb = table+ntb;
200 
201 	/*
202 	 * Build a table of sizes
203 	 */
204 	for(p = root; p != nil; p = p->link) {
205 		if(p->ccrb == 0x06) {
206 			if(p->ccru != 0x04 || p->bridge == nil) {
207 //				DBG("pci: ignored bridge %T\n", p->tbdf);
208 				continue;
209 			}
210 
211 			sioa = ioa;
212 			smema = mema;
213 			pcibusmap(p->bridge, &smema, &sioa, 0);
214 
215 			hole = pcimask(smema-mema);
216 			if(hole < (1<<20))
217 				hole = 1<<20;
218 			p->mema.size = hole;
219 
220 			hole = pcimask(sioa-ioa);
221 			if(hole < (1<<12))
222 				hole = 1<<12;
223 
224 			p->ioa.size = hole;
225 
226 			itb->dev = p;
227 			itb->bar = -1;
228 			itb->siz = p->ioa.size;
229 			itb++;
230 
231 			mtb->dev = p;
232 			mtb->bar = -1;
233 			mtb->siz = p->mema.size;
234 			mtb++;
235 			continue;
236 		}
237 
238 		for(i = 0; i <= 5; i++) {
239 			rno = PciBAR0 + i*4;
240 			v = pcicfgrw32(p->tbdf, rno, 0, 1);
241 			size = pcibarsize(p, rno);
242 			if(size == 0)
243 				continue;
244 
245 			if(v & 1) {
246 				itb->dev = p;
247 				itb->bar = i;
248 				itb->siz = size;
249 				itb++;
250 			}
251 			else {
252 				mtb->dev = p;
253 				mtb->bar = i;
254 				mtb->siz = size;
255 				mtb++;
256 			}
257 
258 			p->mem[i].size = size;
259 		}
260 	}
261 
262 	/*
263 	 * Sort both tables IO smallest first, Memory largest
264 	 */
265 	qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
266 	tptr = table+ntb;
267 	qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
268 
269 	/*
270 	 * Allocate IO address space on this bus
271 	 */
272 	for(tptr = table; tptr < itb; tptr++) {
273 		hole = tptr->siz;
274 		if(tptr->bar == -1)
275 			hole = 1<<12;
276 		ioa = (ioa+hole-1) & ~(hole-1);
277 
278 		p = tptr->dev;
279 		if(tptr->bar == -1)
280 			p->ioa.bar = ioa;
281 		else {
282 			p->pcr |= IOen;
283 			p->mem[tptr->bar].bar = ioa|1;
284 			if(wrreg)
285 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
286 		}
287 
288 		ioa += tptr->siz;
289 	}
290 
291 	/*
292 	 * Allocate Memory address space on this bus
293 	 */
294 	for(tptr = table+ntb; tptr < mtb; tptr++) {
295 		hole = tptr->siz;
296 		if(tptr->bar == -1)
297 			hole = 1<<20;
298 		mema = (mema+hole-1) & ~(hole-1);
299 
300 		p = tptr->dev;
301 		if(tptr->bar == -1)
302 			p->mema.bar = mema;
303 		else {
304 			p->pcr |= MEMen;
305 			p->mem[tptr->bar].bar = mema;
306 			if(wrreg)
307 				pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
308 		}
309 		mema += tptr->siz;
310 	}
311 
312 	*pmema = mema;
313 	*pioa = ioa;
314 	free(table);
315 
316 	if(wrreg == 0)
317 		return;
318 
319 	/*
320 	 * Finally set all the bridge addresses & registers
321 	 */
322 	for(p = root; p != nil; p = p->link) {
323 		if(p->bridge == nil) {
324 			pcicfgrw8(p->tbdf, PciLTR, 64, 0);
325 
326 			p->pcr |= MASen;
327 			pcicfgrw16(p->tbdf, PciPCR, p->pcr, 0);
328 			continue;
329 		}
330 
331 		base = p->ioa.bar;
332 		limit = base+p->ioa.size-1;
333 		v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
334 		v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
335 		pcicfgrw32(p->tbdf, PciIBR, v, 0);
336 		v = (limit & 0xFFFF0000)|(base>>16);
337 		pcicfgrw32(p->tbdf, PciIUBR, v, 0);
338 
339 		base = p->mema.bar;
340 		limit = base+p->mema.size-1;
341 		v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
342 		pcicfgrw32(p->tbdf, PciMBR, v, 0);
343 
344 		/*
345 		 * Disable memory prefetch
346 		 */
347 		pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
348 		pcicfgrw8(p->tbdf, PciLTR, 64, 0);
349 
350 		/*
351 		 * Enable the bridge
352 		 */
353 		p->pcr |= IOen|MEMen|MASen;
354 		pcicfgrw32(p->tbdf, PciPCR, 0xFFFF0000|p->pcr , 0);
355 
356 		sioa = p->ioa.bar;
357 		smema = p->mema.bar;
358 		pcibusmap(p->bridge, &smema, &sioa, 1);
359 	}
360 }
361 
362 /* side effect: if a video controller is seen, set pcivga non-zero */
363 static int
pcilscan(int bno,Pcidev ** list)364 pcilscan(int bno, Pcidev** list)
365 {
366 	Pcidev *p, *head, *tail;
367 	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
368 
369 	maxubn = bno;
370 	head = nil;
371 	tail = nil;
372 	for(dno = 0; dno <= pcimaxdno; dno++){
373 		maxfno = 0;
374 		for(fno = 0; fno <= maxfno; fno++){
375 			/*
376 			 * For this possible device, form the
377 			 * bus+device+function triplet needed to address it
378 			 * and try to read the vendor and device ID.
379 			 * If successful, allocate a device struct and
380 			 * start to fill it in with some useful information
381 			 * from the device's configuration space.
382 			 */
383 			tbdf = MKBUS(BusPCI, bno, dno, fno);
384 			l = pcicfgrw32(tbdf, PciVID, 0, 1);
385 			if(l == 0xFFFFFFFF || l == 0)
386 				continue;
387 			p = malloc(sizeof(*p));
388 			if(p == nil)
389 				panic("pcilscan: no memory");
390 			p->tbdf = tbdf;
391 			p->vid = l;
392 			p->did = l>>16;
393 
394 			if(pcilist != nil)
395 				pcitail->list = p;
396 			else
397 				pcilist = p;
398 			pcitail = p;
399 
400 			p->pcr = pcicfgr16(p, PciPCR);
401 			p->rid = pcicfgr8(p, PciRID);
402 			p->ccrp = pcicfgr8(p, PciCCRp);
403 			p->ccru = pcicfgr8(p, PciCCRu);
404 			p->ccrb = pcicfgr8(p, PciCCRb);
405 			p->cls = pcicfgr8(p, PciCLS);
406 			p->ltr = pcicfgr8(p, PciLTR);
407 
408 			p->intl = pcicfgr8(p, PciINTL);
409 
410 			/*
411 			 * If the device is a multi-function device adjust the
412 			 * loop count so all possible functions are checked.
413 			 */
414 			hdt = pcicfgr8(p, PciHDT);
415 			if(hdt & 0x80)
416 				maxfno = MaxFNO;
417 
418 			/*
419 			 * If appropriate, read the base address registers
420 			 * and work out the sizes.
421 			 */
422 			switch(p->ccrb) {
423 			case 0x03:		/* display controller */
424 				pcivga = 1;
425 				/* fall through */
426 			case 0x01:		/* mass storage controller */
427 			case 0x02:		/* network controller */
428 			case 0x04:		/* multimedia device */
429 			case 0x07:		/* simple comm. controllers */
430 			case 0x08:		/* base system peripherals */
431 			case 0x09:		/* input devices */
432 			case 0x0A:		/* docking stations */
433 			case 0x0B:		/* processors */
434 			case 0x0C:		/* serial bus controllers */
435 				if((hdt & 0x7F) != 0)
436 					break;
437 				rno = PciBAR0 - 4;
438 				for(i = 0; i < nelem(p->mem); i++) {
439 					rno += 4;
440 					p->mem[i].bar = pcicfgr32(p, rno);
441 					p->mem[i].size = pcibarsize(p, rno);
442 				}
443 				break;
444 
445 			case 0x00:
446 			case 0x05:		/* memory controller */
447 			case 0x06:		/* bridge device */
448 			default:
449 				break;
450 			}
451 
452 			if(head != nil)
453 				tail->link = p;
454 			else
455 				head = p;
456 			tail = p;
457 		}
458 	}
459 
460 	*list = head;
461 	for(p = head; p != nil; p = p->link){
462 		/*
463 		 * Find PCI-PCI bridges and recursively descend the tree.
464 		 */
465 		if(p->ccrb != 0x06 || p->ccru != 0x04)
466 			continue;
467 
468 		/*
469 		 * If the secondary or subordinate bus number is not
470 		 * initialised try to do what the PCI BIOS should have
471 		 * done and fill in the numbers as the tree is descended.
472 		 * On the way down the subordinate bus number is set to
473 		 * the maximum as it's not known how many buses are behind
474 		 * this one; the final value is set on the way back up.
475 		 */
476 		sbn = pcicfgr8(p, PciSBN);
477 		ubn = pcicfgr8(p, PciUBN);
478 
479 		if(sbn == 0 || ubn == 0 || nobios) {
480 			sbn = maxubn+1;
481 			/*
482 			 * Make sure memory, I/O and master enables are
483 			 * off, set the primary, secondary and subordinate
484 			 * bus numbers and clear the secondary status before
485 			 * attempting to scan the secondary bus.
486 			 *
487 			 * Initialisation of the bridge should be done here.
488 			 */
489 			pcicfgw32(p, PciPCR, 0xFFFF0000);
490 			l = (MaxUBN<<16)|(sbn<<8)|bno;
491 			pcicfgw32(p, PciPBN, l);
492 			pcicfgw16(p, PciSPSR, 0xFFFF);
493 			maxubn = pcilscan(sbn, &p->bridge);
494 			l = (maxubn<<16)|(sbn<<8)|bno;
495 
496 			pcicfgw32(p, PciPBN, l);
497 		}
498 		else {
499 			/*
500 			 * You can't go back.
501 			 * This shouldn't be possible, but the
502 			 * Iwill DK8-HTX seems to have subordinate
503 			 * bus numbers which get smaller on the
504 			 * way down. Need to look more closely at
505 			 * this.
506 			 */
507 			if(ubn > maxubn)
508 				maxubn = ubn;
509 			pcilscan(sbn, &p->bridge);
510 		}
511 	}
512 
513 	return maxubn;
514 }
515 
516 int
pciscan(int bno,Pcidev ** list)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
pIIxget(Pcidev * router,uchar link)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
pIIxset(Pcidev * router,uchar link,uchar irq)538 pIIxset(Pcidev *router, uchar link, uchar irq)
539 {
540 	pcicfgw8(router, link, irq);
541 }
542 
543 static uchar
viaget(Pcidev * router,uchar link)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
viaset(Pcidev * router,uchar link,uchar irq)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
optiget(Pcidev * router,uchar link)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
optiset(Pcidev * router,uchar link,uchar irq)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
aliget(Pcidev * router,uchar link)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
aliset(Pcidev * router,uchar link,uchar irq)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
cyrixget(Pcidev * router,uchar link)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
cyrixset(Pcidev * router,uchar link,uchar irq)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 	{ 0x8086, 0x1c02, pIIxget, pIIxset },	/* Intel 6 Series/C200 */
671 	{ 0x8086, 0x1c44, pIIxget, pIIxset },	/* Intel 6 Series/Z68 Express */
672 	{ 0x8086, 0x1e53, pIIxget, pIIxset },	/* Intel 7 Series/C216 */
673 	{ 0x1106, 0x0586, viaget, viaset },	/* Viatech 82C586 */
674 	{ 0x1106, 0x0596, viaget, viaset },	/* Viatech 82C596 */
675 	{ 0x1106, 0x0686, viaget, viaset },	/* Viatech 82C686 */
676 	{ 0x1106, 0x3227, viaget, viaset },	/* Viatech VT8237 */
677 	{ 0x1045, 0xc700, optiget, optiset },	/* Opti 82C700 */
678 	{ 0x10b9, 0x1533, aliget, aliset },	/* Al M1533 */
679 	{ 0x1039, 0x0008, pIIxget, pIIxset },	/* SI 503 */
680 	{ 0x1039, 0x0496, pIIxget, pIIxset },	/* SI 496 */
681 	{ 0x1078, 0x0100, cyrixget, cyrixset },	/* Cyrix 5530 Legacy */
682 
683 	{ 0x1022, 0x746B, nil, nil },		/* AMD 8111 */
684 	{ 0x10DE, 0x00D1, nil, nil },		/* NVIDIA nForce 3 */
685 	{ 0x10DE, 0x00E0, nil, nil },		/* NVIDIA nForce 3 250 Series */
686 	{ 0x10DE, 0x00E1, nil, nil },		/* NVIDIA nForce 3 250 Series */
687 	{ 0x1166, 0x0200, nil, nil },		/* ServerWorks ServerSet III LE */
688 	{ 0x1002, 0x4377, nil, nil },		/* ATI Radeon Xpress 200M */
689 	{ 0x1002, 0x4372, nil, nil },		/* ATI SB400 */
690 };
691 
692 typedef struct Slot Slot;
693 struct Slot {
694 	uchar	bus;			// Pci bus number
695 	uchar	dev;			// Pci device number
696 	uchar	maps[12];		// Avoid structs!  Link and mask.
697 	uchar	slot;			// Add-in/built-in slot
698 	uchar	reserved;
699 };
700 
701 typedef struct Router Router;
702 struct Router {
703 	uchar	signature[4];		// Routing table signature
704 	uchar	version[2];		// Version number
705 	uchar	size[2];		// Total table size
706 	uchar	bus;			// Interrupt router bus number
707 	uchar	devfn;			// Router's devfunc
708 	uchar	pciirqs[2];		// Exclusive PCI irqs
709 	uchar	compat[4];		// Compatible PCI interrupt router
710 	uchar	miniport[4];		// Miniport data
711 	uchar	reserved[11];
712 	uchar	checksum;
713 };
714 
715 static ushort pciirqs;			// Exclusive PCI irqs
716 static Bridge *southbridge;		// Which southbridge to use.
717 
718 static void
pcirouting(void)719 pcirouting(void)
720 {
721 	Slot *e;
722 	Router *r;
723 	int size, i, fn, tbdf;
724 	Pcidev *sbpci, *pci;
725 	uchar *p, pin, irq, link, *map;
726 
727 	// Search for PCI interrupt routing table in BIOS
728 	for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
729 		if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
730 			break;
731 
732 	if(p >= (uchar *)KADDR(0xfffff)) {
733 		// print("no PCI intr routing table found\n");
734 		return;
735 	}
736 
737 	r = (Router *)p;
738 
739 	if (0)
740 		print("PCI interrupt routing table version %d.%d at %#p\n",
741 			r->version[0], r->version[1], r);
742 
743 	tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8);
744 	sbpci = pcimatchtbdf(tbdf);
745 	if(sbpci == nil) {
746 		print("pcirouting: Cannot find south bridge %T\n", tbdf);
747 		return;
748 	}
749 
750 	for(i = 0; i != nelem(southbridges); i++)
751 		if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did)
752 			break;
753 
754 	if(i == nelem(southbridges)) {
755 		print("pcirouting: ignoring south bridge %T %.4ux/%.4ux\n", tbdf, sbpci->vid, sbpci->did);
756 		return;
757 	}
758 	southbridge = &southbridges[i];
759 	if(southbridge->get == nil || southbridge->set == nil)
760 		return;
761 
762 	pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0];
763 
764 	size = (r->size[1] << 8)|r->size[0];
765 	for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) {
766 		// print("%.2ux/%.2ux %.2ux: ", e->bus, e->dev, e->slot);
767 		// for (i = 0; i != 4; i++) {
768 		// 	uchar *m = &e->maps[i * 3];
769 		// 	print("[%d] %.2ux %.4ux ",
770 		// 		i, m[0], (m[2] << 8)|m[1]);
771 		// }
772 		// print("\n");
773 
774 		for(fn = 0; fn != 8; fn++) {
775 			tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
776 			pci = pcimatchtbdf(tbdf);
777 			if(pci == nil)
778 				continue;
779 			pin = pcicfgr8(pci, PciINTP);
780 			if(pin == 0 || pin == 0xff)
781 				continue;
782 
783 			map = &e->maps[(pin - 1) * 3];
784 			link = map[0];
785 			irq = southbridge->get(sbpci, link);
786 			if(irq == 0 || irq == pci->intl)
787 				continue;
788 			if(pci->intl != 0 && pci->intl != 0xFF) {
789 				print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
790 					  tbdf, pin, link, irq, pci->intl);
791 				southbridge->set(sbpci, link, pci->intl);
792 				continue;
793 			}
794 			print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
795 			pcicfgw8(pci, PciINTL, irq);
796 			pci->intl = irq;
797 		}
798 	}
799 }
800 
801 static void pcireservemem(void);
802 
803 static void
pcicfginit(void)804 pcicfginit(void)
805 {
806 	char *p;
807 	Pcidev **list;
808 	ulong mema, ioa;
809 	int bno, n;
810 
811 	lock(&pcicfginitlock);
812 	if(pcicfgmode != -1)
813 		goto out;
814 
815 	if(getconf("*nobios"))
816 		nobios = 1;
817 	if(getconf("*nopcirouting"))
818 		nopcirouting = 1;
819 
820 	/*
821 	 * Assume Configuration Mechanism One. Method Two was deprecated
822 	 * a long time ago and was only for backwards compaibility with the
823 	 * Intel Saturn and Mercury chip sets. Thank you, QEMU.
824 	 */
825 	pcicfgmode = 1;
826 	pcimaxdno = 31;
827 
828 	if(pcicfgmode < 0)
829 		goto out;
830 
831 	fmtinstall('T', tbdffmt);
832 
833 	if(p = getconf("*pcimaxbno")){
834 		n = strtoul(p, 0, 0);
835 		if(n < pcimaxbno)
836 			pcimaxbno = n;
837 	}
838 	if(p = getconf("*pcimaxdno")){
839 		n = strtoul(p, 0, 0);
840 		if(n < pcimaxdno)
841 			pcimaxdno = n;
842 	}
843 
844 	list = &pciroot;
845 	for(bno = 0; bno <= pcimaxbno; bno++) {
846 		int sbno = bno;
847 		bno = pcilscan(bno, list);
848 
849 		while(*list)
850 			list = &(*list)->link;
851 
852 		if (sbno == 0) {
853 			Pcidev *pci;
854 
855 			/*
856 			  * If we have found a PCI-to-Cardbus bridge, make sure
857 			  * it has no valid mappings anymore.
858 			  */
859 			pci = pciroot;
860 			while (pci) {
861 				if (pci->ccrb == 6 && pci->ccru == 7) {
862 					ushort bcr;
863 
864 					/* reset the cardbus */
865 					bcr = pcicfgr16(pci, PciBCR);
866 					pcicfgw16(pci, PciBCR, 0x40 | bcr);
867 					delay(50);
868 				}
869 				pci = pci->link;
870 			}
871 		}
872 	}
873 
874 	if(pciroot == nil)
875 		goto out;
876 
877 	if(nobios) {
878 		/*
879 		 * Work out how big the top bus is
880 		 */
881 		mema = 0;
882 		ioa = 0;
883 		pcibusmap(pciroot, &mema, &ioa, 0);
884 
885 		DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
886 			mema, pcimask(mema), ioa);
887 
888 		/*
889 		 * Align the windows and map it
890 		 */
891 		ioa = 0x1000;
892 		mema = 0x90000000;
893 
894 		pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
895 
896 		pcibusmap(pciroot, &mema, &ioa, 1);
897 		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
898 
899 		unlock(&pcicfginitlock);
900 		return;
901 	}
902 
903 	if (!nopcirouting)
904 		pcirouting();
905 
906 out:
907 	pcireservemem();
908 	unlock(&pcicfginitlock);
909 
910 	if(getconf("*pcihinv"))
911 		pcihinv(nil);
912 }
913 
914 static void
pcireservemem(void)915 pcireservemem(void)
916 {
917 	int i;
918 	Pcidev *p;
919 
920 	/*
921 	 * mark all the physical address space claimed by pci devices
922 	 * as in use, so that it's not given out elsewhere.
923 	 * beware the type and size of 'bar'.
924 	 */
925 	for(p=pciroot; p; p=p->list)
926 		for(i=0; i<nelem(p->mem); i++)
927 			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
928 				asmmapinit(p->mem[i].bar&~0x0F, p->mem[i].size, 5);
929 }
930 
931 static int
pcicfgrw8(int tbdf,int rno,int data,int read)932 pcicfgrw8(int tbdf, int rno, int data, int read)
933 {
934 	int o, type, x;
935 
936 	if(pcicfgmode == -1)
937 		pcicfginit();
938 
939 	if(BUSBNO(tbdf))
940 		type = 0x01;
941 	else
942 		type = 0x00;
943 	x = -1;
944 	if(BUSDNO(tbdf) > pcimaxdno)
945 		return x;
946 
947 	lock(&pcicfglock);
948 	switch(pcicfgmode){
949 
950 	case 1:
951 		o = rno & 0x03;
952 		rno &= ~0x03;
953 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
954 		if(read)
955 			x = inb(PciDATA+o);
956 		else
957 			outb(PciDATA+o, data);
958 		outl(PciADDR, 0);
959 		break;
960 
961 	case 2:
962 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
963 		outb(PciFORWARD, BUSBNO(tbdf));
964 		if(read)
965 			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
966 		else
967 			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
968 		outb(PciCSE, 0);
969 		break;
970 	}
971 	unlock(&pcicfglock);
972 
973 	return x;
974 }
975 
976 int
pcicfgr8(Pcidev * pcidev,int rno)977 pcicfgr8(Pcidev* pcidev, int rno)
978 {
979 	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
980 }
981 
982 void
pcicfgw8(Pcidev * pcidev,int rno,int data)983 pcicfgw8(Pcidev* pcidev, int rno, int data)
984 {
985 	pcicfgrw8(pcidev->tbdf, rno, data, 0);
986 }
987 
988 static int
pcicfgrw16(int tbdf,int rno,int data,int read)989 pcicfgrw16(int tbdf, int rno, int data, int read)
990 {
991 	int o, type, x;
992 
993 	if(pcicfgmode == -1)
994 		pcicfginit();
995 
996 	if(BUSBNO(tbdf))
997 		type = 0x01;
998 	else
999 		type = 0x00;
1000 	x = -1;
1001 	if(BUSDNO(tbdf) > pcimaxdno)
1002 		return x;
1003 
1004 	lock(&pcicfglock);
1005 	switch(pcicfgmode){
1006 
1007 	case 1:
1008 		o = rno & 0x02;
1009 		rno &= ~0x03;
1010 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1011 		if(read)
1012 			x = ins(PciDATA+o);
1013 		else
1014 			outs(PciDATA+o, data);
1015 		outl(PciADDR, 0);
1016 		break;
1017 
1018 	case 2:
1019 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1020 		outb(PciFORWARD, BUSBNO(tbdf));
1021 		if(read)
1022 			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1023 		else
1024 			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1025 		outb(PciCSE, 0);
1026 		break;
1027 	}
1028 	unlock(&pcicfglock);
1029 
1030 	return x;
1031 }
1032 
1033 int
pcicfgr16(Pcidev * pcidev,int rno)1034 pcicfgr16(Pcidev* pcidev, int rno)
1035 {
1036 	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
1037 }
1038 
1039 void
pcicfgw16(Pcidev * pcidev,int rno,int data)1040 pcicfgw16(Pcidev* pcidev, int rno, int data)
1041 {
1042 	pcicfgrw16(pcidev->tbdf, rno, data, 0);
1043 }
1044 
1045 static int
pcicfgrw32(int tbdf,int rno,int data,int read)1046 pcicfgrw32(int tbdf, int rno, int data, int read)
1047 {
1048 	int type, x;
1049 
1050 	if(pcicfgmode == -1)
1051 		pcicfginit();
1052 
1053 	if(BUSBNO(tbdf))
1054 		type = 0x01;
1055 	else
1056 		type = 0x00;
1057 	x = -1;
1058 	if(BUSDNO(tbdf) > pcimaxdno)
1059 		return x;
1060 
1061 	lock(&pcicfglock);
1062 	switch(pcicfgmode){
1063 
1064 	case 1:
1065 		rno &= ~0x03;
1066 		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1067 		if(read)
1068 			x = inl(PciDATA);
1069 		else
1070 			outl(PciDATA, data);
1071 		outl(PciADDR, 0);
1072 		break;
1073 
1074 	case 2:
1075 		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1076 		outb(PciFORWARD, BUSBNO(tbdf));
1077 		if(read)
1078 			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1079 		else
1080 			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1081 		outb(PciCSE, 0);
1082 		break;
1083 	}
1084 	unlock(&pcicfglock);
1085 
1086 	return x;
1087 }
1088 
1089 int
pcicfgr32(Pcidev * pcidev,int rno)1090 pcicfgr32(Pcidev* pcidev, int rno)
1091 {
1092 	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
1093 }
1094 
1095 void
pcicfgw32(Pcidev * pcidev,int rno,int data)1096 pcicfgw32(Pcidev* pcidev, int rno, int data)
1097 {
1098 	pcicfgrw32(pcidev->tbdf, rno, data, 0);
1099 }
1100 
1101 Pcidev*
pcimatch(Pcidev * prev,int vid,int did)1102 pcimatch(Pcidev* prev, int vid, int did)
1103 {
1104 	if(pcicfgmode == -1)
1105 		pcicfginit();
1106 
1107 	if(prev == nil)
1108 		prev = pcilist;
1109 	else
1110 		prev = prev->list;
1111 
1112 	while(prev != nil){
1113 		if((vid == 0 || prev->vid == vid)
1114 		&& (did == 0 || prev->did == did))
1115 			break;
1116 		prev = prev->list;
1117 	}
1118 	return prev;
1119 }
1120 
1121 Pcidev*
pcimatchtbdf(int tbdf)1122 pcimatchtbdf(int tbdf)
1123 {
1124 	Pcidev *pcidev;
1125 
1126 	if(pcicfgmode == -1)
1127 		pcicfginit();
1128 
1129 	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
1130 		if(pcidev->tbdf == tbdf)
1131 			break;
1132 	}
1133 	return pcidev;
1134 }
1135 
1136 uchar
pciipin(Pcidev * pci,uchar pin)1137 pciipin(Pcidev *pci, uchar pin)
1138 {
1139 	if (pci == nil)
1140 		pci = pcilist;
1141 
1142 	while (pci) {
1143 		uchar intl;
1144 
1145 		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
1146 			return pci->intl;
1147 
1148 		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
1149 			return intl;
1150 
1151 		pci = pci->list;
1152 	}
1153 	return 0;
1154 }
1155 
1156 static void
pcilhinv(Pcidev * p)1157 pcilhinv(Pcidev* p)
1158 {
1159 	int i;
1160 	Pcidev *t;
1161 
1162 	if(p == nil) {
1163 		putstrn(PCICONS.output, PCICONS.ptr);
1164 		p = pciroot;
1165 		print("bus dev type vid  did intl memory\n");
1166 	}
1167 	for(t = p; t != nil; t = t->link) {
1168 		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
1169 			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
1170 			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
1171 
1172 		for(i = 0; i < nelem(p->mem); i++) {
1173 			if(t->mem[i].size == 0)
1174 				continue;
1175 			print("%d:%.8lux %d ", i,
1176 				t->mem[i].bar, t->mem[i].size);
1177 		}
1178 		if(t->ioa.bar || t->ioa.size)
1179 			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
1180 		if(t->mema.bar || t->mema.size)
1181 			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
1182 		if(t->bridge)
1183 			print("->%d", BUSBNO(t->bridge->tbdf));
1184 		print("\n");
1185 	}
1186 	while(p != nil) {
1187 		if(p->bridge != nil)
1188 			pcilhinv(p->bridge);
1189 		p = p->link;
1190 	}
1191 }
1192 
1193 void
pcihinv(Pcidev * p)1194 pcihinv(Pcidev* p)
1195 {
1196 	if(pcicfgmode == -1)
1197 		pcicfginit();
1198 	lock(&pcicfginitlock);
1199 	pcilhinv(p);
1200 	unlock(&pcicfginitlock);
1201 }
1202 
1203 void
pcireset(void)1204 pcireset(void)
1205 {
1206 	Pcidev *p;
1207 
1208 	if(pcicfgmode == -1)
1209 		pcicfginit();
1210 
1211 	for(p = pcilist; p != nil; p = p->list) {
1212 		/* don't mess with the bridges */
1213 		if(p->ccrb == 0x06)
1214 			continue;
1215 		pciclrbme(p);
1216 	}
1217 }
1218 
1219 void
pcisetioe(Pcidev * p)1220 pcisetioe(Pcidev* p)
1221 {
1222 	p->pcr |= IOen;
1223 	pcicfgw16(p, PciPCR, p->pcr);
1224 }
1225 
1226 void
pciclrioe(Pcidev * p)1227 pciclrioe(Pcidev* p)
1228 {
1229 	p->pcr &= ~IOen;
1230 	pcicfgw16(p, PciPCR, p->pcr);
1231 }
1232 
1233 void
pcisetbme(Pcidev * p)1234 pcisetbme(Pcidev* p)
1235 {
1236 	p->pcr |= MASen;
1237 	pcicfgw16(p, PciPCR, p->pcr);
1238 }
1239 
1240 void
pciclrbme(Pcidev * p)1241 pciclrbme(Pcidev* p)
1242 {
1243 	p->pcr &= ~MASen;
1244 	pcicfgw16(p, PciPCR, p->pcr);
1245 }
1246 
1247 void
pcisetmwi(Pcidev * p)1248 pcisetmwi(Pcidev* p)
1249 {
1250 	p->pcr |= MemWrInv;
1251 	pcicfgw16(p, PciPCR, p->pcr);
1252 }
1253 
1254 void
pciclrmwi(Pcidev * p)1255 pciclrmwi(Pcidev* p)
1256 {
1257 	p->pcr &= ~MemWrInv;
1258 	pcicfgw16(p, PciPCR, p->pcr);
1259 }
1260 
1261 int
pcienumcaps(Pcidev * p,int (* fmatch)(Pcidev *,int,int,int),int arg)1262 pcienumcaps(Pcidev* p, int (*fmatch)(Pcidev*, int, int, int), int arg)
1263 {
1264 	int i, r, cap, off;
1265 
1266 	/* status register bit 4 has capabilities */
1267 	if((pcicfgr16(p, PciPSR) & 1<<4) == 0)
1268 		return -1;
1269 	switch(pcicfgr8(p, PciHDT) & 0x7f){
1270 	default:
1271 		return -1;
1272 	case 0:					/* all other */
1273 	case 1:					/* PCI to PCI bridge */
1274 		off = PciCP;
1275 		break;
1276 	case 2:					/* CardBus bridge */
1277 		off = 0x14;
1278 		break;
1279 	}
1280 	for(i = 48; i--;){
1281 		off = pcicfgr8(p, off);
1282 		if(off < 0x40 || (off & 3))
1283 			break;
1284 		off &= ~3;
1285 		cap = pcicfgr8(p, off);
1286 		if(cap == 0xff)
1287 			break;
1288 		r = (*fmatch)(p, cap, off, arg);
1289 		if(r < 0)
1290 			break;
1291 		if(r == 0)
1292 			return off;
1293 		off++;
1294 	}
1295 
1296 	return -1;
1297 }
1298 
1299 static int
matchcap(Pcidev *,int cap,int,int arg)1300 matchcap(Pcidev*, int cap, int, int arg)
1301 {
1302 	return cap != arg;
1303 }
1304 
1305 static int
matchhtcap(Pcidev * p,int cap,int off,int arg)1306 matchhtcap(Pcidev* p, int cap, int off, int arg)
1307 {
1308 	int mask;
1309 
1310 	if(cap != PciCapHTC)
1311 		return 1;
1312 	if(arg == 0x00 || arg == 0x20)
1313 		mask = 0xE0;
1314 	else
1315 		mask = 0xF8;
1316 	cap = pcicfgr8(p, off+3);
1317 	return (cap & mask) != arg;
1318 }
1319 
1320 int
pcicap(Pcidev * p,int cap)1321 pcicap(Pcidev* p, int cap)
1322 {
1323 	return pcienumcaps(p, matchcap, cap);
1324 }
1325 
1326 int
pcihtcap(Pcidev * p,int cap)1327 pcihtcap(Pcidev* p, int cap)
1328 {
1329 	return pcienumcaps(p, matchhtcap, cap);
1330 }
1331 
1332 int
pcigetpms(Pcidev * p)1333 pcigetpms(Pcidev* p)
1334 {
1335 	int pmcsr, ptr;
1336 
1337 	if((ptr = pcicap(p, PciCapPMG)) == -1)
1338 		return -1;
1339 
1340 	/*
1341 	 * Power Management Register Block:
1342 	 *  offset 0:	Capability ID
1343 	 *	   1:	next item pointer
1344 	 *	   2:	capabilities
1345 	 *	   4:	control/status
1346 	 *	   6:	bridge support extensions
1347 	 *	   7:	data
1348 	 */
1349 	pmcsr = pcicfgr16(p, ptr+4);
1350 
1351 	return pmcsr & 0x0003;
1352 }
1353 
1354 int
pcisetpms(Pcidev * p,int state)1355 pcisetpms(Pcidev* p, int state)
1356 {
1357 	int ostate, pmc, pmcsr, ptr;
1358 
1359 	if((ptr = pcicap(p, PciCapPMG)) == -1)
1360 		return -1;
1361 
1362 	pmc = pcicfgr16(p, ptr+2);
1363 	pmcsr = pcicfgr16(p, ptr+4);
1364 	ostate = pmcsr & 0x0003;
1365 	pmcsr &= ~0x0003;
1366 
1367 	switch(state){
1368 	default:
1369 		return -1;
1370 	case 0:
1371 		break;
1372 	case 1:
1373 		if(!(pmc & 0x0200))
1374 			return -1;
1375 		break;
1376 	case 2:
1377 		if(!(pmc & 0x0400))
1378 			return -1;
1379 		break;
1380 	case 3:
1381 		break;
1382 	}
1383 	pmcsr |= state;
1384 	pcicfgw16(p, ptr+4, pmcsr);
1385 
1386 	return ostate;
1387 }
1388