Full support for Ginger Console
[linux-ginger.git] / arch / arm / oprofile / common.c
blob3fcd752d6146d205860e00464ff23ca8008a7cd0
1 /**
2 * @file common.c
4 * @remark Copyright 2004 Oprofile Authors
5 * @remark Read the file COPYING
7 * @author Zwane Mwaikambo
8 */
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>
17 #include "op_counter.h"
18 #include "op_arm_model.h"
20 static struct op_arm_model_spec *op_arm_model;
21 static int op_arm_enabled;
22 static DEFINE_MUTEX(op_arm_mutex);
24 struct op_counter_config *counter_config;
26 static int op_arm_create_files(struct super_block *sb, struct dentry *root)
28 unsigned int i;
30 for (i = 0; i < op_arm_model->num_counters; i++) {
31 struct dentry *dir;
32 char buf[4];
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);
44 return 0;
47 static int op_arm_setup(void)
49 int ret;
51 spin_lock(&oprofilefs_lock);
52 ret = op_arm_model->setup_ctrs();
53 spin_unlock(&oprofilefs_lock);
54 return ret;
57 static int op_arm_start(void)
59 int ret = -EBUSY;
61 mutex_lock(&op_arm_mutex);
62 if (!op_arm_enabled) {
63 ret = op_arm_model->start();
64 op_arm_enabled = !ret;
66 mutex_unlock(&op_arm_mutex);
67 return ret;
70 static void op_arm_stop(void)
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);
79 #ifdef CONFIG_PM
80 static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
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;
89 static int op_arm_resume(struct sys_device *dev)
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;
98 static struct sysdev_class oprofile_sysclass = {
99 .name = "oprofile",
100 .resume = op_arm_resume,
101 .suspend = op_arm_suspend,
104 static struct sys_device device_oprofile = {
105 .id = 0,
106 .cls = &oprofile_sysclass,
109 static int __init init_driverfs(void)
111 int ret;
113 if (!(ret = sysdev_class_register(&oprofile_sysclass)))
114 ret = sysdev_register(&device_oprofile);
116 return ret;
119 static void exit_driverfs(void)
121 sysdev_unregister(&device_oprofile);
122 sysdev_class_unregister(&oprofile_sysclass);
124 #else
125 #define init_driverfs() do { } while (0)
126 #define exit_driverfs() do { } while (0)
127 #endif /* CONFIG_PM */
129 int __init oprofile_arch_init(struct oprofile_operations *ops)
131 struct op_arm_model_spec *spec = NULL;
132 int ret = -ENODEV;
134 ops->backtrace = arm_backtrace;
136 #ifdef CONFIG_CPU_XSCALE
137 spec = &op_xscale_spec;
138 #endif
140 #ifdef CONFIG_OPROFILE_ARMV6
141 spec = &op_armv6_spec;
142 #endif
144 #ifdef CONFIG_OPROFILE_MPCORE
145 spec = &op_mpcore_spec;
146 #endif
148 #ifdef CONFIG_OPROFILE_ARMV7
149 spec = &op_armv7_spec;
150 #endif
152 if (spec) {
153 ret = spec->init();
154 if (ret < 0)
155 return ret;
157 counter_config = kcalloc(spec->num_counters, sizeof(struct op_counter_config),
158 GFP_KERNEL);
159 if (!counter_config)
160 return -ENOMEM;
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);
173 return ret;
176 void oprofile_arch_exit(void)
178 if (op_arm_model) {
179 exit_driverfs();
180 op_arm_model = NULL;
182 kfree(counter_config);