Remove my local patch again, it was still not meant to be commited.
[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.9 2004/12/22 11:03:27 joerg 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 <sys/sysctl.h>
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42 #include <machine/md_var.h>
43 #include <machine/clock.h>
44 #include <bus/pci/pcivar.h>
45 #include <bus/pci/pcireg.h>
46 #include <bus/isa/isavar.h>
47 #include <bus/pci/i386/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 #define PRVERB(a) do {                                                  \
56         if (bootverbose)                                                \
57                 printf a ;                                              \
58 } while(0)
59
60 static int pci_disable_bios_route = 0;
61 SYSCTL_INT(_hw, OID_AUTO, pci_disable_bios_route, CTLFLAG_RD,
62         &pci_disable_bios_route, 0, "disable interrupt routing via PCI-BIOS");
63 TUNABLE_INT("hw.pci_disable_bios_route", &pci_disable_bios_route);
64
65 static int cfgmech;
66 static int devmax;
67
68 static int      pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq);
69 static int      pci_cfgintr_unique(struct PIR_entry *pe, int pin);
70 static int      pci_cfgintr_linked(struct PIR_entry *pe, int pin);
71 static int      pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
72 static int      pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
73
74 static void     pci_print_irqmask(u_int16_t irqs);
75 static void     pci_print_route_table(struct PIR_table *prt, int size);
76 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
77 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
78 static int      pcireg_cfgopen(void);
79
80 static struct PIR_table *pci_route_table;
81 static int              pci_route_count;
82
83 /*
84  * Some BIOS writers seem to want to ignore the spec and put
85  * 0 in the intline rather than 255 to indicate none. Some use
86  * numbers in the range 128-254 to indicate something strange and
87  * apparently undocumented anywhere. Assume these are completely bogus
88  * and map them to 255, which means "none".
89  */
90 static int
91 pci_i386_map_intline(int line)
92 {
93         if (line == 0 || line >= 128)
94                 return (PCI_INVALID_IRQ);
95         return (line);
96 }
97
98 static u_int16_t
99 pcibios_get_version(void)
100 {
101         struct bios_regs args;
102
103         if (PCIbios.ventry == 0) {
104                 PRVERB(("pcibios: No call entry point\n"));
105                 return (0);
106         }
107         args.eax = PCIBIOS_BIOS_PRESENT;
108         if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
109                 PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
110                 return (0);
111         }
112         if (args.edx != 0x20494350) {
113                 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
114                 return (0);
115         }
116         return (args.ebx & 0xffff);
117 }
118
119 /* 
120  * Initialise access to PCI configuration space 
121  */
122 int
123 pci_cfgregopen(void)
124 {
125         static int              opened = 0;
126         u_long                  sigaddr;
127         static struct PIR_table *pt;
128         u_int16_t               v;
129         u_int8_t                ck, *cv;
130         int                     i;
131
132         if (opened)
133                 return (1);
134
135         if (pcireg_cfgopen() == 0)
136                 return (0);
137
138         v = pcibios_get_version();
139         if (v > 0)
140                 printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
141                        v & 0xff);
142
143         /*
144          * Look for the interrupt routing table.
145          *
146          * We use PCI BIOS's PIR table if it's available $PIR is the
147          * standard way to do this.  Sadly some machines are not
148          * standards conforming and have _PIR instead. We shrug and cope
149          * by looking for both.
150          */
151         if (pcibios_get_version() >= 0x0210 && pt == NULL) {
152                 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
153                 if (sigaddr == 0)
154                         sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
155                 if (sigaddr != 0) {
156                         pt = (struct PIR_table *)(uintptr_t)
157                              BIOS_PADDRTOVADDR(sigaddr);
158                         for (cv = (u_int8_t *)pt, ck = 0, i = 0;
159                              i < (pt->pt_header.ph_length); i++)
160                                 ck += cv[i];
161                         if (ck == 0 && pt->pt_header.ph_length >
162                             sizeof(struct PIR_header)) {
163                                 pci_route_table = pt;
164                                 pci_route_count = (pt->pt_header.ph_length -
165                                     sizeof(struct PIR_header)) /
166                                     sizeof(struct PIR_entry);
167                                 printf("Using $PIR table, %d entries at %p\n",
168                                        pci_route_count, pci_route_table);
169                                 if (bootverbose)
170                                         pci_print_route_table(pci_route_table,
171                                             pci_route_count);
172                         }
173                 }
174         }
175         opened = 1;
176         return (1);     
177 }
178
179 /* 
180  * Read configuration space register
181  */
182 u_int32_t
183 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
184 {
185         uint32_t line;
186 #ifdef APIC_IO
187         uint32_t pin;
188
189         /*
190          * If we are using the APIC, the contents of the intline
191          * register will probably be wrong (since they are set up for
192          * use with the PIC.  Rather than rewrite these registers
193          * (maybe that would be smarter) we trap attempts to read them
194          * and translate to our private vector numbers.
195          */
196         if ((reg == PCIR_INTLINE) && (bytes == 1)) {
197
198                 pin = pcireg_cfgread(bus, slot, func, PCIR_INTPIN, 1);
199                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
200
201                 if (pin != 0) {
202                         int airq;
203
204                         airq = pci_apic_irq(bus, slot, pin);
205                         if (airq >= 0) {
206                                 /* PCI specific entry found in MP table */
207                                 if (airq != line)
208                                         undirect_pci_irq(line);
209                                 return (airq);
210                         } else {
211                                 /* 
212                                  * PCI interrupts might be redirected to the
213                                  * ISA bus according to some MP tables. Use the
214                                  * same methods as used by the ISA devices
215                                  * devices to find the proper IOAPIC int pin.
216                                  */
217                                 airq = isa_apic_irq(line);
218                                 if ((airq >= 0) && (airq != line)) {
219                                         /* XXX: undirect_pci_irq() ? */
220                                         undirect_isa_irq(line);
221                                         return (airq);
222                                 }
223                         }
224                 }
225                 return (line);
226         }
227 #else
228         /*
229          * Some BIOS writers seem to want to ignore the spec and put
230          * 0 in the intline rather than 255 to indicate none.  The rest of
231          * the code uses 255 as an invalid IRQ.
232          */
233         if (reg == PCIR_INTLINE && bytes == 1) {
234                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
235                 return pci_i386_map_intline(line);
236         }
237 #endif /* APIC_IO */
238         return (pcireg_cfgread(bus, slot, func, reg, bytes));
239 }
240
241 /* 
242  * Write configuration space register 
243  */
244 void
245 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
246 {
247         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
248 }
249
250 int
251 pci_cfgread(pcicfgregs *cfg, int reg, int bytes)
252 {
253         return (pci_cfgregread(cfg->bus, cfg->slot, cfg->func, reg, bytes));
254 }
255
256 void
257 pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes)
258 {
259         pci_cfgregwrite(cfg->bus, cfg->slot, cfg->func, reg, data, bytes);
260 }
261
262
263 /*
264  * Route a PCI interrupt
265  */
266 int
267 pci_cfgintr(int bus, int device, int pin, int oldirq)
268 {
269         struct PIR_entry        *pe;
270         int                     i, irq;
271         struct bios_regs        args;
272         u_int16_t               v;
273
274         int already = 0;
275         int errok = 0;
276     
277         v = pcibios_get_version();
278         if (v < 0x0210) {
279                 PRVERB((
280                   "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
281                   (v & 0xff00) >> 8, v & 0xff));
282                 return (PCI_INVALID_IRQ);
283         }
284         if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
285             (pin < 1) || (pin > 4))
286                 return (PCI_INVALID_IRQ);
287
288         /*
289          * Scan the entry table for a contender
290          */
291         for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
292              i++, pe++) {
293                 if ((bus != pe->pe_bus) || (device != pe->pe_device))
294                         continue;
295
296                 /*
297                  * A link of 0 means that this intpin is not connected to
298                  * any other device's interrupt pins and is not connected to
299                  * any of the Interrupt Router's interrupt pins, so we can't
300                  * route it.
301                  */
302                 if (pe->pe_intpin[pin - 1].link == 0)
303                         continue;
304
305                 if (pci_cfgintr_valid(pe, pin, oldirq)) {
306                         printf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus,
307                                device, 'A' + pin - 1, oldirq);
308                         return (oldirq);
309                 }
310
311                 /*
312                  * We try to find a linked interrupt, then we look to see
313                  * if the interrupt is uniquely routed, then we look for
314                  * a virgin interrupt. The virgin interrupt should return
315                  * an interrupt we can route, but if that fails, maybe we
316                  * should try harder to route a different interrupt.
317                  * However, experience has shown that that's rarely the
318                  * failure mode we see.
319                  */
320                 irq = pci_cfgintr_linked(pe, pin);
321                 if (irq != PCI_INVALID_IRQ)
322                         already = 1;
323                 if (irq == PCI_INVALID_IRQ) {
324                         irq = pci_cfgintr_unique(pe, pin);
325                         if (irq != PCI_INVALID_IRQ)
326                                 errok = 1;
327                 }
328                 if (irq == PCI_INVALID_IRQ)
329                         irq = pci_cfgintr_virgin(pe, pin);
330
331                 if (irq == PCI_INVALID_IRQ)
332                         break;
333
334                 if (pci_disable_bios_route != 0)
335                         break;
336                 /*
337                  * Ask the BIOS to route the interrupt. If we picked an
338                  * interrupt that failed, we should really try other
339                  * choices that the BIOS offers us.
340                  *
341                  * For uniquely routed interrupts, we need to try
342                  * to route them on some machines. Yet other machines
343                  * fail to route, so we have to pretend that in that
344                  * case it worked.  Isn't PC hardware fun?
345                  *
346                  * NOTE: if we want to whack hardware to do this, then
347                  * I think the right way to do that would be to have
348                  * bridge drivers that do this. I'm not sure that the
349                  * $PIR table would be valid for those interrupt
350                  * routers.
351                  */
352                 args.eax = PCIBIOS_ROUTE_INTERRUPT;
353                 args.ebx = (bus << 8) | (device << 3);
354                 /* pin value is 0xa - 0xd */
355                 args.ecx = (irq << 8) | (0xa + pin -1);
356                 if (!already &&
357                     bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) &&
358                     !errok) {
359                         PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
360                         return (PCI_INVALID_IRQ);
361                 }
362                 printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
363                        device, 'A' + pin - 1, irq);
364                 return(irq);
365         }
366
367         PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus,
368                device, 'A' + pin - 1));
369         return (PCI_INVALID_IRQ);
370 }
371
372 /*
373  * Check to see if an existing IRQ setting is valid.
374  */
375 static int
376 pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq)
377 {
378         uint32_t irqmask;
379
380         if (!PCI_INTERRUPT_VALID(irq))
381                 return (0);
382         irqmask = pe->pe_intpin[pin - 1].irqs;
383         if (irqmask & (1 << irq)) {
384                 PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq));
385                 return (1);
386         }
387         return (0);
388 }
389
390 /*
391  * Look to see if the routing table claims this pin is uniquely routed.
392  */
393 static int
394 pci_cfgintr_unique(struct PIR_entry *pe, int pin)
395 {
396         int             irq;
397         uint32_t        irqmask;
398
399         irqmask = pe->pe_intpin[pin - 1].irqs;
400         if(irqmask != 0 && powerof2(irqmask)) {
401                 irq = ffs(irqmask) - 1;
402                 PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
403                 return (irq);
404         }
405         return (PCI_INVALID_IRQ);
406 }
407
408 /*
409  * Look for another device which shares the same link byte and
410  * already has a unique IRQ, or which has had one routed already.
411  */
412 static int
413 pci_cfgintr_linked(struct PIR_entry *pe, int pin)
414 {
415         struct PIR_entry        *oe;
416         struct PIR_intpin       *pi;
417         int                     i, j, irq;
418
419         /*
420          * Scan table slots.
421          */
422         for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
423              i++, oe++) {
424                 /* scan interrupt pins */
425                 for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
426
427                         /* don't look at the entry we're trying to match */
428                         if ((pe == oe) && (i == (pin - 1)))
429                                 continue;
430                         /* compare link bytes */
431                         if (pi->link != pe->pe_intpin[pin - 1].link)
432                                 continue;
433                         /* link destination mapped to a unique interrupt? */
434                         if (pi->irqs != 0 && powerof2(pi->irqs)) {
435                                 irq = ffs(pi->irqs) - 1;
436                                 PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
437                                        pi->link, irq));
438                                 return(irq);
439                         } 
440
441                         /*
442                          * look for the real PCI device that matches this
443                          * table entry
444                          */
445                         irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
446                                                  j, pin);
447                         if (irq != PCI_INVALID_IRQ)
448                                 return (irq);
449                 }
450         }
451         return (PCI_INVALID_IRQ);
452 }
453
454 /*
455  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
456  * see if it has already been assigned an interrupt.
457  */
458 static int
459 pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
460 {
461         devclass_t              pci_devclass;
462         device_t                *pci_devices;
463         int                     pci_count;
464         device_t                *pci_children;
465         int                     pci_childcount;
466         device_t                *busp, *childp;
467         int                     i, j, irq;
468
469         /*
470          * Find all the PCI busses.
471          */
472         pci_count = 0;
473         if ((pci_devclass = devclass_find("pci")) != NULL)
474                 devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
475
476         /*
477          * Scan all the PCI busses/devices looking for this one.
478          */
479         irq = PCI_INVALID_IRQ;
480         for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
481              i++, busp++) {
482                 pci_childcount = 0;
483                 device_get_children(*busp, &pci_children, &pci_childcount);
484                 
485                 for (j = 0, childp = pci_children; j < pci_childcount; j++,
486                      childp++) {
487                         if ((pci_get_bus(*childp) == bus) &&
488                             (pci_get_slot(*childp) == device) &&
489                             (pci_get_intpin(*childp) == matchpin)) {
490                                 irq = pci_i386_map_intline(pci_get_irq(*childp));
491                                 if (irq != PCI_INVALID_IRQ)
492                                         PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
493                                             pe->pe_intpin[pin - 1].link, irq,
494                                             pci_get_bus(*childp),
495                                             pci_get_slot(*childp),
496                                             pci_get_function(*childp)));
497                                 break;
498                         }
499                 }
500                 if (pci_children != NULL)
501                         free(pci_children, M_TEMP);
502         }
503         if (pci_devices != NULL)
504                 free(pci_devices, M_TEMP);
505         return (irq);
506 }
507
508 /*
509  * Pick a suitable IRQ from those listed as routable to this device.
510  */
511 static int
512 pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
513 {
514         int irq, ibit;
515     
516         /*
517          * first scan the set of PCI-only interrupts and see if any of these
518          * are routable
519          */
520         for (irq = 0; irq < 16; irq++) {
521                 ibit = (1 << irq);
522
523                 /* can we use this interrupt? */
524                 if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
525                     (pe->pe_intpin[pin - 1].irqs & ibit)) {
526                         PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
527                         return (irq);
528                 }
529         }
530     
531         /* life is tough, so just pick an interrupt */
532         for (irq = 0; irq < 16; irq++) {
533                 ibit = (1 << irq);
534     
535                 if (pe->pe_intpin[pin - 1].irqs & ibit) {
536                         PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
537                         return (irq);
538                 }
539         }
540         return (PCI_INVALID_IRQ);
541 }
542
543 static void
544 pci_print_irqmask(u_int16_t irqs)
545 {
546         int i, first;
547
548         if (irqs == 0) {
549                 printf("none");
550                 return;
551         }
552         first = 1;
553         for (i = 0; i < 16; i++, irqs >>= 1)
554                 if (irqs & 1) {
555                         if (!first)
556                                 printf(" ");
557                         else
558                                 first = 0;
559                         printf("%d", i);
560                 }
561 }
562
563 /*
564  * Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
565  */
566 static void
567 pci_print_route_table(struct PIR_table *ptr, int size)
568 {
569         struct PIR_entry *entry;
570         struct PIR_intpin *intpin;
571         int i, pin;
572
573         printf("PCI-Only Interrupts: ");
574         pci_print_irqmask(ptr->pt_header.ph_pci_irqs);
575         printf("\nLocation  Bus Device Pin  Link  IRQs\n");
576         entry = &ptr->pt_entry[0];
577         for (i = 0; i < size; i++, entry++) {
578                 intpin = &entry->pe_intpin[0];
579                 for (pin = 0; pin < 4; pin++, intpin++)
580                         if (intpin->link != 0) {
581                                 if (entry->pe_slot == 0)
582                                         printf("embedded ");
583                                 else
584                                         printf("slot %-3d ", entry->pe_slot);
585                                 printf(" %3d  %3d    %c   0x%02x  ",
586                                        entry->pe_bus, entry->pe_device,
587                                        'A' + pin, intpin->link);
588                                 pci_print_irqmask(intpin->irqs);
589                                 printf("\n");
590                         }
591         }
592 }
593
594 /*
595  * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
596  * even bother looking if the BIOS doesn't support routing anyways.
597  */
598 int
599 pci_probe_route_table(int bus)
600 {
601         int i;
602         u_int16_t v;
603
604         v = pcibios_get_version();
605         if (v < 0x0210)
606                 return (0);
607         for (i = 0; i < pci_route_count; i++)
608                 if (pci_route_table->pt_entry[i].pe_bus == bus)
609                         return (1);
610         return (0);
611 }
612
613 /* 
614  * Configuration space access using direct register operations
615  */
616
617 /* enable configuration space accesses and return data port address */
618 static int
619 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
620 {
621         int dataport = 0;
622
623         if (bus <= PCI_BUSMAX
624             && slot < devmax
625             && func <= PCI_FUNCMAX
626             && reg <= PCI_REGMAX
627             && bytes != 3
628             && (unsigned) bytes <= 4
629             && (reg & (bytes - 1)) == 0) {
630                 switch (cfgmech) {
631                 case 1:
632                         outl(CONF1_ADDR_PORT, (1 << 31)
633                              | (bus << 16) | (slot << 11) 
634                              | (func << 8) | (reg & ~0x03));
635                         dataport = CONF1_DATA_PORT + (reg & 0x03);
636                         break;
637                 case 2:
638                         outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
639                         outb(CONF2_FORWARD_PORT, bus);
640                         dataport = 0xc000 | (slot << 8) | reg;
641                         break;
642                 }
643         }
644         return (dataport);
645 }
646
647 /* disable configuration space accesses */
648 static void
649 pci_cfgdisable(void)
650 {
651         switch (cfgmech) {
652         case 1:
653                 outl(CONF1_ADDR_PORT, 0);
654                 break;
655         case 2:
656                 outb(CONF2_ENABLE_PORT, 0);
657                 outb(CONF2_FORWARD_PORT, 0);
658                 break;
659         }
660 }
661
662 static int
663 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
664 {
665         int data = -1;
666         int port;
667
668         port = pci_cfgenable(bus, slot, func, reg, bytes);
669         if (port != 0) {
670                 switch (bytes) {
671                 case 1:
672                         data = inb(port);
673                         break;
674                 case 2:
675                         data = inw(port);
676                         break;
677                 case 4:
678                         data = inl(port);
679                         break;
680                 }
681                 pci_cfgdisable();
682         }
683         return (data);
684 }
685
686 static void
687 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
688 {
689         int port;
690
691         port = pci_cfgenable(bus, slot, func, reg, bytes);
692         if (port != 0) {
693                 switch (bytes) {
694                 case 1:
695                         outb(port, data);
696                         break;
697                 case 2:
698                         outw(port, data);
699                         break;
700                 case 4:
701                         outl(port, data);
702                         break;
703                 }
704                 pci_cfgdisable();
705         }
706 }
707
708 /* check whether the configuration mechanism has been correctly identified */
709 static int
710 pci_cfgcheck(int maxdev)
711 {
712         uint32_t id, class;
713         uint8_t header;
714         uint8_t device;
715         int port;
716
717         if (bootverbose) 
718                 printf("pci_cfgcheck:\tdevice ");
719
720         for (device = 0; device < maxdev; device++) {
721                 if (bootverbose) 
722                         printf("%d ", device);
723
724                 port = pci_cfgenable(0, device, 0, 0, 4);
725                 id = inl(port);
726                 if (id == 0 || id == 0xffffffff)
727                         continue;
728
729                 port = pci_cfgenable(0, device, 0, 8, 4);
730                 class = inl(port) >> 8;
731                 if (bootverbose)
732                         printf("[class=%06x] ", class);
733                 if (class == 0 || (class & 0xf870ff) != 0)
734                         continue;
735
736                 port = pci_cfgenable(0, device, 0, 14, 1);
737                 header = inb(port);
738                 if (bootverbose)
739                         printf("[hdr=%02x] ", header);
740                 if ((header & 0x7e) != 0)
741                         continue;
742
743                 if (bootverbose)
744                         printf("is there (id=%08x)\n", id);
745
746                 pci_cfgdisable();
747                 return (1);
748         }
749         if (bootverbose) 
750                 printf("-- nothing found\n");
751
752         pci_cfgdisable();
753         return (0);
754 }
755
756 static int
757 pcireg_cfgopen(void)
758 {
759         uint32_t mode1res,oldval1;
760         uint8_t mode2res,oldval2;
761
762         oldval1 = inl(CONF1_ADDR_PORT);
763
764         if (bootverbose) {
765                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
766                        oldval1);
767         }
768
769         if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
770
771                 cfgmech = 1;
772                 devmax = 32;
773
774                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
775                 DELAY(1);
776                 mode1res = inl(CONF1_ADDR_PORT);
777                 outl(CONF1_ADDR_PORT, oldval1);
778
779                 if (bootverbose)
780                         printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
781                                mode1res, CONF1_ENABLE_CHK);
782
783                 if (mode1res) {
784                         if (pci_cfgcheck(32)) 
785                                 return (cfgmech);
786                 }
787
788                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
789                 mode1res = inl(CONF1_ADDR_PORT);
790                 outl(CONF1_ADDR_PORT, oldval1);
791
792                 if (bootverbose)
793                         printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
794                                mode1res, CONF1_ENABLE_CHK1);
795
796                 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
797                         if (pci_cfgcheck(32)) 
798                                 return (cfgmech);
799                 }
800         }
801
802         oldval2 = inb(CONF2_ENABLE_PORT);
803
804         if (bootverbose) {
805                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
806                        oldval2);
807         }
808
809         if ((oldval2 & 0xf0) == 0) {
810
811                 cfgmech = 2;
812                 devmax = 16;
813
814                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
815                 mode2res = inb(CONF2_ENABLE_PORT);
816                 outb(CONF2_ENABLE_PORT, oldval2);
817
818                 if (bootverbose)
819                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
820                                mode2res, CONF2_ENABLE_CHK);
821
822                 if (mode2res == CONF2_ENABLE_RES) {
823                         if (bootverbose)
824                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
825
826                         if (pci_cfgcheck(16)) 
827                                 return (cfgmech);
828                 }
829         }
830
831         cfgmech = 0;
832         devmax = 0;
833         return (cfgmech);
834 }