linux/arch/arm/oprofile/common.c
<<
>>
Prefs
   1/**
   2 * @file common.c
   3 *
   4 * @remark Copyright 2004 Oprofile Authors
   5 * @remark Read the file COPYING
   6 *
   7 * @author Zwane Mwaikambo
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/oprofile.h>
  12#include <linux/errno.h>
  13#include <linux/slab.h>
  14#include <linux/sysdev.h>
  15#include <linux/mutex.h>
  16
  17#include "op_counter.h"
  18#include "op_arm_model.h"
  19
  20static struct op_arm_model_spec *op_arm_model;
  21static int op_arm_enabled;
  22static DEFINE_MUTEX(op_arm_mutex);
  23
  24struct op_counter_config *counter_config;
  25
  26static int op_arm_create_files(struct super_block *sb, struct dentry *root)
  27{
  28        unsigned int i;
  29
  30        for (i = 0; i < op_arm_model->num_counters; i++) {
  31                struct dentry *dir;
  32                char buf[4];
  33
  34                snprintf(buf, sizeof buf, "%d", i);
  35                dir = oprofilefs_mkdir(sb, root, buf);
  36                oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
  37                oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
  38                oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
  39                oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
  40                oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
  41                oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
  42        }
  43
  44        return 0;
  45}
  46
  47static int op_arm_setup(void)
  48{
  49        int ret;
  50
  51        spin_lock(&oprofilefs_lock);
  52        ret = op_arm_model->setup_ctrs();
  53        spin_unlock(&oprofilefs_lock);
  54        return ret;
  55}
  56
  57static int op_arm_start(void)
  58{
  59        int ret = -EBUSY;
  60
  61        mutex_lock(&op_arm_mutex);
  62        if (!op_arm_enabled) {
  63                ret = op_arm_model->start();
  64                op_arm_enabled = !ret;
  65        }
  66        mutex_unlock(&op_arm_mutex);
  67        return ret;
  68}
  69
  70static void op_arm_stop(void)
  71{
  72        mutex_lock(&op_arm_mutex);
  73        if (op_arm_enabled)
  74                op_arm_model->stop();
  75        op_arm_enabled = 0;
  76        mutex_unlock(&op_arm_mutex);
  77}
  78
  79#ifdef CONFIG_PM
  80static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
  81{
  82        mutex_lock(&op_arm_mutex);
  83        if (op_arm_enabled)
  84                op_arm_model->stop();
  85        mutex_unlock(&op_arm_mutex);
  86        return 0;
  87}
  88
  89static int op_arm_resume(struct sys_device *dev)
  90{
  91        mutex_lock(&op_arm_mutex);
  92        if (op_arm_enabled && op_arm_model->start())
  93                op_arm_enabled = 0;
  94        mutex_unlock(&op_arm_mutex);
  95        return 0;
  96}
  97
  98static struct sysdev_class oprofile_sysclass = {
  99        .name           = "oprofile",
 100        .resume         = op_arm_resume,
 101        .suspend        = op_arm_suspend,
 102};
 103
 104static struct sys_device device_oprofile = {
 105        .id             = 0,
 106        .cls            = &oprofile_sysclass,
 107};
 108
 109static int __init init_driverfs(void)
 110{
 111        int ret;
 112
 113        if (!(ret = sysdev_class_register(&oprofile_sysclass)))
 114                ret = sysdev_register(&device_oprofile);
 115
 116        return ret;
 117}
 118
 119static void  exit_driverfs(void)
 120{
 121        sysdev_unregister(&device_oprofile);
 122        sysdev_class_unregister(&oprofile_sysclass);
 123}
 124#else
 125#define init_driverfs() do { } while (0)
 126#define exit_driverfs() do { } while (0)
 127#endif /* CONFIG_PM */
 128
 129int __init oprofile_arch_init(struct oprofile_operations *ops)
 130{
 131        struct op_arm_model_spec *spec = NULL;
 132        int ret = -ENODEV;
 133
 134        ops->backtrace = arm_backtrace;
 135
 136#ifdef CONFIG_CPU_XSCALE
 137        spec = &op_xscale_spec;
 138#endif
 139
 140#ifdef CONFIG_OPROFILE_ARMV6
 141        spec = &op_armv6_spec;
 142#endif
 143
 144#ifdef CONFIG_OPROFILE_MPCORE
 145        spec = &op_mpcore_spec;
 146#endif
 147
 148#ifdef CONFIG_OPROFILE_ARMV7
 149        spec = &op_armv7_spec;
 150#endif
 151
 152        if (spec) {
 153                ret = spec->init();
 154                if (ret < 0)
 155                        return ret;
 156
 157                counter_config = kcalloc(spec->num_counters, sizeof(struct op_counter_config),
 158                                         GFP_KERNEL);
 159                if (!counter_config)
 160                        return -ENOMEM;
 161
 162                op_arm_model = spec;
 163                init_driverfs();
 164                ops->create_files = op_arm_create_files;
 165                ops->setup = op_arm_setup;
 166                ops->shutdown = op_arm_stop;
 167                ops->start = op_arm_start;
 168                ops->stop = op_arm_stop;
 169                ops->cpu_type = op_arm_model->name;
 170                printk(KERN_INFO "oprofile: using %s\n", spec->name);
 171        }
 172
 173        return ret;
 174}
 175
 176void oprofile_arch_exit(void)
 177{
 178        if (op_arm_model) {
 179                exit_driverfs();
 180                op_arm_model = NULL;
 181        }
 182        kfree(counter_config);
 183}
 184