Merge branch 'x86/cpufeature' into irq/numa
[sfrench/cifs-2.6.git] / arch / sh / oprofile / common.c
1 /*
2  * arch/sh/oprofile/init.c
3  *
4  * Copyright (C) 2003 - 2008  Paul Mundt
5  *
6  * Based on arch/mips/oprofile/common.c:
7  *
8  *      Copyright (C) 2004, 2005 Ralf Baechle
9  *      Copyright (C) 2005 MIPS Technologies, Inc.
10  *
11  * This file is subject to the terms and conditions of the GNU General Public
12  * License.  See the file "COPYING" in the main directory of this archive
13  * for more details.
14  */
15 #include <linux/kernel.h>
16 #include <linux/oprofile.h>
17 #include <linux/init.h>
18 #include <linux/errno.h>
19 #include <linux/smp.h>
20 #include <asm/processor.h>
21 #include "op_impl.h"
22
23 extern struct op_sh_model op_model_sh7750_ops __weak;
24 extern struct op_sh_model op_model_sh4a_ops __weak;
25
26 static struct op_sh_model *model;
27
28 static struct op_counter_config ctr[20];
29
30 extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
31
32 static int op_sh_setup(void)
33 {
34         /* Pre-compute the values to stuff in the hardware registers.  */
35         model->reg_setup(ctr);
36
37         /* Configure the registers on all cpus.  */
38         on_each_cpu(model->cpu_setup, NULL, 1);
39
40         return 0;
41 }
42
43 static int op_sh_create_files(struct super_block *sb, struct dentry *root)
44 {
45         int i, ret = 0;
46
47         for (i = 0; i < model->num_counters; i++) {
48                 struct dentry *dir;
49                 char buf[4];
50
51                 snprintf(buf, sizeof(buf), "%d", i);
52                 dir = oprofilefs_mkdir(sb, root, buf);
53
54                 ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
55                 ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
56                 ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
57                 ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
58
59                 if (model->create_files)
60                         ret |= model->create_files(sb, dir);
61                 else
62                         ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
63
64                 /* Dummy entries */
65                 ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
66         }
67
68         return ret;
69 }
70
71 static int op_sh_start(void)
72 {
73         /* Enable performance monitoring for all counters.  */
74         on_each_cpu(model->cpu_start, NULL, 1);
75
76         return 0;
77 }
78
79 static void op_sh_stop(void)
80 {
81         /* Disable performance monitoring for all counters.  */
82         on_each_cpu(model->cpu_stop, NULL, 1);
83 }
84
85 int __init oprofile_arch_init(struct oprofile_operations *ops)
86 {
87         struct op_sh_model *lmodel = NULL;
88         int ret;
89
90         /*
91          * Always assign the backtrace op. If the counter initialization
92          * fails, we fall back to the timer which will still make use of
93          * this.
94          */
95         ops->backtrace = sh_backtrace;
96
97         switch (current_cpu_data.type) {
98         /* SH-4 types */
99         case CPU_SH7750:
100         case CPU_SH7750S:
101                 lmodel = &op_model_sh7750_ops;
102                 break;
103
104         /* SH-4A types */
105         case CPU_SH7763:
106         case CPU_SH7770:
107         case CPU_SH7780:
108         case CPU_SH7781:
109         case CPU_SH7785:
110         case CPU_SH7786:
111         case CPU_SH7723:
112         case CPU_SHX3:
113                 lmodel = &op_model_sh4a_ops;
114                 break;
115
116         /* SH4AL-DSP types */
117         case CPU_SH7343:
118         case CPU_SH7722:
119         case CPU_SH7366:
120                 lmodel = &op_model_sh4a_ops;
121                 break;
122         }
123
124         if (!lmodel)
125                 return -ENODEV;
126         if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
127                 return -ENODEV;
128
129         ret = lmodel->init();
130         if (unlikely(ret != 0))
131                 return ret;
132
133         model = lmodel;
134
135         ops->setup              = op_sh_setup;
136         ops->create_files       = op_sh_create_files;
137         ops->start              = op_sh_start;
138         ops->stop               = op_sh_stop;
139         ops->cpu_type           = lmodel->cpu_type;
140
141         printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
142                lmodel->cpu_type);
143
144         return 0;
145 }
146
147 void oprofile_arch_exit(void)
148 {
149         if (model && model->exit)
150                 model->exit();
151 }