[ARM] 2/4 Fix oprofile suspend/resume
[linux-2.6/sactl.git] / arch / arm / oprofile / common.c
blob02e5d6f4516600747308b8d7805f2bb3013d1aad
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/sysdev.h>
14 #include <asm/semaphore.h>
16 #include "op_counter.h"
17 #include "op_arm_model.h"
19 static struct op_arm_model_spec *pmu_model;
20 static int pmu_enabled;
21 static struct semaphore pmu_sem;
23 struct op_counter_config counter_config[OP_MAX_COUNTER];
25 static int pmu_create_files(struct super_block *sb, struct dentry *root)
27 unsigned int i;
29 for (i = 0; i < pmu_model->num_counters; i++) {
30 struct dentry *dir;
31 char buf[2];
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);
43 return 0;
46 static int pmu_setup(void)
48 int ret;
50 spin_lock(&oprofilefs_lock);
51 ret = pmu_model->setup_ctrs();
52 spin_unlock(&oprofilefs_lock);
53 return ret;
56 static int pmu_start(void)
58 int ret = -EBUSY;
60 down(&pmu_sem);
61 if (!pmu_enabled) {
62 ret = pmu_model->start();
63 pmu_enabled = !ret;
65 up(&pmu_sem);
66 return ret;
69 static void pmu_stop(void)
71 down(&pmu_sem);
72 if (pmu_enabled)
73 pmu_model->stop();
74 pmu_enabled = 0;
75 up(&pmu_sem);
78 #ifdef CONFIG_PM
79 static int pmu_suspend(struct sys_device *dev, pm_message_t state)
81 down(&pmu_sem);
82 if (pmu_enabled)
83 pmu_model->stop();
84 up(&pmu_sem);
85 return 0;
88 static int pmu_resume(struct sys_device *dev)
90 down(&pmu_sem);
91 if (pmu_enabled && pmu_model->start())
92 pmu_enabled = 0;
93 up(&pmu_sem);
94 return 0;
97 static struct sysdev_class oprofile_sysclass = {
98 set_kset_name("oprofile"),
99 .resume = pmu_resume,
100 .suspend = pmu_suspend,
103 static struct sys_device device_oprofile = {
104 .id = 0,
105 .cls = &oprofile_sysclass,
108 static int __init init_driverfs(void)
110 int ret;
112 if (!(ret = sysdev_class_register(&oprofile_sysclass)))
113 ret = sysdev_register(&device_oprofile);
115 return ret;
118 static void exit_driverfs(void)
120 sysdev_unregister(&device_oprofile);
121 sysdev_class_unregister(&oprofile_sysclass);
123 #else
124 #define init_driverfs() do { } while (0)
125 #define exit_driverfs() do { } while (0)
126 #endif /* CONFIG_PM */
128 int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec)
130 init_MUTEX(&pmu_sem);
132 if (spec->init() < 0)
133 return -ENODEV;
135 pmu_model = spec;
136 init_driverfs();
137 ops->create_files = pmu_create_files;
138 ops->setup = pmu_setup;
139 ops->shutdown = pmu_stop;
140 ops->start = pmu_start;
141 ops->stop = pmu_stop;
142 ops->cpu_type = pmu_model->name;
143 printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
145 return 0;
148 void pmu_exit(void)
150 if (pmu_model) {
151 exit_driverfs();
152 pmu_model = NULL;