The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ofw/ofw_cpu.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/malloc.h>
   39 #include <sys/bus.h>
   40 #include <sys/cpu.h>
   41 #include <machine/bus.h>
   42 
   43 #include <dev/ofw/openfirm.h>
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_bus_subr.h>
   46 #include <dev/ofw/ofw_cpu.h>
   47 
   48 #if defined(__arm__) || defined(__arm64__) || defined(__riscv__)
   49 #include <dev/extres/clk/clk.h>
   50 #endif
   51 
   52 static int      ofw_cpulist_probe(device_t);
   53 static int      ofw_cpulist_attach(device_t);
   54 static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev,
   55     device_t child);
   56 
   57 static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information");
   58 
   59 struct ofw_cpulist_softc {
   60         pcell_t  sc_addr_cells;
   61 };
   62 
   63 static device_method_t ofw_cpulist_methods[] = {
   64         /* Device interface */
   65         DEVMETHOD(device_probe,         ofw_cpulist_probe),
   66         DEVMETHOD(device_attach,        ofw_cpulist_attach),
   67 
   68         /* Bus interface */
   69         DEVMETHOD(bus_add_child,        bus_generic_add_child),
   70         DEVMETHOD(bus_child_pnpinfo,    ofw_bus_gen_child_pnpinfo),
   71         DEVMETHOD(bus_get_device_path,  ofw_bus_gen_get_device_path),
   72 
   73         /* ofw_bus interface */
   74         DEVMETHOD(ofw_bus_get_devinfo,  ofw_cpulist_get_devinfo),
   75         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
   76         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
   77         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
   78         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
   79         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
   80 
   81         DEVMETHOD_END
   82 };
   83 
   84 static driver_t ofw_cpulist_driver = {
   85         "cpulist",
   86         ofw_cpulist_methods,
   87         sizeof(struct ofw_cpulist_softc)
   88 };
   89 
   90 DRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, 0, 0);
   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, -1);
  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         return (bus_generic_attach(dev));
  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         boolean_t        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 DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, 0, 0);
  185 
  186 static int
  187 ofw_cpu_probe(device_t dev)
  188 {
  189         const char *type = ofw_bus_get_type(dev);
  190 
  191         if (type == NULL || strcmp(type, "cpu") != 0)
  192                 return (ENXIO);
  193 
  194         device_set_desc(dev, "Open Firmware CPU");
  195         return (0);
  196 }
  197 
  198 static int
  199 ofw_cpu_attach(device_t dev)
  200 {
  201         struct ofw_cpulist_softc *psc;
  202         struct ofw_cpu_softc *sc;
  203         phandle_t node;
  204         pcell_t cell;
  205         int rv;
  206 #if defined(__arm__) || defined(__arm64__) || defined(__riscv__)
  207         clk_t cpuclk;
  208         uint64_t freq;
  209 #endif
  210 
  211         sc = device_get_softc(dev);
  212         psc = device_get_softc(device_get_parent(dev));
  213 
  214         if (nitems(sc->sc_reg) < psc->sc_addr_cells) {
  215                 if (bootverbose)
  216                         device_printf(dev, "Too many address cells\n");
  217                 return (EINVAL);
  218         }
  219 
  220         node = ofw_bus_get_node(dev);
  221 
  222         /* Read and validate the reg property for use later */
  223         sc->sc_reg_valid = false;
  224         rv = OF_getencprop(node, "reg", sc->sc_reg, sizeof(sc->sc_reg));
  225         if (rv < 0)
  226                 device_printf(dev, "missing 'reg' property\n");
  227         else if ((rv % 4) != 0) {
  228                 if (bootverbose)
  229                         device_printf(dev, "Malformed reg property\n");
  230         } else if ((rv / 4) != psc->sc_addr_cells) {
  231                 if (bootverbose)
  232                         device_printf(dev, "Invalid reg size %u\n", rv);
  233         } else
  234                 sc->sc_reg_valid = true;
  235 
  236 #ifdef __powerpc__
  237         /*
  238          * On powerpc, "interrupt-servers" denotes a SMT CPU.  Look for any
  239          * thread on this CPU, and assign that.
  240          */
  241         if (OF_hasprop(node, "ibm,ppc-interrupt-server#s")) {
  242                 struct cpuref cpuref;
  243                 cell_t *servers;
  244                 int i, nservers, rv;
  245                 
  246                 if ((nservers = OF_getencprop_alloc(node, 
  247                     "ibm,ppc-interrupt-server#s", (void **)&servers)) < 0)
  248                         return (ENXIO);
  249                 nservers /= sizeof(cell_t);
  250                 for (i = 0; i < nservers; i++) {
  251                         for (rv = platform_smp_first_cpu(&cpuref); rv == 0;
  252                             rv = platform_smp_next_cpu(&cpuref)) {
  253                                 if (cpuref.cr_hwref == servers[i]) {
  254                                         sc->sc_cpu_pcpu =
  255                                             pcpu_find(cpuref.cr_cpuid);
  256                                         if (sc->sc_cpu_pcpu == NULL) {
  257                                                 OF_prop_free(servers);
  258                                                 return (ENXIO);
  259                                         }
  260                                         break;
  261                                 }
  262                         }
  263                         if (rv != ENOENT)
  264                                 break;
  265                 }
  266                 OF_prop_free(servers);
  267                 if (sc->sc_cpu_pcpu == NULL) {
  268                         device_printf(dev, "No CPU found for this device.\n");
  269                         return (ENXIO);
  270                 }
  271         } else
  272 #endif
  273         sc->sc_cpu_pcpu = pcpu_find(device_get_unit(dev));
  274 
  275         if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) < 0) {
  276 #if defined(__arm__) || defined(__arm64__) || defined(__riscv__)
  277                 rv = clk_get_by_ofw_index(dev, 0, 0, &cpuclk);
  278                 if (rv == 0) {
  279                         rv = clk_get_freq(cpuclk, &freq);
  280                         if (rv != 0 && bootverbose)
  281                                 device_printf(dev,
  282                                     "Cannot get freq of property clocks\n");
  283                         else
  284                                 sc->sc_nominal_mhz = freq / 1000000;
  285                 } else
  286 #endif
  287                 {
  288                         if (bootverbose)
  289                                 device_printf(dev,
  290                                     "missing 'clock-frequency' property\n");
  291                 }
  292         } else
  293                 sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */
  294 
  295         if (sc->sc_nominal_mhz != 0 && bootverbose)
  296                 device_printf(dev, "Nominal frequency %dMhz\n",
  297                     sc->sc_nominal_mhz);
  298         bus_generic_probe(dev);
  299         return (bus_generic_attach(dev));
  300 }
  301 
  302 static int
  303 ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  304 {
  305         struct ofw_cpulist_softc *psc;
  306         struct ofw_cpu_softc *sc;
  307 
  308         sc = device_get_softc(dev);
  309 
  310         switch (index) {
  311         case CPU_IVAR_PCPU:
  312                 *result = (uintptr_t)sc->sc_cpu_pcpu;
  313                 return (0);
  314         case CPU_IVAR_NOMINAL_MHZ:
  315                 if (sc->sc_nominal_mhz > 0) {
  316                         *result = (uintptr_t)sc->sc_nominal_mhz;
  317                         return (0);
  318                 }
  319                 break;
  320         case CPU_IVAR_CPUID_SIZE:
  321                 psc = device_get_softc(device_get_parent(dev));
  322                 *result = psc->sc_addr_cells;
  323                 return (0);
  324         case CPU_IVAR_CPUID:
  325                 if (sc->sc_reg_valid) {
  326                         *result = (uintptr_t)sc->sc_reg;
  327                         return (0);
  328                 }
  329                 break;
  330         }
  331 
  332         return (ENOENT);
  333 }
  334 
  335 int
  336 ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, boolean_t only_runnable)
  337 {
  338         phandle_t node, child;
  339         pcell_t addr_cells, reg[2];
  340         char status[16];
  341         char device_type[16];
  342         u_int id, next_id;
  343         int count, rv;
  344 
  345         count = 0;
  346         id = 0;
  347         next_id = 0;
  348 
  349         node = OF_finddevice("/cpus");
  350         if (node == -1)
  351                 return (-1);
  352 
  353         /* Find the number of cells in the cpu register */
  354         if (OF_getencprop(node, "#address-cells", &addr_cells,
  355             sizeof(addr_cells)) < 0)
  356                 return (-1);
  357 
  358         for (child = OF_child(node); child != 0; child = OF_peer(child),
  359             id = next_id) {
  360                 /* Check if child is a CPU */
  361                 memset(device_type, 0, sizeof(device_type));
  362                 rv = OF_getprop(child, "device_type", device_type,
  363                     sizeof(device_type) - 1);
  364                 if (rv < 0)
  365                         continue;
  366                 if (strcmp(device_type, "cpu") != 0)
  367                         continue;
  368 
  369                 /* We're processing CPU, update next_id used in the next iteration */
  370                 next_id++;
  371 
  372                 /*
  373                  * If we are filtering by runnable then limit to only
  374                  * those that have been enabled, or do provide a method
  375                  * to enable them.
  376                  */
  377                 if (only_runnable) {
  378                         status[0] = '\0';
  379                         OF_getprop(child, "status", status, sizeof(status));
  380                         if (status[0] != '\0' && strcmp(status, "okay") != 0 &&
  381                                 strcmp(status, "ok") != 0 &&
  382                                 !OF_hasprop(child, "enable-method"))
  383                                         continue;
  384                 }
  385 
  386                 /*
  387                  * Check we have a register to identify the cpu
  388                  */
  389                 rv = OF_getencprop(child, "reg", reg,
  390                     addr_cells * sizeof(cell_t));
  391                 if (rv != addr_cells * sizeof(cell_t))
  392                         continue;
  393 
  394                 if (callback == NULL || callback(id, child, addr_cells, reg))
  395                         count++;
  396         }
  397 
  398         return (only_runnable ? count : id);
  399 }

Cache object: ad59e9bc5b88fc4508aa37355c8f8016


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.