diff options
Diffstat (limited to 'arch/arm/kernel/perf_event_v7.c')
| -rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 246 | 
1 files changed, 116 insertions, 130 deletions
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index bd4b090ebcf..7d0cce85d17 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -18,8 +18,6 @@  #ifdef CONFIG_CPU_V7 -static struct arm_pmu armv7pmu; -  /*   * Common ARMv7 event types   * @@ -738,7 +736,8 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]   */  #define	ARMV7_IDX_CYCLE_COUNTER	0  #define	ARMV7_IDX_COUNTER0	1 -#define	ARMV7_IDX_COUNTER_LAST	(ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1) +#define	ARMV7_IDX_COUNTER_LAST(cpu_pmu) \ +	(ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)  #define	ARMV7_MAX_COUNTERS	32  #define	ARMV7_COUNTER_MASK	(ARMV7_MAX_COUNTERS - 1) @@ -804,49 +803,34 @@ static inline int armv7_pmnc_has_overflowed(u32 pmnc)  	return pmnc & ARMV7_OVERFLOWED_MASK;  } -static inline int armv7_pmnc_counter_valid(int idx) +static inline int armv7_pmnc_counter_valid(struct arm_pmu *cpu_pmu, int idx)  { -	return idx >= ARMV7_IDX_CYCLE_COUNTER && idx <= ARMV7_IDX_COUNTER_LAST; +	return idx >= ARMV7_IDX_CYCLE_COUNTER && +		idx <= ARMV7_IDX_COUNTER_LAST(cpu_pmu);  }  static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)  { -	int ret = 0; -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u checking wrong counter %d overflow status\n", -			smp_processor_id(), idx); -	} else { -		counter = ARMV7_IDX_TO_COUNTER(idx); -		ret = pmnc & BIT(counter); -	} - -	return ret; +	return pmnc & BIT(ARMV7_IDX_TO_COUNTER(idx));  }  static inline int armv7_pmnc_select_counter(int idx)  { -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u selecting wrong PMNC counter %d\n", -			smp_processor_id(), idx); -		return -EINVAL; -	} - -	counter = ARMV7_IDX_TO_COUNTER(idx); +	u32 counter = ARMV7_IDX_TO_COUNTER(idx);  	asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));  	isb();  	return idx;  } -static inline u32 armv7pmu_read_counter(int idx) +static inline u32 armv7pmu_read_counter(struct perf_event *event)  { +	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); +	struct hw_perf_event *hwc = &event->hw; +	int idx = hwc->idx;  	u32 value = 0; -	if (!armv7_pmnc_counter_valid(idx)) +	if (!armv7_pmnc_counter_valid(cpu_pmu, idx))  		pr_err("CPU%u reading wrong counter %d\n",  			smp_processor_id(), idx);  	else if (idx == ARMV7_IDX_CYCLE_COUNTER) @@ -857,9 +841,13 @@ static inline u32 armv7pmu_read_counter(int idx)  	return value;  } -static inline void armv7pmu_write_counter(int idx, u32 value) +static inline void armv7pmu_write_counter(struct perf_event *event, u32 value)  { -	if (!armv7_pmnc_counter_valid(idx)) +	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); +	struct hw_perf_event *hwc = &event->hw; +	int idx = hwc->idx; + +	if (!armv7_pmnc_counter_valid(cpu_pmu, idx))  		pr_err("CPU%u writing wrong counter %d\n",  			smp_processor_id(), idx);  	else if (idx == ARMV7_IDX_CYCLE_COUNTER) @@ -878,60 +866,28 @@ static inline void armv7_pmnc_write_evtsel(int idx, u32 val)  static inline int armv7_pmnc_enable_counter(int idx)  { -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u enabling wrong PMNC counter %d\n", -			smp_processor_id(), idx); -		return -EINVAL; -	} - -	counter = ARMV7_IDX_TO_COUNTER(idx); +	u32 counter = ARMV7_IDX_TO_COUNTER(idx);  	asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter)));  	return idx;  }  static inline int armv7_pmnc_disable_counter(int idx)  { -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u disabling wrong PMNC counter %d\n", -			smp_processor_id(), idx); -		return -EINVAL; -	} - -	counter = ARMV7_IDX_TO_COUNTER(idx); +	u32 counter = ARMV7_IDX_TO_COUNTER(idx);  	asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter)));  	return idx;  }  static inline int armv7_pmnc_enable_intens(int idx)  { -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n", -			smp_processor_id(), idx); -		return -EINVAL; -	} - -	counter = ARMV7_IDX_TO_COUNTER(idx); +	u32 counter = ARMV7_IDX_TO_COUNTER(idx);  	asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter)));  	return idx;  }  static inline int armv7_pmnc_disable_intens(int idx)  { -	u32 counter; - -	if (!armv7_pmnc_counter_valid(idx)) { -		pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n", -			smp_processor_id(), idx); -		return -EINVAL; -	} - -	counter = ARMV7_IDX_TO_COUNTER(idx); +	u32 counter = ARMV7_IDX_TO_COUNTER(idx);  	asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));  	isb();  	/* Clear the overflow flag in case an interrupt is pending. */ @@ -956,7 +912,7 @@ static inline u32 armv7_pmnc_getreset_flags(void)  }  #ifdef DEBUG -static void armv7_pmnc_dump_regs(void) +static void armv7_pmnc_dump_regs(struct arm_pmu *cpu_pmu)  {  	u32 val;  	unsigned int cnt; @@ -981,7 +937,8 @@ static void armv7_pmnc_dump_regs(void)  	asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));  	printk(KERN_INFO "CCNT  =0x%08x\n", val); -	for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST; cnt++) { +	for (cnt = ARMV7_IDX_COUNTER0; +			cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) {  		armv7_pmnc_select_counter(cnt);  		asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));  		printk(KERN_INFO "CNT[%d] count =0x%08x\n", @@ -993,10 +950,19 @@ static void armv7_pmnc_dump_regs(void)  }  #endif -static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) +static void armv7pmu_enable_event(struct perf_event *event)  {  	unsigned long flags; +	struct hw_perf_event *hwc = &event->hw; +	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);  	struct pmu_hw_events *events = cpu_pmu->get_hw_events(); +	int idx = hwc->idx; + +	if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { +		pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n", +			smp_processor_id(), idx); +		return; +	}  	/*  	 * Enable counter and interrupt, and set the counter to count @@ -1014,7 +980,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)  	 * We only need to set the event for the cycle counter if we  	 * have the ability to perform event filtering.  	 */ -	if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER) +	if (cpu_pmu->set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER)  		armv7_pmnc_write_evtsel(idx, hwc->config_base);  	/* @@ -1030,10 +996,19 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)  	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);  } -static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) +static void armv7pmu_disable_event(struct perf_event *event)  {  	unsigned long flags; +	struct hw_perf_event *hwc = &event->hw; +	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);  	struct pmu_hw_events *events = cpu_pmu->get_hw_events(); +	int idx = hwc->idx; + +	if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { +		pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n", +			smp_processor_id(), idx); +		return; +	}  	/*  	 * Disable counter and interrupt @@ -1057,7 +1032,8 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)  {  	u32 pmnc;  	struct perf_sample_data data; -	struct pmu_hw_events *cpuc; +	struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev; +	struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();  	struct pt_regs *regs;  	int idx; @@ -1077,7 +1053,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)  	 */  	regs = get_irq_regs(); -	cpuc = &__get_cpu_var(cpu_hw_events);  	for (idx = 0; idx < cpu_pmu->num_events; ++idx) {  		struct perf_event *event = cpuc->events[idx];  		struct hw_perf_event *hwc; @@ -1094,13 +1069,13 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)  			continue;  		hwc = &event->hw; -		armpmu_event_update(event, hwc, idx); +		armpmu_event_update(event);  		perf_sample_data_init(&data, 0, hwc->last_period); -		if (!armpmu_event_set_period(event, hwc, idx)) +		if (!armpmu_event_set_period(event))  			continue;  		if (perf_event_overflow(event, &data, regs)) -			cpu_pmu->disable(hwc, idx); +			cpu_pmu->disable(event);  	}  	/* @@ -1115,7 +1090,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)  	return IRQ_HANDLED;  } -static void armv7pmu_start(void) +static void armv7pmu_start(struct arm_pmu *cpu_pmu)  {  	unsigned long flags;  	struct pmu_hw_events *events = cpu_pmu->get_hw_events(); @@ -1126,7 +1101,7 @@ static void armv7pmu_start(void)  	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);  } -static void armv7pmu_stop(void) +static void armv7pmu_stop(struct arm_pmu *cpu_pmu)  {  	unsigned long flags;  	struct pmu_hw_events *events = cpu_pmu->get_hw_events(); @@ -1138,10 +1113,12 @@ static void armv7pmu_stop(void)  }  static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc, -				  struct hw_perf_event *event) +				  struct perf_event *event)  {  	int idx; -	unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT; +	struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); +	struct hw_perf_event *hwc = &event->hw; +	unsigned long evtype = hwc->config_base & ARMV7_EVTYPE_EVENT;  	/* Always place a cycle counter into the cycle counter. */  	if (evtype == ARMV7_PERFCTR_CPU_CYCLES) { @@ -1192,11 +1169,14 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event,  static void armv7pmu_reset(void *info)  { +	struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;  	u32 idx, nb_cnt = cpu_pmu->num_events;  	/* The counter and interrupt enable registers are unknown at reset. */ -	for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) -		armv7pmu_disable_event(NULL, idx); +	for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) { +		armv7_pmnc_disable_counter(idx); +		armv7_pmnc_disable_intens(idx); +	}  	/* Initialize & Reset PMNC: C and P bits */  	armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); @@ -1232,17 +1212,18 @@ static int armv7_a7_map_event(struct perf_event *event)  				&armv7_a7_perf_cache_map, 0xFF);  } -static struct arm_pmu armv7pmu = { -	.handle_irq		= armv7pmu_handle_irq, -	.enable			= armv7pmu_enable_event, -	.disable		= armv7pmu_disable_event, -	.read_counter		= armv7pmu_read_counter, -	.write_counter		= armv7pmu_write_counter, -	.get_event_idx		= armv7pmu_get_event_idx, -	.start			= armv7pmu_start, -	.stop			= armv7pmu_stop, -	.reset			= armv7pmu_reset, -	.max_period		= (1LLU << 32) - 1, +static void armv7pmu_init(struct arm_pmu *cpu_pmu) +{ +	cpu_pmu->handle_irq	= armv7pmu_handle_irq; +	cpu_pmu->enable		= armv7pmu_enable_event; +	cpu_pmu->disable	= armv7pmu_disable_event; +	cpu_pmu->read_counter	= armv7pmu_read_counter; +	cpu_pmu->write_counter	= armv7pmu_write_counter; +	cpu_pmu->get_event_idx	= armv7pmu_get_event_idx; +	cpu_pmu->start		= armv7pmu_start; +	cpu_pmu->stop		= armv7pmu_stop; +	cpu_pmu->reset		= armv7pmu_reset; +	cpu_pmu->max_period	= (1LLU << 32) - 1;  };  static u32 __devinit armv7_read_num_pmnc_events(void) @@ -1256,70 +1237,75 @@ static u32 __devinit armv7_read_num_pmnc_events(void)  	return nb_cnt + 1;  } -static struct arm_pmu *__devinit armv7_a8_pmu_init(void) +static int __devinit armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)  { -	armv7pmu.name		= "ARMv7 Cortex-A8"; -	armv7pmu.map_event	= armv7_a8_map_event; -	armv7pmu.num_events	= armv7_read_num_pmnc_events(); -	return &armv7pmu; +	armv7pmu_init(cpu_pmu); +	cpu_pmu->name		= "ARMv7 Cortex-A8"; +	cpu_pmu->map_event	= armv7_a8_map_event; +	cpu_pmu->num_events	= armv7_read_num_pmnc_events(); +	return 0;  } -static struct arm_pmu *__devinit armv7_a9_pmu_init(void) +static int __devinit armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)  { -	armv7pmu.name		= "ARMv7 Cortex-A9"; -	armv7pmu.map_event	= armv7_a9_map_event; -	armv7pmu.num_events	= armv7_read_num_pmnc_events(); -	return &armv7pmu; +	armv7pmu_init(cpu_pmu); +	cpu_pmu->name		= "ARMv7 Cortex-A9"; +	cpu_pmu->map_event	= armv7_a9_map_event; +	cpu_pmu->num_events	= armv7_read_num_pmnc_events(); +	return 0;  } -static struct arm_pmu *__devinit armv7_a5_pmu_init(void) +static int __devinit armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)  { -	armv7pmu.name		= "ARMv7 Cortex-A5"; -	armv7pmu.map_event	= armv7_a5_map_event; -	armv7pmu.num_events	= armv7_read_num_pmnc_events(); -	return &armv7pmu; +	armv7pmu_init(cpu_pmu); +	cpu_pmu->name		= "ARMv7 Cortex-A5"; +	cpu_pmu->map_event	= armv7_a5_map_event; +	cpu_pmu->num_events	= armv7_read_num_pmnc_events(); +	return 0;  } -static struct arm_pmu *__devinit armv7_a15_pmu_init(void) +static int __devinit armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)  { -	armv7pmu.name		= "ARMv7 Cortex-A15"; -	armv7pmu.map_event	= armv7_a15_map_event; -	armv7pmu.num_events	= armv7_read_num_pmnc_events(); -	armv7pmu.set_event_filter = armv7pmu_set_event_filter; -	return &armv7pmu; +	armv7pmu_init(cpu_pmu); +	cpu_pmu->name		= "ARMv7 Cortex-A15"; +	cpu_pmu->map_event	= armv7_a15_map_event; +	cpu_pmu->num_events	= armv7_read_num_pmnc_events(); +	cpu_pmu->set_event_filter = armv7pmu_set_event_filter; +	return 0;  } -static struct arm_pmu *__devinit armv7_a7_pmu_init(void) +static int __devinit armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)  { -	armv7pmu.name		= "ARMv7 Cortex-A7"; -	armv7pmu.map_event	= armv7_a7_map_event; -	armv7pmu.num_events	= armv7_read_num_pmnc_events(); -	armv7pmu.set_event_filter = armv7pmu_set_event_filter; -	return &armv7pmu; +	armv7pmu_init(cpu_pmu); +	cpu_pmu->name		= "ARMv7 Cortex-A7"; +	cpu_pmu->map_event	= armv7_a7_map_event; +	cpu_pmu->num_events	= armv7_read_num_pmnc_events(); +	cpu_pmu->set_event_filter = armv7pmu_set_event_filter; +	return 0;  }  #else -static struct arm_pmu *__devinit armv7_a8_pmu_init(void) +static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)  { -	return NULL; +	return -ENODEV;  } -static struct arm_pmu *__devinit armv7_a9_pmu_init(void) +static inline int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)  { -	return NULL; +	return -ENODEV;  } -static struct arm_pmu *__devinit armv7_a5_pmu_init(void) +static inline int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)  { -	return NULL; +	return -ENODEV;  } -static struct arm_pmu *__devinit armv7_a15_pmu_init(void) +static inline int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)  { -	return NULL; +	return -ENODEV;  } -static struct arm_pmu *__devinit armv7_a7_pmu_init(void) +static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)  { -	return NULL; +	return -ENODEV;  }  #endif	/* CONFIG_CPU_V7 */  |