diff options
author | Drew Richardson <drew.richardson@arm.com> | 2011-09-30 12:00:00 -0700 |
---|---|---|
committer | Drew Richardson <drew.richardson@arm.com> | 2014-12-19 15:16:17 -0800 |
commit | c5f78695067d4614bcb494d5f54bde4405c43609 (patch) | |
tree | 5413ee61289c45be1917e93852d491aa1f778087 /driver/gator_events_armv7.c | |
parent | 73158f9d05b7087bb6ff895e820017af3c94a1a6 (diff) |
gator: Version 5.75.7
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
Diffstat (limited to 'driver/gator_events_armv7.c')
-rw-r--r-- | driver/gator_events_armv7.c | 186 |
1 files changed, 80 insertions, 106 deletions
diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c index 0f0d7ef..58855f8 100644 --- a/driver/gator_events_armv7.c +++ b/driver/gator_events_armv7.c @@ -6,129 +6,116 @@ * published by the Free Software Foundation. */ -#include "gator.h" - -#define CORTEX_A5 0xc05 -#define CORTEX_A8 0xc08 -#define CORTEX_A9 0xc09 -#define CORTEX_A15 0xc0f - -static const char *pmnc_name; -static int pmnc_count; - -// Per-CPU PMNC: config reg -#define PMNC_E (1 << 0) /* Enable all counters */ -#define PMNC_P (1 << 1) /* Reset all counters */ -#define PMNC_C (1 << 2) /* Cycle counter reset */ -#define PMNC_MASK 0x3f /* Mask for writable bits */ +/* Disabling interrupts + * Many of the functions below disable interrupts via local_irq_save(). This disabling of interrupts is done to prevent any race conditions + * between multiple entities (e.g. hrtimer interrupts and event based interrupts) calling the same functions. As accessing the pmu involves + * several steps (disable, select, read, enable), these steps must be performed atomically. Normal synchronization routines cannot be used + * as these functions are being called from interrupt context. + */ -// ccnt reg -#define CCNT_REG (1 << 31) +#include "gator.h" +#include "gator_events_armv7.h" -#define CCNT 0 -#define CNT0 1 -#define CNTMAX (6+1) +const char *pmnc_name; +int pmnc_counters; -static unsigned long pmnc_enabled[CNTMAX]; -static unsigned long pmnc_event[CNTMAX]; -static unsigned long pmnc_key[CNTMAX]; +unsigned long pmnc_enabled[CNTMAX]; +unsigned long pmnc_event[CNTMAX]; +unsigned long pmnc_count[CNTMAX]; +unsigned long pmnc_key[CNTMAX]; static DEFINE_PER_CPU(int[CNTMAX], perfPrev); static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); -static inline void armv7_pmnc_write(u32 val) +inline void armv7_pmnc_write(u32 val) { val &= PMNC_MASK; asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val)); } -static inline u32 armv7_pmnc_read(void) +inline u32 armv7_pmnc_read(void) { u32 val; asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); return val; } -static inline u32 armv7_ccnt_read(void) +inline u32 armv7_ccnt_read(u32 reset_value) { - u32 zero = 0; + unsigned long flags; + u32 newval = -reset_value; u32 den = CCNT_REG; u32 val; + local_irq_save(flags); asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read - asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (zero)); // zero + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval));// new value asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable + local_irq_restore(flags); return val; } -static inline u32 armv7_cntn_read(unsigned int cnt) +inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value) { - u32 zero = 0; + unsigned long flags; + u32 newval = -reset_value; u32 sel = (cnt - CNT0); u32 den = 1 << sel; - u32 val; + u32 oldval; + local_irq_save(flags); asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select - asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); // read - asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (zero)); // zero + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read + asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval));// new value asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable + local_irq_restore(flags); - return val; + return oldval; } -static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) +static inline void armv7_pmnc_enable_interrupt(unsigned int cnt) { - u32 val; + u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31); + asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val)); +} - if (cnt >= CNTMAX) { - pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt); - return -1; - } +static inline void armv7_pmnc_disable_interrupt(unsigned int cnt) +{ + u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31); + asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); +} - if (cnt == CCNT) - val = CCNT_REG; - else - val = (1 << (cnt - CNT0)); +inline u32 armv7_pmnc_reset_interrupt() +{ + // Get and reset overflow status flags + u32 flags; + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags)); + flags &= 0x8000003f; + asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags)); + return flags; +} +static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) +{ + u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); - return cnt; } static inline u32 armv7_pmnc_disable_counter(unsigned int cnt) { - u32 val; - - if (cnt >= CNTMAX) { - pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt); - return -1; - } - - if (cnt == CCNT) - val = CCNT_REG; - else - val = (1 << (cnt - CNT0)); - + u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); - return cnt; } static inline int armv7_pmnc_select_counter(unsigned int cnt) { - u32 val; - - if ((cnt == CCNT) || (cnt >= CNTMAX)) { - pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt); - return -1; - } - - val = (cnt - CNT0); + u32 val = (cnt - CNT0); asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); - return cnt; } @@ -139,37 +126,12 @@ static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val) } } -static void armv7_pmnc_reset_counter(unsigned int cnt) -{ - u32 val = 0; - - if (cnt == CCNT) { - armv7_pmnc_disable_counter(cnt); - - asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val)); - - if (pmnc_enabled[cnt] != 0) - armv7_pmnc_enable_counter(cnt); - - } else if (cnt >= CNTMAX) { - pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt); - } else { - armv7_pmnc_disable_counter(cnt); - - if (armv7_pmnc_select_counter(cnt) == cnt) - asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val)); - - if (pmnc_enabled[cnt] != 0) - armv7_pmnc_enable_counter(cnt); - } -} - static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root) { struct dentry *dir; int i; - for (i = 0; i < pmnc_count; i++) { + for (i = 0; i < pmnc_counters; i++) { char buf[40]; if (i == 0) { snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name); @@ -181,10 +143,11 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry return -1; } gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); + gatorfs_create_ulong(sb, dir, "count", &pmnc_count[i]); + gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); if (i > 0) { gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); } - gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); } return 0; @@ -202,6 +165,9 @@ static void gator_events_armv7_online(void) // Initialize & Reset PMNC: C bit and P bit armv7_pmnc_write(PMNC_P | PMNC_C); + // Reset overflow flags + armv7_pmnc_reset_interrupt(); + for (cnt = CCNT; cnt < CNTMAX; cnt++) { unsigned long event; @@ -219,10 +185,16 @@ static void gator_events_armv7_online(void) if (cnt != CCNT) armv7_pmnc_write_evtsel(cnt, event); + // Enable/disable interrupt + if (pmnc_count[cnt] > 0) + armv7_pmnc_enable_interrupt(cnt); + else + armv7_pmnc_disable_interrupt(cnt); + // Reset counter - armv7_pmnc_reset_counter(cnt); + cnt ? armv7_cntn_read(cnt, pmnc_count[cnt]) : armv7_ccnt_read(pmnc_count[cnt]); - // Enable counter, but do not enable interrupt for this counter + // Enable counter armv7_pmnc_enable_counter(cnt); } @@ -242,6 +214,7 @@ static void gator_events_armv7_stop(void) for (cnt = CCNT; cnt < CNTMAX; cnt++) { pmnc_enabled[cnt] = 0; pmnc_event[cnt] = 0; + pmnc_count[cnt] = 0; } } @@ -250,16 +223,16 @@ static int gator_events_armv7_read(int **buffer) int cnt, len = 0; int cpu = smp_processor_id(); - if (!pmnc_count) + if (!pmnc_counters) return 0; - for (cnt = 0; cnt < pmnc_count; cnt++) { - if (pmnc_enabled[cnt]) { + for (cnt = 0; cnt < pmnc_counters; cnt++) { + if (pmnc_enabled[cnt] && pmnc_count[cnt] == 0) { int value; if (cnt == CCNT) { - value = armv7_ccnt_read(); + value = armv7_ccnt_read(0); } else { - value = armv7_cntn_read(cnt); + value = armv7_cntn_read(cnt, 0); } if (value != per_cpu(perfPrev, cpu)[cnt]) { per_cpu(perfPrev, cpu)[cnt] = value; @@ -291,29 +264,30 @@ int gator_events_armv7_init(void) switch (gator_cpuid()) { case CORTEX_A5: pmnc_name = "Cortex-A5"; - pmnc_count = 2; + pmnc_counters = 2; break; case CORTEX_A8: pmnc_name = "Cortex-A8"; - pmnc_count = 4; + pmnc_counters = 4; break; case CORTEX_A9: pmnc_name = "Cortex-A9"; - pmnc_count = 6; + pmnc_counters = 6; break; case CORTEX_A15: pmnc_name = "Cortex-A15"; - pmnc_count = 6; + pmnc_counters = 6; break; default: return -1; } - pmnc_count++; // CNT[n] + CCNT + pmnc_counters++; // CNT[n] + CCNT for (cnt = CCNT; cnt < CNTMAX; cnt++) { pmnc_enabled[cnt] = 0; pmnc_event[cnt] = 0; + pmnc_count[cnt] = 0; pmnc_key[cnt] = gator_events_get_key(); } |