Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 105988c0 authored by Paul Mackerras's avatar Paul Mackerras Committed by Ingo Molnar
Browse files

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: default avatarPaul 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: default avatarIngo Molnar <mingo@elte.hu>
parent a73c7d84
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ config PPC
	select HAVE_OPROFILE
	select HAVE_SYSCALL_WRAPPERS if PPC64
	select GENERIC_ATOMIC64 if PPC32
	select HAVE_PERF_COUNTERS

config EARLY_PRINTK
	bool
+4 −1
Original line number Diff line number Diff line
@@ -131,6 +131,8 @@ static inline int irqs_disabled_flags(unsigned long flags)
struct irq_chip;

#ifdef CONFIG_PERF_COUNTERS

#ifdef CONFIG_PPC64
static inline unsigned long test_perf_counter_pending(void)
{
	unsigned long x;
@@ -154,8 +156,9 @@ static inline void clear_perf_counter_pending(void)
		"r" (0),
		"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)
{
+8 −2
Original line number Diff line number Diff line
@@ -57,10 +57,16 @@ extern struct power_pmu *ppmu;

struct pt_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);

/*
 * 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
 * a 64-bit mask that express the constraints between this event and
+3 −3
Original line number Diff line number Diff line
@@ -95,9 +95,9 @@ obj64-$(CONFIG_AUDIT) += compat_audit.o

obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
obj-$(CONFIG_PERF_COUNTERS)	+= perf_counter.o power4-pmu.o ppc970-pmu.o \
				   power5-pmu.o power5+-pmu.o power6-pmu.o \
				   power7-pmu.o
obj-$(CONFIG_PPC_PERF_CTRS)	+= perf_counter.o
obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
				   power5+-pmu.o power6-pmu.o power7-pmu.o

obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o

+25 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
#include <linux/posix-timers.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/perf_counter.h>

#include <asm/io.h>
#include <asm/processor.h>
@@ -525,6 +526,26 @@ void __init iSeries_time_init_early(void)
}
#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
 * set the hardware decrementer.  We set a virtual decrementer
@@ -551,6 +572,10 @@ void timer_interrupt(struct pt_regs * regs)
	set_dec(DECREMENTER_MAX);

#ifdef CONFIG_PPC32
	if (test_perf_counter_pending()) {
		clear_perf_counter_pending();
		perf_counter_do_pending();
	}
	if (atomic_read(&ppc_n_lost_interrupts) != 0)
		do_IRQ(regs);
#endif
Loading