X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Foprofile%2Fcommon.c;h=6f833358cd0612c4c13e5d59619e86ccee2749e5;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=e57dde88289813d785b332de04be2eaebd98a6dd;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index e57dde882..6f833358c 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -10,40 +10,95 @@ #include #include #include -#include +#include #include +#include #include "op_counter.h" #include "op_arm_model.h" -static struct op_arm_model_spec *pmu_model; -static int pmu_enabled; -static struct semaphore pmu_sem; +static struct op_arm_model_spec *op_arm_model; +static int op_arm_enabled; +static DEFINE_MUTEX(op_arm_mutex); -static int pmu_start(void); -static int pmu_setup(void); -static void pmu_stop(void); -static int pmu_create_files(struct super_block *, struct dentry *); +struct op_counter_config *counter_config; + +static int op_arm_create_files(struct super_block *sb, struct dentry *root) +{ + unsigned int i; + + for (i = 0; i < op_arm_model->num_counters; i++) { + struct dentry *dir; + char buf[4]; + + snprintf(buf, sizeof buf, "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + } + + return 0; +} + +static int op_arm_setup(void) +{ + int ret; + + spin_lock(&oprofilefs_lock); + ret = op_arm_model->setup_ctrs(); + spin_unlock(&oprofilefs_lock); + return ret; +} + +static int op_arm_start(void) +{ + int ret = -EBUSY; + + mutex_lock(&op_arm_mutex); + if (!op_arm_enabled) { + ret = op_arm_model->start(); + op_arm_enabled = !ret; + } + mutex_unlock(&op_arm_mutex); + return ret; +} + +static void op_arm_stop(void) +{ + mutex_lock(&op_arm_mutex); + if (op_arm_enabled) + op_arm_model->stop(); + op_arm_enabled = 0; + mutex_unlock(&op_arm_mutex); +} #ifdef CONFIG_PM -static int pmu_suspend(struct sys_device *dev, pm_message_t state) +static int op_arm_suspend(struct sys_device *dev, pm_message_t state) { - if (pmu_enabled) - pmu_stop(); + mutex_lock(&op_arm_mutex); + if (op_arm_enabled) + op_arm_model->stop(); + mutex_unlock(&op_arm_mutex); return 0; } -static int pmu_resume(struct sys_device *dev) +static int op_arm_resume(struct sys_device *dev) { - if (pmu_enabled) - pmu_start(); + mutex_lock(&op_arm_mutex); + if (op_arm_enabled && op_arm_model->start()) + op_arm_enabled = 0; + mutex_unlock(&op_arm_mutex); return 0; } static struct sysdev_class oprofile_sysclass = { set_kset_name("oprofile"), - .resume = pmu_resume, - .suspend = pmu_suspend, + .resume = op_arm_resume, + .suspend = op_arm_suspend, }; static struct sys_device device_oprofile = { @@ -71,86 +126,45 @@ static void exit_driverfs(void) #define exit_driverfs() do { } while (0) #endif /* CONFIG_PM */ -struct op_counter_config counter_config[OP_MAX_COUNTER]; - -static int pmu_create_files(struct super_block *sb, struct dentry *root) +int __init oprofile_arch_init(struct oprofile_operations *ops) { - unsigned int i; - - for (i = 0; i < pmu_model->num_counters; i++) { - struct dentry *dir; - char buf[2]; - - snprintf(buf, sizeof buf, "%d", i); - dir = oprofilefs_mkdir(sb, root, buf); - oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); - oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); - oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); - oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); - oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); - oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + struct op_arm_model_spec *spec = NULL; + int ret = -ENODEV; + +#ifdef CONFIG_CPU_XSCALE + spec = &op_xscale_spec; +#endif + + if (spec) { + ret = spec->init(); + if (ret < 0) + return ret; + + counter_config = kcalloc(spec->num_counters, sizeof(struct op_counter_config), + GFP_KERNEL); + if (!counter_config) + return -ENOMEM; + + op_arm_model = spec; + init_driverfs(); + ops->create_files = op_arm_create_files; + ops->setup = op_arm_setup; + ops->shutdown = op_arm_stop; + ops->start = op_arm_start; + ops->stop = op_arm_stop; + ops->cpu_type = op_arm_model->name; + ops->backtrace = arm_backtrace; + printk(KERN_INFO "oprofile: using %s\n", spec->name); } - return 0; -} - -static int pmu_setup(void) -{ - int ret; - - spin_lock(&oprofilefs_lock); - ret = pmu_model->setup_ctrs(); - spin_unlock(&oprofilefs_lock); return ret; } -static int pmu_start(void) +void oprofile_arch_exit(void) { - int ret = -EBUSY; - - down(&pmu_sem); - if (!pmu_enabled) { - ret = pmu_model->start(); - pmu_enabled = !ret; - } - up(&pmu_sem); - return ret; -} - -static void pmu_stop(void) -{ - down(&pmu_sem); - if (pmu_enabled) - pmu_model->stop(); - pmu_enabled = 0; - up(&pmu_sem); -} - -int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) -{ - init_MUTEX(&pmu_sem); - - if (spec->init() < 0) - return -ENODEV; - - pmu_model = spec; - init_driverfs(); - ops->create_files = pmu_create_files; - ops->setup = pmu_setup; - ops->shutdown = pmu_stop; - ops->start = pmu_start; - ops->stop = pmu_stop; - ops->cpu_type = pmu_model->name; - printk(KERN_INFO "oprofile: using %s PMU\n", spec->name); - - return 0; -} - -void pmu_exit(void) -{ - if (pmu_model) { + if (op_arm_model) { exit_driverfs(); - pmu_model = NULL; + op_arm_model = NULL; } + kfree(counter_config); } -