diff options
author | Michael Neuling <mikey@neuling.org> | 2013-05-13 14:44:58 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-05-14 02:00:22 -0400 |
commit | 691231846cebfe1fbbcf898c8af17a569dbb5463 (patch) | |
tree | edb500ca27ae25cfdae8526a9efb884143a12f5c /arch/powerpc/perf | |
parent | 506e70d13236dfdb0bc15e0914298ab0a7b7f4df (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/powerpc/perf')
-rw-r--r-- | arch/powerpc/perf/core-book3s.c | 31 |
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 */ | ||
368 | static __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 */ |
367 | void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) | 395 | void 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 | } |