2 * Broadcom BCM47xx Performance Counters
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: perfcntr.c 241435 2011-02-18 04:04:21Z $
21 #include <linux/version.h>
23 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
24 #include <linux/config.h>
28 #include <linux/proc_fs.h>
31 #include <asm/mipsregs.h>
35 read_perf_cntr(uint sel
)
37 /* Beware: Don't collapse this into a single call to read_c0_perf,
38 * it is not really a function, it is a macro that generates a
39 * different assembly instruction in each case.
44 return read_c0_perf(0);
46 return read_c0_perf(1);
48 return read_c0_perf(2);
50 return read_c0_perf(3);
52 return read_c0_perf(4);
54 return read_c0_perf(5);
56 return read_c0_perf(6);
58 return read_c0_perf(7);
60 /* New style register access macros - LR */
61 case 0: return read_c0_perfctrl0(); /* Control */
62 case 2: return read_c0_perfctrl1();
63 case 4: return read_c0_perfctrl2();
64 case 6: return read_c0_perfctrl3();
65 case 1: return read_c0_perfcntr0(); /* Counter */
66 case 3: return read_c0_perfcntr1();
67 case 5: return read_c0_perfcntr2();
68 case 7: return read_c0_perfcntr3();
75 /* HACK: map the old-style CP0 access macro */
77 #define write_c0_perf(sel,val) __write_32bit_c0_register($25, sel, val)
80 static uint perf_ctrl
= 0;
83 ctrl_read(char *page
, char **start
, off_t off
,
84 int count
, int *eof
, void *data
)
88 /* we have done once so stop */
93 /* return the value in hex string */
94 len
= sprintf(page
, "0x%08x\n", perf_ctrl
);
96 len
= sprintf(page
, "0x%08x 0x%08x 0x%08x 0x%08x\n",
97 read_perf_cntr(0), read_perf_cntr(2),
98 read_perf_cntr(4), read_perf_cntr(6));
109 event
= (value
>> 24) & 0x7f;
110 if (event
!= ((perf_ctrl
>> 24) & 0x7f)) {
114 write_c0_perf(0, (event
<< 5) | 0xf);
116 event
= (value
>> 16) & 0x7f;
117 if (event
!= ((perf_ctrl
>> 16) & 0x7f)) {
121 write_c0_perf(2, (event
<< 5) | 0xf);
123 event
= (value
>> 8) & 0x7f;
124 if (event
!= ((perf_ctrl
>> 8) & 0x7f)) {
128 write_c0_perf(4, (event
<< 5) | 0xf);
130 event
= value
& 0x7f;
131 if (event
!= (perf_ctrl
& 0x7f)) {
135 write_c0_perf(6, (event
<< 5) | 0xf);
137 perf_ctrl
= value
& 0x7f7f7f7f;
141 ctrl_write(struct file
*file
, const char *buf
,
142 unsigned long count
, void *data
)
146 value
= simple_strtoul(buf
, NULL
, 0);
155 cntrs_read(char *page
, char **start
, off_t off
,
156 int count
, int *eof
, void *data
)
160 /* we have done once so stop */
164 /* return the values in hex string */
165 len
= sprintf(page
, "%10u %10u %10u %10u\n",
166 read_perf_cntr(1), read_perf_cntr(3),
167 read_perf_cntr(5), read_perf_cntr(7));
182 clear_write(struct file
*file
, const char *buf
,
183 unsigned long count
, void *data
)
190 static struct proc_dir_entry
*perf_proc
= NULL
;
195 struct proc_dir_entry
* ctrl_proc
, * ctrlraw_proc
;
196 struct proc_dir_entry
* cntrs_proc
, *clear_proc
;
197 struct proc_dir_entry
* proc_root_ptr
;
200 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
201 proc_root_ptr
= NULL
;
203 proc_root_ptr
= &proc_root
;
206 /* create proc entries for enabling cache hit/miss counting */
207 prid
= read_c0_prid();
208 if (((prid
& PRID_COMP_MASK
) == PRID_COMP_MIPS
) &&
209 ((prid
& PRID_IMP_MASK
) == PRID_IMP_74K
)) {
211 /* create proc entry cp0 in root */
212 perf_proc
= create_proc_entry("perf", 0444 | S_IFDIR
,
217 ctrl_proc
= create_proc_entry("ctrl", 0644, perf_proc
);
220 ctrl_proc
->data
= NULL
;
221 ctrl_proc
->read_proc
= ctrl_read
;
222 ctrl_proc
->write_proc
= ctrl_write
;
224 ctrlraw_proc
= create_proc_entry("ctrlraw", 0444, perf_proc
);
227 ctrlraw_proc
->data
= (void *)1;
228 ctrlraw_proc
->read_proc
= ctrl_read
;
230 cntrs_proc
= create_proc_entry("cntrs", 0444, perf_proc
);
233 cntrs_proc
->read_proc
= cntrs_read
;
235 clear_proc
= create_proc_entry("clear", 0444, perf_proc
);
238 clear_proc
->write_proc
= clear_write
;
242 set_ctrl(0x7f7f7f7f);
245 remove_proc_entry("cntrs", perf_proc
);
247 remove_proc_entry("ctrlraw", perf_proc
);
249 remove_proc_entry("ctrl", perf_proc
);
251 remove_proc_entry("perf", proc_root_ptr
);
256 static void __exit
perf_cleanup(void)
258 struct proc_dir_entry
* proc_root_ptr
;
259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
260 proc_root_ptr
= NULL
;
262 proc_root_ptr
= &proc_root
;
265 remove_proc_entry("clear", perf_proc
);
266 remove_proc_entry("cntrs", perf_proc
);
267 remove_proc_entry("ctrlraw", perf_proc
);
268 remove_proc_entry("ctrl", perf_proc
);
269 remove_proc_entry("perf", proc_root_ptr
);
273 /* hook it up with system at boot time */
274 module_init(perf_init
);
275 module_exit(perf_cleanup
);
277 #endif /* CONFIG_PROC_FS */