xref: /openbsd-src/sys/arch/i386/pci/pci_bus_fixup.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: pci_bus_fixup.c,v 1.8 2001/01/27 04:59:40 mickey Exp $	*/
2 /*	$NetBSD: pci_bus_fixup.c,v 1.1 1999/11/17 07:32:58 thorpej Exp $  */
3 
4 /*
5  * Copyright (c) 1999, by UCHIYAMA Yasushi
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. The name of the developer may NOT be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * PCI bus renumbering support.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/device.h>
37 
38 #include <machine/bus.h>
39 
40 #include <dev/pci/pcireg.h>
41 #include <dev/pci/pcivar.h>
42 #include <dev/pci/pcidevs.h>
43 #include <dev/pci/ppbreg.h>
44 
45 #include <i386/pci/pcibiosvar.h>
46 
47 int
48 pci_bus_fixup(pc, bus)
49 	pci_chipset_tag_t pc;
50 	int bus;
51 {
52 	static int bridge_cnt;
53 	int bridge, device, maxdevs, function, nfuncs, bus_max, bus_sub;
54 	const struct pci_quirkdata *qd;
55 	pcireg_t reg;
56 	pcitag_t tag;
57 
58 	bus_max = bus;
59 	bus_sub = 0;
60 
61 	maxdevs = pci_bus_maxdevs(pc, bus);
62 
63 	for (device = 0; device < maxdevs; device++) {
64 		tag = pci_make_tag(pc, bus, device, 0);
65 		reg = pci_conf_read(pc, tag, PCI_ID_REG);
66 
67 		/* can't be that many */
68 		if (bus_max == 255)
69 			break;
70 
71 		/* Invalid vendor ID value? */
72 		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
73 			continue;
74 		/* XXX Not invalid, but we've done this ~forever. */
75 		if (PCI_VENDOR(reg) == 0)
76 			continue;
77 
78 		qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
79 
80 		reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
81 		if (PCI_HDRTYPE_MULTIFN(reg) ||
82 		    (qd != NULL &&
83 		     (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
84 			nfuncs = 8;
85 		else
86 			nfuncs = 1;
87 
88 		for (function = 0; function < nfuncs; function++) {
89 			tag = pci_make_tag(pc, bus, device, function);
90 			reg = pci_conf_read(pc, tag, PCI_ID_REG);
91 
92 			/* Invalid vendor ID value? */
93 			if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
94 				continue;
95 			/* XXX Not invalid, but we've done this ~forever. */
96 			if (PCI_VENDOR(reg) == 0)
97 				continue;
98 
99 			reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
100 			if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
101 			    (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
102 			     PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
103 				/* Assign the bridge's secondary bus #. */
104 				bus_max++;
105 
106 				reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
107 				reg &= 0xff000000;
108 				reg |= bus | (bus_max << 8) | (0xff << 16);
109 				pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
110 
111 				/* Scan subordinate bus. */
112 				bus_sub = pci_bus_fixup(pc, bus_max);
113 
114 				/* Configure the bridge. */
115 				reg &= 0xff000000;
116 				reg |= bus | (bus_max << 8) | (bus_sub << 16);
117 				pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
118 
119 				if (pcibios_flags & PCIBIOS_VERBOSE) {
120 					/* Assign the bridge #. */
121 					bridge = bridge_cnt++;
122 
123 					printf("PCI bridge %d: primary %d, "
124 					    "secondary %d, subordinate %d\n",
125 					    bridge, bus, bus_max, bus_sub);
126 				}
127 
128 				/* Next bridge's secondary bus #. */
129 				bus_max = (bus_sub > bus_max) ?
130 				    bus_sub : bus_max;
131 			}
132 		}
133 	}
134 
135 	return (bus_max);	/* last # of subordinate bus */
136 }
137