Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / arch / ia64 / kernel / perfmon_default_smpl.c
1 /*
2  * Copyright (C) 2002-2003 Hewlett-Packard Co
3  *               Stephane Eranian <eranian@hpl.hp.com>
4  *
5  * This file implements the default sampling buffer format
6  * for the Linux/ia64 perfmon-2 subsystem.
7  */
8 #include <linux/kernel.h>
9 #include <linux/types.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <asm/delay.h>
13 #include <linux/smp.h>
14
15 #include <asm/perfmon.h>
16 #include <asm/perfmon_default_smpl.h>
17
18 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
19 MODULE_DESCRIPTION("perfmon default sampling format");
20 MODULE_LICENSE("GPL");
21
22 #define DEFAULT_DEBUG 1
23
24 #ifdef DEFAULT_DEBUG
25 #define DPRINT(a) \
26         do { \
27                 if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
28         } while (0)
29
30 #define DPRINT_ovfl(a) \
31         do { \
32                 if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
33         } while (0)
34
35 #else
36 #define DPRINT(a)
37 #define DPRINT_ovfl(a)
38 #endif
39
40 static int
41 default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
42 {
43         pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data;
44         int ret = 0;
45
46         if (data == NULL) {
47                 DPRINT(("[%d] no argument passed\n", task_pid_nr(task)));
48                 return -EINVAL;
49         }
50
51         DPRINT(("[%d] validate flags=0x%x CPU%d\n", task_pid_nr(task), flags, cpu));
52
53         /*
54          * must hold at least the buffer header + one minimally sized entry
55          */
56         if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL;
57
58         DPRINT(("buf_size=%lu\n", arg->buf_size));
59
60         return ret;
61 }
62
63 static int
64 default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size)
65 {
66         pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
67
68         /*
69          * size has been validated in default_validate
70          */
71         *size = arg->buf_size;
72
73         return 0;
74 }
75
76 static int
77 default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data)
78 {
79         pfm_default_smpl_hdr_t *hdr;
80         pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
81
82         hdr = (pfm_default_smpl_hdr_t *)buf;
83
84         hdr->hdr_version      = PFM_DEFAULT_SMPL_VERSION;
85         hdr->hdr_buf_size     = arg->buf_size;
86         hdr->hdr_cur_offs     = sizeof(*hdr);
87         hdr->hdr_overflows    = 0UL;
88         hdr->hdr_count        = 0UL;
89
90         DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n",
91                 task_pid_nr(task),
92                 buf,
93                 hdr->hdr_buf_size,
94                 sizeof(*hdr),
95                 hdr->hdr_version,
96                 hdr->hdr_cur_offs));
97
98         return 0;
99 }
100
101 static int
102 default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp)
103 {
104         pfm_default_smpl_hdr_t *hdr;
105         pfm_default_smpl_entry_t *ent;
106         void *cur, *last;
107         unsigned long *e, entry_size;
108         unsigned int npmds, i;
109         unsigned char ovfl_pmd;
110         unsigned char ovfl_notify;
111
112         if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) {
113                 DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg));
114                 return -EINVAL;
115         }
116
117         hdr         = (pfm_default_smpl_hdr_t *)buf;
118         cur         = buf+hdr->hdr_cur_offs;
119         last        = buf+hdr->hdr_buf_size;
120         ovfl_pmd    = arg->ovfl_pmd;
121         ovfl_notify = arg->ovfl_notify;
122
123         /*
124          * precheck for sanity
125          */
126         if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
127
128         npmds = hweight64(arg->smpl_pmds[0]);
129
130         ent = (pfm_default_smpl_entry_t *)cur;
131
132         prefetch(arg->smpl_pmds_values);
133
134         entry_size = sizeof(*ent) + (npmds << 3);
135
136         /* position for first pmd */
137         e = (unsigned long *)(ent+1);
138
139         hdr->hdr_count++;
140
141         DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n",
142                         task->pid,
143                         hdr->hdr_count,
144                         cur, last,
145                         last-cur,
146                         ovfl_pmd,
147                         ovfl_notify, npmds));
148
149         /*
150          * current = task running at the time of the overflow.
151          *
152          * per-task mode:
153          *      - this is ususally the task being monitored.
154          *        Under certain conditions, it might be a different task
155          *
156          * system-wide:
157          *      - this is not necessarily the task controlling the session
158          */
159         ent->pid            = current->pid;
160         ent->ovfl_pmd       = ovfl_pmd;
161         ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val;
162
163         /*
164          * where did the fault happen (includes slot number)
165          */
166         ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3);
167
168         ent->tstamp    = stamp;
169         ent->cpu       = smp_processor_id();
170         ent->set       = arg->active_set;
171         ent->tgid      = current->tgid;
172
173         /*
174          * selectively store PMDs in increasing index number
175          */
176         if (npmds) {
177                 unsigned long *val = arg->smpl_pmds_values;
178                 for(i=0; i < npmds; i++) {
179                         *e++ = *val++;
180                 }
181         }
182
183         /*
184          * update position for next entry
185          */
186         hdr->hdr_cur_offs += entry_size;
187         cur               += entry_size;
188
189         /*
190          * post check to avoid losing the last sample
191          */
192         if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
193
194         /*
195          * keep same ovfl_pmds, ovfl_notify
196          */
197         arg->ovfl_ctrl.bits.notify_user     = 0;
198         arg->ovfl_ctrl.bits.block_task      = 0;
199         arg->ovfl_ctrl.bits.mask_monitoring = 0;
200         arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */
201
202         return 0;
203 full:
204         DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify));
205
206         /*
207          * increment number of buffer overflow.
208          * important to detect duplicate set of samples.
209          */
210         hdr->hdr_overflows++;
211
212         /*
213          * if no notification requested, then we saturate the buffer
214          */
215         if (ovfl_notify == 0) {
216                 arg->ovfl_ctrl.bits.notify_user     = 0;
217                 arg->ovfl_ctrl.bits.block_task      = 0;
218                 arg->ovfl_ctrl.bits.mask_monitoring = 1;
219                 arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0;
220         } else {
221                 arg->ovfl_ctrl.bits.notify_user     = 1;
222                 arg->ovfl_ctrl.bits.block_task      = 1; /* ignored for non-blocking context */
223                 arg->ovfl_ctrl.bits.mask_monitoring = 1;
224                 arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */
225         }
226         return -1; /* we are full, sorry */
227 }
228
229 static int
230 default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
231 {
232         pfm_default_smpl_hdr_t *hdr;
233
234         hdr = (pfm_default_smpl_hdr_t *)buf;
235
236         hdr->hdr_count    = 0UL;
237         hdr->hdr_cur_offs = sizeof(*hdr);
238
239         ctrl->bits.mask_monitoring = 0;
240         ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */
241
242         return 0;
243 }
244
245 static int
246 default_exit(struct task_struct *task, void *buf, struct pt_regs *regs)
247 {
248         DPRINT(("[%d] exit(%p)\n", task_pid_nr(task), buf));
249         return 0;
250 }
251
252 static pfm_buffer_fmt_t default_fmt={
253         .fmt_name           = "default_format",
254         .fmt_uuid           = PFM_DEFAULT_SMPL_UUID,
255         .fmt_arg_size       = sizeof(pfm_default_smpl_arg_t),
256         .fmt_validate       = default_validate,
257         .fmt_getsize        = default_get_size,
258         .fmt_init           = default_init,
259         .fmt_handler        = default_handler,
260         .fmt_restart        = default_restart,
261         .fmt_restart_active = default_restart,
262         .fmt_exit           = default_exit,
263 };
264
265 static int __init
266 pfm_default_smpl_init_module(void)
267 {
268         int ret;
269
270         ret = pfm_register_buffer_fmt(&default_fmt);
271         if (ret == 0) {
272                 printk("perfmon_default_smpl: %s v%u.%u registered\n",
273                         default_fmt.fmt_name,
274                         PFM_DEFAULT_SMPL_VERSION_MAJ,
275                         PFM_DEFAULT_SMPL_VERSION_MIN);
276         } else {
277                 printk("perfmon_default_smpl: %s cannot register ret=%d\n",
278                         default_fmt.fmt_name,
279                         ret);
280         }
281
282         return ret;
283 }
284
285 static void __exit
286 pfm_default_smpl_cleanup_module(void)
287 {
288         int ret;
289         ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid);
290
291         printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret);
292 }
293
294 module_init(pfm_default_smpl_init_module);
295 module_exit(pfm_default_smpl_cleanup_module);
296