Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / oprofile / oprof.c
1 /**
2  * @file oprof.c
3  *
4  * @remark Copyright 2002 OProfile authors
5  * @remark Read the file COPYING
6  *
7  * @author John Levon <levon@movementarian.org>
8  *
9  * Modified by Aravind Menon for Xen
10  * These modifications are:
11  * Copyright (C) 2005 Hewlett-Packard Co.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/oprofile.h>
18 #include <linux/moduleparam.h>
19 #include <asm/mutex.h>
20
21 #include "oprof.h"
22 #include "event_buffer.h"
23 #include "cpu_buffer.h"
24 #include "buffer_sync.h"
25 #include "oprofile_stats.h"
26
27 struct oprofile_operations oprofile_ops;
28
29 unsigned long oprofile_started;
30 unsigned long backtrace_depth;
31 static unsigned long is_setup;
32 static DEFINE_MUTEX(start_mutex);
33
34 /* timer
35    0 - use performance monitoring hardware if available
36    1 - use the timer int mechanism regardless
37  */
38 static int timer = 0;
39
40 int oprofile_set_active(int active_domains[], unsigned int adomains)
41 {
42         int err;
43
44         if (!oprofile_ops.set_active)
45                 return -EINVAL;
46
47         mutex_lock(&start_mutex);
48         err = oprofile_ops.set_active(active_domains, adomains);
49         mutex_unlock(&start_mutex);
50         return err;
51 }
52
53 int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
54 {
55         int err;
56
57         if (!oprofile_ops.set_passive)
58                 return -EINVAL;
59
60         mutex_lock(&start_mutex);
61         err = oprofile_ops.set_passive(passive_domains, pdomains);
62         mutex_unlock(&start_mutex);
63         return err;
64 }
65
66 int oprofile_setup(void)
67 {
68         int err;
69  
70         mutex_lock(&start_mutex);
71
72         if ((err = alloc_cpu_buffers()))
73                 goto out;
74
75         if ((err = alloc_event_buffer()))
76                 goto out1;
77  
78         if (oprofile_ops.setup && (err = oprofile_ops.setup()))
79                 goto out2;
80  
81         /* Note even though this starts part of the
82          * profiling overhead, it's necessary to prevent
83          * us missing task deaths and eventually oopsing
84          * when trying to process the event buffer.
85          */
86         if ((err = sync_start()))
87                 goto out3;
88
89         is_setup = 1;
90         mutex_unlock(&start_mutex);
91         return 0;
92  
93 out3:
94         if (oprofile_ops.shutdown)
95                 oprofile_ops.shutdown();
96 out2:
97         free_event_buffer();
98 out1:
99         free_cpu_buffers();
100 out:
101         mutex_unlock(&start_mutex);
102         return err;
103 }
104
105
106 /* Actually start profiling (echo 1>/dev/oprofile/enable) */
107 int oprofile_start(void)
108 {
109         int err = -EINVAL;
110  
111         mutex_lock(&start_mutex);
112  
113         if (!is_setup)
114                 goto out;
115
116         err = 0; 
117  
118         if (oprofile_started)
119                 goto out;
120  
121         oprofile_reset_stats();
122
123         if ((err = oprofile_ops.start()))
124                 goto out;
125
126         oprofile_started = 1;
127 out:
128         mutex_unlock(&start_mutex);
129         return err;
130 }
131
132  
133 /* echo 0>/dev/oprofile/enable */
134 void oprofile_stop(void)
135 {
136         mutex_lock(&start_mutex);
137         if (!oprofile_started)
138                 goto out;
139         oprofile_ops.stop();
140         oprofile_started = 0;
141         /* wake up the daemon to read what remains */
142         wake_up_buffer_waiter();
143 out:
144         mutex_unlock(&start_mutex);
145 }
146
147
148 void oprofile_shutdown(void)
149 {
150         mutex_lock(&start_mutex);
151         sync_stop();
152         if (oprofile_ops.shutdown)
153                 oprofile_ops.shutdown();
154         is_setup = 0;
155         free_event_buffer();
156         free_cpu_buffers();
157         mutex_unlock(&start_mutex);
158 }
159
160
161 int oprofile_set_backtrace(unsigned long val)
162 {
163         int err = 0;
164
165         mutex_lock(&start_mutex);
166
167         if (oprofile_started) {
168                 err = -EBUSY;
169                 goto out;
170         }
171
172         if (!oprofile_ops.backtrace) {
173                 err = -EINVAL;
174                 goto out;
175         }
176
177         backtrace_depth = val;
178
179 out:
180         mutex_unlock(&start_mutex);
181         return err;
182 }
183
184 static int __init oprofile_init(void)
185 {
186         int err;
187
188         err = oprofile_arch_init(&oprofile_ops);
189
190         if (err < 0 || timer) {
191                 printk(KERN_INFO "oprofile: using timer interrupt.\n");
192                 oprofile_timer_init(&oprofile_ops);
193         }
194
195         err = oprofilefs_register();
196         if (err)
197                 oprofile_arch_exit();
198
199         return err;
200 }
201
202
203 static void __exit oprofile_exit(void)
204 {
205         oprofilefs_unregister();
206         oprofile_arch_exit();
207 }
208
209  
210 module_init(oprofile_init);
211 module_exit(oprofile_exit);
212
213 module_param_named(timer, timer, int, 0644);
214 MODULE_PARM_DESC(timer, "force use of timer interrupt");
215  
216 MODULE_LICENSE("GPL");
217 MODULE_AUTHOR("John Levon <levon@movementarian.org>");
218 MODULE_DESCRIPTION("OProfile system profiler");