BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / linux / linux-2.6 / arch / mips / brcm-boards / bcm947xx / perfcntr.c
blobbd324faee281543e608e3b7c94fa07fbc82c943c
1 /*
2 * Broadcom BCM47xx Performance Counters
4 * Copyright (C) 2011, 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/config.h>
23 #ifdef CONFIG_PROC_FS
24 #include <linux/proc_fs.h>
25 #include <typedefs.h>
26 #include <osl.h>
27 #include <asm/mipsregs.h>
28 #include <mipsinc.h>
31 asmlinkage uint
32 read_perf_cntr(uint sel)
34 /* Beware: Don't collapse this into a single call to read_c0_perf,
35 * it is not really a function, it is a macro that generates a
36 * different assembly instruction in each case.
38 switch (sel) {
39 case 0:
40 return read_c0_perf(0);
41 case 1:
42 return read_c0_perf(1);
43 case 2:
44 return read_c0_perf(2);
45 case 3:
46 return read_c0_perf(3);
47 case 4:
48 return read_c0_perf(4);
49 case 5:
50 return read_c0_perf(5);
51 case 6:
52 return read_c0_perf(6);
53 case 7:
54 return read_c0_perf(7);
55 default:
56 return 0;
60 static uint perf_ctrl = 0;
62 static int
63 ctrl_read(char *page, char **start, off_t off,
64 int count, int *eof, void *data)
66 size_t len = 0;
68 /* we have done once so stop */
69 if (off)
70 return 0;
72 if (data == NULL) {
73 /* return the value in hex string */
74 len = sprintf(page, "0x%08x\n", perf_ctrl);
75 } else {
76 len = sprintf(page, "0x%08x 0x%08x 0x%08x 0x%08x\n",
77 read_perf_cntr(0), read_perf_cntr(2),
78 read_perf_cntr(4), read_perf_cntr(6));
80 *start = page;
81 return len;
84 static void
85 set_ctrl(uint value)
87 uint event;
89 event = (value >> 24) & 0x7f;
90 if (event != ((perf_ctrl >> 24) & 0x7f)) {
91 write_c0_perf(0, 0);
92 write_c0_perf(1, 0);
93 if (event != 0x7f)
94 write_c0_perf(0, (event << 5) | 0xf);
96 event = (value >> 16) & 0x7f;
97 if (event != ((perf_ctrl >> 16) & 0x7f)) {
98 write_c0_perf(2, 0);
99 write_c0_perf(3, 0);
100 if (event != 0x7f)
101 write_c0_perf(2, (event << 5) | 0xf);
103 event = (value >> 8) & 0x7f;
104 if (event != ((perf_ctrl >> 8) & 0x7f)) {
105 write_c0_perf(4, 0);
106 write_c0_perf(5, 0);
107 if (event != 0x7f)
108 write_c0_perf(4, (event << 5) | 0xf);
110 event = value & 0x7f;
111 if (event != (perf_ctrl & 0x7f)) {
112 write_c0_perf(6, 0);
113 write_c0_perf(7, 0);
114 if (event != 0x7f)
115 write_c0_perf(6, (event << 5) | 0xf);
117 perf_ctrl = value & 0x7f7f7f7f;
120 static int
121 ctrl_write(struct file *file, const char *buf,
122 unsigned long count, void *data)
124 uint value;
126 value = simple_strtoul(buf, NULL, 0);
128 set_ctrl(value);
130 return count;
134 static int
135 cntrs_read(char *page, char **start, off_t off,
136 int count, int *eof, void *data)
138 size_t len = 0;
140 /* we have done once so stop */
141 if (off)
142 return 0;
144 /* return the values in hex string */
145 len = sprintf(page, "%10u %10u %10u %10u\n",
146 read_perf_cntr(1), read_perf_cntr(3),
147 read_perf_cntr(5), read_perf_cntr(7));
148 *start = page;
149 return len;
152 static void
153 cntrs_clear(void)
155 write_c0_perf(1, 0);
156 write_c0_perf(3, 0);
157 write_c0_perf(5, 0);
158 write_c0_perf(7, 0);
161 static int
162 clear_write(struct file *file, const char *buf,
163 unsigned long count, void *data)
165 cntrs_clear();
167 return count;
170 static struct proc_dir_entry *perf_proc = NULL;
172 static int __init
173 perf_init(void)
175 struct proc_dir_entry *ctrl_proc, *ctrlraw_proc, *cntrs_proc, *clear_proc;
176 uint prid;
179 /* create proc entries for enabling cache hit/miss counting */
180 prid = read_c0_prid();
181 if (((prid & PRID_COMP_MASK) == PRID_COMP_MIPS) &&
182 ((prid & PRID_IMP_MASK) == PRID_IMP_74K)) {
184 /* create proc entry cp0 in root */
185 perf_proc = create_proc_entry("perf", 0444 | S_IFDIR, &proc_root);
186 if (!perf_proc)
187 return -ENOMEM;
189 ctrl_proc = create_proc_entry("ctrl", 0644, perf_proc);
190 if (!ctrl_proc)
191 goto noctrl;
192 ctrl_proc->data = NULL;
193 ctrl_proc->read_proc = ctrl_read;
194 ctrl_proc->write_proc = ctrl_write;
196 ctrlraw_proc = create_proc_entry("ctrlraw", 0444, perf_proc);
197 if (!ctrlraw_proc)
198 goto noctrlraw;
199 ctrlraw_proc->data = (void *)1;
200 ctrlraw_proc->read_proc = ctrl_read;
202 cntrs_proc = create_proc_entry("cntrs", 0444, perf_proc);
203 if (!cntrs_proc)
204 goto nocntrs;
205 cntrs_proc->read_proc = cntrs_read;
207 clear_proc = create_proc_entry("clear", 0444, perf_proc);
208 if (!clear_proc)
209 goto noclear;
210 clear_proc->write_proc = clear_write;
213 /* Initialize off */
214 set_ctrl(0x7f7f7f7f);
215 return 0;
216 noclear:
217 remove_proc_entry("cntrs", perf_proc);
218 nocntrs:
219 remove_proc_entry("ctrlraw", perf_proc);
220 noctrlraw:
221 remove_proc_entry("ctrl", perf_proc);
222 noctrl:
223 remove_proc_entry("perf", &proc_root);
225 return -ENOMEM;
228 static void __exit perf_cleanup(void)
230 remove_proc_entry("clear", perf_proc);
231 remove_proc_entry("cntrs", perf_proc);
232 remove_proc_entry("ctrlraw", perf_proc);
233 remove_proc_entry("ctrl", perf_proc);
234 remove_proc_entry("perf", &proc_root);
235 perf_proc = NULL;
238 /* hook it up with system at boot time */
239 module_init(perf_init);
240 module_exit(perf_cleanup);
242 #endif /* CONFIG_PROC_FS */