diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-04-17 06:35:01 +0200 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-04-18 07:38:47 +0200 |
commit | 945feb174b14e7098cc7ecf0cf4768d35bc52f9c (patch) | |
tree | 9810b2ff0efe8edbfb1506f65834ea0d553e2848 /arch | |
parent | [POWERPC] Stacktrace support for lockdep (diff) | |
download | linux-945feb174b14e7098cc7ecf0cf4768d35bc52f9c.tar.xz linux-945feb174b14e7098cc7ecf0cf4768d35bc52f9c.zip |
[POWERPC] irqtrace support for 64-bit powerpc
This adds the low level irq tracing hooks to the powerpc architecture
needed to enable full lockdep functionality.
This is partly based on Johannes Berg's initial version. I removed
the asm trampoline that isn't needed (thus improving performance) and
modified all sorts of bits and pieces, reworking most of the assembly,
etc...
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/Kconfig | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 27 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_64.S | 47 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/ppc_ksyms.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 4 |
6 files changed, 72 insertions, 22 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index ecca20d17a7b..4bb2e9310a56 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -53,6 +53,15 @@ config STACKTRACE_SUPPORT bool default y +config TRACE_IRQFLAGS_SUPPORT + bool + depends on PPC64 + default y + +config LOCKDEP_SUPPORT + bool + default y + config RWSEM_GENERIC_SPINLOCK bool diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 13019845536b..c0db5b769e55 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -30,6 +30,7 @@ #include <asm/firmware.h> #include <asm/bug.h> #include <asm/ptrace.h> +#include <asm/irqflags.h> /* * System calls. @@ -89,6 +90,14 @@ system_call_common: addi r9,r1,STACK_FRAME_OVERHEAD ld r11,exception_marker@toc(r2) std r11,-16(r9) /* "regshere" marker */ +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_on + REST_GPR(0,r1) + REST_4GPRS(3,r1) + REST_2GPRS(7,r1) + addi r9,r1,STACK_FRAME_OVERHEAD + ld r12,_MSR(r1) +#endif /* CONFIG_TRACE_IRQFLAGS */ li r10,1 stb r10,PACASOFTIRQEN(r13) stb r10,PACAHARDIRQEN(r13) @@ -103,7 +112,7 @@ BEGIN_FW_FTR_SECTION b hardware_interrupt_entry 2: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif +#endif /* CONFIG_PPC_ISERIES */ mfmsr r11 ori r11,r11,MSR_EE mtmsrd r11,1 @@ -505,6 +514,10 @@ BEGIN_FW_FTR_SECTION li r3,0 stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_off + mfmsr r10 +#endif ori r10,r10,MSR_EE mtmsrd r10 /* hard-enable again */ addi r3,r1,STACK_FRAME_OVERHEAD @@ -513,7 +526,7 @@ BEGIN_FW_FTR_SECTION 4: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif - stb r5,PACASOFTIRQEN(r13) + TRACE_AND_RESTORE_IRQ(r5); /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) @@ -581,6 +594,16 @@ do_work: bne restore /* here we are preempting the current task */ 1: +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_on + /* Note: we just clobbered r10 which used to contain the previous + * MSR before the hard-disabling done by the caller of do_work. + * We don't have that value anymore, but it doesn't matter as + * we will hard-enable unconditionally, we can just reload the + * current MSR into r10 + */ + mfmsr r10 +#endif /* CONFIG_TRACE_IRQFLAGS */ li r0,1 stb r0,PACASOFTIRQEN(r13) stb r0,PACAHARDIRQEN(r13) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 44229c3749ac..215973a2c8d5 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -36,8 +36,7 @@ #include <asm/firmware.h> #include <asm/page_64.h> #include <asm/exception.h> - -#define DO_SOFT_DISABLE +#include <asm/irqflags.h> /* * We layout physical memory as follows: @@ -450,8 +449,8 @@ bad_stack: */ fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) + TRACE_AND_RESTORE_IRQ(r3); ld r12,_MSR(r1) - stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ b 1f @@ -824,7 +823,7 @@ _STATIC(load_up_altivec) * Hash table stuff */ .align 7 -_GLOBAL(do_hash_page) +_STATIC(do_hash_page) std r3,_DAR(r1) std r4,_DSISR(r1) @@ -836,6 +835,27 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFCLR(CPU_FTR_SLB) /* + * On iSeries, we soft-disable interrupts here, then + * hard-enable interrupts so that the hash_page code can spin on + * the hash_table_lock without problems on a shared processor. + */ + DISABLE_INTS + + /* + * Currently, trace_hardirqs_off() will be called by DISABLE_INTS + * and will clobber volatile registers when irq tracing is enabled + * so we need to reload them. It may be possible to be smarter here + * and move the irq tracing elsewhere but let's keep it simple for + * now + */ +#ifdef CONFIG_TRACE_IRQFLAGS + ld r3,_DAR(r1) + ld r4,_DSISR(r1) + ld r5,_TRAP(r1) + ld r12,_MSR(r1) + clrrdi r5,r5,4 +#endif /* CONFIG_TRACE_IRQFLAGS */ + /* * We need to set the _PAGE_USER bit if MSR_PR is set or if we are * accessing a userspace segment (even from the kernel). We assume * kernel addresses always have the high bit set. @@ -848,13 +868,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */ /* - * On iSeries, we soft-disable interrupts here, then - * hard-enable interrupts so that the hash_page code can spin on - * the hash_table_lock without problems on a shared processor. - */ - DISABLE_INTS - - /* * r3 contains the faulting address * r4 contains the required access permissions * r5 contains the trap number @@ -864,7 +877,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) bl .hash_page /* build HPTE if possible */ cmpdi r3,0 /* see if hash_page succeeded */ -#ifdef DO_SOFT_DISABLE BEGIN_FW_FTR_SECTION /* * If we had interrupts soft-enabled at the point where the @@ -876,7 +888,7 @@ BEGIN_FW_FTR_SECTION */ beq 13f END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) -#endif + BEGIN_FW_FTR_SECTION /* * Here we have interrupts hard-disabled, so it is sufficient @@ -890,11 +902,12 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) /* * hash_page couldn't handle it, set soft interrupt enable back - * to what it was before the trap. Note that .local_irq_restore + * to what it was before the trap. Note that .raw_local_irq_restore * handles any interrupts pending at this point. */ ld r3,SOFTE(r1) - bl .local_irq_restore + TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f) + bl .raw_local_irq_restore b 11f /* Here we have a page fault that hash_page can't handle. */ @@ -1493,6 +1506,10 @@ _INIT_STATIC(start_here_multiplatform) addi r2,r2,0x4000 add r2,r2,r26 + /* Set initial ptr to current */ + LOAD_REG_IMMEDIATE(r4, init_task) + std r4,PACACURRENT(r13) + /* Do very early kernel initializations, including initial hash table, * stab and slb setup before we turn on relocation. */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4617b65d464d..425616f92d18 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsigned long enable) : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); } -void local_irq_restore(unsigned long en) +void raw_local_irq_restore(unsigned long en) { /* * get_paca()->soft_enabled = en; @@ -174,6 +174,7 @@ void local_irq_restore(unsigned long en) __hard_irq_enable(); } +EXPORT_SYMBOL(raw_local_irq_restore); #endif /* CONFIG_PPC64 */ int show_interrupts(struct seq_file *p, void *v) diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 5a4c76eada48..b9b765c7d1a7 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -45,10 +45,6 @@ #include <asm/signal.h> #include <asm/dcr.h> -#ifdef CONFIG_PPC64 -EXPORT_SYMBOL(local_irq_restore); -#endif - #ifdef CONFIG_PPC32 extern void transfer_to_handler(void); extern void do_IRQ(struct pt_regs *regs); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 0205d408d2ed..31ada9fdfc5c 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -33,6 +33,7 @@ #include <linux/serial_8250.h> #include <linux/bootmem.h> #include <linux/pci.h> +#include <linux/lockdep.h> #include <linux/lmb.h> #include <asm/io.h> #include <asm/kdump.h> @@ -178,6 +179,9 @@ void __init early_setup(unsigned long dt_ptr) /* Enable early debugging if any specified (see udbg.h) */ udbg_early_init(); + /* Initialize lockdep early or else spinlocks will blow */ + lockdep_init(); + DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr); /* |