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/hwpmc/hwpmc_power8.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) 2013 Justin Hibbits
    5  * Copyright (c) 2020 Leandro Lupori
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/pmc.h>
   35 #include <sys/pmckern.h>
   36 #include <sys/systm.h>
   37 
   38 #include <machine/pmc_mdep.h>
   39 #include <machine/spr.h>
   40 #include <machine/cpu.h>
   41 
   42 #include "hwpmc_powerpc.h"
   43 
   44 #define POWER8_MAX_PMCS         6
   45 
   46 #define PM_EVENT_CODE(pe)       (pe & 0xffff)
   47 #define PM_EVENT_COUNTER(pe)    ((pe >> 16) & 0xffff)
   48 
   49 #define PM_CYC                  0x1e
   50 #define PM_INST_CMPL            0x02
   51 
   52 static void
   53 power8_set_pmc(int cpu, int ri, int config)
   54 {
   55         register_t mmcr;
   56 
   57         /* Select event */
   58         switch (ri) {
   59         case 0:
   60         case 1:
   61         case 2:
   62         case 3:
   63                 mmcr = mfspr(SPR_MMCR1);
   64                 mmcr &= ~SPR_MMCR1_P8_PMCNSEL_MASK(ri);
   65                 mmcr |= SPR_MMCR1_P8_PMCNSEL(ri, config & ~POWERPC_PMC_ENABLE);
   66                 mtspr(SPR_MMCR1, mmcr);
   67                 break;
   68         }
   69 
   70         /*
   71          * By default, freeze counter in all states.
   72          * If counter is being started, unfreeze it in selected states.
   73          */
   74         mmcr = mfspr(SPR_MMCR2) | SPR_MMCR2_FCNHSP(ri);
   75         if (config != PMCN_NONE) {
   76                 if (config & POWERPC_PMC_USER_ENABLE)
   77                         mmcr &= ~(SPR_MMCR2_FCNP0(ri) |
   78                             SPR_MMCR2_FCNP1(ri));
   79                 if (config & POWERPC_PMC_KERNEL_ENABLE)
   80                         mmcr &= ~(SPR_MMCR2_FCNH(ri) |
   81                             SPR_MMCR2_FCNS(ri));
   82         }
   83         mtspr(SPR_MMCR2, mmcr);
   84 }
   85 
   86 static int
   87 power8_pcpu_init(struct pmc_mdep *md, int cpu)
   88 {
   89         register_t mmcr0;
   90         int i;
   91 
   92         powerpc_pcpu_init(md, cpu);
   93 
   94         /* Freeze all counters before modifying PMC registers */
   95         mmcr0 = mfspr(SPR_MMCR0) | SPR_MMCR0_FC;
   96         mtspr(SPR_MMCR0, mmcr0);
   97 
   98         /*
   99          * Now setup MMCR0:
  100          *  - PMAO=0: clear alerts
  101          *  - FCPC=0, FCP=0: don't freeze counters in problem state
  102          *  - FCECE: Freeze Counters on Enabled Condition or Event
  103          *  - PMC1CE/PMCNCE: PMC1/N Condition Enable
  104          */
  105         mmcr0 &= ~(SPR_MMCR0_PMAO | SPR_MMCR0_FCPC | SPR_MMCR0_FCP);
  106         mmcr0 |= SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE;
  107         mtspr(SPR_MMCR0, mmcr0);
  108 
  109         /* Clear all PMCs to prevent enabled condition interrupts */
  110         for (i = 0; i < POWER8_MAX_PMCS; i++)
  111                 powerpc_pmcn_write(i, 0);
  112 
  113         /* Disable events in PMCs 1-4 */
  114         mtspr(SPR_MMCR1, mfspr(SPR_MMCR1) & ~SPR_MMCR1_P8_PMCSEL_ALL);
  115 
  116         /* Freeze each counter, in all states */
  117         mtspr(SPR_MMCR2, mfspr(SPR_MMCR2) |
  118             SPR_MMCR2_FCNHSP(0) | SPR_MMCR2_FCNHSP(1) | SPR_MMCR2_FCNHSP(2) |
  119             SPR_MMCR2_FCNHSP(3) | SPR_MMCR2_FCNHSP(4) | SPR_MMCR2_FCNHSP(5));
  120 
  121         /* Enable interrupts, unset global freeze */
  122         mmcr0 &= ~SPR_MMCR0_FC;
  123         mmcr0 |= SPR_MMCR0_PMAE;
  124         mtspr(SPR_MMCR0, mmcr0);
  125         return (0);
  126 }
  127 
  128 static int
  129 power8_pcpu_fini(struct pmc_mdep *md, int cpu)
  130 {
  131         register_t mmcr0;
  132 
  133         /* Freeze counters, disable interrupts */
  134         mmcr0 = mfspr(SPR_MMCR0);
  135         mmcr0 &= ~SPR_MMCR0_PMAE;
  136         mmcr0 |= SPR_MMCR0_FC;
  137         mtspr(SPR_MMCR0, mmcr0);
  138 
  139         return (powerpc_pcpu_fini(md, cpu));
  140 }
  141 
  142 static void
  143 power8_resume_pmc(bool ie)
  144 {
  145         register_t mmcr0;
  146 
  147         /* Unfreeze counters and re-enable PERF exceptions if requested. */
  148         mmcr0 = mfspr(SPR_MMCR0);
  149         mmcr0 &= ~(SPR_MMCR0_FC | SPR_MMCR0_PMAO | SPR_MMCR0_PMAE);
  150         if (ie)
  151                 mmcr0 |= SPR_MMCR0_PMAE;
  152         mtspr(SPR_MMCR0, mmcr0);
  153 }
  154 
  155 static int
  156 power8_allocate_pmc(int cpu, int ri, struct pmc *pm,
  157         const struct pmc_op_pmcallocate *a)
  158 {
  159         uint32_t caps, config, counter, pe;
  160 
  161         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  162             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  163         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  164             ("[powerpc,%d] illegal row index %d", __LINE__, ri));
  165 
  166         pe = a->pm_md.pm_event;
  167         counter = PM_EVENT_COUNTER(pe);
  168         config = PM_EVENT_CODE(pe);
  169 
  170         if (a->pm_class != PMC_CLASS_POWER8)
  171                 return (EINVAL);
  172 
  173         /*
  174          * PMC5 and PMC6 are not programmable and always count instructions
  175          * completed and cycles, respectively.
  176          *
  177          * When counter is 0 any of the 4 programmable PMCs may be used for
  178          * the specified event, otherwise it must match ri + 1.
  179          */
  180         if (counter == 0 && config == PM_INST_CMPL)
  181                 counter = 5;
  182         else if (counter == 0 && config == PM_CYC)
  183                 counter = 6;
  184         else if (counter > 4)
  185                 return (EINVAL);
  186 
  187         if (counter != 0 && counter != ri + 1)
  188                 return (EINVAL);
  189 
  190         caps = a->pm_caps;
  191 
  192         if (caps & PMC_CAP_SYSTEM)
  193                 config |= POWERPC_PMC_KERNEL_ENABLE;
  194         if (caps & PMC_CAP_USER)
  195                 config |= POWERPC_PMC_USER_ENABLE;
  196         if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
  197                 config |= POWERPC_PMC_ENABLE;
  198 
  199         pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
  200 
  201         PMCDBG3(MDP,ALL,1,"powerpc-allocate cpu=%d ri=%d -> config=0x%x",
  202             cpu, ri, config);
  203         return (0);
  204 }
  205 
  206 int
  207 pmc_power8_initialize(struct pmc_mdep *pmc_mdep)
  208 {
  209         struct pmc_classdep *pcd;
  210 
  211         pmc_mdep->pmd_cputype = PMC_CPU_PPC_POWER8;
  212 
  213         pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
  214         pcd->pcd_caps  = POWERPC_PMC_CAPS;
  215         pcd->pcd_class = PMC_CLASS_POWER8;
  216         pcd->pcd_num   = POWER8_MAX_PMCS;
  217         pcd->pcd_ri    = pmc_mdep->pmd_npmc;
  218         pcd->pcd_width = 32;
  219 
  220         pcd->pcd_pcpu_init      = power8_pcpu_init;
  221         pcd->pcd_pcpu_fini      = power8_pcpu_fini;
  222         pcd->pcd_allocate_pmc   = power8_allocate_pmc;
  223         pcd->pcd_release_pmc    = powerpc_release_pmc;
  224         pcd->pcd_start_pmc      = powerpc_start_pmc;
  225         pcd->pcd_stop_pmc       = powerpc_stop_pmc;
  226         pcd->pcd_get_config     = powerpc_get_config;
  227         pcd->pcd_config_pmc     = powerpc_config_pmc;
  228         pcd->pcd_describe       = powerpc_describe;
  229         pcd->pcd_read_pmc       = powerpc_read_pmc;
  230         pcd->pcd_write_pmc      = powerpc_write_pmc;
  231 
  232         pmc_mdep->pmd_npmc     += POWER8_MAX_PMCS;
  233         pmc_mdep->pmd_intr      = powerpc_pmc_intr;
  234 
  235         ppc_max_pmcs = POWER8_MAX_PMCS;
  236 
  237         powerpc_set_pmc = power8_set_pmc;
  238         powerpc_pmcn_read = powerpc_pmcn_read_default;
  239         powerpc_pmcn_write = powerpc_pmcn_write_default;
  240         powerpc_resume_pmc = power8_resume_pmc;
  241 
  242         return (0);
  243 }

Cache object: 3f01212ac9dab25b4c1359514fde092c


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