bf9e3395b0d9a768da682f885ba22259f476ce3a
[linux-3.10.git] / drivers / misc / tegra-profiler / quadd_proc.c
1 /*
2  * drivers/misc/tegra-profiler/quadd_proc.c
3  *
4  * Copyright (c) 2014-2016, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #ifdef CONFIG_PROC_FS
18
19 #include <linux/proc_fs.h>
20 #include <linux/seq_file.h>
21
22 #include <linux/tegra_profiler.h>
23
24 #include "quadd.h"
25 #include "version.h"
26 #include "quadd_proc.h"
27 #include "arm_pmu.h"
28
29 #define YES_NO(x) ((x) ? "yes" : "no")
30
31 static struct quadd_ctx *ctx;
32
33 #define QUADD_PROC_DEV QUADD_DEVICE_NAME
34
35 static int show_version(struct seq_file *f, void *offset)
36 {
37         seq_printf(f, "version:         %s\n", QUADD_MODULE_VERSION);
38         seq_printf(f, "branch:          %s\n", QUADD_MODULE_BRANCH);
39         seq_printf(f, "samples version: %d\n", QUADD_SAMPLES_VERSION);
40         seq_printf(f, "io version:      %d\n", QUADD_IO_VERSION);
41
42         return 0;
43 }
44
45 static int show_version_proc_open(struct inode *inode, struct file *file)
46 {
47         return single_open(file, show_version, NULL);
48 }
49
50 static const struct file_operations version_proc_fops = {
51         .open           = show_version_proc_open,
52         .read           = seq_read,
53         .llseek         = seq_lseek,
54         .release        = single_release,
55 };
56
57 static int show_capabilities(struct seq_file *f, void *offset)
58 {
59         int cpuid;
60         struct quadd_comm_cap *cap = &ctx->cap;
61         unsigned int extra = cap->reserved[QUADD_COMM_CAP_IDX_EXTRA];
62         struct quadd_arch_info *arch = NULL;
63
64         seq_printf(f, "pmu:                                   %s\n",
65                    YES_NO(cap->pmu));
66         seq_printf(f, "tegra 3 LP cluster:                    %s\n",
67                    YES_NO(cap->tegra_lp_cluster));
68         seq_printf(f, "power rate samples:                    %s\n",
69                    YES_NO(cap->power_rate));
70
71         seq_printf(f, "support polling mode:                  %s\n",
72                    YES_NO(cap->blocked_read));
73         seq_printf(f, "backtrace from the kernel ctx:         %s\n",
74                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_BT_KERNEL_CTX));
75         seq_printf(f, "send mmap regions at the start:        %s\n",
76                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_GET_MMAP));
77         seq_printf(f, "group samples:                         %s\n",
78                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_GROUP_SAMPLES));
79         seq_printf(f, "unwinding based on ex-handling tables: %s\n",
80                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_BT_UNWIND_TABLES));
81         seq_printf(f, "support AArch64 architecture:          %s\n",
82                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_SUPPORT_AARCH64));
83         seq_printf(f, "support special architecture mappings: %s\n",
84                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_SPECIAL_ARCH_MMAP));
85         seq_printf(f, "support mixed unwinding mode:          %s\n",
86                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNWIND_MIXED));
87         seq_printf(f, "information about unwind entry:        %s\n",
88                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE));
89         seq_printf(f, "arch timer is available:               %s\n",
90                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_ARCH_TIMER));
91         seq_printf(f, "ring buffer mmap operation:            %s\n",
92                    YES_NO(extra & QUADD_COMM_CAP_EXTRA_RB_MMAP_OP));
93
94         seq_puts(f, "\n");
95
96         if (ctx->pmu) {
97                 for_each_possible_cpu(cpuid) {
98                         struct quadd_comm_cap_for_cpu *cpu_cap;
99                         struct quadd_events_cap *event;
100
101                         arch = ctx->pmu->get_arch(cpuid);
102                         if (!arch)
103                                 continue;
104
105                         cpu_cap = ctx->get_capabilities_for_cpu(cpuid);
106                         event = &cpu_cap->events_cap;
107
108                         seq_printf(f, "\nCPU %d\n", cpuid);
109
110                         seq_printf(f, "pmu arch:                  %s\n",
111                                            arch->name);
112                         seq_printf(f, "pmu arch version:          %d\n",
113                                            arch->ver);
114
115                         seq_printf(f, "l2 cache:                  %s\n",
116                                    YES_NO(cpu_cap->l2_cache));
117                         if (cap->l2_cache) {
118                                 seq_printf(f, "multiple l2 events:        %s\n",
119                                            YES_NO(cpu_cap->l2_multiple_events));
120                         }
121
122                         seq_puts(f, "  Supported events:\n");
123                         seq_printf(f, "  cpu_cycles:                     %s\n",
124                                    YES_NO(event->cpu_cycles));
125                         seq_printf(f, "  instructions:                   %s\n",
126                                    YES_NO(event->instructions));
127                         seq_printf(f, "  branch_instructions:            %s\n",
128                                    YES_NO(event->branch_instructions));
129                         seq_printf(f, "  branch_misses:                  %s\n",
130                                    YES_NO(event->branch_misses));
131                         seq_printf(f, "  bus_cycles:                     %s\n",
132                                    YES_NO(event->bus_cycles));
133                         seq_printf(f, "  l1_dcache_read_misses:          %s\n",
134                                    YES_NO(event->l1_dcache_read_misses));
135                         seq_printf(f, "  l1_dcache_write_misses:         %s\n",
136                                    YES_NO(event->l1_dcache_write_misses));
137                         seq_printf(f, "  l1_icache_misses:               %s\n",
138                                    YES_NO(event->l1_icache_misses));
139                         seq_printf(f, "  l2_dcache_read_misses:          %s\n",
140                                    YES_NO(event->l2_dcache_read_misses));
141                         seq_printf(f, "  l2_dcache_write_misses:         %s\n",
142                                    YES_NO(event->l2_dcache_write_misses));
143                         seq_printf(f, "  l2_icache_misses:               %s\n",
144                                    YES_NO(event->l2_icache_misses));
145                 }
146         }
147
148         return 0;
149 }
150
151 static int show_capabilities_proc_open(struct inode *inode, struct file *file)
152 {
153         return single_open(file, show_capabilities, NULL);
154 }
155
156 static const struct file_operations capabilities_proc_fops = {
157         .open           = show_capabilities_proc_open,
158         .read           = seq_read,
159         .llseek         = seq_lseek,
160         .release        = single_release,
161 };
162
163 static int show_status(struct seq_file *f, void *offset)
164 {
165         unsigned int status;
166         unsigned int is_auth_open, active;
167         struct quadd_module_state s;
168
169         quadd_get_state(&s);
170         status = s.reserved[QUADD_MOD_STATE_IDX_STATUS];
171
172         active = status & QUADD_MOD_STATE_STATUS_IS_ACTIVE;
173         is_auth_open = status & QUADD_MOD_STATE_STATUS_IS_AUTH_OPEN;
174
175         seq_printf(f, "status:          %s\n", active ? "active" : "waiting");
176         seq_printf(f, "auth:            %s\n", YES_NO(is_auth_open));
177         seq_printf(f, "all samples:     %llu\n", s.nr_all_samples);
178         seq_printf(f, "skipped samples: %llu\n", s.nr_skipped_samples);
179
180         return 0;
181 }
182
183 static int show_status_proc_open(struct inode *inode, struct file *file)
184 {
185         return single_open(file, show_status, NULL);
186 }
187
188 static const struct file_operations status_proc_fops = {
189         .open           = show_status_proc_open,
190         .read           = seq_read,
191         .llseek         = seq_lseek,
192         .release        = single_release,
193 };
194
195 void quadd_proc_init(struct quadd_ctx *context)
196 {
197         ctx = context;
198
199         proc_mkdir(QUADD_PROC_DEV, NULL);
200
201         proc_create(QUADD_PROC_DEV "/version", 0, NULL, &version_proc_fops);
202         proc_create(QUADD_PROC_DEV "/capabilities", 0, NULL,
203                     &capabilities_proc_fops);
204         proc_create(QUADD_PROC_DEV "/status", 0, NULL, &status_proc_fops);
205 }
206
207 void quadd_proc_deinit(void)
208 {
209         remove_proc_entry(QUADD_PROC_DEV "/version", NULL);
210         remove_proc_entry(QUADD_PROC_DEV "/capabilities", NULL);
211         remove_proc_entry(QUADD_PROC_DEV "/status", NULL);
212         remove_proc_entry(QUADD_PROC_DEV, NULL);
213 }
214
215 #endif  /* CONFIG_PROC_FS */