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