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/powerpc/cpufreq/pmcr.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018 Justin Hibbits
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/cpu.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 
   38 #include <dev/ofw/openfirm.h>
   39 
   40 #include "cpufreq_if.h"
   41 
   42 static int pstate_ids[256];
   43 static int pstate_freqs[256];
   44 static int npstates;
   45 
   46 static void parse_pstates(void)
   47 {
   48         phandle_t node;
   49 
   50         node = OF_finddevice("/ibm,opal/power-mgt");
   51 
   52         /* If this fails, npstates will remain 0, and any attachment will bail. */
   53         if (node == -1)
   54                 return;
   55 
   56         npstates = OF_getencprop(node, "ibm,pstate-ids", pstate_ids,
   57             sizeof(pstate_ids));
   58         if (npstates < 0) {
   59                 npstates = 0;
   60                 return;
   61         }
   62 
   63         if (OF_getencprop(node, "ibm,pstate-frequencies-mhz", pstate_freqs,
   64             sizeof(pstate_freqs)) != npstates) {
   65                 npstates = 0;
   66                 return;
   67         }
   68         npstates /= sizeof(cell_t);
   69 
   70 }
   71 
   72 /* Make this a sysinit so it runs before the cpufreq driver attaches. */
   73 SYSINIT(parse_pstates, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, parse_pstates, NULL);
   74 
   75 #define PMCR_UPPERPS_MASK       0xff00000000000000UL
   76 #define PMCR_UPPERPS_SHIFT      56
   77 #define PMCR_LOWERPS_MASK       0x00ff000000000000UL
   78 #define PMCR_LOWERPS_SHIFT      48
   79 #define PMCR_VERSION_MASK       0x0000000f
   80 #define   PMCR_VERSION_1          1
   81 
   82 struct pmcr_softc {
   83         device_t dev;
   84 };
   85 
   86 static void     pmcr_identify(driver_t *driver, device_t parent);
   87 static int      pmcr_probe(device_t dev);
   88 static int      pmcr_attach(device_t dev);
   89 static int      pmcr_settings(device_t dev, struct cf_setting *sets, int *count);
   90 static int      pmcr_set(device_t dev, const struct cf_setting *set);
   91 static int      pmcr_get(device_t dev, struct cf_setting *set);
   92 static int      pmcr_type(device_t dev, int *type);
   93 
   94 static device_method_t pmcr_methods[] = {
   95         /* Device interface */
   96         DEVMETHOD(device_identify,      pmcr_identify),
   97         DEVMETHOD(device_probe,         pmcr_probe),
   98         DEVMETHOD(device_attach,        pmcr_attach),
   99 
  100         /* cpufreq interface */
  101         DEVMETHOD(cpufreq_drv_set,      pmcr_set),
  102         DEVMETHOD(cpufreq_drv_get,      pmcr_get),
  103         DEVMETHOD(cpufreq_drv_type,     pmcr_type),
  104         DEVMETHOD(cpufreq_drv_settings, pmcr_settings),
  105         {0, 0}
  106 };
  107 
  108 static driver_t pmcr_driver = {
  109         "pmcr",
  110         pmcr_methods,
  111         sizeof(struct pmcr_softc)
  112 };
  113 
  114 DRIVER_MODULE(pmcr, cpu, pmcr_driver, 0, 0);
  115 
  116 static void
  117 pmcr_identify(driver_t *driver, device_t parent)
  118 {
  119 
  120         /* Make sure we're not being doubly invoked. */
  121         if (device_find_child(parent, "pmcr", -1) != NULL)
  122                 return;
  123 
  124         /*
  125          * We attach a child for every CPU since settings need to
  126          * be performed on every CPU in the SMP case.
  127          */
  128         if (BUS_ADD_CHILD(parent, 10, "pmcr", -1) == NULL)
  129                 device_printf(parent, "add pmcr child failed\n");
  130 }
  131 
  132 static int
  133 pmcr_probe(device_t dev)
  134 {
  135         if (resource_disabled("pmcr", 0))
  136                 return (ENXIO);
  137 
  138         if (npstates == 0)
  139                 return (ENXIO);
  140 
  141         device_set_desc(dev, "Power Management Control Register");
  142         return (0);
  143 }
  144 
  145 static int
  146 pmcr_attach(device_t dev)
  147 {
  148         struct pmcr_softc *sc;
  149 
  150         sc = device_get_softc(dev);
  151         sc->dev = dev;
  152 
  153         cpufreq_register(dev);
  154         return (0);
  155 }
  156 
  157 static int
  158 pmcr_settings(device_t dev, struct cf_setting *sets, int *count)
  159 {
  160         int i;
  161 
  162         if (sets == NULL || count == NULL)
  163                 return (EINVAL);
  164         if (*count < npstates)
  165                 return (E2BIG);
  166 
  167         /* Return a list of valid settings for this driver. */
  168         memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * npstates);
  169 
  170         for (i = 0; i < npstates; i++) {
  171                 sets[i].freq = pstate_freqs[i];
  172                 sets[i].spec[0] = pstate_ids[i];
  173                 sets[i].spec[1] = i;
  174                 sets[i].dev = dev;
  175         }
  176         *count = npstates;
  177 
  178         return (0);
  179 }
  180 
  181 static int
  182 pmcr_set(device_t dev, const struct cf_setting *set)
  183 {
  184         register_t pmcr;
  185 
  186         if (set == NULL)
  187                 return (EINVAL);
  188 
  189         if (set->spec[1] < 0 || set->spec[1] >= npstates)
  190                 return (EINVAL);
  191 
  192         pmcr = ((long)set->spec[0] << PMCR_LOWERPS_SHIFT) & PMCR_LOWERPS_MASK;
  193         pmcr |= ((long)set->spec[0] << PMCR_UPPERPS_SHIFT) & PMCR_UPPERPS_MASK;
  194         pmcr |= PMCR_VERSION_1;
  195 
  196         mtspr(SPR_PMCR, pmcr);
  197         powerpc_sync(); isync();
  198 
  199         return (0);
  200 }
  201 
  202 static int
  203 pmcr_get(device_t dev, struct cf_setting *set)
  204 {
  205         register_t pmcr;
  206         int i, pstate;
  207 
  208         if (set == NULL)
  209                 return (EINVAL);
  210 
  211         memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
  212 
  213         pmcr = mfspr(SPR_PMCR);
  214 
  215         pstate = (pmcr & PMCR_LOWERPS_MASK) >> PMCR_LOWERPS_SHIFT;
  216 
  217         for (i = 0; i < npstates && pstate_ids[i] != pstate; i++)
  218                 ;
  219 
  220         if (i == npstates)
  221                 return (EINVAL);
  222 
  223         set->spec[0] = pstate;
  224         set->spec[1] = i;
  225         set->freq = pstate_freqs[i];
  226 
  227         set->dev = dev;
  228 
  229         return (0);
  230 }
  231 
  232 static int
  233 pmcr_type(device_t dev, int *type)
  234 {
  235 
  236         if (type == NULL)
  237                 return (EINVAL);
  238 
  239         *type = CPUFREQ_TYPE_ABSOLUTE;
  240         return (0);
  241 }

Cache object: 7d1f3b4d2fc8e8d13227b0613eca484b


[ 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.