]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/i386/pci/pci_cfgreg.c
This commit was generated by cvs2svn to compensate for changes in r73569,
[FreeBSD/FreeBSD.git] / sys / i386 / pci / pci_cfgreg.c
1 /*
2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
4  * Copyright (c) 2000, BSDi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  *
30  */
31
32 #include <sys/param.h>          /* XXX trim includes */
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/malloc.h>
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40 #include <machine/md_var.h>
41 #include <pci/pcivar.h>
42 #include <pci/pcireg.h>
43 #include <isa/isavar.h>
44 #include <machine/nexusvar.h>
45 #include <machine/pci_cfgreg.h>
46 #include <machine/segments.h>
47 #include <machine/pc/bios.h>
48
49 #ifdef APIC_IO
50 #include <machine/smp.h>
51 #endif /* APIC_IO */
52
53 #include "pcib_if.h"
54
55 static int cfgmech;
56 static int devmax;
57 static int usebios;
58
59 static int      pci_cfgintr_unique(struct PIR_entry *pe, int pin);
60 static int      pci_cfgintr_linked(struct PIR_entry *pe, int pin);
61 static int      pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
62 static int      pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
63
64 static int      pcibios_cfgread(int bus, int slot, int func, int reg, int bytes);
65 static void     pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
66 static int      pcibios_cfgopen(void);
67 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
68 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
69 static int      pcireg_cfgopen(void);
70
71 static struct PIR_table *pci_route_table;
72 static int              pci_route_count;
73
74 /* 
75  * Initialise access to PCI configuration space 
76  */
77 int
78 pci_cfgregopen(void)
79 {
80     static int                  opened = 0;
81     u_long                      sigaddr;
82     static struct PIR_table     *pt;
83     u_int8_t                    ck, *cv;
84     int                         i;
85
86     if (opened)
87         return(1);
88
89     if (pcibios_cfgopen() != 0) {
90         usebios = 1;
91     } else if (pcireg_cfgopen() != 0) {
92         usebios = 0;
93     } else {
94         return(0);
95     }
96
97     /*
98      * Look for the interrupt routing table.
99      */
100     /* XXX use PCI BIOS if it's available */
101
102     if ((pt == NULL) && ((sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0)) {
103         pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
104         for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) {
105             ck += cv[i];
106         }
107         if (ck == 0) {
108             pci_route_table = pt;
109             pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry);
110             printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table);
111         }
112     }
113
114     opened = 1;
115     return(1);
116 }
117
118 /* 
119  * Read configuration space register
120  */
121 static u_int32_t
122 pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
123 {
124     return(usebios ? 
125            pcibios_cfgread(bus, slot, func, reg, bytes) : 
126            pcireg_cfgread(bus, slot, func, reg, bytes));
127 }
128
129 u_int32_t
130 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
131 {
132 #ifdef APIC_IO
133     /*
134      * If we are using the APIC, the contents of the intline register will probably
135      * be wrong (since they are set up for use with the PIC.
136      * Rather than rewrite these registers (maybe that would be smarter) we trap
137      * attempts to read them and translate to our private vector numbers.
138      */
139     if ((reg == PCIR_INTLINE) && (bytes == 1)) {
140         int     pin, line;
141
142         pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
143         line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
144
145         if (pin != 0) {
146             int airq;
147
148             airq = pci_apic_irq(bus, slot, pin);
149             if (airq >= 0) {
150                 /* PCI specific entry found in MP table */
151                 if (airq != line)
152                     undirect_pci_irq(line);
153                 return(airq);
154             } else {
155                 /* 
156                  * PCI interrupts might be redirected to the
157                  * ISA bus according to some MP tables. Use the
158                  * same methods as used by the ISA devices
159                  * devices to find the proper IOAPIC int pin.
160                  */
161                 airq = isa_apic_irq(line);
162                 if ((airq >= 0) && (airq != line)) {
163                     /* XXX: undirect_pci_irq() ? */
164                     undirect_isa_irq(line);
165                     return(airq);
166                 }
167             }
168         }
169         return(line);
170     }
171 #endif /* APIC_IO */
172     return(pci_do_cfgregread(bus, slot, func, reg, bytes));
173 }
174
175 /* 
176  * Write configuration space register 
177  */
178 void
179 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
180 {
181     return(usebios ? 
182            pcibios_cfgwrite(bus, slot, func, reg, data, bytes) : 
183            pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
184 }
185
186 /*
187  * Route a PCI interrupt
188  *
189  * XXX we don't do anything "right" with the function number in the PIR table
190  *     (because the consumer isn't currently passing it in).  We don't care
191  *     anyway, due to the way PCI interrupts are assigned.
192  */
193 int
194 pci_cfgintr(int bus, int device, int pin)
195 {
196     struct PIR_entry    *pe;
197     int                 i, irq;
198     struct bios_regs    args;
199     
200     if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
201       (pin < 1) || (pin > 4))
202         return(255);
203
204     /*
205      * Scan the entry table for a contender
206      */
207     for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) {
208         if ((bus != pe->pe_bus) || (device != pe->pe_device))
209             continue;
210
211         irq = pci_cfgintr_unique(pe, pin);
212         if (irq == 255)
213             irq = pci_cfgintr_linked(pe, pin);
214         if (irq == 255)
215             irq = pci_cfgintr_virgin(pe, pin);
216         
217         if (irq == 255)
218             break;
219             
220             
221         /*
222          * Ask the BIOS to route the interrupt
223          */
224         args.eax = PCIBIOS_ROUTE_INTERRUPT;
225         args.ebx = (bus << 8) | (device << 3);
226         args.ecx = (irq << 8) | (0xa + pin - 1);        /* pin value is 0xa - 0xd */
227         bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
228
229         /*
230          * XXX if it fails, we should try to smack the router hardware directly
231          */
232
233         printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", 
234                bus, device, 'A' + pin - 1, irq);
235         return(irq);
236     }
237
238     printf("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1);
239     return(255);
240 }
241
242 /*
243  * Look to see if the routing table claims this pin is uniquely routed.
244  */
245 static int
246 pci_cfgintr_unique(struct PIR_entry *pe, int pin)
247 {
248     int         irq;
249     
250     if (powerof2(pe->pe_intpin[pin - 1].irqs)) {
251         irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1;
252         printf("pci_cfgintr_unique: hard-routed to irq %d\n", irq);
253         return(irq);
254     }
255     return(255);
256 }
257
258 /*
259  * Look for another device which shares the same link byte and
260  * already has a unique IRQ, or which has had one routed already.
261  */
262 static int
263 pci_cfgintr_linked(struct PIR_entry *pe, int pin)
264 {
265     struct PIR_entry    *oe;
266     struct PIR_intpin   *pi;
267     int                 i, j, irq;
268
269     /*
270      * Scan table slots.
271      */
272     for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) {
273
274         /* scan interrupt pins */
275         for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
276
277             /* don't look at the entry we're trying to match with */
278             if ((pe == oe) && (i == (pin - 1)))
279                 continue;
280
281             /* compare link bytes */
282             if (pi->link != pe->pe_intpin[pin - 1].link)
283                 continue;
284             
285             /* link destination mapped to a unique interrupt? */
286             if (powerof2(pi->irqs)) {
287                 irq = ffs(pi->irqs) - 1;
288                 printf("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
289                        pi->link, irq);
290                 return(irq);
291             } 
292
293             /* look for the real PCI device that matches this table entry */
294             if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255)
295                 return(irq);
296         }
297     }
298     return(255);
299 }
300
301 /*
302  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
303  * see if it has already been assigned an interrupt.
304  */
305 static int
306 pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
307 {
308     devclass_t          pci_devclass;
309     device_t            *pci_devices;
310     int                 pci_count;
311     device_t            *pci_children;
312     int                 pci_childcount;
313     device_t            *busp, *childp;
314     int                 i, j, irq;
315
316     /*
317      * Find all the PCI busses.
318      */
319     pci_count = 0;
320     if ((pci_devclass = devclass_find("pci")) != NULL)
321         devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
322
323     /*
324      * Scan all the PCI busses/devices looking for this one.
325      */
326     irq = 255;
327     for (i = 0, busp = pci_devices; (i < pci_count) && (irq == 255); i++, busp++) {
328         pci_childcount = 0;
329         device_get_children(*busp, &pci_children, &pci_childcount);
330                 
331         for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
332             if ((pci_get_bus(*childp) == bus) &&
333                 (pci_get_slot(*childp) == device) &&
334                 (pci_get_intpin(*childp) == matchpin) &&
335                 ((irq = pci_get_irq(*childp)) != 255)) {
336                 printf("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
337                        irq, pe->pe_intpin[pin - 1].link,
338                        pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp));
339                 break;
340             }
341         }
342         if (pci_children != NULL)
343             free(pci_children, M_TEMP);
344     }
345     if (pci_devices != NULL)
346         free(pci_devices, M_TEMP);
347     return(irq);
348 }
349
350 /*
351  * Pick a suitable IRQ from those listed as routable to this device.
352  */
353 static int
354 pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
355 {
356     int         irq, ibit;
357     
358     /* first scan the set of PCI-only interrupts and see if any of these are routable */
359     for (irq = 0; irq < 16; irq++) {
360         ibit = (1 << irq);
361
362         /* can we use this interrupt? */
363         if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
364             (pe->pe_intpin[pin - 1].irqs & ibit)) {
365             printf("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq);
366             return(irq);
367         }
368     }
369     
370     /* life is tough, so just pick an interrupt */
371     for (irq = 0; irq < 16; irq++) {
372         ibit = (1 << irq);
373     
374         if (pe->pe_intpin[pin - 1].irqs & ibit) {
375             printf("pci_cfgintr_virgin: using routable interrupt %d\n", irq);
376             return(irq);
377         }
378     }
379     return(255);
380 }
381
382
383 /*
384  * Config space access using BIOS functions 
385  */
386 static int
387 pcibios_cfgread(int bus, int slot, int func, int reg, int bytes)
388 {
389     struct bios_regs args;
390     u_int mask;
391
392     switch(bytes) {
393     case 1:
394         args.eax = PCIBIOS_READ_CONFIG_BYTE;
395         mask = 0xff;
396         break;
397     case 2:
398         args.eax = PCIBIOS_READ_CONFIG_WORD;
399         mask = 0xffff;
400         break;
401     case 4:
402         args.eax = PCIBIOS_READ_CONFIG_DWORD;
403         mask = 0xffffffff;
404         break;
405     default:
406         return(-1);
407     }
408     args.ebx = (bus << 8) | (slot << 3) | func;
409     args.edi = reg;
410     bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
411     /* check call results? */
412     return(args.ecx & mask);
413 }
414
415 static void
416 pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
417 {
418     struct bios_regs args;
419
420     switch(bytes) {
421     case 1:
422         args.eax = PCIBIOS_WRITE_CONFIG_BYTE;
423         break;
424     case 2:
425         args.eax = PCIBIOS_WRITE_CONFIG_WORD;
426         break;
427     case 4:
428         args.eax = PCIBIOS_WRITE_CONFIG_DWORD;
429         break;
430     default:
431         return;
432     }
433     args.ebx = (bus << 8) | (slot << 3) | func;
434     args.ecx = data;
435     args.edi = reg;
436     bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
437 }
438
439 /*
440  * Determine whether there is a PCI BIOS present
441  */
442 static int
443 pcibios_cfgopen(void)
444 {
445     /* check for a found entrypoint */
446     return(PCIbios.entry != 0);
447 }
448
449 /* 
450  * Configuration space access using direct register operations
451  */
452
453 /* enable configuration space accesses and return data port address */
454 static int
455 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
456 {
457     int dataport = 0;
458
459     if (bus <= PCI_BUSMAX
460         && slot < devmax
461         && func <= PCI_FUNCMAX
462         && reg <= PCI_REGMAX
463         && bytes != 3
464         && (unsigned) bytes <= 4
465         && (reg & (bytes -1)) == 0) {
466         switch (cfgmech) {
467         case 1:
468             outl(CONF1_ADDR_PORT, (1 << 31)
469                  | (bus << 16) | (slot << 11) 
470                  | (func << 8) | (reg & ~0x03));
471             dataport = CONF1_DATA_PORT + (reg & 0x03);
472             break;
473         case 2:
474             outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
475             outb(CONF2_FORWARD_PORT, bus);
476             dataport = 0xc000 | (slot << 8) | reg;
477             break;
478         }
479     }
480     return (dataport);
481 }
482
483 /* disable configuration space accesses */
484 static void
485 pci_cfgdisable(void)
486 {
487     switch (cfgmech) {
488     case 1:
489         outl(CONF1_ADDR_PORT, 0);
490         break;
491     case 2:
492         outb(CONF2_ENABLE_PORT, 0);
493         outb(CONF2_FORWARD_PORT, 0);
494         break;
495     }
496 }
497
498 static int
499 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
500 {
501     int data = -1;
502     int port;
503
504     port = pci_cfgenable(bus, slot, func, reg, bytes);
505
506     if (port != 0) {
507         switch (bytes) {
508         case 1:
509             data = inb(port);
510             break;
511         case 2:
512             data = inw(port);
513             break;
514         case 4:
515             data = inl(port);
516             break;
517         }
518         pci_cfgdisable();
519     }
520     return (data);
521 }
522
523 static void
524 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
525 {
526     int port;
527
528     port = pci_cfgenable(bus, slot, func, reg, bytes);
529     if (port != 0) {
530         switch (bytes) {
531         case 1:
532             outb(port, data);
533             break;
534         case 2:
535             outw(port, data);
536             break;
537         case 4:
538             outl(port, data);
539             break;
540         }
541         pci_cfgdisable();
542     }
543 }
544
545 /* check whether the configuration mechanism has been correctly identified */
546 static int
547 pci_cfgcheck(int maxdev)
548 {
549     u_char device;
550
551     if (bootverbose) 
552         printf("pci_cfgcheck:\tdevice ");
553
554     for (device = 0; device < maxdev; device++) {
555         unsigned id, class, header;
556         if (bootverbose) 
557             printf("%d ", device);
558
559         id = inl(pci_cfgenable(0, device, 0, 0, 4));
560         if (id == 0 || id == -1)
561             continue;
562
563         class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
564         if (bootverbose)
565             printf("[class=%06x] ", class);
566         if (class == 0 || (class & 0xf870ff) != 0)
567             continue;
568
569         header = inb(pci_cfgenable(0, device, 0, 14, 1));
570         if (bootverbose) 
571             printf("[hdr=%02x] ", header);
572         if ((header & 0x7e) != 0)
573             continue;
574
575         if (bootverbose)
576             printf("is there (id=%08x)\n", id);
577
578         pci_cfgdisable();
579         return (1);
580     }
581     if (bootverbose) 
582         printf("-- nothing found\n");
583
584     pci_cfgdisable();
585     return (0);
586 }
587
588 static int
589 pcireg_cfgopen(void)
590 {
591     unsigned long mode1res,oldval1;
592     unsigned char mode2res,oldval2;
593
594     oldval1 = inl(CONF1_ADDR_PORT);
595
596     if (bootverbose) {
597         printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
598                oldval1);
599     }
600
601     if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
602
603         cfgmech = 1;
604         devmax = 32;
605
606         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
607         outb(CONF1_ADDR_PORT +3, 0);
608         mode1res = inl(CONF1_ADDR_PORT);
609         outl(CONF1_ADDR_PORT, oldval1);
610
611         if (bootverbose)
612             printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 
613                    mode1res, CONF1_ENABLE_CHK);
614
615         if (mode1res) {
616             if (pci_cfgcheck(32)) 
617                 return (cfgmech);
618         }
619
620         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
621         mode1res = inl(CONF1_ADDR_PORT);
622         outl(CONF1_ADDR_PORT, oldval1);
623
624         if (bootverbose)
625             printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 
626                    mode1res, CONF1_ENABLE_CHK1);
627
628         if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
629             if (pci_cfgcheck(32)) 
630                 return (cfgmech);
631         }
632     }
633
634     oldval2 = inb(CONF2_ENABLE_PORT);
635
636     if (bootverbose) {
637         printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
638                oldval2);
639     }
640
641     if ((oldval2 & 0xf0) == 0) {
642
643         cfgmech = 2;
644         devmax = 16;
645
646         outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
647         mode2res = inb(CONF2_ENABLE_PORT);
648         outb(CONF2_ENABLE_PORT, oldval2);
649
650         if (bootverbose)
651             printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
652                    mode2res, CONF2_ENABLE_CHK);
653
654         if (mode2res == CONF2_ENABLE_RES) {
655             if (bootverbose)
656                 printf("pci_open(2a):\tnow trying mechanism 2\n");
657
658             if (pci_cfgcheck(16)) 
659                 return (cfgmech);
660         }
661     }
662
663     cfgmech = 0;
664     devmax = 0;
665     return (cfgmech);
666 }
667