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 <sys/smp.h> 39 #include <machine/bus.h> 40 41 #include <dev/ofw/openfirm.h> 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 #include <dev/ofw/ofw_cpu.h> 45 46 #if defined(__arm__) || defined(__arm64__) || defined(__riscv) 47 #include <dev/clk/clk.h> 48 #define HAS_CLK 49 #endif 50 51 static int ofw_cpulist_probe(device_t); 52 static int ofw_cpulist_attach(device_t); 53 static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, 54 device_t child); 55 56 static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); 57 58 struct ofw_cpulist_softc { 59 pcell_t sc_addr_cells; 60 }; 61 62 static device_method_t ofw_cpulist_methods[] = { 63 /* Device interface */ 64 DEVMETHOD(device_probe, ofw_cpulist_probe), 65 DEVMETHOD(device_attach, ofw_cpulist_attach), 66 67 /* Bus interface */ 68 DEVMETHOD(bus_add_child, bus_generic_add_child), 69 DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo), 70 DEVMETHOD(bus_get_device_path, ofw_bus_gen_get_device_path), 71 72 /* ofw_bus interface */ 73 DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo), 74 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 75 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 76 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 77 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 78 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 79 80 DEVMETHOD_END 81 }; 82 83 static driver_t ofw_cpulist_driver = { 84 "cpulist", 85 ofw_cpulist_methods, 86 sizeof(struct ofw_cpulist_softc) 87 }; 88 89 EARLY_DRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, 0, 0, 90 BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 91 92 static int 93 ofw_cpulist_probe(device_t dev) 94 { 95 const char *name; 96 97 name = ofw_bus_get_name(dev); 98 99 if (name == NULL || strcmp(name, "cpus") != 0) 100 return (ENXIO); 101 102 device_set_desc(dev, "Open Firmware CPU Group"); 103 104 return (0); 105 } 106 107 static int 108 ofw_cpulist_attach(device_t dev) 109 { 110 struct ofw_cpulist_softc *sc; 111 phandle_t root, child; 112 device_t cdev; 113 struct ofw_bus_devinfo *dinfo; 114 115 sc = device_get_softc(dev); 116 root = ofw_bus_get_node(dev); 117 118 sc->sc_addr_cells = 1; 119 OF_getencprop(root, "#address-cells", &sc->sc_addr_cells, 120 sizeof(sc->sc_addr_cells)); 121 122 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 123 dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); 124 125 if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 126 free(dinfo, M_OFWCPU); 127 continue; 128 } 129 cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 130 if (cdev == NULL) { 131 device_printf(dev, "<%s>: device_add_child failed\n", 132 dinfo->obd_name); 133 ofw_bus_gen_destroy_devinfo(dinfo); 134 free(dinfo, M_OFWCPU); 135 continue; 136 } 137 device_set_ivars(cdev, dinfo); 138 } 139 140 bus_attach_children(dev); 141 return (0); 142 } 143 144 static const struct ofw_bus_devinfo * 145 ofw_cpulist_get_devinfo(device_t dev, device_t child) 146 { 147 return (device_get_ivars(child)); 148 } 149 150 static int ofw_cpu_probe(device_t); 151 static int ofw_cpu_attach(device_t); 152 static int ofw_cpu_read_ivar(device_t dev, device_t child, int index, 153 uintptr_t *result); 154 155 struct ofw_cpu_softc { 156 struct pcpu *sc_cpu_pcpu; 157 uint32_t sc_nominal_mhz; 158 bool sc_reg_valid; 159 pcell_t sc_reg[2]; 160 }; 161 162 static device_method_t ofw_cpu_methods[] = { 163 /* Device interface */ 164 DEVMETHOD(device_probe, ofw_cpu_probe), 165 DEVMETHOD(device_attach, ofw_cpu_attach), 166 167 /* Bus interface */ 168 DEVMETHOD(bus_add_child, bus_generic_add_child), 169 DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar), 170 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 171 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 172 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 173 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 174 DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), 175 176 DEVMETHOD_END 177 }; 178 179 static driver_t ofw_cpu_driver = { 180 "cpu", 181 ofw_cpu_methods, 182 sizeof(struct ofw_cpu_softc) 183 }; 184 185 EARLY_DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, 0, 0, 186 BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 187 188 static bool 189 ofw_cpu_is_runnable(phandle_t node) 190 { 191 /* 192 * Per the DeviceTree Specification, a cpu node (under /cpus) that 193 * has 'status = disabled' indicates that "the CPU is in a quiescent 194 * state." 195 * 196 * A quiescent CPU that specifies an "enable-method", such as 197 * "spin-table", can still be used by the kernel. 198 * 199 * Lacking this, any CPU marked "disabled" or other non-okay status 200 * should be excluded from the kernel's view. 201 */ 202 return (ofw_bus_node_status_okay(node) || 203 OF_hasprop(node, "enable-method")); 204 } 205 206 static int 207 ofw_cpu_probe(device_t dev) 208 { 209 const char *type = ofw_bus_get_type(dev); 210 211 if (type == NULL || strcmp(type, "cpu") != 0) 212 return (ENXIO); 213 214 if (!ofw_cpu_is_runnable(ofw_bus_get_node(dev))) 215 return (ENXIO); 216 217 device_set_desc(dev, "Open Firmware CPU"); 218 if (!bootverbose && device_get_unit(dev) != 0) { 219 device_quiet(dev); 220 device_quiet_children(dev); 221 } 222 223 return (0); 224 } 225 226 static int 227 get_freq_from_clk(device_t dev, struct ofw_cpu_softc *sc) 228 { 229 #ifdef HAS_CLK 230 clk_t cpuclk; 231 uint64_t freq; 232 int rv; 233 234 rv = clk_get_by_ofw_index(dev, 0, 0, &cpuclk); 235 if (rv == 0) { 236 rv = clk_get_freq(cpuclk, &freq); 237 if (rv != 0 && bootverbose) 238 device_printf(dev, 239 "Cannot get freq of property clocks\n"); 240 else 241 sc->sc_nominal_mhz = freq / 1000000; 242 } 243 244 return (rv); 245 #else 246 return (ENODEV); 247 #endif 248 } 249 250 static int 251 ofw_cpu_attach(device_t dev) 252 { 253 struct ofw_cpulist_softc *psc; 254 struct ofw_cpu_softc *sc; 255 phandle_t node; 256 pcell_t cell; 257 int rv; 258 259 sc = device_get_softc(dev); 260 psc = device_get_softc(device_get_parent(dev)); 261 262 if (nitems(sc->sc_reg) < psc->sc_addr_cells) { 263 if (bootverbose) 264 device_printf(dev, "Too many address cells\n"); 265 return (EINVAL); 266 } 267 268 node = ofw_bus_get_node(dev); 269 270 /* Read and validate the reg property for use later */ 271 sc->sc_reg_valid = false; 272 rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg)); 273 if (rv < 0) 274 device_printf(dev, "missing 'reg' property\n"); 275 else if ((rv % 4) != 0) { 276 if (bootverbose) 277 device_printf(dev, "Malformed reg property\n"); 278 } else if ((rv / 4) != psc->sc_addr_cells) { 279 if (bootverbose) 280 device_printf(dev, "Invalid reg size %u\n", rv); 281 } else 282 sc->sc_reg_valid = true; 283 284 #ifdef __aarch64__ 285 if (sc->sc_reg_valid) { 286 uint64_t target_mpidr; 287 288 target_mpidr = sc->sc_reg[0]; 289 if (psc->sc_addr_cells > 1) { 290 MPASS(psc->sc_addr_cells == 2); 291 target_mpidr <<= 32; 292 target_mpidr |= sc->sc_reg[1]; 293 } 294 target_mpidr &= CPU_AFF_MASK; 295 for (int cpu = 0; cpu <= mp_maxid; cpu++) { 296 if (cpuid_to_pcpu[cpu] == NULL) 297 continue; 298 299 if (cpuid_to_pcpu[cpu]->pc_mpidr == target_mpidr) { 300 sc->sc_cpu_pcpu = cpuid_to_pcpu[cpu]; 301 break; 302 } 303 } 304 } 305 #endif 306 #ifdef __powerpc__ 307 /* 308 * On powerpc, "interrupt-servers" denotes a SMT CPU. Look for any 309 * thread on this CPU, and assign that. 310 */ 311 if (OF_hasprop(node, "ibm,ppc-interrupt-server#s")) { 312 struct cpuref cpuref; 313 cell_t *servers; 314 int i, nservers, rv; 315 316 if ((nservers = OF_getencprop_alloc(node, 317 "ibm,ppc-interrupt-server#s", (void **)&servers)) < 0) 318 return (ENXIO); 319 nservers /= sizeof(cell_t); 320 for (i = 0; i < nservers; i++) { 321 for (rv = platform_smp_first_cpu(&cpuref); rv == 0; 322 rv = platform_smp_next_cpu(&cpuref)) { 323 if (cpuref.cr_hwref == servers[i]) { 324 sc->sc_cpu_pcpu = 325 pcpu_find(cpuref.cr_cpuid); 326 if (sc->sc_cpu_pcpu == NULL) { 327 OF_prop_free(servers); 328 return (ENXIO); 329 } 330 break; 331 } 332 } 333 if (rv != ENOENT) 334 break; 335 } 336 OF_prop_free(servers); 337 if (sc->sc_cpu_pcpu == NULL) { 338 device_printf(dev, "No CPU found for this device.\n"); 339 return (ENXIO); 340 } 341 } 342 #endif 343 if (sc->sc_cpu_pcpu == NULL) 344 sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev)); 345 346 if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) { 347 if (get_freq_from_clk(dev, sc) != 0) { 348 if (bootverbose) 349 device_printf(dev, 350 "missing 'clock-frequency' property\n"); 351 } 352 } else 353 sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ 354 355 if (sc->sc_nominal_mhz != 0 && bootverbose) 356 device_printf(dev, "Nominal frequency %dMhz\n", 357 sc->sc_nominal_mhz); 358 359 OF_device_register_xref(OF_xref_from_node(node), dev); 360 bus_identify_children(dev); 361 bus_attach_children(dev); 362 return (0); 363 } 364 365 static int 366 ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 367 { 368 struct ofw_cpulist_softc *psc; 369 struct ofw_cpu_softc *sc; 370 371 sc = device_get_softc(dev); 372 373 switch (index) { 374 case CPU_IVAR_PCPU: 375 *result = (uintptr_t)sc->sc_cpu_pcpu; 376 return (0); 377 case CPU_IVAR_NOMINAL_MHZ: 378 if (sc->sc_nominal_mhz > 0) { 379 *result = (uintptr_t)sc->sc_nominal_mhz; 380 return (0); 381 } 382 break; 383 case CPU_IVAR_CPUID_SIZE: 384 psc = device_get_softc(device_get_parent(dev)); 385 *result = psc->sc_addr_cells; 386 return (0); 387 case CPU_IVAR_CPUID: 388 if (sc->sc_reg_valid) { 389 *result = (uintptr_t)sc->sc_reg; 390 return (0); 391 } 392 break; 393 } 394 395 return (ENOENT); 396 } 397 398 int 399 ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, bool only_runnable) 400 { 401 phandle_t node, child; 402 pcell_t addr_cells, reg[2]; 403 char device_type[16]; 404 u_int id, next_id; 405 int count, rv; 406 407 count = 0; 408 id = 0; 409 next_id = 0; 410 411 node = OF_finddevice("/cpus"); 412 if (node == -1) 413 return (-1); 414 415 /* Find the number of cells in the cpu register */ 416 if (OF_getencprop(node, "#address-cells", &addr_cells, 417 sizeof(addr_cells)) < 0) 418 return (-1); 419 420 for (child = OF_child(node); child != 0; child = OF_peer(child), 421 id = next_id) { 422 /* Check if child is a CPU */ 423 memset(device_type, 0, sizeof(device_type)); 424 rv = OF_getprop(child, "device_type", device_type, 425 sizeof(device_type) - 1); 426 if (rv < 0) 427 continue; 428 if (strcmp(device_type, "cpu") != 0) 429 continue; 430 431 /* We're processing CPU, update next_id used in the next iteration */ 432 next_id++; 433 434 /* 435 * If we are filtering by runnable then limit to only 436 * those that have been enabled, or do provide a method 437 * to enable them. 438 */ 439 if (only_runnable && !ofw_cpu_is_runnable(child)) 440 continue; 441 442 /* 443 * Check we have a register to identify the cpu 444 */ 445 rv = OF_getencprop(child, "reg", reg, 446 addr_cells * sizeof(cell_t)); 447 if (rv != addr_cells * sizeof(cell_t)) 448 continue; 449 450 if (callback == NULL || callback(id, child, addr_cells, reg)) 451 count++; 452 } 453 454 return (only_runnable ? count : id); 455 } 456