misc: tegra-profiler: support raw hardware events
[linux-3.10.git] / drivers / misc / tegra-profiler / pl310.c
1 /*
2  * drivers/misc/tegra-profiler/pl310.c
3  *
4  * Copyright (c) 2014-2017, 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_CACHE_L2X0
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20 #include <linux/module.h>
21 #include <linux/init.h>
22 #include <linux/io.h>
23 #include <asm/hardware/cache-l2x0.h>
24
25 #include <linux/tegra_profiler.h>
26
27 #include "quadd.h"
28 #include "pl310.h"
29 #include "debug.h"
30
31 DEFINE_PER_CPU(u32, pl310_prev_val);
32
33 static struct l2x0_context l2x0_ctx;
34
35 static void l2x0_enable_event_counters(u32 event0, u32 event1)
36 {
37         u32 reg_val;
38         void __iomem *base = l2x0_ctx.l2x0_base;
39
40         /* configure counter0 */
41         reg_val = event0;
42         writel_relaxed(reg_val, base + L2X0_EVENT_CNT0_CFG);
43
44         /* configure counter1 */
45         reg_val = event1;
46         writel_relaxed(reg_val, base + L2X0_EVENT_CNT1_CFG);
47
48         /* enable event counting */
49         reg_val = L2X0_EVENT_CNT_ENABLE;
50         writel_relaxed(reg_val, base + L2X0_EVENT_CNT_CTRL);
51 }
52
53 static void __maybe_unused l2x0_disable_event_counters(void)
54 {
55         u32 reg_val;
56         void __iomem *base = l2x0_ctx.l2x0_base;
57
58         /* disable event counting */
59         reg_val = 0;
60         writel_relaxed(reg_val, base + L2X0_EVENT_CNT_CTRL);
61 }
62
63 static void l2x0_stop_event_counters(void)
64 {
65         void __iomem *base = l2x0_ctx.l2x0_base;
66
67         writel_relaxed(0, base + L2X0_EVENT_CNT_CTRL);
68
69         writel_relaxed(0, base + L2X0_EVENT_CNT0_CFG);
70         writel_relaxed(0, base + L2X0_EVENT_CNT1_CFG);
71 }
72
73 static void l2x0_reset_event_counters(void)
74 {
75         u32 reg_val;
76         void __iomem *base = l2x0_ctx.l2x0_base;
77
78         reg_val = readl_relaxed(base + L2X0_EVENT_CNT_CTRL);
79         reg_val |= L2X0_EVENT_CNT_RESET_CNT0 | L2X0_EVENT_CNT_RESET_CNT1;
80         writel_relaxed(reg_val, base + L2X0_EVENT_CNT_CTRL);
81 }
82
83 static u32 l2x0_read_event_counter(enum quadd_l2x0_counter counter)
84 {
85         u32 reg_val = 0;
86         void __iomem *base = l2x0_ctx.l2x0_base;
87
88         switch (counter) {
89         case QUADD_L2X0_COUNTER0:
90                 reg_val = readl_relaxed(base + L2X0_EVENT_CNT0_VAL);
91                 break;
92         case QUADD_L2X0_COUNTER1:
93                 reg_val = readl_relaxed(base + L2X0_EVENT_CNT1_VAL);
94                 break;
95         }
96
97         return reg_val;
98 }
99
100 static void l2x0_enable_perf_event(enum quadd_l2x0_event_type type)
101 {
102         l2x0_reset_event_counters();
103
104         switch (type) {
105         case QUADD_L2X0_TYPE_DATA_READ_MISSES:
106                 l2x0_enable_event_counters(L2X0_EVENT_CNT_CFG_DRREQ,
107                                            L2X0_EVENT_CNT_CFG_DRHIT);
108                 break;
109         case QUADD_L2X0_TYPE_DATA_WRITE_MISSES:
110                 l2x0_enable_event_counters(L2X0_EVENT_CNT_CFG_DWREQ,
111                                            L2X0_EVENT_CNT_CFG_DWHIT);
112                 break;
113         case QUADD_L2X0_TYPE_INSTRUCTION_MISSES:
114                 l2x0_enable_event_counters(L2X0_EVENT_CNT_CFG_IRREQ,
115                                            L2X0_EVENT_CNT_CFG_IRHIT);
116                 break;
117         }
118 }
119
120 static u32 l2x0_read_perf_event(void)
121 {
122         u32 count_req, count_hit, count_miss;
123
124         count_req = l2x0_read_event_counter(QUADD_L2X0_COUNTER0);
125         count_hit = l2x0_read_event_counter(QUADD_L2X0_COUNTER1);
126
127         count_miss = count_req - count_hit;
128         if (count_req < count_hit)
129                 return 0;
130
131         return count_miss;
132 }
133
134 static void l2x0_clear_values(void)
135 {
136         int cpu_id;
137
138         for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++)
139                 per_cpu(pl310_prev_val, cpu_id) = 0;
140 }
141
142 static int __maybe_unused l2x0_events_enable(void)
143 {
144         return 0;
145 }
146
147 static void __maybe_unused l2x0_events_disable(void)
148 {
149 }
150
151 static void __maybe_unused l2x0_events_start(void)
152 {
153         unsigned long flags;
154
155         if (l2x0_ctx.l2x0_event_type < 0)
156                 return;
157
158         spin_lock_irqsave(&l2x0_ctx.lock, flags);
159         l2x0_clear_values();
160         l2x0_enable_perf_event(l2x0_ctx.l2x0_event_type);
161         spin_unlock_irqrestore(&l2x0_ctx.lock, flags);
162
163         qm_debug_start_source(QUADD_EVENT_SOURCE_PL310);
164 }
165
166 static void __maybe_unused l2x0_events_stop(void)
167 {
168         unsigned long flags;
169
170         if (l2x0_ctx.l2x0_event_type < 0)
171                 return;
172
173         spin_lock_irqsave(&l2x0_ctx.lock, flags);
174         l2x0_stop_event_counters();
175         l2x0_clear_values();
176         spin_unlock_irqrestore(&l2x0_ctx.lock, flags);
177
178         qm_debug_stop_source(QUADD_EVENT_SOURCE_PL310);
179 }
180
181 static int __maybe_unused
182 l2x0_events_read(struct event_data *events, int max_events)
183 {
184         unsigned long flags;
185
186         if (l2x0_ctx.l2x0_event_type < 0)
187                 return 0;
188
189         if (max_events == 0)
190                 return 0;
191
192         events[0].event_source = QUADD_EVENT_SOURCE_PL310;
193         events[0].event_id = l2x0_ctx.event_id;
194
195         spin_lock_irqsave(&l2x0_ctx.lock, flags);
196         events[0].val = l2x0_read_perf_event();
197         spin_unlock_irqrestore(&l2x0_ctx.lock, flags);
198
199         events[0].prev_val = __get_cpu_var(pl310_prev_val);
200
201         __get_cpu_var(pl310_prev_val) = events[0].val;
202
203         qm_debug_read_counter(l2x0_ctx.event_id, events[0].prev_val,
204                               events[0].val);
205
206         return 1;
207 }
208
209 static int __maybe_unused
210 l2x0_events_read_emulate(int cpuid, struct event_data *events, int max_events)
211 {
212         static u32 val;
213
214         if (max_events == 0)
215                 return 0;
216
217         if (val > 100)
218                 val = 0;
219
220         events[0].event_source = QUADD_EVENT_SOURCE_PL310;
221         events[0].event_id = QUADD_L2X0_TYPE_DATA_READ_MISSES;
222
223         events[0].val = val;
224         events[0].prev_val = __get_cpu_var(pl310_prev_val);
225
226         __get_cpu_var(pl310_prev_val) = val;
227
228         val += 10;
229
230         return 1;
231 }
232
233 static int __maybe_unused
234 l2x0_set_events(int cpuid, struct quadd_event *events, int size)
235 {
236         unsigned int id, type;
237
238         if (!events || size == 0) {
239                 l2x0_ctx.l2x0_event_type = -1;
240                 l2x0_ctx.event_id = -1;
241                 return 0;
242         }
243
244         if (size != 1) {
245                 pr_err("Error: number of events more than one\n");
246                 return -ENOSPC;
247         }
248
249         type = events->type;
250         id = events->id;
251
252         if (type != QUADD_EVENT_TYPE_HARDWARE)
253                 return -EINVAL;
254
255         switch (id) {
256         case QUADD_EVENT_HW_L2_DCACHE_READ_MISSES:
257                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_DATA_READ_MISSES;
258                 break;
259         case QUADD_EVENT_HW_L2_DCACHE_WRITE_MISSES:
260                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_DATA_WRITE_MISSES;
261                 break;
262         case QUADD_EVENT_HW_L2_ICACHE_MISSES:
263                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_INSTRUCTION_MISSES;
264                 break;
265         default:
266                 pr_err("Error event: %s\n", quadd_get_hw_event_str(*events));
267                 return 1;
268         }
269         l2x0_ctx.event_id = *events;
270
271         pr_info("Event has been added: id/l2x0: %s/%#x\n",
272                 quadd_get_hw_event_str(id), l2x0_ctx.l2x0_event_type);
273         return 0;
274 }
275
276 static int
277 get_supported_events(int cpuid, int *events,
278                      int max_events, unsigned int *raw_event_mask)
279 {
280         if (max_events < 3)
281                 return 0;
282
283         events[0].type = QUADD_EVENT_TYPE_HARDWARE;
284         events[0].id = QUADD_EVENT_HW_L2_DCACHE_READ_MISSES;
285
286         events[1].type = QUADD_EVENT_TYPE_HARDWARE;
287         events[1].id = QUADD_EVENT_HW_L2_DCACHE_WRITE_MISSES;
288
289         events[2].type = QUADD_EVENT_TYPE_HARDWARE;
290         events[2].id = QUADD_EVENT_HW_L2_ICACHE_MISSES;
291
292         *raw_event_mask = 0;
293
294         return 3;
295 }
296
297 static int get_current_events(int cpuid, int *events, int max_events)
298 {
299         if (max_events == 0)
300                 return 0;
301
302         *events = l2x0_ctx.event_id;
303
304         return 1;
305 }
306
307 static struct quadd_event_source_interface l2x0_int = {
308         .enable                 = l2x0_events_enable,
309         .disable                = l2x0_events_disable,
310
311         .start                  = l2x0_events_start,
312         .stop                   = l2x0_events_stop,
313
314 #ifndef QUADD_USE_EMULATE_COUNTERS
315         .read                   = l2x0_events_read,
316 #else
317         .read                   = l2x0_events_read_emulate,
318 #endif
319         .set_events             = l2x0_set_events,
320         .get_supported_events   = get_supported_events,
321         .get_current_events     = get_current_events,
322 };
323
324 struct quadd_event_source_interface *quadd_l2x0_events_init(void)
325 {
326         void __iomem *base;
327         unsigned long phys_addr;
328
329         l2x0_ctx.l2x0_event_type = -1;
330         l2x0_ctx.event_id = -1;
331
332         l2x0_ctx.l2x0_base = NULL;
333
334         phys_addr = quadd_get_pl310_phys_addr();
335         if (!phys_addr)
336                 return NULL;
337
338         base = ioremap(phys_addr, SZ_4K);
339         if (base) {
340                 u32 cache_id = readl(base + L2X0_CACHE_ID);
341
342                 if ((cache_id & 0xff0003c0) != 0x410000c0) {
343                         iounmap(base);
344                         return NULL;
345                 }
346         }
347
348         if (!base)
349                 return NULL;
350
351         l2x0_ctx.l2x0_base = base;
352
353         l2x0_clear_values();
354         spin_lock_init(&l2x0_ctx.lock);
355
356         pr_debug("pl310 init success, l2x0_base: %p\n", base);
357         return &l2x0_int;
358 }
359 #endif /* CONFIG_CACHE_L2X0 */