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 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 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 * 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 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 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 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 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 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 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