]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/ppc/oprofile/common.c
f63bee23f20c04d84d434b1ed600767009b720c2
[karo-tx-linux.git] / arch / ppc / oprofile / common.c
1 /*
2  * PPC 32 oprofile support
3  * Based on PPC64 oprofile support
4  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
5  *
6  * Copyright (C) Freescale Semiconductor, Inc 2004
7  *
8  * Author: Andy Fleming
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version
13  * 2 of the License, or (at your option) any later version.
14  */
15
16 #include <linux/oprofile.h>
17 #include <linux/slab.h>
18 #include <linux/init.h>
19 #include <linux/smp.h>
20 #include <linux/errno.h>
21 #include <asm/ptrace.h>
22 #include <asm/system.h>
23 #include <asm/perfmon.h>
24 #include <asm/cputable.h>
25 #include <asm/oprofile_impl.h>
26
27 static struct op_powerpc_model *model;
28
29 static struct op_counter_config ctr[OP_MAX_COUNTER];
30 static struct op_system_config sys;
31
32 static void op_handle_interrupt(struct pt_regs *regs)
33 {
34         model->handle_interrupt(regs, ctr);
35 }
36
37 static int op_ppc32_setup(void)
38 {
39         /* Install our interrupt handler into the existing hook.  */
40         if(request_perfmon_irq(&op_handle_interrupt))
41                 return -EBUSY;
42
43         mb();
44
45         /* Pre-compute the values to stuff in the hardware registers.  */
46         model->reg_setup(ctr, &sys, model->num_counters);
47
48 #if 0
49         /* FIXME: Make multi-cpu work */
50         /* Configure the registers on all cpus.  */
51         on_each_cpu(model->reg_setup, NULL, 0, 1);
52 #endif
53
54         return 0;
55 }
56
57 static void op_ppc32_shutdown(void)
58 {
59         mb();
60
61         /* Remove our interrupt handler. We may be removing this module. */
62         free_perfmon_irq();
63 }
64
65 static void op_ppc32_cpu_start(void *dummy)
66 {
67         model->start(ctr);
68 }
69
70 static int op_ppc32_start(void)
71 {
72         on_each_cpu(op_ppc32_cpu_start, NULL, 0, 1);
73         return 0;
74 }
75
76 static inline void op_ppc32_cpu_stop(void *dummy)
77 {
78         model->stop();
79 }
80
81 static void op_ppc32_stop(void)
82 {
83         on_each_cpu(op_ppc32_cpu_stop, NULL, 0, 1);
84 }
85
86 static int op_ppc32_create_files(struct super_block *sb, struct dentry *root)
87 {
88         int i;
89
90         for (i = 0; i < model->num_counters; ++i) {
91                 struct dentry *dir;
92                 char buf[3];
93
94                 snprintf(buf, sizeof buf, "%d", i);
95                 dir = oprofilefs_mkdir(sb, root, buf);
96
97                 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
98                 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
99                 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
100                 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
101                 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
102
103                 /* FIXME: Not sure if this is used */
104                 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
105         }
106
107         oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
108         oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
109
110         /* Default to tracing both kernel and user */
111         sys.enable_kernel = 1;
112         sys.enable_user = 1;
113
114         return 0;
115 }
116
117 static struct oprofile_operations oprof_ppc32_ops = {
118         .create_files   = op_ppc32_create_files,
119         .setup          = op_ppc32_setup,
120         .shutdown       = op_ppc32_shutdown,
121         .start          = op_ppc32_start,
122         .stop           = op_ppc32_stop,
123         .cpu_type       = NULL          /* To be filled in below. */
124 };
125
126 int __init oprofile_arch_init(struct oprofile_operations *ops)
127 {
128         char *name;
129         int cpu_id = smp_processor_id();
130
131 #ifdef CONFIG_FSL_BOOKE
132         model = &op_model_fsl_booke;
133 #else
134         return -ENODEV;
135 #endif
136
137         name = kmalloc(32, GFP_KERNEL);
138
139         if (NULL == name)
140                 return -ENOMEM;
141
142         sprintf(name, "ppc/%s", cur_cpu_spec[cpu_id]->cpu_name);
143
144         oprof_ppc32_ops.cpu_type = name;
145
146         model->num_counters = cur_cpu_spec[cpu_id]->num_pmcs;
147
148         *ops = oprof_ppc32_ops;
149
150         printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
151                oprof_ppc32_ops.cpu_type);
152
153         return 0;
154 }
155
156 void oprofile_arch_exit(void)
157 {
158         kfree(oprof_ppc32_ops.cpu_type);
159         oprof_ppc32_ops.cpu_type = NULL;
160 }