From 5f00d7115f1aec2fff250e496150813a624a9f65 Mon Sep 17 00:00:00 2001 From: Igor Nabirushkin Date: Thu, 5 Jun 2014 09:10:47 +0400 Subject: [PATCH] misc: tegra-profiler: get perfmon extension Add version of the ARMv8 NVIDIA perfmon extension to device capabilities. Bug 1520757 Change-Id: I18d10133272a10e3faf5022b4579c7dfea78791e Signed-off-by: Igor Nabirushkin Reviewed-on: http://git-master/r/419274 (cherry picked from commit 1973fe595ad0fc5ec45e65df3c70ffbeaac94e7e) Reviewed-on: http://git-master/r/454453 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Tested-by: Maxim Morin Reviewed-by: Mitch Luban --- drivers/misc/tegra-profiler/arm_pmu.h | 12 ++++- drivers/misc/tegra-profiler/armv7_pmu.c | 34 ++++++++---- drivers/misc/tegra-profiler/armv8_events.h | 7 ++- drivers/misc/tegra-profiler/armv8_pmu.c | 61 +++++++++++++++++----- drivers/misc/tegra-profiler/quadd.h | 2 + drivers/misc/tegra-profiler/quadd_proc.c | 16 +++++- drivers/misc/tegra-profiler/version.h | 2 +- 7 files changed, 105 insertions(+), 29 deletions(-) diff --git a/drivers/misc/tegra-profiler/arm_pmu.h b/drivers/misc/tegra-profiler/arm_pmu.h index b0d139a9488..6071c469fe8 100644 --- a/drivers/misc/tegra-profiler/arm_pmu.h +++ b/drivers/misc/tegra-profiler/arm_pmu.h @@ -28,9 +28,17 @@ struct quadd_pmu_event_info { struct list_head list; }; +#define QUADD_ARCH_NAME_MAX 64 + +struct quadd_arch_info { + int type; + int ver; + + char name[QUADD_ARCH_NAME_MAX]; +}; + struct quadd_pmu_ctx { - int arch; - char arch_name[64]; + struct quadd_arch_info arch; u32 counters_mask; diff --git a/drivers/misc/tegra-profiler/armv7_pmu.c b/drivers/misc/tegra-profiler/armv7_pmu.c index 97ccb65255b..1962a3ea0ba 100644 --- a/drivers/misc/tegra-profiler/armv7_pmu.c +++ b/drivers/misc/tegra-profiler/armv7_pmu.c @@ -301,8 +301,8 @@ static u32 armv7_pmu_adjust_value(u32 value, int event_id) * so currently we are devided by two */ if (pmu_ctx.l1_cache_rw && - (pmu_ctx.arch == QUADD_ARM_CPU_TYPE_CORTEX_A8 || - pmu_ctx.arch == QUADD_ARM_CPU_TYPE_CORTEX_A9) && + (pmu_ctx.arch.type == QUADD_ARM_CPU_TYPE_CORTEX_A8 || + pmu_ctx.arch.type == QUADD_ARM_CPU_TYPE_CORTEX_A9) && (event_id == QUADD_EVENT_TYPE_L1_DCACHE_READ_MISSES || event_id == QUADD_EVENT_TYPE_L1_DCACHE_WRITE_MISSES)) { return value / 2; @@ -722,6 +722,11 @@ static int get_current_events(int *events, int max_events) return i; } +static struct quadd_arch_info *get_arch(void) +{ + return &pmu_ctx.arch; +} + static struct quadd_event_source_interface pmu_armv7_int = { .enable = pmu_enable, .disable = pmu_disable, @@ -737,6 +742,7 @@ static struct quadd_event_source_interface pmu_armv7_int = { .set_events = set_events, .get_supported_events = get_supported_events, .get_current_events = get_current_events, + .get_arch = get_arch, }; struct quadd_event_source_interface *quadd_armv7_pmu_init(void) @@ -748,11 +754,18 @@ struct quadd_event_source_interface *quadd_armv7_pmu_init(void) cpu_implementer = cpu_id >> 24; part_number = cpu_id & 0xFFF0; + pmu_ctx.arch.type = QUADD_ARM_CPU_TYPE_UNKNOWN; + pmu_ctx.arch.ver = 0; + strncpy(pmu_ctx.arch.name, "Unknown", + sizeof(pmu_ctx.arch.name)); + if (cpu_implementer == ARM_CPU_IMP_ARM) { switch (part_number) { case ARM_CPU_PART_CORTEX_A9: - pmu_ctx.arch = QUADD_ARM_CPU_TYPE_CORTEX_A9; - strcpy(pmu_ctx.arch_name, "Cortex A9"); + pmu_ctx.arch.type = QUADD_ARM_CPU_TYPE_CORTEX_A9; + strncpy(pmu_ctx.arch.name, "Cortex A9", + sizeof(pmu_ctx.arch.name)); + pmu_ctx.counters_mask = QUADD_ARMV7_COUNTERS_MASK_CORTEX_A9; pmu_ctx.current_map = quadd_armv7_a9_events_map; @@ -760,8 +773,10 @@ struct quadd_event_source_interface *quadd_armv7_pmu_init(void) break; case ARM_CPU_PART_CORTEX_A15: - pmu_ctx.arch = QUADD_ARM_CPU_TYPE_CORTEX_A15; - strcpy(pmu_ctx.arch_name, "Cortex A15"); + pmu_ctx.arch.type = QUADD_ARM_CPU_TYPE_CORTEX_A15; + strncpy(pmu_ctx.arch.name, "Cortex A15", + sizeof(pmu_ctx.arch.name)); + pmu_ctx.counters_mask = QUADD_ARMV7_COUNTERS_MASK_CORTEX_A15; pmu_ctx.current_map = quadd_armv7_a15_events_map; @@ -769,8 +784,7 @@ struct quadd_event_source_interface *quadd_armv7_pmu_init(void) break; default: - pmu_ctx.arch = QUADD_ARM_CPU_TYPE_UNKNOWN; - strcpy(pmu_ctx.arch_name, "Unknown"); + pmu_ctx.arch.type = QUADD_ARM_CPU_TYPE_UNKNOWN; pmu_ctx.current_map = NULL; break; } @@ -778,7 +792,9 @@ struct quadd_event_source_interface *quadd_armv7_pmu_init(void) INIT_LIST_HEAD(&pmu_ctx.used_events); - pr_info("arch: %s\n", pmu_ctx.arch_name); + pmu_ctx.arch.name[sizeof(pmu_ctx.arch.name) - 1] = '\0'; + pr_info("arch: %s, type: %d, ver: %d\n", + pmu_ctx.arch.name, pmu_ctx.arch.type, pmu_ctx.arch.ver); return pmu; } diff --git a/drivers/misc/tegra-profiler/armv8_events.h b/drivers/misc/tegra-profiler/armv8_events.h index e5fcf080c91..1d675ddddab 100644 --- a/drivers/misc/tegra-profiler/armv8_events.h +++ b/drivers/misc/tegra-profiler/armv8_events.h @@ -52,11 +52,11 @@ enum { #define QUADD_ARMV8_PMCR_LC (1 << 6) /* Number of event counters */ -#define QUADD_ARMV8_PMCR_N_SHIFT 16 +#define QUADD_ARMV8_PMCR_N_SHIFT 11 #define QUADD_ARMV8_PMCR_N_MASK 0x1f /* Identification code */ -#define QUADD_ARMV8_PMCR_IDCODE_SHIFT 11 +#define QUADD_ARMV8_PMCR_IDCODE_SHIFT 16 #define QUADD_ARMV8_PMCR_IDCODE_MASK 0xff /* Implementer code */ @@ -81,6 +81,9 @@ enum { #define QUADD_ARMV8_COUNTERS_MASK_PMUV3 0x3f +#define QUADD_ARMV8_PMU_NVEXT_SHIFT 4 +#define QUADD_ARMV8_PMU_NVEXT_MASK 0x0f + /* * ARMv8 PMUv3 Performance Events handling code. * Common event types. diff --git a/drivers/misc/tegra-profiler/armv8_pmu.c b/drivers/misc/tegra-profiler/armv8_pmu.c index 9bc8eb232b6..7a4ffc17079 100644 --- a/drivers/misc/tegra-profiler/armv8_pmu.c +++ b/drivers/misc/tegra-profiler/armv8_pmu.c @@ -219,9 +219,15 @@ armv8_pmu_pmovsclr_write(int idx) asm volatile("msr pmovsclr_el0, %0" : : "r" (BIT(idx))); } -/*********************************************************************/ - +static inline u32 +armv8_id_afr0_el1_read(void) +{ + u32 val; + /* Read Auxiliary Feature Register 0 */ + asm volatile("mrs %0, id_afr0_el1" : "=r" (val)); + return val; +} static void enable_counter(int idx) { @@ -710,7 +716,10 @@ static int get_current_events(int *events, int max_events) return i; } -/*********************************************************************/ +static struct quadd_arch_info *get_arch(void) +{ + return &pmu_ctx.arch; +} static struct quadd_event_source_interface pmu_armv8_int = { .enable = pmu_enable, @@ -727,6 +736,7 @@ static struct quadd_event_source_interface pmu_armv8_int = { .set_events = set_events, .get_supported_events = get_supported_events, .get_current_events = get_current_events, + .get_arch = get_arch, }; struct quadd_event_source_interface *quadd_armv8_pmu_init(void) @@ -737,11 +747,16 @@ struct quadd_event_source_interface *quadd_armv8_pmu_init(void) u64 aa64_dfr = read_cpuid(ID_AA64DFR0_EL1); aa64_dfr = (aa64_dfr >> 8) & 0x0f; - pmu_ctx.arch = QUADD_AA64_CPU_TYPE_UNKNOWN; + strncpy(pmu_ctx.arch.name, "Unknown", sizeof(pmu_ctx.arch.name)); + pmu_ctx.arch.type = QUADD_AA64_CPU_TYPE_UNKNOWN; + pmu_ctx.arch.ver = 0; switch (aa64_dfr) { case QUADD_AA64_PMUVER_PMUV3: - strcpy(pmu_ctx.arch_name, "AA64 PmuV3"); + strncpy(pmu_ctx.arch.name, "AA64 PmuV3", + sizeof(pmu_ctx.arch.name)); + pmu_ctx.arch.name[sizeof(pmu_ctx.arch.name) - 1] = '\0'; + pmu_ctx.counters_mask = QUADD_ARMV8_COUNTERS_MASK_PMUV3; pmu_ctx.current_map = quadd_armv8_pmuv3_events_map; @@ -755,19 +770,35 @@ struct quadd_event_source_interface *quadd_armv8_pmu_init(void) pr_info("imp: %#x, idcode: %#x\n", imp, idcode); if (imp == ARM_CPU_IMP_ARM) { - strcat(pmu_ctx.arch_name, " ARM"); + strncat(pmu_ctx.arch.name, " ARM", + sizeof(pmu_ctx.arch.name) - + strlen(pmu_ctx.arch.name)); + pmu_ctx.arch.name[sizeof(pmu_ctx.arch.name) - 1] = '\0'; + if (idcode == QUADD_AA64_CPU_IDCODE_CORTEX_A57) { - pmu_ctx.arch = QUADD_AA64_CPU_TYPE_CORTEX_A57; - strcat(pmu_ctx.arch_name, " CORTEX_A57"); + pmu_ctx.arch.type = + QUADD_AA64_CPU_TYPE_CORTEX_A57; + strncat(pmu_ctx.arch.name, " CORTEX_A57", + sizeof(pmu_ctx.arch.name) - + strlen(pmu_ctx.arch.name)); } else { - pmu_ctx.arch = QUADD_AA64_CPU_TYPE_ARM; + pmu_ctx.arch.type = QUADD_AA64_CPU_TYPE_ARM; } } else if (imp == QUADD_AA64_CPU_IMP_NVIDIA) { - strcat(pmu_ctx.arch_name, " Nvidia"); - pmu_ctx.arch = QUADD_AA64_CPU_TYPE_DENVER; + u32 ext_ver = armv8_id_afr0_el1_read(); + ext_ver = (ext_ver >> QUADD_ARMV8_PMU_NVEXT_SHIFT) & + QUADD_ARMV8_PMU_NVEXT_MASK; + + strncat(pmu_ctx.arch.name, " NVIDIA (Denver)", + sizeof(pmu_ctx.arch.name) - + strlen(pmu_ctx.arch.name)); + pmu_ctx.arch.type = QUADD_AA64_CPU_TYPE_DENVER; + pmu_ctx.arch.ver = ext_ver; } else { - strcat(pmu_ctx.arch_name, " Unknown"); - pmu_ctx.arch = QUADD_AA64_CPU_TYPE_UNKNOWN_IMP; + strncat(pmu_ctx.arch.name, " Unknown implementor code", + sizeof(pmu_ctx.arch.name) - + strlen(pmu_ctx.arch.name)); + pmu_ctx.arch.type = QUADD_AA64_CPU_TYPE_UNKNOWN_IMP; } pmu = &pmu_armv8_int; @@ -780,7 +811,9 @@ struct quadd_event_source_interface *quadd_armv8_pmu_init(void) INIT_LIST_HEAD(&pmu_ctx.used_events); - pr_info("arch: %s\n", pmu_ctx.arch_name); + pmu_ctx.arch.name[sizeof(pmu_ctx.arch.name) - 1] = '\0'; + pr_info("arch: %s, type: %d, ver: %d\n", + pmu_ctx.arch.name, pmu_ctx.arch.type, pmu_ctx.arch.ver); return pmu; } diff --git a/drivers/misc/tegra-profiler/quadd.h b/drivers/misc/tegra-profiler/quadd.h index 9de52c77372..c25835e29f0 100644 --- a/drivers/misc/tegra-profiler/quadd.h +++ b/drivers/misc/tegra-profiler/quadd.h @@ -25,6 +25,7 @@ struct event_data; struct quadd_comm_data_interface; struct quadd_hrt_ctx; struct quadd_module_state; +struct quadd_arch_info; struct quadd_event_source_interface { int (*enable)(void); @@ -35,6 +36,7 @@ struct quadd_event_source_interface { int (*set_events)(int *events, int size); int (*get_supported_events)(int *events, int max_events); int (*get_current_events)(int *events, int max_events); + struct quadd_arch_info * (*get_arch)(void); }; struct source_info { diff --git a/drivers/misc/tegra-profiler/quadd_proc.c b/drivers/misc/tegra-profiler/quadd_proc.c index b7993e8ac8e..8f656fae213 100644 --- a/drivers/misc/tegra-profiler/quadd_proc.c +++ b/drivers/misc/tegra-profiler/quadd_proc.c @@ -24,6 +24,7 @@ #include "quadd.h" #include "version.h" #include "quadd_proc.h" +#include "arm_pmu.h" #define YES_NO(x) ((x) ? "yes" : "no") @@ -58,6 +59,10 @@ static int show_capabilities(struct seq_file *f, void *offset) struct quadd_comm_cap *cap = &ctx->cap; struct quadd_events_cap *event = &cap->events_cap; unsigned int extra = cap->reserved[QUADD_COMM_CAP_IDX_EXTRA]; + struct quadd_arch_info *arch = NULL; + + if (ctx->pmu) + arch = ctx->pmu->get_arch(); seq_printf(f, "pmu: %s\n", YES_NO(cap->pmu)); @@ -69,7 +74,7 @@ static int show_capabilities(struct seq_file *f, void *offset) seq_printf(f, "l2 cache: %s\n", YES_NO(cap->l2_cache)); if (cap->l2_cache) { - seq_printf(f, "multiple l2 events: %s\n", + seq_printf(f, "multiple l2 events: %s\n", YES_NO(cap->l2_multiple_events)); } @@ -92,6 +97,15 @@ static int show_capabilities(struct seq_file *f, void *offset) seq_printf(f, "information about unwind entry: %s\n", YES_NO(extra & QUADD_COMM_CAP_EXTRA_UNW_ENTRY_TYPE)); + seq_puts(f, "\n"); + + if (arch) { + seq_printf(f, "pmu arch: %s\n", + arch->name); + seq_printf(f, "pmu arch version: %d\n", + arch->ver); + } + seq_puts(f, "\n"); seq_puts(f, "Supported events:\n"); seq_printf(f, "cpu_cycles: %s\n", diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h index 779dc6b5ac4..392ea70b7a9 100644 --- a/drivers/misc/tegra-profiler/version.h +++ b/drivers/misc/tegra-profiler/version.h @@ -18,7 +18,7 @@ #ifndef __QUADD_VERSION_H #define __QUADD_VERSION_H -#define QUADD_MODULE_VERSION "1.71" +#define QUADD_MODULE_VERSION "1.72" #define QUADD_MODULE_BRANCH "Dev" #endif /* __QUADD_VERSION_H */ -- 2.39.2