This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / arm / oprofile / common.c
index 100fe58..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 int pmu_start(void);
-static int pmu_setup(void);
-static void pmu_stop(void);
-static int pmu_create_files(struct super_block *, struct dentry *);
-
-static struct oprofile_operations pmu_ops = {
-       .create_files   = pmu_create_files,
-       .setup          = pmu_setup,
-       .shutdown       = pmu_stop,
-       .start          = pmu_start,
-       .stop           = pmu_stop,
-};
-
-#ifdef CONFIG_PM
-static struct sys_device device_oprofile = {
-       .id             = 0,
-       .cls            = &oprofile_sysclass,
-};
-
-static int __init init_driverfs(void)
-{
-       int ret;
-
-       if (!(ret = sysdev_class_register(&oprofile_sysclass)))
-               ret = sys_device_register(&device_oprofile);
-
-       return ret;
-}
+static struct op_arm_model_spec *op_arm_model;
+static int op_arm_enabled;
+static DEFINE_MUTEX(op_arm_mutex);
 
-static void __exit exit_driverfs(void)
-{
-       sys_device_unregister(&device_oprofile);
-       sysdev_class_unregister(&oprofile_sysclass);
-}
-#else
-#define init_driverfs()        do { } while (0)
-#define exit_driverfs() do { } while (0)
-#endif /* CONFIG_PM */
+struct op_counter_config *counter_config;
 
-struct op_counter_config counter_config[OP_MAX_COUNTER];
-
-static int pmu_create_files(struct super_block *sb, struct dentry *root)
+static int op_arm_create_files(struct super_block *sb, struct dentry *root)
 {
        unsigned int i;
 
-       for (i = 0; i < pmu_model->num_counters; i++) {
+       for (i = 0; i < op_arm_model->num_counters; i++) {
                struct dentry *dir;
-               char buf[2];
+               char buf[4];
 
                snprintf(buf, sizeof buf, "%d", i);
                dir = oprofilefs_mkdir(sb, root, buf);
@@ -81,58 +44,127 @@ static int pmu_create_files(struct super_block *sb, struct dentry *root)
        return 0;
 }
 
-static int pmu_setup(void)
+static int op_arm_setup(void)
 {
        int ret;
 
        spin_lock(&oprofilefs_lock);
-       ret = pmu_model->setup_ctrs();
+       ret = op_arm_model->setup_ctrs();
        spin_unlock(&oprofilefs_lock);
        return ret;
 }
 
-static int pmu_start(void)
+static int op_arm_start(void)
 {
        int ret = -EBUSY;
 
-       down(&pmu_sem);
-       if (!pmu_enabled) {
-               ret = pmu_model->start();
-               pmu_enabled = !ret;
+       mutex_lock(&op_arm_mutex);
+       if (!op_arm_enabled) {
+               ret = op_arm_model->start();
+               op_arm_enabled = !ret;
        }
-       up(&pmu_sem);
+       mutex_unlock(&op_arm_mutex);
        return ret;
 }
 
-static void pmu_stop(void)
+static void op_arm_stop(void)
 {
-       down(&pmu_sem);
-       if (pmu_enabled)
-               pmu_model->stop();
-       pmu_enabled = 0;
-       up(&pmu_sem);
+       mutex_lock(&op_arm_mutex);
+       if (op_arm_enabled)
+               op_arm_model->stop();
+       op_arm_enabled = 0;
+       mutex_unlock(&op_arm_mutex);
 }
 
-int __init pmu_init(struct oprofile_operations **ops, struct op_arm_model_spec *spec)
+#ifdef CONFIG_PM
+static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
 {
-       init_MUTEX(&pmu_sem);
-
-       if (spec->init() < 0)
-               return -ENODEV;
+       mutex_lock(&op_arm_mutex);
+       if (op_arm_enabled)
+               op_arm_model->stop();
+       mutex_unlock(&op_arm_mutex);
+       return 0;
+}
 
-       pmu_model = spec;
-       init_driverfs();
-       *ops = &pmu_ops;
-       pmu_ops.cpu_type = pmu_model->name;
-       printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
+static int op_arm_resume(struct sys_device *dev)
+{
+       mutex_lock(&op_arm_mutex);
+       if (op_arm_enabled && op_arm_model->start())
+               op_arm_enabled = 0;
+       mutex_unlock(&op_arm_mutex);
        return 0;
 }
 
-void pmu_exit(void)
+static struct sysdev_class oprofile_sysclass = {
+       set_kset_name("oprofile"),
+       .resume         = op_arm_resume,
+       .suspend        = op_arm_suspend,
+};
+
+static struct sys_device device_oprofile = {
+       .id             = 0,
+       .cls            = &oprofile_sysclass,
+};
+
+static int __init init_driverfs(void)
+{
+       int ret;
+
+       if (!(ret = sysdev_class_register(&oprofile_sysclass)))
+               ret = sysdev_register(&device_oprofile);
+
+       return ret;
+}
+
+static void  exit_driverfs(void)
 {
-       if (pmu_model) {
-               exit_driverfs();
-               pmu_model = NULL;
+       sysdev_unregister(&device_oprofile);
+       sysdev_class_unregister(&oprofile_sysclass);
+}
+#else
+#define init_driverfs()        do { } while (0)
+#define exit_driverfs() do { } while (0)
+#endif /* CONFIG_PM */
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+       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 ret;
 }
 
+void oprofile_arch_exit(void)
+{
+       if (op_arm_model) {
+               exit_driverfs();
+               op_arm_model = NULL;
+       }
+       kfree(counter_config);
+}