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