summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorPawel Moll2011-09-30 05:47:12 -0500
committerPawel Moll2011-09-30 05:47:12 -0500
commit1d5b785dbabac2dfc45103e7c2d787952c93488c (patch)
treee03426ecb18855bb05af48a811e619cc26eb2f3b /driver
parent7c366b2d106bd14742cc3446f874e520d473703d (diff)
downloadarm-ds5-gator-1d5b785dbabac2dfc45103e7c2d787952c93488c.tar.gz
arm-ds5-gator-1d5b785dbabac2dfc45103e7c2d787952c93488c.tar.xz
arm-ds5-gator-1d5b785dbabac2dfc45103e7c2d787952c93488c.zip
gator: Move driver sources to a separate directory
... in prepration for daemon sources. Signed-off-by: Pawel Moll <pawel.moll@arm.com>
Diffstat (limited to 'driver')
-rw-r--r--driver/LICENSE339
-rw-r--r--driver/Makefile45
-rw-r--r--driver/README_Streamline.txt81
-rw-r--r--driver/gator.h79
-rw-r--r--driver/gator_annotate.c166
-rw-r--r--driver/gator_backtrace.c68
-rw-r--r--driver/gator_cookies.c384
-rw-r--r--driver/gator_events.c40
-rw-r--r--driver/gator_events.h19
-rw-r--r--driver/gator_events.sh19
-rw-r--r--driver/gator_events_armv6.c224
-rw-r--r--driver/gator_events_armv7.c322
-rw-r--r--driver/gator_events_block.c171
-rw-r--r--driver/gator_events_irq.c171
-rw-r--r--driver/gator_events_meminfo.c195
-rw-r--r--driver/gator_events_mmaped.c196
-rw-r--r--driver/gator_events_net.c177
-rw-r--r--driver/gator_events_pl310.c176
-rw-r--r--driver/gator_events_sched.c114
-rw-r--r--driver/gator_events_scorpion.c661
-rw-r--r--driver/gator_fs.c284
-rw-r--r--driver/gator_main.c1057
-rw-r--r--driver/gator_trace.h26
-rw-r--r--driver/gator_trace_sched.c263
24 files changed, 5277 insertions, 0 deletions
diff --git a/driver/LICENSE b/driver/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/driver/LICENSE
@@ -0,0 +1,339 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Lesser General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public License instead of this License.
diff --git a/driver/Makefile b/driver/Makefile
new file mode 100644
index 0000000..b3680e1
--- /dev/null
+++ b/driver/Makefile
@@ -0,0 +1,45 @@
1ifneq ($(KERNELRELEASE),)
2
3obj-m := gator.o
4
5gator-y := gator_main.o \
6 gator_events_irq.o \
7 gator_events_sched.o \
8 gator_events_net.o \
9 gator_events_block.o \
10 gator_events_meminfo.o
11
12gator-y += gator_events_mmaped.o
13
14ifneq ($(GATOR_WITH_MALI_SUPPORT),)
15gator-y += gator_events_mali.o
16endif
17
18gator-$(CONFIG_ARM) += gator_events_armv6.o \
19 gator_events_armv7.o \
20 gator_events_pl310.o
21
22$(obj)/gator_main.o: gator_events.h
23
24clean-files := gator_events.h
25
26 chk_events.h = :
27 quiet_chk_events.h = echo ' CHK $@'
28silent_chk_events.h = :
29gator_events.h: FORCE
30 @$($(quiet)chk_events.h)
31 $(Q)cd $(obj) ; $(CONFIG_SHELL) $(obj)/gator_events.sh $@
32
33else
34
35all:
36 @echo
37 @echo "usage:"
38 @echo " make -C <kernel_build_dir> M=\`pwd\` ARCH=arm CROSS_COMPILE=<...> modules"
39 @echo
40 $(error)
41
42clean:
43 rm -f *.o modules.order Module.symvers gator.ko gator.mod.c
44
45endif
diff --git a/driver/README_Streamline.txt b/driver/README_Streamline.txt
new file mode 100644
index 0000000..4688474
--- /dev/null
+++ b/driver/README_Streamline.txt
@@ -0,0 +1,81 @@
1
2*** Purpose ***
3
4Instructions on setting up ARM Streamline on the target.
5The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate.
6The driver should be built as a module and the daemon must run with root permissions on the target.
7
8*** Preparing and building the kernel ***
9
10cd into the root source dir of the linux kernel
11make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- <platform_defconfig> (choose the appropriate configuration for your board)
12make ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig
13
14Required Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different)
15- General Setup
16 - [*] Profiling Support
17- Kernel hacking
18 - [*] Tracers
19 - [*] Trace process context switches and events
20- Kernel Features
21 - [*] High Resolution Timer Support
22
23The "context switches and events" option will not be available if other trace configurations are enabled. Other trace configurations being enabled is sufficient to turn on context switches and events.
24
25Optional Kernel Changes (depending on the kernel version, the location of these configuration settings within menuconfig may be different)
26Note: Configurations may not be supported on all targets
27- System Type
28 - [*] <SoC name> debugging peripherals (enable core performance counters on supported SoCs) /* kernels before 2.6.35 */
29
30make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage
31
32*** Building the gator module ***
33
34To create the gator.ko module,
35 cd /ds-5-install-directory/arm/src
36 tar xzf gator-driver.tar.gz
37 cd gator-driver
38 make -C <kernel_build_dir> M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules
39for example
40 make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- modules
41If successful, a gator.ko module should be generated
42
43*** Compiling an application or shared library ***
44
45Recommended compiler settings:
46 "-g": Debug symbols needed for best analysis results.
47 "-fno-inline": Speed improvement when processing the image files and most accurate analysis results.
48 "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow the call stack to be recorded with each sample taken when in ARM state (i.e. not -mthumb).
49
50*** Running gator ***
51
52Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem.
53gatord is located in <installdir>/arm/armv5t/.
54Ensure gatord has execute permissions
55 chmod +x gatord
56gator.ko must be located in the same directory as gatord on the target.
57With root privileges, run the daemon
58 sudo ./gatord &
59
60*** Profiling the kernel (optional) ***
61
62make ARCH=arm CROSS_COMPILE=$(CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig
63- Kernel Hacking
64 - [*] Compile the kernel with debug info
65
66make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage
67Use vmlinux as the image for debug symbols in Streamline.
68Drivers may be profiled using this method by statically linking the driver into the kernel image.
69Note that the gator driver does not perform kernel call stack recording.
70
71*** Automatically start gator on boot (optional) ***
72
73cd /etc/init.d
74vi rungator.sh
75 #!/bin/bash
76 /path/to/gatord &
77update-rc.d rungator.sh defaults
78
79*** GPL License ***
80
81For license information, please see the file LICENSE.
diff --git a/driver/gator.h b/driver/gator.h
new file mode 100644
index 0000000..9d802a3
--- /dev/null
+++ b/driver/gator.h
@@ -0,0 +1,79 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef GATOR_H_
10#define GATOR_H_
11
12#include <linux/version.h>
13#include <linux/fs.h>
14#include <linux/mm.h>
15#include <linux/list.h>
16
17/******************************************************************************
18 * Filesystem
19 ******************************************************************************/
20int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
21 char const *name, const struct file_operations *fops, int perm);
22
23struct dentry *gatorfs_mkdir(struct super_block *sb,
24 struct dentry *root, char const *name);
25
26int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
27 char const *name, unsigned long *val);
28
29int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
30 char const *name, unsigned long *val);
31
32void gator_op_create_files(struct super_block *sb, struct dentry *root);
33
34/******************************************************************************
35 * Tracepoints
36 ******************************************************************************/
37#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
38# error Kernels prior to 2.6.32 not supported
39#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
40# define GATOR_DEFINE_PROBE(probe_name, proto) \
41 static void probe_##probe_name(PARAMS(proto))
42# define GATOR_REGISTER_TRACE(probe_name) \
43 register_trace_##probe_name(probe_##probe_name)
44# define GATOR_UNREGISTER_TRACE(probe_name) \
45 unregister_trace_##probe_name(probe_##probe_name)
46#else
47# define GATOR_DEFINE_PROBE(probe_name, proto) \
48 static void probe_##probe_name(void *data, PARAMS(proto))
49# define GATOR_REGISTER_TRACE(probe_name) \
50 register_trace_##probe_name(probe_##probe_name, NULL)
51# define GATOR_UNREGISTER_TRACE(probe_name) \
52 unregister_trace_##probe_name(probe_##probe_name, NULL)
53#endif
54
55/******************************************************************************
56 * Events
57 ******************************************************************************/
58struct gator_interface {
59 int (*create_files)(struct super_block *sb, struct dentry *root);
60 int (*start)(void);
61 void (*stop)(void);
62 void (*online)(void);
63 void (*offline)(void);
64 int (*read)(int **buffer);
65 struct list_head list;
66};
67
68#define gator_events_init(initfn) \
69 static inline int __gator_events_init_test(void) \
70 { return initfn(); }
71
72int gator_events_install(struct gator_interface *interface);
73int gator_events_get_key(void);
74extern u32 gator_cpuid(void);
75
76extern unsigned long gator_net_traffic;
77
78
79#endif // GATOR_H_
diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c
new file mode 100644
index 0000000..d8d86af
--- /dev/null
+++ b/driver/gator_annotate.c
@@ -0,0 +1,166 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/slab.h>
11#include <linux/fs.h>
12#include <linux/mm.h>
13#include <linux/sched.h>
14#include <asm/uaccess.h>
15#include <asm/current.h>
16#include <linux/spinlock.h>
17
18#define ANNOTATE_SIZE (16*1024)
19static DEFINE_SPINLOCK(annotate_lock);
20static char *annotateBuf;
21static char *annotateBuf0;
22static char *annotateBuf1;
23static int annotatePos;
24static int annotateSel;
25
26static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
27{
28 char tempBuffer[512];
29 int retval, remaining, size;
30
31 if (*offset)
32 return -EINVAL;
33
34 // determine size to capture
35 remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release
36 size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
37 size = size < remaining ? size : remaining;
38 if (size <= 0) {
39 wake_up(&gator_buffer_wait);
40 return 0;
41 }
42
43 // copy from user space
44 retval = copy_from_user(tempBuffer, buf, size);
45 if (retval == 0) {
46 // synchronize shared variables annotateBuf and annotatePos
47 spin_lock(&annotate_lock);
48 if (annotateBuf) {
49 uint32_t tid = current->pid;
50 uint32_t tick = gator_master_tick;
51 uint64_t time = gator_get_time();
52 uint32_t cpuid = smp_processor_id();
53 int pos = annotatePos;
54 pos += gator_write_packed_int(&annotateBuf[pos], tid);
55 pos += gator_write_packed_int(&annotateBuf[pos], tick);
56 pos += gator_write_packed_int(&annotateBuf[pos], time);
57 pos += gator_write_packed_int(&annotateBuf[pos], time >> 32);
58 pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
59 pos += gator_write_packed_int(&annotateBuf[pos], size);
60 memcpy(&annotateBuf[pos], tempBuffer, size);
61 annotatePos = pos + size;
62 }
63 spin_unlock(&annotate_lock);
64
65 // return the number of bytes written
66 retval = size;
67 } else {
68 retval = -EINVAL;
69 }
70
71 return retval;
72}
73
74static int annotate_release(struct inode *inode, struct file *file)
75{
76 int remaining = ANNOTATE_SIZE - annotatePos;
77 if (remaining < 16) {
78 return -EFAULT;
79 }
80
81 spin_lock(&annotate_lock);
82 if (annotateBuf) {
83 uint32_t tid = current->pid;
84 uint32_t tick = gator_master_tick;
85 int pos = annotatePos;
86 pos += gator_write_packed_int(&annotateBuf[pos], tid);
87 pos += gator_write_packed_int(&annotateBuf[pos], tick);
88 pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
89 pos += gator_write_packed_int(&annotateBuf[pos], 0); // time
90 pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
91 pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
92 annotatePos = pos;
93 }
94 spin_unlock(&annotate_lock);
95
96 return 0;
97}
98
99static const struct file_operations annotate_fops = {
100 .write = annotate_write,
101 .release = annotate_release
102};
103
104static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
105{
106 annotateBuf = NULL;
107 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
108}
109
110static int gator_annotate_init(void)
111{
112 annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
113 annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
114 if (!annotateBuf0 || !annotateBuf1)
115 return -1;
116 return 0;
117}
118
119static int gator_annotate_start(void)
120{
121 annotatePos = annotateSel = 0;
122 annotateBuf = annotateBuf0;
123 return 0;
124}
125
126static void gator_annotate_stop(void)
127{
128 spin_lock(&annotate_lock);
129 annotateBuf = NULL;
130 spin_unlock(&annotate_lock);
131}
132
133static void gator_annotate_exit(void)
134{
135 spin_lock(&annotate_lock);
136 kfree(annotateBuf0);
137 kfree(annotateBuf1);
138 annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
139 spin_unlock(&annotate_lock);
140}
141
142static int gator_annotate_ready(void)
143{
144 return annotatePos && annotateBuf;
145}
146
147static int gator_annotate_read(char **buffer)
148{
149 int len;
150
151 if (!gator_annotate_ready())
152 return 0;
153
154 annotateSel = !annotateSel;
155
156 if (buffer)
157 *buffer = annotateBuf;
158
159 spin_lock(&annotate_lock);
160 len = annotatePos;
161 annotatePos = 0;
162 annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
163 spin_unlock(&annotate_lock);
164
165 return len;
166}
diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c
new file mode 100644
index 0000000..628a18f
--- /dev/null
+++ b/driver/gator_backtrace.c
@@ -0,0 +1,68 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10/*
11 * EABI backtrace stores {fp,lr} on the stack.
12 */
13struct frame_tail_eabi {
14 unsigned long fp; // points to prev_lr
15 unsigned long lr;
16};
17
18static void arm_backtrace_eabi(int cpu, struct pt_regs * const regs, unsigned int depth)
19{
20#if defined(__arm__)
21 struct frame_tail_eabi *tail;
22 struct frame_tail_eabi *next;
23 struct frame_tail_eabi *ptrtail;
24 struct frame_tail_eabi buftail;
25 unsigned long fp = regs->ARM_fp;
26 unsigned long lr = regs->ARM_lr;
27 int is_user_mode = user_mode(regs);
28
29 if (!is_user_mode) {
30 return;
31 }
32
33 /* entry preamble may not have executed */
34 gator_add_trace(cpu, lr);
35
36 /* check tail is valid */
37 if (fp == 0) {
38 return;
39 }
40
41 tail = (struct frame_tail_eabi *)(fp - 4);
42
43 while (depth-- && tail && !((unsigned long) tail & 3)) {
44 /* Also check accessibility of one struct frame_tail beyond */
45 if (!access_ok(VERIFY_READ, tail, sizeof(struct frame_tail_eabi)))
46 return;
47 if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi)))
48 return;
49 ptrtail = &buftail;
50
51 lr = ptrtail[0].lr;
52 gator_add_trace(cpu, lr);
53
54 /* frame pointers should progress back up the stack, towards higher addresses */
55 next = (struct frame_tail_eabi *)(lr - 4);
56 if (tail >= next || lr == 0) {
57 fp = ptrtail[0].fp;
58 next = (struct frame_tail_eabi *)(fp - 4);
59 /* check tail is valid */
60 if (tail >= next || fp == 0) {
61 return;
62 }
63 }
64
65 tail = next;
66 }
67#endif
68}
diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c
new file mode 100644
index 0000000..64be841
--- /dev/null
+++ b/driver/gator_cookies.c
@@ -0,0 +1,384 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */
11#define TRANSLATE_SIZE 256
12#define MAX_COLLISIONS 2
13
14static uint32_t *gator_crc32_table;
15static uint32_t translate_buffer_mask;
16
17static DEFINE_PER_CPU(char *, translate_text);
18static DEFINE_PER_CPU(uint32_t, cookie_next_key);
19static DEFINE_PER_CPU(uint64_t *, cookie_keys);
20static DEFINE_PER_CPU(uint32_t *, cookie_values);
21static DEFINE_PER_CPU(int, translate_buffer_read);
22static DEFINE_PER_CPU(int, translate_buffer_write);
23static DEFINE_PER_CPU(unsigned int *, translate_buffer);
24
25static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod);
26static void wq_cookie_handler(struct work_struct *unused);
27DECLARE_WORK(cookie_work, wq_cookie_handler);
28
29static uint32_t cookiemap_code(uint64_t value64) {
30 uint32_t value = (uint32_t)((value64 >> 32) + value64);
31 uint32_t cookiecode = (value >> 24) & 0xff;
32 cookiecode = cookiecode * 31 + ((value >> 16) & 0xff);
33 cookiecode = cookiecode * 31 + ((value >> 8) & 0xff);
34 cookiecode = cookiecode * 31 + ((value >> 0) & 0xff);
35 cookiecode &= (COOKIEMAP_ENTRIES-1);
36 return cookiecode * MAX_COLLISIONS;
37}
38
39static uint32_t gator_chksum_crc32(char *data)
40{
41 register unsigned long crc;
42 unsigned char *block = data;
43 int i, length = strlen(data);
44
45 crc = 0xFFFFFFFF;
46 for (i = 0; i < length; i++) {
47 crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF];
48 }
49
50 return (crc ^ 0xFFFFFFFF);
51}
52
53/*
54 * Exists
55 * Pre: [0][1][v][3]..[n-1]
56 * Post: [v][0][1][3]..[n-1]
57 */
58static uint32_t cookiemap_exists(uint64_t key) {
59 unsigned long x, flags, retval = 0;
60 int cpu = smp_processor_id();
61 uint32_t cookiecode = cookiemap_code(key);
62 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
63 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
64
65 // Can be called from interrupt handler or from work queue
66 local_irq_save(flags);
67 for (x = 0; x < MAX_COLLISIONS; x++) {
68 if (keys[x] == key) {
69 uint32_t value = values[x];
70 for (; x > 0; x--) {
71 keys[x] = keys[x-1];
72 values[x] = values[x-1];
73 }
74 keys[0] = key;
75 values[0] = value;
76 retval = value;
77 break;
78 }
79 }
80 local_irq_restore(flags);
81
82 return retval;
83}
84
85/*
86 * Add
87 * Pre: [0][1][2][3]..[n-1]
88 * Post: [v][0][1][2]..[n-2]
89 */
90static void cookiemap_add(uint64_t key, uint32_t value) {
91 int cpu = smp_processor_id();
92 int cookiecode = cookiemap_code(key);
93 uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]);
94 uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]);
95 int x;
96
97 for (x = MAX_COLLISIONS-1; x > 0; x--) {
98 keys[x] = keys[x-1];
99 values[x] = keys[x-1];
100 }
101 keys[0] = key;
102 values[0] = value;
103}
104
105static void translate_buffer_write_int(int cpu, unsigned int x)
106{
107 per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
108 per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
109}
110
111static unsigned int translate_buffer_read_int(int cpu)
112{
113 unsigned int value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
114 per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
115 return value;
116}
117
118static void wq_cookie_handler(struct work_struct *unused)
119{
120 struct task_struct *task;
121 struct vm_area_struct *vma;
122 int cpu = smp_processor_id();
123 unsigned int cookie, commit;
124
125 commit = per_cpu(translate_buffer_write, cpu);
126 while (per_cpu(translate_buffer_read, cpu) != commit) {
127 task = (struct task_struct *)translate_buffer_read_int(cpu);
128 vma = (struct vm_area_struct *)translate_buffer_read_int(cpu);
129 cookie = get_cookie(cpu, task, vma, NULL);
130 }
131}
132
133// Retrieve full name from proc/pid/cmdline for java processes on Android
134static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma)
135{
136 void *maddr;
137 unsigned int len;
138 unsigned long addr;
139 struct mm_struct *mm;
140 struct page *page = NULL;
141 struct vm_area_struct *page_vma;
142 int bytes, offset, retval = 0, ptr;
143 char * buf = per_cpu(translate_text, cpu);
144
145 // Push work into a work queue if in atomic context as the kernel functions below might sleep
146 if (in_irq()) {
147 // Check if already in buffer
148 ptr = per_cpu(translate_buffer_read, cpu);
149 while (ptr != per_cpu(translate_buffer_write, cpu)) {
150 if (per_cpu(translate_buffer, cpu)[ptr] == (int)task)
151 goto out;
152 ptr = (ptr + 2) & translate_buffer_mask;
153 }
154
155 translate_buffer_write_int(cpu, (unsigned int)task);
156 translate_buffer_write_int(cpu, (unsigned int)vma);
157 schedule_work(&cookie_work);
158 goto out;
159 }
160
161 mm = get_task_mm(task);
162 if (!mm)
163 goto out;
164 if (!mm->arg_end)
165 goto outmm;
166 addr = mm->arg_start;
167 len = mm->arg_end - mm->arg_start;
168
169 if (len > TRANSLATE_SIZE)
170 len = TRANSLATE_SIZE;
171
172 down_read(&mm->mmap_sem);
173 while (len) {
174 if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0)
175 goto outsem;
176
177 maddr = kmap(page);
178 offset = addr & (PAGE_SIZE-1);
179 bytes = len;
180 if (bytes > PAGE_SIZE - offset)
181 bytes = PAGE_SIZE - offset;
182
183 copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes);
184
185 kunmap(page); // release page allocated by get_user_pages()
186 page_cache_release(page);
187
188 len -= bytes;
189 buf += bytes;
190 addr += bytes;
191
192 *text = per_cpu(translate_text, cpu);
193 retval = 1;
194 }
195
196 // On app_process startup, /proc/pid/cmdline is initially "zygote" then "<pre-initialized>" but changes after an initial startup period
197 if (strcmp(*text, "zygote") == 0 || strcmp(*text, "<pre-initialized>") == 0)
198 retval = 0;
199
200outsem:
201 up_read(&mm->mmap_sem);
202outmm:
203 mmput(mm);
204out:
205 return retval;
206}
207
208static inline uint32_t get_cookie(int cpu, struct task_struct *task, struct vm_area_struct *vma, struct module *mod)
209{
210 unsigned long flags, cookie;
211 struct path *path;
212 uint64_t key;
213 char *text;
214
215 if (mod) {
216 text = mod->name;
217 } else {
218 if (!vma || !vma->vm_file) {
219 return INVALID_COOKIE;
220 }
221 path = &vma->vm_file->f_path;
222 if (!path || !path->dentry) {
223 return INVALID_COOKIE;
224 }
225
226 text = (char*)path->dentry->d_name.name;
227 }
228
229 key = gator_chksum_crc32(text);
230 key = (key << 32) | (uint32_t)task->tgid;
231
232 cookie = cookiemap_exists(key);
233 if (cookie) {
234 return cookie;
235 }
236
237 if (strcmp(text, "app_process") == 0 && !mod) {
238 if (!translate_app_process(&text, cpu, task, vma))
239 return INVALID_COOKIE;
240 }
241
242 // Can be called from interrupt handler or from work queue
243 local_irq_save(flags);
244
245 cookie = per_cpu(cookie_next_key, cpu)+=nr_cpu_ids;
246 cookiemap_add(key, cookie);
247
248 gator_buffer_write_packed_int(cpu, PROTOCOL_COOKIE);
249 gator_buffer_write_packed_int(cpu, cookie);
250 gator_buffer_write_string(cpu, text);
251
252 local_irq_restore(flags);
253
254 return cookie;
255}
256
257static int get_exec_cookie(int cpu, struct task_struct *task)
258{
259 unsigned long cookie = NO_COOKIE;
260 struct mm_struct *mm = task->mm;
261 struct vm_area_struct *vma;
262
263 if (!mm)
264 return cookie;
265
266 for (vma = mm->mmap; vma; vma = vma->vm_next) {
267 if (!vma->vm_file)
268 continue;
269 if (!(vma->vm_flags & VM_EXECUTABLE))
270 continue;
271 cookie = get_cookie(cpu, task, vma, NULL);
272 break;
273 }
274
275 return cookie;
276}
277
278static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset)
279{
280 unsigned long cookie = NO_COOKIE;
281 struct mm_struct *mm = task->mm;
282 struct vm_area_struct *vma;
283
284 if (!mm)
285 return cookie;
286
287 for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
288 if (addr < vma->vm_start || addr >= vma->vm_end)
289 continue;
290
291 if (vma->vm_file) {
292 cookie = get_cookie(cpu, task, vma, NULL);
293 *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
294 } else {
295 /* must be an anonymous map */
296 *offset = addr;
297 }
298
299 break;
300 }
301
302 if (!vma)
303 cookie = INVALID_COOKIE;
304
305 return cookie;
306}
307
308static int cookies_initialize(void)
309{
310 uint32_t crc, poly;
311 int i, j, cpu, size, err = 0;
312
313 int translate_buffer_size = 512; // must be a power of 2
314 translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1;
315
316 for_each_present_cpu(cpu) {
317 per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu;
318
319 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t);
320 per_cpu(cookie_keys, cpu) = (uint64_t*)kmalloc(size, GFP_KERNEL);
321 memset(per_cpu(cookie_keys, cpu), 0, size);
322
323 size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t);
324 per_cpu(cookie_values, cpu) = (uint32_t*)kmalloc(size, GFP_KERNEL);
325 memset(per_cpu(cookie_values, cpu), 0, size);
326
327 per_cpu(translate_buffer, cpu) = (unsigned int *)kmalloc(translate_buffer_size, GFP_KERNEL);
328 if (!per_cpu(translate_buffer, cpu)) {
329 err = -ENOMEM;
330 goto cookie_setup_error;
331 }
332
333 per_cpu(translate_buffer_write, cpu) = 0;
334 per_cpu(translate_buffer_read, cpu) = 0;
335
336 per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL);
337 if (!per_cpu(translate_text, cpu)) {
338 err = -ENOMEM;
339 goto cookie_setup_error;
340 }
341 }
342
343 // build CRC32 table
344 poly = 0x04c11db7;
345 gator_crc32_table = (uint32_t*)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL);
346 for (i = 0; i < 256; i++) {
347 crc = i;
348 for (j = 8; j > 0; j--) {
349 if (crc & 1) {
350 crc = (crc >> 1) ^ poly;
351 } else {
352 crc >>= 1;
353 }
354 }
355 gator_crc32_table[i] = crc;
356 }
357
358cookie_setup_error:
359 return err;
360}
361
362static void cookies_release(void)
363{
364 int cpu;
365
366 for_each_present_cpu(cpu) {
367 kfree(per_cpu(cookie_keys, cpu));
368 per_cpu(cookie_keys, cpu) = NULL;
369
370 kfree(per_cpu(cookie_values, cpu));
371 per_cpu(cookie_values, cpu) = NULL;
372
373 kfree(per_cpu(translate_buffer, cpu));
374 per_cpu(translate_buffer, cpu) = NULL;
375 per_cpu(translate_buffer_read, cpu) = 0;
376 per_cpu(translate_buffer_write, cpu) = 0;
377
378 kfree(per_cpu(translate_text, cpu));
379 per_cpu(translate_text, cpu) = NULL;
380 }
381
382 kfree(gator_crc32_table);
383 gator_crc32_table = NULL;
384}
diff --git a/driver/gator_events.c b/driver/gator_events.c
new file mode 100644
index 0000000..d837257
--- /dev/null
+++ b/driver/gator_events.c
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10/**
11 * This file is #included in gator_main.c
12 * Update this file and Makefile to add custom counters.
13 */
14
15extern int gator_events_armv6_install(gator_interface *gi);
16extern int gator_events_armv7_install(gator_interface *gi);
17extern int gator_events_irq_install(gator_interface *gi);
18extern int gator_events_sched_install(gator_interface *gi);
19extern int gator_events_block_install(gator_interface *gi);
20extern int gator_events_meminfo_install(gator_interface *gi);
21extern int gator_events_net_install(gator_interface *gi);
22
23static int gator_events_install(void)
24{
25 if (gator_event_install(gator_events_armv6_install))
26 return -1;
27 if (gator_event_install(gator_events_armv7_install))
28 return -1;
29 if (gator_event_install(gator_events_irq_install))
30 return -1;
31 if (gator_event_install(gator_events_sched_install))
32 return -1;
33 if (gator_event_install(gator_events_block_install))
34 return -1;
35 if (gator_event_install(gator_events_meminfo_install))
36 return -1;
37 if (gator_event_install(gator_events_net_install))
38 return -1;
39 return 0;
40}
diff --git a/driver/gator_events.h b/driver/gator_events.h
new file mode 100644
index 0000000..8237c1a
--- /dev/null
+++ b/driver/gator_events.h
@@ -0,0 +1,19 @@
1/**
2 * Copyright 2010 ARM, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9
10struct __gator_interface {
11 int (*create_files)(struct super_block *sb, struct dentry *root);
12 int (*init)(int *key);
13 int (*start)(void);
14 void (*stop)(void);
15 int (*read)(int **buffer);
16 struct __gator_interface *next;
17};
18
19typedef struct __gator_interface gator_interface;
diff --git a/driver/gator_events.sh b/driver/gator_events.sh
new file mode 100644
index 0000000..5467dd6
--- /dev/null
+++ b/driver/gator_events.sh
@@ -0,0 +1,19 @@
1#!/bin/sh
2
3EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'`
4
5(
6 echo /\* This file is auto generated \*/
7 echo
8 for EVENT in $EVENTS; do
9 echo __weak int $EVENT\(void\)\;
10 done
11 echo
12 echo static int \(*gator_events_list[]\)\(void\) = {
13 for EVENT in $EVENTS; do
14 echo \ $EVENT,
15 done
16 echo }\;
17) > $1.tmp
18
19cmp -s $1 $1.tmp && rm $1.tmp || mv $1.tmp $1
diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c
new file mode 100644
index 0000000..7b1d875
--- /dev/null
+++ b/driver/gator_events_armv6.c
@@ -0,0 +1,224 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#define ARM1136 0xb36
12#define ARM1156 0xb56
13#define ARM1176 0xb76
14
15static const char *pmnc_name;
16
17/*
18 * Per-CPU PMCR
19 */
20#define PMCR_E (1 << 0) /* Enable */
21#define PMCR_P (1 << 1) /* Count reset */
22#define PMCR_C (1 << 2) /* Cycle counter reset */
23#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */
24#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */
25#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */
26
27#define PMN0 0
28#define PMN1 1
29#define CCNT 2
30#define CNTMAX (CCNT+1)
31
32static int pmnc_count = 0;
33static unsigned long pmnc_enabled[CNTMAX];
34static unsigned long pmnc_event[CNTMAX];
35static unsigned long pmnc_key[CNTMAX];
36
37static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
38static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
39
40static inline void armv6_pmnc_write(u32 val)
41{
42 /* upper 4bits and 7, 11 are write-as-0 */
43 val &= 0x0ffff77f;
44 asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val));
45}
46
47static inline u32 armv6_pmnc_read(void)
48{
49 u32 val;
50 asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
51 return val;
52}
53
54static void armv6_pmnc_reset_counter(unsigned int cnt)
55{
56 u32 val = 0;
57 switch (cnt) {
58 case CCNT:
59 asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val));
60 break;
61 case PMN0:
62 asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val));
63 break;
64 case PMN1:
65 asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val));
66 break;
67 }
68}
69
70int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root)
71{
72 struct dentry *dir;
73 int i;
74
75 pmnc_count = 3;
76
77 for (i = PMN0; i <= CCNT; i++) {
78 char buf[40];
79 if (i == CCNT) {
80 snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
81 } else {
82 snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i);
83 }
84 dir = gatorfs_mkdir(sb, root, buf);
85 if (!dir) {
86 return -1;
87 }
88 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
89 if (i != CCNT) {
90 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
91 }
92 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
93 }
94
95 return 0;
96}
97
98static void gator_events_armv6_online(void)
99{
100 unsigned int cnt;
101 u32 pmnc;
102
103 if (armv6_pmnc_read() & PMCR_E) {
104 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
105 }
106
107 /* initialize PMNC, reset overflow, D bit, C bit and P bit. */
108 armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT |
109 PMCR_C | PMCR_P);
110
111 /* configure control register */
112 for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) {
113 unsigned long event;
114
115 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
116
117 if (!pmnc_enabled[cnt])
118 continue;
119
120 event = pmnc_event[cnt] & 255;
121
122 /*
123 * Set event (if destined for PMNx counters)
124 */
125 if (cnt == PMN0) {
126 pmnc |= event << 20;
127 } else if (cnt == PMN1) {
128 pmnc |= event << 12;
129 }
130
131 /*
132 * Reset counter
133 */
134 armv6_pmnc_reset_counter(cnt);
135 }
136 armv6_pmnc_write(pmnc | PMCR_E);
137}
138
139static void gator_events_armv6_offline(void)
140{
141 unsigned int cnt;
142
143 armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E);
144 for (cnt = PMN0; cnt <= CCNT; cnt++) {
145 armv6_pmnc_reset_counter(cnt);
146 }
147}
148
149static void gator_events_armv6_stop(void)
150{
151 unsigned int cnt;
152
153 for (cnt = PMN0; cnt <= CCNT; cnt++) {
154 pmnc_enabled[cnt] = 0;
155 pmnc_event[cnt] = 0;
156 }
157}
158
159static int gator_events_armv6_read(int **buffer)
160{
161 int cnt, len = 0;
162 int cpu = smp_processor_id();
163
164 for (cnt = PMN0; cnt <= CCNT; cnt++) {
165 if (pmnc_enabled[cnt]) {
166 u32 value = 0;
167 switch (cnt) {
168 case CCNT:
169 asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value));
170 break;
171 case PMN0:
172 asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value));
173 break;
174 case PMN1:
175 asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value));
176 break;
177 }
178 armv6_pmnc_reset_counter(cnt);
179 if (value != per_cpu(perfPrev, cpu)[cnt]) {
180 per_cpu(perfPrev, cpu)[cnt] = value;
181 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
182 per_cpu(perfCnt, cpu)[len++] = value;
183 }
184 }
185 }
186
187 // update or discard
188 if (buffer)
189 *buffer = per_cpu(perfCnt, cpu);
190
191 return len;
192}
193
194static struct gator_interface gator_events_armv6_interface = {
195 .create_files = gator_events_armv6_create_files,
196 .stop = gator_events_armv6_stop,
197 .online = gator_events_armv6_online,
198 .offline = gator_events_armv6_offline,
199 .read = gator_events_armv6_read,
200};
201
202int gator_events_armv6_init(void)
203{
204 unsigned int cnt;
205
206 switch (gator_cpuid()) {
207 case ARM1136:
208 case ARM1156:
209 case ARM1176:
210 pmnc_name = "ARM11";
211 break;
212 default:
213 return -1;
214 }
215
216 for (cnt = PMN0; cnt <= CCNT; cnt++) {
217 pmnc_enabled[cnt] = 0;
218 pmnc_event[cnt] = 0;
219 pmnc_key[cnt] = gator_events_get_key();
220 }
221
222 return gator_events_install(&gator_events_armv6_interface);
223}
224gator_events_init(gator_events_armv6_init);
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c
new file mode 100644
index 0000000..0b84745
--- /dev/null
+++ b/driver/gator_events_armv7.c
@@ -0,0 +1,322 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#define CORTEX_A5 0xc05
12#define CORTEX_A8 0xc08
13#define CORTEX_A9 0xc09
14#define CORTEX_A15 0xc0f
15
16static const char *pmnc_name;
17static int pmnc_count;
18
19// Per-CPU PMNC: config reg
20#define PMNC_E (1 << 0) /* Enable all counters */
21#define PMNC_P (1 << 1) /* Reset all counters */
22#define PMNC_C (1 << 2) /* Cycle counter reset */
23#define PMNC_MASK 0x3f /* Mask for writable bits */
24
25// ccnt reg
26#define CCNT_REG (1 << 31)
27
28#define CCNT 0
29#define CNT0 1
30#define CNTMAX (6+1)
31
32static unsigned long pmnc_enabled[CNTMAX];
33static unsigned long pmnc_event[CNTMAX];
34static unsigned long pmnc_key[CNTMAX];
35
36static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
37static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
38
39static inline void armv7_pmnc_write(u32 val)
40{
41 val &= PMNC_MASK;
42 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
43}
44
45static inline u32 armv7_pmnc_read(void)
46{
47 u32 val;
48 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
49 return val;
50}
51
52static inline u32 armv7_ccnt_read(void)
53{
54 u32 zero = 0;
55 u32 den = CCNT_REG;
56 u32 val;
57
58 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
59 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read
60 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (zero)); // zero
61 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
62
63 return val;
64}
65
66static inline u32 armv7_cntn_read(unsigned int cnt)
67{
68 u32 zero = 0;
69 u32 sel = (cnt - CNT0);
70 u32 den = 1 << sel;
71 u32 val;
72
73 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable
74 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select
75 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); // read
76 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (zero)); // zero
77 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable
78
79 return val;
80}
81
82static inline u32 armv7_pmnc_enable_counter(unsigned int cnt)
83{
84 u32 val;
85
86 if (cnt >= CNTMAX) {
87 pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
88 return -1;
89 }
90
91 if (cnt == CCNT)
92 val = CCNT_REG;
93 else
94 val = (1 << (cnt - CNT0));
95
96 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
97
98 return cnt;
99}
100
101static inline u32 armv7_pmnc_disable_counter(unsigned int cnt)
102{
103 u32 val;
104
105 if (cnt >= CNTMAX) {
106 pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
107 return -1;
108 }
109
110 if (cnt == CCNT)
111 val = CCNT_REG;
112 else
113 val = (1 << (cnt - CNT0));
114
115 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
116
117 return cnt;
118}
119
120static inline int armv7_pmnc_select_counter(unsigned int cnt)
121{
122 u32 val;
123
124 if ((cnt == CCNT) || (cnt >= CNTMAX)) {
125 pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
126 return -1;
127 }
128
129 val = (cnt - CNT0);
130 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
131
132 return cnt;
133}
134
135static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val)
136{
137 if (armv7_pmnc_select_counter(cnt) == cnt) {
138 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
139 }
140}
141
142static void armv7_pmnc_reset_counter(unsigned int cnt)
143{
144 u32 val = 0;
145
146 if (cnt == CCNT) {
147 armv7_pmnc_disable_counter(cnt);
148
149 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
150
151 if (pmnc_enabled[cnt] != 0)
152 armv7_pmnc_enable_counter(cnt);
153
154 } else if (cnt >= CNTMAX) {
155 pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
156 } else {
157 armv7_pmnc_disable_counter(cnt);
158
159 if (armv7_pmnc_select_counter(cnt) == cnt)
160 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
161
162 if (pmnc_enabled[cnt] != 0)
163 armv7_pmnc_enable_counter(cnt);
164 }
165}
166
167static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root)
168{
169 struct dentry *dir;
170 int i;
171
172 for (i = 0; i < pmnc_count; i++) {
173 char buf[40];
174 if (i == 0) {
175 snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name);
176 } else {
177 snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i-1);
178 }
179 dir = gatorfs_mkdir(sb, root, buf);
180 if (!dir) {
181 return -1;
182 }
183 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
184 if (i > 0) {
185 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
186 }
187 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
188 }
189
190 return 0;
191}
192
193static void gator_events_armv7_online(void)
194{
195 unsigned int cnt;
196 int cpu = smp_processor_id();
197
198 if (armv7_pmnc_read() & PMNC_E) {
199 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
200 }
201
202 // Initialize & Reset PMNC: C bit and P bit
203 armv7_pmnc_write(PMNC_P | PMNC_C);
204
205 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
206 unsigned long event;
207
208 per_cpu(perfPrev, cpu)[cnt] = 0;
209
210 if (!pmnc_enabled[cnt])
211 continue;
212
213 // Disable counter
214 armv7_pmnc_disable_counter(cnt);
215
216 event = pmnc_event[cnt] & 255;
217
218 // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count
219 if (cnt != CCNT)
220 armv7_pmnc_write_evtsel(cnt, event);
221
222 // Reset counter
223 armv7_pmnc_reset_counter(cnt);
224
225 // Enable counter, but do not enable interrupt for this counter
226 armv7_pmnc_enable_counter(cnt);
227 }
228
229 // enable
230 armv7_pmnc_write(armv7_pmnc_read() | PMNC_E);
231}
232
233static void gator_events_armv7_offline(void)
234{
235 armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E);
236}
237
238static void gator_events_armv7_stop(void)
239{
240 unsigned int cnt;
241
242 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
243 pmnc_enabled[cnt] = 0;
244 pmnc_event[cnt] = 0;
245 }
246}
247
248static int gator_events_armv7_read(int **buffer)
249{
250 int cnt, len = 0;
251 int cpu = smp_processor_id();
252
253 if (!pmnc_count)
254 return 0;
255
256 for (cnt = 0; cnt < pmnc_count; cnt++) {
257 if (pmnc_enabled[cnt]) {
258 int value;
259 if (cnt == CCNT) {
260 value = armv7_ccnt_read();
261 } else {
262 value = armv7_cntn_read(cnt);
263 }
264 if (value != per_cpu(perfPrev, cpu)[cnt]) {
265 per_cpu(perfPrev, cpu)[cnt] = value;
266 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
267 per_cpu(perfCnt, cpu)[len++] = value;
268 }
269 }
270 }
271
272 // update or discard
273 if (buffer)
274 *buffer = per_cpu(perfCnt, cpu);
275
276 return len;
277}
278
279static struct gator_interface gator_events_armv7_interface = {
280 .create_files = gator_events_armv7_create_files,
281 .stop = gator_events_armv7_stop,
282 .online = gator_events_armv7_online,
283 .offline = gator_events_armv7_offline,
284 .read = gator_events_armv7_read,
285};
286
287int gator_events_armv7_init(void)
288{
289 unsigned int cnt;
290
291 switch (gator_cpuid()) {
292 case CORTEX_A5:
293 pmnc_name = "Cortex-A5";
294 pmnc_count = 2;
295 break;
296 case CORTEX_A8:
297 pmnc_name = "Cortex-A8";
298 pmnc_count = 4;
299 break;
300 case CORTEX_A9:
301 pmnc_name = "Cortex-A9";
302 pmnc_count = 6;
303 break;
304 case CORTEX_A15:
305 pmnc_name = "Cortex-A15";
306 pmnc_count = 6;
307 break;
308 default:
309 return -1;
310 }
311
312 pmnc_count++; // CNT[n] + CCNT
313
314 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
315 pmnc_enabled[cnt] = 0;
316 pmnc_event[cnt] = 0;
317 pmnc_key[cnt] = gator_events_get_key();
318 }
319
320 return gator_events_install(&gator_events_armv7_interface);
321}
322gator_events_init(gator_events_armv7_init);
diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c
new file mode 100644
index 0000000..cbfed86
--- /dev/null
+++ b/driver/gator_events_block.c
@@ -0,0 +1,171 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/block.h>
12
13#define BLOCK_RQ_WR 0
14#define BLOCK_RQ_RD 1
15
16#define BLOCK_TOTAL (BLOCK_RQ_RD+1)
17
18#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
19#define EVENTWRITE REQ_RW
20#else
21#define EVENTWRITE REQ_WRITE
22#endif
23
24static ulong block_rq_wr_enabled;
25static ulong block_rq_rd_enabled;
26static ulong block_rq_wr_key;
27static ulong block_rq_rd_key;
28static DEFINE_PER_CPU(int[BLOCK_TOTAL], blockCnt);
29static DEFINE_PER_CPU(int[BLOCK_TOTAL * 2], blockGet);
30static DEFINE_PER_CPU(bool, new_data_avail);
31
32GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq))
33{
34 unsigned long flags;
35 int write, size;
36 int cpu = smp_processor_id();
37
38 if (!rq)
39 return;
40
41 write = rq->cmd_flags & EVENTWRITE;
42 size = rq->resid_len;
43
44 if (!size)
45 return;
46
47 // disable interrupts to synchronize with gator_events_block_read()
48 // spinlocks not needed since percpu buffers are used
49 local_irq_save(flags);
50 if (write)
51 per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] += size;
52 else
53 per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] += size;
54 local_irq_restore(flags);
55
56 per_cpu(new_data_avail, cpu) = true;
57}
58
59static int gator_events_block_create_files(struct super_block *sb, struct dentry *root)
60{
61 struct dentry *dir;
62
63 /* block_complete_wr */
64 dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr");
65 if (!dir) {
66 return -1;
67 }
68 gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled);
69 gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key);
70
71 /* block_complete_rd */
72 dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd");
73 if (!dir) {
74 return -1;
75 }
76 gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled);
77 gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key);
78
79 return 0;
80}
81
82static int gator_events_block_start(void)
83{
84 int cpu;
85
86 for_each_present_cpu(cpu)
87 per_cpu(new_data_avail, cpu) = true;
88
89 // register tracepoints
90 if (block_rq_wr_enabled || block_rq_rd_enabled)
91 if (GATOR_REGISTER_TRACE(block_rq_complete))
92 goto fail_block_rq_exit;
93 pr_debug("gator: registered block event tracepoints\n");
94
95 return 0;
96
97 // unregister tracepoints on error
98fail_block_rq_exit:
99 pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
100
101 return -1;
102}
103
104static void gator_events_block_stop(void)
105{
106 if (block_rq_wr_enabled || block_rq_rd_enabled)
107 GATOR_UNREGISTER_TRACE(block_rq_complete);
108 pr_debug("gator: unregistered block event tracepoints\n");
109
110 block_rq_wr_enabled = 0;
111 block_rq_rd_enabled = 0;
112}
113
114static int gator_events_block_read(int **buffer)
115{
116 unsigned long flags;
117 int len, value, cpu, data = 0;
118 cpu = smp_processor_id();
119
120 if (per_cpu(new_data_avail, cpu) == false)
121 return 0;
122
123 per_cpu(new_data_avail, cpu) = false;
124
125 len = 0;
126 if (block_rq_wr_enabled) {
127 local_irq_save(flags);
128 value = per_cpu(blockCnt, cpu)[BLOCK_RQ_WR];
129 per_cpu(blockCnt, cpu)[BLOCK_RQ_WR] = 0;
130 local_irq_restore(flags);
131 per_cpu(blockGet, cpu)[len++] = block_rq_wr_key;
132 per_cpu(blockGet, cpu)[len++] = value;
133 data += value;
134 }
135 if (block_rq_rd_enabled) {
136 local_irq_save(flags);
137 value = per_cpu(blockCnt, cpu)[BLOCK_RQ_RD];
138 per_cpu(blockCnt, cpu)[BLOCK_RQ_RD] = 0;
139 local_irq_restore(flags);
140 per_cpu(blockGet, cpu)[len++] = block_rq_rd_key;
141 per_cpu(blockGet, cpu)[len++] = value;
142 data += value;
143 }
144
145 if (data != 0)
146 per_cpu(new_data_avail, cpu) = true;
147
148 if (buffer)
149 *buffer = per_cpu(blockGet, cpu);
150
151 return len;
152}
153
154static struct gator_interface gator_events_block_interface = {
155 .create_files = gator_events_block_create_files,
156 .start = gator_events_block_start,
157 .stop = gator_events_block_stop,
158 .read = gator_events_block_read,
159};
160
161int gator_events_block_init(void)
162{
163 block_rq_wr_enabled = 0;
164 block_rq_rd_enabled = 0;
165
166 block_rq_wr_key = gator_events_get_key();
167 block_rq_rd_key = gator_events_get_key();
168
169 return gator_events_install(&gator_events_block_interface);
170}
171gator_events_init(gator_events_block_init);
diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c
new file mode 100644
index 0000000..36a6589
--- /dev/null
+++ b/driver/gator_events_irq.c
@@ -0,0 +1,171 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/irq.h>
12
13#define HARDIRQ 0
14#define SOFTIRQ 1
15#define TOTALIRQ (SOFTIRQ+1)
16
17static ulong hardirq_enabled;
18static ulong softirq_enabled;
19static ulong hardirq_key;
20static ulong softirq_key;
21static DEFINE_PER_CPU(int[TOTALIRQ], irqCnt);
22static DEFINE_PER_CPU(int[TOTALIRQ], irqPrev);
23static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet);
24
25GATOR_DEFINE_PROBE(irq_handler_exit, TP_PROTO(int irq,
26 struct irqaction *action, int ret))
27{
28 unsigned long flags;
29
30 // disable interrupts to synchronize with gator_events_irq_read()
31 // spinlocks not needed since percpu buffers are used
32 local_irq_save(flags);
33 per_cpu(irqCnt, smp_processor_id())[HARDIRQ]++;
34 local_irq_restore(flags);
35}
36
37#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)
38GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec))
39#else
40GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr))
41#endif
42{
43 unsigned long flags;
44
45 // disable interrupts to synchronize with gator_events_irq_read()
46 // spinlocks not needed since percpu buffers are used
47 local_irq_save(flags);
48 per_cpu(irqCnt, smp_processor_id())[SOFTIRQ]++;
49 local_irq_restore(flags);
50}
51
52static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root)
53{
54 struct dentry *dir;
55
56 /* irq */
57 dir = gatorfs_mkdir(sb, root, "Linux_irq_irq");
58 if (!dir) {
59 return -1;
60 }
61 gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled);
62 gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key);
63
64 /* soft irq */
65 dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq");
66 if (!dir) {
67 return -1;
68 }
69 gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled);
70 gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key);
71
72 return 0;
73}
74
75static int gator_events_irq_start(void)
76{
77 int cpu, i;
78
79 for_each_present_cpu(cpu) {
80 for (i = 0; i < TOTALIRQ; i++)
81 per_cpu(irqPrev, cpu)[i] = 0;
82 }
83
84 // register tracepoints
85 if (hardirq_enabled)
86 if (GATOR_REGISTER_TRACE(irq_handler_exit))
87 goto fail_hardirq_exit;
88 if (softirq_enabled)
89 if (GATOR_REGISTER_TRACE(softirq_exit))
90 goto fail_softirq_exit;
91 pr_debug("gator: registered irq tracepoints\n");
92
93 return 0;
94
95 // unregister tracepoints on error
96fail_softirq_exit:
97 if (hardirq_enabled)
98 GATOR_UNREGISTER_TRACE(irq_handler_exit);
99fail_hardirq_exit:
100 pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
101
102 return -1;
103}
104
105static void gator_events_irq_stop(void)
106{
107 if (hardirq_enabled)
108 GATOR_UNREGISTER_TRACE(irq_handler_exit);
109 if (softirq_enabled)
110 GATOR_UNREGISTER_TRACE(softirq_exit);
111 pr_debug("gator: unregistered irq tracepoints\n");
112
113 hardirq_enabled = 0;
114 softirq_enabled = 0;
115}
116
117static int gator_events_irq_read(int **buffer)
118{
119 unsigned long flags;
120 int len, value;
121 int cpu = smp_processor_id();
122
123 len = 0;
124 if (hardirq_enabled) {
125 local_irq_save(flags);
126 value = per_cpu(irqCnt, cpu)[HARDIRQ];
127 per_cpu(irqCnt, cpu)[HARDIRQ] = 0;
128 local_irq_restore(flags);
129 if (value != per_cpu(irqPrev, cpu)[HARDIRQ]) {
130 per_cpu(irqPrev, cpu)[HARDIRQ] = value;
131 per_cpu(irqGet, cpu)[len++] = hardirq_key;
132 per_cpu(irqGet, cpu)[len++] = value;
133 }
134 }
135
136 if (softirq_enabled) {
137 local_irq_save(flags);
138 value = per_cpu(irqCnt, cpu)[SOFTIRQ];
139 per_cpu(irqCnt, cpu)[SOFTIRQ] = 0;
140 local_irq_restore(flags);
141 if (value != per_cpu(irqPrev, cpu)[SOFTIRQ]) {
142 per_cpu(irqPrev, cpu)[SOFTIRQ] = value;
143 per_cpu(irqGet, cpu)[len++] = softirq_key;
144 per_cpu(irqGet, cpu)[len++] = value;
145 }
146 }
147
148 if (buffer)
149 *buffer = per_cpu(irqGet, cpu);
150
151 return len;
152}
153
154static struct gator_interface gator_events_irq_interface = {
155 .create_files = gator_events_irq_create_files,
156 .start = gator_events_irq_start,
157 .stop = gator_events_irq_stop,
158 .read = gator_events_irq_read,
159};
160
161int gator_events_irq_init(void)
162{
163 hardirq_key = gator_events_get_key();
164 softirq_key = gator_events_get_key();
165
166 hardirq_enabled = 0;
167 softirq_enabled = 0;
168
169 return gator_events_install(&gator_events_irq_interface);
170}
171gator_events_init(gator_events_irq_init);
diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c
new file mode 100644
index 0000000..f1595bd
--- /dev/null
+++ b/driver/gator_events_meminfo.c
@@ -0,0 +1,195 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <linux/workqueue.h>
12#include <trace/events/kmem.h>
13
14#define MEMINFO_MEMFREE 0
15#define MEMINFO_MEMUSED 1
16#define MEMINFO_BUFFERRAM 2
17#define MEMINFO_TOTAL 3
18
19static ulong meminfo_global_enabled;
20static ulong meminfo_enabled[MEMINFO_TOTAL];
21static ulong meminfo_key[MEMINFO_TOTAL];
22static int meminfo_buffer[MEMINFO_TOTAL * 2];
23static int meminfo_length = 0;
24static unsigned int mem_event = 0;
25static bool new_data_avail;
26
27static void wq_sched_handler(struct work_struct *wsptr);
28
29DECLARE_WORK(work, wq_sched_handler);
30
31GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
32 mem_event++;
33}
34
35GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) {
36 mem_event++;
37}
38
39GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) {
40 mem_event++;
41}
42
43static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root)
44{
45 struct dentry *dir;
46 int i;
47
48 for (i = 0; i < MEMINFO_TOTAL; i++) {
49 switch (i) {
50 case MEMINFO_MEMFREE:
51 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree");
52 break;
53 case MEMINFO_MEMUSED:
54 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused");
55 break;
56 case MEMINFO_BUFFERRAM:
57 dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram");
58 break;
59 default:
60 return -1;
61 }
62 if (!dir) {
63 return -1;
64 }
65 gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]);
66 gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]);
67 }
68
69 return 0;
70}
71
72static int gator_events_meminfo_start(void)
73{
74 int i;
75
76 new_data_avail = true;
77 for (i = 0; i < MEMINFO_TOTAL; i++) {
78 if (meminfo_enabled[i]) {
79 meminfo_global_enabled = 1;
80 }
81 }
82
83 if (meminfo_global_enabled == 0)
84 return 0;
85
86 if (GATOR_REGISTER_TRACE(mm_page_free_direct))
87 goto mm_page_free_direct_exit;
88 if (GATOR_REGISTER_TRACE(mm_pagevec_free))
89 goto mm_pagevec_free_exit;
90 if (GATOR_REGISTER_TRACE(mm_page_alloc))
91 goto mm_page_alloc_exit;
92
93 return 0;
94
95mm_page_alloc_exit:
96 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
97mm_pagevec_free_exit:
98 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
99mm_page_free_direct_exit:
100 return -1;
101}
102
103static void gator_events_meminfo_stop(void)
104{
105 int i;
106
107 if (meminfo_global_enabled) {
108 GATOR_UNREGISTER_TRACE(mm_page_free_direct);
109 GATOR_UNREGISTER_TRACE(mm_pagevec_free);
110 GATOR_UNREGISTER_TRACE(mm_page_alloc);
111 }
112
113 meminfo_global_enabled = 0;
114 for (i = 0; i < MEMINFO_TOTAL; i++) {
115 meminfo_enabled[i] = 0;
116 }
117}
118
119// Must be run in a work queue as the kernel function si_meminfo() can sleep
120static void wq_sched_handler(struct work_struct *wsptr)
121{
122 struct sysinfo info;
123 int i, len, value;
124
125 meminfo_length = len = 0;
126
127 si_meminfo(&info);
128 for (i = 0; i < MEMINFO_TOTAL; i++) {
129 if (meminfo_enabled[i]) {
130 switch (i) {
131 case MEMINFO_MEMFREE:
132 value = info.freeram * PAGE_SIZE;
133 break;
134 case MEMINFO_MEMUSED:
135 value = (info.totalram - info.freeram) * PAGE_SIZE;
136 break;
137 case MEMINFO_BUFFERRAM:
138 value = info.bufferram * PAGE_SIZE;
139 break;
140 default:
141 value = 0;
142 break;
143 }
144 meminfo_buffer[len++] = meminfo_key[i];
145 meminfo_buffer[len++] = value;
146 }
147 }
148
149 meminfo_length = len;
150 new_data_avail = true;
151}
152
153static int gator_events_meminfo_read(int **buffer)
154{
155 static unsigned int last_mem_event = 0;
156
157 if (smp_processor_id() || !meminfo_global_enabled)
158 return 0;
159
160 if (last_mem_event != mem_event) {
161 last_mem_event = mem_event;
162 schedule_work(&work);
163 }
164
165 if (!new_data_avail)
166 return 0;
167
168 new_data_avail = false;
169
170 if (buffer)
171 *buffer = meminfo_buffer;
172
173 return meminfo_length;
174}
175
176static struct gator_interface gator_events_meminfo_interface = {
177 .create_files = gator_events_meminfo_create_files,
178 .start = gator_events_meminfo_start,
179 .stop = gator_events_meminfo_stop,
180 .read = gator_events_meminfo_read,
181};
182
183int gator_events_meminfo_init(void)
184{
185 int i;
186
187 meminfo_global_enabled = 0;
188 for (i = 0; i < MEMINFO_TOTAL; i++) {
189 meminfo_enabled[i] = 0;
190 meminfo_key[i] = gator_events_get_key();
191 }
192
193 return gator_events_install(&gator_events_meminfo_interface);
194}
195gator_events_init(gator_events_meminfo_init);
diff --git a/driver/gator_events_mmaped.c b/driver/gator_events_mmaped.c
new file mode 100644
index 0000000..6884684
--- /dev/null
+++ b/driver/gator_events_mmaped.c
@@ -0,0 +1,196 @@
1/*
2 * Example events provider
3 *
4 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Similar entires must be present in events.xml file:
11 *
12 * <counter_set name="mmaped_cntX">
13 * <counter name="mmaped_cnt0"/>
14 * <counter name="mmaped_cnt1"/>
15 * </counter_set>
16 * <category name="mmaped" counter_set="mmaped_cntX" per_cpu="no">
17 * <event event="0x0" title="Simulated" name="Sine" description="Sort-of-sine"/>
18 * <event event="0x1" title="Simulated" name="Triangle" description="Triangular wave"/>
19 * <event event="0x2" title="Simulated" name="PWM" description="PWM Signal"/>
20 * </category>
21 */
22
23#include <linux/init.h>
24#include <linux/io.h>
25#include <linux/ratelimit.h>
26
27#include "gator.h"
28
29#define MMAPED_COUNTERS_NUM 3
30
31static struct {
32 unsigned long enabled;
33 unsigned long event;
34 unsigned long key;
35} mmaped_counters[MMAPED_COUNTERS_NUM];
36
37static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
38
39#ifdef TODO
40static void __iomem *mmaped_base;
41#endif
42
43/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */
44static int gator_events_mmaped_create_files(struct super_block *sb,
45 struct dentry *root)
46{
47 int i;
48
49 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
50 char buf[16];
51 struct dentry *dir;
52
53 snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
54 dir = gatorfs_mkdir(sb, root, buf);
55 if (WARN_ON(!dir))
56 return -1;
57 gatorfs_create_ulong(sb, dir, "enabled",
58 &mmaped_counters[i].enabled);
59 gatorfs_create_ulong(sb, dir, "event",
60 &mmaped_counters[i].event);
61 gatorfs_create_ro_ulong(sb, dir, "key",
62 &mmaped_counters[i].key);
63 }
64
65 return 0;
66}
67
68static int gator_events_mmaped_start(void)
69{
70#ifdef TODO
71 for (i = 0; i < MMAPED_COUNTERS_NUM; i++)
72 writel(mmaped_counters[i].event,
73 mmaped_base + COUNTERS_CONFIG_OFFSET[i]);
74
75 writel(ENABLED, COUNTERS_CONTROL_OFFSET);
76#endif
77
78 return 0;
79}
80
81static void gator_events_mmaped_stop(void)
82{
83#ifdef TODO
84 writel(DISABLED, COUNTERS_CONTROL_OFFSET);
85#endif
86}
87
88#ifndef TODO
89/* This function "simulates" counters, generating values of fancy
90 * functions like sine or triangle... */
91static int mmaped_simulate(int counter)
92{
93 int result = 0;
94
95 switch (counter) {
96 case 0: /* sort-of-sine */
97 {
98 static int t;
99 int x;
100
101 if (t % 1024 < 512)
102 x = 512 - (t % 512);
103 else
104 x = t % 512;
105
106 result = 32 * x / 512;
107 result = result * result;
108
109 if (t < 1024)
110 result = 1922 - result;
111
112 t = (t + 1) % 2048;
113 }
114 break;
115 case 1: /* triangle */
116 {
117 static int v, d = 1;
118
119 v += d;
120 if (v % 2000 == 0)
121 d = -d;
122
123 result = v;
124 }
125 break;
126 case 2: /* PWM signal */
127 {
128 static int t, dc;
129
130 t = (t + 1) % 2000;
131 if (t % 100)
132 dc = (dc + 200) % 2000;
133
134 result = t < dc ? 0 : 2000;
135 }
136 break;
137 }
138
139 return result;
140}
141#endif
142
143static int gator_events_mmaped_read(int **buffer)
144{
145 int i;
146 int len = 0;
147
148 /* System wide counters - read from one core only */
149 if (smp_processor_id())
150 return 0;
151
152 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
153 if (mmaped_counters[i].enabled) {
154 mmaped_buffer[len++] = mmaped_counters[i].key;
155#ifdef TODO
156 mmaped_buffer[len++] = readl(mmaped_base +
157 COUNTERS_VALUE_OFFSET[i]);
158#else
159 mmaped_buffer[len++] = mmaped_simulate(
160 mmaped_counters[i].event);
161#endif
162 }
163 }
164
165 if (buffer)
166 *buffer = mmaped_buffer;
167
168 return len;
169}
170
171static struct gator_interface gator_events_mmaped_interface = {
172 .create_files = gator_events_mmaped_create_files,
173 .start = gator_events_mmaped_start,
174 .stop = gator_events_mmaped_stop,
175 .read = gator_events_mmaped_read,
176};
177
178/* Must not be static! */
179int __init gator_events_mmaped_init(void)
180{
181 int i;
182
183#ifdef TODO
184 mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K);
185 if (!mmaped_base)
186 return -ENOMEM;
187#endif
188
189 for (i = 0; i < MMAPED_COUNTERS_NUM; i++) {
190 mmaped_counters[i].enabled = 0;
191 mmaped_counters[i].key = gator_events_get_key();
192 }
193
194 return gator_events_install(&gator_events_mmaped_interface);
195}
196gator_events_init(gator_events_mmaped_init);
diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c
new file mode 100644
index 0000000..a921586
--- /dev/null
+++ b/driver/gator_events_net.c
@@ -0,0 +1,177 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <linux/netdevice.h>
12
13#define NETRX 0
14#define NETTX 1
15#define NETDRV 2
16#define TOTALNET (NETDRV+1)
17
18static ulong netdrv_enabled;
19static ulong netrx_enabled;
20static ulong nettx_enabled;
21static ulong netdrv_key;
22static ulong netrx_key;
23static ulong nettx_key;
24static int rx_total, tx_total;
25static ulong netPrev[TOTALNET];
26static int netGet[TOTALNET * 2];
27
28static void get_network_stats(struct work_struct *wsptr) {
29 int rx = 0, tx = 0;
30 struct net_device *dev;
31
32 for_each_netdev(&init_net, dev) {
33#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
34 const struct net_device_stats *stats = dev_get_stats(dev);
35#else
36 struct rtnl_link_stats64 temp;
37 const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
38#endif
39 rx += stats->rx_bytes;
40 tx += stats->tx_bytes;
41 }
42 rx_total = rx;
43 tx_total = tx;
44}
45DECLARE_WORK(wq_get_stats, get_network_stats);
46
47static void calculate_delta(int *drv, int *rx, int *tx)
48{
49 int drv_calc, rx_calc, tx_calc;
50
51 drv_calc = gator_net_traffic - netPrev[NETDRV];
52 if (drv_calc > 0) {
53 netPrev[NETDRV] += drv_calc;
54 netPrev[NETTX] += drv_calc;
55 // remove tcp/ip header overhead
56 // approximation based on empirical measurement
57 netPrev[NETRX] += drv_calc / 42;
58 netPrev[NETTX] += drv_calc / 18;
59 }
60
61 rx_calc = (int)(rx_total - netPrev[NETRX]);
62 if (rx_calc < 0)
63 rx_calc = 0;
64 netPrev[NETRX] += rx_calc;
65
66 tx_calc = (int)(tx_total - netPrev[NETTX]);
67 if (tx_calc < 0)
68 tx_calc = 0;
69 netPrev[NETTX] += tx_calc;
70
71 *drv = drv_calc;
72 *rx = rx_calc;
73 *tx = tx_calc;
74}
75
76static int gator_events_net_create_files(struct super_block *sb, struct dentry *root)
77{
78 struct dentry *dir;
79
80 dir = gatorfs_mkdir(sb, root, "Linux_net_drv");
81 if (!dir) {
82 return -1;
83 }
84 gatorfs_create_ulong(sb, dir, "enabled", &netdrv_enabled);
85 gatorfs_create_ro_ulong(sb, dir, "key", &netdrv_key);
86
87 dir = gatorfs_mkdir(sb, root, "Linux_net_rx");
88 if (!dir) {
89 return -1;
90 }
91 gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled);
92 gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key);
93
94 dir = gatorfs_mkdir(sb, root, "Linux_net_tx");
95 if (!dir) {
96 return -1;
97 }
98 gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled);
99 gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key);
100
101 return 0;
102}
103
104static int gator_events_net_start(void)
105{
106 get_network_stats(NULL);
107 netPrev[NETDRV] = 0;
108 netPrev[NETRX] = rx_total;
109 netPrev[NETTX] = tx_total;
110 return 0;
111}
112
113static void gator_events_net_stop(void)
114{
115 netdrv_enabled = 0;
116 netrx_enabled = 0;
117 nettx_enabled = 0;
118}
119
120static int gator_events_net_read(int **buffer)
121{
122 int len, drv_delta, rx_delta, tx_delta;
123 static int last_drv_delta = 0, last_rx_delta = 0, last_tx_delta = 0;
124
125 if (smp_processor_id() != 0)
126 return 0;
127
128 schedule_work(&wq_get_stats);
129 calculate_delta(&drv_delta, &rx_delta, &tx_delta);
130
131 len = 0;
132 if (netdrv_enabled && last_drv_delta != drv_delta) {
133 last_drv_delta = drv_delta;
134 netGet[len++] = netdrv_key;
135 netGet[len++] = drv_delta;
136 }
137
138 if (netrx_enabled && last_rx_delta != rx_delta) {
139 last_rx_delta = rx_delta;
140 netGet[len++] = netrx_key;
141 netGet[len++] = rx_delta;
142 }
143
144 if (nettx_enabled && last_tx_delta != tx_delta) {
145 last_tx_delta = tx_delta;
146 netGet[len++] = nettx_key;
147 netGet[len++] = tx_delta;
148 }
149
150 if (buffer)
151 *buffer = netGet;
152
153 return len;
154}
155
156static struct gator_interface gator_events_net_interface = {
157 .create_files = gator_events_net_create_files,
158 .start = gator_events_net_start,
159 .stop = gator_events_net_stop,
160 .read = gator_events_net_read,
161};
162
163int gator_events_net_init(void)
164{
165 gator_net_traffic++;
166
167 netdrv_key = gator_events_get_key();
168 netrx_key = gator_events_get_key();
169 nettx_key = gator_events_get_key();
170
171 netdrv_enabled = 0;
172 netrx_enabled = 0;
173 nettx_enabled = 0;
174
175 return gator_events_install(&gator_events_net_interface);
176}
177gator_events_init(gator_events_net_init);
diff --git a/driver/gator_events_pl310.c b/driver/gator_events_pl310.c
new file mode 100644
index 0000000..0ef0cf3
--- /dev/null
+++ b/driver/gator_events_pl310.c
@@ -0,0 +1,176 @@
1/**
2 * PL310 (L2 Cache Controller) event counters for gator
3 *
4 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/io.h>
13#include <asm/hardware/cache-l2x0.h>
14
15#include "gator.h"
16
17#define PL310_COUNTERS_NUM 2
18
19static struct {
20 unsigned long enabled;
21 unsigned long event;
22 unsigned long key;
23} pl310_counters[PL310_COUNTERS_NUM];
24
25static int pl310_buffer[PL310_COUNTERS_NUM * 2];
26
27static void __iomem *pl310_base;
28
29
30
31static void gator_events_pl310_reset_counters(void)
32{
33 u32 val = readl(pl310_base + L2X0_EVENT_CNT_CTRL);
34
35 val |= ((1 << PL310_COUNTERS_NUM) - 1) << 1;
36
37 writel(val, pl310_base + L2X0_EVENT_CNT_CTRL);
38}
39
40
41static int gator_events_pl310_create_files(struct super_block *sb,
42 struct dentry *root)
43{
44 int i;
45
46 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
47 char buf[16];
48 struct dentry *dir;
49
50 snprintf(buf, sizeof(buf), "PL310_cnt%d", i);
51 dir = gatorfs_mkdir(sb, root, buf);
52 if (WARN_ON(!dir))
53 return -1;
54 gatorfs_create_ulong(sb, dir, "enabled",
55 &pl310_counters[i].enabled);
56 gatorfs_create_ulong(sb, dir, "event",
57 &pl310_counters[i].event);
58 gatorfs_create_ro_ulong(sb, dir, "key",
59 &pl310_counters[i].key);
60 }
61
62 return 0;
63}
64
65static int gator_events_pl310_start(void)
66{
67 static const unsigned long l2x0_event_cntx_cfg[PL310_COUNTERS_NUM] = {
68 L2X0_EVENT_CNT0_CFG,
69 L2X0_EVENT_CNT1_CFG,
70 };
71 int i;
72
73 /* Counter event sources */
74 for (i = 0; i < PL310_COUNTERS_NUM; i++)
75 writel((pl310_counters[i].event & 0xf) << 2,
76 pl310_base + l2x0_event_cntx_cfg[i]);
77
78 gator_events_pl310_reset_counters();
79
80 /* Event counter enable */
81 writel(1, pl310_base + L2X0_EVENT_CNT_CTRL);
82
83 return 0;
84}
85
86static void gator_events_pl310_stop(void)
87{
88 /* Event counter disable */
89 writel(0, pl310_base + L2X0_EVENT_CNT_CTRL);
90}
91
92static int gator_events_pl310_read(int **buffer)
93{
94 static const unsigned long l2x0_event_cntx_val[PL310_COUNTERS_NUM] = {
95 L2X0_EVENT_CNT0_VAL,
96 L2X0_EVENT_CNT1_VAL,
97 };
98 int i;
99 int len = 0;
100
101 if (smp_processor_id())
102 return 0;
103
104 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
105 if (pl310_counters[i].enabled) {
106 pl310_buffer[len++] = pl310_counters[i].key;
107 pl310_buffer[len++] = readl(pl310_base +
108 l2x0_event_cntx_val[i]);
109 }
110 }
111
112 /* PL310 counters are saturating, not wrapping in case of overflow */
113 gator_events_pl310_reset_counters();
114
115 if (buffer)
116 *buffer = pl310_buffer;
117
118 return len;
119}
120
121static struct gator_interface gator_events_pl310_interface = {
122 .create_files = gator_events_pl310_create_files,
123 .start = gator_events_pl310_start,
124 .stop = gator_events_pl310_stop,
125 .read = gator_events_pl310_read,
126};
127
128static void __maybe_unused gator_events_pl310_probe(unsigned long phys)
129{
130 if (pl310_base)
131 return;
132
133 pl310_base = ioremap(phys, SZ_4K);
134 if (pl310_base) {
135 u32 cache_id = readl(pl310_base + L2X0_CACHE_ID);
136
137 if ((cache_id & 0xff0003c0) != 0x410000c0) {
138 iounmap(pl310_base);
139 pl310_base = NULL;
140 }
141 }
142}
143
144int gator_events_pl310_init(void)
145{
146 int i;
147
148#if defined(CONFIG_ARCH_EXYNOS4)
149 gator_events_pl310_probe(0xfe600000);
150#endif
151#if defined(CONFIG_ARCH_OMAP4)
152 gator_events_pl310_probe(0x48242000);
153#endif
154#if defined(CONFIG_ARCH_TEGRA)
155 gator_events_pl310_probe(0x50043000);
156#endif
157#if defined(CONFIG_ARCH_U8500)
158 gator_events_pl310_probe(0xa0412000);
159#endif
160#if defined(CONFIG_ARCH_VEXPRESS) && !defined(CONFIG_ARCH_VEXPRESS_CA15X4)
161 // A9x4 core tile (HBI-0191)
162 gator_events_pl310_probe(0x1e00a000);
163 // New memory map tiles
164 gator_events_pl310_probe(0x2c0f0000);
165#endif
166 if (!pl310_base)
167 return -1;
168
169 for (i = 0; i < PL310_COUNTERS_NUM; i++) {
170 pl310_counters[i].enabled = 0;
171 pl310_counters[i].key = gator_events_get_key();
172 }
173
174 return gator_events_install(&gator_events_pl310_interface);
175}
176gator_events_init(gator_events_pl310_init);
diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c
new file mode 100644
index 0000000..7e9db60
--- /dev/null
+++ b/driver/gator_events_sched.c
@@ -0,0 +1,114 @@
1/**
2 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include "gator.h"
11#include <trace/events/sched.h>
12
13#define SCHED_SWITCH 0
14#define SCHED_TOTAL (SCHED_SWITCH+1)
15
16static ulong sched_switch_enabled;
17static ulong sched_switch_key;
18static DEFINE_PER_CPU(int[SCHED_TOTAL], schedCnt);
19static DEFINE_PER_CPU(int[SCHED_TOTAL * 2], schedGet);
20
21#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
22GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
23#else
24GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
25#endif
26{
27 unsigned long flags;
28
29 // disable interrupts to synchronize with gator_events_sched_read()
30 // spinlocks not needed since percpu buffers are used
31 local_irq_save(flags);
32 per_cpu(schedCnt, smp_processor_id())[SCHED_SWITCH]++;
33 local_irq_restore(flags);
34}
35
36static int gator_events_sched_create_files(struct super_block *sb, struct dentry *root)
37{
38 struct dentry *dir;
39
40 /* switch */
41 dir = gatorfs_mkdir(sb, root, "Linux_sched_switch");
42 if (!dir) {
43 return -1;
44 }
45 gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled);
46 gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key);
47
48 return 0;
49}
50
51static int gator_events_sched_start(void)
52{
53 // register tracepoints
54 if (sched_switch_enabled)
55 if (GATOR_REGISTER_TRACE(sched_switch))
56 goto sched_switch_exit;
57 pr_debug("gator: registered scheduler event tracepoints\n");
58
59 return 0;
60
61 // unregister tracepoints on error
62sched_switch_exit:
63 pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n");
64
65 return -1;
66}
67
68static void gator_events_sched_stop(void)
69{
70 if (sched_switch_enabled)
71 GATOR_UNREGISTER_TRACE(sched_switch);
72 pr_debug("gator: unregistered scheduler event tracepoints\n");
73
74 sched_switch_enabled = 0;
75}
76
77static int gator_events_sched_read(int **buffer)
78{
79 unsigned long flags;
80 int len, value;
81 int cpu = smp_processor_id();
82
83 len = 0;
84 if (sched_switch_enabled) {
85 local_irq_save(flags);
86 value = per_cpu(schedCnt, cpu)[SCHED_SWITCH];
87 per_cpu(schedCnt, cpu)[SCHED_SWITCH] = 0;
88 local_irq_restore(flags);
89 per_cpu(schedGet, cpu)[len++] = sched_switch_key;
90 per_cpu(schedGet, cpu)[len++] = value;
91 }
92
93 if (buffer)
94 *buffer = per_cpu(schedGet, cpu);
95
96 return len;
97}
98
99static struct gator_interface gator_events_sched_interface = {
100 .create_files = gator_events_sched_create_files,
101 .start = gator_events_sched_start,
102 .stop = gator_events_sched_stop,
103 .read = gator_events_sched_read,
104};
105
106int gator_events_sched_init(void)
107{
108 sched_switch_enabled = 0;
109
110 sched_switch_key = gator_events_get_key();
111
112 return gator_events_install(&gator_events_sched_interface);
113}
114gator_events_init(gator_events_sched_init);
diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c
new file mode 100644
index 0000000..d831a50
--- /dev/null
+++ b/driver/gator_events_scorpion.c
@@ -0,0 +1,661 @@
1/**
2 * Copyright (C) ARM Limited 2011. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "gator.h"
10
11#define SCORPION 0xf
12#define SCORPIONMP 0x2d
13
14static const char *pmnc_name;
15static int pmnc_count;
16
17// Per-CPU PMNC: config reg
18#define PMNC_E (1 << 0) /* Enable all counters */
19#define PMNC_P (1 << 1) /* Reset all counters */
20#define PMNC_C (1 << 2) /* Cycle counter reset */
21#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */
22#define PMNC_X (1 << 4) /* Export to ETM */
23#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug*/
24#define PMNC_MASK 0x3f /* Mask for writable bits */
25
26// ccnt reg
27#define CCNT_REG (1 << 31)
28
29#define CCNT 0
30#define CNT0 1
31#define CNTMAX (4+1)
32
33static unsigned long pmnc_enabled[CNTMAX];
34static unsigned long pmnc_event[CNTMAX];
35static unsigned long pmnc_key[CNTMAX];
36
37static DEFINE_PER_CPU(int[CNTMAX], perfPrev);
38static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt);
39
40enum scorpion_perf_types {
41 SCORPION_ICACHE_EXPL_INV = 0x4c,
42 SCORPION_ICACHE_MISS = 0x4d,
43 SCORPION_ICACHE_ACCESS = 0x4e,
44 SCORPION_ICACHE_CACHEREQ_L2 = 0x4f,
45 SCORPION_ICACHE_NOCACHE_L2 = 0x50,
46 SCORPION_HIQUP_NOPED = 0x51,
47 SCORPION_DATA_ABORT = 0x52,
48 SCORPION_IRQ = 0x53,
49 SCORPION_FIQ = 0x54,
50 SCORPION_ALL_EXCPT = 0x55,
51 SCORPION_UNDEF = 0x56,
52 SCORPION_SVC = 0x57,
53 SCORPION_SMC = 0x58,
54 SCORPION_PREFETCH_ABORT = 0x59,
55 SCORPION_INDEX_CHECK = 0x5a,
56 SCORPION_NULL_CHECK = 0x5b,
57 SCORPION_EXPL_ICIALLU = 0x5c,
58 SCORPION_IMPL_ICIALLU = 0x5d,
59 SCORPION_NONICIALLU_BTAC_INV = 0x5e,
60 SCORPION_ICIMVAU_IMPL_ICIALLU = 0x5f,
61 SCORPION_SPIPE_ONLY_CYCLES = 0x60,
62 SCORPION_XPIPE_ONLY_CYCLES = 0x61,
63 SCORPION_DUAL_CYCLES = 0x62,
64 SCORPION_DISPATCH_ANY_CYCLES = 0x63,
65 SCORPION_FIFO_FULLBLK_CMT = 0x64,
66 SCORPION_FAIL_COND_INST = 0x65,
67 SCORPION_PASS_COND_INST = 0x66,
68 SCORPION_ALLOW_VU_CLK = 0x67,
69 SCORPION_VU_IDLE = 0x68,
70 SCORPION_ALLOW_L2_CLK = 0x69,
71 SCORPION_L2_IDLE = 0x6a,
72 SCORPION_DTLB_IMPL_INV_SCTLR_DACR = 0x6b,
73 SCORPION_DTLB_EXPL_INV = 0x6c,
74 SCORPION_DTLB_MISS = 0x6d,
75 SCORPION_DTLB_ACCESS = 0x6e,
76 SCORPION_ITLB_MISS = 0x6f,
77 SCORPION_ITLB_IMPL_INV = 0x70,
78 SCORPION_ITLB_EXPL_INV = 0x71,
79 SCORPION_UTLB_D_MISS = 0x72,
80 SCORPION_UTLB_D_ACCESS = 0x73,
81 SCORPION_UTLB_I_MISS = 0x74,
82 SCORPION_UTLB_I_ACCESS = 0x75,
83 SCORPION_UTLB_INV_ASID = 0x76,
84 SCORPION_UTLB_INV_MVA = 0x77,
85 SCORPION_UTLB_INV_ALL = 0x78,
86 SCORPION_S2_HOLD_RDQ_UNAVAIL = 0x79,
87 SCORPION_S2_HOLD = 0x7a,
88 SCORPION_S2_HOLD_DEV_OP = 0x7b,
89 SCORPION_S2_HOLD_ORDER = 0x7c,
90 SCORPION_S2_HOLD_BARRIER = 0x7d,
91 SCORPION_VIU_DUAL_CYCLE = 0x7e,
92 SCORPION_VIU_SINGLE_CYCLE = 0x7f,
93 SCORPION_VX_PIPE_WAR_STALL_CYCLES = 0x80,
94 SCORPION_VX_PIPE_WAW_STALL_CYCLES = 0x81,
95 SCORPION_VX_PIPE_RAW_STALL_CYCLES = 0x82,
96 SCORPION_VX_PIPE_LOAD_USE_STALL = 0x83,
97 SCORPION_VS_PIPE_WAR_STALL_CYCLES = 0x84,
98 SCORPION_VS_PIPE_WAW_STALL_CYCLES = 0x85,
99 SCORPION_VS_PIPE_RAW_STALL_CYCLES = 0x86,
100 SCORPION_EXCEPTIONS_INV_OPERATION = 0x87,
101 SCORPION_EXCEPTIONS_DIV_BY_ZERO = 0x88,
102 SCORPION_COND_INST_FAIL_VX_PIPE = 0x89,
103 SCORPION_COND_INST_FAIL_VS_PIPE = 0x8a,
104 SCORPION_EXCEPTIONS_OVERFLOW = 0x8b,
105 SCORPION_EXCEPTIONS_UNDERFLOW = 0x8c,
106 SCORPION_EXCEPTIONS_DENORM = 0x8d,
107#ifdef CONFIG_ARCH_MSM_SCORPIONMP
108 SCORPIONMP_NUM_BARRIERS = 0x8e,
109 SCORPIONMP_BARRIER_CYCLES = 0x8f,
110#else
111 SCORPION_BANK_AB_HIT = 0x8e,
112 SCORPION_BANK_AB_ACCESS = 0x8f,
113 SCORPION_BANK_CD_HIT = 0x90,
114 SCORPION_BANK_CD_ACCESS = 0x91,
115 SCORPION_BANK_AB_DSIDE_HIT = 0x92,
116 SCORPION_BANK_AB_DSIDE_ACCESS = 0x93,
117 SCORPION_BANK_CD_DSIDE_HIT = 0x94,
118 SCORPION_BANK_CD_DSIDE_ACCESS = 0x95,
119 SCORPION_BANK_AB_ISIDE_HIT = 0x96,
120 SCORPION_BANK_AB_ISIDE_ACCESS = 0x97,
121 SCORPION_BANK_CD_ISIDE_HIT = 0x98,
122 SCORPION_BANK_CD_ISIDE_ACCESS = 0x99,
123 SCORPION_ISIDE_RD_WAIT = 0x9a,
124 SCORPION_DSIDE_RD_WAIT = 0x9b,
125 SCORPION_BANK_BYPASS_WRITE = 0x9c,
126 SCORPION_BANK_AB_NON_CASTOUT = 0x9d,
127 SCORPION_BANK_AB_L2_CASTOUT = 0x9e,
128 SCORPION_BANK_CD_NON_CASTOUT = 0x9f,
129 SCORPION_BANK_CD_L2_CASTOUT = 0xa0,
130#endif
131 MSM_MAX_EVT
132};
133
134struct scorp_evt {
135 u32 evt_type;
136 u32 val;
137 u8 grp;
138 u32 evt_type_act;
139};
140
141static const struct scorp_evt sc_evt[] = {
142 {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d},
143 {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e},
144 {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f},
145 {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f},
146 {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f},
147 {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e},
148 {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c},
149 {SCORPION_IRQ, 0x80000a00, 0, 0x4d},
150 {SCORPION_FIQ, 0x800a0000, 0, 0x4e},
151 {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f},
152 {SCORPION_UNDEF, 0x8000000b, 0, 0x4c},
153 {SCORPION_SVC, 0x80000b00, 0, 0x4d},
154 {SCORPION_SMC, 0x800b0000, 0, 0x4e},
155 {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f},
156 {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c},
157 {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d},
158 {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c},
159 {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d},
160 {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e},
161 {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f},
162
163 {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51},
164 {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52},
165 {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53},
166 {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53},
167 {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50},
168 {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52},
169 {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53},
170 {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50},
171 {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51},
172 {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52},
173 {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53},
174
175 {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54},
176 {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55},
177 {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56},
178 {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57},
179 {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55},
180 {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56},
181 {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57},
182 {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54},
183 {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55},
184 {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56},
185 {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57},
186 {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55},
187 {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56},
188 {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57},
189 {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55},
190 {SCORPION_S2_HOLD, 0x88000000, 2, 0x57},
191 {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55},
192 {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56},
193 {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57},
194
195 {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c},
196 {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d},
197 {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c},
198 {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d},
199 {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e},
200 {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c},
201 {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c},
202 {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d},
203 {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e},
204 {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c},
205 {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d},
206 {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e},
207 {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f},
208 {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c},
209 {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d},
210 {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f},
211
212 {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58},
213 {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59},
214 {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a},
215 {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b},
216 {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58},
217 {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59},
218 {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a},
219 {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b},
220 {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58},
221 {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59},
222 {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a},
223 {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b},
224 {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58},
225 {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a},
226 {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58},
227 {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58},
228 {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59},
229 {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a},
230 {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b},
231};
232
233static inline void scorpion_pmnc_write(u32 val)
234{
235 val &= PMNC_MASK;
236 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
237}
238
239static inline u32 scorpion_pmnc_read(void)
240{
241 u32 val;
242 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
243 return val;
244}
245
246static inline u32 scorpion_ccnt_read(void)
247{
248 u32 val;
249 asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
250 return val;
251}
252
253static inline u32 scorpion_cntn_read(void)
254{
255 u32 val;
256 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
257 return val;
258}
259
260static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt)
261{
262 u32 val;
263
264 if (cnt >= CNTMAX) {
265 pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
266 return -1;
267 }
268
269 if (cnt == CCNT)
270 val = CCNT_REG;
271 else
272 val = (1 << (cnt - CNT0));
273
274 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
275
276 return cnt;
277}
278
279static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt)
280{
281 u32 val;
282
283 if (cnt >= CNTMAX) {
284 pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt);
285 return -1;
286 }
287
288 if (cnt == CCNT)
289 val = CCNT_REG;
290 else
291 val = (1 << (cnt - CNT0));
292
293 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
294
295 return cnt;
296}
297
298static inline int scorpion_pmnc_select_counter(unsigned int cnt)
299{
300 u32 val;
301
302 if ((cnt == CCNT) || (cnt >= CNTMAX)) {
303 pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt);
304 return -1;
305 }
306
307 val = (cnt - CNT0);
308 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
309
310 return cnt;
311}
312
313static u32 scorpion_read_lpm0(void)
314{
315 u32 val;
316 asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val));
317 return val;
318}
319
320static void scorpion_write_lpm0(u32 val)
321{
322 asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val));
323}
324
325static u32 scorpion_read_lpm1(void)
326{
327 u32 val;
328 asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val));
329 return val;
330}
331
332static void scorpion_write_lpm1(u32 val)
333{
334 asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val));
335}
336
337static u32 scorpion_read_lpm2(void)
338{
339 u32 val;
340 asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val));
341 return val;
342}
343
344static void scorpion_write_lpm2(u32 val)
345{
346 asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val));
347}
348
349static u32 scorpion_read_l2lpm(void)
350{
351 u32 val;
352 asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val));
353 return val;
354}
355
356static void scorpion_write_l2lpm(u32 val)
357{
358 asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val));
359}
360
361static u32 scorpion_read_vlpm(void)
362{
363 u32 val;
364 asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
365 return val;
366}
367
368static void scorpion_write_vlpm(u32 val)
369{
370 asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
371}
372
373struct scorpion_access_funcs {
374 u32 (*read) (void);
375 void (*write) (u32);
376};
377
378struct scorpion_access_funcs scor_func[] = {
379 {scorpion_read_lpm0, scorpion_write_lpm0},
380 {scorpion_read_lpm1, scorpion_write_lpm1},
381 {scorpion_read_lpm2, scorpion_write_lpm2},
382 {scorpion_read_l2lpm, scorpion_write_l2lpm},
383 {scorpion_read_vlpm, scorpion_write_vlpm},
384};
385
386u32 venum_orig_val;
387u32 fp_orig_val;
388
389static void scorpion_pre_vlpm(void)
390{
391 u32 venum_new_val;
392 u32 fp_new_val;
393
394 /* CPACR Enable CP10 access*/
395 asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val));
396 venum_new_val = venum_orig_val | 0x00300000;
397 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val));
398 /* Enable FPEXC */
399 asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val));
400 fp_new_val = fp_orig_val | 0x40000000;
401 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val));
402}
403
404static void scorpion_post_vlpm(void)
405{
406 /* Restore FPEXC*/
407 asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val));
408 /* Restore CPACR*/
409 asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val));
410}
411
412#define COLMN0MASK 0x000000ff
413#define COLMN1MASK 0x0000ff00
414#define COLMN2MASK 0x00ff0000
415static u32 scorpion_get_columnmask(u32 setval)
416{
417 if (setval & COLMN0MASK)
418 return 0xffffff00;
419 else if (setval & COLMN1MASK)
420 return 0xffff00ff;
421 else if (setval & COLMN2MASK)
422 return 0xff00ffff;
423 else
424 return 0x80ffffff;
425}
426
427static void scorpion_evt_setup(u32 gr, u32 setval)
428{
429 u32 val;
430 if (gr == 4)
431 scorpion_pre_vlpm();
432 val = scorpion_get_columnmask(setval) & scor_func[gr].read();
433 val = val | setval;
434 scor_func[gr].write(val);
435 if (gr == 4)
436 scorpion_post_vlpm();
437}
438
439static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo)
440{
441 u32 idx;
442 if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT))
443 return 0;
444 idx = evt_type - 0x4c;
445 if (sc_evt[idx].evt_type == evt_type) {
446 evtinfo->val = sc_evt[idx].val;
447 evtinfo->grp = sc_evt[idx].grp;
448 evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
449 return 1;
450 }
451 return 0;
452}
453
454static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val)
455{
456 if (scorpion_pmnc_select_counter(cnt) == cnt) {
457 if (val < 0x40) {
458 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
459 } else {
460 u32 zero = 0;
461 struct scorp_evt evtinfo;
462 // extract evtinfo.grp and evtinfo.tevt_type_act from val
463 if (get_scorpion_evtinfo(val, &evtinfo) == 0) return;
464 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act));
465 asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero));
466 scorpion_evt_setup(evtinfo.grp, val);
467 }
468 }
469}
470
471static void scorpion_pmnc_reset_counter(unsigned int cnt)
472{
473 u32 val = 0;
474
475 if (cnt == CCNT) {
476 scorpion_pmnc_disable_counter(cnt);
477
478 asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
479
480 if (pmnc_enabled[cnt] != 0)
481 scorpion_pmnc_enable_counter(cnt);
482
483 } else if (cnt >= CNTMAX) {
484 pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt);
485 } else {
486 scorpion_pmnc_disable_counter(cnt);
487
488 if (scorpion_pmnc_select_counter(cnt) == cnt)
489 asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
490
491 if (pmnc_enabled[cnt] != 0)
492 scorpion_pmnc_enable_counter(cnt);
493 }
494}
495
496static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root)
497{
498 struct dentry *dir;
499 int i;
500
501 for (i = 0; i < pmnc_count; i++) {
502 char buf[40];
503 if (i == 0) {
504 snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name);
505 } else {
506 snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i-1);
507 }
508 dir = gatorfs_mkdir(sb, root, buf);
509 if (!dir) {
510 return -1;
511 }
512 gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]);
513 if (i > 0) {
514 gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]);
515 }
516 gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]);
517 }
518
519 return 0;
520}
521
522static void gator_events_scorpion_online(void)
523{
524 unsigned int cnt;
525
526 if (scorpion_pmnc_read() & PMNC_E) {
527 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
528 }
529
530 /* Initialize & Reset PMNC: C bit and P bit */
531 scorpion_pmnc_write(PMNC_P | PMNC_C);
532
533 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
534 unsigned long event;
535
536 per_cpu(perfPrev, smp_processor_id())[cnt] = 0;
537
538 if (!pmnc_enabled[cnt])
539 continue;
540
541 // disable counter
542 scorpion_pmnc_disable_counter(cnt);
543
544 event = pmnc_event[cnt] & 255;
545
546 // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count
547 if (cnt != CCNT)
548 scorpion_pmnc_write_evtsel(cnt, event);
549
550 // reset counter
551 scorpion_pmnc_reset_counter(cnt);
552
553 // Enable counter, do not enable interrupt for this counter
554 scorpion_pmnc_enable_counter(cnt);
555 }
556
557 // enable
558 scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E);
559}
560
561static void gator_events_scorpion_offline(void)
562{
563 scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E);
564
565 // investigate: need to do the clearpmu() here on each counter?
566}
567
568static void gator_events_scorpion_stop(void)
569{
570 unsigned int cnt;
571
572 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
573 pmnc_enabled[cnt] = 0;
574 pmnc_event[cnt] = 0;
575 }
576}
577
578static int gator_events_scorpion_read(int **buffer)
579{
580 int cnt, len = 0;
581 int cpu = smp_processor_id();
582
583 if (!pmnc_count)
584 return 0;
585
586 for (cnt = 0; cnt < pmnc_count; cnt++) {
587 if (pmnc_enabled[cnt]) {
588 int value;
589 if (cnt == CCNT) {
590 value = scorpion_ccnt_read();
591 } else if (scorpion_pmnc_select_counter(cnt) == cnt) {
592 value = scorpion_cntn_read();
593 } else {
594 value = 0;
595 }
596 scorpion_pmnc_reset_counter(cnt);
597 if (value != per_cpu(perfPrev, cpu)[cnt]) {
598 per_cpu(perfPrev, cpu)[cnt] = value;
599 per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt];
600 per_cpu(perfCnt, cpu)[len++] = value;
601 }
602 }
603 }
604
605 // update or discard
606 if (buffer)
607 *buffer = per_cpu(perfCnt, cpu);
608
609 return len;
610}
611
612static struct gator_interface gator_events_scorpion_interface = {
613 .create_files = gator_events_scorpion_create_files,
614 .stop = gator_events_scorpion_stop,
615 .online = gator_events_scorpion_online,
616 .offline = gator_events_scorpion_offline,
617 .read = gator_events_scorpion_read,
618};
619
620
621static void scorpion_clear_pmuregs(void)
622{
623 scorpion_write_lpm0(0);
624 scorpion_write_lpm1(0);
625 scorpion_write_lpm2(0);
626 scorpion_write_l2lpm(0);
627 scorpion_pre_vlpm();
628 scorpion_write_vlpm(0);
629 scorpion_post_vlpm();
630}
631
632int gator_events_scorpion_init(void)
633{
634 unsigned int cnt;
635
636 switch (gator_cpuid()) {
637 case SCORPION:
638 pmnc_name = "Scorpion";
639 pmnc_count = 4;
640 break;
641 case SCORPIONMP:
642 pmnc_name = "ScorpionMP";
643 pmnc_count = 4;
644 break;
645 default:
646 return -1;
647 }
648
649 pmnc_count++; // CNT[n] + CCNT
650
651 for (cnt = CCNT; cnt < CNTMAX; cnt++) {
652 pmnc_enabled[cnt] = 0;
653 pmnc_event[cnt] = 0;
654 pmnc_key[cnt] = gator_events_get_key();
655 }
656
657 scorpion_clear_pmuregs();
658
659 return gator_events_install(&gator_events_scorpion_interface);
660}
661gator_events_init(gator_events_scorpion_init);
diff --git a/driver/gator_fs.c b/driver/gator_fs.c
new file mode 100644
index 0000000..8277c3a
--- /dev/null
+++ b/driver/gator_fs.c
@@ -0,0 +1,284 @@
1/**
2 * @file gatorfs.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon
8 *
9 * A simple filesystem for configuration and
10 * access of oprofile.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/pagemap.h>
17#include <asm/uaccess.h>
18
19#define gatorfs_MAGIC 0x24051020
20#define TMPBUFSIZE 50
21DEFINE_SPINLOCK(gatorfs_lock);
22
23static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
24{
25 struct inode *inode = new_inode(sb);
26
27 if (inode) {
28#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
29 inode->i_ino = get_next_ino();
30#endif
31 inode->i_mode = mode;
32 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
33 }
34 return inode;
35}
36
37static const struct super_operations s_ops = {
38 .statfs = simple_statfs,
39 .drop_inode = generic_delete_inode,
40};
41
42ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
43{
44 return simple_read_from_buffer(buf, count, offset, str, strlen(str));
45}
46
47ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
48{
49 char tmpbuf[TMPBUFSIZE];
50 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
51 if (maxlen > TMPBUFSIZE)
52 maxlen = TMPBUFSIZE;
53 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
54}
55
56int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
57{
58 char tmpbuf[TMPBUFSIZE];
59 unsigned long flags;
60
61 if (!count)
62 return 0;
63
64 if (count > TMPBUFSIZE - 1)
65 return -EINVAL;
66
67 memset(tmpbuf, 0x0, TMPBUFSIZE);
68
69 if (copy_from_user(tmpbuf, buf, count))
70 return -EFAULT;
71
72 spin_lock_irqsave(&gatorfs_lock, flags);
73 *val = simple_strtoul(tmpbuf, NULL, 0);
74 spin_unlock_irqrestore(&gatorfs_lock, flags);
75 return 0;
76}
77
78static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
79{
80 unsigned long *val = file->private_data;
81 return gatorfs_ulong_to_user(*val, buf, count, offset);
82}
83
84static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
85{
86 unsigned long *value = file->private_data;
87 int retval;
88
89 if (*offset)
90 return -EINVAL;
91
92 retval = gatorfs_ulong_from_user(value, buf, count);
93
94 if (retval)
95 return retval;
96 return count;
97}
98
99static int default_open(struct inode *inode, struct file *filp)
100{
101 if (inode->i_private)
102 filp->private_data = inode->i_private;
103 return 0;
104}
105
106static const struct file_operations ulong_fops = {
107 .read = ulong_read_file,
108 .write = ulong_write_file,
109 .open = default_open,
110};
111
112static const struct file_operations ulong_ro_fops = {
113 .read = ulong_read_file,
114 .open = default_open,
115};
116
117static struct dentry *__gatorfs_create_file(struct super_block *sb,
118 struct dentry *root, char const *name, const struct file_operations *fops,
119 int perm)
120{
121 struct dentry *dentry;
122 struct inode *inode;
123
124 dentry = d_alloc_name(root, name);
125 if (!dentry)
126 return NULL;
127 inode = gatorfs_get_inode(sb, S_IFREG | perm);
128 if (!inode) {
129 dput(dentry);
130 return NULL;
131 }
132 inode->i_fop = fops;
133 d_add(dentry, inode);
134 return dentry;
135}
136
137int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
138 char const *name, unsigned long *val)
139{
140 struct dentry *d = __gatorfs_create_file(sb, root, name,
141 &ulong_fops, 0644);
142 if (!d)
143 return -EFAULT;
144
145 d->d_inode->i_private = val;
146 return 0;
147}
148
149int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
150 char const *name, unsigned long *val)
151{
152 struct dentry *d = __gatorfs_create_file(sb, root, name,
153 &ulong_ro_fops, 0444);
154 if (!d)
155 return -EFAULT;
156
157 d->d_inode->i_private = val;
158 return 0;
159}
160
161static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
162{
163 atomic_t *val = file->private_data;
164 return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
165}
166
167static const struct file_operations atomic_ro_fops = {
168 .read = atomic_read_file,
169 .open = default_open,
170};
171
172int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root,
173 char const *name, atomic_t *val)
174{
175 struct dentry *d = __gatorfs_create_file(sb, root, name,
176 &atomic_ro_fops, 0444);
177 if (!d)
178