RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / mips / brcm-boards / bcm947xx / perfcntr.c
blobcd7b86478fa0948dc298a40c5cd25ab90e6df87c
1 /*
2 * Broadcom BCM47xx Performance Counters
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
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.
9 *
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>
25 #endif
27 #ifdef CONFIG_PROC_FS
28 #include <linux/proc_fs.h>
29 #include <typedefs.h>
30 #include <osl.h>
31 #include <asm/mipsregs.h>
32 #include <mipsinc.h>
34 asmlinkage uint
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.
41 switch (sel) {
42 #ifdef read_c0_perf
43 case 0:
44 return read_c0_perf(0);
45 case 1:
46 return read_c0_perf(1);
47 case 2:
48 return read_c0_perf(2);
49 case 3:
50 return read_c0_perf(3);
51 case 4:
52 return read_c0_perf(4);
53 case 5:
54 return read_c0_perf(5);
55 case 6:
56 return read_c0_perf(6);
57 case 7:
58 return read_c0_perf(7);
59 #else
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();
69 #endif
70 default:
71 return 0;
75 /* HACK: map the old-style CP0 access macro */
76 #ifndef write_c0_perf
77 #define write_c0_perf(sel,val) __write_32bit_c0_register($25, sel, val)
78 #endif
80 static uint perf_ctrl = 0;
82 static int
83 ctrl_read(char *page, char **start, off_t off,
84 int count, int *eof, void *data)
86 size_t len = 0;
88 /* we have done once so stop */
89 if (off)
90 return 0;
92 if (data == NULL) {
93 /* return the value in hex string */
94 len = sprintf(page, "0x%08x\n", perf_ctrl);
95 } else {
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));
100 *start = page;
101 return len;
104 static void
105 set_ctrl(uint value)
107 uint event;
109 event = (value >> 24) & 0x7f;
110 if (event != ((perf_ctrl >> 24) & 0x7f)) {
111 write_c0_perf(0, 0);
112 write_c0_perf(1, 0);
113 if (event != 0x7f)
114 write_c0_perf(0, (event << 5) | 0xf);
116 event = (value >> 16) & 0x7f;
117 if (event != ((perf_ctrl >> 16) & 0x7f)) {
118 write_c0_perf(2, 0);
119 write_c0_perf(3, 0);
120 if (event != 0x7f)
121 write_c0_perf(2, (event << 5) | 0xf);
123 event = (value >> 8) & 0x7f;
124 if (event != ((perf_ctrl >> 8) & 0x7f)) {
125 write_c0_perf(4, 0);
126 write_c0_perf(5, 0);
127 if (event != 0x7f)
128 write_c0_perf(4, (event << 5) | 0xf);
130 event = value & 0x7f;
131 if (event != (perf_ctrl & 0x7f)) {
132 write_c0_perf(6, 0);
133 write_c0_perf(7, 0);
134 if (event != 0x7f)
135 write_c0_perf(6, (event << 5) | 0xf);
137 perf_ctrl = value & 0x7f7f7f7f;
140 static int
141 ctrl_write(struct file *file, const char *buf,
142 unsigned long count, void *data)
144 uint value;
146 value = simple_strtoul(buf, NULL, 0);
148 set_ctrl(value);
150 return count;
154 static int
155 cntrs_read(char *page, char **start, off_t off,
156 int count, int *eof, void *data)
158 size_t len = 0;
160 /* we have done once so stop */
161 if (off)
162 return 0;
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));
168 *start = page;
169 return len;
172 static void
173 cntrs_clear(void)
175 write_c0_perf(1, 0);
176 write_c0_perf(3, 0);
177 write_c0_perf(5, 0);
178 write_c0_perf(7, 0);
181 static int
182 clear_write(struct file *file, const char *buf,
183 unsigned long count, void *data)
185 cntrs_clear();
187 return count;
190 static struct proc_dir_entry *perf_proc = NULL;
192 static int __init
193 perf_init(void)
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 ;
198 uint prid;
200 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
201 proc_root_ptr = NULL ;
202 #else
203 proc_root_ptr = &proc_root ;
204 #endif
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,
213 proc_root_ptr);
214 if (!perf_proc)
215 return -ENOMEM;
217 ctrl_proc = create_proc_entry("ctrl", 0644, perf_proc);
218 if (!ctrl_proc)
219 goto noctrl;
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);
225 if (!ctrlraw_proc)
226 goto noctrlraw;
227 ctrlraw_proc->data = (void *)1;
228 ctrlraw_proc->read_proc = ctrl_read;
230 cntrs_proc = create_proc_entry("cntrs", 0444, perf_proc);
231 if (!cntrs_proc)
232 goto nocntrs;
233 cntrs_proc->read_proc = cntrs_read;
235 clear_proc = create_proc_entry("clear", 0444, perf_proc);
236 if (!clear_proc)
237 goto noclear;
238 clear_proc->write_proc = clear_write;
241 /* Initialize off */
242 set_ctrl(0x7f7f7f7f);
243 return 0;
244 noclear:
245 remove_proc_entry("cntrs", perf_proc);
246 nocntrs:
247 remove_proc_entry("ctrlraw", perf_proc);
248 noctrlraw:
249 remove_proc_entry("ctrl", perf_proc);
250 noctrl:
251 remove_proc_entry("perf", proc_root_ptr);
253 return -ENOMEM;
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 ;
261 #else
262 proc_root_ptr = &proc_root ;
263 #endif
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);
270 perf_proc = NULL;
273 /* hook it up with system at boot time */
274 module_init(perf_init);
275 module_exit(perf_cleanup);
277 #endif /* CONFIG_PROC_FS */