FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/pcibus.c
1 /*
2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 *
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34
35 #include <pci/pcivar.h>
36 #include <pci/pcireg.h>
37 #include <i386/isa/pcibus.h>
38 #include <machine/pci_cfgreg.h>
39 #include <machine/md_var.h>
40
41 #include "opt_cpu.h"
42
43 #include "pci_if.h"
44
45 static devclass_t pcib_devclass;
46
47 static const char *
48 nexus_pcib_is_host_bridge(pcicfgregs *cfg,
49 u_int32_t id, u_int8_t class, u_int8_t subclass,
50 u_int8_t *busnum)
51 {
52 const char *s = NULL;
53 static u_int8_t pxb[4]; /* hack for 450nx */
54
55 *busnum = 0;
56
57 switch (id) {
58 case 0x12258086:
59 s = "Intel 824?? host to PCI bridge";
60 /* XXX This is a guess */
61 /* *busnum = pci_cfgread(cfg, 0x41, 1); */
62 *busnum = cfg->bus;
63 break;
64 case 0x71208086:
65 s = "Intel 82810 (i810 GMCH) Host To Hub bridge";
66 break;
67 case 0x71228086:
68 s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge";
69 break;
70 case 0x71248086:
71 s = "Intel 82810E (i810E GMCH) Host To Hub bridge";
72 break;
73 case 0x71808086:
74 s = "Intel 82443LX (440 LX) host to PCI bridge";
75 break;
76 case 0x71908086:
77 s = "Intel 82443BX (440 BX) host to PCI bridge";
78 break;
79 case 0x71928086:
80 s = "Intel 82443BX host to PCI bridge (AGP disabled)";
81 break;
82 case 0x71948086:
83 s = "Intel 82443MX host to PCI bridge";
84 break;
85 case 0x71a08086:
86 s = "Intel 82443GX host to PCI bridge";
87 break;
88 case 0x71a18086:
89 s = "Intel 82443GX host to AGP bridge";
90 break;
91 case 0x71a28086:
92 s = "Intel 82443GX host to PCI bridge (AGP disabled)";
93 break;
94 case 0x84c48086:
95 s = "Intel 82454KX/GX (Orion) host to PCI bridge";
96 *busnum = pci_cfgread(cfg, 0x4a, 1);
97 break;
98 case 0x84ca8086:
99 /*
100 * For the 450nx chipset, there is a whole bundle of
101 * things pretending to be host bridges. The MIOC will
102 * be seen first and isn't really a pci bridge (the
103 * actual busses are attached to the PXB's). We need to
104 * read the registers of the MIOC to figure out the
105 * bus numbers for the PXB channels.
106 *
107 * Since the MIOC doesn't have a pci bus attached, we
108 * pretend it wasn't there.
109 */
110 pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */
111 pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */
112 pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */
113 pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */
114 return NULL;
115 case 0x84cb8086:
116 switch (cfg->slot) {
117 case 0x12:
118 s = "Intel 82454NX PXB#0, Bus#A";
119 *busnum = pxb[0];
120 break;
121 case 0x13:
122 s = "Intel 82454NX PXB#0, Bus#B";
123 *busnum = pxb[1];
124 break;
125 case 0x14:
126 s = "Intel 82454NX PXB#1, Bus#A";
127 *busnum = pxb[2];
128 break;
129 case 0x15:
130 s = "Intel 82454NX PXB#1, Bus#B";
131 *busnum = pxb[3];
132 break;
133 }
134 break;
135 case 0x1A308086:
136 s = "Intel 82845 Host to PCI bridge";
137 break;
138
139 /* AMD -- vendor 0x1022 */
140 case 0x30001022:
141 s = "AMD Elan SC520 host to PCI bridge";
142 #ifdef CPU_ELAN
143 init_AMD_Elan_sc520();
144 #else
145 printf("*** WARNING: kernel option CPU_ELAN missing");
146 printf("-- timekeeping may be wrong\n");
147 #endif
148 break;
149 case 0x70061022:
150 s = "AMD-751 host to PCI bridge";
151 break;
152 case 0x700e1022:
153 s = "AMD-761 host to PCI bridge";
154 break;
155
156 /* SiS -- vendor 0x1039 */
157 case 0x04961039:
158 s = "SiS 85c496";
159 break;
160 case 0x04061039:
161 s = "SiS 85c501";
162 break;
163 case 0x06011039:
164 s = "SiS 85c601";
165 break;
166 case 0x55911039:
167 s = "SiS 5591 host to PCI bridge";
168 break;
169 case 0x00011039:
170 s = "SiS 5591 host to AGP bridge";
171 break;
172
173 /* VLSI -- vendor 0x1004 */
174 case 0x00051004:
175 s = "VLSI 82C592 Host to PCI bridge";
176 break;
177
178 /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */
179 /* totally. Please let me know if anything wrong. -F */
180 /* XXX need info on the MVP3 -- any takers? */
181 case 0x05981106:
182 s = "VIA 82C598MVP (Apollo MVP3) host bridge";
183 break;
184
185 /* AcerLabs -- vendor 0x10b9 */
186 /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
187 /* id is '10b9" but the register always shows "10b9". -Foxfair */
188 case 0x154110b9:
189 s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
190 break;
191
192 /* OPTi -- vendor 0x1045 */
193 case 0xc8221045:
194 s = "OPTi 82C822 host to PCI Bridge";
195 break;
196
197 /* ServerWorks -- vendor 0x1166 */
198 case 0x00051166:
199 s = "ServerWorks NB6536 2.0HE host to PCI bridge";
200 *busnum = pci_cfgread(cfg, 0x44, 1);
201 break;
202
203 case 0x00061166:
204 /* FALLTHROUGH */
205 case 0x00081166:
206 s = "ServerWorks host to PCI bridge";
207 *busnum = pci_cfgread(cfg, 0x44, 1);
208 break;
209
210 case 0x00091166:
211 s = "ServerWorks NB6635 3.0LE host to PCI bridge";
212 *busnum = pci_cfgread(cfg, 0x44, 1);
213 break;
214
215 case 0x00101166:
216 s = "ServerWorks CIOB30 host to PCI bridge";
217 *busnum = pci_cfgread(cfg, 0x44, 1);
218 break;
219
220 /* XXX unknown chipset, but working */
221 case 0x00171166:
222 /* FALLTHROUGH */
223 case 0x01011166:
224 s = "ServerWorks host to PCI bridge(unknown chipset)";
225 *busnum = pci_cfgread(cfg, 0x44, 1);
226 break;
227
228 /* Integrated Micro Solutions -- vendor 0x10e0 */
229 case 0x884910e0:
230 s = "Integrated Micro Solutions VL Bridge";
231 break;
232
233 default:
234 if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST)
235 s = "Host to PCI bridge";
236 break;
237 }
238
239 return s;
240 }
241
242 /*
243 * Scan the first pci bus for host-pci bridges and add pcib instances
244 * to the nexus for each bridge.
245 */
246 static void
247 nexus_pcib_identify(driver_t *driver, device_t parent)
248 {
249 pcicfgregs probe;
250 u_int8_t hdrtype;
251 int found = 0;
252 int pcifunchigh;
253 int found824xx = 0;
254 int found_orion = 0;
255
256 if (pci_cfgregopen() == 0)
257 return;
258 probe.hose = 0;
259 probe.bus = 0;
260 retry:
261 for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
262 probe.func = 0;
263 hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1);
264 if ((hdrtype & ~PCIM_MFDEV) > 2)
265 continue;
266 if (hdrtype & PCIM_MFDEV && (!found_orion || hdrtype != 0xff) )
267 pcifunchigh = 7;
268 else
269 pcifunchigh = 0;
270 for (probe.func = 0;
271 probe.func <= pcifunchigh;
272 probe.func++) {
273 /*
274 * Read the IDs and class from the device.
275 */
276 u_int32_t id;
277 u_int8_t class, subclass, busnum;
278 device_t child;
279 const char *s;
280
281 id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4);
282 if (id == -1)
283 continue;
284 class = pci_cfgread(&probe, PCIR_CLASS, 1);
285 subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1);
286
287 s = nexus_pcib_is_host_bridge(&probe, id,
288 class, subclass,
289 &busnum);
290 if (s) {
291 /*
292 * Add at priority 100 to make sure we
293 * go after any motherboard resources
294 */
295 child = BUS_ADD_CHILD(parent, 100,
296 "pcib", busnum);
297 device_set_desc(child, s);
298 found = 1;
299 if (id == 0x12258086)
300 found824xx = 1;
301 if (id == 0x84c48086)
302 found_orion = 1;
303 }
304 }
305 }
306 if (found824xx && probe.bus == 0) {
307 probe.bus++;
308 goto retry;
309 }
310
311 /*
312 * Make sure we add at least one bridge since some old
313 * hardware doesn't actually have a host-pci bridge device.
314 * Note that pci_cfgregopen() thinks we have PCI devices..
315 */
316 if (!found) {
317 if (bootverbose)
318 printf(
319 "nexus_pcib_identify: no bridge found, adding pcib0 anyway\n");
320 BUS_ADD_CHILD(parent, 100, "pcib", 0);
321 }
322 }
323
324 static int
325 nexus_pcib_probe(device_t dev)
326 {
327 if (pci_cfgregopen() != 0) {
328 device_add_child(dev, "pci", device_get_unit(dev));
329 return 0;
330 }
331 return ENXIO;
332 }
333
334 /* route interrupt */
335
336 static int
337 nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
338 {
339 return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin));
340 }
341
342 static device_method_t nexus_pcib_methods[] = {
343 /* Device interface */
344 DEVMETHOD(device_identify, nexus_pcib_identify),
345 DEVMETHOD(device_probe, nexus_pcib_probe),
346 DEVMETHOD(device_attach, bus_generic_attach),
347 DEVMETHOD(device_shutdown, bus_generic_shutdown),
348 DEVMETHOD(device_suspend, bus_generic_suspend),
349 DEVMETHOD(device_resume, bus_generic_resume),
350
351 /* Bus interface */
352 DEVMETHOD(bus_print_child, bus_generic_print_child),
353 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
354 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
355 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
356 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
357 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
358 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
359
360 /* pci interface */
361 DEVMETHOD(pci_route_interrupt, nexus_pcib_route_interrupt),
362 { 0, 0 }
363 };
364
365 static driver_t nexus_pcib_driver = {
366 "pcib",
367 nexus_pcib_methods,
368 1,
369 };
370
371 DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);
Cache object: 7b4071e9d5fd392fc7769f87baf0eb80
|