blob: b57b6d11c9fb5366d0d08472b526d91a89f544aa [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/sysdev.h>
Russell King93ad7942006-03-16 11:38:16 +000014#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
16#include "op_counter.h"
17#include "op_arm_model.h"
18
Russell King55f05232005-10-28 14:54:21 +010019static struct op_arm_model_spec *op_arm_model;
20static int op_arm_enabled;
Russell King93ad7942006-03-16 11:38:16 +000021static DEFINE_MUTEX(op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Linus Torvalds1da177e2005-04-16 15:20:36 -070023struct op_counter_config counter_config[OP_MAX_COUNTER];
24
Russell King55f05232005-10-28 14:54:21 +010025static int op_arm_create_files(struct super_block *sb, struct dentry *root)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026{
27 unsigned int i;
28
Russell King55f05232005-10-28 14:54:21 +010029 for (i = 0; i < op_arm_model->num_counters; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 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
Russell King55f05232005-10-28 14:54:21 +010046static int op_arm_setup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047{
48 int ret;
49
50 spin_lock(&oprofilefs_lock);
Russell King55f05232005-10-28 14:54:21 +010051 ret = op_arm_model->setup_ctrs();
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 spin_unlock(&oprofilefs_lock);
53 return ret;
54}
55
Russell King55f05232005-10-28 14:54:21 +010056static int op_arm_start(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070057{
58 int ret = -EBUSY;
59
Russell King93ad7942006-03-16 11:38:16 +000060 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010061 if (!op_arm_enabled) {
62 ret = op_arm_model->start();
63 op_arm_enabled = !ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 }
Russell King93ad7942006-03-16 11:38:16 +000065 mutex_unlock(&op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 return ret;
67}
68
Russell King55f05232005-10-28 14:54:21 +010069static void op_arm_stop(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Russell King93ad7942006-03-16 11:38:16 +000071 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010072 if (op_arm_enabled)
73 op_arm_model->stop();
74 op_arm_enabled = 0;
Russell King93ad7942006-03-16 11:38:16 +000075 mutex_unlock(&op_arm_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
77
Russell Kingb5893c52005-10-28 14:51:15 +010078#ifdef CONFIG_PM
Russell King55f05232005-10-28 14:54:21 +010079static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
Russell Kingb5893c52005-10-28 14:51:15 +010080{
Russell King93ad7942006-03-16 11:38:16 +000081 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010082 if (op_arm_enabled)
83 op_arm_model->stop();
Russell King93ad7942006-03-16 11:38:16 +000084 mutex_unlock(&op_arm_mutex);
Russell Kingb5893c52005-10-28 14:51:15 +010085 return 0;
86}
87
Russell King55f05232005-10-28 14:54:21 +010088static int op_arm_resume(struct sys_device *dev)
Russell Kingb5893c52005-10-28 14:51:15 +010089{
Russell King93ad7942006-03-16 11:38:16 +000090 mutex_lock(&op_arm_mutex);
Russell King55f05232005-10-28 14:54:21 +010091 if (op_arm_enabled && op_arm_model->start())
92 op_arm_enabled = 0;
Russell King93ad7942006-03-16 11:38:16 +000093 mutex_unlock(&op_arm_mutex);
Russell Kingb5893c52005-10-28 14:51:15 +010094 return 0;
95}
96
97static struct sysdev_class oprofile_sysclass = {
98 set_kset_name("oprofile"),
Russell King55f05232005-10-28 14:54:21 +010099 .resume = op_arm_resume,
100 .suspend = op_arm_suspend,
Russell Kingb5893c52005-10-28 14:51:15 +0100101};
102
103static struct sys_device device_oprofile = {
104 .id = 0,
105 .cls = &oprofile_sysclass,
106};
107
108static 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
118static 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
Russell Kingc6b9daf2005-10-28 14:56:04 +0100128int __init oprofile_arch_init(struct oprofile_operations *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Russell Kingc6b9daf2005-10-28 14:56:04 +0100130 struct op_arm_model_spec *spec = NULL;
131 int ret = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Russell Kingc6b9daf2005-10-28 14:56:04 +0100133#ifdef CONFIG_CPU_XSCALE
134 spec = &op_xscale_spec;
135#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Russell Kingc6b9daf2005-10-28 14:56:04 +0100137 if (spec) {
Russ Dill7610dfa2006-02-01 21:07:28 +0000138 ret = spec->init();
139 if (ret < 0)
140 return ret;
Russell Kingc6b9daf2005-10-28 14:56:04 +0100141
142 op_arm_model = spec;
143 init_driverfs();
144 ops->create_files = op_arm_create_files;
145 ops->setup = op_arm_setup;
146 ops->shutdown = op_arm_stop;
147 ops->start = op_arm_start;
148 ops->stop = op_arm_stop;
149 ops->cpu_type = op_arm_model->name;
150 ops->backtrace = arm_backtrace;
151 printk(KERN_INFO "oprofile: using %s\n", spec->name);
152 }
153
154 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
Russell Kingc6b9daf2005-10-28 14:56:04 +0100157void oprofile_arch_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
Russell King55f05232005-10-28 14:54:21 +0100159 if (op_arm_model) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 exit_driverfs();
Russell King55f05232005-10-28 14:54:21 +0100161 op_arm_model = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
163}