Merge remote-tracking branch 'lsk/v3.10/topic/gicv3' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / gator / gator_trace_gpu.c
1 /**
2  * Copyright (C) ARM Limited 2010-2014. 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 #include <linux/slab.h>
12 #include <linux/module.h>
13 #include <linux/time.h>
14 #include <linux/math64.h>
15
16 #ifdef MALI_SUPPORT
17 #ifdef MALI_DIR_MIDGARD
18 /* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
19 #include "mali_linux_trace.h"
20 #else
21 /* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
22 #include "linux/mali_linux_trace.h"
23 #endif
24 #endif
25
26 /*
27  * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK.
28  */
29 #define EVENT_TYPE_SINGLE  0
30 #define EVENT_TYPE_START   1
31 #define EVENT_TYPE_STOP    2
32 #define EVENT_TYPE_SUSPEND 3
33 #define EVENT_TYPE_RESUME  4
34
35 /* Note whether tracepoints have been registered */
36 static int mali_timeline_trace_registered;
37 static int mali_job_slots_trace_registered;
38
39 enum {
40         GPU_UNIT_NONE = 0,
41         GPU_UNIT_VP,
42         GPU_UNIT_FP,
43         GPU_UNIT_CL,
44         NUMBER_OF_GPU_UNITS
45 };
46
47 #if defined(MALI_SUPPORT)
48
49 struct mali_activity {
50         int core;
51         int key;
52         int count;
53         int last_activity;
54         int last_pid;
55 };
56
57 #define NUMBER_OF_GPU_CORES 16
58 static struct mali_activity mali_activities[NUMBER_OF_GPU_UNITS*NUMBER_OF_GPU_CORES];
59 static DEFINE_SPINLOCK(mali_activities_lock);
60
61 /* Only one event should be running on a unit and core at a time (ie, a start
62  * event can only be followed by a stop and vice versa), but because the kernel
63  * only knows when a job is enqueued and not started, it is possible for a
64  * start1, start2, stop1, stop2. Change it back into start1, stop1, start2,
65  * stop2 by queueing up start2 and releasing it when stop1 is received.
66  */
67
68 static int mali_activity_index(int core, int key)
69 {
70         int i;
71
72         for (i = 0; i < ARRAY_SIZE(mali_activities); ++i) {
73                 if ((mali_activities[i].core == core) && (mali_activities[i].key == key)) {
74                         break;
75                 }
76                 if ((mali_activities[i].core == 0) && (mali_activities[i].key == 0)) {
77                         mali_activities[i].core = core;
78                         mali_activities[i].key = key;
79                         break;
80                 }
81         }
82         BUG_ON(i >= ARRAY_SIZE(mali_activities));
83
84         return i;
85 }
86
87 static void mali_activity_enqueue(int core, int key, int activity, int pid)
88 {
89         int i;
90         int count;
91
92         spin_lock(&mali_activities_lock);
93         i = mali_activity_index(core, key);
94
95         count = mali_activities[i].count;
96         BUG_ON(count < 0);
97         ++mali_activities[i].count;
98         if (count) {
99                 mali_activities[i].last_activity = activity;
100                 mali_activities[i].last_pid = pid;
101         }
102         spin_unlock(&mali_activities_lock);
103
104         if (!count) {
105                 gator_marshal_activity_switch(core, key, activity, pid);
106         }
107 }
108
109 static void mali_activity_stop(int core, int key)
110 {
111         int i;
112         int count;
113         int last_activity = 0;
114         int last_pid = 0;
115
116         spin_lock(&mali_activities_lock);
117         i = mali_activity_index(core, key);
118
119         if (mali_activities[i].count == 0) {
120                 spin_unlock(&mali_activities_lock);
121                 return;
122         }
123         --mali_activities[i].count;
124         count = mali_activities[i].count;
125         if (count) {
126                 last_activity = mali_activities[i].last_activity;
127                 last_pid = mali_activities[i].last_pid;
128         }
129         spin_unlock(&mali_activities_lock);
130
131         gator_marshal_activity_switch(core, key, 0, 0);
132         if (count) {
133                 gator_marshal_activity_switch(core, key, last_activity, last_pid);
134         }
135 }
136
137 void mali_activity_clear(mali_counter mali_activity[], size_t mali_activity_size)
138 {
139         int activity;
140         int cores;
141         int core;
142
143         for (activity = 0; activity < mali_activity_size; ++activity) {
144                 cores = mali_activity[activity].cores;
145                 if (cores < 0) {
146                         cores = 1;
147                 }
148                 for (core = 0; core < cores; ++core) {
149                         if (mali_activity[activity].enabled) {
150                                 gator_marshal_activity_switch(core, mali_activity[activity].key, 0, 0);
151                         }
152                 }
153         }
154 }
155
156 #endif
157
158 #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
159 #include "gator_events_mali_4xx.h"
160
161 /*
162  * Taken from MALI_PROFILING_EVENT_CHANNEL_* in Mali DDK.
163  */
164 enum {
165         EVENT_CHANNEL_SOFTWARE = 0,
166         EVENT_CHANNEL_VP0 = 1,
167         EVENT_CHANNEL_FP0 = 5,
168         EVENT_CHANNEL_FP1,
169         EVENT_CHANNEL_FP2,
170         EVENT_CHANNEL_FP3,
171         EVENT_CHANNEL_FP4,
172         EVENT_CHANNEL_FP5,
173         EVENT_CHANNEL_FP6,
174         EVENT_CHANNEL_FP7,
175         EVENT_CHANNEL_GPU = 21
176 };
177
178 /**
179  * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel
180  */
181 enum {
182         EVENT_REASON_SINGLE_GPU_NONE = 0,
183         EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1,
184 };
185
186 mali_counter mali_activity[2];
187
188 GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4))
189 {
190         unsigned int component, state;
191
192         // do as much work as possible before disabling interrupts
193         component = (event_id >> 16) & 0xFF;    // component is an 8-bit field
194         state = (event_id >> 24) & 0xF; // state is a 4-bit field
195
196         switch (state) {
197         case EVENT_TYPE_START:
198                 if (component == EVENT_CHANNEL_VP0) {
199                         /* tgid = d0; pid = d1; */
200                         if (mali_activity[1].enabled) {
201                                 mali_activity_enqueue(0, mali_activity[1].key, 1, d1);
202                         }
203                 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
204                         /* tgid = d0; pid = d1; */
205                         if (mali_activity[0].enabled) {
206                                 mali_activity_enqueue(component - EVENT_CHANNEL_FP0, mali_activity[0].key, 1, d1);
207                         }
208                 }
209                 break;
210
211         case EVENT_TYPE_STOP:
212                 if (component == EVENT_CHANNEL_VP0) {
213                         if (mali_activity[1].enabled) {
214                                 mali_activity_stop(0, mali_activity[1].key);
215                         }
216                 } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) {
217                         if (mali_activity[0].enabled) {
218                                 mali_activity_stop(component - EVENT_CHANNEL_FP0, mali_activity[0].key);
219                         }
220                 }
221                 break;
222
223         case EVENT_TYPE_SINGLE:
224                 if (component == EVENT_CHANNEL_GPU) {
225                         unsigned int reason = (event_id & 0xffff);
226
227                         if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) {
228                                 gator_events_mali_log_dvfs_event(d0, d1);
229                         }
230                 }
231                 break;
232
233         default:
234                 break;
235         }
236 }
237 #endif
238
239 #if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
240
241 mali_counter mali_activity[3];
242
243 #if defined(MALI_JOB_SLOTS_EVENT_CHANGED)
244 GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id))
245 #else
246 GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid))
247 #endif
248 {
249         unsigned int component, state, unit;
250 #if !defined(MALI_JOB_SLOTS_EVENT_CHANGED)
251         unsigned char job_id = 0;
252 #endif
253
254         component = (event_id >> 16) & 0xFF;    // component is an 8-bit field
255         state = (event_id >> 24) & 0xF; // state is a 4-bit field
256
257         switch (component) {
258         case 0:
259                 unit = GPU_UNIT_FP;
260                 break;
261         case 1:
262                 unit = GPU_UNIT_VP;
263                 break;
264         case 2:
265                 unit = GPU_UNIT_CL;
266                 break;
267         default:
268                 unit = GPU_UNIT_NONE;
269         }
270
271         if (unit != GPU_UNIT_NONE) {
272                 switch (state) {
273                 case EVENT_TYPE_START:
274                         if (mali_activity[component].enabled) {
275                                 mali_activity_enqueue(0, mali_activity[component].key, 1, (pid != 0 ? pid : tgid));
276                         }
277                         break;
278                 case EVENT_TYPE_STOP:
279                 default: // Some jobs can be soft-stopped, so ensure that this terminates the activity trace.
280                         if (mali_activity[component].enabled) {
281                                 mali_activity_stop(0, mali_activity[component].key);
282                         }
283                         break;
284                 }
285         }
286 }
287 #endif
288
289 static int gator_trace_gpu_start(void)
290 {
291         /*
292          * Returns nonzero for installation failed
293          * Absence of gpu trace points is not an error
294          */
295
296 #if defined(MALI_SUPPORT)
297         memset(&mali_activities, 0, sizeof(mali_activities));
298 #endif
299         mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
300
301 #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
302         mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
303         if (!GATOR_REGISTER_TRACE(mali_timeline_event)) {
304                 mali_timeline_trace_registered = 1;
305         }
306 #endif
307
308 #if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
309         mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity));
310         if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) {
311                 mali_job_slots_trace_registered = 1;
312         }
313 #endif
314
315         return 0;
316 }
317
318 static void gator_trace_gpu_stop(void)
319 {
320 #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx)
321         if (mali_timeline_trace_registered) {
322                 GATOR_UNREGISTER_TRACE(mali_timeline_event);
323         }
324 #endif
325
326 #if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx)
327         if (mali_job_slots_trace_registered) {
328                 GATOR_UNREGISTER_TRACE(mali_job_slots_event);
329         }
330 #endif
331
332         mali_timeline_trace_registered = mali_job_slots_trace_registered = 0;
333 }