diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/powerpc/perf/core-book3s.c | 17 | 
1 files changed, 16 insertions, 1 deletions
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index bae697cd5925..6b0641c3f03f 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -996,7 +996,22 @@ static void power_pmu_read(struct perf_event *event)  	} while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);  	local64_add(delta, &event->count); -	local64_sub(delta, &event->hw.period_left); + +	/* +	 * A number of places program the PMC with (0x80000000 - period_left). +	 * We never want period_left to be less than 1 because we will program +	 * the PMC with a value >= 0x800000000 and an edge detected PMC will +	 * roll around to 0 before taking an exception. We have seen this +	 * on POWER8. +	 * +	 * To fix this, clamp the minimum value of period_left to 1. +	 */ +	do { +		prev = local64_read(&event->hw.period_left); +		val = prev - delta; +		if (val < 1) +			val = 1; +	} while (local64_cmpxchg(&event->hw.period_left, prev, val) != prev);  }  /*  | 
