Back to home page

LXR

 
 

    


0001 /*
0002  * PPC 64 oprofile support:
0003  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
0004  * PPC 32 oprofile support: (based on PPC 64 support)
0005  * Copyright (C) Freescale Semiconductor, Inc 2004
0006  *  Author: Andy Fleming
0007  *
0008  * Based on alpha version.
0009  *
0010  * This program is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU General Public License
0012  * as published by the Free Software Foundation; either version
0013  * 2 of the License, or (at your option) any later version.
0014  */
0015 
0016 #include <linux/oprofile.h>
0017 #include <linux/init.h>
0018 #include <linux/smp.h>
0019 #include <linux/errno.h>
0020 #include <asm/ptrace.h>
0021 #include <asm/pmc.h>
0022 #include <asm/cputable.h>
0023 #include <asm/oprofile_impl.h>
0024 #include <asm/firmware.h>
0025 
0026 static struct op_powerpc_model *model;
0027 
0028 static struct op_counter_config ctr[OP_MAX_COUNTER];
0029 static struct op_system_config sys;
0030 
0031 static int op_per_cpu_rc;
0032 
0033 static void op_handle_interrupt(struct pt_regs *regs)
0034 {
0035     model->handle_interrupt(regs, ctr);
0036 }
0037 
0038 static void op_powerpc_cpu_setup(void *dummy)
0039 {
0040     int ret;
0041 
0042     ret = model->cpu_setup(ctr);
0043 
0044     if (ret != 0)
0045         op_per_cpu_rc = ret;
0046 }
0047 
0048 static int op_powerpc_setup(void)
0049 {
0050     int err;
0051 
0052     op_per_cpu_rc = 0;
0053 
0054     /* Grab the hardware */
0055     err = reserve_pmc_hardware(op_handle_interrupt);
0056     if (err)
0057         return err;
0058 
0059     /* Pre-compute the values to stuff in the hardware registers.  */
0060     op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
0061 
0062     if (op_per_cpu_rc)
0063         goto out;
0064 
0065     /* Configure the registers on all cpus.  If an error occurs on one
0066      * of the cpus, op_per_cpu_rc will be set to the error */
0067     on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
0068 
0069 out:    if (op_per_cpu_rc) {
0070         /* error on setup release the performance counter hardware */
0071         release_pmc_hardware();
0072     }
0073 
0074     return op_per_cpu_rc;
0075 }
0076 
0077 static void op_powerpc_shutdown(void)
0078 {
0079     release_pmc_hardware();
0080 }
0081 
0082 static void op_powerpc_cpu_start(void *dummy)
0083 {
0084     /* If any of the cpus have return an error, set the
0085      * global flag to the error so it can be returned
0086      * to the generic OProfile caller.
0087      */
0088     int ret;
0089 
0090     ret = model->start(ctr);
0091     if (ret != 0)
0092         op_per_cpu_rc = ret;
0093 }
0094 
0095 static int op_powerpc_start(void)
0096 {
0097     op_per_cpu_rc = 0;
0098 
0099     if (model->global_start)
0100         return model->global_start(ctr);
0101     if (model->start) {
0102         on_each_cpu(op_powerpc_cpu_start, NULL, 1);
0103         return op_per_cpu_rc;
0104     }
0105     return -EIO; /* No start function is defined for this
0106             power architecture */
0107 }
0108 
0109 static inline void op_powerpc_cpu_stop(void *dummy)
0110 {
0111     model->stop();
0112 }
0113 
0114 static void op_powerpc_stop(void)
0115 {
0116     if (model->stop)
0117         on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
0118         if (model->global_stop)
0119                 model->global_stop();
0120 }
0121 
0122 static int op_powerpc_create_files(struct dentry *root)
0123 {
0124     int i;
0125 
0126 #ifdef CONFIG_PPC64
0127     /*
0128      * There is one mmcr0, mmcr1 and mmcra for setting the events for
0129      * all of the counters.
0130      */
0131     oprofilefs_create_ulong(root, "mmcr0", &sys.mmcr0);
0132     oprofilefs_create_ulong(root, "mmcr1", &sys.mmcr1);
0133     oprofilefs_create_ulong(root, "mmcra", &sys.mmcra);
0134 #ifdef CONFIG_OPROFILE_CELL
0135     /* create a file the user tool can check to see what level of profiling
0136      * support exits with this kernel. Initialize bit mask to indicate
0137      * what support the kernel has:
0138      * bit 0      -  Supports SPU event profiling in addition to PPU
0139      *               event and cycles; and SPU cycle profiling
0140      * bits 1-31  -  Currently unused.
0141      *
0142      * If the file does not exist, then the kernel only supports SPU
0143      * cycle profiling, PPU event and cycle profiling.
0144      */
0145     oprofilefs_create_ulong(root, "cell_support", &sys.cell_support);
0146     sys.cell_support = 0x1; /* Note, the user OProfile tool must check
0147                  * that this bit is set before attempting to
0148                  * user SPU event profiling.  Older kernels
0149                  * will not have this file, hence the user
0150                  * tool is not allowed to do SPU event
0151                  * profiling on older kernels.  Older kernels
0152                  * will accept SPU events but collected data
0153                  * is garbage.
0154                  */
0155 #endif
0156 #endif
0157 
0158     for (i = 0; i < model->num_counters; ++i) {
0159         struct dentry *dir;
0160         char buf[4];
0161 
0162         snprintf(buf, sizeof buf, "%d", i);
0163         dir = oprofilefs_mkdir(root, buf);
0164 
0165         oprofilefs_create_ulong(dir, "enabled", &ctr[i].enabled);
0166         oprofilefs_create_ulong(dir, "event", &ctr[i].event);
0167         oprofilefs_create_ulong(dir, "count", &ctr[i].count);
0168 
0169         /*
0170          * Classic PowerPC doesn't support per-counter
0171          * control like this, but the options are
0172          * expected, so they remain.  For Freescale
0173          * Book-E style performance monitors, we do
0174          * support them.
0175          */
0176         oprofilefs_create_ulong(dir, "kernel", &ctr[i].kernel);
0177         oprofilefs_create_ulong(dir, "user", &ctr[i].user);
0178 
0179         oprofilefs_create_ulong(dir, "unit_mask", &ctr[i].unit_mask);
0180     }
0181 
0182     oprofilefs_create_ulong(root, "enable_kernel", &sys.enable_kernel);
0183     oprofilefs_create_ulong(root, "enable_user", &sys.enable_user);
0184 
0185     /* Default to tracing both kernel and user */
0186     sys.enable_kernel = 1;
0187     sys.enable_user = 1;
0188 
0189     return 0;
0190 }
0191 
0192 int __init oprofile_arch_init(struct oprofile_operations *ops)
0193 {
0194     if (!cur_cpu_spec->oprofile_cpu_type)
0195         return -ENODEV;
0196 
0197     switch (cur_cpu_spec->oprofile_type) {
0198 #ifdef CONFIG_PPC_BOOK3S_64
0199 #ifdef CONFIG_OPROFILE_CELL
0200         case PPC_OPROFILE_CELL:
0201             if (firmware_has_feature(FW_FEATURE_LPAR))
0202                 return -ENODEV;
0203             model = &op_model_cell;
0204             ops->sync_start = model->sync_start;
0205             ops->sync_stop = model->sync_stop;
0206             break;
0207 #endif
0208         case PPC_OPROFILE_POWER4:
0209             model = &op_model_power4;
0210             break;
0211         case PPC_OPROFILE_PA6T:
0212             model = &op_model_pa6t;
0213             break;
0214 #endif
0215 #ifdef CONFIG_6xx
0216         case PPC_OPROFILE_G4:
0217             model = &op_model_7450;
0218             break;
0219 #endif
0220 #if defined(CONFIG_FSL_EMB_PERFMON)
0221         case PPC_OPROFILE_FSL_EMB:
0222             model = &op_model_fsl_emb;
0223             break;
0224 #endif
0225         default:
0226             return -ENODEV;
0227     }
0228 
0229     model->num_counters = cur_cpu_spec->num_pmcs;
0230 
0231     ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
0232     ops->create_files = op_powerpc_create_files;
0233     ops->setup = op_powerpc_setup;
0234     ops->shutdown = op_powerpc_shutdown;
0235     ops->start = op_powerpc_start;
0236     ops->stop = op_powerpc_stop;
0237     ops->backtrace = op_powerpc_backtrace;
0238 
0239     printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
0240            ops->cpu_type);
0241 
0242     return 0;
0243 }
0244 
0245 void oprofile_arch_exit(void)
0246 {
0247 }