diff options
author | Paul Mackerras <paulus@samba.org> | 2009-06-17 07:50:04 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-18 05:11:44 -0400 |
commit | 105988c015943e77092a6568bc5fb7e386df6ccd (patch) | |
tree | bd352fe5e68a66de2e08a8b91c8f8cccf422f346 | |
parent | a73c7d84a1975b44c0ebd03c2dec288af1426349 (diff) |
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>
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/hw_irq.h | 5 | ||||
-rw-r--r-- | arch/powerpc/include/asm/perf_counter.h | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/Makefile | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 25 | ||||
-rw-r--r-- | arch/powerpc/platforms/Kconfig.cputype | 11 |
6 files changed, 51 insertions, 7 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 9fb344d5a86a..bf6cedfa05db 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -126,6 +126,7 @@ config PPC | |||
126 | select HAVE_OPROFILE | 126 | select HAVE_OPROFILE |
127 | select HAVE_SYSCALL_WRAPPERS if PPC64 | 127 | select HAVE_SYSCALL_WRAPPERS if PPC64 |
128 | select GENERIC_ATOMIC64 if PPC32 | 128 | select GENERIC_ATOMIC64 if PPC32 |
129 | select HAVE_PERF_COUNTERS | ||
129 | 130 | ||
130 | config EARLY_PRINTK | 131 | config EARLY_PRINTK |
131 | bool | 132 | bool |
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index 10a642df014e..867ab8ed69b3 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h | |||
@@ -131,6 +131,8 @@ static inline int irqs_disabled_flags(unsigned long flags) | |||
131 | struct irq_chip; | 131 | struct irq_chip; |
132 | 132 | ||
133 | #ifdef CONFIG_PERF_COUNTERS | 133 | #ifdef CONFIG_PERF_COUNTERS |
134 | |||
135 | #ifdef CONFIG_PPC64 | ||
134 | static inline unsigned long test_perf_counter_pending(void) | 136 | static inline unsigned long test_perf_counter_pending(void) |
135 | { | 137 | { |
136 | unsigned long x; | 138 | unsigned long x; |
@@ -154,8 +156,9 @@ static inline void clear_perf_counter_pending(void) | |||
154 | "r" (0), | 156 | "r" (0), |
155 | "i" (offsetof(struct paca_struct, perf_counter_pending))); | 157 | "i" (offsetof(struct paca_struct, perf_counter_pending))); |
156 | } | 158 | } |
159 | #endif /* CONFIG_PPC64 */ | ||
157 | 160 | ||
158 | #else | 161 | #else /* CONFIG_PERF_COUNTERS */ |
159 | 162 | ||
160 | static inline unsigned long test_perf_counter_pending(void) | 163 | static inline unsigned long test_perf_counter_pending(void) |
161 | { | 164 | { |
diff --git a/arch/powerpc/include/asm/perf_counter.h b/arch/powerpc/include/asm/perf_counter.h index b398a84edced..2c2d9f643df0 100644 --- a/arch/powerpc/include/asm/perf_counter.h +++ b/arch/powerpc/include/asm/perf_counter.h | |||
@@ -57,11 +57,17 @@ extern struct power_pmu *ppmu; | |||
57 | 57 | ||
58 | struct pt_regs; | 58 | struct pt_regs; |
59 | extern unsigned long perf_misc_flags(struct pt_regs *regs); | 59 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
60 | #define perf_misc_flags(regs) perf_misc_flags(regs) | ||
61 | |||
62 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); | 60 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); |
63 | 61 | ||
64 | /* | 62 | /* |
63 | * Only override the default definitions in include/linux/perf_counter.h | ||
64 | * if we have hardware PMU support. | ||
65 | */ | ||
66 | #ifdef CONFIG_PPC_PERF_CTRS | ||
67 | #define perf_misc_flags(regs) perf_misc_flags(regs) | ||
68 | #endif | ||
69 | |||
70 | /* | ||
65 | * The power_pmu.get_constraint function returns a 64-bit value and | 71 | * The power_pmu.get_constraint function returns a 64-bit value and |
66 | * a 64-bit mask that express the constraints between this event and | 72 | * a 64-bit mask that express the constraints between this event and |
67 | * other events. | 73 | * other events. |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 612b0c4dc26d..c5f93f061927 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -95,9 +95,9 @@ obj64-$(CONFIG_AUDIT) += compat_audit.o | |||
95 | 95 | ||
96 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 96 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
97 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 97 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
98 | obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o power4-pmu.o ppc970-pmu.o \ | 98 | obj-$(CONFIG_PPC_PERF_CTRS) += perf_counter.o |
99 | power5-pmu.o power5+-pmu.o power6-pmu.o \ | 99 | obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ |
100 | power7-pmu.o | 100 | power5+-pmu.o power6-pmu.o power7-pmu.o |
101 | 101 | ||
102 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o | 102 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o |
103 | 103 | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 15391c2ab013..eae4511ceeac 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/posix-timers.h> | 53 | #include <linux/posix-timers.h> |
54 | #include <linux/irq.h> | 54 | #include <linux/irq.h> |
55 | #include <linux/delay.h> | 55 | #include <linux/delay.h> |
56 | #include <linux/perf_counter.h> | ||
56 | 57 | ||
57 | #include <asm/io.h> | 58 | #include <asm/io.h> |
58 | #include <asm/processor.h> | 59 | #include <asm/processor.h> |
@@ -525,6 +526,26 @@ void __init iSeries_time_init_early(void) | |||
525 | } | 526 | } |
526 | #endif /* CONFIG_PPC_ISERIES */ | 527 | #endif /* CONFIG_PPC_ISERIES */ |
527 | 528 | ||
529 | #if defined(CONFIG_PERF_COUNTERS) && defined(CONFIG_PPC32) | ||
530 | DEFINE_PER_CPU(u8, perf_counter_pending); | ||
531 | |||
532 | void set_perf_counter_pending(void) | ||
533 | { | ||
534 | get_cpu_var(perf_counter_pending) = 1; | ||
535 | set_dec(1); | ||
536 | put_cpu_var(perf_counter_pending); | ||
537 | } | ||
538 | |||
539 | #define test_perf_counter_pending() __get_cpu_var(perf_counter_pending) | ||
540 | #define clear_perf_counter_pending() __get_cpu_var(perf_counter_pending) = 0 | ||
541 | |||
542 | #else /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */ | ||
543 | |||
544 | #define test_perf_counter_pending() 0 | ||
545 | #define clear_perf_counter_pending() | ||
546 | |||
547 | #endif /* CONFIG_PERF_COUNTERS && CONFIG_PPC32 */ | ||
548 | |||
528 | /* | 549 | /* |
529 | * For iSeries shared processors, we have to let the hypervisor | 550 | * For iSeries shared processors, we have to let the hypervisor |
530 | * set the hardware decrementer. We set a virtual decrementer | 551 | * set the hardware decrementer. We set a virtual decrementer |
@@ -551,6 +572,10 @@ void timer_interrupt(struct pt_regs * regs) | |||
551 | set_dec(DECREMENTER_MAX); | 572 | set_dec(DECREMENTER_MAX); |
552 | 573 | ||
553 | #ifdef CONFIG_PPC32 | 574 | #ifdef CONFIG_PPC32 |
575 | if (test_perf_counter_pending()) { | ||
576 | clear_perf_counter_pending(); | ||
577 | perf_counter_do_pending(); | ||
578 | } | ||
554 | if (atomic_read(&ppc_n_lost_interrupts) != 0) | 579 | if (atomic_read(&ppc_n_lost_interrupts) != 0) |
555 | do_IRQ(regs); | 580 | do_IRQ(regs); |
556 | #endif | 581 | #endif |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index cca6b4fc719a..dd9f3ec5ee30 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -1,7 +1,7 @@ | |||
1 | config PPC64 | 1 | config PPC64 |
2 | bool "64-bit kernel" | 2 | bool "64-bit kernel" |
3 | default n | 3 | default n |
4 | select HAVE_PERF_COUNTERS | 4 | select PPC_HAVE_PMU_SUPPORT |
5 | help | 5 | help |
6 | This option selects whether a 32-bit or a 64-bit kernel | 6 | This option selects whether a 32-bit or a 64-bit kernel |
7 | will be built. | 7 | will be built. |
@@ -243,6 +243,15 @@ config VIRT_CPU_ACCOUNTING | |||
243 | 243 | ||
244 | If in doubt, say Y here. | 244 | If in doubt, say Y here. |
245 | 245 | ||
246 | config PPC_HAVE_PMU_SUPPORT | ||
247 | bool | ||
248 | |||
249 | config PPC_PERF_CTRS | ||
250 | def_bool y | ||
251 | depends on PERF_COUNTERS && PPC_HAVE_PMU_SUPPORT | ||
252 | help | ||
253 | This enables the powerpc-specific perf_counter back-end. | ||
254 | |||
246 | config SMP | 255 | config SMP |
247 | depends on PPC_STD_MMU || FSL_BOOKE | 256 | depends on PPC_STD_MMU || FSL_BOOKE |
248 | bool "Symmetric multi-processing support" | 257 | bool "Symmetric multi-processing support" |