hwpmc_powerpc.c revision 255199
1251881Speter/*- 2251881Speter * Copyright (c) 2011,2013 Justin Hibbits 3251881Speter * Copyright (c) 2005, Joseph Koshy 4251881Speter * All rights reserved. 5251881Speter * 6251881Speter * Redistribution and use in source and binary forms, with or without 7251881Speter * modification, are permitted provided that the following conditions 8251881Speter * are met: 9251881Speter * 1. Redistributions of source code must retain the above copyright 10251881Speter * notice, this list of conditions and the following disclaimer. 11251881Speter * 2. Redistributions in binary form must reproduce the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer in the 13251881Speter * documentation and/or other materials provided with the distribution. 14251881Speter * 15251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25251881Speter * SUCH DAMAGE. 26251881Speter * 27251881Speter */ 28251881Speter 29251881Speter#include <sys/cdefs.h> 30251881Speter__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_powerpc.c 255199 2013-09-04 04:11:38Z jhibbits $"); 31251881Speter 32251881Speter#include <sys/param.h> 33251881Speter#include <sys/pmc.h> 34251881Speter#include <sys/pmckern.h> 35251881Speter#include <sys/systm.h> 36251881Speter 37251881Speter#include <machine/pmc_mdep.h> 38251881Speter#include <machine/spr.h> 39251881Speter#include <machine/pte.h> 40251881Speter#include <machine/sr.h> 41251881Speter#include <machine/cpu.h> 42251881Speter#include <machine/vmparam.h> /* For VM_MIN_KERNEL_ADDRESS/VM_MAX_KERNEL_ADDRESS */ 43251881Speter 44251881Speter#include "hwpmc_powerpc.h" 45251881Speter 46251881Speter#define INKERNEL(x) (((vm_offset_t)(x)) <= VM_MAX_KERNEL_ADDRESS && \ 47251881Speter ((vm_offset_t)(x)) >= VM_MIN_KERNEL_ADDRESS) 48251881Speter 49251881Speterint 50251881Speterpmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, 51251881Speter struct trapframe *tf) 52251881Speter{ 53251881Speter int frames = 0; 54251881Speter uintptr_t *sp; 55251881Speter 56251881Speter cc[frames++] = tf->srr0; 57251881Speter sp = (uintptr_t *)tf->fixreg[1]; 58251881Speter 59251881Speter for (frames = 1; frames < maxsamples; frames++) { 60251881Speter if (!INKERNEL(sp)) 61251881Speter break; 62251881Speter cc[frames++] = *(sp + 1); 63251881Speter sp = (uintptr_t *)*sp; 64251881Speter } 65251881Speter return (frames); 66251881Speter} 67251881Speter 68251881Speterstatic int 69251881Speterpowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 70251881Speter{ 71251881Speter return (0); 72251881Speter} 73251881Speter 74251881Speterstatic int 75251881Speterpowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 76251881Speter{ 77251881Speter return (0); 78251881Speter} 79251881Speter 80251881Speterint 81251881Speterpowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) 82251881Speter{ 83251881Speter int error; 84251881Speter struct pmc_hw *phw; 85251881Speter char powerpc_name[PMC_NAME_MAX]; 86251881Speter 87251881Speter KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), 88251881Speter ("[powerpc,%d], illegal CPU %d", __LINE__, cpu)); 89251881Speter 90251881Speter phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri]; 91251881Speter snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri); 92251881Speter if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX, 93251881Speter NULL)) != 0) 94251881Speter return error; 95251881Speter pi->pm_class = PMC_CLASS_PPC7450; 96251881Speter if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { 97251881Speter pi->pm_enabled = TRUE; 98251881Speter *ppmc = phw->phw_pmc; 99251881Speter } else { 100251881Speter pi->pm_enabled = FALSE; 101251881Speter *ppmc = NULL; 102251881Speter } 103251881Speter 104251881Speter return (0); 105251881Speter} 106251881Speter 107251881Speterint 108251881Speterpowerpc_get_config(int cpu, int ri, struct pmc **ppm) 109251881Speter{ 110251881Speter *ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc; 111251881Speter 112251881Speter return (0); 113251881Speter} 114251881Speter 115251881Speterstruct pmc_mdep * 116251881Speterpmc_md_initialize() 117251881Speter{ 118251881Speter struct pmc_mdep *pmc_mdep; 119251881Speter int error; 120251881Speter uint16_t vers; 121251881Speter 122251881Speter /* 123251881Speter * Allocate space for pointers to PMC HW descriptors and for 124299742Sdim * the MDEP structure used by MI code. 125299742Sdim */ 126299742Sdim powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC, 127299742Sdim M_WAITOK|M_ZERO); 128299742Sdim 129299742Sdim /* Just one class */ 130299742Sdim pmc_mdep = pmc_mdep_alloc(1); 131299742Sdim 132299742Sdim pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450; 133299742Sdim 134299742Sdim vers = mfpvr() >> 16; 135299742Sdim 136299742Sdim pmc_mdep->pmd_switch_in = powerpc_switch_in; 137299742Sdim pmc_mdep->pmd_switch_out = powerpc_switch_out; 138299742Sdim 139299742Sdim switch (vers) { 140251881Speter case MPC7447A: 141299742Sdim case MPC7448: 142299742Sdim case MPC7450: 143299742Sdim case MPC7455: 144251881Speter case MPC7457: 145251881Speter error = pmc_mpc7xxx_initialize(pmc_mdep); 146251881Speter case IBM970: 147251881Speter case IBM970FX: 148251881Speter case IBM970MP: 149299742Sdim default: 150251881Speter error = -1; 151251881Speter break; 152251881Speter } 153251881Speter 154251881Speter if (error != 0) { 155251881Speter pmc_mdep_free(pmc_mdep); 156251881Speter pmc_mdep = NULL; 157251881Speter return NULL; 158251881Speter } 159251881Speter 160251881Speter return (pmc_mdep); 161251881Speter} 162251881Speter 163251881Spetervoid 164251881Speterpmc_md_finalize(struct pmc_mdep *md) 165251881Speter{ 166251881Speter free(md, M_PMC); 167251881Speter} 168251881Speter 169251881Speterint 170251881Speterpmc_save_user_callchain(uintptr_t *cc, int maxsamples, 171251881Speter struct trapframe *tf) 172251881Speter{ 173251881Speter (void) cc; 174251881Speter (void) maxsamples; 175251881Speter (void) tf; 176251881Speter return (0); 177251881Speter} 178251881Speter