aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/oprofile/op_model_sh7750.c172
1 files changed, 78 insertions, 94 deletions
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c
index 008b3b03750a..c892c7c30c2f 100644
--- a/arch/sh/oprofile/op_model_sh7750.c
+++ b/arch/sh/oprofile/op_model_sh7750.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * OProfile support for SH7750/SH7750S Performance Counters 4 * OProfile support for SH7750/SH7750S Performance Counters
5 * 5 *
6 * Copyright (C) 2003, 2004 Paul Mundt 6 * Copyright (C) 2003 - 2008 Paul Mundt
7 * 7 *
8 * This file is subject to the terms and conditions of the GNU General Public 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 9 * License. See the file "COPYING" in the main directory of this archive
@@ -15,19 +15,16 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/io.h>
18#include <linux/fs.h> 19#include <linux/fs.h>
19#include <asm/uaccess.h> 20#include "op_impl.h"
20#include <asm/io.h>
21 21
22#define PM_CR_BASE 0xff000084 /* 16-bit */ 22#define PM_CR_BASE 0xff000084 /* 16-bit */
23#define PM_CTR_BASE 0xff100004 /* 32-bit */ 23#define PM_CTR_BASE 0xff100004 /* 32-bit */
24 24
25#define PMCR1 (PM_CR_BASE + 0x00) 25#define PMCR(n) (PM_CR_BASE + ((n) * 0x04))
26#define PMCR2 (PM_CR_BASE + 0x04) 26#define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08))
27#define PMCTR1H (PM_CTR_BASE + 0x00) 27#define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08))
28#define PMCTR1L (PM_CTR_BASE + 0x04)
29#define PMCTR2H (PM_CTR_BASE + 0x08)
30#define PMCTR2L (PM_CTR_BASE + 0x0c)
31 28
32#define PMCR_PMM_MASK 0x0000003f 29#define PMCR_PMM_MASK 0x0000003f
33 30
@@ -36,25 +33,15 @@
36#define PMCR_PMST 0x00004000 33#define PMCR_PMST 0x00004000
37#define PMCR_PMEN 0x00008000 34#define PMCR_PMEN 0x00008000
38 35
39#define PMCR_ENABLE (PMCR_PMST | PMCR_PMEN) 36struct op_sh_model op_model_sh7750_ops;
40 37
41/*
42 * SH7750/SH7750S have 2 perf counters
43 */
44#define NR_CNTRS 2 38#define NR_CNTRS 2
45 39
46struct op_counter_config { 40static struct sh7750_ppc_register_config {
47 unsigned long enabled; 41 unsigned int ctrl;
48 unsigned long event; 42 unsigned long cnt_hi;
49 unsigned long count; 43 unsigned long cnt_lo;
50 44} regcache[NR_CNTRS];
51 /* Dummy values for userspace tool compliance */
52 unsigned long kernel;
53 unsigned long user;
54 unsigned long unit_mask;
55};
56
57static struct op_counter_config ctr[NR_CNTRS];
58 45
59/* 46/*
60 * There are a number of events supported by each counter (33 in total). 47 * There are a number of events supported by each counter (33 in total).
@@ -116,12 +103,8 @@ static int sh7750_timer_notify(struct pt_regs *regs)
116 103
117static u64 sh7750_read_counter(int counter) 104static u64 sh7750_read_counter(int counter)
118{ 105{
119 u32 hi, lo; 106 return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) |
120 107 __raw_readl(PMCTRL(counter));
121 hi = (counter == 0) ? ctrl_inl(PMCTR1H) : ctrl_inl(PMCTR2H);
122 lo = (counter == 0) ? ctrl_inl(PMCTR1L) : ctrl_inl(PMCTR2L);
123
124 return (u64)((u64)(hi & 0xffff) << 32) | lo;
125} 108}
126 109
127/* 110/*
@@ -170,11 +153,7 @@ static ssize_t sh7750_write_count(struct file *file, const char __user *buf,
170 */ 153 */
171 WARN_ON(val != 0); 154 WARN_ON(val != 0);
172 155
173 if (counter == 0) { 156 __raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter));
174 ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1);
175 } else {
176 ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2);
177 }
178 157
179 return count; 158 return count;
180} 159}
@@ -184,88 +163,93 @@ static const struct file_operations count_fops = {
184 .write = sh7750_write_count, 163 .write = sh7750_write_count,
185}; 164};
186 165
187static int sh7750_perf_counter_create_files(struct super_block *sb, struct dentry *root) 166static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir)
188{ 167{
189 int i; 168 return oprofilefs_create_file(sb, dir, "count", &count_fops);
169}
190 170
191 for (i = 0; i < NR_CNTRS; i++) { 171static void sh7750_ppc_reg_setup(struct op_counter_config *ctr)
192 struct dentry *dir; 172{
193 char buf[4]; 173 unsigned int counters = op_model_sh7750_ops.num_counters;
174 int i;
194 175
195 snprintf(buf, sizeof(buf), "%d", i); 176 for (i = 0; i < counters; i++) {
196 dir = oprofilefs_mkdir(sb, root, buf); 177 regcache[i].ctrl = 0;
178 regcache[i].cnt_hi = 0;
179 regcache[i].cnt_lo = 0;
197 180
198 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); 181 if (!ctr[i].enabled)
199 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); 182 continue;
200 oprofilefs_create_file(sb, dir, "count", &count_fops);
201 183
202 /* Dummy entries */ 184 regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST;
203 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); 185 regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff);
204 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); 186 regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff);
205 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
206 } 187 }
207
208 return 0;
209} 188}
210 189
211static int sh7750_perf_counter_start(void) 190static void sh7750_ppc_cpu_setup(void *args)
212{ 191{
213 u16 pmcr; 192 unsigned int counters = op_model_sh7750_ops.num_counters;
214 193 int i;
215 /* Enable counter 1 */
216 if (ctr[0].enabled) {
217 pmcr = ctrl_inw(PMCR1);
218 WARN_ON(pmcr & PMCR_PMEN);
219
220 pmcr &= ~PMCR_PMM_MASK;
221 pmcr |= ctr[0].event;
222 ctrl_outw(pmcr | PMCR_ENABLE, PMCR1);
223 }
224
225 /* Enable counter 2 */
226 if (ctr[1].enabled) {
227 pmcr = ctrl_inw(PMCR2);
228 WARN_ON(pmcr & PMCR_PMEN);
229 194
230 pmcr &= ~PMCR_PMM_MASK; 195 for (i = 0; i < counters; i++) {
231 pmcr |= ctr[1].event; 196 __raw_writew(0, PMCR(i));
232 ctrl_outw(pmcr | PMCR_ENABLE, PMCR2); 197 __raw_writel(regcache[i].cnt_hi, PMCTRH(i));
198 __raw_writel(regcache[i].cnt_lo, PMCTRL(i));
233 } 199 }
234
235 return register_timer_hook(sh7750_timer_notify);
236} 200}
237 201
238static void sh7750_perf_counter_stop(void) 202static void sh7750_ppc_cpu_start(void *args)
239{ 203{
240 ctrl_outw(ctrl_inw(PMCR1) & ~PMCR_PMEN, PMCR1); 204 unsigned int counters = op_model_sh7750_ops.num_counters;
241 ctrl_outw(ctrl_inw(PMCR2) & ~PMCR_PMEN, PMCR2); 205 int i;
242 206
243 unregister_timer_hook(sh7750_timer_notify); 207 for (i = 0; i < counters; i++)
208 __raw_writew(regcache[i].ctrl, PMCR(i));
244} 209}
245 210
246static struct oprofile_operations sh7750_perf_counter_ops = { 211static void sh7750_ppc_cpu_stop(void *args)
247 .create_files = sh7750_perf_counter_create_files,
248 .start = sh7750_perf_counter_start,
249 .stop = sh7750_perf_counter_stop,
250};
251
252int __init oprofile_arch_init(struct oprofile_operations *ops)
253{ 212{
254 if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER)) 213 unsigned int counters = op_model_sh7750_ops.num_counters;
255 return -ENODEV; 214 int i;
256 215
257 ops = &sh7750_perf_counter_ops; 216 /* Disable the counters */
258 ops->cpu_type = "sh/sh7750"; 217 for (i = 0; i < counters; i++)
218 __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
219}
259 220
260 printk(KERN_INFO "oprofile: using SH-4 performance monitoring.\n"); 221static inline void sh7750_ppc_reset(void)
222{
223 unsigned int counters = op_model_sh7750_ops.num_counters;
224 int i;
261 225
262 /* Clear the counters */ 226 /* Clear the counters */
263 ctrl_outw(ctrl_inw(PMCR1) | PMCR_PMCLR, PMCR1); 227 for (i = 0; i < counters; i++)
264 ctrl_outw(ctrl_inw(PMCR2) | PMCR_PMCLR, PMCR2); 228 __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i));
229}
265 230
266 return 0; 231static int sh7750_ppc_init(void)
232{
233 sh7750_ppc_reset();
234
235 return register_timer_hook(sh7750_timer_notify);
267} 236}
268 237
269void oprofile_arch_exit(void) 238static void sh7750_ppc_exit(void)
270{ 239{
240 unregister_timer_hook(sh7750_timer_notify);
241
242 sh7750_ppc_reset();
271} 243}
244
245struct 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,
255};