Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / arch / arm / oprofile / common.c
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
20 static struct op_arm_model_spec *op_arm_model;
21 static int op_arm_enabled;
22 static DEFINE_MUTEX(op_arm_mutex);
23
24 struct op_counter_config *counter_config;
25
26 static 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
47 static 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
57 static 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
70 static 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
80 static 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
89 static 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
98 static struct sysdev_class oprofile_sysclass = {
99         .name           = "oprofile",
100         .resume         = op_arm_resume,
101         .suspend        = op_arm_suspend,
102 };
103
104 static struct sys_device device_oprofile = {
105         .id             = 0,
106         .cls            = &oprofile_sysclass,
107 };
108
109 static 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
119 static 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
129 int __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
176 void oprofile_arch_exit(void)
177 {
178         if (op_arm_model) {
179                 exit_driverfs();
180                 op_arm_model = NULL;
181         }
182         kfree(counter_config);
183 }