Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/9/teg2/pci.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
374
pciintr(Ureg *ureg, void *p)
375
{
376
	rtl8169interrupt(ureg, p);		/* HACK */
377
}
378
 
379
static 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
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 *
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
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
524
pcicfgr8(Pcidev* pcidev, int rno)
525
{
526
	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
527
}
528
 
529
void
530
pcicfgw8(Pcidev* pcidev, int rno, int data)
531
{
532
	pcicfgrw8(pcidev->tbdf, rno, data, 0);
533
}
534
 
535
static int
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
561
pcicfgr16(Pcidev* pcidev, int rno)
562
{
563
	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
564
}
565
 
566
void
567
pcicfgw16(Pcidev* pcidev, int rno, int data)
568
{
569
	pcicfgrw16(pcidev->tbdf, rno, data, 0);
570
}
571
 
572
static int
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
602
pcicfgr32(Pcidev* pcidev, int rno)
603
{
604
	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
605
}
606
 
607
void
608
pcicfgw32(Pcidev* pcidev, int rno, int data)
609
{
610
	pcicfgrw32(pcidev->tbdf, rno, data, 0);
611
}
612
 
613
Pcidev*
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*
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
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
682
pcihinv(Pcidev* p)
683
{
684
	if(pcicfgmode == -1)
685
		pcicfginit();
686
	lock(&pcicfginitlock);
687
	pcilhinv(p);
688
	unlock(&pcicfginitlock);
689
}
690
 
691
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
708
pcisetioe(Pcidev* p)
709
{
710
	p->pcr |= IOen;
711
	pcicfgw16(p, PciPCR, p->pcr);
712
}
713
 
714
void
715
pciclrioe(Pcidev* p)
716
{
717
	p->pcr &= ~IOen;
718
	pcicfgw16(p, PciPCR, p->pcr);
719
}
720
 
721
void
722
pcisetbme(Pcidev* p)
723
{
724
	p->pcr |= MASen;
725
	pcicfgw16(p, PciPCR, p->pcr);
726
}
727
 
728
void
729
pciclrbme(Pcidev* p)
730
{
731
	p->pcr &= ~MASen;
732
	pcicfgw16(p, PciPCR, p->pcr);
733
}
734
 
735
void
736
pcisetmwi(Pcidev* p)
737
{
738
	p->pcr |= MemWrInv;
739
	pcicfgw16(p, PciPCR, p->pcr);
740
}
741
 
742
void
743
pciclrmwi(Pcidev* p)
744
{
745
	p->pcr &= ~MemWrInv;
746
	pcicfgw16(p, PciPCR, p->pcr);
747
}
748
 
749
static int
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
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
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
}