1 /*-
2 * Copyright (C) 2009 Nathan Whitehorn
3 * Copyright (C) 2015 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Portions of this software were developed by Andrew Turner
7 * under sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/malloc.h>
36 #include <sys/bus.h>
37 #include <sys/cpu.h>
38 #include <machine/bus.h>
39
40 #include <dev/ofw/openfirm.h>
41 #include <dev/ofw/ofw_bus.h>
42 #include <dev/ofw/ofw_bus_subr.h>
43 #include <dev/ofw/ofw_cpu.h>
44
45 #if defined(__arm__) || defined(__arm64__) || defined(__riscv)
46 #include <dev/clk/clk.h>
47 #define HAS_CLK
48 #endif
49
50 static int ofw_cpulist_probe(device_t);
51 static int ofw_cpulist_attach(device_t);
52 static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev,
53 device_t child);
54
55 static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information");
56
57 struct ofw_cpulist_softc {
58 pcell_t sc_addr_cells;
59 };
60
61 static device_method_t ofw_cpulist_methods[] = {
62 /* Device interface */
63 DEVMETHOD(device_probe, ofw_cpulist_probe),
64 DEVMETHOD(device_attach, ofw_cpulist_attach),
65
66 /* Bus interface */
67 DEVMETHOD(bus_add_child, bus_generic_add_child),
68 DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo),
69 DEVMETHOD(bus_get_device_path, ofw_bus_gen_get_device_path),
70
71 /* ofw_bus interface */
72 DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo),
73 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
74 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
75 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
76 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
77 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
78
79 DEVMETHOD_END
80 };
81
82 static driver_t ofw_cpulist_driver = {
83 "cpulist",
84 ofw_cpulist_methods,
85 sizeof(struct ofw_cpulist_softc)
86 };
87
88 EARLY_DRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, 0, 0,
89 BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
90
91 static int
ofw_cpulist_probe(device_t dev)92 ofw_cpulist_probe(device_t dev)
93 {
94 const char *name;
95
96 name = ofw_bus_get_name(dev);
97
98 if (name == NULL || strcmp(name, "cpus") != 0)
99 return (ENXIO);
100
101 device_set_desc(dev, "Open Firmware CPU Group");
102
103 return (0);
104 }
105
106 static int
ofw_cpulist_attach(device_t dev)107 ofw_cpulist_attach(device_t dev)
108 {
109 struct ofw_cpulist_softc *sc;
110 phandle_t root, child;
111 device_t cdev;
112 struct ofw_bus_devinfo *dinfo;
113
114 sc = device_get_softc(dev);
115 root = ofw_bus_get_node(dev);
116
117 sc->sc_addr_cells = 1;
118 OF_getencprop(root, "#address-cells", &sc->sc_addr_cells,
119 sizeof(sc->sc_addr_cells));
120
121 for (child = OF_child(root); child != 0; child = OF_peer(child)) {
122 dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO);
123
124 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
125 free(dinfo, M_OFWCPU);
126 continue;
127 }
128 cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY);
129 if (cdev == NULL) {
130 device_printf(dev, "<%s>: device_add_child failed\n",
131 dinfo->obd_name);
132 ofw_bus_gen_destroy_devinfo(dinfo);
133 free(dinfo, M_OFWCPU);
134 continue;
135 }
136 device_set_ivars(cdev, dinfo);
137 }
138
139 bus_attach_children(dev);
140 return (0);
141 }
142
143 static const struct ofw_bus_devinfo *
ofw_cpulist_get_devinfo(device_t dev,device_t child)144 ofw_cpulist_get_devinfo(device_t dev, device_t child)
145 {
146 return (device_get_ivars(child));
147 }
148
149 static int ofw_cpu_probe(device_t);
150 static int ofw_cpu_attach(device_t);
151 static int ofw_cpu_read_ivar(device_t dev, device_t child, int index,
152 uintptr_t *result);
153
154 struct ofw_cpu_softc {
155 struct pcpu *sc_cpu_pcpu;
156 uint32_t sc_nominal_mhz;
157 bool sc_reg_valid;
158 pcell_t sc_reg[2];
159 };
160
161 static device_method_t ofw_cpu_methods[] = {
162 /* Device interface */
163 DEVMETHOD(device_probe, ofw_cpu_probe),
164 DEVMETHOD(device_attach, ofw_cpu_attach),
165
166 /* Bus interface */
167 DEVMETHOD(bus_add_child, bus_generic_add_child),
168 DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar),
169 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
170 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
171 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
172 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
173 DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
174
175 DEVMETHOD_END
176 };
177
178 static driver_t ofw_cpu_driver = {
179 "cpu",
180 ofw_cpu_methods,
181 sizeof(struct ofw_cpu_softc)
182 };
183
184 EARLY_DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, 0, 0,
185 BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE);
186
187 static bool
ofw_cpu_is_runnable(phandle_t node)188 ofw_cpu_is_runnable(phandle_t node)
189 {
190 /*
191 * Per the DeviceTree Specification, a cpu node (under /cpus) that
192 * has 'status = disabled' indicates that "the CPU is in a quiescent
193 * state."
194 *
195 * A quiescent CPU that specifies an "enable-method", such as
196 * "spin-table", can still be used by the kernel.
197 *
198 * Lacking this, any CPU marked "disabled" or other non-okay status
199 * should be excluded from the kernel's view.
200 */
201 return (ofw_bus_node_status_okay(node) ||
202 OF_hasprop(node, "enable-method"));
203 }
204
205 static int
ofw_cpu_probe(device_t dev)206 ofw_cpu_probe(device_t dev)
207 {
208 const char *type = ofw_bus_get_type(dev);
209
210 if (type == NULL || strcmp(type, "cpu") != 0)
211 return (ENXIO);
212
213 if (!ofw_cpu_is_runnable(ofw_bus_get_node(dev)))
214 return (ENXIO);
215
216 device_set_desc(dev, "Open Firmware CPU");
217 if (!bootverbose && device_get_unit(dev) != 0) {
218 device_quiet(dev);
219 device_quiet_children(dev);
220 }
221
222 return (0);
223 }
224
225 static int
get_freq_from_clk(device_t dev,struct ofw_cpu_softc * sc)226 get_freq_from_clk(device_t dev, struct ofw_cpu_softc *sc)
227 {
228 #ifdef HAS_CLK
229 clk_t cpuclk;
230 uint64_t freq;
231 int rv;
232
233 rv = clk_get_by_ofw_index(dev, 0, 0, &cpuclk);
234 if (rv == 0) {
235 rv = clk_get_freq(cpuclk, &freq);
236 if (rv != 0 && bootverbose)
237 device_printf(dev,
238 "Cannot get freq of property clocks\n");
239 else
240 sc->sc_nominal_mhz = freq / 1000000;
241 }
242
243 return (rv);
244 #else
245 return (ENODEV);
246 #endif
247 }
248
249 static int
ofw_cpu_attach(device_t dev)250 ofw_cpu_attach(device_t dev)
251 {
252 struct ofw_cpulist_softc *psc;
253 struct ofw_cpu_softc *sc;
254 phandle_t node;
255 pcell_t cell;
256 int rv;
257
258 sc = device_get_softc(dev);
259 psc = device_get_softc(device_get_parent(dev));
260
261 if (nitems(sc->sc_reg) < psc->sc_addr_cells) {
262 if (bootverbose)
263 device_printf(dev, "Too many address cells\n");
264 return (EINVAL);
265 }
266
267 node = ofw_bus_get_node(dev);
268
269 /* Read and validate the reg property for use later */
270 sc->sc_reg_valid = false;
271 rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg));
272 if (rv < 0)
273 device_printf(dev, "missing 'reg' property\n");
274 else if ((rv % 4) != 0) {
275 if (bootverbose)
276 device_printf(dev, "Malformed reg property\n");
277 } else if ((rv / 4) != psc->sc_addr_cells) {
278 if (bootverbose)
279 device_printf(dev, "Invalid reg size %u\n", rv);
280 } else
281 sc->sc_reg_valid = true;
282
283 #ifdef __powerpc__
284 /*
285 * On powerpc, "interrupt-servers" denotes a SMT CPU. Look for any
286 * thread on this CPU, and assign that.
287 */
288 if (OF_hasprop(node, "ibm,ppc-interrupt-server#s")) {
289 struct cpuref cpuref;
290 cell_t *servers;
291 int i, nservers, rv;
292
293 if ((nservers = OF_getencprop_alloc(node,
294 "ibm,ppc-interrupt-server#s", (void **)&servers)) < 0)
295 return (ENXIO);
296 nservers /= sizeof(cell_t);
297 for (i = 0; i < nservers; i++) {
298 for (rv = platform_smp_first_cpu(&cpuref); rv == 0;
299 rv = platform_smp_next_cpu(&cpuref)) {
300 if (cpuref.cr_hwref == servers[i]) {
301 sc->sc_cpu_pcpu =
302 pcpu_find(cpuref.cr_cpuid);
303 if (sc->sc_cpu_pcpu == NULL) {
304 OF_prop_free(servers);
305 return (ENXIO);
306 }
307 break;
308 }
309 }
310 if (rv != ENOENT)
311 break;
312 }
313 OF_prop_free(servers);
314 if (sc->sc_cpu_pcpu == NULL) {
315 device_printf(dev, "No CPU found for this device.\n");
316 return (ENXIO);
317 }
318 } else
319 #endif
320 sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev));
321
322 if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) {
323 if (get_freq_from_clk(dev, sc) != 0) {
324 if (bootverbose)
325 device_printf(dev,
326 "missing 'clock-frequency' property\n");
327 }
328 } else
329 sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */
330
331 if (sc->sc_nominal_mhz != 0 && bootverbose)
332 device_printf(dev, "Nominal frequency %dMhz\n",
333 sc->sc_nominal_mhz);
334
335 OF_device_register_xref(OF_xref_from_node(node), dev);
336 bus_identify_children(dev);
337 bus_attach_children(dev);
338 return (0);
339 }
340
341 static int
ofw_cpu_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)342 ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
343 {
344 struct ofw_cpulist_softc *psc;
345 struct ofw_cpu_softc *sc;
346
347 sc = device_get_softc(dev);
348
349 switch (index) {
350 case CPU_IVAR_PCPU:
351 *result = (uintptr_t)sc->sc_cpu_pcpu;
352 return (0);
353 case CPU_IVAR_NOMINAL_MHZ:
354 if (sc->sc_nominal_mhz > 0) {
355 *result = (uintptr_t)sc->sc_nominal_mhz;
356 return (0);
357 }
358 break;
359 case CPU_IVAR_CPUID_SIZE:
360 psc = device_get_softc(device_get_parent(dev));
361 *result = psc->sc_addr_cells;
362 return (0);
363 case CPU_IVAR_CPUID:
364 if (sc->sc_reg_valid) {
365 *result = (uintptr_t)sc->sc_reg;
366 return (0);
367 }
368 break;
369 }
370
371 return (ENOENT);
372 }
373
374 int
ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback,bool only_runnable)375 ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, bool only_runnable)
376 {
377 phandle_t node, child;
378 pcell_t addr_cells, reg[2];
379 char device_type[16];
380 u_int id, next_id;
381 int count, rv;
382
383 count = 0;
384 id = 0;
385 next_id = 0;
386
387 node = OF_finddevice("/cpus");
388 if (node == -1)
389 return (-1);
390
391 /* Find the number of cells in the cpu register */
392 if (OF_getencprop(node, "#address-cells", &addr_cells,
393 sizeof(addr_cells)) < 0)
394 return (-1);
395
396 for (child = OF_child(node); child != 0; child = OF_peer(child),
397 id = next_id) {
398 /* Check if child is a CPU */
399 memset(device_type, 0, sizeof(device_type));
400 rv = OF_getprop(child, "device_type", device_type,
401 sizeof(device_type) - 1);
402 if (rv < 0)
403 continue;
404 if (strcmp(device_type, "cpu") != 0)
405 continue;
406
407 /* We're processing CPU, update next_id used in the next iteration */
408 next_id++;
409
410 /*
411 * If we are filtering by runnable then limit to only
412 * those that have been enabled, or do provide a method
413 * to enable them.
414 */
415 if (only_runnable && !ofw_cpu_is_runnable(child))
416 continue;
417
418 /*
419 * Check we have a register to identify the cpu
420 */
421 rv = OF_getencprop(child, "reg", reg,
422 addr_cells * sizeof(cell_t));
423 if (rv != addr_cells * sizeof(cell_t))
424 continue;
425
426 if (callback == NULL || callback(id, child, addr_cells, reg))
427 count++;
428 }
429
430 return (only_runnable ? count : id);
431 }
432