mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	arm64: perf: Disable PMU while processing counter overflows
The arm64 PMU updates the event counters and reprograms the counters in the overflow IRQ handler without disabling the PMU. This could potentially cause skews in for group counters, where the overflowed counters may potentially loose some event counts, while they are reprogrammed. To prevent this, disable the PMU while we process the counter overflows and enable it right back when we are done. This patch also moves the PMU stop/start routines to avoid a forward declaration. Suggested-by: Mark Rutland <mark.rutland@arm.com> Cc: Will Deacon <will.deacon@arm.com> Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
		
							parent
							
								
									0c55d19c16
								
							
						
					
					
						commit
						3cce50dfec
					
				
					 1 changed files with 28 additions and 22 deletions
				
			
		|  | @ -678,6 +678,28 @@ static void armv8pmu_disable_event(struct perf_event *event) | |||
| 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void armv8pmu_start(struct arm_pmu *cpu_pmu) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); | ||||
| 
 | ||||
| 	raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||||
| 	/* Enable all counters */ | ||||
| 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); | ||||
| 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void armv8pmu_stop(struct arm_pmu *cpu_pmu) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); | ||||
| 
 | ||||
| 	raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||||
| 	/* Disable all counters */ | ||||
| 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E); | ||||
| 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) | ||||
| { | ||||
| 	u32 pmovsr; | ||||
|  | @ -702,6 +724,11 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) | |||
| 	 */ | ||||
| 	regs = get_irq_regs(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Stop the PMU while processing the counter overflows | ||||
| 	 * to prevent skews in group events. | ||||
| 	 */ | ||||
| 	armv8pmu_stop(cpu_pmu); | ||||
| 	for (idx = 0; idx < cpu_pmu->num_events; ++idx) { | ||||
| 		struct perf_event *event = cpuc->events[idx]; | ||||
| 		struct hw_perf_event *hwc; | ||||
|  | @ -726,6 +753,7 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) | |||
| 		if (perf_event_overflow(event, &data, regs)) | ||||
| 			cpu_pmu->disable(event); | ||||
| 	} | ||||
| 	armv8pmu_start(cpu_pmu); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Handle the pending perf events. | ||||
|  | @ -739,28 +767,6 @@ static irqreturn_t armv8pmu_handle_irq(struct arm_pmu *cpu_pmu) | |||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| static void armv8pmu_start(struct arm_pmu *cpu_pmu) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); | ||||
| 
 | ||||
| 	raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||||
| 	/* Enable all counters */ | ||||
| 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMU_PMCR_E); | ||||
| 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void armv8pmu_stop(struct arm_pmu *cpu_pmu) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); | ||||
| 
 | ||||
| 	raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||||
| 	/* Disable all counters */ | ||||
| 	armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMU_PMCR_E); | ||||
| 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||||
| } | ||||
| 
 | ||||
| static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc, | ||||
| 				  struct perf_event *event) | ||||
| { | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Suzuki K Poulose
						Suzuki K Poulose