hwpmc_powerpc.c revision 261173
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: head/sys/dev/hwpmc/hwpmc_powerpc.c 261173 2014-01-25 22:50:42Z jhibbits $"); 31147191Sjkoshy 32147191Sjkoshy#include <sys/param.h> 33147191Sjkoshy#include <sys/pmc.h> 34228869Sjhibbits#include <sys/pmckern.h> 35228869Sjhibbits#include <sys/systm.h> 36147191Sjkoshy 37147191Sjkoshy#include <machine/pmc_mdep.h> 38228869Sjhibbits#include <machine/spr.h> 39255199Sjhibbits#include <machine/pte.h> 40255199Sjhibbits#include <machine/sr.h> 41228869Sjhibbits#include <machine/cpu.h> 42255164Sjhibbits#include <machine/vmparam.h> /* For VM_MIN_KERNEL_ADDRESS/VM_MAX_KERNEL_ADDRESS */ 43147191Sjkoshy 44255164Sjhibbits#include "hwpmc_powerpc.h" 45174410Sjkoshy 46255164Sjhibbits#define INKERNEL(x) (((vm_offset_t)(x)) <= VM_MAX_KERNEL_ADDRESS && \ 47255164Sjhibbits ((vm_offset_t)(x)) >= VM_MIN_KERNEL_ADDRESS) 48259395Sjhibbits#define INUSER(x) (((vm_offset_t)(x)) <= VM_MAXUSER_ADDRESS && \ 49259395Sjhibbits ((vm_offset_t)(x)) >= VM_MIN_ADDRESS) 50185168Sjkoshy 51255228Sjhibbitsstruct powerpc_cpu **powerpc_pcpu; 52255228Sjhibbits 53174410Sjkoshyint 54174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, 55174410Sjkoshy struct trapframe *tf) 56174410Sjkoshy{ 57255164Sjhibbits int frames = 0; 58255164Sjhibbits uintptr_t *sp; 59174410Sjkoshy 60259395Sjhibbits cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 61259395Sjhibbits sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 62228869Sjhibbits 63255164Sjhibbits for (frames = 1; frames < maxsamples; frames++) { 64255164Sjhibbits if (!INKERNEL(sp)) 65228869Sjhibbits break; 66259395Sjhibbits cc[frames++] = sp[1]; 67255164Sjhibbits sp = (uintptr_t *)*sp; 68228869Sjhibbits } 69255164Sjhibbits return (frames); 70228869Sjhibbits} 71228869Sjhibbits 72228869Sjhibbitsstatic int 73228869Sjhibbitspowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 74228869Sjhibbits{ 75255164Sjhibbits return (0); 76228869Sjhibbits} 77228869Sjhibbits 78228869Sjhibbitsstatic int 79228869Sjhibbitspowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 80228869Sjhibbits{ 81255164Sjhibbits return (0); 82228869Sjhibbits} 83228869Sjhibbits 84255164Sjhibbitsint 85228869Sjhibbitspowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 86228869Sjhibbits{ 87228869Sjhibbits int error; 88228869Sjhibbits struct pmc_hw *phw; 89228869Sjhibbits char powerpc_name[PMC_NAME_MAX]; 90228869Sjhibbits 91228869Sjhibbits KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 92228869Sjhibbits ("[powerpc,%d], illegal CPU %d", __LINE__, cpu)); 93228869Sjhibbits 94228869Sjhibbits phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 95228869Sjhibbits snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri); 96228869Sjhibbits if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX, 97228869Sjhibbits NULL)) != 0) 98228869Sjhibbits return error; 99228869Sjhibbits pi->pm_class = PMC_CLASS_PPC7450; 100228869Sjhibbits if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 101228869Sjhibbits pi->pm_enabled = TRUE; 102228869Sjhibbits *ppmc = phw->phw_pmc; 103228869Sjhibbits } else { 104228869Sjhibbits pi->pm_enabled = FALSE; 105228869Sjhibbits *ppmc = NULL; 106228869Sjhibbits } 107228869Sjhibbits 108228869Sjhibbits return (0); 109228869Sjhibbits} 110228869Sjhibbits 111255164Sjhibbitsint 112228869Sjhibbitspowerpc_get_config(int cpu, int ri, struct pmc **ppm) 113228869Sjhibbits{ 114228869Sjhibbits *ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 115228869Sjhibbits 116255164Sjhibbits return (0); 117228869Sjhibbits} 118228869Sjhibbits 119228869Sjhibbitsstruct pmc_mdep * 120228869Sjhibbitspmc_md_initialize() 121228869Sjhibbits{ 122228869Sjhibbits struct pmc_mdep *pmc_mdep; 123255164Sjhibbits int error; 124255164Sjhibbits uint16_t vers; 125228869Sjhibbits 126228869Sjhibbits /* 127228869Sjhibbits * Allocate space for pointers to PMC HW descriptors and for 128228869Sjhibbits * the MDEP structure used by MI code. 129228869Sjhibbits */ 130228869Sjhibbits powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC, 131228869Sjhibbits M_WAITOK|M_ZERO); 132228869Sjhibbits 133228869Sjhibbits /* Just one class */ 134234598Sfabient pmc_mdep = pmc_mdep_alloc(1); 135228869Sjhibbits 136228869Sjhibbits pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450; 137228869Sjhibbits 138255164Sjhibbits vers = mfpvr() >> 16; 139228869Sjhibbits 140228869Sjhibbits pmc_mdep->pmd_switch_in = powerpc_switch_in; 141228869Sjhibbits pmc_mdep->pmd_switch_out = powerpc_switch_out; 142228869Sjhibbits 143255164Sjhibbits switch (vers) { 144255164Sjhibbits case MPC7447A: 145255164Sjhibbits case MPC7448: 146255164Sjhibbits case MPC7450: 147255164Sjhibbits case MPC7455: 148255164Sjhibbits case MPC7457: 149255164Sjhibbits error = pmc_mpc7xxx_initialize(pmc_mdep); 150261173Sjhibbits break; 151255164Sjhibbits case IBM970: 152255164Sjhibbits case IBM970FX: 153255164Sjhibbits case IBM970MP: 154255164Sjhibbits default: 155255164Sjhibbits error = -1; 156255164Sjhibbits break; 157255164Sjhibbits } 158228869Sjhibbits 159255164Sjhibbits if (error != 0) { 160255164Sjhibbits pmc_mdep_free(pmc_mdep); 161255164Sjhibbits pmc_mdep = NULL; 162255164Sjhibbits return NULL; 163255164Sjhibbits } 164255164Sjhibbits 165228869Sjhibbits return (pmc_mdep); 166228869Sjhibbits} 167228869Sjhibbits 168228869Sjhibbitsvoid 169228869Sjhibbitspmc_md_finalize(struct pmc_mdep *md) 170228869Sjhibbits{ 171228869Sjhibbits free(md, M_PMC); 172228869Sjhibbits} 173228869Sjhibbits 174174410Sjkoshyint 175174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples, 176174410Sjkoshy struct trapframe *tf) 177174410Sjkoshy{ 178259395Sjhibbits uintptr_t *sp; 179259395Sjhibbits int frames = 0; 180259395Sjhibbits 181259395Sjhibbits cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); 182259395Sjhibbits sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); 183259395Sjhibbits 184259395Sjhibbits for (frames = 1; frames < maxsamples; frames++) { 185259395Sjhibbits if (!INUSER(sp)) 186259395Sjhibbits break; 187259395Sjhibbits cc[frames++] = fuword(sp + 1); 188259395Sjhibbits sp = (uintptr_t *)fuword(sp); 189259395Sjhibbits } 190259395Sjhibbits return (frames); 191174410Sjkoshy} 192