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