1 /* $NetBSD: mainbus.c,v 1.7 2021/08/07 16:19:08 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
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, 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30
31 __KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.7 2021/08/07 16:19:08 thorpej Exp $");
32
33 #include "opt_acpi.h"
34 #include "opt_mpbios.h"
35 #include "opt_pcifixup.h"
36 #include "opt_pci.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/reboot.h>
42
43 #include <machine/cpuvar.h>
44 #include <machine/mpbiosvar.h>
45 #include <machine/mpacpi.h>
46 #include <xen/hypervisor.h>
47
48 #include "pci.h"
49 #include "isa.h"
50 #include "isadma.h"
51 #include "acpica.h"
52 #include "ipmi.h"
53
54 #if NACPICA > 0
55 #include <dev/acpi/acpivar.h>
56 #endif
57
58 #include <x86/autoconf.h>
59
60 #if NIPMI > 0
61 #include <x86/ipmivar.h>
62 #endif
63
64 #if NPCI > 0
65 #include <dev/pci/pcivar.h>
66 #if defined(PCI_BUS_FIXUP)
67 #include <arch/x86/pci/pci_bus_fixup.h>
68 #if defined(PCI_ADDR_FIXUP)
69 #include <arch/x86/pci/pci_addr_fixup.h>
70 #endif
71 #endif
72 #ifdef __HAVE_PCI_MSI_MSIX
73 #include <arch/x86/pci/msipic.h>
74 #endif /* __HAVE_PCI_MSI_MSIX */
75 #endif
76
77 bool acpi_present = false;
78 bool mpacpi_active = false;
79
80 int mainbus_rescan(device_t, const char *, const int *);
81 void mainbus_childdetached(device_t, device_t);
82 void mainbus_attach(device_t, device_t, void *);
83 int mainbus_match(device_t, cfdata_t, void *);
84
85 CFATTACH_DECL2_NEW(mainbus, sizeof(struct mainbus_softc),
86 mainbus_match, mainbus_attach,
87 NULL, NULL,
88 mainbus_rescan, mainbus_childdetached);
89
90 #if defined(__i386__) && !defined(XENPV)
91 void i386_mainbus_childdetached(device_t, device_t);
92 int i386_mainbus_rescan(device_t, const char *, const int *);
93 void i386_mainbus_attach(device_t, device_t, void *);
94 #endif
95
96 #if defined(__x86_64__) && !defined(XENPV)
97 void amd64_mainbus_attach(device_t, device_t, void *);
98 #endif
99
100 static int
mainbus_cpu_print(void * aux,const char * busname)101 mainbus_cpu_print(void *aux, const char *busname)
102 {
103 char *cpuname = aux;
104
105 if (busname)
106 aprint_normal("%s at %s", cpuname, busname);
107 return UNCONF;
108 }
109
110 /*
111 * On x86, CPUs can be enumerated and attached to mainbus in mainly two ways
112 * depending on the platform (configuration): via MP BIOS tables, and via
113 * ACPI tables.
114 *
115 * Since CPUs are not an optional part of computers, this attachment is made
116 * common across all x86 architectures and modes, and thus hard-coded into
117 * the boot path, with the exception of XEN PV domU.
118 *
119 * Along with CPUs, APICs come in various shapes and forms, and to accommodate
120 * for the configurable ioapic topology, the "ioapicbus" is also enumerated
121 * here as part of the mpbios/mpacpi probe path.
122 *
123 * All other busses are attached variously depending on the platform
124 * architecture and config(5).
125 *
126 * These configurations and attach orderings for various platforms are
127 * currently respectively driven in the functions:
128 *
129 * i386_mainbus_attach();
130 * amd64_mainbus_attach();
131 * xen_mainbus_attach();
132 *
133 * This arrangement gives us the flexibility to do things such as dynamic
134 * attach path traversal at boot time, depending on the "mode" of operation,
135 * ie: virtualition aware or native.
136 *
137 * For (a contrived) eg: XEN PVHVM would allow us to attach pci(9) either via
138 * hypervisorbus or mainbus depending on if the kernel is running under the
139 * hypervisor or not.
140 */
141
142 static void
x86_cpubus_attach(device_t self)143 x86_cpubus_attach(device_t self)
144 {
145 int numcpus = 0;
146
147 #if NPCI > 0
148
149 #ifdef __HAVE_PCI_MSI_MSIX
150 msipic_init();
151 #endif
152
153 /*
154 * ACPI needs to be able to access PCI configuration space.
155 */
156 pci_mode_detect();
157 #if defined(PCI_BUS_FIXUP)
158 int pci_maxbus = 0;
159
160 if (pci_mode_detect() != 0) {
161 pci_maxbus = pci_bus_fixup(NULL, 0);
162 aprint_debug("PCI bus max, after pci_bus_fixup: %i\n",
163 pci_maxbus);
164 #if defined(PCI_ADDR_FIXUP)
165 pciaddr.extent_port = NULL;
166 pciaddr.extent_mem = NULL;
167 pci_addr_fixup(NULL, pci_maxbus);
168 #endif
169 }
170 #endif
171 #endif /* NPCI */
172
173 #if NACPICA > 0
174 if ((boothowto & RB_MD2) == 0 && acpi_check(self, "acpibus"))
175 acpi_present = acpi_probe() != 0;
176 /*
177 * First, see if the MADT contains CPUs, and possibly I/O APICs.
178 * Building the interrupt routing structures can only
179 * be done later (via a callback).
180 */
181 if (acpi_present)
182 mpacpi_active = mpacpi_scan_apics(self, &numcpus) != 0;
183
184 if (!mpacpi_active) {
185 #endif
186 #ifdef MPBIOS
187 if (mpbios_probe(self))
188 mpbios_scan(self, &numcpus);
189 else
190 #endif
191 if (numcpus == 0) {
192 struct cpu_attach_args caa;
193
194 memset(&caa, 0, sizeof(caa));
195 caa.cpu_number = 0;
196 caa.cpu_role = CPU_ROLE_SP;
197 caa.cpu_func = 0;
198
199 config_found(self, &caa, mainbus_cpu_print,
200 CFARGS(.iattr = "cpubus"));
201 }
202 #if NACPICA > 0
203 }
204 #endif
205 }
206
207 int
mainbus_match(device_t parent,cfdata_t match,void * aux)208 mainbus_match(device_t parent, cfdata_t match, void *aux)
209 {
210
211 return 1;
212 }
213
214 void
mainbus_attach(device_t parent,device_t self,void * aux)215 mainbus_attach(device_t parent, device_t self, void *aux)
216 {
217
218 aprint_naive("\n");
219 aprint_normal("\n");
220
221 #if defined(XENPVHVM)
222 xen_hvm_init(); /* before attaching CPUs */
223 #endif
224
225 #if defined(XENPV)
226 if (xendomain_is_dom0()) {
227 #endif /* XENPV */
228 x86_cpubus_attach(self);
229
230 #if defined(XENPV)
231 }
232 #endif /* XENPV */
233 #if defined(XEN)
234 /*
235 * before isa/pci probe, so that PV devices are not probed again
236 * as emulated
237 */
238 xen_mainbus_attach(parent, self, aux);
239 #endif
240 #if defined(__i386__) && !defined(XENPV)
241 i386_mainbus_attach(parent, self, aux);
242 #elif defined(__x86_64__) && !defined(XENPV)
243 amd64_mainbus_attach(parent, self, aux);
244 #endif
245 }
246
247 int
mainbus_rescan(device_t self,const char * ifattr,const int * locators)248 mainbus_rescan(device_t self, const char *ifattr, const int *locators)
249 {
250 #if defined(__i386__) && !defined(XEN)
251 return i386_mainbus_rescan(self, ifattr, locators);
252 #endif
253 return ENOTTY; /* Inappropriate ioctl for this device */
254 }
255
256 void
mainbus_childdetached(device_t self,device_t child)257 mainbus_childdetached(device_t self, device_t child)
258 {
259 #if defined(__i386__) && !defined(XEN)
260 i386_mainbus_childdetached(self, child);
261 #endif
262 }
263
264