]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/mtx/pci.c
bcm64: set XN bits for kernel device mappings
[plan9front.git] / sys / src / 9 / mtx / pci.c
1 /*
2  * PCI support code.
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "../port/error.h"
11
12 #define DBG     if(0) pcilog
13
14 struct
15 {
16         char    output[16384];
17         int     ptr;
18 }PCICONS;
19
20 int
21 pcilog(char *fmt, ...)
22 {
23         int n;
24         va_list arg;
25         char buf[PRINTSIZE];
26
27         va_start(arg, fmt);
28         n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
29         va_end(arg);
30
31         memmove(PCICONS.output+PCICONS.ptr, buf, n);
32         PCICONS.ptr += n;
33         return n;
34 }
35
36 enum
37 {                                       /* configuration mechanism #1 */
38         PciADDR         = 0xCF8,        /* CONFIG_ADDRESS */
39         PciDATA         = 0xCFC,        /* CONFIG_DATA */
40
41                                         /* configuration mechanism #2 */
42         PciCSE          = 0xCF8,        /* configuration space enable */
43         PciFORWARD      = 0xCFA,        /* which bus */
44
45         MaxFNO          = 7,
46         MaxUBN          = 255,
47 };
48
49 enum
50 {                                       /* command register */
51         IOen            = (1<<0),
52         MEMen           = (1<<1),
53         MASen           = (1<<2),
54         MemWrInv        = (1<<4),
55         PErrEn          = (1<<6),
56         SErrEn          = (1<<8),
57 };
58
59 static Lock pcicfglock;
60 static QLock pcicfginitlock;
61 static int pcicfgmode = -1;
62 static int pcimaxbno = 7;
63 static int pcimaxdno;
64 static Pcidev* pciroot;
65 static Pcidev* pcilist;
66 static Pcidev* pcitail;
67
68 static int pcicfgrw32(int, int, int, int);
69 static int pcicfgrw8(int, int, int, int);
70
71 static char* bustypes[] = {
72         "CBUSI",
73         "CBUSII",
74         "EISA",
75         "FUTURE",
76         "INTERN",
77         "ISA",
78         "MBI",
79         "MBII",
80         "MCA",
81         "MPI",
82         "MPSA",
83         "NUBUS",
84         "PCI",
85         "PCMCIA",
86         "TC",
87         "VL",
88         "VME",
89         "XPRESS",
90 };
91
92 #pragma varargck        type    "T"     int
93
94 static int
95 tbdffmt(Fmt* fmt)
96 {
97         char *p;
98         int l, r, type, tbdf;
99
100         if((p = malloc(READSTR)) == nil)
101                 return fmtstrcpy(fmt, "(tbdfconv)");
102                 
103         switch(fmt->r){
104         case 'T':
105                 tbdf = va_arg(fmt->args, int);
106                 type = BUSTYPE(tbdf);
107                 if(type < nelem(bustypes))
108                         l = snprint(p, READSTR, bustypes[type]);
109                 else
110                         l = snprint(p, READSTR, "%d", type);
111                 snprint(p+l, READSTR-l, ".%d.%d.%d",
112                         BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));
113                 break;
114
115         default:
116                 snprint(p, READSTR, "(tbdfconv)");
117                 break;
118         }
119         r = fmtstrcpy(fmt, p);
120         free(p);
121
122         return r;
123 }
124
125 ulong
126 pcibarsize(Pcidev *p, int rno)
127 {
128         ulong v, size;
129
130         v = pcicfgrw32(p->tbdf, rno, 0, 1);
131         pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
132         size = pcicfgrw32(p->tbdf, rno, 0, 1);
133         if(v & 1)
134                 size |= 0xFFFF0000;
135         pcicfgrw32(p->tbdf, rno, v, 0);
136
137         return -(size & ~0x0F);
138 }
139
140 static int
141 pcisizcmp(void *a, void *b)
142 {
143         Pcisiz *aa, *bb;
144
145         aa = a;
146         bb = b;
147         return aa->siz - bb->siz;
148 }
149
150 static ulong
151 pcimask(ulong v)
152 {
153         ulong m;
154
155         m = BI2BY*sizeof(v);
156         for(m = 1<<(m-1); m != 0; m >>= 1) {
157                 if(m & v)
158                         break;
159         }
160
161         m--;
162         if((v & m) == 0)
163                 return v;
164
165         v |= m;
166         return v+1;
167 }
168
169 static void
170 pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
171 {
172         Pcidev *p;
173         int ntb, i, size, rno, hole;
174         ulong v, mema, ioa, sioa, smema, base, limit;
175         Pcisiz *table, *tptr, *mtb, *itb;
176         extern void qsort(void*, long, long, int (*)(void*, void*));
177
178         ioa = *pioa;
179         mema = *pmema;
180
181         DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", 
182                 wrreg, root->tbdf, mema, ioa);
183
184         ntb = 0;
185         for(p = root; p != nil; p = p->link)
186                 ntb++;
187
188         ntb *= (PciCIS-PciBAR0)/4;
189         table = malloc(2*ntb*sizeof(Pcisiz));
190         itb = table;
191         mtb = table+ntb;
192
193         /*
194          * Build a table of sizes
195          */
196         for(p = root; p != nil; p = p->link) {
197                 if(p->ccrb == 0x06) {
198                         if(p->ccru == 0x04 && p->bridge != nil) {
199                                 sioa = ioa;
200                                 smema = mema;
201                                 pcibusmap(p->bridge, &smema, &sioa, 0);
202         
203                                 hole = pcimask(smema-mema);
204                                 if(hole < (1<<20))
205                                         hole = 1<<20;
206                                 p->mema.size = hole;
207         
208                                 hole = pcimask(sioa-ioa);
209                                 if(hole < (1<<12))
210                                         hole = 1<<12;
211         
212                                 p->ioa.size = hole;
213         
214                                 itb->dev = p;
215                                 itb->bar = -1;
216                                 itb->siz = p->ioa.size;
217                                 itb++;
218         
219                                 mtb->dev = p;
220                                 mtb->bar = -1;
221                                 mtb->siz = p->mema.size;
222                                 mtb++;
223                         }
224                         if((pcicfgr8(p, PciHDT)&0x7f) != 0)
225                                 continue;
226                 }
227
228                 for(i = 0; i <= 5; i++) {
229                         rno = PciBAR0 + i*4;
230                         v = pcicfgrw32(p->tbdf, rno, 0, 1);
231                         size = pcibarsize(p, rno);
232                         if(size == 0)
233                                 continue;
234
235                         if(v & 1) {
236                                 itb->dev = p;
237                                 itb->bar = i;
238                                 itb->siz = size;
239                                 itb++;
240                         }
241                         else {
242                                 mtb->dev = p;
243                                 mtb->bar = i;
244                                 mtb->siz = size;
245                                 mtb++;
246                         }
247
248                         p->mem[i].size = size;
249                 }
250         }
251
252         /*
253          * Sort both tables IO smallest first, Memory largest
254          */
255         qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp);
256         tptr = table+ntb;
257         qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp);
258
259         /*
260          * Allocate IO address space on this bus
261          */
262         for(tptr = table; tptr < itb; tptr++) {
263                 hole = tptr->siz;
264                 if(tptr->bar == -1)
265                         hole = 1<<12;
266                 ioa = (ioa+hole-1) & ~(hole-1);
267
268                 p = tptr->dev;
269                 if(tptr->bar == -1)
270                         p->ioa.bar = ioa;
271                 else {
272                         p->pcr |= IOen;
273                         p->mem[tptr->bar].bar = ioa|1;
274                         if(wrreg)
275                                 pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0);
276                 }
277
278                 ioa += tptr->siz;
279         }
280
281         /*
282          * Allocate Memory address space on this bus
283          */
284         for(tptr = table+ntb; tptr < mtb; tptr++) {
285                 hole = tptr->siz;
286                 if(tptr->bar == -1)
287                         hole = 1<<20;
288                 mema = (mema+hole-1) & ~(hole-1);
289
290                 p = tptr->dev;
291                 if(tptr->bar == -1)
292                         p->mema.bar = mema;
293                 else {
294                         p->pcr |= MEMen;
295                         p->mem[tptr->bar].bar = mema;
296                         if(wrreg)
297                                 pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0);
298                 }
299                 mema += tptr->siz;
300         }
301
302         *pmema = mema;
303         *pioa = ioa;
304         free(table);
305
306         if(wrreg == 0)
307                 return;
308
309         /*
310          * Finally set all the bridge addresses & registers
311          */
312         for(p = root; p != nil; p = p->link) {
313                 if(p->bridge == nil) {
314                         pcicfgrw8(p->tbdf, PciLTR, 64, 0);
315
316                         p->pcr |= MASen;
317                         pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0);
318                         continue;
319                 }
320
321                 base = p->ioa.bar;
322                 limit = base+p->ioa.size-1;
323                 v = pcicfgrw32(p->tbdf, PciIBR, 0, 1);
324                 v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8);
325                 pcicfgrw32(p->tbdf, PciIBR, v, 0);
326                 v = (limit & 0xFFFF0000)|(base>>16);
327                 pcicfgrw32(p->tbdf, PciIUBR, v, 0);
328
329                 base = p->mema.bar;
330                 limit = base+p->mema.size-1;
331                 v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16);
332                 pcicfgrw32(p->tbdf, PciMBR, v, 0);
333
334                 /*
335                  * Disable memory prefetch
336                  */
337                 pcicfgrw32(p->tbdf, PciPMBR, 0x0000FFFF, 0);
338                 pcicfgrw8(p->tbdf, PciLTR, 64, 0);
339
340                 /*
341                  * Enable the bridge
342                  */
343                 v = 0xFFFF0000 | IOen | MEMen | MASen;
344                 pcicfgrw32(p->tbdf, PciPCR, v, 0);
345
346                 sioa = p->ioa.bar;
347                 smema = p->mema.bar;
348                 pcibusmap(p->bridge, &smema, &sioa, 1);
349         }
350 }
351
352 static int
353 pcilscan(int bno, Pcidev** list)
354 {
355         Pcidev *p, *head, *tail;
356         int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
357
358         maxubn = bno;
359         head = nil;
360         tail = nil;
361         for(dno = 0; dno <= pcimaxdno; dno++){
362                 maxfno = 0;
363                 for(fno = 0; fno <= maxfno; fno++){
364                         /*
365                          * For this possible device, form the
366                          * bus+device+function triplet needed to address it
367                          * and try to read the vendor and device ID.
368                          * If successful, allocate a device struct and
369                          * start to fill it in with some useful information
370                          * from the device's configuration space.
371                          */
372                         tbdf = MKBUS(BusPCI, bno, dno, fno);
373                         l = pcicfgrw32(tbdf, PciVID, 0, 1);
374                         if(l == 0xFFFFFFFF || l == 0)
375                                 continue;
376                         p = malloc(sizeof(*p));
377                         p->tbdf = tbdf;
378                         p->vid = l;
379                         p->did = l>>16;
380
381                         if(pcilist != nil)
382                                 pcitail->list = p;
383                         else
384                                 pcilist = p;
385                         pcitail = p;
386
387                         p->rid = pcicfgr8(p, PciRID);
388                         p->ccrp = pcicfgr8(p, PciCCRp);
389                         p->ccru = pcicfgr8(p, PciCCRu);
390                         p->ccrb = pcicfgr8(p, PciCCRb);
391                         p->pcr = pcicfgr32(p, PciPCR);
392
393                         p->intl = pcicfgr8(p, PciINTL);
394
395                         /*
396                          * If the device is a multi-function device adjust the
397                          * loop count so all possible functions are checked.
398                          */
399                         hdt = pcicfgr8(p, PciHDT);
400                         if(hdt & 0x80)
401                                 maxfno = MaxFNO;
402
403                         /*
404                          * If appropriate, read the base address registers
405                          * and work out the sizes.
406                          */
407                         switch(p->ccrb) {
408                         case 0x01:              /* mass storage controller */
409                         case 0x02:              /* network controller */
410                         case 0x03:              /* display controller */
411                         case 0x04:              /* multimedia device */
412                         case 0x06:              /* bridge device */
413                         case 0x07:              /* simple comm. controllers */
414                         case 0x08:              /* base system peripherals */
415                         case 0x09:              /* input devices */
416                         case 0x0A:              /* docking stations */
417                         case 0x0B:              /* processors */
418                         case 0x0C:              /* serial bus controllers */
419                                 if((hdt & 0x7F) != 0)
420                                         break;
421                                 rno = PciBAR0 - 4;
422                                 for(i = 0; i < nelem(p->mem); i++) {
423                                         rno += 4;
424                                         p->mem[i].bar = pcicfgr32(p, rno);
425                                         p->mem[i].size = pcibarsize(p, rno);
426                                 }
427                                 break;
428
429                         case 0x00:
430                         case 0x05:              /* memory controller */
431                         default:
432                                 break;
433                         }
434
435                         if(head != nil)
436                                 tail->link = p;
437                         else
438                                 head = p;
439                         tail = p;
440                 }
441         }
442
443         *list = head;
444         for(p = head; p != nil; p = p->link){
445                 /*
446                  * Find PCI-PCI bridges and recursively descend the tree.
447                  */
448                 if(p->ccrb != 0x06 || p->ccru != 0x04)
449                         continue;
450
451                 /*
452                  * If the secondary or subordinate bus number is not
453                  * initialised try to do what the PCI BIOS should have
454                  * done and fill in the numbers as the tree is descended.
455                  * On the way down the subordinate bus number is set to
456                  * the maximum as it's not known how many buses are behind
457                  * this one; the final value is set on the way back up.
458                  */
459                 sbn = pcicfgr8(p, PciSBN);
460                 ubn = pcicfgr8(p, PciUBN);
461
462                 if(sbn == 0 || ubn == 0) {
463                         sbn = maxubn+1;
464                         /*
465                          * Make sure memory, I/O and master enables are
466                          * off, set the primary, secondary and subordinate
467                          * bus numbers and clear the secondary status before
468                          * attempting to scan the secondary bus.
469                          *
470                          * Initialisation of the bridge should be done here.
471                          */
472                         pcicfgw32(p, PciPCR, 0xFFFF0000);
473                         l = (MaxUBN<<16)|(sbn<<8)|bno;
474                         pcicfgw32(p, PciPBN, l);
475                         pcicfgw16(p, PciSPSR, 0xFFFF);
476                         maxubn = pcilscan(sbn, &p->bridge);
477                         l = (maxubn<<16)|(sbn<<8)|bno;
478
479                         pcicfgw32(p, PciPBN, l);
480                 }
481                 else {
482                         maxubn = ubn;
483                         pcilscan(sbn, &p->bridge);
484                 }
485         }
486
487         return maxubn;
488 }
489
490 int
491 pciscan(int bno, Pcidev **list)
492 {
493         int ubn;
494
495         qlock(&pcicfginitlock);
496         ubn = pcilscan(bno, list);
497         qunlock(&pcicfginitlock);
498         return ubn;
499 }
500
501 static void
502 pcicfginit(void)
503 {
504         char *p;
505         int bno;
506         Pcidev **list;
507         ulong mema, ioa;
508
509         qlock(&pcicfginitlock);
510         if(pcicfgmode != -1)
511                 goto out;
512
513         /*
514          * Try to determine which PCI configuration mode is implemented.
515          * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
516          * a DWORD at 0xCF8 and another at 0xCFC and will pass through
517          * any non-DWORD accesses as normal I/O cycles. There shouldn't be
518          * a device behind these addresses so if Mode2 accesses fail try
519          * for Mode1 (which is preferred, Mode2 is deprecated).
520          */
521         outb(PciCSE, 0);
522         if(inb(PciCSE) == 0){
523                 pcicfgmode = 2;
524                 pcimaxdno = 15;
525         }
526         else {
527                 outl(PciADDR, 0);
528                 if(inl(PciADDR) == 0){
529                         pcicfgmode = 1;
530                         pcimaxdno = 31;
531                 }
532         }
533         
534         if(pcicfgmode < 0)
535                 goto out;
536
537         fmtinstall('T', tbdffmt);
538
539         if(p = getconf("*pcimaxbno"))
540                 pcimaxbno = strtoul(p, 0, 0);
541         if(p = getconf("*pcimaxdno"))
542                 pcimaxdno = strtoul(p, 0, 0);
543
544         list = &pciroot;
545         for(bno = 0; bno <= pcimaxbno; bno++) {
546                 int sbno = bno;
547                 bno = pcilscan(bno, list);
548
549                 while(*list)
550                         list = &(*list)->link;
551
552                 if (sbno == 0) {
553                         Pcidev *pci;
554
555                         /*
556                           * If we have found a PCI-to-Cardbus bridge, make sure
557                           * it has no valid mappings anymore.  
558                           */
559                         pci = pciroot;
560                         while (pci) {
561                                 if (pci->ccrb == 6 && pci->ccru == 7) {
562                                         ushort bcr;
563
564                                         /* reset the cardbus */
565                                         bcr = pcicfgr16(pci, PciBCR);
566                                         pcicfgw16(pci, PciBCR, 0x40 | bcr);
567                                         delay(50);
568                                 }
569                                 pci = pci->link;
570                         }
571                 }
572         }
573
574         if(pciroot == nil)
575                 goto out;
576
577         /*
578          * Work out how big the top bus is
579          */
580         mema = 0;
581         ioa = 0;
582         pcibusmap(pciroot, &mema, &ioa, 0);
583
584         DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n",
585                 mema, pcimask(mema), ioa);
586
587         /*
588          * Align the windows and map it
589          */
590         ioa = 0x1000;
591         mema = 0;
592
593         pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa);
594
595         pcibusmap(pciroot, &mema, &ioa, 1);
596         DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
597
598 out:
599         qunlock(&pcicfginitlock);
600 }
601
602 static int
603 pcicfgrw8(int tbdf, int rno, int data, int read)
604 {
605         int o, type, x;
606
607         if(pcicfgmode == -1)
608                 pcicfginit();
609
610         if(BUSBNO(tbdf))
611                 type = 0x01;
612         else
613                 type = 0x00;
614         x = -1;
615         if(BUSDNO(tbdf) > pcimaxdno)
616                 return x;
617
618         lock(&pcicfglock);
619         switch(pcicfgmode){
620
621         case 1:
622                 o = rno & 0x03;
623                 rno &= ~0x03;
624                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
625                 if(read)
626                         x = inb(PciDATA+o);
627                 else
628                         outb(PciDATA+o, data);
629                 outl(PciADDR, 0);
630                 break;
631
632         case 2:
633                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
634                 outb(PciFORWARD, BUSBNO(tbdf));
635                 if(read)
636                         x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
637                 else
638                         outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
639                 outb(PciCSE, 0);
640                 break;
641         }
642         unlock(&pcicfglock);
643
644         return x;
645 }
646
647 int
648 pcicfgr8(Pcidev* pcidev, int rno)
649 {
650         return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
651 }
652
653 void
654 pcicfgw8(Pcidev* pcidev, int rno, int data)
655 {
656         pcicfgrw8(pcidev->tbdf, rno, data, 0);
657 }
658
659 static int
660 pcicfgrw16(int tbdf, int rno, int data, int read)
661 {
662         int o, type, x;
663
664         if(pcicfgmode == -1)
665                 pcicfginit();
666
667         if(BUSBNO(tbdf))
668                 type = 0x01;
669         else
670                 type = 0x00;
671         x = -1;
672         if(BUSDNO(tbdf) > pcimaxdno)
673                 return x;
674
675         lock(&pcicfglock);
676         switch(pcicfgmode){
677
678         case 1:
679                 o = rno & 0x02;
680                 rno &= ~0x03;
681                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
682                 if(read)
683                         x = ins(PciDATA+o);
684                 else
685                         outs(PciDATA+o, data);
686                 outl(PciADDR, 0);
687                 break;
688
689         case 2:
690                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
691                 outb(PciFORWARD, BUSBNO(tbdf));
692                 if(read)
693                         x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
694                 else
695                         outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
696                 outb(PciCSE, 0);
697                 break;
698         }
699         unlock(&pcicfglock);
700
701         return x;
702 }
703
704 int
705 pcicfgr16(Pcidev* pcidev, int rno)
706 {
707         return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
708 }
709
710 void
711 pcicfgw16(Pcidev* pcidev, int rno, int data)
712 {
713         pcicfgrw16(pcidev->tbdf, rno, data, 0);
714 }
715
716 static int
717 pcicfgrw32(int tbdf, int rno, int data, int read)
718 {
719         int type, x;
720
721         if(pcicfgmode == -1)
722                 pcicfginit();
723
724         if(BUSBNO(tbdf))
725                 type = 0x01;
726         else
727                 type = 0x00;
728         x = -1;
729         if(BUSDNO(tbdf) > pcimaxdno)
730                 return x;
731
732         lock(&pcicfglock);
733         switch(pcicfgmode){
734
735         case 1:
736                 rno &= ~0x03;
737                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
738                 if(read)
739                         x = inl(PciDATA);
740                 else
741                         outl(PciDATA, data);
742                 outl(PciADDR, 0);
743                 break;
744
745         case 2:
746                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
747                 outb(PciFORWARD, BUSBNO(tbdf));
748                 if(read)
749                         x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
750                 else
751                         outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
752                 outb(PciCSE, 0);
753                 break;
754         }
755         unlock(&pcicfglock);
756
757         return x;
758 }
759
760 int
761 pcicfgr32(Pcidev* pcidev, int rno)
762 {
763         return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
764 }
765
766 void
767 pcicfgw32(Pcidev* pcidev, int rno, int data)
768 {
769         pcicfgrw32(pcidev->tbdf, rno, data, 0);
770 }
771
772 Pcidev*
773 pcimatch(Pcidev* prev, int vid, int did)
774 {
775         if(pcicfgmode == -1)
776                 pcicfginit();
777
778         if(prev == nil)
779                 prev = pcilist;
780         else
781                 prev = prev->list;
782
783         while(prev != nil){
784                 if((vid == 0 || prev->vid == vid)
785                 && (did == 0 || prev->did == did))
786                         break;
787                 prev = prev->list;
788         }
789         return prev;
790 }
791
792 Pcidev*
793 pcimatchtbdf(int tbdf)
794 {
795         Pcidev *pcidev;
796
797         if(pcicfgmode == -1)
798                 pcicfginit();
799
800         for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) {
801                 if(pcidev->tbdf == tbdf)
802                         break;
803         }
804         return pcidev;
805 }
806
807 uchar
808 pciipin(Pcidev *pci, uchar pin)
809 {
810         if (pci == nil)
811                 pci = pcilist;
812
813         while (pci) {
814                 uchar intl;
815
816                 if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
817                         return pci->intl;
818
819                 if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
820                         return intl;
821
822                 pci = pci->list;
823         }
824         return 0;
825 }
826
827 static void
828 pcilhinv(Pcidev* p)
829 {
830         int i;
831         Pcidev *t;
832
833         if(p == nil) {
834                 putstrn(PCICONS.output, PCICONS.ptr);
835                 p = pciroot;
836                 print("bus dev type vid  did intl memory\n");
837         }
838         for(t = p; t != nil; t = t->link) {
839                 print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
840                         BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
841                         t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
842
843                 for(i = 0; i < nelem(p->mem); i++) {
844                         if(t->mem[i].size == 0)
845                                 continue;
846                         print("%d:%.8lux %d ", i,
847                                 t->mem[i].bar, t->mem[i].size);
848                 }
849                 if(t->ioa.bar || t->ioa.size)
850                         print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size);
851                 if(t->mema.bar || t->mema.size)
852                         print("mema:%.8lux %d ", t->mema.bar, t->mema.size);
853                 if(t->bridge)
854                         print("->%d", BUSBNO(t->bridge->tbdf));
855                 print("\n");
856         }
857         while(p != nil) {
858                 if(p->bridge != nil)
859                         pcilhinv(p->bridge);
860                 p = p->link;
861         }       
862 }
863
864 void
865 pcihinv(Pcidev* p)
866 {
867         if(pcicfgmode == -1)
868                 pcicfginit();
869         qlock(&pcicfginitlock);
870         pcilhinv(p);
871         qunlock(&pcicfginitlock);
872 }
873
874 void
875 pcireset(void)
876 {
877         Pcidev *p;
878         int pcr;
879
880         if(pcicfgmode == -1)
881                 pcicfginit();
882
883         for(p = pcilist; p != nil; p = p->list){
884                 pcr = pcicfgr16(p, PciPCR);
885                 pcr &= ~0x0004;
886                 pcicfgw16(p, PciPCR, pcr);
887         }
888 }
889
890 void
891 pcisetbme(Pcidev* p)
892 {
893         int pcr;
894
895         pcr = pcicfgr16(p, PciPCR);
896         pcr |= MASen;
897         pcicfgw16(p, PciPCR, pcr);
898 }
899
900 void
901 pciclrbme(Pcidev* p)
902 {
903         int pcr;
904
905         pcr = pcicfgr16(p, PciPCR);
906         pcr &= ~MASen;
907         pcicfgw16(p, PciPCR, pcr);
908 }