]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_events_mali_t6xx_hw.c
gator: Version 5.12
[android-sdk/arm-ds5-gator.git] / driver / gator_events_mali_t6xx_hw.c
1 /**
2  * Copyright (C) ARM Limited 2012. 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  */
10 #include "gator.h"
12 #include <linux/module.h>
13 #include <linux/time.h>
14 #include <linux/math64.h>
15 #include <linux/slab.h>
16 #include <asm/io.h>
18 /* Mali T6xx DDK includes */
19 #include "linux/mali_linux_trace.h"
20 #include "kbase/src/common/mali_kbase.h"
21 #include "kbase/src/linux/mali_kbase_mem_linux.h"
23 #include "gator_events_mali_common.h"
25 /*
26  * Mali-T6xx
27  */
28 typedef struct kbase_device *kbase_find_device_type(int);
29 typedef kbase_context *kbase_create_context_type(kbase_device*);
30 typedef void kbase_destroy_context_type(kbase_context *);
31 typedef void *kbase_va_alloc_type(kbase_context *, u32);
32 typedef void kbase_va_free_type(kbase_context *, void *);
33 typedef mali_error kbase_instr_hwcnt_enable_type(kbase_context *, kbase_uk_hwcnt_setup *);
34 typedef mali_error kbase_instr_hwcnt_disable_type(kbase_context *);
35 typedef mali_error kbase_instr_hwcnt_clear_type(kbase_context *);
36 typedef mali_error kbase_instr_hwcnt_dump_irq_type(kbase_context *);
37 typedef mali_bool kbase_instr_hwcnt_dump_complete_type(kbase_context *, mali_bool *);
39 static kbase_find_device_type * kbase_find_device_symbol;
40 static kbase_create_context_type * kbase_create_context_symbol;
41 static kbase_va_alloc_type * kbase_va_alloc_symbol;
42 static kbase_instr_hwcnt_enable_type * kbase_instr_hwcnt_enable_symbol;
43 static kbase_instr_hwcnt_clear_type * kbase_instr_hwcnt_clear_symbol;
44 static kbase_instr_hwcnt_dump_irq_type * kbase_instr_hwcnt_dump_irq_symbol;
45 static kbase_instr_hwcnt_dump_complete_type * kbase_instr_hwcnt_dump_complete_symbol;
46 static kbase_instr_hwcnt_disable_type * kbase_instr_hwcnt_disable_symbol;
47 static kbase_va_free_type * kbase_va_free_symbol;
48 static kbase_destroy_context_type * kbase_destroy_context_symbol;
50 /** The interval between reads, in ns. */
51 static const int READ_INTERVAL_NSEC = 1000000;
54 #if GATOR_TEST
55 #include "gator_events_mali_t6xx_hw_test.c"
56 #endif
58 /* Blocks for HW counters */
59 enum
60 {
61     JM_BLOCK = 0,
62     TILER_BLOCK,
63     SHADER_BLOCK,
64     MMU_BLOCK
65 };
67 /* Counters for Mali-T6xx:
68  *
69  *  - HW counters, 4 blocks
70  *    For HW counters we need strings to create /dev/gator/events files.
71  *    Enums are not needed because the position of the HW name in the array is the same
72  *    of the corresponding value in the received block of memory.
73  *    HW counters are requested by calculating a bitmask, passed then to the driver.
74  *    Every millisecond a HW counters dump is requested, and if the previous has been completed they are read.
75  */
77 /* Hardware Counters */
78 static const char* const hardware_counter_names [] =
79 {
80     /* Job Manager */
81     "",
82     "",
83     "",
84     "",
85     "MESSAGES_SENT",
86     "MESSAGES_RECEIVED",
87     "GPU_ACTIVE",            /* 6 */
88     "IRQ_ACTIVE",
89     "JS0_JOBS",
90     "JS0_TASKS",
91     "JS0_ACTIVE",
92     "",
93     "JS0_WAIT_READ",
94     "JS0_WAIT_ISSUE",
95     "JS0_WAIT_DEPEND",
96     "JS0_WAIT_FINISH",
97     "JS1_JOBS",
98     "JS1_TASKS",
99     "JS1_ACTIVE",
100     "",
101     "JS1_WAIT_READ",
102     "JS1_WAIT_ISSUE",
103     "JS1_WAIT_DEPEND",
104     "JS1_WAIT_FINISH",
105     "JS2_JOBS",
106     "JS2_TASKS",
107     "JS2_ACTIVE",
108     "",
109     "JS2_WAIT_READ",
110     "JS2_WAIT_ISSUE",
111     "JS2_WAIT_DEPEND",
112     "JS2_WAIT_FINISH",
113     "JS3_JOBS",
114     "JS3_TASKS",
115     "JS3_ACTIVE",
116     "",
117     "JS3_WAIT_READ",
118     "JS3_WAIT_ISSUE",
119     "JS3_WAIT_DEPEND",
120     "JS3_WAIT_FINISH",
121     "JS4_JOBS",
122     "JS4_TASKS",
123     "JS4_ACTIVE",
124     "",
125     "JS4_WAIT_READ",
126     "JS4_WAIT_ISSUE",
127     "JS4_WAIT_DEPEND",
128     "JS4_WAIT_FINISH",
129     "JS5_JOBS",
130     "JS5_TASKS",
131     "JS5_ACTIVE",
132     "",
133     "JS5_WAIT_READ",
134     "JS5_WAIT_ISSUE",
135     "JS5_WAIT_DEPEND",
136     "JS5_WAIT_FINISH",
137     "JS6_JOBS",
138     "JS6_TASKS",
139     "JS6_ACTIVE",
140     "",
141     "JS6_WAIT_READ",
142     "JS6_WAIT_ISSUE",
143     "JS6_WAIT_DEPEND",
144     "JS6_WAIT_FINISH",
146     /*Tiler*/
147     "",
148     "",
149     "",
150     "JOBS_PROCESSED",
151     "TRIANGLES",
152     "QUADS",
153     "POLYGONS",
154     "POINTS",
155     "LINES",
156     "VCACHE_HIT",
157     "VCACHE_MISS",
158     "FRONT_FACING",
159     "BACK_FACING",
160     "PRIM_VISIBLE",
161     "PRIM_CULLED",
162     "PRIM_CLIPPED",
163     "LEVEL0",
164     "LEVEL1",
165     "LEVEL2",
166     "LEVEL3",
167     "LEVEL4",
168     "LEVEL5",
169     "LEVEL6",
170     "LEVEL7",
171     "COMMAND_1",
172     "COMMAND_2",
173     "COMMAND_3",
174     "COMMAND_4",
175     "COMMAND_4_7",
176     "COMMAND_8_15",
177     "COMMAND_16_63",
178     "COMMAND_64",
179     "COMPRESS_IN",
180     "COMPRESS_OUT",
181     "COMPRESS_FLUSH",
182     "TIMESTAMPS",
183     "PCACHE_HIT",
184     "PCACHE_MISS",
185     "PCACHE_LINE",
186     "PCACHE_STALL",
187     "WRBUF_HIT",
188     "WRBUF_MISS",
189     "WRBUF_LINE",
190     "WRBUF_PARTIAL",
191     "WRBUF_STALL",
192     "ACTIVE",
193     "LOADING_DESC",
194     "INDEX_WAIT",
195     "INDEX_RANGE_WAIT",
196     "VERTEX_WAIT",
197     "PCACHE_WAIT",
198     "WRBUF_WAIT",
199     "BUS_READ",
200     "BUS_WRITE",
201     "",
202     "",
203     "",
204     "",
205     "",
206     "UTLB_STALL",
207     "UTLB_REPLAY_MISS",
208     "UTLB_REPLAY_FULL",
209     "UTLB_NEW_MISS",
210     "UTLB_HIT",
212     /* Shader Core */
213     "",
214     "",
215     "",
216     "SHADER_CORE_ACTIVE",
217     "FRAG_ACTIVE",
218     "FRAG_PRIMATIVES",
219     "FRAG_PRIMATIVES_DROPPED",
220     "FRAG_CYCLE_DESC",
221     "FRAG_CYCLES_PLR",
222     "FRAG_CYCLES_VERT",
223     "FRAG_CYCLES_TRISETUP",
224     "FRAG_CYCLES_RAST",
225     "FRAG_THREADS",
226     "FRAG_DUMMY_THREADS",
227     "FRAG_QUADS_RAST",
228     "FRAG_QUADS_EZS_TEST",
229     "FRAG_QUADS_EZS_KILLED",
230     "FRAG_QUADS_LZS_TEST",
231     "FRAG_QUADS_LZS_KILLED",
232     "FRAG_CYCLE_NO_TILE",
233     "FRAG_NUM_TILES",
234     "FRAG_TRANS_ELIM",
235     "COMPUTE_ACTIVE",
236     "COMPUTE_TASKS",
237     "COMPUTE_THREADS",
238     "COMPUTE_CYCLES_DESC",
239     "TRIPIPE_ACTIVE",
240     "ARITH_WORDS",
241     "ARITH_CYCLES_REG",
242     "ARITH_CYCLES_L0",
243     "ARITH_FRAG_DEPEND",
244     "LS_WORDS",
245     "LS_ISSUES",
246     "LS_RESTARTS",
247     "LS_REISSUES_MISS",
248     "LS_REISSUES_VD",
249     "LS_REISSUE_ATTRIB_MISS",
250     "LS_NO_WB",
251     "TEX_WORDS",
252     "TEX_BUBBLES",
253     "TEX_WORDS_L0",
254     "TEX_WORDS_DESC",
255     "TEX_THREADS",
256     "TEX_RECIRC_FMISS",
257     "TEX_RECIRC_DESC",
258     "TEX_RECIRC_MULTI",
259     "TEX_RECIRC_PMISS",
260     "TEX_RECIRC_CONF",
261     "LSC_READ_HITS",
262     "LSC_READ_MISSES",
263     "LSC_WRITE_HITS",
264     "LSC_WRITE_MISSES",
265     "LSC_ATOMIC_HITS",
266     "LSC_ATOMIC_MISSES",
267     "LSC_LINE_FETCHES",
268     "LSC_DIRTY_LINE",
269     "LSC_SNOOPS",
270     "AXI_TLB_STALL",
271     "AXI_TLB_MIESS",
272     "AXI_TLB_TRANSACTION",
273     "LS_TLB_MISS",
274     "LS_TLB_HIT",
275     "AXI_BEATS_READ",
276     "AXI_BEATS_WRITTEN",
278     /*L2 and MMU */
279     "",
280     "",
281     "",
282     "",
283     "MMU_TABLE_WALK",
284     "MMU_REPLAY_MISS",
285     "MMU_REPLAY_FULL",
286     "MMU_NEW_MISS",
287     "MMU_HIT",
288     "",
289     "",
290     "",
291     "",
292     "",
293     "",
294     "",
295     "UTLB_STALL",
296     "UTLB_REPLAY_MISS",
297     "UTLB_REPLAY_FULL",
298     "UTLB_NEW_MISS",
299     "UTLB_HIT",
300     "",
301     "",
302     "",
303     "",
304     "",
305     "",
306     "",
307     "",
308     "",
309     "L2_WRITE_BEATS",
310     "L2_READ_BEATS",
311     "L2_ANY_LOOKUP",
312     "L2_READ_LOOKUP",
313     "L2_SREAD_LOOKUP",
314     "L2_READ_REPLAY",
315     "L2_READ_SNOOP",
316     "L2_READ_HIT",
317     "L2_CLEAN_MISS",
318     "L2_WRITE_LOOKUP",
319     "L2_SWRITE_LOOKUP",
320     "L2_WRITE_REPLAY",
321     "L2_WRITE_SNOOP",
322     "L2_WRITE_HIT",
323     "L2_EXT_READ_FULL",
324     "L2_EXT_READ_HALF",
325     "L2_EXT_WRITE_FULL",
326     "L2_EXT_WRITE_HALF",
327     "L2_EXT_READ",
328     "L2_EXT_READ_LINE",
329     "L2_EXT_WRITE",
330     "L2_EXT_WRITE_LINE",
331     "L2_EXT_WRITE_SMALL",
332     "L2_EXT_BARRIER",
333     "L2_EXT_AR_STALL",
334     "L2_EXT_R_BUF_FULL",
335     "L2_EXT_RD_BUF_FULL",
336     "L2_EXT_R_RAW",
337     "L2_EXT_W_STALL",
338     "L2_EXT_W_BUF_FULL",
339     "L2_EXT_R_W_HAZARD",
340     "L2_TAG_HAZARD",
341     "L2_SNOOP_FULL",
342     "L2_REPLAY_FULL"
343 };
345 #define NUMBER_OF_HARDWARE_COUNTERS (sizeof(hardware_counter_names) / sizeof(hardware_counter_names[0]))
347 #define GET_HW_BLOCK(c) (((c) >> 6) & 0x3)
348 #define GET_COUNTER_OFFSET(c) ((c) & 0x3f)
350 /* Memory to dump hardware counters into */
351 static void *kernel_dump_buffer;
353 /* kbase context and device */
354 static kbase_context *kbcontext = NULL;
355 static struct kbase_device *kbdevice = NULL;
357 /*
358  * The following function has no external prototype in older DDK revisions.  When the DDK
359  * is updated then this should be removed.
360  */
361 struct kbase_device *kbase_find_device(int minor);
363 static volatile bool kbase_device_busy = false;
364 static unsigned int num_hardware_counters_enabled;
366 /*
367  * gatorfs variables for counter enable state
368  */
369 static mali_counter counters[NUMBER_OF_HARDWARE_COUNTERS];
371 /* An array used to return the data we recorded
372  * as key,value pairs hence the *2
373  */
374 static unsigned long counter_dump[NUMBER_OF_HARDWARE_COUNTERS * 2];
376 #define SYMBOL_GET(FUNCTION, ERROR_COUNT) \
377         if(FUNCTION ## _symbol) \
378         { \
379                 printk("gator: mali " #FUNCTION " symbol was already registered\n"); \
380                 (ERROR_COUNT)++; \
381         } \
382         else \
383         { \
384                 FUNCTION ## _symbol = symbol_get(FUNCTION); \
385                 if(! FUNCTION ## _symbol) \
386                 { \
387                         printk("gator: mali online " #FUNCTION " symbol not found\n"); \
388                         (ERROR_COUNT)++; \
389                 } \
390         }
392 #define SYMBOL_CLEANUP(FUNCTION) \
393         if(FUNCTION ## _symbol) \
394         { \
395                 symbol_put(FUNCTION); \
396                 FUNCTION ## _symbol = NULL; \
397         }
399 /**
400  * Execute symbol_get for all the Mali symbols and check for success.
401  * @return the number of symbols not loaded.
402  */
403 static int init_symbols(void)
405         int error_count = 0;
406         SYMBOL_GET(kbase_find_device, error_count);
407         SYMBOL_GET(kbase_create_context, error_count);
408         SYMBOL_GET(kbase_va_alloc, error_count);
409         SYMBOL_GET(kbase_instr_hwcnt_enable, error_count);
410         SYMBOL_GET(kbase_instr_hwcnt_clear, error_count);
411         SYMBOL_GET(kbase_instr_hwcnt_dump_irq, error_count);
412         SYMBOL_GET(kbase_instr_hwcnt_dump_complete, error_count);
413         SYMBOL_GET(kbase_instr_hwcnt_disable, error_count);
414         SYMBOL_GET(kbase_va_free, error_count);
415         SYMBOL_GET(kbase_destroy_context, error_count);
417         return error_count;
420 /**
421  * Execute symbol_put for all the registered Mali symbols.
422  */
423 static void clean_symbols(void)
425         SYMBOL_CLEANUP(kbase_find_device);
426         SYMBOL_CLEANUP(kbase_create_context);
427         SYMBOL_CLEANUP(kbase_va_alloc);
428         SYMBOL_CLEANUP(kbase_instr_hwcnt_enable);
429         SYMBOL_CLEANUP(kbase_instr_hwcnt_clear);
430         SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_irq);
431         SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_complete);
432         SYMBOL_CLEANUP(kbase_instr_hwcnt_disable);
433         SYMBOL_CLEANUP(kbase_va_free);
434         SYMBOL_CLEANUP(kbase_destroy_context);
437 /**
438  * Determines whether a read should take place
439  * @param current_time The current time, obtained from getnstimeofday()
440  * @param prev_time_s The number of seconds at the previous read attempt.
441  * @param next_read_time_ns The time (in ns) when the next read should be allowed.
442  *
443  * Note that this function has been separated out here to allow it to be tested.
444  */
445 static int is_read_scheduled(const struct timespec *current_time, u32* prev_time_s, s32* next_read_time_ns)
447         /* If the current ns count rolls over a second, roll the next read time too. */
448         if(current_time->tv_sec != *prev_time_s)
449         {
450                 *next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC;
451         }
453         /* Abort the read if the next read time has not arrived. */
454         if(current_time->tv_nsec < *next_read_time_ns)
455         {
456                 return 0;
457         }
459         /* Set the next read some fixed time after this one, and update the read timestamp. */
460         *next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC;
462         *prev_time_s = current_time->tv_sec;
463         return 1;
466 static int start(void)
468     kbase_uk_hwcnt_setup setup;
469     mali_error err;
470     int cnt;
471     u16 bitmask[] = {0, 0, 0, 0};
473     /* Setup HW counters */
474     num_hardware_counters_enabled = 0;
476     if(NUMBER_OF_HARDWARE_COUNTERS != 256)
477     {
478         pr_debug("Unexpected number of hardware counters defined: expecting 256, got %d\n", NUMBER_OF_HARDWARE_COUNTERS);
479     }
481     /* Calculate enable bitmasks based on counters_enabled array */
482     for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++)
483     {
484         const mali_counter *counter = &counters[cnt];
485         if (counter->enabled)
486         {
487             int block = GET_HW_BLOCK(cnt);
488             int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
489             bitmask[block] |= (1 << enable_bit);
490             pr_debug("gator: Mali-T6xx: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
491             num_hardware_counters_enabled++;
492         }
493     }
495     /* Create a kbase context for HW counters */
496     if (num_hardware_counters_enabled > 0)
497     {
498             if(init_symbols() > 0)
499             {
500                     clean_symbols();
501                     /* No Mali driver code entrypoints found - not a fault. */
502                     return 0;
503             }
505             kbdevice = kbase_find_device_symbol(-1);
507             /* If we already got a context, fail */
508             if (kbcontext) {
509                     pr_debug("gator: Mali-T6xx: error context already present\n");
510                     goto out;
511             }
513             /* kbcontext will only be valid after all the Mali symbols are loaded successfully */
514             kbcontext = kbase_create_context_symbol(kbdevice);
515         if (!kbcontext)
516         {
517             pr_debug("gator: Mali-T6xx: error creating kbase context\n");
518             goto out;
519         }
521         /*
522          * The amount of memory needed to store the dump (bytes)
523          * DUMP_SIZE = number of core groups
524          *             * number of blocks (always 8 for midgard)
525          *             * number of counters per block (always 64 for midgard)
526          *             * number of bytes per counter (always 4 in midgard)
527          * For a Mali-T6xx with a single core group = 1 * 8 * 64 * 4
528          */
529         kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 2048);
530         if (!kernel_dump_buffer)
531         {
532             pr_debug("gator: Mali-T6xx: error trying to allocate va\n");
533             goto destroy_context;
534         }
536         setup.dump_buffer = (uintptr_t)kernel_dump_buffer;
537         setup.jm_bm = bitmask[JM_BLOCK];
538         setup.tiler_bm = bitmask[TILER_BLOCK];
539         setup.shader_bm = bitmask[SHADER_BLOCK];
540         setup.mmu_l2_bm = bitmask[MMU_BLOCK];
541         /* These counters do not exist on Mali-T60x */
542         setup.l3_cache_bm = 0;
544         /* Use kbase API to enable hardware counters and provide dump buffer */
545         err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup);
546         if (err != MALI_ERROR_NONE)
547         {
548             pr_debug("gator: Mali-T6xx: can't setup hardware counters\n");
549             goto free_buffer;
550         }
551         pr_debug("gator: Mali-T6xx: hardware counters enabled\n");
552         kbase_instr_hwcnt_clear_symbol(kbcontext);
553         pr_debug("gator: Mali-T6xx: hardware counters cleared \n");
555         kbase_device_busy = false;
556     }
558     return 0;
560     free_buffer:
561         kbase_va_free_symbol(kbcontext, kernel_dump_buffer);
563     destroy_context:
564         kbase_destroy_context_symbol(kbcontext);
566     out:
567         clean_symbols();
568         return -1;
571 static void stop(void) {
572     unsigned int cnt;
573     kbase_context *temp_kbcontext;
575     pr_debug("gator: Mali-T6xx: stop\n");
577     /* Set all counters as disabled */
578     for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) {
579         counters[cnt].enabled = 0;
580     }
582     /* Destroy the context for HW counters */
583     if (num_hardware_counters_enabled > 0 && kbcontext != NULL)
584     {
585         /*
586          * Set the global variable to NULL before destroying it, because
587          * other function will check this before using it.
588          */
589         temp_kbcontext = kbcontext;
590         kbcontext = NULL;
592         kbase_instr_hwcnt_disable_symbol(temp_kbcontext);
593         kbase_va_free_symbol(temp_kbcontext, kernel_dump_buffer);
594         kbase_destroy_context_symbol(temp_kbcontext);
596         pr_debug("gator: Mali-T6xx: hardware counters stopped\n");
598         clean_symbols();
599     }
602 static int read(int **buffer) {
603     int cnt;
604     int len = 0;
605     u32 value = 0;
606     mali_bool success;
608         struct timespec current_time;
609         static u32 prev_time_s = 0;
610         static s32 next_read_time_ns = 0;
612     if (smp_processor_id()!=0)
613     {
614         return 0;
615     }
617         getnstimeofday(&current_time);
619         /*
620          * Discard reads unless a respectable time has passed.  This reduces the load on the GPU without sacrificing
621          * accuracy on the Streamline display.
622          */
623         if(!is_read_scheduled(&current_time, &prev_time_s, &next_read_time_ns))
624         {
625                 return 0;
626         }
628     /*
629      * Report the HW counters
630      * Only process hardware counters if at least one of the hardware counters is enabled.
631      */
632     if (num_hardware_counters_enabled > 0)
633     {
634         const unsigned int vithar_blocks[] = {
635             0x700,    /* VITHAR_JOB_MANAGER,     Block 0 */
636             0x400,    /* VITHAR_TILER,           Block 1 */
637             0x000,    /* VITHAR_SHADER_CORE,     Block 2 */
638             0x500     /* VITHAR_MEMORY_SYSTEM,   Block 3 */
639         };
641         if (!kbcontext)
642         {
643             return -1;
644         }
646         /* Mali symbols can be called safely since a kbcontext is valid */
647         if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE)
648         {
649             kbase_device_busy = false;
651             if (success == MALI_TRUE)
652             {
653                 for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++)
654                 {
655                     const mali_counter *counter = &counters[cnt];
656                     if (counter->enabled)
657                     {
658                         const int block = GET_HW_BLOCK(cnt);
659                         const int counter_offset = GET_COUNTER_OFFSET(cnt);
660                         const u32 *counter_block = (u32 *)((uintptr_t)kernel_dump_buffer + vithar_blocks[block]);
661                         const u32 *counter_address = counter_block + counter_offset;
663                         value = *counter_address;
665                         if(block == SHADER_BLOCK){
666                             /* (counter_address + 0x000) has already been accounted-for above. */
667                             value += *(counter_address + 0x100);
668                             value += *(counter_address + 0x200);
669                             value += *(counter_address + 0x300);
670                         }
672                         counter_dump[len++] = counter->key;
673                         counter_dump[len++] = value;
674                     }
675                 }
676             }
677         }
679         if (! kbase_device_busy)
680         {
681             kbase_device_busy = true;
682             kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
683         }
684     }
686     /* Update the buffer */
687     if (buffer) {
688         *buffer = (int*) counter_dump;
689     }
691     return len;
694 static int create_files(struct super_block *sb, struct dentry *root)
696     unsigned int event;
697     /*
698      * Create the filesystem for all events
699      */
700     int counter_index = 0;
701     const char* mali_name = gator_mali_get_mali_name();
703     for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++)
704     {
705         if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event]) != 0)
706             return -1;
707         counter_index++;
708     }
710     return 0;
713 static struct gator_interface gator_events_mali_t6xx_interface = {
714     .create_files    = create_files,
715     .start        = start,
716     .stop        = stop,
717     .read        = read
718 };
720 int gator_events_mali_t6xx_hw_init(void)
722     pr_debug("gator: Mali-T6xx: sw_counters init\n");
724 #if GATOR_TEST
725         test_all_is_read_scheduled();
726 #endif
728     gator_mali_initialise_counters(counters, NUMBER_OF_HARDWARE_COUNTERS);
730     return gator_events_install(&gator_events_mali_t6xx_interface);
733 gator_events_init(gator_events_mali_t6xx_hw_init);