aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2013-05-13 14:44:58 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-14 02:00:22 -0400
commit691231846cebfe1fbbcf898c8af17a569dbb5463 (patch)
treeedb500ca27ae25cfdae8526a9efb884143a12f5c /arch
parent506e70d13236dfdb0bc15e0914298ab0a7b7f4df (diff)
powerpc/perf: Fix setting of "to" addresses for BHRB
Currently we only set the "to" address in the branch stack when the CPU explicitly gives us a value. Unfortunately it only does this for XL form branches (eg blr, bctr, bctar) and not I and B form branches (eg b, bc). Fortunately if we read the instruction from memory we can extract the offset of a branch and calculate the target address. This adds a function power_pmu_bhrb_to() to calculate the target/to address of the corresponding I and B form branches. It handles branches in both user and kernel spaces. It also plumbs this into the perf brhb reading code. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/perf/core-book3s.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 3fdfe4575b8f..426180b84978 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -13,11 +13,13 @@
13#include <linux/perf_event.h> 13#include <linux/perf_event.h>
14#include <linux/percpu.h> 14#include <linux/percpu.h>
15#include <linux/hardirq.h> 15#include <linux/hardirq.h>
16#include <linux/uaccess.h>
16#include <asm/reg.h> 17#include <asm/reg.h>
17#include <asm/pmc.h> 18#include <asm/pmc.h>
18#include <asm/machdep.h> 19#include <asm/machdep.h>
19#include <asm/firmware.h> 20#include <asm/firmware.h>
20#include <asm/ptrace.h> 21#include <asm/ptrace.h>
22#include <asm/code-patching.h>
21 23
22#define BHRB_MAX_ENTRIES 32 24#define BHRB_MAX_ENTRIES 32
23#define BHRB_TARGET 0x0000000000000002 25#define BHRB_TARGET 0x0000000000000002
@@ -362,6 +364,32 @@ void power_pmu_flush_branch_stack(void)
362 if (ppmu->bhrb_nr) 364 if (ppmu->bhrb_nr)
363 power_pmu_bhrb_reset(); 365 power_pmu_bhrb_reset();
364} 366}
367/* Calculate the to address for a branch */
368static __u64 power_pmu_bhrb_to(u64 addr)
369{
370 unsigned int instr;
371 int ret;
372 __u64 target;
373
374 if (is_kernel_addr(addr))
375 return branch_target((unsigned int *)addr);
376
377 /* Userspace: need copy instruction here then translate it */
378 pagefault_disable();
379 ret = __get_user_inatomic(instr, (unsigned int __user *)addr);
380 if (ret) {
381 pagefault_enable();
382 return 0;
383 }
384 pagefault_enable();
385
386 target = branch_target(&instr);
387 if ((!target) || (instr & BRANCH_ABSOLUTE))
388 return target;
389
390 /* Translate relative branch target from kernel to user address */
391 return target - (unsigned long)&instr + addr;
392}
365 393
366/* Processing BHRB entries */ 394/* Processing BHRB entries */
367void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) 395void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
@@ -426,7 +454,8 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
426 /* Branches to immediate field 454 /* Branches to immediate field
427 (ie I or B form) */ 455 (ie I or B form) */
428 cpuhw->bhrb_entries[u_index].from = addr; 456 cpuhw->bhrb_entries[u_index].from = addr;
429 cpuhw->bhrb_entries[u_index].to = 0; 457 cpuhw->bhrb_entries[u_index].to =
458 power_pmu_bhrb_to(addr);
430 cpuhw->bhrb_entries[u_index].mispred = pred; 459 cpuhw->bhrb_entries[u_index].mispred = pred;
431 cpuhw->bhrb_entries[u_index].predicted = ~pred; 460 cpuhw->bhrb_entries[u_index].predicted = ~pred;
432 } 461 }