Initial import from FreeBSD RELENG_4:
[games.git] / sys / bus / pci / i386 / 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: src/sys/i386/isa/pci_cfgreg.c,v 1.1.2.7 2001/11/28 05:47:03 imp Exp $
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 <i386/isa/pcibus.h>
45 /* #include <machine/nexusvar.h> */
46 #include <machine/pci_cfgreg.h>
47 #include <machine/segments.h>
48 #include <machine/pc/bios.h>
49
50 #ifdef APIC_IO
51 #include <machine/smp.h>
52 #endif /* APIC_IO */
53
54 static int cfgmech;
55 static int devmax;
56
57 #define PRVERB(a) printf a
58 static int      pci_cfgintr_unique(struct PIR_entry *pe, int pin);
59 static int      pci_cfgintr_linked(struct PIR_entry *pe, int pin);
60 static int      pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
61 static int      pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
62
63 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
64 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
65 static int      pcireg_cfgopen(void);
66
67 static struct PIR_table *pci_route_table;
68 static int              pci_route_count;
69
70 static u_int16_t
71 pcibios_get_version(void)
72 {
73     struct bios_regs args;
74
75     if (PCIbios.entry == 0) {
76         PRVERB(("pcibios: No call entry point\n"));
77         return (0);
78     }
79     args.eax = PCIBIOS_BIOS_PRESENT;
80     if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
81         PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
82         return (0);
83     }
84     if (args.edx != 0x20494350) {
85         PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
86         return (0);
87     }
88     return (args.ebx & 0xffff);
89 }
90
91 /* 
92  * Initialise access to PCI configuration space 
93  */
94 int
95 pci_cfgregopen(void)
96 {
97     static int                  opened = 0;
98     u_long                      sigaddr;
99     static struct PIR_table     *pt;
100     u_int8_t                    ck, *cv;
101     int                         i;
102
103     if (opened)
104         return(1);
105
106     if (pcireg_cfgopen() == 0)
107         return(0);
108
109     /*
110      * Look for the interrupt routing table.
111      */
112     /* We use PCI BIOS's PIR table if it's available */
113     if (pcibios_get_version() >= 0x0210 && pt == NULL && 
114       (sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0) {
115         pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
116         for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) {
117             ck += cv[i];
118         }
119         if (ck == 0) {
120             pci_route_table = pt;
121             pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry);
122             printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table);
123         }
124     }
125
126     opened = 1;
127     return(1);
128 }
129
130 /* 
131  * Read configuration space register
132  */
133 static u_int32_t
134 pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
135 {
136     return(pcireg_cfgread(bus, slot, func, reg, bytes));
137 }
138
139 u_int32_t
140 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
141 {
142 #ifdef APIC_IO
143     /*
144      * If we are using the APIC, the contents of the intline register will probably
145      * be wrong (since they are set up for use with the PIC.
146      * Rather than rewrite these registers (maybe that would be smarter) we trap
147      * attempts to read them and translate to our private vector numbers.
148      */
149     if ((reg == PCIR_INTLINE) && (bytes == 1)) {
150         int     pin, line;
151
152         pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
153         line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
154
155         if (pin != 0) {
156             int airq;
157
158             airq = pci_apic_irq(bus, slot, pin);
159             if (airq >= 0) {
160                 /* PCI specific entry found in MP table */
161                 if (airq != line)
162                     undirect_pci_irq(line);
163                 return(airq);
164             } else {
165                 /* 
166                  * PCI interrupts might be redirected to the
167                  * ISA bus according to some MP tables. Use the
168                  * same methods as used by the ISA devices
169                  * devices to find the proper IOAPIC int pin.
170                  */
171                 airq = isa_apic_irq(line);
172                 if ((airq >= 0) && (airq != line)) {
173                     /* XXX: undirect_pci_irq() ? */
174                     undirect_isa_irq(line);
175                     return(airq);
176                 }
177             }
178         }
179         return(line);
180     }
181 #endif /* APIC_IO */
182     return(pci_do_cfgregread(bus, slot, func, reg, bytes));
183 }
184
185 /* 
186  * Write configuration space register 
187  */
188 void
189 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
190 {
191     return(pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
192 }
193
194 int
195 pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
196 {
197         return(pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes));
198 }
199
200 void
201 pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
202 {
203         pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes);
204 }
205
206
207 /*
208  * Route a PCI interrupt
209  *
210  * XXX we don't do anything "right" with the function number in the PIR table
211  *     (because the consumer isn't currently passing it in).  We don't care
212  *     anyway, due to the way PCI interrupts are assigned.
213  */
214 int
215 pci_cfgintr(int bus, int device, int pin)
216 {
217     struct PIR_entry    *pe;
218     int                 i, irq;
219     struct bios_regs    args;
220     u_int16_t           v;
221     int already = 0;
222     
223     v = pcibios_get_version();
224     if (v < 0x0210) {
225         PRVERB((
226           "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
227           (v & 0xff00) >> 8, v & 0xff));
228         return (255);
229     }
230     if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
231       (pin < 1) || (pin > 4))
232         return(255);
233
234     /*
235      * Scan the entry table for a contender
236      */
237     for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) {
238         if ((bus != pe->pe_bus) || (device != pe->pe_device))
239             continue;
240
241         irq = pci_cfgintr_linked(pe, pin);
242         if (irq != 255)
243              already = 1;
244         if (irq == 255)
245             irq = pci_cfgintr_unique(pe, pin);
246         if (irq == 255)
247             irq = pci_cfgintr_virgin(pe, pin);
248
249         if (irq == 255)
250             break;
251
252         /*
253          * Ask the BIOS to route the interrupt
254          */
255         args.eax = PCIBIOS_ROUTE_INTERRUPT;
256         args.ebx = (bus << 8) | (device << 3);
257         args.ecx = (irq << 8) | (0xa + pin - 1);        /* pin value is 0xa - 0xd */
258         if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) && !already) {
259             /*
260              * XXX if it fails, we should try to smack the router
261              * hardware directly.
262              * XXX Also, there may be other choices that we can try that
263              * will work.
264              */
265             PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
266             return(255);
267         }
268         printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, device, 'A' + pin - 1, irq);
269         return(irq);
270     }
271
272     PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1));
273     return(255);
274 }
275
276 /*
277  * Look to see if the routing table claims this pin is uniquely routed.
278  */
279 static int
280 pci_cfgintr_unique(struct PIR_entry *pe, int pin)
281 {
282     int         irq;
283     
284     if (powerof2(pe->pe_intpin[pin - 1].irqs)) {
285         irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1;
286         PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
287         return(irq);
288     }
289     return(255);
290 }
291
292 /*
293  * Look for another device which shares the same link byte and
294  * already has a unique IRQ, or which has had one routed already.
295  */
296 static int
297 pci_cfgintr_linked(struct PIR_entry *pe, int pin)
298 {
299     struct PIR_entry    *oe;
300     struct PIR_intpin   *pi;
301     int                 i, j, irq;
302
303     /*
304      * Scan table slots.
305      */
306     for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) {
307
308         /* scan interrupt pins */
309         for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
310
311             /* don't look at the entry we're trying to match with */
312             if ((pe == oe) && (i == (pin - 1)))
313                 continue;
314
315             /* compare link bytes */
316             if (pi->link != pe->pe_intpin[pin - 1].link)
317                 continue;
318             
319             /* link destination mapped to a unique interrupt? */
320             if (powerof2(pi->irqs)) {
321                 irq = ffs(pi->irqs) - 1;
322                 PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
323                        pi->link, irq));
324                 return(irq);
325             } 
326
327             /* look for the real PCI device that matches this table entry */
328             if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255)
329                 return(irq);
330         }
331     }
332     return(255);
333 }
334
335 /*
336  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
337  * see if it has already been assigned an interrupt.
338  */
339 static int
340 pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
341 {
342     devclass_t          pci_devclass;
343     device_t            *pci_devices;
344     int                 pci_count;
345     device_t            *pci_children;
346     int                 pci_childcount;
347     device_t            *busp, *childp;
348     int                 i, j, irq;
349
350     /*
351      * Find all the PCI busses.
352      */
353     pci_count = 0;
354     if ((pci_devclass = devclass_find("pci")) != NULL)
355         devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
356
357     /*
358      * Scan all the PCI busses/devices looking for this one.
359      */
360     irq = 255;
361     for (i = 0, busp = pci_devices; (i < pci_count) && (irq == 255); i++, busp++) {
362         pci_childcount = 0;
363         device_get_children(*busp, &pci_children, &pci_childcount);
364                 
365         for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
366             if ((pci_get_bus(*childp) == bus) &&
367                 (pci_get_slot(*childp) == device) &&
368                 (pci_get_intpin(*childp) == matchpin)) {
369                 irq = pci_get_irq(*childp);
370                 /*
371                  * Some BIOS writers seem to want to ignore the spec and put
372                  * 0 in the intline rather than 255 to indicate none.  Once
373                  * we've found one that matches, we break because there can
374                  * be no others (which is why test looks a little odd).
375                  */
376                 if (irq == 0)
377                     irq = 255;
378                 if (irq != 255)
379                     PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
380                       pe->pe_intpin[pin - 1].link, irq,
381                       pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp)));
382                 break;
383             }
384         }
385         if (pci_children != NULL)
386             free(pci_children, M_TEMP);
387     }
388     if (pci_devices != NULL)
389         free(pci_devices, M_TEMP);
390     return(irq);
391 }
392
393 /*
394  * Pick a suitable IRQ from those listed as routable to this device.
395  */
396 static int
397 pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
398 {
399     int         irq, ibit;
400     
401     /* first scan the set of PCI-only interrupts and see if any of these are routable */
402     for (irq = 0; irq < 16; irq++) {
403         ibit = (1 << irq);
404
405         /* can we use this interrupt? */
406         if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
407             (pe->pe_intpin[pin - 1].irqs & ibit)) {
408             PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
409             return(irq);
410         }
411     }
412     
413     /* life is tough, so just pick an interrupt */
414     for (irq = 0; irq < 16; irq++) {
415         ibit = (1 << irq);
416     
417         if (pe->pe_intpin[pin - 1].irqs & ibit) {
418             PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
419             return(irq);
420         }
421     }
422     return(255);
423 }
424
425 /* 
426  * Configuration space access using direct register operations
427  */
428
429 /* enable configuration space accesses and return data port address */
430 static int
431 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
432 {
433     int dataport = 0;
434
435     if (bus <= PCI_BUSMAX
436         && slot < devmax
437         && func <= PCI_FUNCMAX
438         && reg <= PCI_REGMAX
439         && bytes != 3
440         && (unsigned) bytes <= 4
441         && (reg & (bytes -1)) == 0) {
442         switch (cfgmech) {
443         case 1:
444             outl(CONF1_ADDR_PORT, (1 << 31)
445                  | (bus << 16) | (slot << 11) 
446                  | (func << 8) | (reg & ~0x03));
447             dataport = CONF1_DATA_PORT + (reg & 0x03);
448             break;
449         case 2:
450             outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
451             outb(CONF2_FORWARD_PORT, bus);
452             dataport = 0xc000 | (slot << 8) | reg;
453             break;
454         }
455     }
456     return (dataport);
457 }
458
459 /* disable configuration space accesses */
460 static void
461 pci_cfgdisable(void)
462 {
463     switch (cfgmech) {
464     case 1:
465         outl(CONF1_ADDR_PORT, 0);
466         break;
467     case 2:
468         outb(CONF2_ENABLE_PORT, 0);
469         outb(CONF2_FORWARD_PORT, 0);
470         break;
471     }
472 }
473
474 static int
475 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
476 {
477     int data = -1;
478     int port;
479
480     port = pci_cfgenable(bus, slot, func, reg, bytes);
481
482     if (port != 0) {
483         switch (bytes) {
484         case 1:
485             data = inb(port);
486             break;
487         case 2:
488             data = inw(port);
489             break;
490         case 4:
491             data = inl(port);
492             break;
493         }
494         pci_cfgdisable();
495     }
496     return (data);
497 }
498
499 static void
500 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
501 {
502     int port;
503
504     port = pci_cfgenable(bus, slot, func, reg, bytes);
505     if (port != 0) {
506         switch (bytes) {
507         case 1:
508             outb(port, data);
509             break;
510         case 2:
511             outw(port, data);
512             break;
513         case 4:
514             outl(port, data);
515             break;
516         }
517         pci_cfgdisable();
518     }
519 }
520
521 /* check whether the configuration mechanism has been correctly identified */
522 static int
523 pci_cfgcheck(int maxdev)
524 {
525     u_char device;
526
527     if (bootverbose) 
528         printf("pci_cfgcheck:\tdevice ");
529
530     for (device = 0; device < maxdev; device++) {
531         unsigned id, class, header;
532         if (bootverbose) 
533             printf("%d ", device);
534
535         id = inl(pci_cfgenable(0, device, 0, 0, 4));
536         if (id == 0 || id == -1)
537             continue;
538
539         class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
540         if (bootverbose)
541             printf("[class=%06x] ", class);
542         if (class == 0 || (class & 0xf870ff) != 0)
543             continue;
544
545         header = inb(pci_cfgenable(0, device, 0, 14, 1));
546         if (bootverbose) 
547             printf("[hdr=%02x] ", header);
548         if ((header & 0x7e) != 0)
549             continue;
550
551         if (bootverbose)
552             printf("is there (id=%08x)\n", id);
553
554         pci_cfgdisable();
555         return (1);
556     }
557     if (bootverbose) 
558         printf("-- nothing found\n");
559
560     pci_cfgdisable();
561     return (0);
562 }
563
564 static int
565 pcireg_cfgopen(void)
566 {
567     unsigned long mode1res,oldval1;
568     unsigned char mode2res,oldval2;
569
570     oldval1 = inl(CONF1_ADDR_PORT);
571
572     if (bootverbose) {
573         printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
574                oldval1);
575     }
576
577     if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
578
579         cfgmech = 1;
580         devmax = 32;
581
582         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
583         outb(CONF1_ADDR_PORT +3, 0);
584         mode1res = inl(CONF1_ADDR_PORT);
585         outl(CONF1_ADDR_PORT, oldval1);
586
587         if (bootverbose)
588             printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 
589                    mode1res, CONF1_ENABLE_CHK);
590
591         if (mode1res) {
592             if (pci_cfgcheck(32)) 
593                 return (cfgmech);
594         }
595
596         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
597         mode1res = inl(CONF1_ADDR_PORT);
598         outl(CONF1_ADDR_PORT, oldval1);
599
600         if (bootverbose)
601             printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 
602                    mode1res, CONF1_ENABLE_CHK1);
603
604         if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
605             if (pci_cfgcheck(32)) 
606                 return (cfgmech);
607         }
608     }
609
610     oldval2 = inb(CONF2_ENABLE_PORT);
611
612     if (bootverbose) {
613         printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
614                oldval2);
615     }
616
617     if ((oldval2 & 0xf0) == 0) {
618
619         cfgmech = 2;
620         devmax = 16;
621
622         outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
623         mode2res = inb(CONF2_ENABLE_PORT);
624         outb(CONF2_ENABLE_PORT, oldval2);
625
626         if (bootverbose)
627             printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
628                    mode2res, CONF2_ENABLE_CHK);
629
630         if (mode2res == CONF2_ENABLE_RES) {
631             if (bootverbose)
632                 printf("pci_open(2a):\tnow trying mechanism 2\n");
633
634             if (pci_cfgcheck(16)) 
635                 return (cfgmech);
636         }
637     }
638
639     cfgmech = 0;
640     devmax = 0;
641     return (cfgmech);
642 }
643