0172bb1de7e0a808febe7cfa3500723cf3d88e28
[linux-3.10.git] / drivers / misc / tegra-profiler / pl310.c
1 /*
2  * drivers/misc/tegra-profiler/pl310.c
3  *
4  * Copyright (c) 2014-2015, 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 l2x0_set_events(int cpuid, int *events, int size)
234 {
235         if (!events || size == 0) {
236                 l2x0_ctx.l2x0_event_type = -1;
237                 l2x0_ctx.event_id = -1;
238                 return 0;
239         }
240
241         if (size != 1) {
242                 pr_err("Error: number of events more than one\n");
243                 return -ENOSPC;
244         }
245
246         switch (*events) {
247         case QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES:
248                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_DATA_READ_MISSES;
249                 break;
250         case QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES:
251                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_DATA_WRITE_MISSES;
252                 break;
253         case QUADD_EVENT_TYPE_L2_ICACHE_MISSES:
254                 l2x0_ctx.l2x0_event_type = QUADD_L2X0_TYPE_INSTRUCTION_MISSES;
255                 break;
256         default:
257                 pr_err("Error event: %s\n", quadd_get_event_str(*events));
258                 return 1;
259         }
260         l2x0_ctx.event_id = *events;
261
262         pr_info("Event has been added: id/l2x0: %s/%#x\n",
263                 quadd_get_event_str(*events), l2x0_ctx.l2x0_event_type);
264         return 0;
265 }
266
267 static int get_supported_events(int cpuid, int *events, int max_events)
268 {
269         if (max_events < 3)
270                 return 0;
271
272         events[0] = QUADD_EVENT_TYPE_L2_DCACHE_READ_MISSES;
273         events[1] = QUADD_EVENT_TYPE_L2_DCACHE_WRITE_MISSES;
274         events[2] = QUADD_EVENT_TYPE_L2_ICACHE_MISSES;
275
276         return 3;
277 }
278
279 static int get_current_events(int cpuid, int *events, int max_events)
280 {
281         if (max_events == 0)
282                 return 0;
283
284         *events = l2x0_ctx.event_id;
285
286         return 1;
287 }
288
289 static struct quadd_event_source_interface l2x0_int = {
290         .enable                 = l2x0_events_enable,
291         .disable                = l2x0_events_disable,
292
293         .start                  = l2x0_events_start,
294         .stop                   = l2x0_events_stop,
295
296 #ifndef QUADD_USE_EMULATE_COUNTERS
297         .read                   = l2x0_events_read,
298 #else
299         .read                   = l2x0_events_read_emulate,
300 #endif
301         .set_events             = l2x0_set_events,
302         .get_supported_events   = get_supported_events,
303         .get_current_events     = get_current_events,
304 };
305
306 struct quadd_event_source_interface *quadd_l2x0_events_init(void)
307 {
308         void __iomem *base;
309         unsigned long phys_addr;
310
311         l2x0_ctx.l2x0_event_type = -1;
312         l2x0_ctx.event_id = -1;
313
314         l2x0_ctx.l2x0_base = NULL;
315
316         phys_addr = quadd_get_pl310_phys_addr();
317         if (!phys_addr)
318                 return NULL;
319
320         base = ioremap(phys_addr, SZ_4K);
321         if (base) {
322                 u32 cache_id = readl(base + L2X0_CACHE_ID);
323
324                 if ((cache_id & 0xff0003c0) != 0x410000c0) {
325                         iounmap(base);
326                         return NULL;
327                 }
328         }
329
330         if (!base)
331                 return NULL;
332
333         l2x0_ctx.l2x0_base = base;
334
335         l2x0_clear_values();
336         spin_lock_init(&l2x0_ctx.lock);
337
338         pr_debug("pl310 init success, l2x0_base: %p\n", base);
339         return &l2x0_int;
340 }
341 #endif /* CONFIG_CACHE_L2X0 */