blob: 3fcd752d6146d205860e00464ff23ca8008a7cd0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/**
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>
Russell Kingae92dc92006-03-16 11:32:51 +000013#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/sysdev.h>
Russell King93ad7942006-03-16 11:38:16 +000015#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include "op_counter.h"
18#include "op_arm_model.h"
19
Russell King55f05232005-10-28 14:54:21 +010020static struct op_arm_model_spec *op_arm_model;
21static int op_arm_enabled;
Russell King93ad7942006-03-16 11:38:16 +000022static DEFINE_MUTEX(op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Russell Kingae92dc92006-03-16 11:32:51 +000024struct op_counter_config *counter_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Russell King55f05232005-10-28 14:54:21 +010026static int op_arm_create_files(struct super_block *sb, struct dentry *root)
Linus Torvalds1da177e2005-04-16 15:20:36 -070027{
28 unsigned int i;
29
Russell King55f05232005-10-28 14:54:21 +010030 for (i = 0; i < op_arm_model->num_counters; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 struct dentry *dir;
Russell Kingae92dc92006-03-16 11:32:51 +000032 char buf[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
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
Russell King55f05232005-10-28 14:54:21 +010047static int op_arm_setup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
49 int ret;
50
51 spin_lock(&oprofilefs_lock);
Russell King55f05232005-10-28 14:54:21 +010052 ret = op_arm_model->setup_ctrs();
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 spin_unlock(&oprofilefs_lock);
54 return ret;
55}
56
Russell King55f05232005-10-28 14:54:21 +010057static int op_arm_start(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
59 int ret = -EBUSY;
60
Russell King93ad7942006-03-16 11:38:16 +000061 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010062 if (!op_arm_enabled) {
63 ret = op_arm_model->start();
64 op_arm_enabled = !ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 }
Russell King93ad7942006-03-16 11:38:16 +000066 mutex_unlock(&op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 return ret;
68}
69
Russell King55f05232005-10-28 14:54:21 +010070static void op_arm_stop(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
Russell King93ad7942006-03-16 11:38:16 +000072 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010073 if (op_arm_enabled)
74 op_arm_model->stop();
75 op_arm_enabled = 0;
Russell King93ad7942006-03-16 11:38:16 +000076 mutex_unlock(&op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077}
78
Russell Kingb5893c52005-10-28 14:51:15 +010079#ifdef CONFIG_PM
Russell King55f05232005-10-28 14:54:21 +010080static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
Russell Kingb5893c52005-10-28 14:51:15 +010081{
Russell King93ad7942006-03-16 11:38:16 +000082 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010083 if (op_arm_enabled)
84 op_arm_model->stop();
Russell King93ad7942006-03-16 11:38:16 +000085 mutex_unlock(&op_arm_mutex);
Russell Kingb5893c52005-10-28 14:51:15 +010086 return 0;
87}
88
Russell King55f05232005-10-28 14:54:21 +010089static int op_arm_resume(struct sys_device *dev)
Russell Kingb5893c52005-10-28 14:51:15 +010090{
Russell King93ad7942006-03-16 11:38:16 +000091 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010092 if (op_arm_enabled && op_arm_model->start())
93 op_arm_enabled = 0;
Russell King93ad7942006-03-16 11:38:16 +000094 mutex_unlock(&op_arm_mutex);
Russell Kingb5893c52005-10-28 14:51:15 +010095 return 0;
96}
97
98static struct sysdev_class oprofile_sysclass = {
Kay Sieversaf5ca3f2007-12-20 02:09:39 +010099 .name = "oprofile",
Russell King55f05232005-10-28 14:54:21 +0100100 .resume = op_arm_resume,
101 .suspend = op_arm_suspend,
Russell Kingb5893c52005-10-28 14:51:15 +0100102};
103
104static struct sys_device device_oprofile = {
105 .id = 0,
106 .cls = &oprofile_sysclass,
107};
108
109static 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
119static 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
Russell Kingc6b9daf2005-10-28 14:56:04 +0100129int __init oprofile_arch_init(struct oprofile_operations *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Russell Kingc6b9daf2005-10-28 14:56:04 +0100131 struct op_arm_model_spec *spec = NULL;
132 int ret = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Richard Purdie1b7b5692007-02-27 12:09:33 +0100134 ops->backtrace = arm_backtrace;
135
Russell Kingc6b9daf2005-10-28 14:56:04 +0100136#ifdef CONFIG_CPU_XSCALE
137 spec = &op_xscale_spec;
138#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Russell King2d9e1ae2006-12-19 12:41:22 +0000140#ifdef CONFIG_OPROFILE_ARMV6
141 spec = &op_armv6_spec;
142#endif
143
Russell King10c03f62006-12-19 14:17:46 +0000144#ifdef CONFIG_OPROFILE_MPCORE
145 spec = &op_mpcore_spec;
146#endif
147
Jean PIHETd7ac4e22008-08-12 19:07:39 +0100148#ifdef CONFIG_OPROFILE_ARMV7
149 spec = &op_armv7_spec;
150#endif
151
Russell Kingc6b9daf2005-10-28 14:56:04 +0100152 if (spec) {
Russ Dill7610dfa2006-02-01 21:07:28 +0000153 ret = spec->init();
154 if (ret < 0)
155 return ret;
Russell Kingc6b9daf2005-10-28 14:56:04 +0100156
Russell King58e9ff52006-03-20 16:52:32 +0000157 counter_config = kcalloc(spec->num_counters, sizeof(struct op_counter_config),
Russell Kingae92dc92006-03-16 11:32:51 +0000158 GFP_KERNEL);
159 if (!counter_config)
160 return -ENOMEM;
161
Russell Kingc6b9daf2005-10-28 14:56:04 +0100162 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;
Russell Kingc6b9daf2005-10-28 14:56:04 +0100170 printk(KERN_INFO "oprofile: using %s\n", spec->name);
171 }
172
173 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
Russell Kingc6b9daf2005-10-28 14:56:04 +0100176void oprofile_arch_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
Russell King55f05232005-10-28 14:54:21 +0100178 if (op_arm_model) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 exit_driverfs();
Russell King55f05232005-10-28 14:54:21 +0100180 op_arm_model = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
Russell Kingae92dc92006-03-16 11:32:51 +0000182 kfree(counter_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}