aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c52
1 files changed, 38 insertions, 14 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 32e9ed81cd00..c1760ff3c757 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -12,6 +12,7 @@
12 12
13#define BTS_BUFFER_SIZE (PAGE_SIZE << 4) 13#define BTS_BUFFER_SIZE (PAGE_SIZE << 4)
14#define PEBS_BUFFER_SIZE PAGE_SIZE 14#define PEBS_BUFFER_SIZE PAGE_SIZE
15#define PEBS_FIXUP_SIZE PAGE_SIZE
15 16
16/* 17/*
17 * pebs_record_32 for p4 and core not supported 18 * pebs_record_32 for p4 and core not supported
@@ -228,12 +229,14 @@ void fini_debug_store_on_cpu(int cpu)
228 wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); 229 wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
229} 230}
230 231
232static DEFINE_PER_CPU(void *, insn_buffer);
233
231static int alloc_pebs_buffer(int cpu) 234static int alloc_pebs_buffer(int cpu)
232{ 235{
233 struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; 236 struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
234 int node = cpu_to_node(cpu); 237 int node = cpu_to_node(cpu);
235 int max, thresh = 1; /* always use a single PEBS record */ 238 int max, thresh = 1; /* always use a single PEBS record */
236 void *buffer; 239 void *buffer, *ibuffer;
237 240
238 if (!x86_pmu.pebs) 241 if (!x86_pmu.pebs)
239 return 0; 242 return 0;
@@ -242,6 +245,19 @@ static int alloc_pebs_buffer(int cpu)
242 if (unlikely(!buffer)) 245 if (unlikely(!buffer))
243 return -ENOMEM; 246 return -ENOMEM;
244 247
248 /*
249 * HSW+ already provides us the eventing ip; no need to allocate this
250 * buffer then.
251 */
252 if (x86_pmu.intel_cap.pebs_format < 2) {
253 ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node);
254 if (!ibuffer) {
255 kfree(buffer);
256 return -ENOMEM;
257 }
258 per_cpu(insn_buffer, cpu) = ibuffer;
259 }
260
245 max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size; 261 max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
246 262
247 ds->pebs_buffer_base = (u64)(unsigned long)buffer; 263 ds->pebs_buffer_base = (u64)(unsigned long)buffer;
@@ -262,6 +278,9 @@ static void release_pebs_buffer(int cpu)
262 if (!ds || !x86_pmu.pebs) 278 if (!ds || !x86_pmu.pebs)
263 return; 279 return;
264 280
281 kfree(per_cpu(insn_buffer, cpu));
282 per_cpu(insn_buffer, cpu) = NULL;
283
265 kfree((void *)(unsigned long)ds->pebs_buffer_base); 284 kfree((void *)(unsigned long)ds->pebs_buffer_base);
266 ds->pebs_buffer_base = 0; 285 ds->pebs_buffer_base = 0;
267} 286}
@@ -729,6 +748,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
729 unsigned long old_to, to = cpuc->lbr_entries[0].to; 748 unsigned long old_to, to = cpuc->lbr_entries[0].to;
730 unsigned long ip = regs->ip; 749 unsigned long ip = regs->ip;
731 int is_64bit = 0; 750 int is_64bit = 0;
751 void *kaddr;
732 752
733 /* 753 /*
734 * We don't need to fixup if the PEBS assist is fault like 754 * We don't need to fixup if the PEBS assist is fault like
@@ -752,7 +772,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
752 * unsigned math, either ip is before the start (impossible) or 772 * unsigned math, either ip is before the start (impossible) or
753 * the basic block is larger than 1 page (sanity) 773 * the basic block is larger than 1 page (sanity)
754 */ 774 */
755 if ((ip - to) > PAGE_SIZE) 775 if ((ip - to) > PEBS_FIXUP_SIZE)
756 return 0; 776 return 0;
757 777
758 /* 778 /*
@@ -763,29 +783,33 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
763 return 1; 783 return 1;
764 } 784 }
765 785
786 if (!kernel_ip(ip)) {
787 int size, bytes;
788 u8 *buf = this_cpu_read(insn_buffer);
789
790 size = ip - to; /* Must fit our buffer, see above */
791 bytes = copy_from_user_nmi(buf, (void __user *)to, size);
792 if (bytes != size)
793 return 0;
794
795 kaddr = buf;
796 } else {
797 kaddr = (void *)to;
798 }
799
766 do { 800 do {
767 struct insn insn; 801 struct insn insn;
768 u8 buf[MAX_INSN_SIZE];
769 void *kaddr;
770 802
771 old_to = to; 803 old_to = to;
772 if (!kernel_ip(ip)) {
773 int bytes, size = MAX_INSN_SIZE;
774
775 bytes = copy_from_user_nmi(buf, (void __user *)to, size);
776 if (bytes != size)
777 return 0;
778
779 kaddr = buf;
780 } else
781 kaddr = (void *)to;
782 804
783#ifdef CONFIG_X86_64 805#ifdef CONFIG_X86_64
784 is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); 806 is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
785#endif 807#endif
786 insn_init(&insn, kaddr, is_64bit); 808 insn_init(&insn, kaddr, is_64bit);
787 insn_get_length(&insn); 809 insn_get_length(&insn);
810
788 to += insn.length; 811 to += insn.length;
812 kaddr += insn.length;
789 } while (to < ip); 813 } while (to < ip);
790 814
791 if (to == ip) { 815 if (to == ip) {