1193156Snwhitehorn/*- 2193156Snwhitehorn * Copyright (C) 2009 Nathan Whitehorn 3277378Sandrew * Copyright (C) 2015 The FreeBSD Foundation 4193156Snwhitehorn * All rights reserved. 5193156Snwhitehorn * 6277378Sandrew * Portions of this software were developed by Andrew Turner 7277378Sandrew * under sponsorship from the FreeBSD Foundation. 8277378Sandrew * 9193156Snwhitehorn * Redistribution and use in source and binary forms, with or without 10193156Snwhitehorn * modification, are permitted provided that the following conditions 11193156Snwhitehorn * are met: 12193156Snwhitehorn * 1. Redistributions of source code must retain the above copyright 13193156Snwhitehorn * notice, this list of conditions and the following disclaimer. 14193156Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 15193156Snwhitehorn * notice, this list of conditions and the following disclaimer in the 16193156Snwhitehorn * documentation and/or other materials provided with the distribution. 17193156Snwhitehorn * 18275815Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19275815Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20275815Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21275815Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22275815Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23275815Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24275815Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25275815Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26275815Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27275815Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28275815Semaste * SUCH DAMAGE. 29193156Snwhitehorn */ 30193156Snwhitehorn 31227843Smarius#include <sys/cdefs.h> 32227843Smarius__FBSDID("$FreeBSD: releng/11.0/sys/dev/ofw/ofw_cpu.c 285957 2015-07-28 13:16:08Z zbb $"); 33227843Smarius 34193156Snwhitehorn#include <sys/param.h> 35193156Snwhitehorn#include <sys/systm.h> 36193156Snwhitehorn#include <sys/kernel.h> 37193156Snwhitehorn#include <sys/module.h> 38193156Snwhitehorn#include <sys/malloc.h> 39193156Snwhitehorn#include <sys/bus.h> 40193156Snwhitehorn#include <sys/cpu.h> 41193156Snwhitehorn#include <machine/bus.h> 42193156Snwhitehorn 43193156Snwhitehorn#include <dev/ofw/openfirm.h> 44193156Snwhitehorn#include <dev/ofw/ofw_bus.h> 45193156Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 46279012Sandrew#include <dev/ofw/ofw_cpu.h> 47193156Snwhitehorn 48193156Snwhitehornstatic int ofw_cpulist_probe(device_t); 49193156Snwhitehornstatic int ofw_cpulist_attach(device_t); 50193156Snwhitehornstatic const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, 51193156Snwhitehorn device_t child); 52193156Snwhitehorn 53193156Snwhitehornstatic MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); 54193156Snwhitehorn 55277491Sandrewstruct ofw_cpulist_softc { 56277491Sandrew pcell_t sc_addr_cells; 57277491Sandrew}; 58277491Sandrew 59193156Snwhitehornstatic device_method_t ofw_cpulist_methods[] = { 60193156Snwhitehorn /* Device interface */ 61193156Snwhitehorn DEVMETHOD(device_probe, ofw_cpulist_probe), 62193156Snwhitehorn DEVMETHOD(device_attach, ofw_cpulist_attach), 63193156Snwhitehorn 64193156Snwhitehorn /* Bus interface */ 65193156Snwhitehorn DEVMETHOD(bus_add_child, bus_generic_add_child), 66193156Snwhitehorn DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 67193156Snwhitehorn 68193156Snwhitehorn /* ofw_bus interface */ 69193156Snwhitehorn DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo), 70193156Snwhitehorn DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 71193156Snwhitehorn DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 72193156Snwhitehorn DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 73193156Snwhitehorn DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 74193156Snwhitehorn DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 75193156Snwhitehorn 76227843Smarius DEVMETHOD_END 77193156Snwhitehorn}; 78193156Snwhitehorn 79193156Snwhitehornstatic driver_t ofw_cpulist_driver = { 80193156Snwhitehorn "cpulist", 81193156Snwhitehorn ofw_cpulist_methods, 82277491Sandrew sizeof(struct ofw_cpulist_softc) 83193156Snwhitehorn}; 84193156Snwhitehorn 85193156Snwhitehornstatic devclass_t ofw_cpulist_devclass; 86193156Snwhitehorn 87261513SnwhitehornDRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, ofw_cpulist_devclass, 88193156Snwhitehorn 0, 0); 89193156Snwhitehorn 90193156Snwhitehornstatic int 91193156Snwhitehornofw_cpulist_probe(device_t dev) 92193156Snwhitehorn{ 93193156Snwhitehorn const char *name; 94193156Snwhitehorn 95193156Snwhitehorn name = ofw_bus_get_name(dev); 96193156Snwhitehorn 97193156Snwhitehorn if (name == NULL || strcmp(name, "cpus") != 0) 98193156Snwhitehorn return (ENXIO); 99193156Snwhitehorn 100193156Snwhitehorn device_set_desc(dev, "Open Firmware CPU Group"); 101193156Snwhitehorn 102193156Snwhitehorn return (0); 103193156Snwhitehorn} 104193156Snwhitehorn 105193156Snwhitehornstatic int 106193156Snwhitehornofw_cpulist_attach(device_t dev) 107193156Snwhitehorn{ 108277491Sandrew struct ofw_cpulist_softc *sc; 109193156Snwhitehorn phandle_t root, child; 110193156Snwhitehorn device_t cdev; 111193156Snwhitehorn struct ofw_bus_devinfo *dinfo; 112193156Snwhitehorn 113277491Sandrew sc = device_get_softc(dev); 114193156Snwhitehorn root = ofw_bus_get_node(dev); 115193156Snwhitehorn 116277491Sandrew sc->sc_addr_cells = 1; 117277491Sandrew OF_getencprop(root, "#address-cells", &sc->sc_addr_cells, 118277491Sandrew sizeof(sc->sc_addr_cells)); 119277491Sandrew 120193156Snwhitehorn for (child = OF_child(root); child != 0; child = OF_peer(child)) { 121193156Snwhitehorn dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); 122193156Snwhitehorn 123193156Snwhitehorn if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 124193156Snwhitehorn free(dinfo, M_OFWCPU); 125193156Snwhitehorn continue; 126193156Snwhitehorn } 127193156Snwhitehorn cdev = device_add_child(dev, NULL, -1); 128193156Snwhitehorn if (cdev == NULL) { 129193156Snwhitehorn device_printf(dev, "<%s>: device_add_child failed\n", 130193156Snwhitehorn dinfo->obd_name); 131193156Snwhitehorn ofw_bus_gen_destroy_devinfo(dinfo); 132193156Snwhitehorn free(dinfo, M_OFWCPU); 133193156Snwhitehorn continue; 134193156Snwhitehorn } 135193156Snwhitehorn device_set_ivars(cdev, dinfo); 136193156Snwhitehorn } 137193156Snwhitehorn 138193156Snwhitehorn return (bus_generic_attach(dev)); 139193156Snwhitehorn} 140193156Snwhitehorn 141193156Snwhitehornstatic const struct ofw_bus_devinfo * 142193156Snwhitehornofw_cpulist_get_devinfo(device_t dev, device_t child) 143193156Snwhitehorn{ 144193156Snwhitehorn return (device_get_ivars(child)); 145193156Snwhitehorn} 146193156Snwhitehorn 147193156Snwhitehornstatic int ofw_cpu_probe(device_t); 148193156Snwhitehornstatic int ofw_cpu_attach(device_t); 149193156Snwhitehornstatic int ofw_cpu_read_ivar(device_t dev, device_t child, int index, 150193156Snwhitehorn uintptr_t *result); 151193156Snwhitehorn 152252115Sjhibbitsstruct ofw_cpu_softc { 153252115Sjhibbits struct pcpu *sc_cpu_pcpu; 154252115Sjhibbits uint32_t sc_nominal_mhz; 155277491Sandrew boolean_t sc_reg_valid; 156277491Sandrew pcell_t sc_reg[2]; 157252115Sjhibbits}; 158252115Sjhibbits 159193156Snwhitehornstatic device_method_t ofw_cpu_methods[] = { 160193156Snwhitehorn /* Device interface */ 161193156Snwhitehorn DEVMETHOD(device_probe, ofw_cpu_probe), 162193156Snwhitehorn DEVMETHOD(device_attach, ofw_cpu_attach), 163193156Snwhitehorn 164193156Snwhitehorn /* Bus interface */ 165193156Snwhitehorn DEVMETHOD(bus_add_child, bus_generic_add_child), 166193156Snwhitehorn DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar), 167193156Snwhitehorn DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 168193156Snwhitehorn DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 169193156Snwhitehorn DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 170193156Snwhitehorn DEVMETHOD(bus_release_resource, bus_generic_release_resource), 171193156Snwhitehorn DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), 172193156Snwhitehorn 173227843Smarius DEVMETHOD_END 174193156Snwhitehorn}; 175193156Snwhitehorn 176193156Snwhitehornstatic driver_t ofw_cpu_driver = { 177193156Snwhitehorn "cpu", 178193156Snwhitehorn ofw_cpu_methods, 179255378Snwhitehorn sizeof(struct ofw_cpu_softc) 180193156Snwhitehorn}; 181193156Snwhitehorn 182193156Snwhitehornstatic devclass_t ofw_cpu_devclass; 183193156Snwhitehorn 184193156SnwhitehornDRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, ofw_cpu_devclass, 0, 0); 185193156Snwhitehorn 186193156Snwhitehornstatic int 187193156Snwhitehornofw_cpu_probe(device_t dev) 188193156Snwhitehorn{ 189193156Snwhitehorn const char *type = ofw_bus_get_type(dev); 190193156Snwhitehorn 191276162Sian if (type == NULL || strcmp(type, "cpu") != 0) 192193156Snwhitehorn return (ENXIO); 193193156Snwhitehorn 194193156Snwhitehorn device_set_desc(dev, "Open Firmware CPU"); 195193156Snwhitehorn return (0); 196193156Snwhitehorn} 197193156Snwhitehorn 198193156Snwhitehornstatic int 199193156Snwhitehornofw_cpu_attach(device_t dev) 200193156Snwhitehorn{ 201277491Sandrew struct ofw_cpulist_softc *psc; 202252115Sjhibbits struct ofw_cpu_softc *sc; 203276162Sian phandle_t node; 204277491Sandrew pcell_t cell; 205277491Sandrew int rv; 206252115Sjhibbits 207252115Sjhibbits sc = device_get_softc(dev); 208277491Sandrew psc = device_get_softc(device_get_parent(dev)); 209277491Sandrew 210277491Sandrew if (nitems(sc->sc_reg) < psc->sc_addr_cells) { 211277491Sandrew if (bootverbose) 212277491Sandrew device_printf(dev, "Too many address cells\n"); 213277491Sandrew return (EINVAL); 214277491Sandrew } 215277491Sandrew 216276162Sian node = ofw_bus_get_node(dev); 217277491Sandrew 218277491Sandrew /* Read and validate the reg property for use later */ 219277491Sandrew sc->sc_reg_valid = false; 220277491Sandrew rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg)); 221277491Sandrew if (rv < 0) 222277491Sandrew device_printf(dev, "missing 'reg' property\n"); 223277491Sandrew else if ((rv % 4) != 0) { 224277491Sandrew if (bootverbose) 225277491Sandrew device_printf(dev, "Malformed reg property\n"); 226277491Sandrew } else if ((rv / 4) != psc->sc_addr_cells) { 227277491Sandrew if (bootverbose) 228277491Sandrew device_printf(dev, "Invalid reg size %u\n", rv); 229277491Sandrew } else 230277491Sandrew sc->sc_reg_valid = true; 231277491Sandrew 232277491Sandrew sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev)); 233277491Sandrew 234276162Sian if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) { 235277378Sandrew if (bootverbose) 236277378Sandrew device_printf(dev, 237277378Sandrew "missing 'clock-frequency' property\n"); 238277378Sandrew } else 239277378Sandrew sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ 240252115Sjhibbits 241193156Snwhitehorn bus_generic_probe(dev); 242193156Snwhitehorn return (bus_generic_attach(dev)); 243193156Snwhitehorn} 244193156Snwhitehorn 245193156Snwhitehornstatic int 246193156Snwhitehornofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 247193156Snwhitehorn{ 248278998Sandrew struct ofw_cpulist_softc *psc; 249252115Sjhibbits struct ofw_cpu_softc *sc; 250193156Snwhitehorn 251252115Sjhibbits sc = device_get_softc(dev); 252252115Sjhibbits 253193156Snwhitehorn switch (index) { 254193156Snwhitehorn case CPU_IVAR_PCPU: 255252115Sjhibbits *result = (uintptr_t)sc->sc_cpu_pcpu; 256193156Snwhitehorn return (0); 257193156Snwhitehorn case CPU_IVAR_NOMINAL_MHZ: 258277378Sandrew if (sc->sc_nominal_mhz > 0) { 259277378Sandrew *result = (uintptr_t)sc->sc_nominal_mhz; 260277378Sandrew return (0); 261277378Sandrew } 262277378Sandrew break; 263278998Sandrew case CPU_IVAR_CPUID_SIZE: 264278998Sandrew psc = device_get_softc(device_get_parent(dev)); 265278998Sandrew *result = psc->sc_addr_cells; 266278998Sandrew return (0); 267278998Sandrew case CPU_IVAR_CPUID: 268278998Sandrew if (sc->sc_reg_valid) { 269278998Sandrew *result = (uintptr_t)sc->sc_reg; 270278998Sandrew return (0); 271278998Sandrew } 272278998Sandrew break; 273193156Snwhitehorn } 274193156Snwhitehorn 275193156Snwhitehorn return (ENOENT); 276193156Snwhitehorn} 277193156Snwhitehorn 278279012Sandrewint 279279012Sandrewofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, boolean_t only_runnable) 280279012Sandrew{ 281279012Sandrew phandle_t node, child; 282279012Sandrew pcell_t addr_cells, reg[2]; 283279012Sandrew char status[16]; 284285957Szbb char device_type[16]; 285285957Szbb u_int id, next_id; 286279012Sandrew int count, rv; 287279012Sandrew 288279012Sandrew count = 0; 289279012Sandrew id = 0; 290285957Szbb next_id = 0; 291279012Sandrew 292279012Sandrew node = OF_finddevice("/cpus"); 293279012Sandrew if (node == -1) 294279012Sandrew return (-1); 295279012Sandrew 296279012Sandrew /* Find the number of cells in the cpu register */ 297279012Sandrew if (OF_getencprop(node, "#address-cells", &addr_cells, 298279012Sandrew sizeof(addr_cells)) < 0) 299279012Sandrew return (-1); 300279012Sandrew 301285957Szbb for (child = OF_child(node); child != 0; child = OF_peer(child), 302285957Szbb id = next_id) { 303285957Szbb 304285957Szbb /* Check if child is a CPU */ 305285957Szbb memset(device_type, 0, sizeof(device_type)); 306285957Szbb rv = OF_getprop(child, "device_type", device_type, 307285957Szbb sizeof(device_type) - 1); 308285957Szbb if (rv < 0) 309285957Szbb continue; 310285957Szbb if (strcmp(device_type, "cpu") != 0) 311285957Szbb continue; 312285957Szbb 313285957Szbb /* We're processing CPU, update next_id used in the next iteration */ 314285957Szbb next_id++; 315285957Szbb 316279012Sandrew /* 317279012Sandrew * If we are filtering by runnable then limit to only 318279012Sandrew * those that have been enabled. 319279012Sandrew */ 320279012Sandrew if (only_runnable) { 321279012Sandrew status[0] = '\0'; 322279012Sandrew OF_getprop(child, "status", status, sizeof(status)); 323279012Sandrew if (status[0] != '\0' && strcmp(status, "okay") != 0) 324279012Sandrew continue; 325279012Sandrew } 326279012Sandrew 327279012Sandrew /* 328279012Sandrew * Check we have a register to identify the cpu 329279012Sandrew */ 330279012Sandrew rv = OF_getencprop(child, "reg", reg, 331279012Sandrew addr_cells * sizeof(cell_t)); 332279012Sandrew if (rv != addr_cells * sizeof(cell_t)) 333279012Sandrew continue; 334279012Sandrew 335279012Sandrew if (callback == NULL || callback(id, child, addr_cells, reg)) 336279012Sandrew count++; 337279012Sandrew } 338279012Sandrew 339279012Sandrew return (only_runnable ? count : id); 340279012Sandrew} 341