xref: /netbsd-src/sys/arch/i386/i386/i386_mainbus.c (revision 37da905e53a2fb2658e9076edbb142b478e38efc)
1 /*	$NetBSD: i386_mainbus.c,v 1.8 2025/01/07 14:37:09 imil Exp $	*/
2 /*	NetBSD: mainbus.c,v 1.104 2018/12/02 08:19:44 cherry Exp 	*/
3 
4 /*
5  * Copyright (c) 1996 Christopher G. Demetriou.  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, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Christopher G. Demetriou
18  *	for the NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: i386_mainbus.c,v 1.8 2025/01/07 14:37:09 imil Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/reboot.h>
41 #include <sys/bus.h>
42 
43 #include <dev/isa/isavar.h>
44 #include <dev/eisa/eisavar.h>
45 #include <dev/pci/pcivar.h>
46 
47 #include <dev/isa/isareg.h>		/* for ISA_HOLE_VADDR */
48 
49 #include "pci.h"
50 #include "eisa.h"
51 #include "isa.h"
52 #include "isadma.h"
53 #include "mca.h"
54 #include "pnpbios.h"
55 #include "acpica.h"
56 #include "ipmi.h"
57 #include "pvbus.h"
58 
59 #include "opt_acpi.h"
60 #include "opt_mpbios.h"
61 #include "opt_pcifixup.h"
62 
63 #include <machine/cpuvar.h>
64 #include <machine/i82093var.h>
65 #include <machine/mpbiosvar.h>
66 #include <machine/mpacpi.h>
67 
68 #if NPNPBIOS > 0
69 #include <arch/i386/pnpbios/pnpbiosvar.h>
70 #endif
71 
72 #if NACPICA > 0
73 #include <dev/acpi/acpivar.h>
74 #endif
75 
76 #if NMCA > 0
77 #include <dev/mca/mcavar.h>
78 #endif
79 
80 #include <x86/autoconf.h>
81 
82 #if NIPMI > 0
83 #include <x86/ipmivar.h>
84 #endif
85 
86 #if NPCI > 0
87 #if defined(PCI_BUS_FIXUP)
88 #include <arch/x86/pci/pci_bus_fixup.h>
89 #if defined(PCI_ADDR_FIXUP)
90 #include <arch/x86/pci/pci_addr_fixup.h>
91 #endif /* PCI_ADDR_FIXUP */
92 #endif /* PCI_BUS_FIXUP */
93 #endif /* NPCI > 0 */
94 #if NPVBUS > 0
95 #include <arch/x86/pv/pvvar.h>
96 #endif
97 
98 void	i386_mainbus_childdetached(device_t, device_t);
99 int	i386_mainbus_match(device_t, cfdata_t, void *);
100 void	i386_mainbus_attach(device_t, device_t, void *);
101 int	i386_mainbus_rescan(device_t, const char *, const int *);
102 
103 union i386_mainbus_attach_args {
104 	const char *mba_busname;		/* first elem of all */
105 	struct pcibus_attach_args mba_pba;
106 	struct eisabus_attach_args mba_eba;
107 	struct isabus_attach_args mba_iba;
108 #if NMCA > 0
109 	struct mcabus_attach_args mba_mba;
110 #endif
111 #if NPNPBIOS > 0
112 	struct pnpbios_attach_args mba_paa;
113 #endif
114 	struct cpu_attach_args mba_caa;
115 	struct apic_attach_args aaa_caa;
116 #if NACPICA > 0
117 	struct acpibus_attach_args mba_acpi;
118 #endif
119 #if NIPMI > 0
120 	struct ipmi_attach_args mba_ipmi;
121 #endif
122 #if NPVBUS > 0
123 	struct pvbus_attach_args mba_pvba;
124 #endif
125 };
126 
127 /*
128  * This is set when the ISA bus is attached.  If it's not set by the
129  * time it's checked below, then mainbus attempts to attach an ISA.
130  */
131 int isa_has_been_seen;
132 struct x86_isa_chipset x86_isa_chipset;
133 #if NISA > 0
134 static const struct isabus_attach_args mba_iba = {
135 	._iba_busname = "isa",
136 	.iba_dmat = &isa_bus_dma_tag,
137 	.iba_ic = &x86_isa_chipset
138 };
139 #endif
140 
141 /*
142  * Same as above, but for EISA.
143  */
144 int eisa_has_been_seen;
145 
146 #if defined(MPBIOS) || NACPICA > 0
147 struct mp_bus *mp_busses;
148 int mp_nbus;
149 struct mp_intr_map *mp_intrs;
150 int mp_nintr;
151 
152 int mp_isa_bus = -1;	/* XXX */
153 int mp_eisa_bus = -1;	/* XXX */
154 
155 extern bool acpi_present;
156 extern bool mpacpi_active;
157 
158 # ifdef MPVERBOSE
159 #  if MPVERBOSE > 0
160 int mp_verbose = MPVERBOSE;
161 #  else
162 int mp_verbose = 1;
163 #  endif
164 # else
165 int mp_verbose = 0;
166 # endif
167 #endif
168 
169 void
170 i386_mainbus_childdetached(device_t self, device_t child)
171 {
172 	struct mainbus_softc *sc = device_private(self);
173 
174 	if (sc->sc_acpi == child)
175 		sc->sc_acpi = NULL;
176 	if (sc->sc_ipmi == child)
177 		sc->sc_ipmi = NULL;
178 	if (sc->sc_mca == child)
179 		sc->sc_mca = NULL;
180 	if (sc->sc_pnpbios == child)
181 		sc->sc_pnpbios = NULL;
182 	if (sc->sc_pci == child)
183 		sc->sc_pci = NULL;
184 
185 #if NPCI > 0 && (defined(MPBIOS) || NACPICA > 0)
186 	mp_pci_childdetached(self, child);
187 #endif
188 }
189 
190 /*
191  * Probe for the mainbus; always succeeds.
192  */
193 int
194 i386_mainbus_match(device_t parent, cfdata_t match, void *aux)
195 {
196 
197 	return 1;
198 }
199 
200 /*
201  * Attach the mainbus.
202  */
203 void
204 i386_mainbus_attach(device_t parent, device_t self, void *aux)
205 {
206 	struct mainbus_softc *sc = device_private(self);
207 	union i386_mainbus_attach_args mba;
208 
209 	sc->sc_dev = self;
210 
211 #if NISADMA > 0 && (NACPICA > 0 || NPNPBIOS > 0)
212 	/*
213 	 * ACPI and PNPBIOS need ISA DMA initialized before they start probing.
214 	 */
215 	isa_dmainit(&x86_isa_chipset, x86_bus_space_io, &isa_bus_dma_tag,
216 	    self);
217 #endif
218 
219 	i386_mainbus_rescan(self, "acpibus", NULL);
220 
221 	i386_mainbus_rescan(self, "pnpbiosbus", NULL);
222 
223 	i386_mainbus_rescan(self, "ipmibus", NULL);
224 
225 	i386_mainbus_rescan(self, "pcibus", NULL);
226 
227 	i386_mainbus_rescan(self, "mcabus", NULL);
228 
229 	if (memcmp(ISA_HOLE_VADDR(EISA_ID_PADDR), EISA_ID, EISA_ID_LEN) == 0 &&
230 	    eisa_has_been_seen == 0) {
231 		mba.mba_eba.eba_iot = x86_bus_space_io;
232 		mba.mba_eba.eba_memt = x86_bus_space_mem;
233 #if NEISA > 0
234 		mba.mba_eba.eba_dmat = &eisa_bus_dma_tag;
235 #endif
236 		config_found(self, &mba.mba_eba, eisabusprint,
237 		    CFARGS(.iattr = "eisabus"));
238 	}
239 
240 #if NISA > 0
241 	if (isa_has_been_seen == 0) {
242 		mba.mba_iba = mba_iba;
243 		mba.mba_iba.iba_iot = x86_bus_space_io;
244 		mba.mba_iba.iba_memt = x86_bus_space_mem;
245 		config_found(self, &mba.mba_iba, isabusprint,
246 		    CFARGS(.iattr = "isabus"));
247 	}
248 #endif
249 
250 #if NPVBUS > 0
251 	/* add here more VM guests types that would benefit from a pv bus */
252 	switch(vm_guest) {
253 	/* FALLTHROUGH */
254 	case VM_GUEST_GENPVH:
255 	case VM_GUEST_KVM:
256 		mba.mba_pvba.pvba_busname = "pvbus";
257 		config_found(self, &mba.mba_pvba.pvba_busname, NULL,
258 			CFARGS(.iattr = "pvbus"));
259 		break;
260 	default:
261 		break;
262 	}
263 #endif
264 	if (!pmf_device_register(self, NULL, NULL))
265 		aprint_error_dev(self, "couldn't establish power handler\n");
266 }
267 
268 /* scan for new children */
269 int
270 i386_mainbus_rescan(device_t self, const char *ifattr, const int *locators)
271 {
272 	struct mainbus_softc *sc = device_private(self);
273 #if NACPICA > 0 || NIPMI > 0 || NMCA > 0 || NPCI > 0 || NPNPBIOS > 0
274 	union i386_mainbus_attach_args mba;
275 #endif
276 
277 	if (ifattr_match(ifattr, "acpibus") && sc->sc_acpi == NULL &&
278 	    acpi_present) {
279 #if NACPICA > 0
280 		mba.mba_acpi.aa_iot = x86_bus_space_io;
281 		mba.mba_acpi.aa_memt = x86_bus_space_mem;
282 		mba.mba_acpi.aa_pc = NULL;
283 		mba.mba_acpi.aa_pciflags =
284 		    PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY |
285 		    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY |
286 		    PCI_FLAGS_MWI_OKAY;
287 		mba.mba_acpi.aa_ic = &x86_isa_chipset;
288 		mba.mba_acpi.aa_dmat = &pci_bus_dma_tag;
289 		mba.mba_acpi.aa_dmat64 = NULL;
290 		sc->sc_acpi = config_found(self, &mba.mba_acpi, NULL,
291 		    CFARGS(.iattr = "acpibus"));
292 #if 0 /* XXXJRT not yet */
293 		if (acpi_active) {
294 			/*
295 			 * ACPI already did all the work for us, there
296 			 * is nothing more for us to do.
297 			 */
298 			return;
299 		}
300 #endif
301 #endif
302 	}
303 
304 	if (ifattr_match(ifattr, "pnpbiosbus") && sc->sc_pnpbios == NULL) {
305 #if NPNPBIOS > 0
306 #if NACPICA > 0
307 		if (acpi_active == 0)
308 #endif
309 		if (pnpbios_probe()) {
310 			mba.mba_paa.paa_ic = &x86_isa_chipset;
311 			sc->sc_pnpbios = config_found(self, &mba.mba_paa, NULL,
312 			    CFARGS(.iattr = "pnpbiosbus"));
313 		}
314 #endif
315 	}
316 
317 	if (ifattr_match(ifattr, "ipmibus") && sc->sc_ipmi == NULL) {
318 #if NIPMI > 0
319 		memset(&mba.mba_ipmi, 0, sizeof(mba.mba_ipmi));
320 		mba.mba_ipmi.iaa_iot = x86_bus_space_io;
321 		mba.mba_ipmi.iaa_memt = x86_bus_space_mem;
322 		if (ipmi_probe(&mba.mba_ipmi)) {
323 			sc->sc_ipmi = config_found(self, &mba.mba_ipmi, NULL,
324 			    CFARGS(.iattr = "ipmibus"));
325 		}
326 #endif
327 	}
328 
329 	/*
330 	 * XXX Note also that the presence of a PCI bus should
331 	 * XXX _always_ be checked, and if present the bus should be
332 	 * XXX 'found'.  However, because of the structure of the code,
333 	 * XXX that's not currently possible.
334 	 */
335 #if NPCI > 0
336 	if (pci_mode_detect() != 0 && ifattr_match(ifattr, "pcibus")) {
337 		int npcibus = 0;
338 
339 		mba.mba_pba.pba_iot = x86_bus_space_io;
340 		mba.mba_pba.pba_memt = x86_bus_space_mem;
341 		mba.mba_pba.pba_dmat = &pci_bus_dma_tag;
342 		mba.mba_pba.pba_dmat64 = NULL;
343 		mba.mba_pba.pba_pc = NULL;
344 		mba.mba_pba.pba_flags =
345 		    PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY |
346 		    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY |
347 		    PCI_FLAGS_MWI_OKAY;
348 		mba.mba_pba.pba_bus = 0;
349 		/* XXX On those machines with >1 Host-PCI bridge,
350 		 * XXX not every bus > pba_bus is subordinate to pba_bus,
351 		 * XXX but this works on many machines, and pba_sub is
352 		 * XXX not used today by any critical code, so it is safe
353 		 * XXX to be so inclusive at this time.
354 		 */
355 		mba.mba_pba.pba_sub = 255;
356 		mba.mba_pba.pba_bridgetag = NULL;
357 #if NACPICA > 0 && defined(ACPI_SCANPCI)
358 		if (npcibus == 0 && mpacpi_active)
359 			npcibus = mp_pci_scan(self, &mba.mba_pba, pcibusprint);
360 #endif
361 #if defined(MPBIOS) && defined(MPBIOS_SCANPCI)
362 		if (npcibus == 0 && mpbios_scanned != 0)
363 			npcibus = mp_pci_scan(self, &mba.mba_pba, pcibusprint);
364 #endif
365 		if (npcibus == 0 && sc->sc_pci == NULL) {
366 			sc->sc_pci =
367 			    config_found(self, &mba.mba_pba, pcibusprint,
368 					 CFARGS(.iattr = "pcibus"));
369 		}
370 #if NACPICA > 0
371 		if (mp_verbose)
372 			acpi_pci_link_state();
373 #endif
374 	}
375 #endif
376 
377 
378 	if (ifattr_match(ifattr, "mcabus") && sc->sc_mca == NULL) {
379 #if NMCA > 0
380 	/* Note: MCA bus probe is done in i386/machdep.c */
381 		if (MCA_system) {
382 			mba.mba_mba.mba_iot = x86_bus_space_io;
383 			mba.mba_mba.mba_memt = x86_bus_space_mem;
384 			mba.mba_mba.mba_dmat = &mca_bus_dma_tag;
385 			mba.mba_mba.mba_mc = NULL;
386 			mba.mba_mba.mba_bus = 0;
387 			sc->sc_mca = config_found(self,
388 			    &mba.mba_mba, mcabusprint,
389 			    CFARGS(.iattr = "mcabus"));
390 		}
391 #endif
392 	}
393 	return 0;
394 }
395 
396