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