2 * Copyright (C) ARM Limited 2012-2015. All rights reserved.
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.
12 #include <linux/module.h>
13 #include <linux/time.h>
14 #include <linux/math64.h>
15 #include <linux/slab.h>
18 /* Mali Midgard DDK includes */
19 #if defined(MALI_SIMPLE_API)
20 /* Header with wrapper functions to kbase structures and functions */
21 #include "mali_kbase_gator_api.h"
22 #elif defined(MALI_DIR_MIDGARD)
23 /* New DDK Directory structure with kernel/drivers/gpu/arm/midgard */
24 #include "mali_linux_trace.h"
25 #include "mali_kbase.h"
26 #include "mali_kbase_mem_linux.h"
28 /* Old DDK Directory structure with kernel/drivers/gpu/arm/t6xx */
29 #include "linux/mali_linux_trace.h"
30 #include "kbase/src/common/mali_kbase.h"
31 #include "kbase/src/linux/mali_kbase_mem_linux.h"
34 /* If API version is not specified then assume API version 1. */
35 #ifndef MALI_DDK_GATOR_API_VERSION
36 #define MALI_DDK_GATOR_API_VERSION 1
39 #if (MALI_DDK_GATOR_API_VERSION != 1) && (MALI_DDK_GATOR_API_VERSION != 2) && (MALI_DDK_GATOR_API_VERSION != 3)
40 #error MALI_DDK_GATOR_API_VERSION is invalid (must be 1 for r1/r2 DDK, or 2 for r3/r4 DDK, or 3 for r5 and later DDK).
43 #if !defined(CONFIG_MALI_GATOR_SUPPORT)
44 #error CONFIG_MALI_GATOR_SUPPORT is required for GPU activity and software counters
47 #include "gator_events_mali_common.h"
52 #if MALI_DDK_GATOR_API_VERSION == 3
53 static uint32_t (*kbase_gator_instr_hwcnt_dump_irq_symbol)(struct kbase_gator_hwcnt_handles *);
54 static uint32_t (*kbase_gator_instr_hwcnt_dump_complete_symbol)(struct kbase_gator_hwcnt_handles *, uint32_t *const);
55 static struct kbase_gator_hwcnt_handles *(*kbase_gator_hwcnt_init_symbol)(struct kbase_gator_hwcnt_info *);
56 static void (*kbase_gator_hwcnt_term_symbol)(struct kbase_gator_hwcnt_info *, struct kbase_gator_hwcnt_handles *);
59 static struct kbase_device *(*kbase_find_device_symbol)(int);
60 static struct kbase_context *(*kbase_create_context_symbol)(struct kbase_device *);
61 static void (*kbase_destroy_context_symbol)(struct kbase_context *);
63 #if MALI_DDK_GATOR_API_VERSION == 1
64 static void *(*kbase_va_alloc_symbol)(struct kbase_context *, u32);
65 static void (*kbase_va_free_symbol)(struct kbase_context *, void *);
66 #elif MALI_DDK_GATOR_API_VERSION == 2
67 static void *(*kbase_va_alloc_symbol)(struct kbase_context *, u32, struct kbase_hwc_dma_mapping *);
68 static void (*kbase_va_free_symbol)(struct kbase_context *, struct kbase_hwc_dma_mapping *);
71 static mali_error (*kbase_instr_hwcnt_enable_symbol)(struct kbase_context *, struct kbase_uk_hwcnt_setup *);
72 static mali_error (*kbase_instr_hwcnt_disable_symbol)(struct kbase_context *);
73 static mali_error (*kbase_instr_hwcnt_clear_symbol)(struct kbase_context *);
74 static mali_error (*kbase_instr_hwcnt_dump_irq_symbol)(struct kbase_context *);
75 static mali_bool (*kbase_instr_hwcnt_dump_complete_symbol)(struct kbase_context *, mali_bool *);
77 static long shader_present_low;
80 /** The interval between reads, in ns.
82 * Earlier we introduced a 'hold off for 1ms after last read' to
83 * resolve MIDBASE-2178 and MALINE-724. However, the 1ms hold off is
84 * too long if no context switches occur as there is a race between
85 * this value and the tick of the read clock in gator which is also
86 * 1ms. If we 'miss' the current read, the counter values are
87 * effectively 'spread' over 2ms and the values seen are half what
88 * they should be (since Streamline averages over sample time). In the
89 * presence of context switches this spread can vary and markedly
90 * affect the counters. Currently there is no 'proper' solution to
91 * this, but empirically we have found that reducing the minimum read
92 * interval to 950us causes the counts to be much more stable.
94 static const int READ_INTERVAL_NSEC = 950000;
97 #include "gator_events_mali_midgard_hw_test.c"
100 #if MALI_DDK_GATOR_API_VERSION != 3
101 /* Blocks for HW counters */
110 static const char *mali_name;
112 /* Counters for Mali-Midgard:
114 * For HW counters we need strings to create /dev/gator/events files.
115 * Enums are not needed because the position of the HW name in the array is the same
116 * of the corresponding value in the received block of memory.
117 * HW counters are requested by calculating a bitmask, passed then to the driver.
118 * Every millisecond a HW counters dump is requested, and if the previous has been completed they are read.
121 /* Hardware Counters */
122 #if MALI_DDK_GATOR_API_VERSION == 3
124 static const char *const *hardware_counter_names;
125 static int number_of_hardware_counters;
129 static const char *const hardware_counter_names[] = {
137 "GPU_ACTIVE", /* 6 */
266 "SHADER_CORE_ACTIVE",
269 "FRAG_PRIMATIVES_DROPPED",
273 "FRAG_CYCLES_TRISETUP",
276 "FRAG_DUMMY_THREADS",
278 "FRAG_QUADS_EZS_TEST",
279 "FRAG_QUADS_EZS_KILLED",
280 "FRAG_QUADS_LZS_TEST",
281 "FRAG_QUADS_LZS_KILLED",
282 "FRAG_CYCLE_NO_TILE",
288 "COMPUTE_CYCLES_DESC",
299 "LS_REISSUE_ATTRIB_MISS",
322 "AXI_TLB_TRANSACTION",
381 "L2_EXT_WRITE_SMALL",
385 "L2_EXT_RD_BUF_FULL",
395 static const int number_of_hardware_counters = ARRAY_SIZE(hardware_counter_names);
399 #define GET_HW_BLOCK(c) (((c) >> 6) & 0x3)
400 #define GET_COUNTER_OFFSET(c) ((c) & 0x3f)
402 #if MALI_DDK_GATOR_API_VERSION == 3
403 /* Opaque handles for kbase_context and kbase_hwc_dma_mapping */
404 static struct kbase_gator_hwcnt_handles *handles;
406 /* Information about hardware counters */
407 static struct kbase_gator_hwcnt_info *in_out_info;
410 /* Memory to dump hardware counters into */
411 static void *kernel_dump_buffer;
413 #if MALI_DDK_GATOR_API_VERSION == 2
414 /* DMA state used to manage lifetime of the buffer */
415 struct kbase_hwc_dma_mapping kernel_dump_buffer_handle;
418 /* kbase context and device */
419 static struct kbase_context *kbcontext;
420 static struct kbase_device *kbdevice;
423 * The following function has no external prototype in older DDK
424 * revisions. When the DDK is updated then this should be removed.
426 struct kbase_device *kbase_find_device(int minor);
429 static volatile bool kbase_device_busy;
430 static unsigned int num_hardware_counters_enabled;
432 /* gatorfs variables for counter enable state */
433 static struct mali_counter *counters;
435 /* An array used to return the data we recorded as key,value pairs */
436 static long long *counter_dump;
437 static uint64_t last_read_time;
439 extern struct mali_counter mali_activity[3];
441 static const char *const mali_activity_names[] = {
447 #define SYMBOL_GET(FUNCTION, ERROR_COUNT) \
449 if (FUNCTION ## _symbol) { \
450 pr_err("gator: mali " #FUNCTION " symbol was already registered\n"); \
453 FUNCTION ## _symbol = symbol_get(FUNCTION); \
454 if (!FUNCTION ## _symbol) { \
455 pr_err("gator: mali online " #FUNCTION " symbol not found\n"); \
461 #define SYMBOL_CLEANUP(FUNCTION) \
463 if (FUNCTION ## _symbol) { \
464 symbol_put(FUNCTION); \
465 FUNCTION ## _symbol = NULL; \
470 * Execute symbol_get for all the Mali symbols and check for success.
471 * @return the number of symbols not loaded.
473 static int init_symbols(void)
476 #if MALI_DDK_GATOR_API_VERSION == 3
477 SYMBOL_GET(kbase_gator_instr_hwcnt_dump_irq, error_count);
478 SYMBOL_GET(kbase_gator_instr_hwcnt_dump_complete, error_count);
479 SYMBOL_GET(kbase_gator_hwcnt_init, error_count);
480 SYMBOL_GET(kbase_gator_hwcnt_term, error_count);
482 SYMBOL_GET(kbase_find_device, error_count);
483 SYMBOL_GET(kbase_create_context, error_count);
484 SYMBOL_GET(kbase_va_alloc, error_count);
485 SYMBOL_GET(kbase_instr_hwcnt_enable, error_count);
486 SYMBOL_GET(kbase_instr_hwcnt_clear, error_count);
487 SYMBOL_GET(kbase_instr_hwcnt_dump_irq, error_count);
488 SYMBOL_GET(kbase_instr_hwcnt_dump_complete, error_count);
489 SYMBOL_GET(kbase_instr_hwcnt_disable, error_count);
490 SYMBOL_GET(kbase_va_free, error_count);
491 SYMBOL_GET(kbase_destroy_context, error_count);
498 * Execute symbol_put for all the registered Mali symbols.
500 static void clean_symbols(void)
502 #if MALI_DDK_GATOR_API_VERSION == 3
503 SYMBOL_CLEANUP(kbase_gator_instr_hwcnt_dump_irq);
504 SYMBOL_CLEANUP(kbase_gator_instr_hwcnt_dump_complete);
505 SYMBOL_CLEANUP(kbase_gator_hwcnt_init);
506 SYMBOL_CLEANUP(kbase_gator_hwcnt_term);
508 SYMBOL_CLEANUP(kbase_find_device);
509 SYMBOL_CLEANUP(kbase_create_context);
510 SYMBOL_CLEANUP(kbase_va_alloc);
511 SYMBOL_CLEANUP(kbase_instr_hwcnt_enable);
512 SYMBOL_CLEANUP(kbase_instr_hwcnt_clear);
513 SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_irq);
514 SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_complete);
515 SYMBOL_CLEANUP(kbase_instr_hwcnt_disable);
516 SYMBOL_CLEANUP(kbase_va_free);
517 SYMBOL_CLEANUP(kbase_destroy_context);
521 static int start(void)
523 #if MALI_DDK_GATOR_API_VERSION != 3
524 struct kbase_uk_hwcnt_setup setup;
525 unsigned long long shadersPresent = 0;
526 u16 bitmask[] = { 0, 0, 0, 0 };
533 #if MALI_DDK_GATOR_API_VERSION == 3
534 /* Setup HW counters */
535 num_hardware_counters_enabled = 0;
537 /* Declare and initialise kbase_gator_hwcnt_info structure */
538 in_out_info = kmalloc(sizeof(*in_out_info), GFP_KERNEL);
539 for (cnt = 0; cnt < ARRAY_SIZE(in_out_info->bitmask); cnt++)
540 in_out_info->bitmask[cnt] = 0;
542 /* Calculate enable bitmasks based on counters_enabled array */
543 for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
544 if (counters[cnt].enabled) {
545 int block = GET_HW_BLOCK(cnt);
546 int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
548 in_out_info->bitmask[block] |= (1 << enable_bit);
549 pr_debug("gator: Mali-Midgard: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
550 num_hardware_counters_enabled++;
554 /* Create a kbase context for HW counters */
555 if (num_hardware_counters_enabled > 0) {
556 if (init_symbols() > 0) {
558 /* No Mali driver code entrypoints found - not a fault. */
562 handles = kbase_gator_hwcnt_init_symbol(in_out_info);
567 kbase_device_busy = false;
572 /* Setup HW counters */
573 num_hardware_counters_enabled = 0;
575 /* Calculate enable bitmasks based on counters_enabled array */
576 for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
577 const struct mali_counter *counter = &counters[cnt];
579 if (counter->enabled) {
580 int block = GET_HW_BLOCK(cnt);
581 int enable_bit = GET_COUNTER_OFFSET(cnt) / 4;
583 bitmask[block] |= (1 << enable_bit);
584 pr_debug("gator: Mali-Midgard: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt);
585 num_hardware_counters_enabled++;
589 /* Create a kbase context for HW counters */
590 if (num_hardware_counters_enabled > 0) {
591 if (init_symbols() > 0) {
593 /* No Mali driver code entrypoints found - not a fault. */
597 kbdevice = kbase_find_device_symbol(-1);
599 /* If we already got a context, fail */
601 pr_err("gator: Mali-Midgard: error context already present\n");
605 /* kbcontext will only be valid after all the Mali symbols are loaded successfully */
606 kbcontext = kbase_create_context_symbol(kbdevice);
608 pr_err("gator: Mali-Midgard: error creating kbase context\n");
612 /* See if we can get the number of shader cores */
613 shadersPresent = kbdevice->shader_present_bitmap;
614 shader_present_low = (unsigned long)shadersPresent;
617 * The amount of memory needed to store the dump (bytes)
618 * DUMP_SIZE = number of core groups
619 * * number of blocks (always 8 for midgard)
620 * * number of counters per block (always 64 for midgard)
621 * * number of bytes per counter (always 4 in midgard)
622 * For a Mali-Midgard with a single core group = 1 * 8 * 64 * 4 = 2048
623 * For a Mali-Midgard with a dual core group = 2 * 8 * 64 * 4 = 4096
625 #if MALI_DDK_GATOR_API_VERSION == 1
626 kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096);
627 #elif MALI_DDK_GATOR_API_VERSION == 2
628 kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096, &kernel_dump_buffer_handle);
630 if (!kernel_dump_buffer) {
631 pr_err("gator: Mali-Midgard: error trying to allocate va\n");
632 goto destroy_context;
635 setup.dump_buffer = (uintptr_t)kernel_dump_buffer;
636 setup.jm_bm = bitmask[JM_BLOCK];
637 setup.tiler_bm = bitmask[TILER_BLOCK];
638 setup.shader_bm = bitmask[SHADER_BLOCK];
639 setup.mmu_l2_bm = bitmask[MMU_BLOCK];
640 /* These counters do not exist on Mali-T60x */
641 setup.l3_cache_bm = 0;
643 /* Use kbase API to enable hardware counters and provide dump buffer */
644 err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup);
645 if (err != MALI_ERROR_NONE) {
646 pr_err("gator: Mali-Midgard: can't setup hardware counters\n");
649 pr_debug("gator: Mali-Midgard: hardware counters enabled\n");
650 kbase_instr_hwcnt_clear_symbol(kbcontext);
651 pr_debug("gator: Mali-Midgard: hardware counters cleared\n");
653 kbase_device_busy = false;
659 #if MALI_DDK_GATOR_API_VERSION == 1
660 kbase_va_free_symbol(kbcontext, kernel_dump_buffer);
661 #elif MALI_DDK_GATOR_API_VERSION == 2
662 kbase_va_free_symbol(kbcontext, &kernel_dump_buffer_handle);
666 kbase_destroy_context_symbol(kbcontext);
674 static void stop(void)
677 #if MALI_DDK_GATOR_API_VERSION == 3
678 struct kbase_gator_hwcnt_handles *temp_hand;
680 struct kbase_context *temp_kbcontext;
683 pr_debug("gator: Mali-Midgard: stop\n");
685 /* Set all counters as disabled */
686 for (cnt = 0; cnt < number_of_hardware_counters; cnt++)
687 counters[cnt].enabled = 0;
689 /* Destroy the context for HW counters */
690 #if MALI_DDK_GATOR_API_VERSION == 3
691 if (num_hardware_counters_enabled > 0 && handles != NULL) {
693 * Set the global variable to NULL before destroying it, because
694 * other function will check this before using it.
699 kbase_gator_hwcnt_term_symbol(in_out_info, temp_hand);
704 if (num_hardware_counters_enabled > 0 && kbcontext != NULL) {
706 * Set the global variable to NULL before destroying it, because
707 * other function will check this before using it.
709 temp_kbcontext = kbcontext;
712 kbase_instr_hwcnt_disable_symbol(temp_kbcontext);
714 #if MALI_DDK_GATOR_API_VERSION == 1
715 kbase_va_free_symbol(temp_kbcontext, kernel_dump_buffer);
716 #elif MALI_DDK_GATOR_API_VERSION == 2
717 kbase_va_free_symbol(temp_kbcontext, &kernel_dump_buffer_handle);
720 kbase_destroy_context_symbol(temp_kbcontext);
723 pr_debug("gator: Mali-Midgard: hardware counters stopped\n");
729 static int read_counter(const int cnt, const int len, const struct mali_counter *counter)
731 const int block = GET_HW_BLOCK(cnt);
732 const int counter_offset = GET_COUNTER_OFFSET(cnt);
735 #if MALI_DDK_GATOR_API_VERSION == 3
736 const char *block_base_address = (char *)in_out_info->kernel_dump_buffer;
738 int shader_core_count = 0;
740 for (i = 0; i < in_out_info->nr_hwc_blocks; i++) {
741 if (block == in_out_info->hwc_layout[i]) {
742 value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
743 if (block == SHADER_BLOCK)
748 if (shader_core_count > 1)
749 value /= shader_core_count;
751 const unsigned int vithar_blocks[] = {
752 0x700, /* VITHAR_JOB_MANAGER, Block 0 */
753 0x400, /* VITHAR_TILER, Block 1 */
754 0x000, /* VITHAR_SHADER_CORE, Block 2 */
755 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */
757 const char *block_base_address = (char *)kernel_dump_buffer + vithar_blocks[block];
759 /* If counter belongs to shader block need to take into account all cores */
760 if (block == SHADER_BLOCK) {
762 int shader_core_count = 0;
766 for (i = 0; i < 4; i++) {
767 if ((shader_present_low >> i) & 1) {
768 value += *((u32 *)(block_base_address + (0x100 * i)) + counter_offset);
773 for (i = 0; i < 4; i++) {
774 if ((shader_present_low >> (i+4)) & 1) {
775 value += *((u32 *)(block_base_address + (0x100 * i) + 0x800) + counter_offset);
780 /* Need to total by number of cores to produce an average */
781 if (shader_core_count != 0)
782 value /= shader_core_count;
784 value = *((u32 *)block_base_address + counter_offset);
788 counter_dump[len + 0] = counter->key;
789 counter_dump[len + 1] = value;
794 static int read(long long **buffer, bool sched_switch)
802 if (!on_primary_core() || sched_switch)
806 * Report the HW counters
807 * Only process hardware counters if at least one of the hardware counters is enabled.
809 if (num_hardware_counters_enabled <= 0)
812 curr_time = gator_get_time();
815 * Discard reads unless a respectable time has passed. This
816 * reduces the load on the GPU without sacrificing accuracy on
817 * the Streamline display.
819 if (curr_time - last_read_time < READ_INTERVAL_NSEC)
822 #if MALI_DDK_GATOR_API_VERSION == 3
826 /* Mali symbols can be called safely since a kbcontext is valid */
827 if (kbase_gator_instr_hwcnt_dump_complete_symbol(handles, &success)) {
832 /* Mali symbols can be called safely since a kbcontext is valid */
833 if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success)) {
835 kbase_device_busy = false;
838 * If last_read_time is zero, then this result is from a previous
839 * capture or in error.
841 if (success && last_read_time > 0) {
842 /* Backdate these events to when they were requested */
843 counter_dump[len++] = 0;
844 counter_dump[len++] = last_read_time;
846 /* Cycle through hardware counters and accumulate totals */
847 for (cnt = 0; cnt < number_of_hardware_counters; cnt++) {
848 const struct mali_counter *counter = &counters[cnt];
850 if (counter->enabled)
851 len += read_counter(cnt, len, counter);
854 /* Restore the timestamp */
855 counter_dump[len++] = 0;
856 counter_dump[len++] = curr_time;
860 if (!kbase_device_busy) {
861 kbase_device_busy = true;
862 last_read_time = curr_time;
863 #if MALI_DDK_GATOR_API_VERSION == 3
864 kbase_gator_instr_hwcnt_dump_irq_symbol(handles);
866 kbase_instr_hwcnt_dump_irq_symbol(kbcontext);
870 /* Update the buffer */
872 *buffer = counter_dump;
877 static int create_files(struct super_block *sb, struct dentry *root)
881 * Create the filesystem for all events
883 for (event = 0; event < ARRAY_SIZE(mali_activity); event++) {
884 if (gator_mali_create_file_system("Midgard", mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0)
888 for (event = 0; event < number_of_hardware_counters; event++) {
889 if (gator_mali_create_file_system(mali_name, hardware_counter_names[event], sb, root, &counters[event], NULL) != 0)
896 static void shutdown(void)
898 #if MALI_DDK_GATOR_API_VERSION == 3
899 void (*kbase_gator_hwcnt_term_names_symbol)(void) = NULL;
906 #if MALI_DDK_GATOR_API_VERSION == 3
907 SYMBOL_GET(kbase_gator_hwcnt_term_names, error_count);
909 number_of_hardware_counters = -1;
910 hardware_counter_names = NULL;
911 if (kbase_gator_hwcnt_term_names_symbol != NULL) {
912 kbase_gator_hwcnt_term_names_symbol();
913 pr_debug("gator: Released symbols\n");
916 SYMBOL_CLEANUP(kbase_gator_hwcnt_term_names);
920 static struct gator_interface gator_events_mali_midgard_interface = {
921 .name = "mali_midgard_hw",
922 .shutdown = shutdown,
923 .create_files = create_files,
929 int gator_events_mali_midgard_hw_init(void)
931 #if MALI_DDK_GATOR_API_VERSION == 3
932 const char *const *(*kbase_gator_hwcnt_init_names_symbol)(uint32_t *) = NULL;
936 pr_debug("gator: Mali-Midgard: sw_counters init\n");
939 test_all_is_read_scheduled();
942 #if MALI_DDK_GATOR_API_VERSION == 3
943 SYMBOL_GET(kbase_gator_hwcnt_init_names, error_count);
944 if (error_count > 0) {
945 SYMBOL_CLEANUP(kbase_gator_hwcnt_init_names);
949 number_of_hardware_counters = -1;
950 hardware_counter_names = kbase_gator_hwcnt_init_names_symbol(&number_of_hardware_counters);
952 SYMBOL_CLEANUP(kbase_gator_hwcnt_init_names);
954 if ((hardware_counter_names == NULL) || (number_of_hardware_counters <= 0)) {
955 pr_err("gator: Error reading hardware counters names: got %d names\n", number_of_hardware_counters);
959 mali_name = "Midgard";
962 counters = kmalloc(sizeof(*counters)*number_of_hardware_counters, GFP_KERNEL);
963 counter_dump = kmalloc(sizeof(*counter_dump)*number_of_hardware_counters*2 + 4, GFP_KERNEL);
965 gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity));
966 gator_mali_initialise_counters(counters, number_of_hardware_counters);
968 return gator_events_install(&gator_events_mali_midgard_interface);