Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / 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/sysdev.h>
14 #include <asm/semaphore.h>
15
16 #include "op_counter.h"
17 #include "op_arm_model.h"
18
19 static struct op_arm_model_spec *op_arm_model;
20 static int op_arm_enabled;
21 static struct semaphore op_arm_sem;
22
23 struct op_counter_config counter_config[OP_MAX_COUNTER];
24
25 static int op_arm_create_files(struct super_block *sb, struct dentry *root)
26 {
27         unsigned int i;
28
29         for (i = 0; i < op_arm_model->num_counters; i++) {
30                 struct dentry *dir;
31                 char buf[2];
32
33                 snprintf(buf, sizeof buf, "%d", i);
34                 dir = oprofilefs_mkdir(sb, root, buf);
35                 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
36                 oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
37                 oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
38                 oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
39                 oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
40                 oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
41         }
42
43         return 0;
44 }
45
46 static int op_arm_setup(void)
47 {
48         int ret;
49
50         spin_lock(&oprofilefs_lock);
51         ret = op_arm_model->setup_ctrs();
52         spin_unlock(&oprofilefs_lock);
53         return ret;
54 }
55
56 static int op_arm_start(void)
57 {
58         int ret = -EBUSY;
59
60         down(&op_arm_sem);
61         if (!op_arm_enabled) {
62                 ret = op_arm_model->start();
63                 op_arm_enabled = !ret;
64         }
65         up(&op_arm_sem);
66         return ret;
67 }
68
69 static void op_arm_stop(void)
70 {
71         down(&op_arm_sem);
72         if (op_arm_enabled)
73                 op_arm_model->stop();
74         op_arm_enabled = 0;
75         up(&op_arm_sem);
76 }
77
78 #ifdef CONFIG_PM
79 static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
80 {
81         down(&op_arm_sem);
82         if (op_arm_enabled)
83                 op_arm_model->stop();
84         up(&op_arm_sem);
85         return 0;
86 }
87
88 static int op_arm_resume(struct sys_device *dev)
89 {
90         down(&op_arm_sem);
91         if (op_arm_enabled && op_arm_model->start())
92                 op_arm_enabled = 0;
93         up(&op_arm_sem);
94         return 0;
95 }
96
97 static struct sysdev_class oprofile_sysclass = {
98         set_kset_name("oprofile"),
99         .resume         = op_arm_resume,
100         .suspend        = op_arm_suspend,
101 };
102
103 static struct sys_device device_oprofile = {
104         .id             = 0,
105         .cls            = &oprofile_sysclass,
106 };
107
108 static int __init init_driverfs(void)
109 {
110         int ret;
111
112         if (!(ret = sysdev_class_register(&oprofile_sysclass)))
113                 ret = sysdev_register(&device_oprofile);
114
115         return ret;
116 }
117
118 static void  exit_driverfs(void)
119 {
120         sysdev_unregister(&device_oprofile);
121         sysdev_class_unregister(&oprofile_sysclass);
122 }
123 #else
124 #define init_driverfs() do { } while (0)
125 #define exit_driverfs() do { } while (0)
126 #endif /* CONFIG_PM */
127
128 int __init oprofile_arch_init(struct oprofile_operations *ops)
129 {
130         struct op_arm_model_spec *spec = NULL;
131         int ret = -ENODEV;
132
133 #ifdef CONFIG_CPU_XSCALE
134         spec = &op_xscale_spec;
135 #endif
136
137         if (spec) {
138                 init_MUTEX(&op_arm_sem);
139
140                 if (spec->init() < 0)
141                         return -ENODEV;
142
143                 op_arm_model = spec;
144                 init_driverfs();
145                 ops->create_files = op_arm_create_files;
146                 ops->setup = op_arm_setup;
147                 ops->shutdown = op_arm_stop;
148                 ops->start = op_arm_start;
149                 ops->stop = op_arm_stop;
150                 ops->cpu_type = op_arm_model->name;
151                 ops->backtrace = arm_backtrace;
152                 printk(KERN_INFO "oprofile: using %s\n", spec->name);
153         }
154
155         return ret;
156 }
157
158 void oprofile_arch_exit(void)
159 {
160         if (op_arm_model) {
161                 exit_driverfs();
162                 op_arm_model = NULL;
163         }
164 }
165