]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/pc/pci.c
perms
[plan9front.git] / sys / src / boot / pc / pci.c
1 /*
2  * PCI support code.
3  * To do:
4  *      initialise bridge mappings if the PCI BIOS didn't.
5  */
6 #include "u.h"
7 #include "lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "error.h"
13
14 enum {                                  /* configuration mechanism #1 */
15         PciADDR         = 0xCF8,        /* CONFIG_ADDRESS */
16         PciDATA         = 0xCFC,        /* CONFIG_DATA */
17
18                                         /* configuration mechanism #2 */
19         PciCSE          = 0xCF8,        /* configuration space enable */
20         PciFORWARD      = 0xCFA,        /* which bus */
21
22         MaxFNO          = 7,
23         MaxUBN          = 255,
24 };
25
26 enum
27 {                                       /* command register */
28         IOen            = (1<<0),
29         MEMen           = (1<<1),
30         MASen           = (1<<2),
31         MemWrInv        = (1<<4),
32         PErrEn          = (1<<6),
33         SErrEn          = (1<<8),
34 };
35
36 static Lock pcicfglock;
37 static Lock pcicfginitlock;
38 static int pcicfgmode = -1;
39 static int pcimaxbno = 7;
40 static int pcimaxdno;
41 static Pcidev* pciroot;
42 static Pcidev* pcilist;
43 static Pcidev* pcitail;
44
45 static int pcicfgrw32(int, int, int, int);
46 static int pcicfgrw8(int, int, int, int);
47
48 ulong
49 pcibarsize(Pcidev *p, int rno)
50 {
51         ulong v, size;
52
53         v = pcicfgrw32(p->tbdf, rno, 0, 1);
54         pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
55         size = pcicfgrw32(p->tbdf, rno, 0, 1);
56         if(v & 1)
57                 size |= 0xFFFF0000;
58         pcicfgrw32(p->tbdf, rno, v, 0);
59
60         return -(size & ~0x0F);
61 }
62
63 /* side effect: if a video controller is seen, set vga non-zero */
64 int
65 pciscan(int bno, Pcidev** list)
66 {
67         Pcidev *p, *head, *tail;
68         int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
69
70         maxubn = bno;
71         head = nil;
72         tail = nil;
73         for(dno = 0; dno <= pcimaxdno; dno++){
74                 maxfno = 0;
75                 for(fno = 0; fno <= maxfno; fno++){
76                         /*
77                          * For this possible device, form the
78                          * bus+device+function triplet needed to address it
79                          * and try to read the vendor and device ID.
80                          * If successful, allocate a device struct and
81                          * start to fill it in with some useful information
82                          * from the device's configuration space.
83                          */
84                         tbdf = MKBUS(BusPCI, bno, dno, fno);
85                         l = pcicfgrw32(tbdf, PciVID, 0, 1);
86                         if(l == 0xFFFFFFFF || l == 0)
87                                 continue;
88                         p = malloc(sizeof(*p));
89                         p->tbdf = tbdf;
90                         p->vid = l;
91                         p->did = l>>16;
92
93                         if(pcilist != nil)
94                                 pcitail->list = p;
95                         else
96                                 pcilist = p;
97                         pcitail = p;
98
99                         p->rid = pcicfgr8(p, PciRID);
100                         p->ccrp = pcicfgr8(p, PciCCRp);
101                         p->ccru = pcicfgr8(p, PciCCRu);
102                         p->ccrb = pcicfgr8(p, PciCCRb);
103                         p->pcr = pcicfgr32(p, PciPCR);
104
105                         p->intl = pcicfgr8(p, PciINTL);
106
107                         /*
108                          * If the device is a multi-function device adjust the
109                          * loop count so all possible functions are checked.
110                          */
111                         hdt = pcicfgr8(p, PciHDT);
112                         if(hdt & 0x80)
113                                 maxfno = MaxFNO;
114
115                         /*
116                          * If appropriate, read the base address registers
117                          * and work out the sizes.
118                          */
119                         switch(p->ccrb){
120
121                         case 0x03:              /* display controller */
122                                 vga = 1;
123                                 /* fall through */
124                         case 0x01:              /* mass storage controller */
125                         case 0x02:              /* network controller */
126                         case 0x04:              /* multimedia device */
127                         case 0x07:              /* simple comm. controllers */
128                         case 0x08:              /* base system peripherals */
129                         case 0x09:              /* input devices */
130                         case 0x0A:              /* docking stations */
131                         case 0x0B:              /* processors */
132                         case 0x0C:              /* serial bus controllers */
133                                 if((hdt & 0x7F) != 0)
134                                         break;
135                                 rno = PciBAR0 - 4;
136                                 for(i = 0; i < nelem(p->mem); i++){
137                                         rno += 4;
138                                         p->mem[i].bar = pcicfgr32(p, rno);
139                                         p->mem[i].size = pcibarsize(p, rno);
140                                 }
141                                 break;
142
143                         case 0x00:
144                         case 0x05:              /* memory controller */
145                         case 0x06:              /* bridge device */
146                         default:
147                                 break;
148                         }
149
150                         if(head != nil)
151                                 tail->link = p;
152                         else
153                                 head = p;
154                         tail = p;
155                 }
156         }
157
158         *list = head;
159         for(p = head; p != nil; p = p->link){
160                 /*
161                  * Find PCI-PCI and PCI-Cardbus bridges
162                  * and recursively descend the tree.
163                  */
164                 if(p->ccrb != 0x06 || p->ccru != 0x04)
165                         continue;
166
167                 /*
168                  * If the secondary or subordinate bus number is not
169                  * initialised try to do what the PCI BIOS should have
170                  * done and fill in the numbers as the tree is descended.
171                  * On the way down the subordinate bus number is set to
172                  * the maximum as it's not known how many buses are behind
173                  * this one; the final value is set on the way back up.
174                  */
175                 ubn = pcicfgr8(p, PciUBN);
176                 sbn = pcicfgr8(p, PciSBN);
177
178                 if(sbn == 0 || ubn == 0){
179                         sbn = maxubn+1;
180                         /*
181                          * Make sure memory, I/O and master enables are
182                          * off, set the primary, secondary and subordinate
183                          * bus numbers and clear the secondary status before
184                          * attempting to scan the secondary bus.
185                          *
186                          * Initialisation of the bridge should be done here.
187                          */
188                         pcicfgw32(p, PciPCR, 0xFFFF0000);
189                         l = (MaxUBN<<16)|(sbn<<8)|bno;
190                         pcicfgw32(p, PciPBN, l);
191                         pcicfgw16(p, PciSPSR, 0xFFFF);
192                         maxubn = pciscan(sbn, &p->bridge);
193                         l = (maxubn<<16)|(sbn<<8)|bno;
194
195                         pcicfgw32(p, PciPBN, l);
196                 }
197                 else{
198                         /*
199                          * You can't go back.
200                          * This shouldn't be possible, but the
201                          * Iwill DK8-HTX seems to have subordinate
202                          * bus numbers which get smaller on the
203                          * way down. Need to look more closely at
204                          * this.
205                          */
206                         if(ubn > maxubn)
207                                 maxubn = ubn;
208                         pciscan(sbn, &p->bridge);
209                 }
210         }
211
212         return maxubn;
213 }
214
215 static uchar
216 null_link(Pcidev *, uchar )
217 {
218         return 0;
219 }
220
221 static void
222 null_init(Pcidev *, uchar , uchar )
223 {
224 }
225
226 static uchar
227 pIIx_link(Pcidev *router, uchar link)
228 {
229         uchar pirq;
230
231         /* link should be 0x60, 0x61, 0x62, 0x63 */
232         pirq = pcicfgr8(router, link);
233         return (pirq < 16)? pirq: 0;
234 }
235
236 static void
237 pIIx_init(Pcidev *router, uchar link, uchar irq)
238 {
239         pcicfgw8(router, link, irq);
240 }
241
242 static uchar
243 via_link(Pcidev *router, uchar link)
244 {
245         uchar pirq;
246
247         /* link should be 1, 2, 3, 5 */
248         pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0;
249
250         return (link & 1)? (pirq >> 4): (pirq & 15);
251 }
252
253 static void
254 via_init(Pcidev *router, uchar link, uchar irq)
255 {
256         uchar pirq;
257
258         pirq = pcicfgr8(router, 0x55 + (link >> 1));
259         pirq &= (link & 1)? 0x0f: 0xf0;
260         pirq |= (link & 1)? (irq << 4): (irq & 15);
261         pcicfgw8(router, 0x55 + (link>>1), pirq);
262 }
263
264 static uchar
265 opti_link(Pcidev *router, uchar link)
266 {
267         uchar pirq = 0;
268
269         /* link should be 0x02, 0x12, 0x22, 0x32 */
270         if ((link & 0xcf) == 0x02)
271                 pirq = pcicfgr8(router, 0xb8 + (link >> 5));
272         return (link & 0x10)? (pirq >> 4): (pirq & 15);
273 }
274
275 static void
276 opti_init(Pcidev *router, uchar link, uchar irq)
277 {
278         uchar pirq;
279
280         pirq = pcicfgr8(router, 0xb8 + (link >> 5));
281         pirq &= (link & 0x10)? 0x0f : 0xf0;
282         pirq |= (link & 0x10)? (irq << 4): (irq & 15);
283         pcicfgw8(router, 0xb8 + (link >> 5), pirq);
284 }
285
286 static uchar
287 ali_link(Pcidev *router, uchar link)
288 {
289         /* No, you're not dreaming */
290         static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
291         uchar pirq;
292
293         /* link should be 0x01..0x08 */
294         pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
295         return (link & 1)? map[pirq&15]: map[pirq>>4];
296 }
297
298 static void
299 ali_init(Pcidev *router, uchar link, uchar irq)
300 {
301         /* Inverse of map in ali_link */
302         static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
303         uchar pirq;
304
305         pirq = pcicfgr8(router, 0x48 + ((link-1)>>1));
306         pirq &= (link & 1)? 0x0f: 0xf0;
307         pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15);
308         pcicfgw8(router, 0x48 + ((link-1)>>1), pirq);
309 }
310
311 static uchar
312 cyrix_link(Pcidev *router, uchar link)
313 {
314         uchar pirq;
315
316         /* link should be 1, 2, 3, 4 */
317         pirq = pcicfgr8(router, 0x5c + ((link-1)>>1));
318         return ((link & 1)? pirq >> 4: pirq & 15);
319 }
320
321 static void
322 cyrix_init(Pcidev *router, uchar link, uchar irq)
323 {
324         uchar pirq;
325
326         pirq = pcicfgr8(router, 0x5c + (link>>1));
327         pirq &= (link & 1)? 0x0f: 0xf0;
328         pirq |= (link & 1)? (irq << 4): (irq & 15);
329         pcicfgw8(router, 0x5c + (link>>1), pirq);
330 }
331
332 typedef struct {
333         ushort  sb_vid, sb_did;
334         uchar   (*sb_translate)(Pcidev *, uchar);
335         void    (*sb_initialize)(Pcidev *, uchar, uchar);
336 } bridge_t;
337
338 static bridge_t southbridges[] = {
339         { 0x8086, 0x122e, pIIx_link, pIIx_init },       // Intel 82371FB
340         { 0x8086, 0x1234, pIIx_link, pIIx_init },       // Intel 82371MX
341         { 0x8086, 0x7000, pIIx_link, pIIx_init },       // Intel 82371SB
342         { 0x8086, 0x7110, pIIx_link, pIIx_init },       // Intel 82371AB
343         { 0x8086, 0x7198, pIIx_link, pIIx_init },       // Intel 82443MX (fn 1)
344         { 0x8086, 0x2410, pIIx_link, pIIx_init },       // Intel 82801AA
345         { 0x8086, 0x2420, pIIx_link, pIIx_init },       // Intel 82801AB
346         { 0x8086, 0x2440, pIIx_link, pIIx_init },       // Intel 82801BA
347         { 0x8086, 0x244c, pIIx_link, pIIx_init },       // Intel 82801BAM
348         { 0x8086, 0x2480, pIIx_link, pIIx_init },       // Intel 82801CA
349         { 0x8086, 0x248c, pIIx_link, pIIx_init },       // Intel 82801CAM
350         { 0x8086, 0x24c0, pIIx_link, pIIx_init },       // Intel 82801DBL
351         { 0x8086, 0x24cc, pIIx_link, pIIx_init },       // Intel 82801DBM
352         { 0x8086, 0x24d0, pIIx_link, pIIx_init },       // Intel 82801EB
353         { 0x8086, 0x25a1, pIIx_link, pIIx_init },       // Intel 6300ESB
354         { 0x8086, 0x2640, pIIx_link, pIIx_init },       // Intel 82801FB
355         { 0x8086, 0x2641, pIIx_link, pIIx_init },       // Intel 82801FBM
356         { 0x8086, 0x27b8, pIIx_link, pIIx_init },       // Intel 82801GB
357         { 0x8086, 0x27b9, pIIx_link, pIIx_init },       // Intel 82801GBM
358         { 0x1106, 0x0586, via_link, via_init },         // Viatech 82C586
359         { 0x1106, 0x0596, via_link, via_init },         // Viatech 82C596
360         { 0x1106, 0x0686, via_link, via_init },         // Viatech 82C686
361         { 0x1106, 0x3227, via_link, via_init },         // Viatech VT8237
362         { 0x1045, 0xc700, opti_link, opti_init },       // Opti 82C700
363         { 0x10b9, 0x1533, ali_link, ali_init },         // Al M1533
364         { 0x1039, 0x0008, pIIx_link, pIIx_init },       // SI 503
365         { 0x1039, 0x0496, pIIx_link, pIIx_init },       // SI 496
366         { 0x1078, 0x0100, cyrix_link, cyrix_init },     // Cyrix 5530 Legacy
367
368         { 0x1002, 0x4377, nil, nil },           // ATI Radeon Xpress 200M
369         { 0x1002, 0x4372, nil, nil },           // ATI SB400
370         { 0x1022, 0x746B, nil, nil },           // AMD 8111
371         { 0x10DE, 0x00D1, nil, nil },           // NVIDIA nForce 3
372         { 0x10DE, 0x00E0, nil, nil },           // NVIDIA nForce 3 250 Series
373         { 0x10DE, 0x00E1, nil, nil },           // NVIDIA nForce 3 250 Series
374         { 0x1166, 0x0200, nil, nil },           // ServerWorks ServerSet III LE
375 };
376
377 typedef struct {
378         uchar   e_bus;                  // Pci bus number
379         uchar   e_dev;                  // Pci device number
380         uchar   e_maps[12];             // Avoid structs!  Link and mask.
381         uchar   e_slot;                 // Add-in/built-in slot
382         uchar   e_reserved;
383 } slot_t;
384
385 typedef struct {
386         uchar   rt_signature[4];        // Routing table signature
387         uchar   rt_version[2];          // Version number
388         uchar   rt_size[2];                     // Total table size
389         uchar   rt_bus;                 // Interrupt router bus number
390         uchar   rt_devfn;                       // Router's devfunc
391         uchar   rt_pciirqs[2];          // Exclusive PCI irqs
392         uchar   rt_compat[4];           // Compatible PCI interrupt router
393         uchar   rt_miniport[4];         // Miniport data
394         uchar   rt_reserved[11];
395         uchar   rt_checksum;
396 } router_t;
397
398 static ushort pciirqs;                  // Exclusive PCI irqs
399 static bridge_t *southbridge;   // Which southbridge to use.
400
401 static void
402 pcirouting(void)
403 {
404         uchar *p, pin, irq;
405         ulong tbdf, vdid;
406         ushort vid, did;
407         router_t *r;
408         slot_t *e;
409         int size, i, fn;
410         Pcidev *sbpci, *pci;
411
412         // Peek in the BIOS
413         for (p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16)
414                 if (p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R')
415                         break;
416
417         if (p >= (uchar *)KADDR(0xfffff))
418                 return;
419
420         r = (router_t *)p;
421
422         // print("PCI interrupt routing table version %d.%d at %.6uX\n",
423         //      r->rt_version[0], r->rt_version[1], (ulong)r & 0xfffff);
424
425         tbdf = (BusPCI << 24)|(r->rt_bus << 16)|(r->rt_devfn << 8);
426         vdid = pcicfgrw32(tbdf, PciVID, 0, 1);
427         vid = vdid;
428         did = vdid >> 16;
429
430         for (i = 0; i != nelem(southbridges); i++)
431                 if (vid == southbridges[i].sb_vid && did == southbridges[i].sb_did)
432                         break;
433
434         if (i == nelem(southbridges)) {
435                 print("pcirouting: South bridge %.4uX, %.4uX not found\n", vid, did);
436                 return;
437         }
438         southbridge = &southbridges[i];
439
440         if ((sbpci = pcimatch(nil, vid, did)) == nil) {
441                 print("pcirouting: Cannot match south bridge %.4uX, %.4uX\n",
442                           vid, did);
443                 return;
444         }
445
446         pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0];
447
448         size = (r->rt_size[1] << 8)|r->rt_size[0];
449         for (e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) {
450                 // print("%.2uX/%.2uX %.2uX: ", e->e_bus, e->e_dev, e->e_slot);
451                 // for (i = 0; i != 4; i++) {
452                 //      uchar *m = &e->e_maps[i * 3];
453                 //      print("[%d] %.2uX %.4uX ",
454                 //              i, m[0], (m[2] << 8)|m[1]);
455                 // }
456                 // print("\n");
457
458                 for (fn = 0; fn != 8; fn++) {
459                         uchar *m;
460
461                         // Retrieve the did and vid through the devfn before
462                         // obtaining the Pcidev structure.
463                         tbdf = (BusPCI << 24)|(e->e_bus << 16)|((e->e_dev | fn) << 8);
464                         vdid = pcicfgrw32(tbdf, PciVID, 0, 1);
465                         if (vdid == 0xFFFFFFFF || vdid == 0)
466                                 continue;
467
468                         vid = vdid;
469                         did = vdid >> 16;
470
471                         pci = nil;
472                         while ((pci = pcimatch(pci, vid, did)) != nil) {
473                                 if (pci->intl != 0 && pci->intl != 0xFF)
474                                         continue;
475
476                                 pin = pcicfgr8(pci, PciINTP);
477                                 if (pin == 0 || pin == 0xff)
478                                         continue;
479
480                                 m = &e->e_maps[(pin - 1) * 3];
481                                 irq = southbridge->sb_translate(sbpci, m[0]);
482                                 if (irq) {
483                                         print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n",
484                                                   vid, did, pin, irq);
485                                         pcicfgw8(pci, PciINTL, irq);
486                                         pci->intl = irq;
487                                 }
488                         }
489                 }
490         }
491 }
492
493 static void
494 pcicfginit(void)
495 {
496         char *p;
497         int bno, n;
498         Pcidev **list;
499
500         lock(&pcicfginitlock);
501         if(pcicfgmode != -1)
502                 goto out;
503
504         /*
505          * Try to determine which PCI configuration mode is implemented.
506          * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses
507          * a DWORD at 0xCF8 and another at 0xCFC and will pass through
508          * any non-DWORD accesses as normal I/O cycles. There shouldn't be
509          * a device behind these addresses so if Mode1 accesses fail try
510          * for Mode2 (Mode2 is deprecated).
511          */
512
513         /*
514          * Bits [30:24] of PciADDR must be 0,
515          * according to the spec.
516          */
517         n = inl(PciADDR);
518         if(!(n & 0x7FF00000)){
519                 outl(PciADDR, 0x80000000);
520                 outb(PciADDR+3, 0);
521                 if(inl(PciADDR) & 0x80000000){
522                         pcicfgmode = 1;
523                         pcimaxdno = 31;
524                 }
525         }
526         outl(PciADDR, n);
527
528         if(pcicfgmode < 0){
529                 /*
530                  * The 'key' part of PciCSE should be 0.
531                  */
532                 n = inb(PciCSE);
533                 if(!(n & 0xF0)){
534                         outb(PciCSE, 0x0E);
535                         if(inb(PciCSE) == 0x0E){
536                                 pcicfgmode = 2;
537                                 pcimaxdno = 15;
538                         }
539                 }
540                 outb(PciCSE, n);
541         }
542
543         if(pcicfgmode < 0)
544                 goto out;
545
546
547         if(p = getconf("*pcimaxbno"))
548                 pcimaxbno = strtoul(p, 0, 0);
549         if(p = getconf("*pcimaxdno"))
550                 pcimaxdno = strtoul(p, 0, 0);
551
552         list = &pciroot;
553         for(bno = 0; bno <= pcimaxbno; bno++) {
554                 bno = pciscan(bno, list);
555                 while(*list)
556                         list = &(*list)->link;
557         }
558
559         pcirouting();
560
561 out:
562         unlock(&pcicfginitlock);
563
564         if(getconf("*pcihinv"))
565                 pcihinv(nil, -1);
566 }
567
568
569 static int
570 pcicfgrw8(int tbdf, int rno, int data, int read)
571 {
572         int o, type, x;
573
574         if(pcicfgmode == -1)
575                 pcicfginit();
576
577         if(BUSBNO(tbdf))
578                 type = 0x01;
579         else
580                 type = 0x00;
581         x = -1;
582         if(BUSDNO(tbdf) > pcimaxdno)
583                 return x;
584
585         lock(&pcicfglock);
586         switch(pcicfgmode){
587
588         case 1:
589                 o = rno & 0x03;
590                 rno &= ~0x03;
591                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
592                 if(read)
593                         x = inb(PciDATA+o);
594                 else
595                         outb(PciDATA+o, data);
596                 outl(PciADDR, 0);
597                 break;
598
599         case 2:
600                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
601                 outb(PciFORWARD, BUSBNO(tbdf));
602                 if(read)
603                         x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno);
604                 else
605                         outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
606                 outb(PciCSE, 0);
607                 break;
608         }
609         unlock(&pcicfglock);
610
611         return x;
612 }
613
614 int
615 pcicfgr8(Pcidev* pcidev, int rno)
616 {
617         return pcicfgrw8(pcidev->tbdf, rno, 0, 1);
618 }
619
620 void
621 pcicfgw8(Pcidev* pcidev, int rno, int data)
622 {
623         pcicfgrw8(pcidev->tbdf, rno, data, 0);
624 }
625
626 static int
627 pcicfgrw16(int tbdf, int rno, int data, int read)
628 {
629         int o, type, x;
630
631         if(pcicfgmode == -1)
632                 pcicfginit();
633
634         if(BUSBNO(tbdf))
635                 type = 0x01;
636         else
637                 type = 0x00;
638         x = -1;
639         if(BUSDNO(tbdf) > pcimaxdno)
640                 return x;
641
642         lock(&pcicfglock);
643         switch(pcicfgmode){
644
645         case 1:
646                 o = rno & 0x02;
647                 rno &= ~0x03;
648                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
649                 if(read)
650                         x = ins(PciDATA+o);
651                 else
652                         outs(PciDATA+o, data);
653                 outl(PciADDR, 0);
654                 break;
655
656         case 2:
657                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
658                 outb(PciFORWARD, BUSBNO(tbdf));
659                 if(read)
660                         x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno);
661                 else
662                         outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
663                 outb(PciCSE, 0);
664                 break;
665         }
666         unlock(&pcicfglock);
667
668         return x;
669 }
670
671 int
672 pcicfgr16(Pcidev* pcidev, int rno)
673 {
674         return pcicfgrw16(pcidev->tbdf, rno, 0, 1);
675 }
676
677 void
678 pcicfgw16(Pcidev* pcidev, int rno, int data)
679 {
680         pcicfgrw16(pcidev->tbdf, rno, data, 0);
681 }
682
683 static int
684 pcicfgrw32(int tbdf, int rno, int data, int read)
685 {
686         int type, x;
687
688         if(pcicfgmode == -1)
689                 pcicfginit();
690
691         if(BUSBNO(tbdf))
692                 type = 0x01;
693         else
694                 type = 0x00;
695         x = -1;
696         if(BUSDNO(tbdf) > pcimaxdno)
697                 return x;
698
699         lock(&pcicfglock);
700         switch(pcicfgmode){
701
702         case 1:
703                 rno &= ~0x03;
704                 outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type);
705                 if(read)
706                         x = inl(PciDATA);
707                 else
708                         outl(PciDATA, data);
709                 outl(PciADDR, 0);
710                 break;
711
712         case 2:
713                 outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1));
714                 outb(PciFORWARD, BUSBNO(tbdf));
715                 if(read)
716                         x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno);
717                 else
718                         outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data);
719                 outb(PciCSE, 0);
720                 break;
721         }
722         unlock(&pcicfglock);
723
724         return x;
725 }
726
727 int
728 pcicfgr32(Pcidev* pcidev, int rno)
729 {
730         return pcicfgrw32(pcidev->tbdf, rno, 0, 1);
731 }
732
733 void
734 pcicfgw32(Pcidev* pcidev, int rno, int data)
735 {
736         pcicfgrw32(pcidev->tbdf, rno, data, 0);
737 }
738
739 Pcidev*
740 pcimatch(Pcidev* prev, int vid, int did)
741 {
742         if(pcicfgmode == -1)
743                 pcicfginit();
744
745         if(prev == nil)
746                 prev = pcilist;
747         else
748                 prev = prev->list;
749
750         while(prev != nil) {
751                 if((vid == 0 || prev->vid == vid)
752                 && (did == 0 || prev->did == did))
753                         break;
754                 prev = prev->list;
755         }
756         return prev;
757 }
758
759 uchar
760 pciipin(Pcidev *pci, uchar pin)
761 {
762         if (pci == nil)
763                 pci = pcilist;
764
765         while (pci) {
766                 uchar intl;
767
768                 if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff)
769                         return pci->intl;
770
771                 if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0)
772                         return intl;
773
774                 pci = pci->list;
775         }
776         return 0;
777 }
778
779 static ushort
780 pciimask(Pcidev *pci)
781 {
782         ushort imask;
783
784         imask = 0;
785         while (pci) {
786                 if (pcicfgr8(pci, PciINTP) && pci->intl < 16)
787                         imask |= 1 << pci->intl;
788
789                 if (pci->bridge)
790                         imask |= pciimask(pci->bridge);
791
792                 pci = pci->list;
793         }
794         return imask;
795 }
796
797 uchar
798 pciintl(Pcidev *pci)
799 {
800         ushort imask;
801         int i;
802
803         if (pci == nil)
804                 pci = pcilist;
805
806         imask = pciimask(pci) | 1;
807         for (i = 0; i != 16; i++)
808                 if ((imask & (1 << i)) == 0)
809                         return i;
810         return 0;
811 }
812
813 void
814 pcihinv(Pcidev* p, int base)
815 {
816         int i;
817         Pcidev *t;
818
819         if(pcicfgmode == -1)
820                 pcicfginit();
821
822         if(p == nil) {
823                 p = pciroot;
824                 print("bus dev type vid  did intl memory\n");
825         }
826         for(t = p; t != nil; t = t->link) {
827                 if (base >= 0 && base != t->ccrb)
828                         continue;
829                 print("%d  %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d  ",
830                         BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
831                         t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl);
832
833                 for(i = 0; i < nelem(p->mem); i++) {
834                         if(t->mem[i].size == 0)
835                                 continue;
836                         print("%d:%.8lux %d ", i,
837                                 t->mem[i].bar, t->mem[i].size);
838                 }
839                 print("\n");
840         }
841         while(p != nil) {
842                 if(p->bridge != nil)
843                         pcihinv(p->bridge, base);
844                 p = p->link;
845         }
846 }
847
848 void
849 pcireset(void)
850 {
851         Pcidev *p;
852         int pcr;
853
854         if(pcicfgmode == -1)
855                 pcicfginit();
856
857         for(p = pcilist; p != nil; p = p->list){
858                 pcr = pcicfgr16(p, PciPSR);
859                 pcicfgw16(p, PciPSR, pcr & ~0x04);
860         }
861 }
862
863 void
864 pcisetioe(Pcidev* p)
865 {
866         p->pcr |= IOen;
867         pcicfgw16(p, PciPCR, p->pcr);
868 }
869
870 void
871 pciclrioe(Pcidev* p)
872 {
873         p->pcr &= ~IOen;
874         pcicfgw16(p, PciPCR, p->pcr);
875 }
876
877 void
878 pcisetbme(Pcidev* p)
879 {
880         p->pcr |= MASen;
881         pcicfgw16(p, PciPCR, p->pcr);
882 }
883
884 void
885 pciclrbme(Pcidev* p)
886 {
887         p->pcr &= ~MASen;
888         pcicfgw16(p, PciPCR, p->pcr);
889 }
890
891 void
892 pcisetmwi(Pcidev* p)
893 {
894         p->pcr |= MemWrInv;
895         pcicfgw16(p, PciPCR, p->pcr);
896 }
897
898 void
899 pciclrmwi(Pcidev* p)
900 {
901         p->pcr &= ~MemWrInv;
902         pcicfgw16(p, PciPCR, p->pcr);
903 }
904
905 static int
906 pcigetpmrb(Pcidev* p)
907 {
908         int ptr;
909
910         if(p->pmrb != 0)
911                 return p->pmrb;
912         p->pmrb = -1;
913
914         /*
915          * If there are no extended capabilities implemented,
916          * (bit 4 in the status register) assume there's no standard
917          * power management method.
918          * Find the capabilities pointer based on PCI header type.
919          */
920         if(!(pcicfgr16(p, PciPSR) & 0x0010))
921                 return -1;
922         switch(pcicfgr8(p, PciHDT)){
923         default:
924                 return -1;
925         case 0:                                 /* all other */
926         case 1:                                 /* PCI to PCI bridge */
927                 ptr = 0x34;
928                 break;
929         case 2:                                 /* CardBus bridge */
930                 ptr = 0x14;
931                 break;
932         }
933         ptr = pcicfgr32(p, ptr);
934
935         while(ptr != 0){
936                 /*
937                  * Check for validity.
938                  * Can't be in standard header and must be double
939                  * word aligned.
940                  */
941                 if(ptr < 0x40 || (ptr & ~0xFC))
942                         return -1;
943                 if(pcicfgr8(p, ptr) == 0x01){
944                         p->pmrb = ptr;
945                         return ptr;
946                 }
947
948                 ptr = pcicfgr8(p, ptr+1);
949         }
950
951         return -1;
952 }
953
954 int
955 pcigetpms(Pcidev* p)
956 {
957         int pmcsr, ptr;
958
959         if((ptr = pcigetpmrb(p)) == -1)
960                 return -1;
961
962         /*
963          * Power Management Register Block:
964          *  offset 0:   Capability ID
965          *         1:   next item pointer
966          *         2:   capabilities
967          *         4:   control/status
968          *         6:   bridge support extensions
969          *         7:   data
970          */
971         pmcsr = pcicfgr16(p, ptr+4);
972
973         return pmcsr & 0x0003;
974 }
975
976 int
977 pcisetpms(Pcidev* p, int state)
978 {
979         int ostate, pmc, pmcsr, ptr;
980
981         if((ptr = pcigetpmrb(p)) == -1)
982                 return -1;
983
984         pmc = pcicfgr16(p, ptr+2);
985         pmcsr = pcicfgr16(p, ptr+4);
986         ostate = pmcsr & 0x0003;
987         pmcsr &= ~0x0003;
988
989         switch(state){
990         default:
991                 return -1;
992         case 0:
993                 break;
994         case 1:
995                 if(!(pmc & 0x0200))
996                         return -1;
997                 break;
998         case 2:
999                 if(!(pmc & 0x0400))
1000                         return -1;
1001                 break;
1002         case 3:
1003                 break;
1004         }
1005         pmcsr |= state;
1006         pcicfgw16(p, ptr+4, pmcsr);
1007
1008         return ostate;
1009 }