• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/mips/brcm-boards/bcm947xx/
1/*
2 * Broadcom BCM47xx Performance Counters
3 *
4 * Copyright (C) 2013, 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.
17 *
18 * $Id: perfcntr.c 241435 2011-02-18 04:04:21Z $
19 */
20
21#include <linux/config.h>
22
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>
29
30
31asmlinkage uint
32read_perf_cntr(uint sel)
33{
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.
37	 */
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;
57	}
58}
59
60static uint perf_ctrl = 0;
61
62static int
63ctrl_read(char *page, char **start, off_t off,
64          int count, int *eof, void *data)
65{
66	size_t len = 0;
67
68	/* we have done once so stop */
69	if (off)
70		return 0;
71
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));
79	}
80	*start = page;
81	return len;
82}
83
84static void
85set_ctrl(uint value)
86{
87	uint event;
88
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);
95	}
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);
102	}
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);
109	}
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);
116	}
117	perf_ctrl = value & 0x7f7f7f7f;
118}
119
120static int
121ctrl_write(struct file *file, const char *buf,
122           unsigned long count, void *data)
123{
124	uint value;
125
126	value = simple_strtoul(buf, NULL, 0);
127
128	set_ctrl(value);
129
130	return count;
131}
132
133
134static int
135cntrs_read(char *page, char **start, off_t off,
136          int count, int *eof, void *data)
137{
138	size_t len = 0;
139
140	/* we have done once so stop */
141	if (off)
142		return 0;
143
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;
150}
151
152static void
153cntrs_clear(void)
154{
155	write_c0_perf(1, 0);
156	write_c0_perf(3, 0);
157	write_c0_perf(5, 0);
158	write_c0_perf(7, 0);
159}
160
161static int
162clear_write(struct file *file, const char *buf,
163           unsigned long count, void *data)
164{
165	cntrs_clear();
166
167	return count;
168}
169
170static struct proc_dir_entry *perf_proc = NULL;
171
172static int __init
173perf_init(void)
174{
175	struct proc_dir_entry *ctrl_proc, *ctrlraw_proc, *cntrs_proc, *clear_proc;
176	uint prid;
177
178
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)) {
183
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;
188
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;
195
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;
201
202		cntrs_proc = create_proc_entry("cntrs", 0444, perf_proc);
203		if (!cntrs_proc)
204			goto nocntrs;
205		cntrs_proc->read_proc = cntrs_read;
206
207		clear_proc = create_proc_entry("clear", 0444, perf_proc);
208		if (!clear_proc)
209			goto noclear;
210		clear_proc->write_proc = clear_write;
211	}
212
213	/* Initialize off */
214	set_ctrl(0x7f7f7f7f);
215	return 0;
216noclear:
217	remove_proc_entry("cntrs", perf_proc);
218nocntrs:
219	remove_proc_entry("ctrlraw", perf_proc);
220noctrlraw:
221	remove_proc_entry("ctrl", perf_proc);
222noctrl:
223	remove_proc_entry("perf", &proc_root);
224
225	return -ENOMEM;
226}
227
228static void __exit perf_cleanup(void)
229{
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;
236}
237
238/* hook it up with system at boot time */
239module_init(perf_init);
240module_exit(perf_cleanup);
241
242#endif	/* CONFIG_PROC_FS */
243