linux/arch/powerpc/oprofile/common.c
<<
>>
Prefs
   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 int op_per_cpu_rc;
  33
  34static void op_handle_interrupt(struct pt_regs *regs)
  35{
  36        model->handle_interrupt(regs, ctr);
  37}
  38
  39static void op_powerpc_cpu_setup(void *dummy)
  40{
  41        int ret;
  42
  43        ret = model->cpu_setup(ctr);
  44
  45        if (ret != 0)
  46                op_per_cpu_rc = ret;
  47}
  48
  49static int op_powerpc_setup(void)
  50{
  51        int err;
  52
  53        op_per_cpu_rc = 0;
  54
  55        /* Grab the hardware */
  56        err = reserve_pmc_hardware(op_handle_interrupt);
  57        if (err)
  58                return err;
  59
  60        /* Pre-compute the values to stuff in the hardware registers.  */
  61        op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
  62
  63        if (op_per_cpu_rc)
  64                goto out;
  65
  66        /* Configure the registers on all cpus.  If an error occurs on one
  67         * of the cpus, op_per_cpu_rc will be set to the error */
  68        on_each_cpu(op_powerpc_cpu_setup, NULL, 1);
  69
  70out:    if (op_per_cpu_rc) {
  71                /* error on setup release the performance counter hardware */
  72                release_pmc_hardware();
  73        }
  74
  75        return op_per_cpu_rc;
  76}
  77
  78static void op_powerpc_shutdown(void)
  79{
  80        release_pmc_hardware();
  81}
  82
  83static void op_powerpc_cpu_start(void *dummy)
  84{
  85        /* If any of the cpus have return an error, set the
  86         * global flag to the error so it can be returned
  87         * to the generic OProfile caller.
  88         */
  89        int ret;
  90
  91        ret = model->start(ctr);
  92        if (ret != 0)
  93                op_per_cpu_rc = ret;
  94}
  95
  96static int op_powerpc_start(void)
  97{
  98        op_per_cpu_rc = 0;
  99
 100        if (model->global_start)
 101                return model->global_start(ctr);
 102        if (model->start) {
 103                on_each_cpu(op_powerpc_cpu_start, NULL, 1);
 104                return op_per_cpu_rc;
 105        }
 106        return -EIO; /* No start function is defined for this
 107                        power architecture */
 108}
 109
 110static inline void op_powerpc_cpu_stop(void *dummy)
 111{
 112        model->stop();
 113}
 114
 115static void op_powerpc_stop(void)
 116{
 117        if (model->stop)
 118                on_each_cpu(op_powerpc_cpu_stop, NULL, 1);
 119        if (model->global_stop)
 120                model->global_stop();
 121}
 122
 123static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
 124{
 125        int i;
 126
 127#ifdef CONFIG_PPC64
 128        /*
 129         * There is one mmcr0, mmcr1 and mmcra for setting the events for
 130         * all of the counters.
 131         */
 132        oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
 133        oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
 134        oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
 135#ifdef CONFIG_OPROFILE_CELL
 136        /* create a file the user tool can check to see what level of profiling
 137         * support exits with this kernel. Initialize bit mask to indicate
 138         * what support the kernel has:
 139         * bit 0      -  Supports SPU event profiling in addition to PPU
 140         *               event and cycles; and SPU cycle profiling
 141         * bits 1-31  -  Currently unused.
 142         *
 143         * If the file does not exist, then the kernel only supports SPU
 144         * cycle profiling, PPU event and cycle profiling.
 145         */
 146        oprofilefs_create_ulong(sb, root, "cell_support", &sys.cell_support);
 147        sys.cell_support = 0x1; /* Note, the user OProfile tool must check
 148                                 * that this bit is set before attempting to
 149                                 * user SPU event profiling.  Older kernels
 150                                 * will not have this file, hence the user
 151                                 * tool is not allowed to do SPU event
 152                                 * profiling on older kernels.  Older kernels
 153                                 * will accept SPU events but collected data
 154                                 * is garbage.
 155                                 */
 156#endif
 157#endif
 158
 159        for (i = 0; i < model->num_counters; ++i) {
 160                struct dentry *dir;
 161                char buf[4];
 162
 163                snprintf(buf, sizeof buf, "%d", i);
 164                dir = oprofilefs_mkdir(sb, root, buf);
 165
 166                oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
 167                oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
 168                oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
 169
 170                /*
 171                 * Classic PowerPC doesn't support per-counter
 172                 * control like this, but the options are
 173                 * expected, so they remain.  For Freescale
 174                 * Book-E style performance monitors, we do
 175                 * support them.
 176                 */
 177                oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
 178                oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
 179
 180                oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
 181        }
 182
 183        oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
 184        oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
 185
 186        /* Default to tracing both kernel and user */
 187        sys.enable_kernel = 1;
 188        sys.enable_user = 1;
 189
 190        return 0;
 191}
 192
 193int __init oprofile_arch_init(struct oprofile_operations *ops)
 194{
 195        if (!cur_cpu_spec->oprofile_cpu_type)
 196                return -ENODEV;
 197
 198        if (firmware_has_feature(FW_FEATURE_ISERIES))
 199                return -ENODEV;
 200
 201        switch (cur_cpu_spec->oprofile_type) {
 202#ifdef CONFIG_PPC64
 203#ifdef CONFIG_OPROFILE_CELL
 204                case PPC_OPROFILE_CELL:
 205                        if (firmware_has_feature(FW_FEATURE_LPAR))
 206                                return -ENODEV;
 207                        model = &op_model_cell;
 208                        ops->sync_start = model->sync_start;
 209                        ops->sync_stop = model->sync_stop;
 210                        break;
 211#endif
 212                case PPC_OPROFILE_RS64:
 213                        model = &op_model_rs64;
 214                        break;
 215                case PPC_OPROFILE_POWER4:
 216                        model = &op_model_power4;
 217                        break;
 218                case PPC_OPROFILE_PA6T:
 219                        model = &op_model_pa6t;
 220                        break;
 221#endif
 222#ifdef CONFIG_6xx
 223                case PPC_OPROFILE_G4:
 224                        model = &op_model_7450;
 225                        break;
 226#endif
 227#if defined(CONFIG_FSL_EMB_PERFMON)
 228                case PPC_OPROFILE_FSL_EMB:
 229                        model = &op_model_fsl_emb;
 230                        break;
 231#endif
 232                default:
 233                        return -ENODEV;
 234        }
 235
 236        model->num_counters = cur_cpu_spec->num_pmcs;
 237
 238        ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
 239        ops->create_files = op_powerpc_create_files;
 240        ops->setup = op_powerpc_setup;
 241        ops->shutdown = op_powerpc_shutdown;
 242        ops->start = op_powerpc_start;
 243        ops->stop = op_powerpc_stop;
 244        ops->backtrace = op_powerpc_backtrace;
 245
 246        printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
 247               ops->cpu_type);
 248
 249        return 0;
 250}
 251
 252void oprofile_arch_exit(void)
 253{
 254}
 255