diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-23 18:54:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-23 18:54:23 -0700 |
commit | 83c7f72259ea4bd0561e2f2762d97ee2888126ce (patch) | |
tree | c8b181e9f9a0bb061f5ab63fabb98197d7aee19a /arch/powerpc/perf/core-book3s.c | |
parent | e05644e17e744315bce12b0948cdc36910b9a76e (diff) | |
parent | 574ce79cea9d3fda109ffcc82f81733de4740e5c (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc updates from Benjamin Herrenschmidt:
"Notable highlights:
- iommu improvements from Anton removing the per-iommu global lock in
favor of dividing the DMA space into pools, each with its own lock,
and hashed on the CPU number. Along with making the locking more
fine grained, this gives significant improvements in multiqueue
networking scalability.
- Still from Anton, we know provide a vdso based variant of getcpu
which makes sched_getcpu with the appropriate glibc patch something
like 18 times faster.
- More anton goodness (he's been busy !) in other areas such as a
faster __clear_user and copy_page on P7, various perf fixes to
improve sampling quality, etc...
- One more step toward removing legacy i2c interfaces by using new
device-tree based probing of platform devices for the AOA audio
drivers
- A nice series of patches from Michael Neuling that helps avoiding
confusion between register numbers and litterals in assembly code,
trying to enforce the use of "%rN" register names in gas rather
than plain numbers.
- A pile of FSL updates
- The usual bunch of small fixes, cleanups etc...
You may spot a change to drivers/char/mem. The patch got no comment
or ack from outside, it's a trivial patch to allow the architecture to
skip creating /dev/port, which we use to disable it on ppc64 that
don't have a legacy brige. On those, IO ports 0...64K are not mapped
in kernel space at all, so accesses to /dev/port cause oopses (and
yes, distros -still- ship userspace that bangs hard coded ports such
as kbdrate)."
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (106 commits)
powerpc/mpic: Create a revmap with enough entries for IPIs and timers
Remove stale .rej file
powerpc/iommu: Fix iommu pool initialization
powerpc/eeh: Check handle_eeh_events() return value
powerpc/85xx: Add phy nodes in SGMII mode for MPC8536/44/72DS & P2020DS
powerpc/e500: add paravirt QEMU platform
powerpc/mpc85xx_ds: convert to unified PCI init
powerpc/fsl-pci: get PCI init out of board files
powerpc/85xx: Update corenet64_smp_defconfig
powerpc/85xx: Update corenet32_smp_defconfig
powerpc/85xx: Rename P1021RDB-PC device trees to be consistent
powerpc/watchdog: move booke watchdog param related code to setup-common.c
sound/aoa: Adapt to new i2c probing scheme
i2c/powermac: Improve detection of devices from device-tree
powerpc: Disable /dev/port interface on systems without an ISA bridge
of: Improve prom_update_property() function
powerpc: Add "memory" attribute for mfmsr()
powerpc/ftrace: Fix assembly trampoline register usage
powerpc/hw_breakpoints: Fix incorrect pointer access
powerpc: Put the gpr save/restore functions in their own section
...
Diffstat (limited to 'arch/powerpc/perf/core-book3s.c')
-rw-r--r-- | arch/powerpc/perf/core-book3s.c | 99 |
1 files changed, 68 insertions, 31 deletions
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 8f84bcba18d..77b49ddda9d 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -73,7 +73,10 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) { return 0; } -static inline void perf_read_regs(struct pt_regs *regs) { } +static inline void perf_read_regs(struct pt_regs *regs) +{ + regs->result = 0; +} static inline int perf_intr_is_nmi(struct pt_regs *regs) { return 0; @@ -116,6 +119,26 @@ static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) *addrp = mfspr(SPRN_SDAR); } +static bool mmcra_sihv(unsigned long mmcra) +{ + unsigned long sihv = MMCRA_SIHV; + + if (ppmu->flags & PPMU_ALT_SIPR) + sihv = POWER6_MMCRA_SIHV; + + return !!(mmcra & sihv); +} + +static bool mmcra_sipr(unsigned long mmcra) +{ + unsigned long sipr = MMCRA_SIPR; + + if (ppmu->flags & PPMU_ALT_SIPR) + sipr = POWER6_MMCRA_SIPR; + + return !!(mmcra & sipr); +} + static inline u32 perf_flags_from_msr(struct pt_regs *regs) { if (regs->msr & MSR_PR) @@ -128,19 +151,9 @@ static inline u32 perf_flags_from_msr(struct pt_regs *regs) static inline u32 perf_get_misc_flags(struct pt_regs *regs) { unsigned long mmcra = regs->dsisr; - unsigned long sihv = MMCRA_SIHV; - unsigned long sipr = MMCRA_SIPR; + unsigned long use_siar = regs->result; - /* Not a PMU interrupt: Make up flags from regs->msr */ - if (TRAP(regs) != 0xf00) - return perf_flags_from_msr(regs); - - /* - * If we don't support continuous sampling and this - * is not a marked event, same deal - */ - if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) && - !(mmcra & MMCRA_SAMPLE_ENABLE)) + if (!use_siar) return perf_flags_from_msr(regs); /* @@ -156,15 +169,10 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) return PERF_RECORD_MISC_USER; } - if (ppmu->flags & PPMU_ALT_SIPR) { - sihv = POWER6_MMCRA_SIHV; - sipr = POWER6_MMCRA_SIPR; - } - /* PR has priority over HV, so order below is important */ - if (mmcra & sipr) + if (mmcra_sipr(mmcra)) return PERF_RECORD_MISC_USER; - if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV)) + if (mmcra_sihv(mmcra) && (freeze_events_kernel != MMCR0_FCHV)) return PERF_RECORD_MISC_HYPERVISOR; return PERF_RECORD_MISC_KERNEL; } @@ -172,10 +180,45 @@ static inline u32 perf_get_misc_flags(struct pt_regs *regs) /* * Overload regs->dsisr to store MMCRA so we only need to read it once * on each interrupt. + * Overload regs->result to specify whether we should use the MSR (result + * is zero) or the SIAR (result is non zero). */ static inline void perf_read_regs(struct pt_regs *regs) { - regs->dsisr = mfspr(SPRN_MMCRA); + unsigned long mmcra = mfspr(SPRN_MMCRA); + int marked = mmcra & MMCRA_SAMPLE_ENABLE; + int use_siar; + + /* + * If this isn't a PMU exception (eg a software event) the SIAR is + * not valid. Use pt_regs. + * + * If it is a marked event use the SIAR. + * + * If the PMU doesn't update the SIAR for non marked events use + * pt_regs. + * + * If the PMU has HV/PR flags then check to see if they + * place the exception in userspace. If so, use pt_regs. In + * continuous sampling mode the SIAR and the PMU exception are + * not synchronised, so they may be many instructions apart. + * This can result in confusing backtraces. We still want + * hypervisor samples as well as samples in the kernel with + * interrupts off hence the userspace check. + */ + if (TRAP(regs) != 0xf00) + use_siar = 0; + else if (marked) + use_siar = 1; + else if ((ppmu->flags & PPMU_NO_CONT_SAMPLING)) + use_siar = 0; + else if (!(ppmu->flags & PPMU_NO_SIPR) && mmcra_sipr(mmcra)) + use_siar = 0; + else + use_siar = 1; + + regs->dsisr = mmcra; + regs->result = use_siar; } /* @@ -1329,18 +1372,12 @@ unsigned long perf_misc_flags(struct pt_regs *regs) */ unsigned long perf_instruction_pointer(struct pt_regs *regs) { - unsigned long mmcra = regs->dsisr; + unsigned long use_siar = regs->result; - /* Not a PMU interrupt */ - if (TRAP(regs) != 0xf00) - return regs->nip; - - /* Processor doesn't support sampling non marked events */ - if ((ppmu->flags & PPMU_NO_CONT_SAMPLING) && - !(mmcra & MMCRA_SAMPLE_ENABLE)) + if (use_siar) + return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); + else return regs->nip; - - return mfspr(SPRN_SIAR) + perf_ip_adjust(regs); } static bool pmc_overflow(unsigned long val) |