1147191Sjkoshy/*- 2255164Sjhibbits * Copyright (c) 2011,2013 Justin Hibbits 3147191Sjkoshy * Copyright (c) 2005, Joseph Koshy 4147191Sjkoshy * All rights reserved. 5147191Sjkoshy * 6147191Sjkoshy * Redistribution and use in source and binary forms, with or without 7147191Sjkoshy * modification, are permitted provided that the following conditions 8147191Sjkoshy * are met: 9147191Sjkoshy * 1. Redistributions of source code must retain the above copyright 10147191Sjkoshy * notice, this list of conditions and the following disclaimer. 11147191Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 12147191Sjkoshy * notice, this list of conditions and the following disclaimer in the 13147191Sjkoshy * documentation and/or other materials provided with the distribution. 14147191Sjkoshy * 15147191Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16147191Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17147191Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18147191Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19147191Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20147191Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21147191Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22147191Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23147191Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24147191Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25147191Sjkoshy * SUCH DAMAGE. 26147191Sjkoshy * 27147191Sjkoshy */ 28147191Sjkoshy 29147191Sjkoshy#include <sys/cdefs.h> 30147191Sjkoshy__FBSDID("$FreeBSD$"); 31147191Sjkoshy 32147191Sjkoshy#include <sys/param.h> 33147191Sjkoshy#include <sys/pmc.h> 34228869Sjhibbits#include <sys/pmckern.h> 35262547Sjhibbits#include <sys/sysent.h> 36228869Sjhibbits#include <sys/systm.h> 37147191Sjkoshy 38147191Sjkoshy#include <machine/pmc_mdep.h> 39228869Sjhibbits#include <machine/spr.h> 40255199Sjhibbits#include <machine/pte.h> 41255199Sjhibbits#include <machine/sr.h> 42228869Sjhibbits#include <machine/cpu.h> 43271602Sjhibbits#include <machine/stack.h> 44147191Sjkoshy 45255164Sjhibbits#include "hwpmc_powerpc.h" 46174410Sjkoshy 47271602Sjhibbits#ifdef __powerpc64__ 48271602Sjhibbits#define OFFSET 4 /* Account for the TOC reload slot */ 49271602Sjhibbits#else 50271602Sjhibbits#define OFFSET 0 51271602Sjhibbits#endif 52185168Sjkoshy 53255228Sjhibbitsstruct powerpc_cpu **powerpc_pcpu; 54255228Sjhibbits 55174410Sjkoshyint 56174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, 57174410Sjkoshy struct trapframe *tf) 58174410Sjkoshy{ 59268207Sjhibbits uintptr_t *osp, *sp; 60271602Sjhibbits uintptr_t pc; 61255164Sjhibbits int frames = 0; 62174410Sjkoshy 63259395Sjhibbits cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 64259395Sjhibbits sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 65271602Sjhibbits osp = (uintptr_t *)PAGE_SIZE; 66228869Sjhibbits 67262547Sjhibbits for (; frames < maxsamples; frames++) { 68271602Sjhibbits if (sp <= osp) 69228869Sjhibbits break; 70271602Sjhibbits #ifdef __powerpc64__ 71271602Sjhibbits pc = sp[2]; 72271602Sjhibbits #else 73271602Sjhibbits pc = sp[1]; 74271602Sjhibbits #endif 75271602Sjhibbits if ((pc & 3) || (pc < 0x100)) 76271602Sjhibbits break; 77271602Sjhibbits 78271602Sjhibbits /* 79271602Sjhibbits * trapexit() and asttrapexit() are sentinels 80271602Sjhibbits * for kernel stack tracing. 81271602Sjhibbits * */ 82271602Sjhibbits if (pc + OFFSET == (uintptr_t) &trapexit || 83271602Sjhibbits pc + OFFSET == (uintptr_t) &asttrapexit) 84271602Sjhibbits break; 85271602Sjhibbits 86271602Sjhibbits cc[frames] = pc; 87268207Sjhibbits osp = sp; 88255164Sjhibbits sp = (uintptr_t *)*sp; 89228869Sjhibbits } 90255164Sjhibbits return (frames); 91228869Sjhibbits} 92228869Sjhibbits 93228869Sjhibbitsstatic int 94228869Sjhibbitspowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 95228869Sjhibbits{ 96262547Sjhibbits 97255164Sjhibbits return (0); 98228869Sjhibbits} 99228869Sjhibbits 100228869Sjhibbitsstatic int 101228869Sjhibbitspowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 102228869Sjhibbits{ 103262547Sjhibbits 104255164Sjhibbits return (0); 105228869Sjhibbits} 106228869Sjhibbits 107255164Sjhibbitsint 108228869Sjhibbitspowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 109228869Sjhibbits{ 110228869Sjhibbits int error; 111228869Sjhibbits struct pmc_hw *phw; 112228869Sjhibbits char powerpc_name[PMC_NAME_MAX]; 113228869Sjhibbits 114228869Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 115228869Sjhibbits ("[powerpc,%d], illegal CPU %d", __LINE__, cpu)); 116228869Sjhibbits 117228869Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 118228869Sjhibbits snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri); 119228869Sjhibbits if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX, 120228869Sjhibbits NULL)) != 0) 121228869Sjhibbits return error; 122261342Sjhibbits pi->pm_class = powerpc_pcpu[cpu]->pc_class; 123228869Sjhibbits if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 124228869Sjhibbits pi->pm_enabled = TRUE; 125228869Sjhibbits *ppmc = phw->phw_pmc; 126228869Sjhibbits } else { 127228869Sjhibbits pi->pm_enabled = FALSE; 128228869Sjhibbits *ppmc = NULL; 129228869Sjhibbits } 130228869Sjhibbits 131228869Sjhibbits return (0); 132228869Sjhibbits} 133228869Sjhibbits 134255164Sjhibbitsint 135228869Sjhibbitspowerpc_get_config(int cpu, int ri, struct pmc **ppm) 136228869Sjhibbits{ 137262547Sjhibbits 138228869Sjhibbits *ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 139228869Sjhibbits 140255164Sjhibbits return (0); 141228869Sjhibbits} 142228869Sjhibbits 143228869Sjhibbitsstruct pmc_mdep * 144228869Sjhibbitspmc_md_initialize() 145228869Sjhibbits{ 146228869Sjhibbits struct pmc_mdep *pmc_mdep; 147255164Sjhibbits int error; 148255164Sjhibbits uint16_t vers; 149228869Sjhibbits 150228869Sjhibbits /* 151228869Sjhibbits * Allocate space for pointers to PMC HW descriptors and for 152228869Sjhibbits * the MDEP structure used by MI code. 153228869Sjhibbits */ 154228869Sjhibbits powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC, 155228869Sjhibbits M_WAITOK|M_ZERO); 156228869Sjhibbits 157228869Sjhibbits /* Just one class */ 158234598Sfabient pmc_mdep = pmc_mdep_alloc(1); 159228869Sjhibbits 160255164Sjhibbits vers = mfpvr() >> 16; 161228869Sjhibbits 162228869Sjhibbits pmc_mdep->pmd_switch_in = powerpc_switch_in; 163228869Sjhibbits pmc_mdep->pmd_switch_out = powerpc_switch_out; 164228869Sjhibbits 165255164Sjhibbits switch (vers) { 166255164Sjhibbits case MPC7447A: 167255164Sjhibbits case MPC7448: 168255164Sjhibbits case MPC7450: 169255164Sjhibbits case MPC7455: 170255164Sjhibbits case MPC7457: 171255164Sjhibbits error = pmc_mpc7xxx_initialize(pmc_mdep); 172261173Sjhibbits break; 173255164Sjhibbits case IBM970: 174255164Sjhibbits case IBM970FX: 175255164Sjhibbits case IBM970MP: 176261342Sjhibbits error = pmc_ppc970_initialize(pmc_mdep); 177261342Sjhibbits break; 178281713Sjhibbits case FSL_E500v1: 179281713Sjhibbits case FSL_E500v2: 180281713Sjhibbits case FSL_E500mc: 181294197Sjhibbits case FSL_E5500: 182281713Sjhibbits error = pmc_e500_initialize(pmc_mdep); 183281713Sjhibbits break; 184255164Sjhibbits default: 185255164Sjhibbits error = -1; 186255164Sjhibbits break; 187255164Sjhibbits } 188228869Sjhibbits 189255164Sjhibbits if (error != 0) { 190255164Sjhibbits pmc_mdep_free(pmc_mdep); 191255164Sjhibbits pmc_mdep = NULL; 192255164Sjhibbits } 193255164Sjhibbits 194228869Sjhibbits return (pmc_mdep); 195228869Sjhibbits} 196228869Sjhibbits 197228869Sjhibbitsvoid 198228869Sjhibbitspmc_md_finalize(struct pmc_mdep *md) 199228869Sjhibbits{ 200261342Sjhibbits 201261342Sjhibbits free(powerpc_pcpu, M_PMC); 202261342Sjhibbits powerpc_pcpu = NULL; 203228869Sjhibbits} 204228869Sjhibbits 205174410Sjkoshyint 206174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples, 207174410Sjkoshy struct trapframe *tf) 208174410Sjkoshy{ 209268207Sjhibbits uintptr_t *osp, *sp; 210259395Sjhibbits int frames = 0; 211259395Sjhibbits 212259395Sjhibbits cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 213259395Sjhibbits sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 214268207Sjhibbits osp = NULL; 215259395Sjhibbits 216262547Sjhibbits for (; frames < maxsamples; frames++) { 217271602Sjhibbits if (sp <= osp) 218259395Sjhibbits break; 219268207Sjhibbits osp = sp; 220262547Sjhibbits#ifdef __powerpc64__ 221262547Sjhibbits /* Check if 32-bit mode. */ 222262547Sjhibbits if (!(tf->srr1 & PSL_SF)) { 223268207Sjhibbits cc[frames] = fuword32((uint32_t *)sp + 1); 224262547Sjhibbits sp = (uintptr_t *)(uintptr_t)fuword32(sp); 225262547Sjhibbits } else { 226268207Sjhibbits cc[frames] = fuword(sp + 2); 227262547Sjhibbits sp = (uintptr_t *)fuword(sp); 228262547Sjhibbits } 229262547Sjhibbits#else 230268207Sjhibbits cc[frames] = fuword32((uint32_t *)sp + 1); 231262547Sjhibbits sp = (uintptr_t *)fuword32(sp); 232262547Sjhibbits#endif 233259395Sjhibbits } 234262547Sjhibbits 235259395Sjhibbits return (frames); 236174410Sjkoshy} 237