hwpmc_powerpc.c revision 294197
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 2011,2013 Justin Hibbits 31573Srgrimes * Copyright (c) 2005, Joseph Koshy 41573Srgrimes * All rights reserved. 51573Srgrimes * 61573Srgrimes * Redistribution and use in source and binary forms, with or without 71573Srgrimes * modification, are permitted provided that the following conditions 81573Srgrimes * are met: 91573Srgrimes * 1. Redistributions of source code must retain the above copyright 101573Srgrimes * notice, this list of conditions and the following disclaimer. 111573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer in the 131573Srgrimes * documentation and/or other materials provided with the distribution. 141573Srgrimes * 151573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16249808Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 191573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251573Srgrimes * SUCH DAMAGE. 261573Srgrimes * 271573Srgrimes */ 281573Srgrimes 291573Srgrimes#include <sys/cdefs.h> 301573Srgrimes__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_powerpc.c 294197 2016-01-17 00:14:22Z jhibbits $"); 311573Srgrimes 321573Srgrimes#include <sys/param.h> 331573Srgrimes#include <sys/pmc.h> 341573Srgrimes#include <sys/pmckern.h> 351573Srgrimes#include <sys/sysent.h> 3692986Sobrien#include <sys/systm.h> 3792986Sobrien 381573Srgrimes#include <machine/pmc_mdep.h> 39130230Sdas#include <machine/spr.h> 401573Srgrimes#include <machine/pte.h> 411573Srgrimes#include <machine/sr.h> 421573Srgrimes#include <machine/cpu.h> 431573Srgrimes#include <machine/stack.h> 441573Srgrimes 451573Srgrimes#include "hwpmc_powerpc.h" 461573Srgrimes 47130230Sdas#ifdef __powerpc64__ 481573Srgrimes#define OFFSET 4 /* Account for the TOC reload slot */ 4916586Sjraynard#else 50249810Semaste#define OFFSET 0 511573Srgrimes#endif 521573Srgrimes 531573Srgrimesstruct powerpc_cpu **powerpc_pcpu; 541573Srgrimes 551573Srgrimesint 561573Srgrimespmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, 571573Srgrimes struct trapframe *tf) 581573Srgrimes{ 591573Srgrimes uintptr_t *osp, *sp; 60130230Sdas uintptr_t pc; 61130230Sdas int frames = 0; 62186887Sdas 631573Srgrimes cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 64130230Sdas sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 651573Srgrimes osp = (uintptr_t *)PAGE_SIZE; 661573Srgrimes 671573Srgrimes for (; frames < maxsamples; frames++) { 681573Srgrimes if (sp <= osp) 691573Srgrimes break; 701573Srgrimes #ifdef __powerpc64__ 711573Srgrimes pc = sp[2]; 721573Srgrimes #else 731573Srgrimes pc = sp[1]; 741573Srgrimes #endif 751573Srgrimes if ((pc & 3) || (pc < 0x100)) 761573Srgrimes break; 771573Srgrimes 781573Srgrimes /* 791573Srgrimes * trapexit() and asttrapexit() are sentinels 801573Srgrimes * for kernel stack tracing. 811573Srgrimes * */ 821573Srgrimes if (pc + OFFSET == (uintptr_t) &trapexit || 831573Srgrimes pc + OFFSET == (uintptr_t) &asttrapexit) 841573Srgrimes break; 851573Srgrimes 861573Srgrimes cc[frames] = pc; 871573Srgrimes osp = sp; 881573Srgrimes sp = (uintptr_t *)*sp; 891573Srgrimes } 901573Srgrimes return (frames); 911573Srgrimes} 921573Srgrimes 93static int 94powerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 95{ 96 97 return (0); 98} 99 100static int 101powerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 102{ 103 104 return (0); 105} 106 107int 108powerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 109{ 110 int error; 111 struct pmc_hw *phw; 112 char powerpc_name[PMC_NAME_MAX]; 113 114 KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 115 ("[powerpc,%d], illegal CPU %d", __LINE__, cpu)); 116 117 phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 118 snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri); 119 if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX, 120 NULL)) != 0) 121 return error; 122 pi->pm_class = powerpc_pcpu[cpu]->pc_class; 123 if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 124 pi->pm_enabled = TRUE; 125 *ppmc = phw->phw_pmc; 126 } else { 127 pi->pm_enabled = FALSE; 128 *ppmc = NULL; 129 } 130 131 return (0); 132} 133 134int 135powerpc_get_config(int cpu, int ri, struct pmc **ppm) 136{ 137 138 *ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 139 140 return (0); 141} 142 143struct pmc_mdep * 144pmc_md_initialize() 145{ 146 struct pmc_mdep *pmc_mdep; 147 int error; 148 uint16_t vers; 149 150 /* 151 * Allocate space for pointers to PMC HW descriptors and for 152 * the MDEP structure used by MI code. 153 */ 154 powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC, 155 M_WAITOK|M_ZERO); 156 157 /* Just one class */ 158 pmc_mdep = pmc_mdep_alloc(1); 159 160 vers = mfpvr() >> 16; 161 162 pmc_mdep->pmd_switch_in = powerpc_switch_in; 163 pmc_mdep->pmd_switch_out = powerpc_switch_out; 164 165 switch (vers) { 166 case MPC7447A: 167 case MPC7448: 168 case MPC7450: 169 case MPC7455: 170 case MPC7457: 171 error = pmc_mpc7xxx_initialize(pmc_mdep); 172 break; 173 case IBM970: 174 case IBM970FX: 175 case IBM970MP: 176 error = pmc_ppc970_initialize(pmc_mdep); 177 break; 178 case FSL_E500v1: 179 case FSL_E500v2: 180 case FSL_E500mc: 181 case FSL_E5500: 182 error = pmc_e500_initialize(pmc_mdep); 183 break; 184 default: 185 error = -1; 186 break; 187 } 188 189 if (error != 0) { 190 pmc_mdep_free(pmc_mdep); 191 pmc_mdep = NULL; 192 } 193 194 return (pmc_mdep); 195} 196 197void 198pmc_md_finalize(struct pmc_mdep *md) 199{ 200 201 free(powerpc_pcpu, M_PMC); 202 powerpc_pcpu = NULL; 203} 204 205int 206pmc_save_user_callchain(uintptr_t *cc, int maxsamples, 207 struct trapframe *tf) 208{ 209 uintptr_t *osp, *sp; 210 int frames = 0; 211 212 cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 213 sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 214 osp = NULL; 215 216 for (; frames < maxsamples; frames++) { 217 if (sp <= osp) 218 break; 219 osp = sp; 220#ifdef __powerpc64__ 221 /* Check if 32-bit mode. */ 222 if (!(tf->srr1 & PSL_SF)) { 223 cc[frames] = fuword32((uint32_t *)sp + 1); 224 sp = (uintptr_t *)(uintptr_t)fuword32(sp); 225 } else { 226 cc[frames] = fuword(sp + 2); 227 sp = (uintptr_t *)fuword(sp); 228 } 229#else 230 cc[frames] = fuword32((uint32_t *)sp + 1); 231 sp = (uintptr_t *)fuword32(sp); 232#endif 233 } 234 235 return (frames); 236} 237