diff options
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event.c')
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 62 | 
1 files changed, 25 insertions, 37 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 5db5b7d65a1..f2da20fda02 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -220,6 +220,7 @@ struct x86_pmu {  						 struct perf_event *event);  	struct event_constraint *event_constraints;  	void		(*quirks)(void); +	int		perfctr_second_write;  	int		(*cpu_prepare)(int cpu);  	void		(*cpu_starting)(int cpu); @@ -295,10 +296,10 @@ x86_perf_event_update(struct perf_event *event)  	 * count to the generic event atomically:  	 */  again: -	prev_raw_count = atomic64_read(&hwc->prev_count); +	prev_raw_count = local64_read(&hwc->prev_count);  	rdmsrl(hwc->event_base + idx, new_raw_count); -	if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, +	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,  					new_raw_count) != prev_raw_count)  		goto again; @@ -313,8 +314,8 @@ again:  	delta = (new_raw_count << shift) - (prev_raw_count << shift);  	delta >>= shift; -	atomic64_add(delta, &event->count); -	atomic64_sub(delta, &hwc->period_left); +	local64_add(delta, &event->count); +	local64_sub(delta, &hwc->period_left);  	return new_raw_count;  } @@ -438,7 +439,7 @@ static int x86_setup_perfctr(struct perf_event *event)  	if (!hwc->sample_period) {  		hwc->sample_period = x86_pmu.max_period;  		hwc->last_period = hwc->sample_period; -		atomic64_set(&hwc->period_left, hwc->sample_period); +		local64_set(&hwc->period_left, hwc->sample_period);  	} else {  		/*  		 * If we have a PMU initialized but no APIC @@ -885,7 +886,7 @@ static int  x86_perf_event_set_period(struct perf_event *event)  {  	struct hw_perf_event *hwc = &event->hw; -	s64 left = atomic64_read(&hwc->period_left); +	s64 left = local64_read(&hwc->period_left);  	s64 period = hwc->sample_period;  	int ret = 0, idx = hwc->idx; @@ -897,14 +898,14 @@ x86_perf_event_set_period(struct perf_event *event)  	 */  	if (unlikely(left <= -period)) {  		left = period; -		atomic64_set(&hwc->period_left, left); +		local64_set(&hwc->period_left, left);  		hwc->last_period = period;  		ret = 1;  	}  	if (unlikely(left <= 0)) {  		left += period; -		atomic64_set(&hwc->period_left, left); +		local64_set(&hwc->period_left, left);  		hwc->last_period = period;  		ret = 1;  	} @@ -923,10 +924,19 @@ x86_perf_event_set_period(struct perf_event *event)  	 * The hw event starts counting from this event offset,  	 * mark it to be able to extra future deltas:  	 */ -	atomic64_set(&hwc->prev_count, (u64)-left); +	local64_set(&hwc->prev_count, (u64)-left); -	wrmsrl(hwc->event_base + idx, +	wrmsrl(hwc->event_base + idx, (u64)(-left) & x86_pmu.cntval_mask); + +	/* +	 * Due to erratum on certan cpu we need +	 * a second write to be sure the register +	 * is updated properly +	 */ +	if (x86_pmu.perfctr_second_write) { +		wrmsrl(hwc->event_base + idx,  			(u64)(-left) & x86_pmu.cntval_mask); +	}  	perf_event_update_userpage(event); @@ -969,7 +979,7 @@ static int x86_pmu_enable(struct perf_event *event)  	 * skip the schedulability test here, it will be peformed  	 * at commit time(->commit_txn) as a whole  	 */ -	if (cpuc->group_flag & PERF_EVENT_TXN_STARTED) +	if (cpuc->group_flag & PERF_EVENT_TXN)  		goto out;  	ret = x86_pmu.schedule_events(cpuc, n, assign); @@ -1096,7 +1106,7 @@ static void x86_pmu_disable(struct perf_event *event)  	 * The events never got scheduled and ->cancel_txn will truncate  	 * the event_list.  	 */ -	if (cpuc->group_flag & PERF_EVENT_TXN_STARTED) +	if (cpuc->group_flag & PERF_EVENT_TXN)  		return;  	x86_pmu_stop(event); @@ -1388,7 +1398,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu)  {  	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); -	cpuc->group_flag |= PERF_EVENT_TXN_STARTED; +	cpuc->group_flag |= PERF_EVENT_TXN;  	cpuc->n_txn = 0;  } @@ -1401,7 +1411,7 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)  {  	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); -	cpuc->group_flag &= ~PERF_EVENT_TXN_STARTED; +	cpuc->group_flag &= ~PERF_EVENT_TXN;  	/*  	 * Truncate the collected events.  	 */ @@ -1435,11 +1445,7 @@ static int x86_pmu_commit_txn(const struct pmu *pmu)  	 */  	memcpy(cpuc->assign, assign, n*sizeof(int)); -	/* -	 * Clear out the txn count so that ->cancel_txn() which gets -	 * run after ->commit_txn() doesn't undo things. -	 */ -	cpuc->n_txn = 0; +	cpuc->group_flag &= ~PERF_EVENT_TXN;  	return 0;  } @@ -1607,8 +1613,6 @@ static const struct stacktrace_ops backtrace_ops = {  	.walk_stack		= print_context_stack_bp,  }; -#include "../dumpstack.h" -  static void  perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)  { @@ -1730,22 +1734,6 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)  	return entry;  } -void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int skip) -{ -	regs->ip = ip; -	/* -	 * perf_arch_fetch_caller_regs adds another call, we need to increment -	 * the skip level -	 */ -	regs->bp = rewind_frame_pointer(skip + 1); -	regs->cs = __KERNEL_CS; -	/* -	 * We abuse bit 3 to pass exact information, see perf_misc_flags -	 * and the comment with PERF_EFLAGS_EXACT. -	 */ -	regs->flags = 0; -} -  unsigned long perf_instruction_pointer(struct pt_regs *regs)  {  	unsigned long ip;  | 
