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_powerpc.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) 2011,2013 Justin Hibbits
    5  * Copyright (c) 2005, Joseph Koshy
    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 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/pmc.h>
   36 #include <sys/pmckern.h>
   37 #include <sys/sysent.h>
   38 #include <sys/syslog.h>
   39 #include <sys/systm.h>
   40 
   41 #include <machine/pmc_mdep.h>
   42 #include <machine/spr.h>
   43 #include <machine/pte.h>
   44 #include <machine/sr.h>
   45 #include <machine/cpu.h>
   46 #include <machine/stack.h>
   47 
   48 #include "hwpmc_powerpc.h"
   49 
   50 #ifdef __powerpc64__
   51 #define OFFSET 4 /* Account for the TOC reload slot */
   52 #else
   53 #define OFFSET 0
   54 #endif
   55 
   56 struct powerpc_cpu **powerpc_pcpu;
   57 struct pmc_ppc_event *ppc_event_codes;
   58 size_t ppc_event_codes_size;
   59 int ppc_event_first;
   60 int ppc_event_last;
   61 int ppc_max_pmcs;
   62 enum pmc_class ppc_class;
   63 
   64 void (*powerpc_set_pmc)(int cpu, int ri, int config);
   65 pmc_value_t (*powerpc_pmcn_read)(unsigned int pmc);
   66 void (*powerpc_pmcn_write)(unsigned int pmc, uint32_t val);
   67 void (*powerpc_resume_pmc)(bool ie);
   68 
   69 
   70 int
   71 pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
   72     struct trapframe *tf)
   73 {
   74         uintptr_t *osp, *sp;
   75         uintptr_t pc;
   76         int frames = 0;
   77 
   78         cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
   79         sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
   80         osp = (uintptr_t *)PAGE_SIZE;
   81 
   82         for (; frames < maxsamples; frames++) {
   83                 if (sp <= osp)
   84                         break;
   85             #ifdef __powerpc64__
   86                 pc = sp[2];
   87             #else
   88                 pc = sp[1];
   89             #endif
   90                 if ((pc & 3) || (pc < 0x100))
   91                         break;
   92 
   93                 /*
   94                  * trapexit() and asttrapexit() are sentinels
   95                  * for kernel stack tracing.
   96                  * */
   97                 if (pc + OFFSET == (uintptr_t) &trapexit ||
   98                     pc + OFFSET == (uintptr_t) &asttrapexit)
   99                         break;
  100 
  101                 cc[frames] = pc;
  102                 osp = sp;
  103                 sp = (uintptr_t *)*sp;
  104         }
  105         return (frames);
  106 }
  107 
  108 static int
  109 powerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
  110 {
  111 
  112         return (0);
  113 }
  114 
  115 static int
  116 powerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
  117 {
  118 
  119         return (0);
  120 }
  121 
  122 int
  123 powerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
  124 {
  125         int error;
  126         struct pmc_hw *phw;
  127         char powerpc_name[PMC_NAME_MAX];
  128 
  129         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  130             ("[powerpc,%d], illegal CPU %d", __LINE__, cpu));
  131 
  132         phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
  133         snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri);
  134         if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX,
  135             NULL)) != 0)
  136                 return error;
  137         pi->pm_class = powerpc_pcpu[cpu]->pc_class;
  138         if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
  139                 pi->pm_enabled = TRUE;
  140                 *ppmc          = phw->phw_pmc;
  141         } else {
  142                 pi->pm_enabled = FALSE;
  143                 *ppmc          = NULL;
  144         }
  145 
  146         return (0);
  147 }
  148 
  149 int
  150 powerpc_get_config(int cpu, int ri, struct pmc **ppm)
  151 {
  152 
  153         *ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
  154 
  155         return (0);
  156 }
  157 
  158 int
  159 powerpc_pcpu_init(struct pmc_mdep *md, int cpu)
  160 {
  161         struct pmc_cpu *pc;
  162         struct powerpc_cpu *pac;
  163         struct pmc_hw  *phw;
  164         int first_ri, i;
  165 
  166         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  167             ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
  168         PMCDBG1(MDP,INI,1,"powerpc-init cpu=%d", cpu);
  169 
  170         powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu) +
  171             ppc_max_pmcs * sizeof(struct pmc_hw), M_PMC, M_WAITOK | M_ZERO);
  172         pac->pc_class =
  173             md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_class;
  174 
  175         pc = pmc_pcpu[cpu];
  176         first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
  177         KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
  178 
  179         for (i = 0, phw = pac->pc_ppcpmcs; i < ppc_max_pmcs; i++, phw++) {
  180                 phw->phw_state = PMC_PHW_FLAG_IS_ENABLED |
  181                     PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
  182                 phw->phw_pmc = NULL;
  183                 pc->pc_hwpmcs[i + first_ri] = phw;
  184         }
  185 
  186         return (0);
  187 }
  188 
  189 int
  190 powerpc_pcpu_fini(struct pmc_mdep *md, int cpu)
  191 {
  192         PMCDBG1(MDP,INI,1,"powerpc-fini cpu=%d", cpu);
  193 
  194         free(powerpc_pcpu[cpu], M_PMC);
  195         powerpc_pcpu[cpu] = NULL;
  196 
  197         return (0);
  198 }
  199 
  200 int
  201 powerpc_allocate_pmc(int cpu, int ri, struct pmc *pm,
  202     const struct pmc_op_pmcallocate *a)
  203 {
  204         enum pmc_event pe;
  205         uint32_t caps, config = 0, counter = 0;
  206         int i;
  207 
  208         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  209             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  210         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  211             ("[powerpc,%d] illegal row index %d", __LINE__, ri));
  212 
  213         if (a->pm_class != ppc_class)
  214                 return (EINVAL);
  215 
  216         caps = a->pm_caps;
  217 
  218         pe = a->pm_ev;
  219 
  220         if (pe < ppc_event_first || pe > ppc_event_last)
  221                 return (EINVAL);
  222 
  223         for (i = 0; i < ppc_event_codes_size; i++) {
  224                 if (ppc_event_codes[i].pe_event == pe) {
  225                         config = ppc_event_codes[i].pe_code;
  226                         counter =  ppc_event_codes[i].pe_flags;
  227                         break;
  228                 }
  229         }
  230         if (i == ppc_event_codes_size)
  231                 return (EINVAL);
  232 
  233         if ((counter & (1 << ri)) == 0)
  234                 return (EINVAL);
  235 
  236         if (caps & PMC_CAP_SYSTEM)
  237                 config |= POWERPC_PMC_KERNEL_ENABLE;
  238         if (caps & PMC_CAP_USER)
  239                 config |= POWERPC_PMC_USER_ENABLE;
  240         if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
  241                 config |= POWERPC_PMC_ENABLE;
  242 
  243         pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
  244 
  245         PMCDBG3(MDP,ALL,1,"powerpc-allocate cpu=%d ri=%d -> config=0x%x",
  246             cpu, ri, config);
  247         return (0);
  248 }
  249 
  250 int
  251 powerpc_release_pmc(int cpu, int ri, struct pmc *pmc)
  252 {
  253         struct pmc_hw *phw __diagused;
  254 
  255         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  256             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  257         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  258             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
  259 
  260         phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
  261         KASSERT(phw->phw_pmc == NULL,
  262             ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
  263 
  264         return (0);
  265 }
  266 
  267 int
  268 powerpc_start_pmc(int cpu, int ri)
  269 {
  270         struct pmc *pm;
  271 
  272         PMCDBG2(MDP,STA,1,"powerpc-start cpu=%d ri=%d", cpu, ri);
  273         pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
  274         powerpc_set_pmc(cpu, ri, pm->pm_md.pm_powerpc.pm_powerpc_evsel);
  275 
  276         return (0);
  277 }
  278 
  279 int
  280 powerpc_stop_pmc(int cpu, int ri)
  281 {
  282         PMCDBG2(MDP,STO,1, "powerpc-stop cpu=%d ri=%d", cpu, ri);
  283         powerpc_set_pmc(cpu, ri, PMCN_NONE);
  284         return (0);
  285 }
  286 
  287 int
  288 powerpc_config_pmc(int cpu, int ri, struct pmc *pm)
  289 {
  290         struct pmc_hw *phw;
  291 
  292         PMCDBG3(MDP,CFG,1, "powerpc-config cpu=%d ri=%d pm=%p", cpu, ri, pm);
  293 
  294         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  295             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  296         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  297             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
  298 
  299         phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
  300 
  301         KASSERT(pm == NULL || phw->phw_pmc == NULL,
  302             ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
  303             __LINE__, pm, phw->phw_pmc));
  304 
  305         phw->phw_pmc = pm;
  306 
  307         return (0);
  308 }
  309 
  310 pmc_value_t
  311 powerpc_pmcn_read_default(unsigned int pmc)
  312 {
  313         pmc_value_t val;
  314 
  315         if (pmc > ppc_max_pmcs)
  316                 panic("Invalid PMC number: %d\n", pmc);
  317 
  318         switch (pmc) {
  319         case 0:
  320                 val = mfspr(SPR_PMC1);
  321                 break;
  322         case 1:
  323                 val = mfspr(SPR_PMC2);
  324                 break;
  325         case 2:
  326                 val = mfspr(SPR_PMC3);
  327                 break;
  328         case 3:
  329                 val = mfspr(SPR_PMC4);
  330                 break;
  331         case 4:
  332                 val = mfspr(SPR_PMC5);
  333                 break;
  334         case 5:
  335                 val = mfspr(SPR_PMC6);
  336                 break;
  337         case 6:
  338                 val = mfspr(SPR_PMC7);
  339                 break;
  340         case 7:
  341                 val = mfspr(SPR_PMC8);
  342                 break;
  343         }
  344 
  345         return (val);
  346 }
  347 
  348 void
  349 powerpc_pmcn_write_default(unsigned int pmc, uint32_t val)
  350 {
  351         if (pmc > ppc_max_pmcs)
  352                 panic("Invalid PMC number: %d\n", pmc);
  353 
  354         switch (pmc) {
  355         case 0:
  356                 mtspr(SPR_PMC1, val);
  357                 break;
  358         case 1:
  359                 mtspr(SPR_PMC2, val);
  360                 break;
  361         case 2:
  362                 mtspr(SPR_PMC3, val);
  363                 break;
  364         case 3:
  365                 mtspr(SPR_PMC4, val);
  366                 break;
  367         case 4:
  368                 mtspr(SPR_PMC5, val);
  369                 break;
  370         case 5:
  371                 mtspr(SPR_PMC6, val);
  372                 break;
  373         case 6:
  374                 mtspr(SPR_PMC7, val);
  375                 break;
  376         case 7:
  377                 mtspr(SPR_PMC8, val);
  378                 break;
  379         }
  380 }
  381 
  382 int
  383 powerpc_read_pmc(int cpu, int ri, pmc_value_t *v)
  384 {
  385         struct pmc *pm;
  386         pmc_value_t p, r, tmp;
  387 
  388         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  389             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  390         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  391             ("[powerpc,%d] illegal row index %d", __LINE__, ri));
  392 
  393         pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
  394         KASSERT(pm,
  395             ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
  396                 ri));
  397 
  398         /*
  399          * After an interrupt occurs because of a PMC overflow, the PMC value
  400          * is not always MAX_PMC_VALUE + 1, but may be a little above it.
  401          * This may mess up calculations and frustrate machine independent
  402          * layer expectations, such as that no value read should be greater
  403          * than reload count in sampling mode.
  404          * To avoid these issues, use MAX_PMC_VALUE as an upper limit.
  405          */
  406         p = MIN(powerpc_pmcn_read(ri), POWERPC_MAX_PMC_VALUE);
  407         r = pm->pm_sc.pm_reloadcount;
  408 
  409         if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
  410                 /*
  411                  * Special case 1: r is too big
  412                  * This usually happens when a PMC write fails, the PMC is
  413                  * stopped and then it is read.
  414                  *
  415                  * Special case 2: PMC was reseted or has a value
  416                  * that should not be possible with current r.
  417                  *
  418                  * In the above cases, just return 0 instead of an arbitrary
  419                  * value.
  420                  */
  421                 if (r > POWERPC_MAX_PMC_VALUE || p + r <= POWERPC_MAX_PMC_VALUE)
  422                         tmp = 0;
  423                 else
  424                         tmp = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(p);
  425         } else
  426                 tmp = p + (POWERPC_MAX_PMC_VALUE + 1) * PPC_OVERFLOWCNT(pm);
  427 
  428         PMCDBG5(MDP,REA,1,"ppc-read cpu=%d ri=%d -> %jx (%jx,%jx)",
  429             cpu, ri, (uintmax_t)tmp, (uintmax_t)PPC_OVERFLOWCNT(pm),
  430             (uintmax_t)p);
  431         *v = tmp;
  432         return (0);
  433 }
  434 
  435 int
  436 powerpc_write_pmc(int cpu, int ri, pmc_value_t v)
  437 {
  438         struct pmc *pm;
  439         pmc_value_t vlo;
  440 
  441         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  442             ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
  443         KASSERT(ri >= 0 && ri < ppc_max_pmcs,
  444             ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
  445 
  446         pm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
  447 
  448         if (PMC_IS_COUNTING_MODE(PMC_TO_MODE(pm))) {
  449                 PPC_OVERFLOWCNT(pm) = v / (POWERPC_MAX_PMC_VALUE + 1);
  450                 vlo = v % (POWERPC_MAX_PMC_VALUE + 1);
  451         } else if (v > POWERPC_MAX_PMC_VALUE) {
  452                 PMCDBG3(MDP,WRI,2,
  453                     "powerpc-write cpu=%d ri=%d: PMC value is too big: %jx",
  454                     cpu, ri, (uintmax_t)v);
  455                 return (EINVAL);
  456         } else
  457                 vlo = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
  458 
  459         PMCDBG5(MDP,WRI,1,"powerpc-write cpu=%d ri=%d -> %jx (%jx,%jx)",
  460             cpu, ri, (uintmax_t)v, (uintmax_t)PPC_OVERFLOWCNT(pm),
  461             (uintmax_t)vlo);
  462 
  463         powerpc_pmcn_write(ri, vlo);
  464         return (0);
  465 }
  466 
  467 int
  468 powerpc_pmc_intr(struct trapframe *tf)
  469 {
  470         struct pmc *pm;
  471         struct powerpc_cpu *pc;
  472         int cpu, error, i, retval;
  473 
  474         cpu = curcpu;
  475         KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
  476             ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
  477 
  478         PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
  479             TRAPF_USERMODE(tf));
  480 
  481         retval = 0;
  482         pc = powerpc_pcpu[cpu];
  483 
  484         /*
  485          * Look for a running, sampling PMC which has overflowed
  486          * and which has a valid 'struct pmc' association.
  487          */
  488         for (i = 0; i < ppc_max_pmcs; i++) {
  489                 if (!POWERPC_PMC_HAS_OVERFLOWED(i))
  490                         continue;
  491                 retval = 1;     /* Found an interrupting PMC. */
  492 
  493                 /*
  494                  * Always clear the PMC, to make it stop interrupting.
  495                  * If pm is available and in sampling mode, use reload
  496                  * count, to make PMC read after stop correct.
  497                  * Otherwise, just reset the PMC.
  498                  */
  499                 if ((pm = pc->pc_ppcpmcs[i].phw_pmc) != NULL &&
  500                     PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
  501                         if (pm->pm_state != PMC_STATE_RUNNING) {
  502                                 powerpc_write_pmc(cpu, i,
  503                                     pm->pm_sc.pm_reloadcount);
  504                                 continue;
  505                         }
  506                 } else {
  507                         if (pm != NULL) { /* !PMC_IS_SAMPLING_MODE */
  508                                 PPC_OVERFLOWCNT(pm) = (PPC_OVERFLOWCNT(pm) +
  509                                     1) % PPC_OVERFLOWCNT_MAX;
  510                                 PMCDBG3(MDP,INT,2,
  511                                     "cpu=%d ri=%d: overflowcnt=%d",
  512                                     cpu, i, PPC_OVERFLOWCNT(pm));
  513                         }
  514 
  515                         powerpc_pmcn_write(i, 0);
  516                         continue;
  517                 }
  518 
  519                 error = pmc_process_interrupt(PMC_HR, pm, tf);
  520                 if (error != 0) {
  521                         PMCDBG3(MDP,INT,3,
  522                             "cpu=%d ri=%d: error %d processing interrupt",
  523                             cpu, i, error);
  524                         powerpc_stop_pmc(cpu, i);
  525                 }
  526 
  527                 /* Reload sampling count */
  528                 powerpc_write_pmc(cpu, i, pm->pm_sc.pm_reloadcount);
  529         }
  530 
  531         if (retval)
  532                 counter_u64_add(pmc_stats.pm_intr_processed, 1);
  533         else
  534                 counter_u64_add(pmc_stats.pm_intr_ignored, 1);
  535 
  536         /*
  537          * Re-enable PERF exceptions if we were able to find the interrupt
  538          * source and handle it. Otherwise, it's better to disable PERF
  539          * interrupts, to avoid the risk of processing the same interrupt
  540          * forever.
  541          */
  542         powerpc_resume_pmc(retval != 0);
  543         if (retval == 0)
  544                 log(LOG_WARNING,
  545                     "pmc_intr: couldn't find interrupting PMC on cpu %d - "
  546                     "disabling PERF interrupts\n", cpu);
  547 
  548         return (retval);
  549 }
  550 
  551 struct pmc_mdep *
  552 pmc_md_initialize(void)
  553 {
  554         struct pmc_mdep *pmc_mdep;
  555         int error;
  556         uint16_t vers;
  557         
  558         /*
  559          * Allocate space for pointers to PMC HW descriptors and for
  560          * the MDEP structure used by MI code.
  561          */
  562         powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC,
  563                            M_WAITOK|M_ZERO);
  564 
  565         /* Just one class */
  566         pmc_mdep = pmc_mdep_alloc(1);
  567 
  568         vers = mfpvr() >> 16;
  569 
  570         pmc_mdep->pmd_switch_in  = powerpc_switch_in;
  571         pmc_mdep->pmd_switch_out = powerpc_switch_out;
  572         
  573         switch (vers) {
  574         case MPC7447A:
  575         case MPC7448:
  576         case MPC7450:
  577         case MPC7455:
  578         case MPC7457:
  579                 error = pmc_mpc7xxx_initialize(pmc_mdep);
  580                 break;
  581         case IBM970:
  582         case IBM970FX:
  583         case IBM970MP:
  584                 error = pmc_ppc970_initialize(pmc_mdep);
  585                 break;
  586         case IBMPOWER8E:
  587         case IBMPOWER8NVL:
  588         case IBMPOWER8:
  589         case IBMPOWER9:
  590                 error = pmc_power8_initialize(pmc_mdep);
  591                 break;
  592         case FSL_E500v1:
  593         case FSL_E500v2:
  594         case FSL_E500mc:
  595         case FSL_E5500:
  596                 error = pmc_e500_initialize(pmc_mdep);
  597                 break;
  598         default:
  599                 error = -1;
  600                 break;
  601         }
  602 
  603         if (error != 0) {
  604                 pmc_mdep_free(pmc_mdep);
  605                 pmc_mdep = NULL;
  606         }
  607 
  608         /* Set the value for kern.hwpmc.cpuid */
  609         snprintf(pmc_cpuid, sizeof(pmc_cpuid), "%08x", mfpvr());
  610 
  611         return (pmc_mdep);
  612 }
  613 
  614 void
  615 pmc_md_finalize(struct pmc_mdep *md)
  616 {
  617 
  618         free(powerpc_pcpu, M_PMC);
  619         powerpc_pcpu = NULL;
  620 }
  621 
  622 int
  623 pmc_save_user_callchain(uintptr_t *cc, int maxsamples,
  624     struct trapframe *tf)
  625 {
  626         uintptr_t *osp, *sp;
  627         int frames = 0;
  628 
  629         cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
  630         sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
  631         osp = NULL;
  632 
  633         for (; frames < maxsamples; frames++) {
  634                 if (sp <= osp)
  635                         break;
  636                 osp = sp;
  637 #ifdef __powerpc64__
  638                 /* Check if 32-bit mode. */
  639                 if (!(tf->srr1 & PSL_SF)) {
  640                         cc[frames] = fuword32((uint32_t *)sp + 1);
  641                         sp = (uintptr_t *)(uintptr_t)fuword32(sp);
  642                 } else {
  643                         cc[frames] = fuword(sp + 2);
  644                         sp = (uintptr_t *)fuword(sp);
  645                 }
  646 #else
  647                 cc[frames] = fuword32((uint32_t *)sp + 1);
  648                 sp = (uintptr_t *)fuword32(sp);
  649 #endif
  650         }
  651 
  652         return (frames);
  653 }

Cache object: 746b4a80de100b1ce39eb1275cf2987c


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