* powerpc stacktrace and lockdep support @ 2007-01-08 13:54 Christoph Hellwig 2007-06-26 22:47 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2007-01-08 13:54 UTC (permalink / raw) To: linuxppc-dev I recently tried to work on lockdep for powerpc. I have preliminary version of the stacktrace code, but had to give up on trace irqflags support because I'm not that knowledgeable on lowlevel ppc details. Maybe someone more faimilar with the code wants to give it another try? My stacktrace code is below: Index: linux-2.6/arch/powerpc/Kconfig =================================================================== --- linux-2.6.orig/arch/powerpc/Kconfig 2006-12-25 13:47:19.000000000 +0100 +++ linux-2.6/arch/powerpc/Kconfig 2006-12-25 13:47:53.000000000 +0100 @@ -34,6 +34,10 @@ bool default y +config STACKTRACE_SUPPORT + bool + default y + config RWSEM_GENERIC_SPINLOCK bool Index: linux-2.6/arch/powerpc/kernel/Makefile =================================================================== --- linux-2.6.orig/arch/powerpc/kernel/Makefile 2006-12-25 13:47:19.000000000 +0100 +++ linux-2.6/arch/powerpc/kernel/Makefile 2006-12-25 13:47:53.000000000 +0100 @@ -58,6 +58,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) Index: linux-2.6/arch/powerpc/kernel/stacktrace.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6/arch/powerpc/kernel/stacktrace.c 2006-12-25 13:51:06.000000000 +0100 @@ -0,0 +1,52 @@ + +#include <linux/sched.h> +#include <linux/stacktrace.h> + + +#ifdef CONFIG_PPC64 +#define MIN_STACK_FRAME 112 /* same as STACK_FRAME_OVERHEAD, in fact */ +#define FRAME_LR_SAVE 2 +#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD + 288) +#define REGS_MARKER 0x7265677368657265ul +#define FRAME_MARKER 12 +#else +#define MIN_STACK_FRAME 16 +#define FRAME_LR_SAVE 1 +#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD) +#define REGS_MARKER 0x72656773ul +#define FRAME_MARKER 2 +#endif + + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + * If all_contexts is set, all contexts (hardirq, softirq and process) + * are saved. If not set then only the current context is saved. + */ +void save_stack_trace(struct stack_trace *trace) +{ + unsigned long sp; + + asm("mr %0,1" : "=r" (sp)); + + for (;;) { + unsigned long *stack = (unsigned long *) sp; + unsigned long newsp, ip; + + if (!validate_sp(sp, current, MIN_STACK_FRAME)) + return; + + newsp = stack[0]; + ip = stack[FRAME_LR_SAVE]; + + if (!trace->skip) + trace->entries[trace->nr_entries++] = ip; + else + trace->skip--; + + if (trace->nr_entries >= trace->max_entries) + return; + + sp = newsp; + } +} ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-01-08 13:54 powerpc stacktrace and lockdep support Christoph Hellwig @ 2007-06-26 22:47 ` Johannes Berg 2007-06-27 19:00 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2007-06-26 22:47 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linuxppc-dev On Mon, 2007-01-08 at 14:54 +0100, Christoph Hellwig wrote: > I recently tried to work on lockdep for powerpc. I have preliminary > version of the stacktrace code That seems to work. > , but had to give up on trace irqflags > support because I'm not that knowledgeable on lowlevel ppc details. I gave it a try. Actually what I had wanted to do was add lockdep support for things like function A: lock() flush_scheduled_work() unlock() function B: (work function that is scheduled) ... lock() ... unlock() ... which can obviously deadlock but isn't caught by any debugging mechanisms right now. So anyway, lockdep doesn't work here since I only own powerpc machines, hence I tried to make it work. Below is the patch, it's quite ugly and only works on 64-bit right now, it'll probably totally screw up on 32-bit (though hopefully it only makes lockdep complain and stop itself on 32-bit). I currently get a lockdep report in XFS with this code. Not sure if there's a bug in this code or if it actually complains rightfully, the self-tests all pass... --- arch/powerpc/Kconfig | 8 +++++ arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/entry_64.S | 23 ++++++++++++++++ arch/powerpc/kernel/head_64.S | 55 ++++++++++++++++++++++++++++++++-------- arch/powerpc/kernel/irq.c | 2 - arch/powerpc/kernel/irqtrace.S | 42 ++++++++++++++++++++++++++++++ arch/powerpc/kernel/ppc_ksyms.c | 2 - arch/powerpc/kernel/setup_64.c | 6 ++++ include/asm-powerpc/hw_irq.h | 34 +++++++++++++----------- include/asm-powerpc/irqflags.h | 11 ++++---- include/asm-powerpc/rwsem.h | 34 ++++++++++++++++++------ include/asm-powerpc/spinlock.h | 1 12 files changed, 177 insertions(+), 42 deletions(-) --- linux-2.6-git.orig/arch/powerpc/Kconfig 2007-06-26 18:12:10.424850274 +0200 +++ linux-2.6-git/arch/powerpc/Kconfig 2007-06-26 20:01:50.544814034 +0200 @@ -38,6 +38,14 @@ config STACKTRACE_SUPPORT bool default y +config TRACE_IRQFLAGS_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + config RWSEM_GENERIC_SPINLOCK bool --- linux-2.6-git.orig/arch/powerpc/kernel/irq.c 2007-06-26 18:12:10.491850274 +0200 +++ linux-2.6-git/arch/powerpc/kernel/irq.c 2007-06-26 18:12:11.376850274 +0200 @@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi : : "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; --- linux-2.6-git.orig/arch/powerpc/kernel/ppc_ksyms.c 2007-06-26 18:12:10.513850274 +0200 +++ linux-2.6-git/arch/powerpc/kernel/ppc_ksyms.c 2007-06-26 18:12:11.377850274 +0200 @@ -50,7 +50,7 @@ #endif #ifdef CONFIG_PPC64 -EXPORT_SYMBOL(local_irq_restore); +EXPORT_SYMBOL(raw_local_irq_restore); #endif #ifdef CONFIG_PPC32 --- linux-2.6-git.orig/include/asm-powerpc/hw_irq.h 2007-06-26 18:12:10.618850274 +0200 +++ linux-2.6-git/include/asm-powerpc/hw_irq.h 2007-06-26 18:12:11.443850274 +0200 @@ -27,7 +27,7 @@ static inline unsigned long local_get_fl return flags; } -static inline unsigned long local_irq_disable(void) +static inline unsigned long raw_local_irq_disable(void) { unsigned long flags, zero; @@ -39,14 +39,15 @@ static inline unsigned long local_irq_di return flags; } -extern void local_irq_restore(unsigned long); +extern void raw_local_irq_restore(unsigned long); extern void iseries_handle_interrupts(void); -#define local_irq_enable() local_irq_restore(1) -#define local_save_flags(flags) ((flags) = local_get_flags()) -#define local_irq_save(flags) ((flags) = local_irq_disable()) +#define raw_local_irq_enable() raw_local_irq_restore(1) +#define raw_local_save_flags(flags) ((flags) = local_get_flags()) +#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable()) -#define irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled_flags(flags) ((flags) == 0) #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) @@ -62,13 +63,13 @@ extern void iseries_handle_interrupts(vo #if defined(CONFIG_BOOKE) #define SET_MSR_EE(x) mtmsr(x) -#define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") +#define raw_local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") #else #define SET_MSR_EE(x) mtmsr(x) -#define local_irq_restore(flags) mtmsr(flags) +#define raw_local_irq_restore(flags) mtmsr(flags) #endif -static inline void local_irq_disable(void) +static inline void raw_local_irq_disable(void) { #ifdef CONFIG_BOOKE __asm__ __volatile__("wrteei 0": : :"memory"); @@ -80,7 +81,7 @@ static inline void local_irq_disable(voi #endif } -static inline void local_irq_enable(void) +static inline void raw_local_irq_enable(void) { #ifdef CONFIG_BOOKE __asm__ __volatile__("wrteei 1": : :"memory"); @@ -92,7 +93,7 @@ static inline void local_irq_enable(void #endif } -static inline void local_irq_save_ptr(unsigned long *flags) +static inline void raw_local_irq_save_ptr(unsigned long *flags) { unsigned long msr; msr = mfmsr(); @@ -105,12 +106,13 @@ static inline void local_irq_save_ptr(un __asm__ __volatile__("": : :"memory"); } -#define local_save_flags(flags) ((flags) = mfmsr()) -#define local_irq_save(flags) local_irq_save_ptr(&flags) -#define irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define raw_local_save_flags(flags) ((flags) = mfmsr()) +#define raw_local_irq_save(flags) raw_local_irq_save_ptr(&flags) +#define raw_irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0) -#define hard_irq_enable() local_irq_enable() -#define hard_irq_disable() local_irq_disable() +#define hard_irq_enable() raw_local_irq_enable() +#define hard_irq_disable() raw_local_irq_disable() #endif /* CONFIG_PPC64 */ --- linux-2.6-git.orig/include/asm-powerpc/irqflags.h 2007-06-26 18:12:10.669850274 +0200 +++ linux-2.6-git/include/asm-powerpc/irqflags.h 2007-06-27 00:35:50.806820710 +0200 @@ -10,19 +10,20 @@ #ifndef _ASM_IRQFLAGS_H #define _ASM_IRQFLAGS_H +#ifndef __ASSEMBLY__ /* * Get definitions for raw_local_save_flags(x), etc. */ #include <asm-powerpc/hw_irq.h> +#endif /* - * Do the CPU's IRQ-state tracing from assembly code. We call a - * C function, so save all the C-clobbered registers: + * Do the CPU's IRQ-state tracing from assembly code. Also + * note the code in arch/powerpc/kernel/irqtrace.S. */ #ifdef CONFIG_TRACE_IRQFLAGS - -#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS - +# define TRACE_IRQS_ON bl .powerpc_trace_irqs_on +# define TRACE_IRQS_OFF bl .powerpc_trace_irqs_off #else # define TRACE_IRQS_ON # define TRACE_IRQS_OFF --- linux-2.6-git.orig/include/asm-powerpc/rwsem.h 2007-06-26 18:12:10.747850274 +0200 +++ linux-2.6-git/include/asm-powerpc/rwsem.h 2007-06-27 00:13:57.397341965 +0200 @@ -28,11 +28,21 @@ struct rw_semaphore { #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) } + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -42,12 +52,15 @@ extern struct rw_semaphore *rwsem_down_w extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ + } while (0) /* * lock for reading @@ -74,7 +87,7 @@ static inline int __down_read_trylock(st /* * lock for writing */ -static inline void __down_write(struct rw_semaphore *sem) +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { int tmp; @@ -84,6 +97,11 @@ static inline void __down_write(struct r rwsem_down_write_failed(sem); } +static inline void __down_write(struct rw_semaphore *sem) +{ + __down_write_nested(sem, 0); +} + static inline int __down_write_trylock(struct rw_semaphore *sem) { int tmp; --- linux-2.6-git.orig/include/asm-powerpc/spinlock.h 2007-06-26 18:12:10.639850274 +0200 +++ linux-2.6-git/include/asm-powerpc/spinlock.h 2007-06-26 18:12:11.446850274 +0200 @@ -19,6 +19,7 @@ * * (the type definitions are in asm/spinlock_types.h) */ +#include <linux/irqflags.h> #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> --- linux-2.6-git.orig/arch/powerpc/kernel/head_64.S 2007-06-26 18:12:10.537850274 +0200 +++ linux-2.6-git/arch/powerpc/kernel/head_64.S 2007-06-27 00:34:57.402820710 +0200 @@ -34,6 +34,7 @@ #include <asm/iseries/lpar_map.h> #include <asm/thread_info.h> #include <asm/firmware.h> +#include <asm/irqflags.h> #define DO_SOFT_DISABLE @@ -394,6 +395,12 @@ label##_iSeries: \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ +#ifdef CONFIG_TRACE_IRQFLAGS +#define TRACE_DISABLE_INTS bl .powerpc_trace_irqs_off +#else +#define TRACE_DISABLE_INTS +#endif + #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ li r11,0; \ @@ -405,14 +412,15 @@ BEGIN_FW_FTR_SECTION; \ mfmsr r10; \ ori r10,r10,MSR_EE; \ mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ + TRACE_DISABLE_INTS #else #define DISABLE_INTS \ li r11,0; \ stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13) - + stb r11,PACAHARDIRQEN(r13); \ + TRACE_DISABLE_INTS #endif /* CONFIG_PPC_ISERIES */ #define ENABLE_INTS \ @@ -965,24 +973,38 @@ bad_stack: */ fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) - ld r12,_MSR(r1) +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 1f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +1: stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ + cmpdi r3,0 + bne 2f + bl .trace_hardirqs_off + ld r3,SOFTE(r1) +2: +#else + stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ +#endif + ld r12,_MSR(r1) rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ - b 1f + b 3f .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) -1: ld r11,_NIP(r1) +3: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer #ifdef CONFIG_VIRT_CPU_ACCOUNTING andi. r3,r12,MSR_PR - beq 2f + beq 4f ACCOUNT_CPU_USER_EXIT(r3, r4) -2: +4: #endif ld r3,_CCR(r1) @@ -1387,11 +1409,24 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER /* * 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 +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 14f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +14: + bl .raw_local_irq_restore + cmpdi r3,0 + bne 15f + bl .trace_hardirqs_off +15: +#else + bl .raw_local_irq_restore +#endif b 11f /* Here we have a page fault that hash_page can't handle. */ --- linux-2.6-git.orig/arch/powerpc/kernel/setup_64.c 2007-06-26 18:12:10.594850274 +0200 +++ linux-2.6-git/arch/powerpc/kernel/setup_64.c 2007-06-26 18:12:11.451850274 +0200 @@ -33,6 +33,7 @@ #include <linux/serial_8250.h> #include <linux/bootmem.h> #include <linux/pci.h> +#include <linux/lockdep.h> #include <asm/io.h> #include <asm/kdump.h> #include <asm/prom.h> @@ -359,6 +360,11 @@ void __init setup_system(void) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); /* + * start lockdep + */ + lockdep_init(); + + /* * Unflatten the device-tree passed by prom_init or kexec */ unflatten_device_tree(); --- linux-2.6-git.orig/arch/powerpc/kernel/entry_64.S 2007-06-26 18:20:59.030850274 +0200 +++ linux-2.6-git/arch/powerpc/kernel/entry_64.S 2007-06-26 21:25:58.630569893 +0200 @@ -29,6 +29,7 @@ #include <asm/cputable.h> #include <asm/firmware.h> #include <asm/bug.h> +#include <asm/irqflags.h> /* * System calls. @@ -91,6 +92,13 @@ system_call_common: li r10,1 stb r10,PACASOFTIRQEN(r13) stb r10,PACAHARDIRQEN(r13) +#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 +#endif std r10,SOFTE(r1) #ifdef CONFIG_PPC_ISERIES BEGIN_FW_FTR_SECTION @@ -491,8 +499,20 @@ BEGIN_FW_FTR_SECTION 4: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r5,0 + beq 5f + bl .trace_hardirqs_on + ld r5,SOFTE(r1) stb r5,PACASOFTIRQEN(r13) - + b 6f +5: + stb r5,PACASOFTIRQEN(r13) + bl .trace_hardirqs_off +6: +#else + stb r5,PACASOFTIRQEN(r13) +#endif /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ @@ -560,6 +580,7 @@ do_work: bne restore /* here we are preempting the current task */ 1: + TRACE_IRQS_ON li r0,1 stb r0,PACASOFTIRQEN(r13) stb r0,PACAHARDIRQEN(r13) --- linux-2.6-git.orig/arch/powerpc/kernel/Makefile 2007-06-26 19:27:54.032776841 +0200 +++ linux-2.6-git/arch/powerpc/kernel/Makefile 2007-06-27 00:30:19.115820710 +0200 @@ -62,6 +62,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_TRACE_IRQFLAGS) += irqtrace.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6-git/arch/powerpc/kernel/irqtrace.S 2007-06-27 00:32:07.125820710 +0200 @@ -0,0 +1,42 @@ +/* + * crappy helper for irq-trace + */ + +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> + +#define STACKSPACE GPR0 + 16*8 + +#ifdef __powerpc64__ +#define ST std +#define L ld +#else +#define ST stw +#define L lw +#endif + +#define PRE \ + subi r1,r1,STACKSPACE ; \ + SAVE_GPR(0, r1) ; \ + SAVE_8GPRS(2, r1) ; \ + SAVE_4GPRS(10, r1) ; \ + mfcr r0 ; \ + ST r0, (14*8)(r1) ; \ + mflr r0 ; \ + ST r0, (15*8)(r1) + +#define POST \ + REST_8GPRS(2, r1) ; \ + REST_4GPRS(10, r1) ; \ + L r0, (14*8)(r1) ; \ + mtcr r0 ; \ + L r0, (15*8)(r1) ; \ + mtlr r0 ; \ + REST_GPR(0, r1) ; \ + addi r1,r1,STACKSPACE + +_GLOBAL(powerpc_trace_irqs_off) + PRE + bl .trace_hardirqs_off + POST + blr ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-06-26 22:47 ` Johannes Berg @ 2007-06-27 19:00 ` Johannes Berg 2007-06-28 16:20 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2007-06-27 19:00 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linuxppc-dev Here's a somewhat cleaned-up version that also works with preempt, still 64-bit only, still breaks 32-bit compile (I think, untested). Works fine on my quad G5 and I've actually made a patch to lockdep to support flagging my workqueue deadlock, that works too. And the XFS report I had previously was also "correct" in the sense that it occurs on all machines and has been patched (although there never was a possible deadlock.) --- arch/powerpc/Kconfig | 8 +++++ arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/entry_64.S | 24 +++++++++++++++++ arch/powerpc/kernel/head_64.S | 54 ++++++++++++++++++++++++++++++++-------- arch/powerpc/kernel/irq.c | 2 - arch/powerpc/kernel/irqtrace.S | 47 ++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/ppc_ksyms.c | 2 - arch/powerpc/kernel/setup_64.c | 6 ++++ include/asm-powerpc/hw_irq.h | 34 +++++++++++++------------ include/asm-powerpc/irqflags.h | 13 --------- include/asm-powerpc/rwsem.h | 34 +++++++++++++++++++------ include/asm-powerpc/spinlock.h | 1 12 files changed, 176 insertions(+), 50 deletions(-) --- linux-2.6-git.orig/arch/powerpc/Kconfig 2007-06-27 17:37:39.884965668 +0200 +++ linux-2.6-git/arch/powerpc/Kconfig 2007-06-27 17:38:07.929965668 +0200 @@ -38,6 +38,14 @@ config STACKTRACE_SUPPORT bool default y +config TRACE_IRQFLAGS_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + config RWSEM_GENERIC_SPINLOCK bool --- linux-2.6-git.orig/arch/powerpc/kernel/irq.c 2007-06-27 17:37:39.907965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/irq.c 2007-06-27 17:38:07.953965668 +0200 @@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi : : "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; --- linux-2.6-git.orig/arch/powerpc/kernel/ppc_ksyms.c 2007-06-27 17:37:39.930965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/ppc_ksyms.c 2007-06-27 17:38:07.954965668 +0200 @@ -50,7 +50,7 @@ #endif #ifdef CONFIG_PPC64 -EXPORT_SYMBOL(local_irq_restore); +EXPORT_SYMBOL(raw_local_irq_restore); #endif #ifdef CONFIG_PPC32 --- linux-2.6-git.orig/include/asm-powerpc/hw_irq.h 2007-06-27 17:37:40.209965668 +0200 +++ linux-2.6-git/include/asm-powerpc/hw_irq.h 2007-06-27 17:38:08.025965668 +0200 @@ -27,7 +27,7 @@ static inline unsigned long local_get_fl return flags; } -static inline unsigned long local_irq_disable(void) +static inline unsigned long raw_local_irq_disable(void) { unsigned long flags, zero; @@ -39,14 +39,15 @@ static inline unsigned long local_irq_di return flags; } -extern void local_irq_restore(unsigned long); +extern void raw_local_irq_restore(unsigned long); extern void iseries_handle_interrupts(void); -#define local_irq_enable() local_irq_restore(1) -#define local_save_flags(flags) ((flags) = local_get_flags()) -#define local_irq_save(flags) ((flags) = local_irq_disable()) +#define raw_local_irq_enable() raw_local_irq_restore(1) +#define raw_local_save_flags(flags) ((flags) = local_get_flags()) +#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable()) -#define irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled_flags(flags) ((flags) == 0) #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) @@ -62,13 +63,13 @@ extern void iseries_handle_interrupts(vo #if defined(CONFIG_BOOKE) #define SET_MSR_EE(x) mtmsr(x) -#define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") +#define raw_local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") #else #define SET_MSR_EE(x) mtmsr(x) -#define local_irq_restore(flags) mtmsr(flags) +#define raw_local_irq_restore(flags) mtmsr(flags) #endif -static inline void local_irq_disable(void) +static inline void raw_local_irq_disable(void) { #ifdef CONFIG_BOOKE __asm__ __volatile__("wrteei 0": : :"memory"); @@ -80,7 +81,7 @@ static inline void local_irq_disable(voi #endif } -static inline void local_irq_enable(void) +static inline void raw_local_irq_enable(void) { #ifdef CONFIG_BOOKE __asm__ __volatile__("wrteei 1": : :"memory"); @@ -92,7 +93,7 @@ static inline void local_irq_enable(void #endif } -static inline void local_irq_save_ptr(unsigned long *flags) +static inline void raw_local_irq_save_ptr(unsigned long *flags) { unsigned long msr; msr = mfmsr(); @@ -105,12 +106,13 @@ static inline void local_irq_save_ptr(un __asm__ __volatile__("": : :"memory"); } -#define local_save_flags(flags) ((flags) = mfmsr()) -#define local_irq_save(flags) local_irq_save_ptr(&flags) -#define irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define raw_local_save_flags(flags) ((flags) = mfmsr()) +#define raw_local_irq_save(flags) raw_local_irq_save_ptr(&flags) +#define raw_irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0) -#define hard_irq_enable() local_irq_enable() -#define hard_irq_disable() local_irq_disable() +#define hard_irq_enable() raw_local_irq_enable() +#define hard_irq_disable() raw_local_irq_disable() #endif /* CONFIG_PPC64 */ --- linux-2.6-git.orig/include/asm-powerpc/irqflags.h 2007-06-27 17:37:40.234965668 +0200 +++ linux-2.6-git/include/asm-powerpc/irqflags.h 2007-06-27 17:39:18.499965668 +0200 @@ -15,17 +15,4 @@ */ #include <asm-powerpc/hw_irq.h> -/* - * Do the CPU's IRQ-state tracing from assembly code. We call a - * C function, so save all the C-clobbered registers: - */ -#ifdef CONFIG_TRACE_IRQFLAGS - -#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS - -#else -# define TRACE_IRQS_ON -# define TRACE_IRQS_OFF -#endif - #endif --- linux-2.6-git.orig/include/asm-powerpc/rwsem.h 2007-06-27 17:37:40.256965668 +0200 +++ linux-2.6-git/include/asm-powerpc/rwsem.h 2007-06-27 17:38:08.051965668 +0200 @@ -28,11 +28,21 @@ struct rw_semaphore { #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) } + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -42,12 +52,15 @@ extern struct rw_semaphore *rwsem_down_w extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ + } while (0) /* * lock for reading @@ -74,7 +87,7 @@ static inline int __down_read_trylock(st /* * lock for writing */ -static inline void __down_write(struct rw_semaphore *sem) +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { int tmp; @@ -84,6 +97,11 @@ static inline void __down_write(struct r rwsem_down_write_failed(sem); } +static inline void __down_write(struct rw_semaphore *sem) +{ + __down_write_nested(sem, 0); +} + static inline int __down_write_trylock(struct rw_semaphore *sem) { int tmp; --- linux-2.6-git.orig/include/asm-powerpc/spinlock.h 2007-06-27 17:37:40.293965668 +0200 +++ linux-2.6-git/include/asm-powerpc/spinlock.h 2007-06-27 17:38:08.056965668 +0200 @@ -19,6 +19,7 @@ * * (the type definitions are in asm/spinlock_types.h) */ +#include <linux/irqflags.h> #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> --- linux-2.6-git.orig/arch/powerpc/kernel/head_64.S 2007-06-27 17:37:39.953965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/head_64.S 2007-06-27 17:52:08.742965668 +0200 @@ -394,6 +394,12 @@ label##_iSeries: \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ +#ifdef CONFIG_TRACE_IRQFLAGS +#define TRACE_DISABLE_INTS bl .powerpc_trace_hardirqs_off +#else +#define TRACE_DISABLE_INTS +#endif + #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ li r11,0; \ @@ -405,14 +411,15 @@ BEGIN_FW_FTR_SECTION; \ mfmsr r10; \ ori r10,r10,MSR_EE; \ mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ + TRACE_DISABLE_INTS #else #define DISABLE_INTS \ li r11,0; \ stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13) - + stb r11,PACAHARDIRQEN(r13); \ + TRACE_DISABLE_INTS #endif /* CONFIG_PPC_ISERIES */ #define ENABLE_INTS \ @@ -965,24 +972,38 @@ bad_stack: */ fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) - ld r12,_MSR(r1) +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 1f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +1: stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ + cmpdi r3,0 + bne 2f + bl .trace_hardirqs_off + ld r3,SOFTE(r1) +2: +#else + stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ +#endif + ld r12,_MSR(r1) rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ - b 1f + b 3f .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) -1: ld r11,_NIP(r1) +3: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer #ifdef CONFIG_VIRT_CPU_ACCOUNTING andi. r3,r12,MSR_PR - beq 2f + beq 4f ACCOUNT_CPU_USER_EXIT(r3, r4) -2: +4: #endif ld r3,_CCR(r1) @@ -1387,11 +1408,24 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER /* * 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 +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 14f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +14: + bl .raw_local_irq_restore + cmpdi r3,0 + bne 15f + bl .trace_hardirqs_off +15: +#else + bl .raw_local_irq_restore +#endif b 11f /* Here we have a page fault that hash_page can't handle. */ --- linux-2.6-git.orig/arch/powerpc/kernel/setup_64.c 2007-06-27 17:37:39.976965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/setup_64.c 2007-06-27 17:38:08.062965668 +0200 @@ -33,6 +33,7 @@ #include <linux/serial_8250.h> #include <linux/bootmem.h> #include <linux/pci.h> +#include <linux/lockdep.h> #include <asm/io.h> #include <asm/kdump.h> #include <asm/prom.h> @@ -359,6 +360,11 @@ void __init setup_system(void) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); /* + * start lockdep + */ + lockdep_init(); + + /* * Unflatten the device-tree passed by prom_init or kexec */ unflatten_device_tree(); --- linux-2.6-git.orig/arch/powerpc/kernel/entry_64.S 2007-06-27 17:37:40.045965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/entry_64.S 2007-06-27 17:50:16.499965668 +0200 @@ -91,6 +91,13 @@ system_call_common: li r10,1 stb r10,PACASOFTIRQEN(r13) stb r10,PACAHARDIRQEN(r13) +#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 +#endif std r10,SOFTE(r1) #ifdef CONFIG_PPC_ISERIES BEGIN_FW_FTR_SECTION @@ -491,8 +498,20 @@ BEGIN_FW_FTR_SECTION 4: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r5,0 + beq 5f + bl .trace_hardirqs_on + ld r5,SOFTE(r1) stb r5,PACASOFTIRQEN(r13) - + b 6f +5: + stb r5,PACASOFTIRQEN(r13) + bl .trace_hardirqs_off +6: +#else + stb r5,PACASOFTIRQEN(r13) +#endif /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ @@ -560,6 +579,9 @@ do_work: bne restore /* here we are preempting the current task */ 1: +#ifdef CONFIG_TRACE_IRQFLAGS + bl .powerpc_trace_hardirqs_on +#endif li r0,1 stb r0,PACASOFTIRQEN(r13) stb r0,PACAHARDIRQEN(r13) --- linux-2.6-git.orig/arch/powerpc/kernel/Makefile 2007-06-27 17:37:40.100965668 +0200 +++ linux-2.6-git/arch/powerpc/kernel/Makefile 2007-06-27 17:38:08.064965668 +0200 @@ -62,6 +62,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_TRACE_IRQFLAGS) += irqtrace.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6-git/arch/powerpc/kernel/irqtrace.S 2007-06-27 17:49:15.650965668 +0200 @@ -0,0 +1,47 @@ +/* + * crappy helper for irq-trace + */ + +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> + +#define STACKSPACE GPR0 + 16*8 + +#ifdef __powerpc64__ +#define ST std +#define L ld +#else +#define ST stw +#define L lw +#endif + +#define PRE \ + subi r1,r1,STACKSPACE ; \ + SAVE_GPR(0, r1) ; \ + SAVE_8GPRS(2, r1) ; \ + SAVE_4GPRS(10, r1) ; \ + mfcr r0 ; \ + ST r0, (14*8)(r1) ; \ + mflr r0 ; \ + ST r0, (15*8)(r1) + +#define POST \ + REST_8GPRS(2, r1) ; \ + REST_4GPRS(10, r1) ; \ + L r0, (14*8)(r1) ; \ + mtcr r0 ; \ + L r0, (15*8)(r1) ; \ + mtlr r0 ; \ + REST_GPR(0, r1) ; \ + addi r1,r1,STACKSPACE + +_GLOBAL(powerpc_trace_hardirqs_off) + PRE + bl .trace_hardirqs_off + POST + blr +_GLOBAL(powerpc_trace_hardirqs_on) + PRE + bl .trace_hardirqs_on + POST + blr ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-06-27 19:00 ` Johannes Berg @ 2007-06-28 16:20 ` Johannes Berg 2007-06-30 8:58 ` Christoph Hellwig 2007-07-05 19:26 ` Sergei Shtylyov 0 siblings, 2 replies; 10+ messages in thread From: Johannes Berg @ 2007-06-28 16:20 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linuxppc-dev This one doesn't break 32-bit build by simply disabling irqtrace for 32-bit. --- arch/powerpc/Kconfig | 9 ++++++ arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/entry_64.S | 24 +++++++++++++++++ arch/powerpc/kernel/head_64.S | 54 ++++++++++++++++++++++++++++++++-------- arch/powerpc/kernel/irq.c | 2 - arch/powerpc/kernel/irqtrace.S | 47 ++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/ppc_ksyms.c | 2 - arch/powerpc/kernel/setup_64.c | 6 ++++ include/asm-powerpc/hw_irq.h | 14 +++++----- include/asm-powerpc/irqflags.h | 13 --------- include/asm-powerpc/rwsem.h | 34 +++++++++++++++++++------ include/asm-powerpc/spinlock.h | 1 12 files changed, 167 insertions(+), 40 deletions(-) --- linux-2.6-git32.orig/arch/powerpc/Kconfig 2007-06-28 14:53:58.603430447 +0200 +++ linux-2.6-git32/arch/powerpc/Kconfig 2007-06-28 14:58:02.683430447 +0200 @@ -38,6 +38,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 --- linux-2.6-git32.orig/arch/powerpc/kernel/irq.c 2007-06-28 14:53:58.604430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/irq.c 2007-06-28 14:48:38.709430447 +0200 @@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi : : "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; --- linux-2.6-git32.orig/arch/powerpc/kernel/ppc_ksyms.c 2007-06-28 14:53:58.678430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/ppc_ksyms.c 2007-06-28 14:49:24.887430447 +0200 @@ -50,7 +50,7 @@ #endif #ifdef CONFIG_PPC64 -EXPORT_SYMBOL(local_irq_restore); +EXPORT_SYMBOL(raw_local_irq_restore); #endif #ifdef CONFIG_PPC32 --- linux-2.6-git32.orig/include/asm-powerpc/hw_irq.h 2007-06-28 14:53:58.730430447 +0200 +++ linux-2.6-git32/include/asm-powerpc/hw_irq.h 2007-06-28 14:58:41.508430447 +0200 @@ -27,7 +27,7 @@ static inline unsigned long local_get_fl return flags; } -static inline unsigned long local_irq_disable(void) +static inline unsigned long raw_local_irq_disable(void) { unsigned long flags, zero; @@ -39,14 +39,15 @@ static inline unsigned long local_irq_di return flags; } -extern void local_irq_restore(unsigned long); +extern void raw_local_irq_restore(unsigned long); extern void iseries_handle_interrupts(void); -#define local_irq_enable() local_irq_restore(1) -#define local_save_flags(flags) ((flags) = local_get_flags()) -#define local_irq_save(flags) ((flags) = local_irq_disable()) +#define raw_local_irq_enable() raw_local_irq_restore(1) +#define raw_local_save_flags(flags) ((flags) = local_get_flags()) +#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable()) -#define irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled_flags(flags) ((flags) == 0) #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) @@ -108,6 +109,7 @@ static inline void local_irq_save_ptr(un #define local_save_flags(flags) ((flags) = mfmsr()) #define local_irq_save(flags) local_irq_save_ptr(&flags) #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0) #define hard_irq_enable() local_irq_enable() #define hard_irq_disable() local_irq_disable() --- linux-2.6-git32.orig/include/asm-powerpc/irqflags.h 2007-06-28 14:53:58.779430447 +0200 +++ linux-2.6-git32/include/asm-powerpc/irqflags.h 2007-06-28 14:52:51.821430447 +0200 @@ -15,17 +15,4 @@ */ #include <asm-powerpc/hw_irq.h> -/* - * Do the CPU's IRQ-state tracing from assembly code. We call a - * C function, so save all the C-clobbered registers: - */ -#ifdef CONFIG_TRACE_IRQFLAGS - -#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS - -#else -# define TRACE_IRQS_ON -# define TRACE_IRQS_OFF -#endif - #endif --- linux-2.6-git32.orig/include/asm-powerpc/rwsem.h 2007-06-28 14:53:58.779430447 +0200 +++ linux-2.6-git32/include/asm-powerpc/rwsem.h 2007-06-28 14:52:51.588430447 +0200 @@ -28,11 +28,21 @@ struct rw_semaphore { #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) } + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -42,12 +52,15 @@ extern struct rw_semaphore *rwsem_down_w extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ + } while (0) /* * lock for reading @@ -74,7 +87,7 @@ static inline int __down_read_trylock(st /* * lock for writing */ -static inline void __down_write(struct rw_semaphore *sem) +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { int tmp; @@ -84,6 +97,11 @@ static inline void __down_write(struct r rwsem_down_write_failed(sem); } +static inline void __down_write(struct rw_semaphore *sem) +{ + __down_write_nested(sem, 0); +} + static inline int __down_write_trylock(struct rw_semaphore *sem) { int tmp; --- linux-2.6-git32.orig/include/asm-powerpc/spinlock.h 2007-06-28 14:53:58.780430447 +0200 +++ linux-2.6-git32/include/asm-powerpc/spinlock.h 2007-06-28 14:52:51.641430447 +0200 @@ -19,6 +19,7 @@ * * (the type definitions are in asm/spinlock_types.h) */ +#include <linux/irqflags.h> #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> --- linux-2.6-git32.orig/arch/powerpc/kernel/head_64.S 2007-06-28 14:53:58.679430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/head_64.S 2007-06-28 14:48:33.858430447 +0200 @@ -394,6 +394,12 @@ label##_iSeries: \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ +#ifdef CONFIG_TRACE_IRQFLAGS +#define TRACE_DISABLE_INTS bl .powerpc_trace_hardirqs_off +#else +#define TRACE_DISABLE_INTS +#endif + #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ li r11,0; \ @@ -405,14 +411,15 @@ BEGIN_FW_FTR_SECTION; \ mfmsr r10; \ ori r10,r10,MSR_EE; \ mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ + TRACE_DISABLE_INTS #else #define DISABLE_INTS \ li r11,0; \ stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13) - + stb r11,PACAHARDIRQEN(r13); \ + TRACE_DISABLE_INTS #endif /* CONFIG_PPC_ISERIES */ #define ENABLE_INTS \ @@ -965,24 +972,38 @@ bad_stack: */ fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) - ld r12,_MSR(r1) +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 1f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +1: stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ + cmpdi r3,0 + bne 2f + bl .trace_hardirqs_off + ld r3,SOFTE(r1) +2: +#else + stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ +#endif + ld r12,_MSR(r1) rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ - b 1f + b 3f .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) -1: ld r11,_NIP(r1) +3: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer #ifdef CONFIG_VIRT_CPU_ACCOUNTING andi. r3,r12,MSR_PR - beq 2f + beq 4f ACCOUNT_CPU_USER_EXIT(r3, r4) -2: +4: #endif ld r3,_CCR(r1) @@ -1387,11 +1408,24 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER /* * 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 +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 14f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +14: + bl .raw_local_irq_restore + cmpdi r3,0 + bne 15f + bl .trace_hardirqs_off +15: +#else + bl .raw_local_irq_restore +#endif b 11f /* Here we have a page fault that hash_page can't handle. */ --- linux-2.6-git32.orig/arch/powerpc/kernel/setup_64.c 2007-06-28 14:53:58.729430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/setup_64.c 2007-06-28 14:49:08.305430447 +0200 @@ -33,6 +33,7 @@ #include <linux/serial_8250.h> #include <linux/bootmem.h> #include <linux/pci.h> +#include <linux/lockdep.h> #include <asm/io.h> #include <asm/kdump.h> #include <asm/prom.h> @@ -359,6 +360,11 @@ void __init setup_system(void) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); /* + * start lockdep + */ + lockdep_init(); + + /* * Unflatten the device-tree passed by prom_init or kexec */ unflatten_device_tree(); --- linux-2.6-git32.orig/arch/powerpc/kernel/entry_64.S 2007-06-28 14:53:58.729430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/entry_64.S 2007-06-28 14:49:13.125430447 +0200 @@ -91,6 +91,13 @@ system_call_common: li r10,1 stb r10,PACASOFTIRQEN(r13) stb r10,PACAHARDIRQEN(r13) +#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 +#endif std r10,SOFTE(r1) #ifdef CONFIG_PPC_ISERIES BEGIN_FW_FTR_SECTION @@ -491,8 +498,20 @@ BEGIN_FW_FTR_SECTION 4: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r5,0 + beq 5f + bl .trace_hardirqs_on + ld r5,SOFTE(r1) stb r5,PACASOFTIRQEN(r13) - + b 6f +5: + stb r5,PACASOFTIRQEN(r13) + bl .trace_hardirqs_off +6: +#else + stb r5,PACASOFTIRQEN(r13) +#endif /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ @@ -560,6 +579,9 @@ do_work: bne restore /* here we are preempting the current task */ 1: +#ifdef CONFIG_TRACE_IRQFLAGS + bl .powerpc_trace_hardirqs_on +#endif li r0,1 stb r0,PACASOFTIRQEN(r13) stb r0,PACAHARDIRQEN(r13) --- linux-2.6-git32.orig/arch/powerpc/kernel/Makefile 2007-06-28 14:53:58.729430447 +0200 +++ linux-2.6-git32/arch/powerpc/kernel/Makefile 2007-06-28 14:48:41.691430447 +0200 @@ -62,6 +62,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_TRACE_IRQFLAGS) += irqtrace.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6-git32/arch/powerpc/kernel/irqtrace.S 2007-06-28 14:49:25.754430447 +0200 @@ -0,0 +1,47 @@ +/* + * crappy helper for irq-trace + */ + +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> + +#define STACKSPACE GPR0 + 16*8 + +#ifdef __powerpc64__ +#define ST std +#define L ld +#else +#define ST stw +#define L lw +#endif + +#define PRE \ + subi r1,r1,STACKSPACE ; \ + SAVE_GPR(0, r1) ; \ + SAVE_8GPRS(2, r1) ; \ + SAVE_4GPRS(10, r1) ; \ + mfcr r0 ; \ + ST r0, (14*8)(r1) ; \ + mflr r0 ; \ + ST r0, (15*8)(r1) + +#define POST \ + REST_8GPRS(2, r1) ; \ + REST_4GPRS(10, r1) ; \ + L r0, (14*8)(r1) ; \ + mtcr r0 ; \ + L r0, (15*8)(r1) ; \ + mtlr r0 ; \ + REST_GPR(0, r1) ; \ + addi r1,r1,STACKSPACE + +_GLOBAL(powerpc_trace_hardirqs_off) + PRE + bl .trace_hardirqs_off + POST + blr +_GLOBAL(powerpc_trace_hardirqs_on) + PRE + bl .trace_hardirqs_on + POST + blr ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-06-28 16:20 ` Johannes Berg @ 2007-06-30 8:58 ` Christoph Hellwig 2007-07-04 22:40 ` Johannes Berg 2007-07-05 19:26 ` Sergei Shtylyov 1 sibling, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2007-06-30 8:58 UTC (permalink / raw) To: Johannes Berg; +Cc: linuxppc-dev, Christoph Hellwig On Thu, Jun 28, 2007 at 06:20:42PM +0200, Johannes Berg wrote: > This one doesn't break 32-bit build by simply disabling irqtrace for > 32-bit. This looks really cool to me. I'd love to see this in 2.6.23. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-06-30 8:58 ` Christoph Hellwig @ 2007-07-04 22:40 ` Johannes Berg 2007-07-06 9:23 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2007-07-04 22:40 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linuxppc-dev [-- Attachment #1: Type: text/plain, Size: 820 bytes --] On Sat, 2007-06-30 at 10:58 +0200, Christoph Hellwig wrote: > On Thu, Jun 28, 2007 at 06:20:42PM +0200, Johannes Berg wrote: > > This one doesn't break 32-bit build by simply disabling irqtrace for > > 32-bit. > > This looks really cool to me. I'd love to see this in 2.6.23. Hmm. Looks like I just found a case where I forgot to trace in some place: [ 241.629380] hardirqs last enabled at (1319): [<c0000000000b3718>] .get_page_from_freelist+0x298/0x620 [ 241.629714] hardirqs last disabled at (1320): [<c000000000033690>] .native_hpte_invalidate+0x60/0x320 [ 241.629732] softirqs last enabled at (1282): [<c000000000059e28>] .__do_softirq+0x198/0x1e0 [ 241.629748] softirqs last disabled at (1273): [<c00000000000c7e4>] .do_softirq+0xd4/0xe0 I'll look into it when I get around. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 190 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-07-04 22:40 ` Johannes Berg @ 2007-07-06 9:23 ` Johannes Berg 2007-07-06 9:54 ` Johannes Berg 0 siblings, 1 reply; 10+ messages in thread From: Johannes Berg @ 2007-07-06 9:23 UTC (permalink / raw) To: Christoph Hellwig, Benjamin Herrenschmidt; +Cc: linuxppc-dev On Thu, 2007-07-05 at 00:40 +0200, Johannes Berg wrote: > On Sat, 2007-06-30 at 10:58 +0200, Christoph Hellwig wrote: > > On Thu, Jun 28, 2007 at 06:20:42PM +0200, Johannes Berg wrote: > > > This one doesn't break 32-bit build by simply disabling irqtrace for > > > 32-bit. > > > > This looks really cool to me. I'd love to see this in 2.6.23. > > Hmm. Looks like I just found a case where I forgot to trace in some > place: > > [ 241.629380] hardirqs last enabled at (1319): [<c0000000000b3718>] .get_page_from_freelist+0x298/0x620 > [ 241.629714] hardirqs last disabled at (1320): [<c000000000033690>] .native_hpte_invalidate+0x60/0x320 > [ 241.629732] softirqs last enabled at (1282): [<c000000000059e28>] .__do_softirq+0x198/0x1e0 > [ 241.629748] softirqs last disabled at (1273): [<c00000000000c7e4>] .do_softirq+0xd4/0xe0 Not sure what that was, but I found one place where it could have come from (do an interdiff if you want to know). Below patch is a bit nicer, especially those trace_hardirqs wrappers. However, the presence of those itself is indication that I haven't given most of the hooks I added much thought. Though, in case somebody wants to develop it further I'll even sign it off. For me it's doing what I want, it allows me to develop with and for lockdep, take advantage of lockdep and still use my machine (with forced preemption) as expected; however I don't think I'd be comfortable with anybody else using it except on test machines unless somebody else gives it a thorough look first. Especially for say iSeries which is quite different in the low-level code and I can't even test. johannes Subject: powerpc: 64-bit irqtrace support From: Johannes Berg <johannes@sipsolutions.net> This adds irqtrace support to 64-bit powerpc. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> --- arch/powerpc/Kconfig | 9 ++++ arch/powerpc/kernel/Makefile | 1 arch/powerpc/kernel/entry_64.S | 24 +++++++++++ arch/powerpc/kernel/head_64.S | 54 +++++++++++++++++++++----- arch/powerpc/kernel/irq.c | 2 arch/powerpc/kernel/irqtrace.S | 82 ++++++++++++++++++++++++++++++++++++++++ arch/powerpc/kernel/ppc_ksyms.c | 2 arch/powerpc/kernel/setup_64.c | 6 ++ include/asm-powerpc/hw_irq.h | 14 +++--- include/asm-powerpc/irqflags.h | 13 ------ include/asm-powerpc/rwsem.h | 34 ++++++++++++---- include/asm-powerpc/spinlock.h | 1 12 files changed, 202 insertions(+), 40 deletions(-) --- linux-2.6-git.orig/arch/powerpc/Kconfig 2007-07-05 23:01:18.001397556 +0200 +++ linux-2.6-git/arch/powerpc/Kconfig 2007-07-05 23:01:18.068397556 +0200 @@ -38,6 +38,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 --- linux-2.6-git.orig/arch/powerpc/kernel/irq.c 2007-07-05 23:01:11.727397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/irq.c 2007-07-05 23:01:18.084397556 +0200 @@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi : : "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; --- linux-2.6-git.orig/arch/powerpc/kernel/ppc_ksyms.c 2007-07-05 23:01:11.759397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/ppc_ksyms.c 2007-07-05 23:01:18.094397556 +0200 @@ -50,7 +50,7 @@ #endif #ifdef CONFIG_PPC64 -EXPORT_SYMBOL(local_irq_restore); +EXPORT_SYMBOL(raw_local_irq_restore); #endif #ifdef CONFIG_PPC32 --- linux-2.6-git.orig/include/asm-powerpc/hw_irq.h 2007-07-05 23:01:11.985397556 +0200 +++ linux-2.6-git/include/asm-powerpc/hw_irq.h 2007-07-05 23:01:18.108397556 +0200 @@ -27,7 +27,7 @@ static inline unsigned long local_get_fl return flags; } -static inline unsigned long local_irq_disable(void) +static inline unsigned long raw_local_irq_disable(void) { unsigned long flags, zero; @@ -39,14 +39,15 @@ static inline unsigned long local_irq_di return flags; } -extern void local_irq_restore(unsigned long); +extern void raw_local_irq_restore(unsigned long); extern void iseries_handle_interrupts(void); -#define local_irq_enable() local_irq_restore(1) -#define local_save_flags(flags) ((flags) = local_get_flags()) -#define local_irq_save(flags) ((flags) = local_irq_disable()) +#define raw_local_irq_enable() raw_local_irq_restore(1) +#define raw_local_save_flags(flags) ((flags) = local_get_flags()) +#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable()) -#define irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled() (local_get_flags() == 0) +#define raw_irqs_disabled_flags(flags) ((flags) == 0) #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) @@ -108,6 +109,7 @@ static inline void local_irq_save_ptr(un #define local_save_flags(flags) ((flags) = mfmsr()) #define local_irq_save(flags) local_irq_save_ptr(&flags) #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) +#define irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0) #define hard_irq_enable() local_irq_enable() #define hard_irq_disable() local_irq_disable() --- linux-2.6-git.orig/include/asm-powerpc/irqflags.h 2007-07-05 23:01:12.018397556 +0200 +++ linux-2.6-git/include/asm-powerpc/irqflags.h 2007-07-05 23:01:18.141397556 +0200 @@ -15,17 +15,4 @@ */ #include <asm-powerpc/hw_irq.h> -/* - * Do the CPU's IRQ-state tracing from assembly code. We call a - * C function, so save all the C-clobbered registers: - */ -#ifdef CONFIG_TRACE_IRQFLAGS - -#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS - -#else -# define TRACE_IRQS_ON -# define TRACE_IRQS_OFF -#endif - #endif --- linux-2.6-git.orig/include/asm-powerpc/rwsem.h 2007-07-05 23:01:12.050397556 +0200 +++ linux-2.6-git/include/asm-powerpc/rwsem.h 2007-07-05 23:01:18.149397556 +0200 @@ -28,11 +28,21 @@ struct rw_semaphore { #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \ - LIST_HEAD_INIT((name).wait_list) } + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -42,12 +52,15 @@ extern struct rw_semaphore *rwsem_down_w extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); -static inline void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ + } while (0) /* * lock for reading @@ -74,7 +87,7 @@ static inline int __down_read_trylock(st /* * lock for writing */ -static inline void __down_write(struct rw_semaphore *sem) +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { int tmp; @@ -84,6 +97,11 @@ static inline void __down_write(struct r rwsem_down_write_failed(sem); } +static inline void __down_write(struct rw_semaphore *sem) +{ + __down_write_nested(sem, 0); +} + static inline int __down_write_trylock(struct rw_semaphore *sem) { int tmp; --- linux-2.6-git.orig/include/asm-powerpc/spinlock.h 2007-07-05 23:01:12.097397556 +0200 +++ linux-2.6-git/include/asm-powerpc/spinlock.h 2007-07-05 23:01:18.152397556 +0200 @@ -19,6 +19,7 @@ * * (the type definitions are in asm/spinlock_types.h) */ +#include <linux/irqflags.h> #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> --- linux-2.6-git.orig/arch/powerpc/kernel/head_64.S 2007-07-05 23:01:11.796397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/head_64.S 2007-07-05 23:01:18.173397556 +0200 @@ -394,6 +394,12 @@ label##_iSeries: \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common; \ +#ifdef CONFIG_TRACE_IRQFLAGS +#define TRACE_DISABLE_INTS bl .powerpc_trace_hardirqs_off +#else +#define TRACE_DISABLE_INTS +#endif + #ifdef CONFIG_PPC_ISERIES #define DISABLE_INTS \ li r11,0; \ @@ -405,14 +411,15 @@ BEGIN_FW_FTR_SECTION; \ mfmsr r10; \ ori r10,r10,MSR_EE; \ mtmsrd r10,1; \ -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ + TRACE_DISABLE_INTS #else #define DISABLE_INTS \ li r11,0; \ stb r11,PACASOFTIRQEN(r13); \ - stb r11,PACAHARDIRQEN(r13) - + stb r11,PACAHARDIRQEN(r13); \ + TRACE_DISABLE_INTS #endif /* CONFIG_PPC_ISERIES */ #define ENABLE_INTS \ @@ -965,24 +972,38 @@ bad_stack: */ fast_exc_return_irq: /* restores irq state too */ ld r3,SOFTE(r1) - ld r12,_MSR(r1) +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 1f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +1: stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ + cmpdi r3,0 + bne 2f + bl .trace_hardirqs_off + ld r3,SOFTE(r1) +2: +#else + stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ +#endif + ld r12,_MSR(r1) rldicl r4,r12,49,63 /* get MSR_EE to LSB */ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ - b 1f + b 3f .globl fast_exception_return fast_exception_return: ld r12,_MSR(r1) -1: ld r11,_NIP(r1) +3: ld r11,_NIP(r1) andi. r3,r12,MSR_RI /* check if RI is set */ beq- unrecov_fer #ifdef CONFIG_VIRT_CPU_ACCOUNTING andi. r3,r12,MSR_PR - beq 2f + beq 4f ACCOUNT_CPU_USER_EXIT(r3, r4) -2: +4: #endif ld r3,_CCR(r1) @@ -1387,11 +1408,24 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER /* * 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 +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r3,0 + beq 14f + bl .trace_hardirqs_on + ld r3,SOFTE(r1) +14: + bl .raw_local_irq_restore + cmpdi r3,0 + bne 15f + bl .trace_hardirqs_off +15: +#else + bl .raw_local_irq_restore +#endif b 11f /* Here we have a page fault that hash_page can't handle. */ --- linux-2.6-git.orig/arch/powerpc/kernel/setup_64.c 2007-07-05 23:01:11.829397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/setup_64.c 2007-07-05 23:01:18.185397556 +0200 @@ -33,6 +33,7 @@ #include <linux/serial_8250.h> #include <linux/bootmem.h> #include <linux/pci.h> +#include <linux/lockdep.h> #include <asm/io.h> #include <asm/kdump.h> #include <asm/prom.h> @@ -359,6 +360,11 @@ void __init setup_system(void) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); /* + * start lockdep + */ + lockdep_init(); + + /* * Unflatten the device-tree passed by prom_init or kexec */ unflatten_device_tree(); --- linux-2.6-git.orig/arch/powerpc/kernel/entry_64.S 2007-07-05 23:01:11.864397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/entry_64.S 2007-07-05 23:01:18.211397556 +0200 @@ -88,6 +88,13 @@ 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 +#endif li r10,1 stb r10,PACASOFTIRQEN(r13) stb r10,PACAHARDIRQEN(r13) @@ -491,8 +498,20 @@ BEGIN_FW_FTR_SECTION 4: END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) #endif +#ifdef CONFIG_TRACE_IRQFLAGS + cmpdi r5,0 + beq 5f + bl .trace_hardirqs_on + ld r5,SOFTE(r1) stb r5,PACASOFTIRQEN(r13) - + b 6f +5: + stb r5,PACASOFTIRQEN(r13) + bl .trace_hardirqs_off +6: +#else + stb r5,PACASOFTIRQEN(r13) +#endif /* extract EE bit and use it to restore paca->hard_enabled */ ld r3,_MSR(r1) rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ @@ -560,6 +579,9 @@ do_work: bne restore /* here we are preempting the current task */ 1: +#ifdef CONFIG_TRACE_IRQFLAGS + bl .powerpc_trace_hardirqs_on +#endif li r0,1 stb r0,PACASOFTIRQEN(r13) stb r0,PACAHARDIRQEN(r13) --- linux-2.6-git.orig/arch/powerpc/kernel/Makefile 2007-07-05 23:01:18.002397556 +0200 +++ linux-2.6-git/arch/powerpc/kernel/Makefile 2007-07-05 23:01:18.212397556 +0200 @@ -62,6 +62,7 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_TRACE_IRQFLAGS) += irqtrace.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6-git/arch/powerpc/kernel/irqtrace.S 2007-07-06 02:11:15.110814034 +0200 @@ -0,0 +1,82 @@ +/* + * helpers for irq-trace + * + * We invoke the hardirq trace functions from various inconvenient + * places; these helpers save all callee-saved registers. + * + * Author: Johannes Berg <johannes@sipsolutions.net> + */ + +#include <asm/ppc_asm.h> +#include <asm/asm-offsets.h> + +#ifdef CONFIG_PPC64 +#define ST std +#define STU stdu +#define L ld +#define WSZ 8 +#define FREE 32 +#else +#error double-check please +#define ST stw +#define STU stwu +#define L lwz +#define WSZ 4 +#define FREE 16 +#endif + +#define STACKSPACE (FREE + 16*WSZ) +#define SAVE(n) (FREE + n*WSZ) + +_GLOBAL(powerpc_trace_hardirqs_on) + ST r3, (SAVE(2)-STACKSPACE)(r1) + LOAD_REG_IMMEDIATE(r3, .trace_hardirqs_on) + b powerpc_trace_hardirqs + +_GLOBAL(powerpc_trace_hardirqs_off) + ST r3, (SAVE(2)-STACKSPACE)(r1) + LOAD_REG_IMMEDIATE(r3, .trace_hardirqs_off) + +powerpc_trace_hardirqs: + ST r0, (SAVE(0)-STACKSPACE)(r1) + mflr r0 + ST r0, LRSAVE(r1) + STU r1, -STACKSPACE(r1) + mfctr r0 + ST r0, SAVE(14)(r1) + mtctr r3 + ST r2, SAVE(1)(r1) + ST r4, SAVE(3)(r1) + ST r5, SAVE(4)(r1) + ST r6, SAVE(5)(r1) + ST r7, SAVE(6)(r1) + ST r8, SAVE(7)(r1) + ST r9, SAVE(8)(r1) + ST r10, SAVE(9)(r1) + ST r11, SAVE(10)(r1) + ST r12, SAVE(11)(r1) + ST r13, SAVE(12)(r1) + mfcr r0 + ST r0, SAVE(13)(r1) + bctrl + L r2, SAVE(1)(r1) + L r3, SAVE(2)(r1) + L r4, SAVE(3)(r1) + L r5, SAVE(4)(r1) + L r6, SAVE(5)(r1) + L r7, SAVE(6)(r1) + L r8, SAVE(7)(r1) + L r9, SAVE(8)(r1) + L r10, SAVE(9)(r1) + L r11, SAVE(10)(r1) + L r12, SAVE(11)(r1) + L r13, SAVE(12)(r1) + L r0, SAVE(13)(r1) + mtcr r0 + L r0, SAVE(14)(r1) + mtctr r0 + L r1, 0(r1) + L r0, LRSAVE(r1) + mtlr r0 + L r0, (SAVE(0)-STACKSPACE)(r1) + blr ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-07-06 9:23 ` Johannes Berg @ 2007-07-06 9:54 ` Johannes Berg 0 siblings, 0 replies; 10+ messages in thread From: Johannes Berg @ 2007-07-06 9:54 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linuxppc-dev [-- Attachment #1: Type: text/plain, Size: 1464 bytes --] *sigh* I really shouldn't have mailed this out in the first place. Every time I look at it I find new bugs despite the fact that it actually works on my machine. > ld r3,SOFTE(r1) > - bl .local_irq_restore > +#ifdef CONFIG_TRACE_IRQFLAGS > + cmpdi r3,0 > + beq 14f > + bl .trace_hardirqs_on > + ld r3,SOFTE(r1) > +14: > + bl .raw_local_irq_restore > + cmpdi r3,0 This should reload r3 before the second compare as raw_local_irq_restore returns nothing (void). And why does it need a second compare anyway? Just rewrite as ld r3, SOFTE(r1) #ifdef CONFIG_TRACE_IRQFLAGS cmpdi r3, 0 bne 14f bl .raw_local_irq_restore bl .trace_hardirqs_off b 15f 14: bl .trace_hardirqs_on li r3, 1 #endif bl .raw_local_irq_restore 15: which has the advantage of having only one conditional branch and less preprocessor foo. > +#ifdef CONFIG_TRACE_IRQFLAGS > + cmpdi r5,0 > + beq 5f > + bl .trace_hardirqs_on > + ld r5,SOFTE(r1) > stb r5,PACASOFTIRQEN(r13) > - > + b 6f > +5: > + stb r5,PACASOFTIRQEN(r13) > + bl .trace_hardirqs_off > +6: > +#else > + stb r5,PACASOFTIRQEN(r13) > +#endif Similarly, that could be rewritten as #ifdef CONFIG_TRACE_IRQFLAGS cmpdi r5, 0 bne 5f stb r5, PACASOFTIRQEN(r13) bl .trace_hardirqs_off b 6f 5: bl .trace_hardirqs_on li r5, 1 #endif stb r5, PACASOFTIRQEN(r13) 6: I can't test these modifications over the weekend but they should be fine. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 190 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-06-28 16:20 ` Johannes Berg 2007-06-30 8:58 ` Christoph Hellwig @ 2007-07-05 19:26 ` Sergei Shtylyov 2007-07-06 10:59 ` Johannes Berg 1 sibling, 1 reply; 10+ messages in thread From: Sergei Shtylyov @ 2007-07-05 19:26 UTC (permalink / raw) To: Johannes Berg; +Cc: linuxppc-dev, Christoph Hellwig Johannes Berg wrote: > This one doesn't break 32-bit build by simply disabling irqtrace for > 32-bit. > --- linux-2.6-git32.orig/include/asm-powerpc/hw_irq.h 2007-06-28 14:53:58.730430447 +0200 > +++ linux-2.6-git32/include/asm-powerpc/hw_irq.h 2007-06-28 14:58:41.508430447 +0200 > @@ -27,7 +27,7 @@ static inline unsigned long local_get_fl > return flags; > } > > -static inline unsigned long local_irq_disable(void) > +static inline unsigned long raw_local_irq_disable(void) > { > unsigned long flags, zero; > > @@ -39,14 +39,15 @@ static inline unsigned long local_irq_di > return flags; > } > > -extern void local_irq_restore(unsigned long); > +extern void raw_local_irq_restore(unsigned long); > extern void iseries_handle_interrupts(void); > > -#define local_irq_enable() local_irq_restore(1) > -#define local_save_flags(flags) ((flags) = local_get_flags()) > -#define local_irq_save(flags) ((flags) = local_irq_disable()) > +#define raw_local_irq_enable() raw_local_irq_restore(1) > +#define raw_local_save_flags(flags) ((flags) = local_get_flags()) > +#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable()) > > -#define irqs_disabled() (local_get_flags() == 0) > +#define raw_irqs_disabled() (local_get_flags() == 0) > +#define raw_irqs_disabled_flags(flags) ((flags) == 0) > > #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) > #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) > @@ -108,6 +109,7 @@ static inline void local_irq_save_ptr(un > #define local_save_flags(flags) ((flags) = mfmsr()) > #define local_irq_save(flags) local_irq_save_ptr(&flags) > #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) > +#define irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0) > > #define hard_irq_enable() local_irq_enable() > #define hard_irq_disable() local_irq_disable() > --- linux-2.6-git32.orig/include/asm-powerpc/irqflags.h 2007-06-28 14:53:58.779430447 +0200 > +++ linux-2.6-git32/include/asm-powerpc/irqflags.h 2007-06-28 14:52:51.821430447 +0200 > @@ -15,17 +15,4 @@ > */ > #include <asm-powerpc/hw_irq.h> > > -/* > - * Do the CPU's IRQ-state tracing from assembly code. We call a > - * C function, so save all the C-clobbered registers: > - */ > -#ifdef CONFIG_TRACE_IRQFLAGS > - > -#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS > - > -#else > -# define TRACE_IRQS_ON > -# define TRACE_IRQS_OFF > -#endif > - > #endif I suggest to also remove these 3 lines from the heading comment in this file -- they're not true anyway: * This file gets included from lowlevel asm headers too, to provide * wrapped versions of the local_irq_*() APIs, based on the * raw_local_irq_*() macros from the lowlevel headers. > --- linux-2.6-git32.orig/arch/powerpc/kernel/head_64.S 2007-06-28 14:53:58.679430447 +0200 > +++ linux-2.6-git32/arch/powerpc/kernel/head_64.S 2007-06-28 14:48:33.858430447 +0200 > @@ -394,6 +394,12 @@ label##_iSeries: \ > EXCEPTION_PROLOG_ISERIES_2; \ > b label##_common; \ > > +#ifdef CONFIG_TRACE_IRQFLAGS > +#define TRACE_DISABLE_INTS bl .powerpc_trace_hardirqs_off > +#else > +#define TRACE_DISABLE_INTS > +#endif > + Erm, weren't those supposed to be in <asm-powerpc/irqflags.h>? > #ifdef CONFIG_PPC_ISERIES > #define DISABLE_INTS \ > li r11,0; \ > @@ -405,14 +411,15 @@ BEGIN_FW_FTR_SECTION; \ > mfmsr r10; \ > ori r10,r10,MSR_EE; \ > mtmsrd r10,1; \ > -END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) > +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ > + TRACE_DISABLE_INTS > > #else > #define DISABLE_INTS \ > li r11,0; \ > stb r11,PACASOFTIRQEN(r13); \ > - stb r11,PACAHARDIRQEN(r13) > - > + stb r11,PACAHARDIRQEN(r13); \ > + TRACE_DISABLE_INTS > #endif /* CONFIG_PPC_ISERIES */ > > #define ENABLE_INTS \ > @@ -965,24 +972,38 @@ bad_stack: The following code seemed over-engineered: > */ > fast_exc_return_irq: /* restores irq state too */ > ld r3,SOFTE(r1) > - ld r12,_MSR(r1) > +#ifdef CONFIG_TRACE_IRQFLAGS > + cmpdi r3,0 > + beq 1f > + bl .trace_hardirqs_on b 2f 1: > + bl .trace_hardirqs_off 2: > + ld r3,SOFTE(r1) > +#endif stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ > + ld r12,_MSR(r1) > rldicl r4,r12,49,63 /* get MSR_EE to LSB */ > stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ > - b 1f > + b 3f [...] > --- linux-2.6-git32.orig/arch/powerpc/kernel/entry_64.S 2007-06-28 14:53:58.729430447 +0200 > +++ linux-2.6-git32/arch/powerpc/kernel/entry_64.S 2007-06-28 14:49:13.125430447 +0200 [...] > @@ -491,8 +498,20 @@ BEGIN_FW_FTR_SECTION > 4: > END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) > #endif > +#ifdef CONFIG_TRACE_IRQFLAGS > + cmpdi r5,0 > + beq 5f > + bl .trace_hardirqs_on > + ld r5,SOFTE(r1) > stb r5,PACASOFTIRQEN(r13) > - > + b 6f > +5: > + stb r5,PACASOFTIRQEN(r13) > + bl .trace_hardirqs_off > +6: > +#else > + stb r5,PACASOFTIRQEN(r13) > +#endif Again, could have been more compact... unless trace_hardirqs_*() calls need to be in certain order WRT writes to PACASOFTIRQEN -- if so, in the 1st case that I've pointed out the order was not identical (probably wrong?)... > --- /dev/null 1970-01-01 00:00:00.000000000 +0000 > +++ linux-2.6-git32/arch/powerpc/kernel/irqtrace.S 2007-06-28 14:49:25.754430447 +0200 > @@ -0,0 +1,47 @@ > +/* > + * crappy helper for irq-trace > + */ > + > +#include <asm/ppc_asm.h> > +#include <asm/asm-offsets.h> > + > +#define STACKSPACE GPR0 + 16*8 I guess this should be 16*4 for PPC32. > + > +#ifdef __powerpc64__ > +#define ST std > +#define L ld > +#else > +#define ST stw > +#define L lw > +#endif > + > +#define PRE \ > + subi r1,r1,STACKSPACE ; \ > + SAVE_GPR(0, r1) ; \ > + SAVE_8GPRS(2, r1) ; \ > + SAVE_4GPRS(10, r1) ; \ > + mfcr r0 ; \ > + ST r0, (14*8)(r1) ; \ > + mflr r0 ; \ > + ST r0, (15*8)(r1) Didn't you forget to add GPR0 to the offsets here? > +#define POST \ > + REST_8GPRS(2, r1) ; \ > + REST_4GPRS(10, r1) ; \ > + L r0, (14*8)(r1) ; \ > + mtcr r0 ; \ > + L r0, (15*8)(r1) ; \ > + mtlr r0 ; \ > + REST_GPR(0, r1) ; \ > + addi r1,r1,STACKSPACE You certainly did. I bet you're clobbering GPR11/12 (if I didn't miscount)... WBR, Sergei ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: powerpc stacktrace and lockdep support 2007-07-05 19:26 ` Sergei Shtylyov @ 2007-07-06 10:59 ` Johannes Berg 0 siblings, 0 replies; 10+ messages in thread From: Johannes Berg @ 2007-07-06 10:59 UTC (permalink / raw) To: Sergei Shtylyov; +Cc: linuxppc-dev, Christoph Hellwig [-- Attachment #1: Type: text/plain, Size: 1654 bytes --] Sergei, Thanks for your review! > I suggest to also remove these 3 lines from the heading comment in this > file -- they're not true anyway: > > * This file gets included from lowlevel asm headers too, to provide > * wrapped versions of the local_irq_*() APIs, based on the > * raw_local_irq_*() macros from the lowlevel headers. Good point. > > +#ifdef CONFIG_TRACE_IRQFLAGS > > +#define TRACE_DISABLE_INTS bl .powerpc_trace_hardirqs_off > > +#else > > +#define TRACE_DISABLE_INTS > > +#endif > > + > > Erm, weren't those supposed to be in <asm-powerpc/irqflags.h>? I guess they could be there. I was mucking my way through ;) > The following code seemed over-engineered: Yeah, perfectly correct. See my last mail to this thread from this morning. > Again, could have been more compact... unless trace_hardirqs_*() calls > need to be in certain order WRT writes to PACASOFTIRQEN -- if so, in the 1st > case that I've pointed out the order was not identical (probably wrong?)... Yeah, there is an ordering requirement and it was wrong in that version of the patch. > > +/* > > + * crappy helper for irq-trace > > + */ > > + > > +#include <asm/ppc_asm.h> > > +#include <asm/asm-offsets.h> > > + > > +#define STACKSPACE GPR0 + 16*8 > > I guess this should be 16*4 for PPC32. > Didn't you forget to add GPR0 to the offsets here? > You certainly did. I bet you're clobbering GPR11/12 (if I didn't miscount)... All correct. That might even be why it didn't work on 32-bit for me and then I gave up. In any case, I completely rewrote this file. johannes [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 190 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-07-06 10:58 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-01-08 13:54 powerpc stacktrace and lockdep support Christoph Hellwig 2007-06-26 22:47 ` Johannes Berg 2007-06-27 19:00 ` Johannes Berg 2007-06-28 16:20 ` Johannes Berg 2007-06-30 8:58 ` Christoph Hellwig 2007-07-04 22:40 ` Johannes Berg 2007-07-06 9:23 ` Johannes Berg 2007-07-06 9:54 ` Johannes Berg 2007-07-05 19:26 ` Sergei Shtylyov 2007-07-06 10:59 ` Johannes Berg
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).