ARM: tizen_odroid_defconfig: Change the default cpufreq governor
[platform/kernel/linux-exynos.git] / drivers / gator / gator_events_mali_midgard.c
1 /**
2  * Copyright (C) ARM Limited 2011-2016. 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
10 #include "gator.h"
11
12 #include <linux/module.h>
13 #include <linux/time.h>
14 #include <linux/math64.h>
15 #include <linux/slab.h>
16 #include <linux/io.h>
17
18 #ifdef MALI_DIR_MIDGARD
19 /* New DDK Directory structure with kernel/drivers/gpu/arm/midgard*/
20 #include "mali_linux_trace.h"
21 #else
22 /* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx*/
23 #include "linux/mali_linux_trace.h"
24 #endif
25
26 #include "gator_events_mali_common.h"
27
28 /*
29  * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
30  */
31 #if (MALI_SUPPORT != MALI_MIDGARD)
32 #error MALI_SUPPORT set to an invalid device code: expecting MALI_MIDGARD
33 #endif
34
35 static const char mali_name[] = "Midgard";
36
37 /* Counters for Mali-Midgard:
38  *
39  *  - Timeline events
40  *    They are tracepoints, but instead of reporting a number they report a START/STOP event.
41  *    They are reported in Streamline as number of microseconds while that particular counter was active.
42  *
43  *  - SW counters
44  *    They are tracepoints reporting a particular number.
45  *    They are accumulated in sw_counter_data array until they are passed to Streamline, then they are zeroed.
46  *
47  *  - Accumulators
48  *    They are the same as software counters but their value is not zeroed.
49  */
50
51 /* Timeline (start/stop) activity */
52 static const char *const timeline_event_names[] = {
53         "PM_SHADER_0",
54         "PM_SHADER_1",
55         "PM_SHADER_2",
56         "PM_SHADER_3",
57         "PM_SHADER_4",
58         "PM_SHADER_5",
59         "PM_SHADER_6",
60         "PM_SHADER_7",
61         "PM_TILER_0",
62         "PM_L2_0",
63         "PM_L2_1",
64         "MMU_AS_0",
65         "MMU_AS_1",
66         "MMU_AS_2",
67         "MMU_AS_3"
68 };
69
70 enum {
71         PM_SHADER_0 = 0,
72         PM_SHADER_1,
73         PM_SHADER_2,
74         PM_SHADER_3,
75         PM_SHADER_4,
76         PM_SHADER_5,
77         PM_SHADER_6,
78         PM_SHADER_7,
79         PM_TILER_0,
80         PM_L2_0,
81         PM_L2_1,
82         MMU_AS_0,
83         MMU_AS_1,
84         MMU_AS_2,
85         MMU_AS_3
86 };
87 /* The number of shader blocks in the enum above */
88 #define NUM_PM_SHADER (8)
89
90 /* Software Counters */
91 static const char *const software_counter_names[] = {
92         "MMU_PAGE_FAULT_0",
93         "MMU_PAGE_FAULT_1",
94         "MMU_PAGE_FAULT_2",
95         "MMU_PAGE_FAULT_3"
96 };
97
98 enum {
99         MMU_PAGE_FAULT_0 = 0,
100         MMU_PAGE_FAULT_1,
101         MMU_PAGE_FAULT_2,
102         MMU_PAGE_FAULT_3
103 };
104
105 /* Software Counters */
106 static const char *const accumulators_names[] = {
107         "TOTAL_ALLOC_PAGES"
108 };
109
110 enum {
111         TOTAL_ALLOC_PAGES = 0
112 };
113
114 #define FIRST_TIMELINE_EVENT (0)
115 #define NUMBER_OF_TIMELINE_EVENTS (sizeof(timeline_event_names) / sizeof(timeline_event_names[0]))
116 #define FIRST_SOFTWARE_COUNTER (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS)
117 #define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0]))
118 #define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS)
119 #define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0]))
120 #define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS)
121 #define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1)
122
123 /*
124  * gatorfs variables for counter enable state
125  */
126 static struct mali_counter counters[NUMBER_OF_EVENTS];
127 static unsigned long filmstrip_event;
128
129 /* An array used to return the data we recorded
130  * as key,value pairs hence the *2
131  */
132 static int counter_dump[NUMBER_OF_EVENTS * 2];
133
134 /*
135  * Array holding counter start times (in ns) for each counter. A zero
136  * here indicates that the activity monitored by this counter is not
137  * running.
138  */
139 static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS];
140
141 /* The data we have recorded */
142 static unsigned int timeline_data[NUMBER_OF_TIMELINE_EVENTS];
143 static unsigned int sw_counter_data[NUMBER_OF_SOFTWARE_COUNTERS];
144 static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
145
146 /* Hold the previous timestamp, used to calculate the sample interval. */
147 static struct timespec prev_timestamp;
148
149 static unsigned long long previous_shader_bitmask;
150 static unsigned long long previous_tiler_bitmask;
151 static unsigned long long previous_l2_bitmask;
152
153 /**
154  * Returns the timespan (in microseconds) between the two specified timestamps.
155  *
156  * @param start Ptr to the start timestamp
157  * @param end Ptr to the end timestamp
158  *
159  * @return Number of microseconds between the two timestamps (can be negative if start follows end).
160  */
161 static inline long get_duration_us(const struct timespec *start, const struct timespec *end)
162 {
163         long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000;
164
165         event_duration_us += (end->tv_sec - start->tv_sec) * 1000000;
166
167         return event_duration_us;
168 }
169
170 static void record_timeline_event(unsigned int timeline_index, unsigned int type)
171 {
172         struct timespec event_timestamp;
173         struct timespec *event_start = &timeline_event_starttime[timeline_index];
174
175         switch (type) {
176         case ACTIVITY_START:
177                 /* Get the event time... */
178                 getnstimeofday(&event_timestamp);
179
180                 /* Remember the start time if the activity is not already started */
181                 if (event_start->tv_sec == 0)
182                         *event_start = event_timestamp; /* Structure copy */
183                 break;
184
185         case ACTIVITY_STOP:
186                 /* if the counter was started... */
187                 if (event_start->tv_sec != 0) {
188                         /* Get the event time... */
189                         getnstimeofday(&event_timestamp);
190
191                         /* Accumulate the duration in us */
192                         timeline_data[timeline_index] += get_duration_us(event_start, &event_timestamp);
193
194                         /* Reset the start time to indicate the activity is stopped. */
195                         event_start->tv_sec = 0;
196                 }
197                 break;
198
199         default:
200                 /* Other activity events are ignored. */
201                 break;
202         }
203 }
204
205 /*
206  * Documentation about the following tracepoints is in mali_linux_trace.h
207  */
208
209 GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long long value))
210 {
211 #define SHADER_PRESENT_LO       0x100   /* (RO) Shader core present bitmap, low word */
212 #define TILER_PRESENT_LO        0x110   /* (RO) Tiler core present bitmap, low word */
213 #define L2_PRESENT_LO           0x120   /* (RO) Level 2 cache present bitmap, low word */
214 #define BIT_AT(value, pos) ((value >> pos) & 1)
215
216         switch (event_id) {
217         case SHADER_PRESENT_LO:
218                 {
219                         unsigned long long changed_bitmask = previous_shader_bitmask ^ value;
220                         int pos;
221
222                         for (pos = 0; pos < NUM_PM_SHADER; ++pos) {
223                                 if (BIT_AT(changed_bitmask, pos))
224                                         record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP);
225                         }
226
227                         previous_shader_bitmask = value;
228                         break;
229                 }
230
231         case TILER_PRESENT_LO:
232                 {
233                         unsigned long long changed = previous_tiler_bitmask ^ value;
234
235                         if (BIT_AT(changed, 0))
236                                 record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
237
238                         previous_tiler_bitmask = value;
239                         break;
240                 }
241
242         case L2_PRESENT_LO:
243                 {
244                         unsigned long long changed = previous_l2_bitmask ^ value;
245
246                         if (BIT_AT(changed, 0))
247                                 record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
248                         if (BIT_AT(changed, 4))
249                                 record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
250
251                         previous_l2_bitmask = value;
252                         break;
253                 }
254
255         default:
256                 /* No other blocks are supported at present */
257                 break;
258         }
259
260 #undef SHADER_PRESENT_LO
261 #undef TILER_PRESENT_LO
262 #undef L2_PRESENT_LO
263 #undef BIT_AT
264 }
265
266 GATOR_DEFINE_PROBE(mali_page_fault_insert_pages, TP_PROTO(int event_id, unsigned long value))
267 {
268         /* We add to the previous since we may receive many tracepoints in one sample period */
269         sw_counter_data[MMU_PAGE_FAULT_0 + event_id] += value;
270 }
271
272 GATOR_DEFINE_PROBE(mali_mmu_as_in_use, TP_PROTO(int event_id))
273 {
274         record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_START);
275 }
276
277 GATOR_DEFINE_PROBE(mali_mmu_as_released, TP_PROTO(int event_id))
278 {
279         record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_STOP);
280 }
281
282 GATOR_DEFINE_PROBE(mali_total_alloc_pages_change, TP_PROTO(long long int event_id))
283 {
284         accumulators_data[TOTAL_ALLOC_PAGES] = event_id;
285 }
286
287 static int create_files(struct super_block *sb, struct dentry *root)
288 {
289         int event;
290         /*
291          * Create the filesystem for all events
292          */
293         int counter_index = 0;
294         mali_profiling_control_type *mali_control;
295
296         for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) {
297                 if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0)
298                         return -1;
299                 counter_index++;
300         }
301         counter_index = 0;
302         for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) {
303                 if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0)
304                         return -1;
305                 counter_index++;
306         }
307         counter_index = 0;
308         for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) {
309                 if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0)
310                         return -1;
311                 counter_index++;
312         }
313
314         mali_control = symbol_get(_mali_profiling_control);
315         if (mali_control) {
316                 if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0)
317                         return -1;
318                 symbol_put(_mali_profiling_control);
319         }
320
321         return 0;
322 }
323
324 static int register_tracepoints(void)
325 {
326         if (GATOR_REGISTER_TRACE(mali_pm_status)) {
327                 pr_err("gator: Mali-Midgard: mali_pm_status tracepoint failed to activate\n");
328                 return 0;
329         }
330
331         if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
332                 pr_err("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint failed to activate\n");
333                 return 0;
334         }
335
336         if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
337                 pr_err("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint failed to activate\n");
338                 return 0;
339         }
340
341         if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
342                 pr_err("gator: Mali-Midgard: mali_mmu_as_released tracepoint failed to activate\n");
343                 return 0;
344         }
345
346         if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
347                 pr_err("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint failed to activate\n");
348                 return 0;
349         }
350
351         pr_debug("gator: Mali-Midgard: start\n");
352         pr_debug("gator: Mali-Midgard: mali_pm_status probe is at %p\n", &probe_mali_pm_status);
353         pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages);
354         pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use);
355         pr_debug("gator: Mali-Midgard: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released);
356         pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change);
357
358         return 1;
359 }
360
361 static int start(void)
362 {
363         unsigned int cnt;
364         mali_profiling_control_type *mali_control;
365
366         previous_shader_bitmask = 0;
367         previous_tiler_bitmask = 0;
368         previous_l2_bitmask = 0;
369
370         /* Clean all data for the next capture */
371         for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
372                 timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
373                 timeline_data[cnt] = 0;
374         }
375
376         for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++)
377                 sw_counter_data[cnt] = 0;
378
379         for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++)
380                 accumulators_data[cnt] = 0;
381
382         /* Register tracepoints */
383         if (register_tracepoints() == 0)
384                 return -1;
385
386         /* Generic control interface for Mali DDK. */
387         mali_control = symbol_get(_mali_profiling_control);
388         if (mali_control) {
389                 /* The event attribute in the XML file keeps the actual frame rate. */
390                 unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0;
391                 unsigned int rate = filmstrip_event & 0xff;
392                 unsigned int resize_factor = (filmstrip_event >> 8) & 0xff;
393
394                 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
395
396 #define FBDUMP_CONTROL_ENABLE (1)
397 #define FBDUMP_CONTROL_RATE (2)
398 #define FBDUMP_CONTROL_RESIZE_FACTOR (4)
399                 mali_control(FBDUMP_CONTROL_ENABLE, enabled);
400                 mali_control(FBDUMP_CONTROL_RATE, rate);
401                 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
402
403                 pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor);
404
405                 symbol_put(_mali_profiling_control);
406         } else {
407                 pr_err("gator: mali online _mali_profiling_control symbol not found\n");
408         }
409
410         /*
411          * Set the first timestamp for calculating the sample interval. The first interval could be quite long,
412          * since it will be the time between 'start' and the first 'read'.
413          * This means that timeline values will be divided by a big number for the first sample.
414          */
415         getnstimeofday(&prev_timestamp);
416
417         return 0;
418 }
419
420 static void stop(void)
421 {
422         mali_profiling_control_type *mali_control;
423
424         pr_debug("gator: Mali-Midgard: stop\n");
425
426         /*
427          * It is safe to unregister traces even if they were not successfully
428          * registered, so no need to check.
429          */
430         GATOR_UNREGISTER_TRACE(mali_pm_status);
431         pr_debug("gator: Mali-Midgard: mali_pm_status tracepoint deactivated\n");
432
433         GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages);
434         pr_debug("gator: Mali-Midgard: mali_page_fault_insert_pages tracepoint deactivated\n");
435
436         GATOR_UNREGISTER_TRACE(mali_mmu_as_in_use);
437         pr_debug("gator: Mali-Midgard: mali_mmu_as_in_use tracepoint deactivated\n");
438
439         GATOR_UNREGISTER_TRACE(mali_mmu_as_released);
440         pr_debug("gator: Mali-Midgard: mali_mmu_as_released tracepoint deactivated\n");
441
442         GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change);
443         pr_debug("gator: Mali-Midgard: mali_total_alloc_pages_change tracepoint deactivated\n");
444
445         /* Generic control interface for Mali DDK. */
446         mali_control = symbol_get(_mali_profiling_control);
447         if (mali_control) {
448                 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control);
449
450                 mali_control(FBDUMP_CONTROL_ENABLE, 0);
451
452                 symbol_put(_mali_profiling_control);
453         } else {
454                 pr_err("gator: mali offline _mali_profiling_control symbol not found\n");
455         }
456 }
457
458 static int read(int **buffer, bool sched_switch)
459 {
460         int cnt;
461         int len = 0;
462         long sample_interval_us = 0;
463         struct timespec read_timestamp;
464
465         if (!on_primary_core())
466                 return 0;
467
468         /* Get the start of this sample period. */
469         getnstimeofday(&read_timestamp);
470
471         /*
472          * Calculate the sample interval if the previous sample time is valid.
473          * We use tv_sec since it will not be 0.
474          */
475         if (prev_timestamp.tv_sec != 0)
476                 sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
477
478         /* Structure copy. Update the previous timestamp. */
479         prev_timestamp = read_timestamp;
480
481         /*
482          * Report the timeline counters (ACTIVITY_START/STOP)
483          */
484         for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) {
485                 struct mali_counter *counter = &counters[cnt];
486
487                 if (counter->enabled) {
488                         const int index = cnt - FIRST_TIMELINE_EVENT;
489                         unsigned int value;
490
491                         /* If the activity is still running, reset its start time to the
492                          * start of this sample period to correct the count. Add the
493                          * time up to the end of the sample onto the count.
494                          */
495                         if (timeline_event_starttime[index].tv_sec != 0) {
496                                 const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp);
497
498                                 timeline_data[index] += event_duration;
499                                 timeline_event_starttime[index] = read_timestamp;       /* Activity is still running. */
500                         }
501
502                         if (sample_interval_us != 0) {
503                                 /* Convert the counter to a percent-of-sample value */
504                                 value = (timeline_data[index] * 100) / sample_interval_us;
505                         } else {
506                                 pr_debug("gator: Mali-Midgard: setting value to zero\n");
507                                 value = 0;
508                         }
509
510                         /* Clear the counter value ready for the next sample. */
511                         timeline_data[index] = 0;
512
513                         counter_dump[len++] = counter->key;
514                         counter_dump[len++] = value;
515                 }
516         }
517
518         /* Report the software counters */
519         for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) {
520                 const struct mali_counter *counter = &counters[cnt];
521
522                 if (counter->enabled) {
523                         const int index = cnt - FIRST_SOFTWARE_COUNTER;
524
525                         counter_dump[len++] = counter->key;
526                         counter_dump[len++] = sw_counter_data[index];
527                         /* Set the value to zero for the next time */
528                         sw_counter_data[index] = 0;
529                 }
530         }
531
532         /* Report the accumulators */
533         for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) {
534                 const struct mali_counter *counter = &counters[cnt];
535
536                 if (counter->enabled) {
537                         const int index = cnt - FIRST_ACCUMULATOR;
538
539                         counter_dump[len++] = counter->key;
540                         counter_dump[len++] = accumulators_data[index];
541                         /* Do not zero the accumulator */
542                 }
543         }
544
545         /* Update the buffer */
546         if (buffer)
547                 *buffer = counter_dump;
548
549         return len;
550 }
551
552 static struct gator_interface gator_events_mali_midgard_interface = {
553         .name = "mali_midgard",
554         .create_files = create_files,
555         .start = start,
556         .stop = stop,
557         .read = read
558 };
559
560 extern int gator_events_mali_midgard_init(void)
561 {
562         pr_debug("gator: Mali-Midgard: sw_counters init\n");
563
564         gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS);
565
566         return gator_events_install(&gator_events_mali_midgard_interface);
567 }