ofw_cpu.c revision 278998
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: head/sys/dev/ofw/ofw_cpu.c 278998 2015-02-19 12:47:48Z andrew $"); 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> 46193156Snwhitehorn 47193156Snwhitehornstatic int ofw_cpulist_probe(device_t); 48193156Snwhitehornstatic int ofw_cpulist_attach(device_t); 49193156Snwhitehornstatic const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, 50193156Snwhitehorn device_t child); 51193156Snwhitehorn 52193156Snwhitehornstatic MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); 53193156Snwhitehorn 54277491Sandrewstruct ofw_cpulist_softc { 55277491Sandrew pcell_t sc_addr_cells; 56277491Sandrew}; 57277491Sandrew 58193156Snwhitehornstatic device_method_t ofw_cpulist_methods[] = { 59193156Snwhitehorn /* Device interface */ 60193156Snwhitehorn DEVMETHOD(device_probe, ofw_cpulist_probe), 61193156Snwhitehorn DEVMETHOD(device_attach, ofw_cpulist_attach), 62193156Snwhitehorn 63193156Snwhitehorn /* Bus interface */ 64193156Snwhitehorn DEVMETHOD(bus_add_child, bus_generic_add_child), 65193156Snwhitehorn DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 66193156Snwhitehorn 67193156Snwhitehorn /* ofw_bus interface */ 68193156Snwhitehorn DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo), 69193156Snwhitehorn DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 70193156Snwhitehorn DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 71193156Snwhitehorn DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 72193156Snwhitehorn DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 73193156Snwhitehorn DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 74193156Snwhitehorn 75227843Smarius DEVMETHOD_END 76193156Snwhitehorn}; 77193156Snwhitehorn 78193156Snwhitehornstatic driver_t ofw_cpulist_driver = { 79193156Snwhitehorn "cpulist", 80193156Snwhitehorn ofw_cpulist_methods, 81277491Sandrew sizeof(struct ofw_cpulist_softc) 82193156Snwhitehorn}; 83193156Snwhitehorn 84193156Snwhitehornstatic devclass_t ofw_cpulist_devclass; 85193156Snwhitehorn 86261513SnwhitehornDRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, ofw_cpulist_devclass, 87193156Snwhitehorn 0, 0); 88193156Snwhitehorn 89193156Snwhitehornstatic int 90193156Snwhitehornofw_cpulist_probe(device_t dev) 91193156Snwhitehorn{ 92193156Snwhitehorn const char *name; 93193156Snwhitehorn 94193156Snwhitehorn name = ofw_bus_get_name(dev); 95193156Snwhitehorn 96193156Snwhitehorn if (name == NULL || strcmp(name, "cpus") != 0) 97193156Snwhitehorn return (ENXIO); 98193156Snwhitehorn 99193156Snwhitehorn device_set_desc(dev, "Open Firmware CPU Group"); 100193156Snwhitehorn 101193156Snwhitehorn return (0); 102193156Snwhitehorn} 103193156Snwhitehorn 104193156Snwhitehornstatic int 105193156Snwhitehornofw_cpulist_attach(device_t dev) 106193156Snwhitehorn{ 107277491Sandrew struct ofw_cpulist_softc *sc; 108193156Snwhitehorn phandle_t root, child; 109193156Snwhitehorn device_t cdev; 110193156Snwhitehorn struct ofw_bus_devinfo *dinfo; 111193156Snwhitehorn 112277491Sandrew sc = device_get_softc(dev); 113193156Snwhitehorn root = ofw_bus_get_node(dev); 114193156Snwhitehorn 115277491Sandrew sc->sc_addr_cells = 1; 116277491Sandrew OF_getencprop(root, "#address-cells", &sc->sc_addr_cells, 117277491Sandrew sizeof(sc->sc_addr_cells)); 118277491Sandrew 119193156Snwhitehorn for (child = OF_child(root); child != 0; child = OF_peer(child)) { 120193156Snwhitehorn dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); 121193156Snwhitehorn 122193156Snwhitehorn if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { 123193156Snwhitehorn free(dinfo, M_OFWCPU); 124193156Snwhitehorn continue; 125193156Snwhitehorn } 126193156Snwhitehorn cdev = device_add_child(dev, NULL, -1); 127193156Snwhitehorn if (cdev == NULL) { 128193156Snwhitehorn device_printf(dev, "<%s>: device_add_child failed\n", 129193156Snwhitehorn dinfo->obd_name); 130193156Snwhitehorn ofw_bus_gen_destroy_devinfo(dinfo); 131193156Snwhitehorn free(dinfo, M_OFWCPU); 132193156Snwhitehorn continue; 133193156Snwhitehorn } 134193156Snwhitehorn device_set_ivars(cdev, dinfo); 135193156Snwhitehorn } 136193156Snwhitehorn 137193156Snwhitehorn return (bus_generic_attach(dev)); 138193156Snwhitehorn} 139193156Snwhitehorn 140193156Snwhitehornstatic const struct ofw_bus_devinfo * 141193156Snwhitehornofw_cpulist_get_devinfo(device_t dev, device_t child) 142193156Snwhitehorn{ 143193156Snwhitehorn return (device_get_ivars(child)); 144193156Snwhitehorn} 145193156Snwhitehorn 146193156Snwhitehornstatic int ofw_cpu_probe(device_t); 147193156Snwhitehornstatic int ofw_cpu_attach(device_t); 148193156Snwhitehornstatic int ofw_cpu_read_ivar(device_t dev, device_t child, int index, 149193156Snwhitehorn uintptr_t *result); 150193156Snwhitehorn 151252115Sjhibbitsstruct ofw_cpu_softc { 152252115Sjhibbits struct pcpu *sc_cpu_pcpu; 153252115Sjhibbits uint32_t sc_nominal_mhz; 154277491Sandrew boolean_t sc_reg_valid; 155277491Sandrew pcell_t sc_reg[2]; 156252115Sjhibbits}; 157252115Sjhibbits 158193156Snwhitehornstatic device_method_t ofw_cpu_methods[] = { 159193156Snwhitehorn /* Device interface */ 160193156Snwhitehorn DEVMETHOD(device_probe, ofw_cpu_probe), 161193156Snwhitehorn DEVMETHOD(device_attach, ofw_cpu_attach), 162193156Snwhitehorn 163193156Snwhitehorn /* Bus interface */ 164193156Snwhitehorn DEVMETHOD(bus_add_child, bus_generic_add_child), 165193156Snwhitehorn DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar), 166193156Snwhitehorn DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 167193156Snwhitehorn DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 168193156Snwhitehorn DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 169193156Snwhitehorn DEVMETHOD(bus_release_resource, bus_generic_release_resource), 170193156Snwhitehorn DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), 171193156Snwhitehorn 172227843Smarius DEVMETHOD_END 173193156Snwhitehorn}; 174193156Snwhitehorn 175193156Snwhitehornstatic driver_t ofw_cpu_driver = { 176193156Snwhitehorn "cpu", 177193156Snwhitehorn ofw_cpu_methods, 178255378Snwhitehorn sizeof(struct ofw_cpu_softc) 179193156Snwhitehorn}; 180193156Snwhitehorn 181193156Snwhitehornstatic devclass_t ofw_cpu_devclass; 182193156Snwhitehorn 183193156SnwhitehornDRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, ofw_cpu_devclass, 0, 0); 184193156Snwhitehorn 185193156Snwhitehornstatic int 186193156Snwhitehornofw_cpu_probe(device_t dev) 187193156Snwhitehorn{ 188193156Snwhitehorn const char *type = ofw_bus_get_type(dev); 189193156Snwhitehorn 190276162Sian if (type == NULL || strcmp(type, "cpu") != 0) 191193156Snwhitehorn return (ENXIO); 192193156Snwhitehorn 193193156Snwhitehorn device_set_desc(dev, "Open Firmware CPU"); 194193156Snwhitehorn return (0); 195193156Snwhitehorn} 196193156Snwhitehorn 197193156Snwhitehornstatic int 198193156Snwhitehornofw_cpu_attach(device_t dev) 199193156Snwhitehorn{ 200277491Sandrew struct ofw_cpulist_softc *psc; 201252115Sjhibbits struct ofw_cpu_softc *sc; 202276162Sian phandle_t node; 203277491Sandrew pcell_t cell; 204277491Sandrew int rv; 205252115Sjhibbits 206252115Sjhibbits sc = device_get_softc(dev); 207277491Sandrew psc = device_get_softc(device_get_parent(dev)); 208277491Sandrew 209277491Sandrew if (nitems(sc->sc_reg) < psc->sc_addr_cells) { 210277491Sandrew if (bootverbose) 211277491Sandrew device_printf(dev, "Too many address cells\n"); 212277491Sandrew return (EINVAL); 213277491Sandrew } 214277491Sandrew 215276162Sian node = ofw_bus_get_node(dev); 216277491Sandrew 217277491Sandrew /* Read and validate the reg property for use later */ 218277491Sandrew sc->sc_reg_valid = false; 219277491Sandrew rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg)); 220277491Sandrew if (rv < 0) 221277491Sandrew device_printf(dev, "missing 'reg' property\n"); 222277491Sandrew else if ((rv % 4) != 0) { 223277491Sandrew if (bootverbose) 224277491Sandrew device_printf(dev, "Malformed reg property\n"); 225277491Sandrew } else if ((rv / 4) != psc->sc_addr_cells) { 226277491Sandrew if (bootverbose) 227277491Sandrew device_printf(dev, "Invalid reg size %u\n", rv); 228277491Sandrew } else 229277491Sandrew sc->sc_reg_valid = true; 230277491Sandrew 231277491Sandrew sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev)); 232277491Sandrew 233276162Sian if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) { 234277378Sandrew if (bootverbose) 235277378Sandrew device_printf(dev, 236277378Sandrew "missing 'clock-frequency' property\n"); 237277378Sandrew } else 238277378Sandrew sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ 239252115Sjhibbits 240193156Snwhitehorn bus_generic_probe(dev); 241193156Snwhitehorn return (bus_generic_attach(dev)); 242193156Snwhitehorn} 243193156Snwhitehorn 244193156Snwhitehornstatic int 245193156Snwhitehornofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 246193156Snwhitehorn{ 247278998Sandrew struct ofw_cpulist_softc *psc; 248252115Sjhibbits struct ofw_cpu_softc *sc; 249193156Snwhitehorn 250252115Sjhibbits sc = device_get_softc(dev); 251252115Sjhibbits 252193156Snwhitehorn switch (index) { 253193156Snwhitehorn case CPU_IVAR_PCPU: 254252115Sjhibbits *result = (uintptr_t)sc->sc_cpu_pcpu; 255193156Snwhitehorn return (0); 256193156Snwhitehorn case CPU_IVAR_NOMINAL_MHZ: 257277378Sandrew if (sc->sc_nominal_mhz > 0) { 258277378Sandrew *result = (uintptr_t)sc->sc_nominal_mhz; 259277378Sandrew return (0); 260277378Sandrew } 261277378Sandrew break; 262278998Sandrew case CPU_IVAR_CPUID_SIZE: 263278998Sandrew psc = device_get_softc(device_get_parent(dev)); 264278998Sandrew *result = psc->sc_addr_cells; 265278998Sandrew return (0); 266278998Sandrew case CPU_IVAR_CPUID: 267278998Sandrew if (sc->sc_reg_valid) { 268278998Sandrew *result = (uintptr_t)sc->sc_reg; 269278998Sandrew return (0); 270278998Sandrew } 271278998Sandrew break; 272193156Snwhitehorn } 273193156Snwhitehorn 274193156Snwhitehorn return (ENOENT); 275193156Snwhitehorn} 276193156Snwhitehorn 277