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