Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / arm / oprofile / common.c
index e57dde8..6f83335 100644 (file)
 #include <linux/init.h>
 #include <linux/oprofile.h>
 #include <linux/errno.h>
-#include <asm/semaphore.h>
+#include <linux/slab.h>
 #include <linux/sysdev.h>
+#include <linux/mutex.h>
 
 #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);
 }
-