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