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, 0, 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, 0, 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, 0, 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#endif
 136
 137        for (i = 0; i < model->num_counters; ++i) {
 138                struct dentry *dir;
 139                char buf[4];
 140
 141                snprintf(buf, sizeof buf, "%d", i);
 142                dir = oprofilefs_mkdir(sb, root, buf);
 143
 144                oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
 145                oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
 146                oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
 147
 148                /*
 149                 * Classic PowerPC doesn't support per-counter
 150                 * control like this, but the options are
 151                 * expected, so they remain.  For Freescale
 152                 * Book-E style performance monitors, we do
 153                 * support them.
 154                 */
 155                oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
 156                oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
 157
 158                oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
 159        }
 160
 161        oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
 162        oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
 163
 164        /* Default to tracing both kernel and user */
 165        sys.enable_kernel = 1;
 166        sys.enable_user = 1;
 167
 168        return 0;
 169}
 170
 171int __init oprofile_arch_init(struct oprofile_operations *ops)
 172{
 173        if (!cur_cpu_spec->oprofile_cpu_type)
 174                return -ENODEV;
 175
 176        if (firmware_has_feature(FW_FEATURE_ISERIES))
 177                return -ENODEV;
 178
 179        switch (cur_cpu_spec->oprofile_type) {
 180#ifdef CONFIG_PPC64
 181#ifdef CONFIG_OPROFILE_CELL
 182                case PPC_OPROFILE_CELL:
 183                        if (firmware_has_feature(FW_FEATURE_LPAR))
 184                                return -ENODEV;
 185                        model = &op_model_cell;
 186                        ops->sync_start = model->sync_start;
 187                        ops->sync_stop = model->sync_stop;
 188                        break;
 189#endif
 190                case PPC_OPROFILE_RS64:
 191                        model = &op_model_rs64;
 192                        break;
 193                case PPC_OPROFILE_POWER4:
 194                        model = &op_model_power4;
 195                        break;
 196                case PPC_OPROFILE_PA6T:
 197                        model = &op_model_pa6t;
 198                        break;
 199#endif
 200#ifdef CONFIG_6xx
 201                case PPC_OPROFILE_G4:
 202                        model = &op_model_7450;
 203                        break;
 204#endif
 205#ifdef CONFIG_FSL_BOOKE
 206                case PPC_OPROFILE_BOOKE:
 207                        model = &op_model_fsl_booke;
 208                        break;
 209#endif
 210                default:
 211                        return -ENODEV;
 212        }
 213
 214        model->num_counters = cur_cpu_spec->num_pmcs;
 215
 216        ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
 217        ops->create_files = op_powerpc_create_files;
 218        ops->setup = op_powerpc_setup;
 219        ops->shutdown = op_powerpc_shutdown;
 220        ops->start = op_powerpc_start;
 221        ops->stop = op_powerpc_stop;
 222        ops->backtrace = op_powerpc_backtrace;
 223
 224        printk(KERN_DEBUG "oprofile: using %s performance monitoring.\n",
 225               ops->cpu_type);
 226
 227        return 0;
 228}
 229
 230void oprofile_arch_exit(void)
 231{
 232}
 233