Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | 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
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
	{ 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
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 %#.6luX\n",
741
			r->version[0], r->version[1], (ulong)r & 0xfffff);
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
		if (0) {
767
			print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot);
768
			for (i = 0; i != 4; i++) {
769
				uchar *m = &e->maps[i * 3];
770
				print("[%d] %.2uX %.4uX ",
771
					i, m[0], (m[2] << 8)|m[1]);
772
			}
773
			print("\n");
774
		}
775
		for(fn = 0; fn != 8; fn++) {
776
			tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8);
777
			pci = pcimatchtbdf(tbdf);
778
			if(pci == nil)
779
				continue;
780
			pin = pcicfgr8(pci, PciINTP);
781
			if(pin == 0 || pin == 0xff)
782
				continue;
783
 
784
			map = &e->maps[(pin - 1) * 3];
785
			link = map[0];
786
			irq = southbridge->get(sbpci, link);
787
			if(irq == 0 || irq == pci->intl)
788
				continue;
789
			if(pci->intl != 0 && pci->intl != 0xFF) {
790
				print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n",
791
					  tbdf, pin, link, irq, pci->intl);
792
				southbridge->set(sbpci, link, pci->intl);
793
				continue;
794
			}
795
			print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq);
796
			pcicfgw8(pci, PciINTL, irq);
797
			pci->intl = irq;
798
		}
799
	}
800
}
801
 
802
static void pcireservemem(void);
803
 
804
static int
805
pcicfgrw8bios(int tbdf, int rno, int data, int read)
806
{
807
	BIOS32ci ci;
808
 
809
	if(pcibiossi == nil)
810
		return -1;
811
 
812
	memset(&ci, 0, sizeof(BIOS32ci));
813
	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
814
	ci.edi = rno;
815
	if(read){
816
		ci.eax = 0xB108;
817
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
818
			return ci.ecx & 0xFF;
819
	}
820
	else{
821
		ci.eax = 0xB10B;
822
		ci.ecx = data & 0xFF;
823
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
824
			return 0;
825
	}
826
 
827
	return -1;
828
}
829
 
830
static int
831
pcicfgrw16bios(int tbdf, int rno, int data, int read)
832
{
833
	BIOS32ci ci;
834
 
835
	if(pcibiossi == nil)
836
		return -1;
837
 
838
	memset(&ci, 0, sizeof(BIOS32ci));
839
	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
840
	ci.edi = rno;
841
	if(read){
842
		ci.eax = 0xB109;
843
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
844
			return ci.ecx & 0xFFFF;
845
	}
846
	else{
847
		ci.eax = 0xB10C;
848
		ci.ecx = data & 0xFFFF;
849
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
850
			return 0;
851
	}
852
 
853
	return -1;
854
}
855
 
856
static int
857
pcicfgrw32bios(int tbdf, int rno, int data, int read)
858
{
859
	BIOS32ci ci;
860
 
861
	if(pcibiossi == nil)
862
		return -1;
863
 
864
	memset(&ci, 0, sizeof(BIOS32ci));
865
	ci.ebx = (BUSBNO(tbdf)<<8)|(BUSDNO(tbdf)<<3)|BUSFNO(tbdf);
866
	ci.edi = rno;
867
	if(read){
868
		ci.eax = 0xB10A;
869
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
870
			return ci.ecx;
871
	}
872
	else{
873
		ci.eax = 0xB10D;
874
		ci.ecx = data;
875
		if(!bios32ci(pcibiossi, &ci)/* && !(ci.eax & 0xFF)*/)
876
			return 0;
877
	}
878
 
879
	return -1;
880
}
881
 
882
static BIOS32si*
883
pcibiosinit(void)
884
{
885
	BIOS32ci ci;
886
	BIOS32si *si;
887
 
888
	if((si = bios32open("$PCI")) == nil)
889
		return nil;
890
 
891
	memset(&ci, 0, sizeof(BIOS32ci));
892
	ci.eax = 0xB101;
893
	if(bios32ci(si, &ci) || ci.edx != ((' '<<24)|('I'<<16)|('C'<<8)|'P')){
894
		free(si);
895
		return nil;
896
	}
897
	if(ci.eax & 0x01)
898
		pcimaxdno = 31;
899
	else
900
		pcimaxdno = 15;
901
	pcimaxbno = ci.ecx & 0xff;
902
 
903
	return si;
904
}
905
 
906
void
907
pcibussize(Pcidev *root, ulong *msize, ulong *iosize)
908
{
909
	*msize = 0;
910
	*iosize = 0;
911
	pcibusmap(root, msize, iosize, 0);
912
}
913
 
914
static void
915
pcicfginit(void)
916
{
917
	char *p;
918
	Pcidev **list;
919
	ulong mema, ioa;
920
	int bno, n, pcibios;
921
 
922
	lock(&pcicfginitlock);
923
	if(pcicfgmode != -1)
924
		goto out;
925
 
926
	pcibios = 0;
927
	if(getconf("*nobios"))
928
		nobios = 1;
929
	else if(getconf("*pcibios"))
930
		pcibios = 1;
931
	if(getconf("*nopcirouting"))
932
		nopcirouting = 1;
933
 
934
	/*
935
	 * Try to determine which PCI configuration mode is implemented.
936
	 * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
937
	 * a DWORD at 0xCF8 and another at 0xCFC and will pass through
938
	 * any non-DWORD accesses as normal I/O cycles. There shouldn't be
939
	 * a device behind these addresses so if Mode1 accesses fail try
940
	 * for Mode2 (Mode2 is deprecated).
941
	 */
942
	if(!pcibios){
943
		/*
944
		 * Bits [30:24] of PciADDR must be 0,
945
		 * according to the spec.
946
		 */
947
		n = inl(PciADDR);
948
		if(!(n & 0x7F000000)){
949
			outl(PciADDR, 0x80000000);
950
			outb(PciADDR+3, 0);
951
			if(inl(PciADDR) & 0x80000000){
952
				pcicfgmode = 1;
953
				pcimaxdno = 31;
954
			}
955
		}
956
		outl(PciADDR, n);
957
 
958
		if(pcicfgmode < 0){
959
			/*
960
			 * The 'key' part of PciCSE should be 0.
961
			 */
962
			n = inb(PciCSE);
963
			if(!(n & 0xF0)){
964
				outb(PciCSE, 0x0E);
965
				if(inb(PciCSE) == 0x0E){
966
					pcicfgmode = 2;
967
					pcimaxdno = 15;
968
				}
969
			}
970
			outb(PciCSE, n);
971
		}
972
	}
973
 
974
	if(pcicfgmode < 0 || pcibios) {
975
		if((pcibiossi = pcibiosinit()) == nil)
976
			goto out;
977
		pcicfgrw8 = pcicfgrw8bios;
978
		pcicfgrw16 = pcicfgrw16bios;
979
		pcicfgrw32 = pcicfgrw32bios;
980
		pcicfgmode = 3;
981
	}
982
 
983
	fmtinstall('T', tbdffmt);
984
 
985
	if(p = getconf("*pcimaxbno")){
986
		n = strtoul(p, 0, 0);
987
		if(n < pcimaxbno)
988
			pcimaxbno = n;
989
	}
990
	if(p = getconf("*pcimaxdno")){
991
		n = strtoul(p, 0, 0);
992
		if(n < pcimaxdno)
993
			pcimaxdno = n;
994
	}
995
 
996
	list = &pciroot;
997
	for(bno = 0; bno <= pcimaxbno; bno++) {
998
		int sbno = bno;
999
		bno = pcilscan(bno, list);
1000
 
1001
		while(*list)
1002
			list = &(*list)->link;
1003
 
1004
		if (sbno == 0) {
1005
			Pcidev *pci;
1006
 
1007
			/*
1008
			  * If we have found a PCI-to-Cardbus bridge, make sure
1009
			  * it has no valid mappings anymore.
1010
			  */
1011
			for(pci = pciroot; pci != nil; pci = pci->link){
1012
				if (pci->ccrb == 6 && pci->ccru == 7) {
1013
					ushort bcr;
1014
 
1015
					/* reset the cardbus */
1016
					bcr = pcicfgr16(pci, PciBCR);
1017
					pcicfgw16(pci, PciBCR, 0x40 | bcr);
1018
					delay(50);
1019
				}
1020
			}
1021
		}
1022
	}
1023
 
1024
	if(pciroot == nil)
1025
		goto out;
1026
 
1027
	if(nobios) {
1028
		/*
1029
		 * Work out how big the top bus is
1030
		 */
1031
		pcibussize(pciroot, &mema, &ioa);
1032
 
1033
		/*
1034
		 * Align the windows and map it
1035
		 */
1036
		ioa = 0x1000;
1037
		mema = 0x90000000;
1038
 
1039
		pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
1040
 
1041
		pcibusmap(pciroot, &mema, &ioa, 1);
1042
		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
1043
 
1044
		unlock(&pcicfginitlock);
1045
		return;
1046
	}
1047
 
1048
	if (!nopcirouting)
1049
		pcirouting();
1050
 
1051
out:
1052
	pcireservemem();
1053
	unlock(&pcicfginitlock);
1054
 
1055
	if(getconf("*pcihinv"))
1056
		pcihinv(nil);
1057
}
1058
 
1059
static void
1060
pcireservemem(void)
1061
{
1062
	int i;
1063
	Pcidev *p;
1064
 
1065
	/*
1066
	 * mark all the physical address space claimed by pci devices
1067
	 * as in use, so that upaalloc doesn't give it out.
1068
	 */
1069
	for(p=pciroot; p; p=p->list)
1070
		for(i=0; i<nelem(p->mem); i++)
1071
			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
1072
				upareserve(p->mem[i].bar&~0x0F, p->mem[i].size);
1073
}
1074
 
1075
static int
1076
pcicfgrw8raw(int tbdf, int rno, int data, int read)
1077
{
1078
	int o, type, x;
1079
 
1080
	if(pcicfgmode == -1)
1081
		pcicfginit();
1082
 
1083
	if(BUSBNO(tbdf))
1084
		type = 0x01;
1085
	else
1086
		type = 0x00;
1087
	x = -1;
1088
	if(BUSDNO(tbdf) > pcimaxdno)
1089
		return x;
1090
 
1091
	lock(&pcicfglock);
1092
	switch(pcicfgmode){
1093
 
1094
	case 1:
1095
		o = rno & 0x03;
1096
		rno &= ~0x03;
1097
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1098
		if(read)
1099
			x = inb(PciDATA+o);
1100
		else
1101
			outb(PciDATA+o, data);
1102
		outl(PciADDR, 0);
1103
		break;
1104
 
1105
	case 2:
1106
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1107
		outb(PciFORWARD, BUSBNO(tbdf));
1108
		if(read)
1109
			x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1110
		else
1111
			outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1112
		outb(PciCSE, 0);
1113
		break;
1114
	}
1115
	unlock(&pcicfglock);
1116
 
1117
	return x;
1118
}
1119
 
1120
int
1121
pcicfgr8(Pcidev* pcidev, int rno)
1122
{
1123
	return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
1124
}
1125
 
1126
void
1127
pcicfgw8(Pcidev* pcidev, int rno, int data)
1128
{
1129
	pcicfgrw8(pcidev->tbdf, rno, data, 0);
1130
}
1131
 
1132
static int
1133
pcicfgrw16raw(int tbdf, int rno, int data, int read)
1134
{
1135
	int o, type, x;
1136
 
1137
	if(pcicfgmode == -1)
1138
		pcicfginit();
1139
 
1140
	if(BUSBNO(tbdf))
1141
		type = 0x01;
1142
	else
1143
		type = 0x00;
1144
	x = -1;
1145
	if(BUSDNO(tbdf) > pcimaxdno)
1146
		return x;
1147
 
1148
	lock(&pcicfglock);
1149
	switch(pcicfgmode){
1150
 
1151
	case 1:
1152
		o = rno & 0x02;
1153
		rno &= ~0x03;
1154
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1155
		if(read)
1156
			x = ins(PciDATA+o);
1157
		else
1158
			outs(PciDATA+o, data);
1159
		outl(PciADDR, 0);
1160
		break;
1161
 
1162
	case 2:
1163
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1164
		outb(PciFORWARD, BUSBNO(tbdf));
1165
		if(read)
1166
			x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1167
		else
1168
			outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1169
		outb(PciCSE, 0);
1170
		break;
1171
	}
1172
	unlock(&pcicfglock);
1173
 
1174
	return x;
1175
}
1176
 
1177
int
1178
pcicfgr16(Pcidev* pcidev, int rno)
1179
{
1180
	return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
1181
}
1182
 
1183
void
1184
pcicfgw16(Pcidev* pcidev, int rno, int data)
1185
{
1186
	pcicfgrw16(pcidev->tbdf, rno, data, 0);
1187
}
1188
 
1189
static int
1190
pcicfgrw32raw(int tbdf, int rno, int data, int read)
1191
{
1192
	int type, x;
1193
 
1194
	if(pcicfgmode == -1)
1195
		pcicfginit();
1196
 
1197
	if(BUSBNO(tbdf))
1198
		type = 0x01;
1199
	else
1200
		type = 0x00;
1201
	x = -1;
1202
	if(BUSDNO(tbdf) > pcimaxdno)
1203
		return x;
1204
 
1205
	lock(&pcicfglock);
1206
	switch(pcicfgmode){
1207
 
1208
	case 1:
1209
		rno &= ~0x03;
1210
		outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
1211
		if(read)
1212
			x = inl(PciDATA);
1213
		else
1214
			outl(PciDATA, data);
1215
		outl(PciADDR, 0);
1216
		break;
1217
 
1218
	case 2:
1219
		outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
1220
		outb(PciFORWARD, BUSBNO(tbdf));
1221
		if(read)
1222
			x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
1223
		else
1224
			outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
1225
		outb(PciCSE, 0);
1226
		break;
1227
	}
1228
	unlock(&pcicfglock);
1229
 
1230
	return x;
1231
}
1232
 
1233
int
1234
pcicfgr32(Pcidev* pcidev, int rno)
1235
{
1236
	return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
1237
}
1238
 
1239
void
1240
pcicfgw32(Pcidev* pcidev, int rno, int data)
1241
{
1242
	pcicfgrw32(pcidev->tbdf, rno, data, 0);
1243
}
1244
 
1245
Pcidev*
1246
pcimatch(Pcidev* prev, int vid, int did)
1247
{
1248
	if(pcicfgmode == -1)
1249
		pcicfginit();
1250
 
1251
	if(prev == nil)
1252
		prev = pcilist;
1253
	else
1254
		prev = prev->list;
1255
 
1256
	while(prev != nil){
1257
		if((vid == 0 || prev->vid == vid)
1258
		&& (did == 0 || prev->did == did))
1259
			break;
1260
		prev = prev->list;
1261
	}
1262
	return prev;
1263
}
1264
 
1265
Pcidev*
1266
pcimatchtbdf(int tbdf)
1267
{
1268
	Pcidev *pcidev;
1269
 
1270
	if(pcicfgmode == -1)
1271
		pcicfginit();
1272
 
1273
	for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
1274
		if(pcidev->tbdf == tbdf)
1275
			break;
1276
	}
1277
	return pcidev;
1278
}
1279
 
1280
uchar
1281
pciipin(Pcidev *pci, uchar pin)
1282
{
1283
	if (pci == nil)
1284
		pci = pcilist;
1285
 
1286
	while (pci) {
1287
		uchar intl;
1288
 
1289
		if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
1290
			return pci->intl;
1291
 
1292
		if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
1293
			return intl;
1294
 
1295
		pci = pci->list;
1296
	}
1297
	return 0;
1298
}
1299
 
1300
static void
1301
pcilhinv(Pcidev* p)
1302
{
1303
	int i;
1304
	Pcidev *t;
1305
 
1306
	if(p == nil) {
1307
		putstrn(PCICONS.output, PCICONS.ptr);
1308
		p = pciroot;
1309
		print("bus dev type vid  did intl memory\n");
1310
	}
1311
	for(t = p; t != nil; t = t->link) {
1312
		print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
1313
			BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
1314
			t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
1315
 
1316
		for(i = 0; i < nelem(p->mem); i++) {
1317
			if(t->mem[i].size == 0)
1318
				continue;
1319
			print("%d:%.8lux %d ", i,
1320
				t->mem[i].bar, t->mem[i].size);
1321
		}
1322
		if(t->ioa.bar || t->ioa.size)
1323
			print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
1324
		if(t->mema.bar || t->mema.size)
1325
			print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
1326
		if(t->bridge)
1327
			print("->%d", BUSBNO(t->bridge->tbdf));
1328
		print("\n");
1329
	}
1330
	while(p != nil) {
1331
		if(p->bridge != nil)
1332
			pcilhinv(p->bridge);
1333
		p = p->link;
1334
	}
1335
}
1336
 
1337
void
1338
pcihinv(Pcidev* p)
1339
{
1340
	if(pcicfgmode == -1)
1341
		pcicfginit();
1342
	lock(&pcicfginitlock);
1343
	pcilhinv(p);
1344
	unlock(&pcicfginitlock);
1345
}
1346
 
1347
void
1348
pcireset(void)
1349
{
1350
	Pcidev *p;
1351
 
1352
	if(pcicfgmode == -1)
1353
		pcicfginit();
1354
 
1355
	for(p = pcilist; p != nil; p = p->list) {
1356
		/* don't mess with the bridges */
1357
		if(p->ccrb == 0x06)
1358
			continue;
1359
		pciclrbme(p);
1360
	}
1361
}
1362
 
1363
void
1364
pcisetioe(Pcidev* p)
1365
{
1366
	p->pcr |= IOen;
1367
	pcicfgw16(p, PciPCR, p->pcr);
1368
}
1369
 
1370
void
1371
pciclrioe(Pcidev* p)
1372
{
1373
	p->pcr &= ~IOen;
1374
	pcicfgw16(p, PciPCR, p->pcr);
1375
}
1376
 
1377
void
1378
pcisetbme(Pcidev* p)
1379
{
1380
	p->pcr |= MASen;
1381
	pcicfgw16(p, PciPCR, p->pcr);
1382
}
1383
 
1384
void
1385
pciclrbme(Pcidev* p)
1386
{
1387
	p->pcr &= ~MASen;
1388
	pcicfgw16(p, PciPCR, p->pcr);
1389
}
1390
 
1391
void
1392
pcisetmwi(Pcidev* p)
1393
{
1394
	p->pcr |= MemWrInv;
1395
	pcicfgw16(p, PciPCR, p->pcr);
1396
}
1397
 
1398
void
1399
pciclrmwi(Pcidev* p)
1400
{
1401
	p->pcr &= ~MemWrInv;
1402
	pcicfgw16(p, PciPCR, p->pcr);
1403
}
1404
 
1405
static int
1406
pcigetpmrb(Pcidev* p)
1407
{
1408
	int ptr;
1409
 
1410
	if(p->pmrb != 0)
1411
		return p->pmrb;
1412
	p->pmrb = -1;
1413
 
1414
	/*
1415
	 * If there are no extended capabilities implemented,
1416
	 * (bit 4 in the status register) assume there's no standard
1417
	 * power management method.
1418
	 * Find the capabilities pointer based on PCI header type.
1419
	 */
1420
	if(!(pcicfgr16(p, PciPSR) & 0x0010))
1421
		return -1;
1422
	switch(pcicfgr8(p, PciHDT)){
1423
	default:
1424
		return -1;
1425
	case 0:					/* all other */
1426
	case 1:					/* PCI to PCI bridge */
1427
		ptr = 0x34;
1428
		break;
1429
	case 2:					/* CardBus bridge */
1430
		ptr = 0x14;
1431
		break;
1432
	}
1433
	ptr = pcicfgr32(p, ptr);
1434
 
1435
	while(ptr != 0){
1436
		/*
1437
		 * Check for validity.
1438
		 * Can't be in standard header and must be double
1439
		 * word aligned.
1440
		 */
1441
		if(ptr < 0x40 || (ptr & ~0xFC))
1442
			return -1;
1443
		if(pcicfgr8(p, ptr) == 0x01){
1444
			p->pmrb = ptr;
1445
			return ptr;
1446
		}
1447
 
1448
		ptr = pcicfgr8(p, ptr+1);
1449
	}
1450
 
1451
	return -1;
1452
}
1453
 
1454
int
1455
pcigetpms(Pcidev* p)
1456
{
1457
	int pmcsr, ptr;
1458
 
1459
	if((ptr = pcigetpmrb(p)) == -1)
1460
		return -1;
1461
 
1462
	/*
1463
	 * Power Management Register Block:
1464
	 *  offset 0:	Capability ID
1465
	 *	   1:	next item pointer
1466
	 *	   2:	capabilities
1467
	 *	   4:	control/status
1468
	 *	   6:	bridge support extensions
1469
	 *	   7:	data
1470
	 */
1471
	pmcsr = pcicfgr16(p, ptr+4);
1472
 
1473
	return pmcsr & 0x0003;
1474
}
1475
 
1476
int
1477
pcisetpms(Pcidev* p, int state)
1478
{
1479
	int ostate, pmc, pmcsr, ptr;
1480
 
1481
	if((ptr = pcigetpmrb(p)) == -1)
1482
		return -1;
1483
 
1484
	pmc = pcicfgr16(p, ptr+2);
1485
	pmcsr = pcicfgr16(p, ptr+4);
1486
	ostate = pmcsr & 0x0003;
1487
	pmcsr &= ~0x0003;
1488
 
1489
	switch(state){
1490
	default:
1491
		return -1;
1492
	case 0:
1493
		break;
1494
	case 1:
1495
		if(!(pmc & 0x0200))
1496
			return -1;
1497
		break;
1498
	case 2:
1499
		if(!(pmc & 0x0400))
1500
			return -1;
1501
		break;
1502
	case 3:
1503
		break;
1504
	}
1505
	pmcsr |= state;
1506
	pcicfgw16(p, ptr+4, pmcsr);
1507
 
1508
	return ostate;
1509
}