perf_counter: powerpc: Enable use of software counters on 32-bit powerpc
This enables the perf_counter subsystem on 32-bit powerpc. Since we don't have any support for hardware counters on 32-bit powerpc yet, only software counters can be used. Besides selecting HAVE_PERF_COUNTERS for 32-bit powerpc as well as 64-bit, the main thing this does is add an implementation of set_perf_counter_pending(). This needs to arrange for perf_counter_do_pending() to be called when interrupts are enabled. Rather than add code to local_irq_restore as 64-bit does, the 32-bit set_perf_counter_pending() generates an interrupt by setting the decrementer to 1 so that a decrementer interrupt will become pending in 1 or 2 timebase ticks (if a decrementer interrupt isn't already pending). When interrupts are enabled, timer_interrupt() will be called, and some new code in there calls perf_counter_do_pending(). We use a per-cpu array of flags to indicate whether we need to call perf_counter_do_pending() or not. This introduces a couple of new Kconfig symbols: PPC_HAVE_PMU_SUPPORT, which is selected by processor families for which we have hardware PMU support (currently only PPC64), and PPC_PERF_CTRS, which enables the powerpc-specific perf_counter back-end. Signed-off-by: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: linuxppc-dev@ozlabs.org Cc: benh@kernel.crashing.org LKML-Reference: <19000.55404.103840.393470@cargo.ozlabs.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
committed by
Ingo Molnar
parent
a73c7d84a1
commit
105988c015
@@ -126,6 +126,7 @@ config PPC
|
|||||||
select HAVE_OPROFILE
|
select HAVE_OPROFILE
|
||||||
select HAVE_SYSCALL_WRAPPERS if PPC64
|
select HAVE_SYSCALL_WRAPPERS if PPC64
|
||||||
select GENERIC_ATOMIC64 if PPC32
|
select GENERIC_ATOMIC64 if PPC32
|
||||||
|
select HAVE_PERF_COUNTERS
|
||||||
|
|
||||||
config EARLY_PRINTK
|
config EARLY_PRINTK
|
||||||
bool
|
bool
|
||||||
|
@@ -131,6 +131,8 @@ static inline int irqs_disabled_flags(unsigned long flags)
|
|||||||
struct irq_chip;
|
struct irq_chip;
|
||||||
|
|
||||||
#ifdef CONFIG_PERF_COUNTERS
|
#ifdef CONFIG_PERF_COUNTERS
|
||||||
|
|
||||||
|
#ifdef CONFIG_PPC64
|
||||||
static inline unsigned long test_perf_counter_pending(void)
|
static inline unsigned long test_perf_counter_pending(void)
|
||||||
{
|
{
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
@@ -154,8 +156,9 @@ static inline void clear_perf_counter_pending(void)
|
|||||||
"r" (0),
|
"r" (0),
|
||||||
"i" (offsetof(struct paca_struct, perf_counter_pending)));
|
"i" (offsetof(struct paca_struct, perf_counter_pending)));
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_PPC64 */
|
||||||
|
|
||||||
#else
|
#else /* CONFIG_PERF_COUNTERS */
|
||||||
|
|
||||||
static inline unsigned long test_perf_counter_pending(void)
|
static inline unsigned long test_perf_counter_pending(void)
|
||||||
{
|
{
|
||||||
|
@@ -57,10 +57,16 @@ extern struct power_pmu *ppmu;
|
|||||||
|
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
extern unsigned long perf_misc_flags(struct pt_regs *regs);
|
extern unsigned long perf_misc_flags(struct pt_regs *regs);
|
||||||
#define perf_misc_flags(regs) perf_misc_flags(regs)
|
|
||||||
|
|
||||||
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
|
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only override the default definitions in include/linux/perf_counter.h
|
||||||
|
* if we have hardware PMU support.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_PPC_PERF_CTRS
|
||||||
|
#define perf_misc_flags(regs) perf_misc_flags(regs)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The power_pmu.get_constraint function returns a 64-bit value and
|
* The power_pmu.get_constraint function returns a 64-bit value and
|
||||||
* a 64-bit mask that express the constraints between this event and
|
* a 64-bit mask that express the constraints between this event and
|
||||||
|
@@ -95,9 +95,9 @@ obj64-$(CONFIG_AUDIT) += compat_audit.o
|
|||||||
|
|
||||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||||
obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o power4-pmu.o ppc970-pmu.o \
|
obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o
|
||||||
power5-pmu.o power5+-pmu.o power6-pmu.o \
|
obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \
|
||||||
power7-pmu.o
|
power5+-pmu.o power6-pmu.o power7-pmu.o
|
||||||
|
|
||||||
obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
|
obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@
|
|||||||
#include <linux/posix-timers.h>
|
#include <linux/posix-timers.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/perf_counter.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
@@ -525,6 +526,26 @@ void __init iSeries_time_init_early(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_PPC_ISERIES */
|
#endif /* CONFIG_PPC_ISERIES */
|
||||||
|
|
||||||
|
#if defined(CONFIG_PERF_COUNTERS) && defined(CONFIG_PPC32)
|
||||||
|
DEFINE_PER_CPU(u8, perf_counter_pending);
|
||||||
|
|
||||||
|
void set_perf_counter_pending(void)
|
||||||
|
{
|
||||||
|
get_cpu_var(perf_counter_pending) = 1;
|
||||||
|
set_dec(1);
|
||||||
|
put_cpu_var(perf_counter_pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define test_perf_counter_pending() __get_cpu_var(perf_counter_pending)
|
||||||
|
#define clear_perf_counter_pending() __get_cpu_var(perf_counter_pending) = 0
|
||||||
|
|
||||||
|
#else /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */
|
||||||
|
|
||||||
|
#define test_perf_counter_pending() 0
|
||||||
|
#define clear_perf_counter_pending()
|
||||||
|
|
||||||
|
#endif /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For iSeries shared processors, we have to let the hypervisor
|
* For iSeries shared processors, we have to let the hypervisor
|
||||||
* set the hardware decrementer. We set a virtual decrementer
|
* set the hardware decrementer. We set a virtual decrementer
|
||||||
@@ -551,6 +572,10 @@ void timer_interrupt(struct pt_regs * regs)
|
|||||||
set_dec(DECREMENTER_MAX);
|
set_dec(DECREMENTER_MAX);
|
||||||
|
|
||||||
#ifdef CONFIG_PPC32
|
#ifdef CONFIG_PPC32
|
||||||
|
if (test_perf_counter_pending()) {
|
||||||
|
clear_perf_counter_pending();
|
||||||
|
perf_counter_do_pending();
|
||||||
|
}
|
||||||
if (atomic_read(&ppc_n_lost_interrupts) != 0)
|
if (atomic_read(&ppc_n_lost_interrupts) != 0)
|
||||||
do_IRQ(regs);
|
do_IRQ(regs);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
config PPC64
|
config PPC64
|
||||||
bool "64-bit kernel"
|
bool "64-bit kernel"
|
||||||
default n
|
default n
|
||||||
select HAVE_PERF_COUNTERS
|
select PPC_HAVE_PMU_SUPPORT
|
||||||
help
|
help
|
||||||
This option selects whether a 32-bit or a 64-bit kernel
|
This option selects whether a 32-bit or a 64-bit kernel
|
||||||
will be built.
|
will be built.
|
||||||
@@ -243,6 +243,15 @@ config VIRT_CPU_ACCOUNTING
|
|||||||
|
|
||||||
If in doubt, say Y here.
|
If in doubt, say Y here.
|
||||||
|
|
||||||
|
config PPC_HAVE_PMU_SUPPORT
|
||||||
|
bool
|
||||||
|
|
||||||
|
config PPC_PERF_CTRS
|
||||||
|
def_bool y
|
||||||
|
depends on PERF_COUNTERS && PPC_HAVE_PMU_SUPPORT
|
||||||
|
help
|
||||||
|
This enables the powerpc-specific perf_counter back-end.
|
||||||
|
|
||||||
config SMP
|
config SMP
|
||||||
depends on PPC_STD_MMU || FSL_BOOKE
|
depends on PPC_STD_MMU || FSL_BOOKE
|
||||||
bool "Symmetric multi-processing support"
|
bool "Symmetric multi-processing support"
|
||||||
|
Reference in New Issue
Block a user