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