linux/arch/sh/oprofile/common.c
<<
>>
Prefs
   1/*
   2 * arch/sh/oprofile/init.c
   3 *
   4 * Copyright (C) 2003 - 2008  Paul Mundt
   5 *
   6 * Based on arch/mips/oprofile/common.c:
   7 *
   8 *      Copyright (C) 2004, 2005 Ralf Baechle
   9 *      Copyright (C) 2005 MIPS Technologies, Inc.
  10 *
  11 * This file is subject to the terms and conditions of the GNU General Public
  12 * License.  See the file "COPYING" in the main directory of this archive
  13 * for more details.
  14 */
  15#include <linux/kernel.h>
  16#include <linux/oprofile.h>
  17#include <linux/init.h>
  18#include <linux/errno.h>
  19#include <linux/smp.h>
  20#include <asm/processor.h>
  21#include "op_impl.h"
  22
  23extern struct op_sh_model op_model_sh7750_ops __weak;
  24extern struct op_sh_model op_model_sh4a_ops __weak;
  25
  26static struct op_sh_model *model;
  27
  28static struct op_counter_config ctr[20];
  29
  30extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
  31
  32static int op_sh_setup(void)
  33{
  34        /* Pre-compute the values to stuff in the hardware registers.  */
  35        model->reg_setup(ctr);
  36
  37        /* Configure the registers on all cpus.  */
  38        on_each_cpu(model->cpu_setup, NULL, 1);
  39
  40        return 0;
  41}
  42
  43static int op_sh_create_files(struct super_block *sb, struct dentry *root)
  44{
  45        int i, ret = 0;
  46
  47        for (i = 0; i < model->num_counters; i++) {
  48                struct dentry *dir;
  49                char buf[4];
  50
  51                snprintf(buf, sizeof(buf), "%d", i);
  52                dir = oprofilefs_mkdir(sb, root, buf);
  53
  54                ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
  55                ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
  56                ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
  57                ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
  58
  59                if (model->create_files)
  60                        ret |= model->create_files(sb, dir);
  61                else
  62                        ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
  63
  64                /* Dummy entries */
  65                ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
  66        }
  67
  68        return ret;
  69}
  70
  71static int op_sh_start(void)
  72{
  73        /* Enable performance monitoring for all counters.  */
  74        on_each_cpu(model->cpu_start, NULL, 1);
  75
  76        return 0;
  77}
  78
  79static void op_sh_stop(void)
  80{
  81        /* Disable performance monitoring for all counters.  */
  82        on_each_cpu(model->cpu_stop, NULL, 1);
  83}
  84
  85int __init oprofile_arch_init(struct oprofile_operations *ops)
  86{
  87        struct op_sh_model *lmodel = NULL;
  88        int ret;
  89
  90        /*
  91         * Always assign the backtrace op. If the counter initialization
  92         * fails, we fall back to the timer which will still make use of
  93         * this.
  94         */
  95        ops->backtrace = sh_backtrace;
  96
  97        switch (current_cpu_data.type) {
  98        /* SH-4 types */
  99        case CPU_SH7750:
 100        case CPU_SH7750S:
 101                lmodel = &op_model_sh7750_ops;
 102                break;
 103
 104        /* SH-4A types */
 105        case CPU_SH7763:
 106        case CPU_SH7770:
 107        case CPU_SH7780:
 108        case CPU_SH7781:
 109        case CPU_SH7785:
 110        case CPU_SH7786:
 111        case CPU_SH7723:
 112        case CPU_SH7724:
 113        case CPU_SHX3:
 114                lmodel = &op_model_sh4a_ops;
 115                break;
 116
 117        /* SH4AL-DSP types */
 118        case CPU_SH7343:
 119        case CPU_SH7722:
 120        case CPU_SH7366:
 121                lmodel = &op_model_sh4a_ops;
 122                break;
 123        }
 124
 125        if (!lmodel)
 126                return -ENODEV;
 127        if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
 128                return -ENODEV;
 129
 130        ret = lmodel->init();
 131        if (unlikely(ret != 0))
 132                return ret;
 133
 134        model = lmodel;
 135
 136        ops->setup              = op_sh_setup;
 137        ops->create_files       = op_sh_create_files;
 138        ops->start              = op_sh_start;
 139        ops->stop               = op_sh_stop;
 140        ops->cpu_type           = lmodel->cpu_type;
 141
 142        printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
 143               lmodel->cpu_type);
 144
 145        return 0;
 146}
 147
 148void oprofile_arch_exit(void)
 149{
 150        if (model && model->exit)
 151                model->exit();
 152}
 153