1/* 2 * PPC 64 oprofile support: 3 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM 4 * PPC 32 oprofile support: (based on PPC 64 support) 5 * Copyright (C) Freescale Semiconductor, Inc 2004 6 * Author: Andy Fleming 7 * 8 * Based on alpha version. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 13 * 2 of the License, or (at your option) any later version. 14 */ 15 16#include <linux/oprofile.h> 17#include <linux/init.h> 18#include <linux/smp.h> 19#include <linux/errno.h> 20#include <asm/ptrace.h> 21#include <asm/system.h> 22#include <asm/pmc.h> 23#include <asm/cputable.h> 24#include <asm/oprofile_impl.h> 25#include <asm/firmware.h> 26 27static struct op_powerpc_model *model; 28 29static struct op_counter_config ctr[OP_MAX_COUNTER]; 30static struct op_system_config sys; 31 32static void op_handle_interrupt(struct pt_regs *regs) 33{ 34 model->handle_interrupt(regs, ctr); 35} 36 37static void op_powerpc_cpu_setup(void *dummy) 38{ 39 model->cpu_setup(ctr); 40} 41 42static int op_powerpc_setup(void) 43{ 44 int err; 45 46 /* Grab the hardware */ 47 err = reserve_pmc_hardware(op_handle_interrupt); 48 if (err) 49 return err; 50 51 /* Pre-compute the values to stuff in the hardware registers. */ 52 model->reg_setup(ctr, &sys, model->num_counters); 53 54 /* Configure the registers on all cpus. */ 55 on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1); 56 57 return 0; 58} 59 60static void op_powerpc_shutdown(void) 61{ 62 release_pmc_hardware(); 63} 64 65static void op_powerpc_cpu_start(void *dummy) 66{ 67 model->start(ctr); 68} 69 70static int op_powerpc_start(void) 71{ 72 if (model->global_start) 73 model->global_start(ctr); 74 if (model->start) 75 on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1); 76 return 0; 77} 78 79static inline void op_powerpc_cpu_stop(void *dummy) 80{ 81 model->stop(); 82} 83 84static void op_powerpc_stop(void) 85{ 86 if (model->stop) 87 on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1); 88 if (model->global_stop) 89 model->global_stop(); 90} 91 92static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) 93{ 94 int i; 95 96#ifdef CONFIG_PPC64 97 /* 98 * There is one mmcr0, mmcr1 and mmcra for setting the events for 99 * all of the counters. 100 */ 101 oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0); 102 oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1); 103 oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra); 104#endif 105 106 for (i = 0; i < model->num_counters; ++i) { 107 struct dentry *dir; 108 char buf[4]; 109 110 snprintf(buf, sizeof buf, "%d", i); 111 dir = oprofilefs_mkdir(sb, root, buf); 112 113 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); 114 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); 115 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); 116 117 /* 118 * Classic PowerPC doesn't support per-counter 119 * control like this, but the options are 120 * expected, so they remain. For Freescale 121 * Book-E style performance monitors, we do 122 * support them. 123 */ 124 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); 125 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); 126 127 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask); 128 } 129 130 oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); 131 oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); 132 133 /* Default to tracing both kernel and user */ 134 sys.enable_kernel = 1; 135 sys.enable_user = 1; 136 137 return 0; 138} 139 140int __init oprofile_arch_init(struct oprofile_operations *ops) 141{ 142 if (!cur_cpu_spec->oprofile_cpu_type) 143 return -ENODEV; 144 145 if (firmware_has_feature(FW_FEATURE_ISERIES)) 146 return -ENODEV; 147 148 switch (cur_cpu_spec->oprofile_type) { 149#ifdef CONFIG_PPC64 150#ifdef CONFIG_PPC_CELL_NATIVE 151 case PPC_OPROFILE_CELL: 152 if (firmware_has_feature(FW_FEATURE_LPAR)) 153 return -ENODEV; 154 model = &op_model_cell; 155 break; 156#endif 157 case PPC_OPROFILE_RS64: 158 model = &op_model_rs64; 159 break; 160 case PPC_OPROFILE_POWER4: 161 model = &op_model_power4; 162 break; 163 case PPC_OPROFILE_PA6T: 164 model = &op_model_pa6t; 165 break; 166#endif 167#ifdef CONFIG_6xx 168 case PPC_OPROFILE_G4: 169 model = &op_model_7450; 170 break; 171#endif 172#ifdef CONFIG_FSL_BOOKE 173 case PPC_OPROFILE_BOOKE: 174 model = &op_model_fsl_booke; 175 break; 176#endif 177 default: 178 return -ENODEV; 179 } 180 181 model->num_counters = cur_cpu_spec->num_pmcs; 182 183 ops->cpu_type = cur_cpu_spec->oprofile_cpu_type; 184 ops->create_files = op_powerpc_create_files; 185 ops->setup = op_powerpc_setup; 186 ops->shutdown = op_powerpc_shutdown; 187 ops->start = op_powerpc_start; 188 ops->stop = op_powerpc_stop; 189 ops->backtrace = op_powerpc_backtrace; 190 191 printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n", 192 ops->cpu_type); 193 194 return 0; 195} 196 197void oprofile_arch_exit(void) 198{ 199} 200