ARM: perf: updates for 3.2
Subsystems (3)
cover ARM: perf: updates for 3.2
Hello,
This patch series contains a number of updates to the ARM PMU and perf code so that we can support mode exclusion, which is new in debug architecture 7.1 (as implemented by the Cortex-A15). Some of these updates also coincide with work to support System PMUs (PMUs that are not affine to a single CPU) but that is a larger body of work which will be posted separately at a later date.
The patches do the following:
1.) Greatly simplify the PMU reservation mechanism so that the
handling of platform_devices is moved into perf.
2.) Cleans up the interrupt registration and some of the types used
to represent events and registers.
3.) Moves event indexing to start from zero rather than one, making
the code more readable and also easier to extend for mode exclusion.
4.) Adds support for mode exclusion (user / kernel / hyp) and
implements this for Cortex-A15.
I've been running these patches since 3.0, so they've been tested on 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
Once again, all feedback is welcome.
Will
Mark Rutland (1):
ARM: perf: de-const struct arm_pmu
Will Deacon (9):
ARM: PMU: move CPU PMU platform device handling and init into perf
ARM: perf: use cpumask_t to record active IRQs
ARM: perf: use u32 instead of unsigned long for PMNC register
ARM: perf: use integers for ARMv7 event indices
ARM: perf: index ARMv7 event counters starting from zero
ARM: perf: index Xscale and ARMv6 event counters starting from zero
ARM: perf: index PMU registers from zero
ARM: perf: allow armpmu to implement mode exclusion
ARM: perf: add mode exclusion for Cortex-A15 PMU
arch/arm/include/asm/pmu.h | 39 +--- arch/arm/kernel/perf_event.c | 176 ++++++++++++------- arch/arm/kernel/perf_event_v6.c | 16 +- arch/arm/kernel/perf_event_v7.c | 327 ++++++++++++++++------------------- arch/arm/kernel/perf_event_xscale.c | 18 +- arch/arm/kernel/pmu.c | 181 +------------------ 6 files changed, 302 insertions(+), 455 deletions(-)
PATCH 1/10 ARM: perf: de-const struct arm_pmu
From: Mark Rutland <[email protected]>
This patch removes const qualifiers from instances of struct arm_pmu, and functions initialising them, in preparation for generalising arm_pmu usage to system (AKA uncore) PMUs.
This will allow for dynamically modifiable structures (locks, struct pmu) to be added as members of struct arm_pmu.
--- arch/arm/kernel/perf_event.c | 2 +- arch/arm/kernel/perf_event_v6.c | 12 ++++++------ arch/arm/kernel/perf_event_v7.c | 16 ++++++++-------- arch/arm/kernel/perf_event_xscale.c | 12 ++++++------ 4 files changed, 21 insertions(+), 21 deletions(-)
arch/arm/kernel/perf_event.c +1 -1
@@ -90,7 +90,7 @@ struct arm_pmu { };/* Set at runtime when we know what CPU type we are. */ -static const struct arm_pmu *armpmu; +static struct arm_pmu *armpmu;enum arm_perf_pmu_ids armpmu_get_pmu_id (void )
arch/arm/kernel/perf_event_v6.c +6 -6
@@ -635,7 +635,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,raw_spin_unlock_irqrestore (&pmu_lock, flags); } -static const struct arm_pmu armv6pmu = { +static struct arm_pmu armv6pmu = { .id =ARM_PERF_PMU_ID_V6 , .name ="v6" , .handle_irq = armv6pmu_handle_irq,
@@ -653,7 +653,7 @@ static const struct arm_pmu armv6pmu = { .max_period = (1LLU << 32) - 1, }; -static const struct arm_pmu *__init armv6pmu_init (void ) +static struct arm_pmu *__init armv6pmu_init (void ) {return &armv6pmu; }
@@ -665,7 +665,7 @@ static const struct arm_pmu *__init armv6pmu_init(void)* disable the interrupt reporting and update the event. When unthrottling we * reset the period and enable the interrupt reporting. */ -static const struct arm_pmu armv6mpcore_pmu = { +static struct arm_pmu armv6mpcore_pmu = { .id =ARM_PERF_PMU_ID_V6MP , .name ="v6mpcore" , .handle_irq = armv6pmu_handle_irq,
@@ -683,17 +683,17 @@ static const struct arm_pmu armv6mpcore_pmu = { .max_period = (1LLU << 32) - 1, }; -static const struct arm_pmu *__init armv6mpcore_pmu_init (void ) +static struct arm_pmu *__init armv6mpcore_pmu_init (void ) {return &armv6mpcore_pmu; }#else -static const struct arm_pmu *__init armv6pmu_init (void ) +static struct arm_pmu *__init armv6pmu_init (void ) {return NULL ; } -static const struct arm_pmu *__init armv6mpcore_pmu_init (void ) +static struct arm_pmu *__init armv6mpcore_pmu_init (void ) {return NULL ; }
arch/arm/kernel/perf_event_v7.c +8 -8
@@ -1188,7 +1188,7 @@ static u32 __init armv7_read_num_pmnc_events(void)return nb_cnt +1 ; } -static const struct arm_pmu *__init armv7_a8_pmu_init (void ) +static struct arm_pmu *__init armv7_a8_pmu_init (void ) { armv7pmu.id =ARM_PERF_PMU_ID_CA8 ; armv7pmu.name ="ARMv7 Cortex-A8" ;
@@ -1198,7 +1198,7 @@ static const struct arm_pmu *__init armv7_a8_pmu_init(void)return &armv7pmu; } -static const struct arm_pmu *__init armv7_a9_pmu_init (void ) +static struct arm_pmu *__init armv7_a9_pmu_init (void ) { armv7pmu.id =ARM_PERF_PMU_ID_CA9 ; armv7pmu.name ="ARMv7 Cortex-A9" ;
@@ -1208,7 +1208,7 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void)return &armv7pmu; } -static const struct arm_pmu *__init armv7_a5_pmu_init (void ) +static struct arm_pmu *__init armv7_a5_pmu_init (void ) { armv7pmu.id =ARM_PERF_PMU_ID_CA5 ; armv7pmu.name ="ARMv7 Cortex-A5" ;
@@ -1218,7 +1218,7 @@ static const struct arm_pmu *__init armv7_a5_pmu_init(void)return &armv7pmu; } -static const struct arm_pmu *__init armv7_a15_pmu_init (void ) +static struct arm_pmu *__init armv7_a15_pmu_init (void ) { armv7pmu.id =ARM_PERF_PMU_ID_CA15 ; armv7pmu.name ="ARMv7 Cortex-A15" ;
@@ -1228,22 +1228,22 @@ static const struct arm_pmu *__init armv7_a15_pmu_init(void) return &armv7pmu; }#else -static const struct arm_pmu *__init armv7_a8_pmu_init (void ) +static struct arm_pmu *__init armv7_a8_pmu_init (void ) {return NULL ; } -static const struct arm_pmu *__init armv7_a9_pmu_init (void ) +static struct arm_pmu *__init armv7_a9_pmu_init (void ) {return NULL ; } -static const struct arm_pmu *__init armv7_a5_pmu_init (void ) +static struct arm_pmu *__init armv7_a5_pmu_init (void ) {return NULL ; } -static const struct arm_pmu *__init armv7_a15_pmu_init (void ) +static struct arm_pmu *__init armv7_a15_pmu_init (void ) {return NULL ; }
arch/arm/kernel/perf_event_xscale.c +6 -6
@@ -424,7 +424,7 @@ xscale1pmu_write_counter(int counter, u32 val) } } -static const struct arm_pmu xscale1pmu = { +static struct arm_pmu xscale1pmu = { .id =ARM_PERF_PMU_ID_XSCALE1 , .name ="xscale1" , .handle_irq = xscale1pmu_handle_irq,
@@ -442,7 +442,7 @@ static const struct arm_pmu xscale1pmu = { .max_period = (1LLU << 32) - 1, }; -static const struct arm_pmu *__init xscale1pmu_init (void ) +static struct arm_pmu *__init xscale1pmu_init (void ) {return &xscale1pmu; }
@@ -786,7 +786,7 @@ xscale2pmu_write_counter(int counter, u32 val) } } -static const struct arm_pmu xscale2pmu = { +static struct arm_pmu xscale2pmu = { .id =ARM_PERF_PMU_ID_XSCALE2 , .name ="xscale2" , .handle_irq = xscale2pmu_handle_irq,
@@ -804,17 +804,17 @@ static const struct arm_pmu xscale2pmu = { .max_period = (1LLU << 32) - 1, }; -static const struct arm_pmu *__init xscale2pmu_init (void ) +static struct arm_pmu *__init xscale2pmu_init (void ) {return &xscale2pmu; }#else -static const struct arm_pmu *__init xscale1pmu_init (void ) +static struct arm_pmu *__init xscale1pmu_init (void ) {return NULL ; } -static const struct arm_pmu *__init xscale2pmu_init (void ) +static struct arm_pmu *__init xscale2pmu_init (void ) {return NULL ; }
Signature · 1 line
1.7.0.4
PATCH 2/10 ARM: PMU: move CPU PMU platform device handling and init into perf
In reply to Will DeaconOnce upon a time, OProfile and Perf fought hard over who could play with the PMU. To stop all hell from breaking loose, pmu.c offered an internal reserve/release API and took care of parsing PMU platform data passed in from board support code.
Now that Perf has ingested OProfile, let's move the platform device handling into the Perf driver and out of the PMU locking code. Unfortunately, the lock has to remain to prevent Perf being bitten by out-of-tree modules such as LTTng, which still claim a right to the PMU when Perf isn't looking.
--- arch/arm/include/asm/pmu.h | 39 +++------- arch/arm/kernel/perf_event.c | 74 ++++++++++++++--- arch/arm/kernel/pmu.c | 181 ++---------------------------------------- 3 files changed, 80 insertions(+), 214 deletions(-)
arch/arm/include/asm/pmu.h +10 -29
@@ -14,6 +14,10 @@#include <linux/interrupt.h> +/* +* Types of PMUs that can be accessed directly and require mutual +* exclusion between profiling tools. +*/ enum arm_pmu_type {ARM_PMU_DEVICE_CPU =0 ,ARM_NUM_PMU_DEVICES ,
@@ -37,54 +41,31 @@ struct arm_pmu_platdata {* reserve_pmu() - reserve the hardware performance counters * * Reserve the hardware performance counters in the system for exclusive use. -* The platform_device for the system is returned on success, ERR_PTR() -* encoded error on failure. +* Returns 0 on success or -EBUSY if the lock is already held. */ -extern struct platform_device * +extern int reserve_pmu (enum arm_pmu_type device);/** * release_pmu() - Relinquish control of the performance counters * * Release the performance counters and allow someone else to use them. -* Callers must have disabled the counters and released IRQs before calling -* this. The platform_device returned from reserve_pmu() must be passed as -* a cookie. */ -extern int +extern void release_pmu (enum arm_pmu_type type); -/** -* init_pmu() - Initialise the PMU. -* -* Initialise the system ready for PMU enabling. This should typically set the -* IRQ affinity and nothing else. The users (oprofile/perf events etc) will do -* the actual hardware initialisation. -*/ -extern int -init_pmu (enum arm_pmu_type device); -#else /* CONFIG_CPU_HAS_PMU */ #include <linux/err.h> -static inline struct platform_device * -reserve_pmu (enum arm_pmu_type device) -{ -return ERR_PTR (-ENODEV ); -} -static inline int -release_pmu (struct platform_device *pdev) +reserve_pmu (enum arm_pmu_type device) {return -ENODEV ; } -static inline int -init_pmu (enum arm_pmu_type device) -{ -return -ENODEV ; -} +static inline void +release_pmu (struct platform_device *pdev) { }#endif /* CONFIG_CPU_HAS_PMU */
arch/arm/kernel/perf_event.c +62 -12
119 lines not on this page · raw message
arch/arm/kernel/pmu.c +8 -173
200 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH 3/10 ARM: perf: use cpumask_t to record active IRQs
In reply to Will DeaconCommit 5dfc54e0 ("ARM: GIC: avoid routing interrupts to offline CPUs") prevents the GIC from setting the affinity of an IRQ to a CPU with id >= nr_cpu_ids. This was previously abused by perf on some platforms where more IRQs were registered than possible CPUs.
This patch fixes the problem by using a cpumask_t to keep track of the active (requested) interrupts in perf. The same effect could be achieved by limiting the number of IRQs to the number of CPUs, but using a mask instead will be useful for adding extended CPU hotplug support in the future.
--- arch/arm/kernel/perf_event.c | 64 ++++++++++++++++++++--------------------- 1 files changed, 31 insertions(+), 33 deletions(-)
arch/arm/kernel/perf_event.c +31 -33
@@ -69,6 +69,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);struct arm_pmu {enum arm_perf_pmu_ids id; +cpumask_t active_irqs;const char *name;irqreturn_t (*handle_irq)(int irq_num,void *dev);void (*enable)(struct hw_perf_event *evt,int idx);
@@ -388,6 +389,25 @@ static irqreturn_t armpmu_platform_irq(int irq, void *dev)return plat->handle_irq (irq, dev, armpmu->handle_irq); } +static void +armpmu_release_hardware (void ) +{ +int i, irq, irqs; + + irqs =min (pmu_device->num_resources,num_possible_cpus ()); + +for (i =0 ; i < irqs; ++i) { +if (!cpumask_test_and_clear_cpu (i, &armpmu->active_irqs)) +continue ; + irq =platform_get_irq (pmu_device, i); +if (irq >=0 ) +free_irq (irq,NULL ); + } + + armpmu->stop (); +release_pmu (ARM_PMU_DEVICE_CPU ); +} +static int armpmu_reserve_hardware (void ) {
@@ -401,20 +421,20 @@ armpmu_reserve_hardware(void)return err; } - irqs = pmu_device->num_resources; - plat =dev_get_platdata (&pmu_device->dev);if (plat && plat->handle_irq) handle_irq = armpmu_platform_irq;else handle_irq = armpmu->handle_irq; + irqs =min (pmu_device->num_resources,num_possible_cpus ());if (irqs <1 ) {pr_err ("no irqs for PMUs defined\n" );return -ENODEV ; }for (i =0 ; i < irqs; ++i) { + err =0 ; irq =platform_get_irq (pmu_device, i);if (irq <0 )continue ;
@@ -422,13 +442,12 @@ armpmu_reserve_hardware(void)/* * If we have a single PMU interrupt that we can't shift, * assume that we're running on a uniprocessor machine and -* continue. +* continue. Otherwise, continue without this interrupt. */ - err =irq_set_affinity (irq,cpumask_of (i)); -if (err && irqs >1 ) { -pr_err ("unable to set irq affinity (irq=%d, cpu=%u)\n" , - irq, i); -break ; +if (irq_set_affinity (irq,cpumask_of (i)) && irqs >1 ) { +pr_warning ("unable to set irq affinity (irq=%d, cpu=%u)\n" , + irq, i); +continue ; } err = request_irq(irq, handle_irq,
@@ -437,35 +456,14 @@ armpmu_reserve_hardware(void)if (err) {pr_err ("unable to request IRQ%d for ARM PMU counters\n" , irq); -break ; +armpmu_release_hardware (); +return err; } - } -if (err) { -for (i = i -1 ; i >=0 ; --i) { - irq =platform_get_irq (pmu_device, i); -if (irq >=0 ) -free_irq (irq,NULL ); - } -release_pmu (ARM_PMU_DEVICE_CPU ); +cpumask_set_cpu (i, &armpmu->active_irqs); } -return err; -} - -static void -armpmu_release_hardware (void ) -{ -int i, irq; - -for (i = pmu_device->num_resources -1 ; i >=0 ; --i) { - irq =platform_get_irq (pmu_device, i); -if (irq >=0 ) -free_irq (irq,NULL ); - } - armpmu->stop (); - -release_pmu (ARM_PMU_DEVICE_CPU ); +return 0 ; }static atomic_t active_events =ATOMIC_INIT (0 );
Signature · 1 line
1.7.0.4
PATCH 4/10 ARM: perf: use u32 instead of unsigned long for PMNC register
In reply to Will DeaconThe ARMv7 perf backend mixes up u32 and unsigned long, which is rather ugly.
This patch makes the ARMv7 PMU code consistently use the u32 type instead.
--- arch/arm/kernel/perf_event_v7.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
arch/arm/kernel/perf_event_v7.c +6 -6
@@ -758,26 +758,26 @@ enum armv7_counters {#define ARMV7_FLAG_MASK 0xffffffff/* Mask for writable bits */ #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK -static inline unsigned long armv7_pmnc_read (void ) +static inline u32 armv7_pmnc_read (void ) {u32 val; asmvolatile ("mrc p15, 0, %0, c9, c12, 0" :"=r" (val));return val; } -static inline void armv7_pmnc_write (unsigned long val) +static inline void armv7_pmnc_write (u32 val) { val &=ARMV7_PMNC_MASK ;isb (); asmvolatile ("mcr p15, 0, %0, c9, c12, 0" : :"r" (val)); } -static inline int armv7_pmnc_has_overflowed (unsigned long pmnc) +static inline int armv7_pmnc_has_overflowed (u32 pmnc) {return pmnc &ARMV7_OVERFLOWED_MASK ; } -static inline int armv7_pmnc_counter_has_overflowed (unsigned long pmnc, +static inline int armv7_pmnc_counter_has_overflowed (u32 pmnc,enum armv7_counters counter) {int ret =0 ;
@@ -812,7 +812,7 @@ static inline int armv7_pmnc_select_counter(unsigned int idx)static inline u32 armv7pmu_read_counter (int idx) { -unsigned long value =0 ; +u32 value =0 ;if (idx ==ARMV7_CYCLE_COUNTER ) asmvolatile ("mrc p15, 0, %0, c9, c13, 0" :"=r" (value));
@@ -1044,7 +1044,7 @@ static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)static irqreturn_t armv7pmu_handle_irq (int irq_num,void *dev) { -unsigned long pmnc; +u32 pmnc;struct perf_sample_data data;struct cpu_hw_events *cpuc;struct pt_regs *regs;
Signature · 1 line
1.7.0.4
PATCH 5/10 ARM: perf: use integers for ARMv7 event indices
In reply to Will DeaconThis patch ensures that integers are used to represent event indices in the ARMv7 PMU backend. This ensures consistency between functions and also with the arm_pmu structure.
--- arch/arm/kernel/perf_event_v7.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
arch/arm/kernel/perf_event_v7.c +6 -6
@@ -793,7 +793,7 @@ static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc,return ret; } -static inline int armv7_pmnc_select_counter (unsigned int idx) +static inline int armv7_pmnc_select_counter (int idx) {u32 val;
@@ -840,7 +840,7 @@ static inline void armv7pmu_write_counter(int idx, u32 value) smp_processor_id(), idx); } -static inline void armv7_pmnc_write_evtsel (unsigned int idx,u32 val) +static inline void armv7_pmnc_write_evtsel (int idx,u32 val) {if (armv7_pmnc_select_counter (idx) == idx) { val &=ARMV7_EVTSEL_MASK ;
@@ -848,7 +848,7 @@ static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val) } } -static inline u32 armv7_pmnc_enable_counter (unsigned int idx) +static inline int armv7_pmnc_enable_counter (int idx) {u32 val;
@@ -869,7 +869,7 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int idx)return idx; } -static inline u32 armv7_pmnc_disable_counter (unsigned int idx) +static inline int armv7_pmnc_disable_counter (int idx) {u32 val;
@@ -891,7 +891,7 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int idx)return idx; } -static inline u32 armv7_pmnc_enable_intens (unsigned int idx) +static inline int armv7_pmnc_enable_intens (int idx) {u32 val;
@@ -912,7 +912,7 @@ static inline u32 armv7_pmnc_enable_intens(unsigned int idx)return idx; } -static inline u32 armv7_pmnc_disable_intens (unsigned int idx) +static inline int armv7_pmnc_disable_intens (int idx) {u32 val;
Signature · 1 line
1.7.0.4
PATCH 6/10 ARM: perf: index ARMv7 event counters starting from zero
In reply to Will DeaconThe current ARMv7 PMU backend indexes event counters from two, with index zero being reserved and index one being used to represent the cycle counter.
This patch tidies up the code by indexing from one instead (with zero for the cycle counter). This allows us to remove many of the accessor macros along with the counter enumeration and makes the code much more readable.
--- arch/arm/kernel/perf_event_v7.c | 239 ++++++++++++++------------------------ 1 files changed, 88 insertions(+), 151 deletions(-)
arch/arm/kernel/perf_event_v7.c +88 -151
@@ -676,23 +676,24 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] };/* -* Perf Events counters +* Perf Events' indices */ -enum armv7_counters { -ARMV7_CYCLE_COUNTER =1 ,/* Cycle counter */ -ARMV7_COUNTER0 =2 ,/* First event counter */ -}; +#define ARMV7_IDX_CYCLE_COUNTER 0 +#define ARMV7_IDX_COUNTER0 1 +#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + armpmu->num_events - 1) + +#define ARMV7_MAX_COUNTERS 32 +#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)/* -* The cycle counter is ARMV7_CYCLE_COUNTER. -* The first event counter is ARMV7_COUNTER0. -* The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1). +* ARMv7 low level PMNC access */ -#define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1)/* -* ARMv7 low level PMNC access +* Perf Event to low level counters mapping */ +#define ARMV7_IDX_TO_COUNTER (x) \ + (((x) - ARMV7_IDX_COUNTER0) & ARMV7_COUNTER_MASK)/* * Per-CPU PMNC: config reg
@@ -708,53 +709,13 @@ enum armv7_counters {#define ARMV7_PMNC_MASK 0x3f/* Mask for writable bits */ /* -* Available counters -*/ -#define ARMV7_CNT0 0/* First event counter */ -#define ARMV7_CCNT 31/* Cycle counter */ - -/* Perf Event to low level counters mapping */ -#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0) - -/* -* CNTENS: counters enable reg -*/ -#define ARMV7_CNTENS_P (idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) -#define ARMV7_CNTENS_C (1 << ARMV7_CCNT) - -/* -* CNTENC: counters disable reg -*/ -#define ARMV7_CNTENC_P (idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) -#define ARMV7_CNTENC_C (1 << ARMV7_CCNT) - -/* -* INTENS: counters overflow interrupt enable reg -*/ -#define ARMV7_INTENS_P (idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) -#define ARMV7_INTENS_C (1 << ARMV7_CCNT) - -/* -* INTENC: counters overflow interrupt disable reg -*/ -#define ARMV7_INTENC_P (idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) -#define ARMV7_INTENC_C (1 << ARMV7_CCNT) - -/* * EVTSEL: Event selection reg */ #define ARMV7_EVTSEL_MASK 0xff/* Mask for writable bits */ /* -* SELECT: Counter selection reg -*/ -#define ARMV7_SELECT_MASK 0x1f/* Mask for writable bits */ - -/* * FLAG: counters overflow flag status reg */ -#define ARMV7_FLAG_P (idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx)) -#define ARMV7_FLAG_C (1 << ARMV7_CCNT)#define ARMV7_FLAG_MASK 0xffffffff/* Mask for writable bits */ #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
@@ -777,34 +738,39 @@ static inline int armv7_pmnc_has_overflowed(u32 pmnc)return pmnc &ARMV7_OVERFLOWED_MASK ; } -static inline int armv7_pmnc_counter_has_overflowed (u32 pmnc, -enum armv7_counters counter) +static inline int armv7_pmnc_counter_valid (int idx) +{ +return idx >=ARMV7_IDX_CYCLE_COUNTER && idx <=ARMV7_IDX_COUNTER_LAST ; +} + +static inline int armv7_pmnc_counter_has_overflowed (u32 pmnc,int idx) {int ret =0 ; +u32 counter; -if (counter ==ARMV7_CYCLE_COUNTER ) - ret = pmnc &ARMV7_FLAG_C ; -else if ((counter >=ARMV7_COUNTER0 ) && (counter <=ARMV7_COUNTER_LAST )) - ret = pmnc &ARMV7_FLAG_P (counter); -else +if (!armv7_pmnc_counter_valid (idx)) {pr_err ("CPU%u checking wrong counter %d overflow status\n" , -smp_processor_id (), counter); +smp_processor_id (), idx); + }else { + counter =ARMV7_IDX_TO_COUNTER (idx); + ret = pmnc &BIT (counter); + }return ret; }static inline int armv7_pmnc_select_counter (int idx) { -u32 val; +u32 counter; -if ((idx <ARMV7_COUNTER0 ) || (idx >ARMV7_COUNTER_LAST )) { -pr_err ("CPU%u selecting wrong PMNC counter" -" %d\n" ,smp_processor_id (), idx); -return -1 ; +if (!armv7_pmnc_counter_valid (idx)) { +pr_err ("CPU%u selecting wrong PMNC counter %d\n" , +smp_processor_id (), idx); +return -EINVAL ; } - val = (idx - ARMV7_EVENT_CNT_TO_CNTx) &ARMV7_SELECT_MASK ; - asmvolatile ("mcr p15, 0, %0, c9, c12, 5" : :"r" (val)); + counter =ARMV7_IDX_TO_COUNTER (idx); + asmvolatile ("mcr p15, 0, %0, c9, c12, 5" : :"r" (counter));isb ();return idx;
@@ -814,30 +780,26 @@ static inline u32 armv7pmu_read_counter(int idx) {u32 value =0 ; -if (idx ==ARMV7_CYCLE_COUNTER ) - asmvolatile ("mrc p15, 0, %0, c9, c13, 0" :"=r" (value)); -else if ((idx >=ARMV7_COUNTER0 ) && (idx <=ARMV7_COUNTER_LAST )) { -if (armv7_pmnc_select_counter (idx) == idx) - asmvolatile ("mrc p15, 0, %0, c9, c13, 2" - :"=r" (value)); - }else +if (!armv7_pmnc_counter_valid (idx))pr_err ("CPU%u reading wrong counter %d\n" ,smp_processor_id (), idx); +else if (idx ==ARMV7_IDX_CYCLE_COUNTER ) + asmvolatile ("mrc p15, 0, %0, c9, c13, 0" :"=r" (value)); +else if (armv7_pmnc_select_counter (idx) == idx) + asmvolatile ("mrc p15, 0, %0, c9, c13, 2" :"=r" (value));return value; }static inline void armv7pmu_write_counter (int idx,u32 value) { -if (idx ==ARMV7_CYCLE_COUNTER ) - asmvolatile ("mcr p15, 0, %0, c9, c13, 0" : :"r" (value)); -else if ((idx >=ARMV7_COUNTER0 ) && (idx <=ARMV7_COUNTER_LAST )) { -if (armv7_pmnc_select_counter (idx) == idx) - asmvolatile ("mcr p15, 0, %0, c9, c13, 2" - : :"r" (value)); - }else +if (!armv7_pmnc_counter_valid (idx))pr_err ("CPU%u writing wrong counter %d\n" ,smp_processor_id (), idx); +else if (idx ==ARMV7_IDX_CYCLE_COUNTER ) + asmvolatile ("mcr p15, 0, %0, c9, c13, 0" : :"r" (value)); +else if (armv7_pmnc_select_counter (idx) == idx) + asmvolatile ("mcr p15, 0, %0, c9, c13, 2" : :"r" (value)); }static inline void armv7_pmnc_write_evtsel (int idx,u32 val)
@@ -850,86 +812,61 @@ static inline void armv7_pmnc_write_evtsel(int idx, u32 val)static inline int armv7_pmnc_enable_counter (int idx) { -u32 val; +u32 counter; -if ((idx !=ARMV7_CYCLE_COUNTER ) && - ((idx <ARMV7_COUNTER0 ) || (idx >ARMV7_COUNTER_LAST ))) { -pr_err ("CPU%u enabling wrong PMNC counter" -" %d\n" ,smp_processor_id (), idx); -return -1 ; +if (!armv7_pmnc_counter_valid (idx)) { +pr_err ("CPU%u enabling wrong PMNC counter %d\n" , +smp_processor_id (), idx); +return -EINVAL ; } -if (idx ==ARMV7_CYCLE_COUNTER ) - val =ARMV7_CNTENS_C ; -else - val =ARMV7_CNTENS_P (idx); - - asmvolatile ("mcr p15, 0, %0, c9, c12, 1" : :"r" (val)); - + counter =ARMV7_IDX_TO_COUNTER (idx); + asmvolatile ("mcr p15, 0, %0, c9, c12, 1" : :"r" (BIT (counter)));return idx; }static inline int armv7_pmnc_disable_counter (int idx) { -u32 val; +u32 counter; - -if ((idx !=ARMV7_CYCLE_COUNTER ) && - ((idx <ARMV7_COUNTER0 ) || (idx >ARMV7_COUNTER_LAST ))) { -pr_err ("CPU%u disabling wrong PMNC counter" -" %d\n" ,smp_processor_id (), idx); -return -1 ; +if (!armv7_pmnc_counter_valid (idx)) { +pr_err ("CPU%u disabling wrong PMNC counter %d\n" , +smp_processor_id (), idx); +return -EINVAL ; } -if (idx ==ARMV7_CYCLE_COUNTER ) - val =ARMV7_CNTENC_C ; -else - val =ARMV7_CNTENC_P (idx); - - asmvolatile ("mcr p15, 0, %0, c9, c12, 2" : :"r" (val)); - + counter =ARMV7_IDX_TO_COUNTER (idx); + asmvolatile ("mcr p15, 0, %0, c9, c12, 2" : :"r" (BIT (counter)));return idx; }static inline int armv7_pmnc_enable_intens (int idx) { -u32 val; +u32 counter; -if ((idx !=ARMV7_CYCLE_COUNTER ) && - ((idx <ARMV7_COUNTER0 ) || (idx >ARMV7_COUNTER_LAST ))) { -pr_err ("CPU%u enabling wrong PMNC counter" -" interrupt enable %d\n" ,smp_processor_id (), idx); -return -1 ; +if (!armv7_pmnc_counter_valid (idx)) { +pr_err ("CPU%u enabling wrong PMNC counter IRQ enable %d\n" , +smp_processor_id (), idx); +return -EINVAL ; } -if (idx ==ARMV7_CYCLE_COUNTER ) - val =ARMV7_INTENS_C ; -else - val =ARMV7_INTENS_P (idx); - - asmvolatile ("mcr p15, 0, %0, c9, c14, 1" : :"r" (val)); - + counter =ARMV7_IDX_TO_COUNTER (idx); + asmvolatile ("mcr p15, 0, %0, c9, c14, 1" : :"r" (BIT (counter)));return idx; }static inline int armv7_pmnc_disable_intens (int idx) { -u32 val; +u32 counter; -if ((idx !=ARMV7_CYCLE_COUNTER ) && - ((idx <ARMV7_COUNTER0 ) || (idx >ARMV7_COUNTER_LAST ))) { -pr_err ("CPU%u disabling wrong PMNC counter" -" interrupt enable %d\n" ,smp_processor_id (), idx); -return -1 ; +if (!armv7_pmnc_counter_valid (idx)) { +pr_err ("CPU%u disabling wrong PMNC counter IRQ enable %d\n" , +smp_processor_id (), idx); +return -EINVAL ; } -if (idx ==ARMV7_CYCLE_COUNTER ) - val =ARMV7_INTENC_C ; -else - val =ARMV7_INTENC_P (idx); - - asmvolatile ("mcr p15, 0, %0, c9, c14, 2" : :"r" (val)); - + counter =ARMV7_IDX_TO_COUNTER (idx); + asmvolatile ("mcr p15, 0, %0, c9, c14, 2" : :"r" (BIT (counter)));return idx; }
@@ -973,14 +910,14 @@ static void armv7_pmnc_dump_regs(void) asmvolatile ("mrc p15, 0, %0, c9, c13, 0" :"=r" (val));printk (KERN_INFO "CCNT =0x%08x\n" , val); -for (cnt =ARMV7_COUNTER0 ; cnt <ARMV7_COUNTER_LAST ; cnt++) { +for (cnt =ARMV7_IDX_COUNTER0 ; cnt <=ARMV7_IDX_COUNTER_LAST ; cnt++) {armv7_pmnc_select_counter (cnt); asmvolatile ("mrc p15, 0, %0, c9, c13, 2" :"=r" (val));printk (KERN_INFO "CNT[%d] count =0x%08x\n" , - cnt-ARMV7_EVENT_CNT_TO_CNTx, val); +ARMV7_IDX_TO_COUNTER (cnt), val); asmvolatile ("mrc p15, 0, %0, c9, c13, 1" :"=r" (val));printk (KERN_INFO "CNT[%d] evtsel=0x%08x\n" , - cnt-ARMV7_EVENT_CNT_TO_CNTx, val); +ARMV7_IDX_TO_COUNTER (cnt), val); } }#endif
@@ -1004,7 +941,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)* Set event (if destined for PMNx counters) * We don't need to set the event if it's a cycle count */ -if (idx !=ARMV7_CYCLE_COUNTER ) +if (idx !=ARMV7_IDX_CYCLE_COUNTER )armv7_pmnc_write_evtsel (idx, hwc->config_base);/*
@@ -1069,7 +1006,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)perf_sample_data_init (&data,0 ); cpuc = &__get_cpu_var (cpu_hw_events); -for (idx =0 ; idx <= armpmu->num_events; ++idx) { +for (idx =0 ; idx < armpmu->num_events; ++idx) {struct perf_event *event = cpuc->events[idx];struct hw_perf_event *hwc;
@@ -1132,23 +1069,23 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,/* Always place a cycle counter into the cycle counter. */ if (event->config_base ==ARMV7_PERFCTR_CPU_CYCLES ) { -if (test_and_set_bit (ARMV7_CYCLE_COUNTER , cpuc->used_mask)) +if (test_and_set_bit (ARMV7_IDX_CYCLE_COUNTER , cpuc->used_mask))return -EAGAIN ; -return ARMV7_CYCLE_COUNTER ; - }else { -/* -* For anything other than a cycle counter, try and use -* the events counters -*/ -for (idx =ARMV7_COUNTER0 ; idx <= armpmu->num_events; ++idx) { -if (!test_and_set_bit (idx, cpuc->used_mask)) -return idx; - } +return ARMV7_IDX_CYCLE_COUNTER ; + } -/* The counters are all in use. */ -return -EAGAIN ; +/* +* For anything other than a cycle counter, try and use +* the events counters +*/ +for (idx =ARMV7_IDX_COUNTER0 ; idx < armpmu->num_events; ++idx) { +if (!test_and_set_bit (idx, cpuc->used_mask)) +return idx; } + +/* The counters are all in use. */ +return -EAGAIN ; }static void armv7pmu_reset (void *info)
@@ -1156,7 +1093,7 @@ static void armv7pmu_reset(void *info)u32 idx, nb_cnt = armpmu->num_events;/* The counter and interrupt enable registers are unknown at reset. */ -for (idx =1 ; idx < nb_cnt; ++idx) +for (idx =ARMV7_IDX_CYCLE_COUNTER ; idx < nb_cnt; ++idx)armv7pmu_disable_event (NULL , idx);/* Initialize & Reset PMNC: C and P bits */
Signature · 1 line
1.7.0.4
PATCH 7/10 ARM: perf: index Xscale and ARMv6 event counters starting from zero
In reply to Will DeaconNow that the ARMv7 PMU backend indexes event counters from zero, follow suit and do the same for ARMv6 and Xscale.
--- arch/arm/kernel/perf_event_v6.c | 4 ++-- arch/arm/kernel/perf_event_xscale.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm/kernel/perf_event_v6.c +2 -2
@@ -54,7 +54,7 @@ enum armv6_perf_types { };enum armv6_counters { -ARMV6_CYCLE_COUNTER =1 , +ARMV6_CYCLE_COUNTER =0 ,ARMV6_COUNTER0 ,ARMV6_COUNTER1 , };
@@ -487,7 +487,7 @@ armv6pmu_handle_irq(int irq_num,perf_sample_data_init (&data,0 ); cpuc = &__get_cpu_var (cpu_hw_events); -for (idx =0 ; idx <= armpmu->num_events; ++idx) { +for (idx =0 ; idx < armpmu->num_events; ++idx) {struct perf_event *event = cpuc->events[idx];struct hw_perf_event *hwc;
arch/arm/kernel/perf_event_xscale.c +3 -3
@@ -40,7 +40,7 @@ enum xscale_perf_types { };enum xscale_counters { -XSCALE_CYCLE_COUNTER =1 , +XSCALE_CYCLE_COUNTER =0 ,XSCALE_COUNTER0 ,XSCALE_COUNTER1 ,XSCALE_COUNTER2 ,
@@ -249,7 +249,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev)perf_sample_data_init (&data,0 ); cpuc = &__get_cpu_var (cpu_hw_events); -for (idx =0 ; idx <= armpmu->num_events; ++idx) { +for (idx =0 ; idx < armpmu->num_events; ++idx) {struct perf_event *event = cpuc->events[idx];struct hw_perf_event *hwc;
@@ -581,7 +581,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev)perf_sample_data_init (&data,0 ); cpuc = &__get_cpu_var (cpu_hw_events); -for (idx =0 ; idx <= armpmu->num_events; ++idx) { +for (idx =0 ; idx < armpmu->num_events; ++idx) {struct perf_event *event = cpuc->events[idx];struct hw_perf_event *hwc;
Signature · 1 line
1.7.0.4
PATCH 8/10 ARM: perf: index PMU registers from zero
In reply to Will DeaconARM PMU code used to use 1-based indices for PMU registers. This caused several data structures (pmu_hw_events::{active_events, used_mask, events}) to have an unused element at index zero. ARMPMU_MAX_HWEVENTS still takes this indexing into account, and currently equates to 33.
This patch updates the core ARM perf code to use the 0th index again.
--- arch/arm/kernel/perf_event.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
arch/arm/kernel/perf_event.c +3 -3
@@ -35,7 +35,7 @@ static struct platform_device *pmu_device;static DEFINE_RAW_SPINLOCK (pmu_lock);/* -* ARMv6 supports a maximum of 3 events, starting from index 1. If we add +* ARMv6 supports a maximum of 3 events, starting from index 0. If we add * another platform that supports more, we need to increase this to be the * largest of all platforms. *
@@ -43,7 +43,7 @@ static DEFINE_RAW_SPINLOCK(pmu_lock);* cycle counter CCNT + 31 events counters CNT0..30. * Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters. */ -#define ARMPMU_MAX_HWEVENTS 33 +#define ARMPMU_MAX_HWEVENTS 32/* The events for a given CPU. */ struct cpu_hw_events {
@@ -597,7 +597,7 @@ static void armpmu_enable(struct pmu *pmu)if (!armpmu)return ; -for (idx =0 ; idx <= armpmu->num_events; ++idx) { +for (idx =0 ; idx < armpmu->num_events; ++idx) {struct perf_event *event = cpuc->events[idx];if (!event)
Signature · 1 line
1.7.0.4
PATCH 9/10 ARM: perf: allow armpmu to implement mode exclusion
In reply to Will DeaconModern PMUs allow for mode exclusion, so we no longer wish to return -EPERM if it is requested.
This patch provides a hook in the armpmu structure for implementing mode exclusion. The hw_perf_event initialisation is slightly delayed so that the backend code can update the structure if required.
--- arch/arm/kernel/perf_event.c | 44 +++++++++++++++++++++++------------------ 1 files changed, 25 insertions(+), 19 deletions(-)
arch/arm/kernel/perf_event.c +25 -19
@@ -76,6 +76,8 @@ struct arm_pmu {void (*disable)(struct hw_perf_event *evt,int idx);int (*get_event_idx)(struct cpu_hw_events *cpuc,struct hw_perf_event *hwc); +int (*set_event_filter)(struct hw_perf_event *evt, +struct perf_event_attr *attr);u32 (*read_counter)(int idx);void (*write_counter)(int idx,u32 val);void (*start)(void );
@@ -479,6 +481,13 @@ hw_perf_event_destroy(struct perf_event *event) }static int +event_requires_mode_exclusion (struct perf_event_attr *attr) +{ +return attr->exclude_idle || attr->exclude_user || + attr->exclude_kernel || attr->exclude_hv; +} + +static int __hw_perf_event_init (struct perf_event *event) {struct hw_perf_event *hwc = &event->hw;
@@ -503,34 +512,31 @@ __hw_perf_event_init(struct perf_event *event) }/* +* We don't assign an index until we actually place the event onto +* hardware. Use -1 to signify that we haven't decided where to put it +* yet. For SMP systems, each core has it's own PMU so we can't do any +* clever allocation or constraints checking at this point. +*/ + hwc->idx =-1 ; + hwc->config_base =0 ; + hwc->config =0 ; + hwc->event_base =0 ; + +/* * Check whether we need to exclude the counter from certain modes. -* The ARM performance counters are on all of the time so if someone -* has asked us for some excludes then we have to fail. */ -if (event->attr.exclude_kernel || event->attr.exclude_user || - event->attr.exclude_hv || event->attr.exclude_idle) { +if ((!armpmu->set_event_filter || + armpmu->set_event_filter (hwc, &event->attr)) && +event_requires_mode_exclusion (&event->attr)) {pr_debug ("ARM performance counters do not support " "mode exclusion\n" );return -EPERM ; }/* -* We don't assign an index until we actually place the event onto -* hardware. Use -1 to signify that we haven't decided where to put it -* yet. For SMP systems, each core has it's own PMU so we can't do any -* clever allocation or constraints checking at this point. -*/ - hwc->idx =-1 ; - -/* -* Store the event encoding into the config_base field. config and -* event_base are unused as the only 2 things we need to know are -* the event mapping and the counter to use. The counter to use is -* also the indx and the config_base is the event type. +* Store the event encoding into the config_base field. */ - hwc->config_base = (unsigned long )mapping; - hwc->config =0 ; - hwc->event_base =0 ; + hwc->config_base |= (unsigned long )mapping;if (!hwc->sample_period) { hwc->sample_period = armpmu->max_period;
Signature · 1 line
1.7.0.4
PATCH 10/10 ARM: perf: add mode exclusion for Cortex-A15 PMU
In reply to Will DeaconThe Cortex-A15 PMU implements the PMUv2 specification and therefore has support for some mode exclusion.
This patch adds support for excluding user, kernel and hypervisor counts from a given event.
--- arch/arm/kernel/perf_event_v7.c | 58 +++++++++++++++++++++++++++++++++------ 1 files changed, 49 insertions(+), 9 deletions(-)
arch/arm/kernel/perf_event_v7.c +49 -9
@@ -17,6 +17,9 @@*/ #ifdef CONFIG_CPU_V7 + +static struct arm_pmu armv7pmu; +/* * Common ARMv7 event types *
@@ -709,16 +712,24 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]#define ARMV7_PMNC_MASK 0x3f/* Mask for writable bits */ /* -* EVTSEL: Event selection reg -*/ -#define ARMV7_EVTSEL_MASK 0xff/* Mask for writable bits */ - -/* * FLAG: counters overflow flag status reg */ #define ARMV7_FLAG_MASK 0xffffffff/* Mask for writable bits */ #define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK +/* +* PMXEVTYPER: Event selection reg +*/ +#define ARMV7_EVTYPE_MASK 0xc00000ff/* Mask for writable bits */ +#define ARMV7_EVTYPE_EVENT 0xff/* Mask for EVENT bits */ + +/* +* Event filters for PMUv2 +*/ +#define ARMV7_EXCLUDE_PL1 (1 << 31) +#define ARMV7_EXCLUDE_USER (1 << 30) +#define ARMV7_INCLUDE_HYP (1 << 27) +static inline u32 armv7_pmnc_read (void ) {u32 val;
@@ -805,7 +816,7 @@ static inline void armv7pmu_write_counter(int idx, u32 value)static inline void armv7_pmnc_write_evtsel (int idx,u32 val) {if (armv7_pmnc_select_counter (idx) == idx) { - val &=ARMV7_EVTSEL_MASK ; + val &=ARMV7_EVTYPE_MASK ; asmvolatile ("mcr p15, 0, %0, c9, c13, 1" : :"r" (val)); } }
@@ -939,9 +950,10 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)/* * Set event (if destined for PMNx counters) -* We don't need to set the event if it's a cycle count +* We only need to set the event for the cycle counter if we +* have the ability to perform event filtering. */ -if (idx !=ARMV7_IDX_CYCLE_COUNTER ) +if (armv7pmu.set_event_filter || idx !=ARMV7_IDX_CYCLE_COUNTER )armv7_pmnc_write_evtsel (idx, hwc->config_base);/*
@@ -1066,9 +1078,10 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *event) {int idx; +unsigned long evtype = event->config_base &ARMV7_EVTYPE_EVENT ;/* Always place a cycle counter into the cycle counter. */ -if (event->config_base ==ARMV7_PERFCTR_CPU_CYCLES ) { +if (evtype ==ARMV7_PERFCTR_CPU_CYCLES ) {if (test_and_set_bit (ARMV7_IDX_CYCLE_COUNTER , cpuc->used_mask))return -EAGAIN ;
@@ -1088,6 +1101,32 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,return -EAGAIN ; } +/* +* Add an event filter to a given event. This will only work for PMUv2 PMUs. +*/ +static int armv7pmu_set_event_filter (struct hw_perf_event *event, +struct perf_event_attr *attr) +{ +unsigned long config_base =0 ; + +if (attr->exclude_idle) +return -EPERM ; +if (attr->exclude_user) + config_base |=ARMV7_EXCLUDE_USER ; +if (attr->exclude_kernel) + config_base |=ARMV7_EXCLUDE_PL1 ; +if (!attr->exclude_hv) + config_base |=ARMV7_INCLUDE_HYP ; + +/* +* Install the filter into config_base as this is used to +* construct the event type. +*/ + event->config_base = config_base; + +return 0 ; +} +static void armv7pmu_reset (void *info) {u32 idx, nb_cnt = armpmu->num_events;
@@ -1162,6 +1201,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) armv7pmu.cache_map = &armv7_a15_perf_cache_map; armv7pmu.event_map = &armv7_a15_perf_map; armv7pmu.num_events =armv7_read_num_pmnc_events (); + armv7pmu.set_event_filter = armv7pmu_set_event_filter; return &armv7pmu; }#else
Signature · 1 line
1.7.0.4
A message that is not in the archive (sent off-list or not yet received): CAKHPGBZ1eXzhsjFvLt_KTYKsR_OH7rgbeSGedTY5g8dhi90uzQ@mail.gmail.com
PATCH 10/10 ARM: perf: add mode exclusion for Cortex-A15 PMU
Hey Will,
Quoted 10 lines
From: Will Deacon <[email protected]>
The Cortex-A15 PMU implements the PMUv2 specification and therefore has support for some mode exclusion.
This patch adds support for excluding user, kernel and hypervisor counts from a given event.
Signed-off-by Will Deacon <[email protected]>---
--8<---
arch/arm/kernel/perf_event_v7.c static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] · line 732
Quoted 8 lines
arch/arm/kernel/perf_event_v7.c +8
-0+ +/* +* Event filters for PMUv2 +*/ +#define ARMV7_EXCLUDE_PL1 (1 << 31) +#define ARMV7_EXCLUDE_USER (1 << 30) +#define ARMV7_INCLUDE_HYP (1 << 27) +
This mode exclusion stuff is confusing me.
For exclude user mode, shouldn't PMXEVTYPER[PL1,U] = 0b11
With this patch the counters will spin with secure mode activity as well, if exclude user mode is selected ?
/me goes to bother the h/w guys.
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 10/10 ARM: perf: add mode exclusion for Cortex-A15 PMU
Quoted 1 line · Ashwin Chaugule
Hey Will,
Hi Ashwin,
Quoted 14 lines
Quoted 10 lines
From: Will Deacon <[email protected]>
The Cortex-A15 PMU implements the PMUv2 specification and therefore has support for some mode exclusion.
This patch adds support for excluding user, kernel and hypervisor counts from a given event.
Signed-off-by Will Deacon <[email protected]>---
--8<---
Quoted 10 lines
arch/arm/kernel/perf_event_v7.c static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] · line 732
Quoted 8 lines
arch/arm/kernel/perf_event_v7.c +8
-0+ +/* +* Event filters for PMUv2 +*/ +#define ARMV7_EXCLUDE_PL1 (1 << 31) +#define ARMV7_EXCLUDE_USER (1 << 30) +#define ARMV7_INCLUDE_HYP (1 << 27) +This mode exclusion stuff is confusing me.
I'm not surprised, the wording is pretty hard to follow in the documentation.
Quoted 1 line
For exclude user mode, shouldn't PMXEVTYPER[PL1,U] = 0b11
No - this is a reserved encoding and results in the counters stopping for *all* modes!
Quoted 2 lines
With this patch the counters will spin with secure mode activity as well, if exclude user mode is selected ?
Yes, but they won't tick for either secure or non-secure user-mode, which is what we want. Note that secure software can stop the counters ticking by messing with the SDER.
Quoted 1 line
/me goes to bother the h/w guys.
Bah, they deserve it :)
Will
cover ARM: perf: updates for 3.2
In reply to Will DeaconHi Will,
Quoted 21 lines · Will Deacon
Hello,
This patch series contains a number of updates to the ARM PMU and perf code so that we can support mode exclusion, which is new in debug architecture 7.1 (as implemented by the Cortex-A15). Some of these updates also coincide with work to support System PMUs (PMUs that are not affine to a single CPU) but that is a larger body of work which will be posted separately at a later date.
The patches do the following:
1.) Greatly simplify the PMU reservation mechanism so that the
handling ofplatform_devicesis moved into perf.
2.) Cleans up the interrupt registration and some of the types used
to represent events and registers.
3.) Moves event indexing to start from zero rather than one, making
the code more readable and also easier to extend for mode exclusion.
4.) Adds support for mode exclusion (user / kernel / hyp) and
implements this for Cortex-A15.
Quoted 2 lines
I've been running these patches since 3.0, so they've been tested on 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
A quick glance through them and they all look nice to me, but I can't get them to apply to any tree (next and master). It looks like they're based on a tree with changes to the v7 perf support so I'm guessing it's your patches with A15 support.
Jamie
cover ARM: perf: updates for 3.2
Quoted 1 line · Jamie Iles
Hi Will,
Hi Jamie,
Quoted 22 lines · Will Deacon
Quoted 21 lines
Hello,
This patch series contains a number of updates to the ARM PMU and perf code so that we can support mode exclusion, which is new in debug architecture 7.1 (as implemented by the Cortex-A15). Some of these updates also coincide with work to support System PMUs (PMUs that are not affine to a single CPU) but that is a larger body of work which will be posted separately at a later date.
The patches do the following:
1.) Greatly simplify the PMU reservation mechanism so that the
handling ofplatform_devicesis moved into perf.
2.) Cleans up the interrupt registration and some of the types used
to represent events and registers.
3.) Moves event indexing to start from zero rather than one, making
the code more readable and also easier to extend for mode exclusion.
4.) Adds support for mode exclusion (user / kernel / hyp) and
implements this for Cortex-A15.
Quoted 7 lines
Quoted 2 lines
I've been running these patches since 3.0, so they've been tested on 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
A quick glance through them and they all look nice to me, but I can't get them to apply to any tree (next and master). It looks like they're based on a tree with changes to the v7 perf support so I'm guessing it's your patches with A15 support.
Thanks for taking a look. The patches should just apply against -rc1:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Cheers,
Will
cover ARM: perf: updates for 3.2
Quoted 30 lines · Will Deacon
Quoted 1 line · Jamie Iles
Hi Will,
Hi Jamie,
Quoted 25 lines · Will Deacon
Quoted 23 lines
Hello,
This patch series contains a number of updates to the ARM PMU and perf code so that we can support mode exclusion, which is new in debug architecture 7.1 (as implemented by the Cortex-A15). Some of these updates also coincide with work to support System PMUs (PMUs that are not affine to a single CPU) but that is a larger body of work which will be posted separately at a later date.
The patches do the following:
1.) Greatly simplify the PMU reservation mechanism so that the
handling ofplatform_devicesis moved into perf.
2.) Cleans up the interrupt registration and some of the types used
to represent events and registers.
3.) Moves event indexing to start from zero rather than one, making
the code more readable and also easier to extend for mode exclusion.
4.) Adds support for mode exclusion (user / kernel / hyp) and
implements this for Cortex-A15.I've been running these patches since 3.0, so they've been tested on 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
Quoted 8 lines
Quoted 4 lines
A quick glance through them and they all look nice to me, but I can't get them to apply to any tree (next and master). It looks like they're based on a tree with changes to the v7 perf support so I'm guessing it's your patches with A15 support.
Thanks for taking a look. The patches should just apply against -rc1:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Yes, you're quite right. I seem to have lost patches 1 and 4. Probably finger trouble on my part!
Anyhow, I've pulled from your git tree and they appear to work nicely, so:
Jamie
cover ARM: perf: updates for 3.2
Quoted 5 lines · Jamie Iles
Quoted 3 lines · Will Deacon
Thanks for taking a look. The patches should just apply against -rc1:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Quoted 7 lines
Yes, you're quite right. I seem to have lost patches 1 and 4. Probably finger trouble on my part!
Anyhow, I've pulled from your git tree and they appear to work nicely, so:
Acked-by Jamie Iles <[email protected]>
Thanks a lot Jamie, I'll update that branch with your acks.
Will
cover ARM: perf: updates for 3.2
Hi Will,
I had a review of the patches and they all look all good to me. Although [06/10] is not easy to look at it seems correct and indeed the resulting code is easier to read.
Not tested though, sorry ;(
Feel free to add:
Thanks!
Jean
Quoted 23 lines · Will Deacon
Quoted 5 lines · Jamie Iles
Quoted 3 lines · Will Deacon
Thanks for taking a look. The patches should just apply against -rc1:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Quoted 7 lines
Yes, you're quite right. ?I seem to have lost patches 1 and 4. ?Probably finger trouble on my part!
Anyhow, I've pulled from your git tree and they appear to work nicely, so:
Acked-by Jamie Iles <[email protected]>Thanks a lot Jamie, I'll update that branch with your acks.
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
cover ARM: perf: updates for 3.2
Quoted 1 line · Jean Pihet
Hi Will,
Hello,
Quoted 4 lines
I had a review of the patches and they all look all good to me. Although [06/10] is not easy to look at it seems correct and indeed the resulting code is easier to read.
Not tested though, sorry ;(
Thanks for having a look. If you do get a chance to test, please let me know how you get on.
Quoted 2 lines
Feel free to add:
Reviewed-by Jean Pihet <[email protected]>
Will do, cheers.
Will