# BRCM_VERSION=3
[bcm963xx.git] / kernel / linux / 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 <asm/semaphore.h>
14
15 #include "op_counter.h"
16 #include "op_arm_model.h"
17
18 static struct op_arm_model_spec *pmu_model;
19 static int pmu_enabled;
20 static struct semaphore pmu_sem;
21
22 static int pmu_start(void);
23 static int pmu_setup(void);
24 static void pmu_stop(void);
25 static int pmu_create_files(struct super_block *, struct dentry *);
26
27 static struct oprofile_operations pmu_ops = {
28         .create_files   = pmu_create_files,
29         .setup          = pmu_setup,
30         .shutdown       = pmu_stop,
31         .start          = pmu_start,
32         .stop           = pmu_stop,
33 };
34
35 #ifdef CONFIG_PM
36 static struct sys_device device_oprofile = {
37         .id             = 0,
38         .cls            = &oprofile_sysclass,
39 };
40
41 static int __init init_driverfs(void)
42 {
43         int ret;
44
45         if (!(ret = sysdev_class_register(&oprofile_sysclass)))
46                 ret = sys_device_register(&device_oprofile);
47
48         return ret;
49 }
50
51 static void __exit exit_driverfs(void)
52 {
53         sys_device_unregister(&device_oprofile);
54         sysdev_class_unregister(&oprofile_sysclass);
55 }
56 #else
57 #define init_driverfs() do { } while (0)
58 #define exit_driverfs() do { } while (0)
59 #endif /* CONFIG_PM */
60
61 struct op_counter_config counter_config[OP_MAX_COUNTER];
62
63 static int pmu_create_files(struct super_block *sb, struct dentry *root)
64 {
65         unsigned int i;
66
67         for (i = 0; i < pmu_model->num_counters; i++) {
68                 struct dentry *dir;
69                 char buf[2];
70
71                 snprintf(buf, sizeof buf, "%d", i);
72                 dir = oprofilefs_mkdir(sb, root, buf);
73                 oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
74                 oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
75                 oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
76                 oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
77                 oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
78                 oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
79         }
80
81         return 0;
82 }
83
84 static int pmu_setup(void)
85 {
86         int ret;
87
88         spin_lock(&oprofilefs_lock);
89         ret = pmu_model->setup_ctrs();
90         spin_unlock(&oprofilefs_lock);
91         return ret;
92 }
93
94 static int pmu_start(void)
95 {
96         int ret = -EBUSY;
97
98         down(&pmu_sem);
99         if (!pmu_enabled) {
100                 ret = pmu_model->start();
101                 pmu_enabled = !ret;
102         }
103         up(&pmu_sem);
104         return ret;
105 }
106
107 static void pmu_stop(void)
108 {
109         down(&pmu_sem);
110         if (pmu_enabled)
111                 pmu_model->stop();
112         pmu_enabled = 0;
113         up(&pmu_sem);
114 }
115
116 int __init pmu_init(struct oprofile_operations **ops, struct op_arm_model_spec *spec)
117 {
118         init_MUTEX(&pmu_sem);
119
120         if (spec->init() < 0)
121                 return -ENODEV;
122
123         pmu_model = spec;
124         init_driverfs();
125         *ops = &pmu_ops;
126         pmu_ops.cpu_type = pmu_model->name;
127         printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
128         return 0;
129 }
130
131 void pmu_exit(void)
132 {
133         if (pmu_model) {
134                 exit_driverfs();
135                 pmu_model = NULL;
136         }
137 }
138