2 * arch/sh/oprofile/op_model_sh7750.c
4 * OProfile support for SH7750/SH7750S Performance Counters
6 * Copyright (C) 2003 - 2008 Paul Mundt
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
12 #include <linux/kernel.h>
13 #include <linux/oprofile.h>
14 #include <linux/profile.h>
15 #include <linux/init.h>
16 #include <linux/errno.h>
17 #include <linux/interrupt.h>
22 #define PM_CR_BASE 0xff000084 /* 16-bit */
23 #define PM_CTR_BASE 0xff100004 /* 32-bit */
25 #define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
26 #define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
27 #define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
29 #define PMCR_PMM_MASK 0x0000003f
31 #define PMCR_CLKF 0x00000100
32 #define PMCR_PMCLR 0x00002000
33 #define PMCR_PMST 0x00004000
34 #define PMCR_PMEN 0x00008000
36 struct op_sh_model op_model_sh7750_ops
;
40 static struct sh7750_ppc_register_config
{
47 * There are a number of events supported by each counter (33 in total).
48 * Since we have 2 counters, each counter will take the event code as it
49 * corresponds to the PMCR PMM setting. Each counter can be configured
52 * Event Code Description
53 * ---------- -----------
55 * 0x01 Operand read access
56 * 0x02 Operand write access
58 * 0x04 Operand cache read miss
59 * 0x05 Operand cache write miss
60 * 0x06 Instruction fetch (w/ cache)
61 * 0x07 Instruction TLB miss
62 * 0x08 Instruction cache miss
63 * 0x09 All operand accesses
64 * 0x0a All instruction accesses
65 * 0x0b OC RAM operand access
66 * 0x0d On-chip I/O space access
67 * 0x0e Operand access (r/w)
68 * 0x0f Operand cache miss (r/w)
69 * 0x10 Branch instruction
72 * 0x13 Instruction execution
73 * 0x14 Instruction execution in parallel
74 * 0x15 FPU Instruction execution
77 * 0x18 trapa instruction execution
80 * 0x21 Instruction cache fill
81 * 0x22 Operand cache fill
83 * 0x24 Pipeline freeze by I-cache miss
84 * 0x25 Pipeline freeze by D-cache miss
85 * 0x27 Pipeline freeze by branch instruction
86 * 0x28 Pipeline freeze by CPU register
87 * 0x29 Pipeline freeze by FPU
89 * Unfortunately we don't have a native exception or interrupt for counter
90 * overflow (although since these counters can run for 16.3 days without
91 * overflowing, it's not really necessary).
93 * OProfile on the other hand likes to have samples taken periodically, so
94 * for now we just piggyback the timer interrupt to get the expected
98 static int sh7750_timer_notify(struct pt_regs
*regs
)
100 oprofile_add_sample(regs
, 0);
104 static u64
sh7750_read_counter(int counter
)
106 return (u64
)((u64
)(__raw_readl(PMCTRH(counter
)) & 0xffff) << 32) |
107 __raw_readl(PMCTRL(counter
));
111 * Files will be in a path like:
113 * /<oprofilefs mount point>/<counter number>/<file>
115 * So when dealing with <file>, we look to the parent dentry for the counter
118 static inline int to_counter(struct file
*file
)
120 const unsigned char *name
= file
->f_path
.dentry
->d_parent
->d_name
.name
;
122 return (int)simple_strtol(name
, NULL
, 10);
126 * XXX: We have 48-bit counters, so we're probably going to want something
127 * more along the lines of oprofilefs_ullong_to_user().. Truncating to
128 * unsigned long works fine for now though, as long as we don't attempt to
129 * profile for too horribly long.
131 static ssize_t
sh7750_read_count(struct file
*file
, char __user
*buf
,
132 size_t count
, loff_t
*ppos
)
134 int counter
= to_counter(file
);
135 u64 val
= sh7750_read_counter(counter
);
137 return oprofilefs_ulong_to_user((unsigned long)val
, buf
, count
, ppos
);
140 static ssize_t
sh7750_write_count(struct file
*file
, const char __user
*buf
,
141 size_t count
, loff_t
*ppos
)
143 int counter
= to_counter(file
);
146 if (oprofilefs_ulong_from_user(&val
, buf
, count
))
150 * Any write will clear the counter, although only 0 should be
151 * written for this purpose, as we do not support setting the
152 * counter to an arbitrary value.
156 __raw_writew(__raw_readw(PMCR(counter
)) | PMCR_PMCLR
, PMCR(counter
));
161 static const struct file_operations count_fops
= {
162 .read
= sh7750_read_count
,
163 .write
= sh7750_write_count
,
166 static int sh7750_ppc_create_files(struct super_block
*sb
, struct dentry
*dir
)
168 return oprofilefs_create_file(sb
, dir
, "count", &count_fops
);
171 static void sh7750_ppc_reg_setup(struct op_counter_config
*ctr
)
173 unsigned int counters
= op_model_sh7750_ops
.num_counters
;
176 for (i
= 0; i
< counters
; i
++) {
177 regcache
[i
].ctrl
= 0;
178 regcache
[i
].cnt_hi
= 0;
179 regcache
[i
].cnt_lo
= 0;
184 regcache
[i
].ctrl
|= ctr
[i
].event
| PMCR_PMEN
| PMCR_PMST
;
185 regcache
[i
].cnt_hi
= (unsigned long)((ctr
->count
>> 32) & 0xffff);
186 regcache
[i
].cnt_lo
= (unsigned long)(ctr
->count
& 0xffffffff);
190 static void sh7750_ppc_cpu_setup(void *args
)
192 unsigned int counters
= op_model_sh7750_ops
.num_counters
;
195 for (i
= 0; i
< counters
; i
++) {
196 __raw_writew(0, PMCR(i
));
197 __raw_writel(regcache
[i
].cnt_hi
, PMCTRH(i
));
198 __raw_writel(regcache
[i
].cnt_lo
, PMCTRL(i
));
202 static void sh7750_ppc_cpu_start(void *args
)
204 unsigned int counters
= op_model_sh7750_ops
.num_counters
;
207 for (i
= 0; i
< counters
; i
++)
208 __raw_writew(regcache
[i
].ctrl
, PMCR(i
));
211 static void sh7750_ppc_cpu_stop(void *args
)
213 unsigned int counters
= op_model_sh7750_ops
.num_counters
;
216 /* Disable the counters */
217 for (i
= 0; i
< counters
; i
++)
218 __raw_writew(__raw_readw(PMCR(i
)) & ~PMCR_PMEN
, PMCR(i
));
221 static inline void sh7750_ppc_reset(void)
223 unsigned int counters
= op_model_sh7750_ops
.num_counters
;
226 /* Clear the counters */
227 for (i
= 0; i
< counters
; i
++)
228 __raw_writew(__raw_readw(PMCR(i
)) | PMCR_PMCLR
, PMCR(i
));
231 static int sh7750_ppc_init(void)
235 return register_timer_hook(sh7750_timer_notify
);
238 static void sh7750_ppc_exit(void)
240 unregister_timer_hook(sh7750_timer_notify
);
245 struct op_sh_model op_model_sh7750_ops
= {
246 .cpu_type
= "sh/sh7750",
247 .num_counters
= NR_CNTRS
,
248 .reg_setup
= sh7750_ppc_reg_setup
,
249 .cpu_setup
= sh7750_ppc_cpu_setup
,
250 .cpu_start
= sh7750_ppc_cpu_start
,
251 .cpu_stop
= sh7750_ppc_cpu_stop
,
252 .init
= sh7750_ppc_init
,
253 .exit
= sh7750_ppc_exit
,
254 .create_files
= sh7750_ppc_create_files
,