From afbfb52e47273a440df33274452c603e8c332de2 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 4 Dec 2006 18:17:28 +0900 Subject: sh: stacktrace/lockdep/irqflags tracing support. Wire up all of the essentials for lockdep.. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 8 +++ arch/sh/Kconfig.debug | 4 ++ arch/sh/kernel/Makefile | 1 + arch/sh/kernel/cpu/sh2/entry.S | 16 ++++++ arch/sh/kernel/cpu/sh3/entry.S | 2 +- arch/sh/kernel/entry-common.S | 64 ++++++++++++++++++++- arch/sh/kernel/stacktrace.c | 43 ++++++++++++++ arch/sh/mm/fault.c | 3 + include/asm-sh/irqflags.h | 123 +++++++++++++++++++++++++++++++++++++++++ include/asm-sh/rwsem.h | 27 ++++++++- include/asm-sh/system.h | 101 +-------------------------------- 11 files changed, 289 insertions(+), 103 deletions(-) create mode 100644 arch/sh/kernel/stacktrace.c create mode 100644 include/asm-sh/irqflags.h diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index aa1ebc561b8..013732074d3 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -51,6 +51,14 @@ config GENERIC_TIME config ARCH_MAY_HAVE_PC_FDC bool +config STACKTRACE_SUPPORT + bool + default y + +config LOCKDEP_SUPPORT + bool + default y + source "init/Kconfig" menu "System type" diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index dcceec95a2d..66a25ef4ef1 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -1,5 +1,9 @@ menu "Kernel hacking" +config TRACE_IRQFLAGS_SUPPORT + bool + default y + source "lib/Kconfig.debug" config SH_STANDARD_BIOS diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 50d54c24d76..99c7e5249f7 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S index 298d9191909..34d51b3745e 100644 --- a/arch/sh/kernel/cpu/sh2/entry.S +++ b/arch/sh/kernel/cpu/sh2/entry.S @@ -184,6 +184,11 @@ trap_entry: add r15,r8 mov.l r9,@r8 mov r9,r8 +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r9 + jsr @r9 + nop +#endif sti bra system_call nop @@ -193,6 +198,9 @@ trap_entry: 2: .long break_point_trap_software 3: .long NR_syscalls 4: .long sys_call_table +#ifdef CONFIG_TRACE_IRQFLAGS +5: .long trace_hardirqs_on +#endif #if defined(CONFIG_SH_STANDARD_BIOS) /* Unwind the stack and jmp to the debug entry */ @@ -255,6 +263,11 @@ ENTRY(address_error_handler) restore_all: cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif mov r15,r0 mov.l $cpu_mode,r2 mov #OFF_SR,r3 @@ -307,6 +320,9 @@ $current_thread_info: .long __current_thread_info $cpu_mode: .long __cpu_mode +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_off +#endif ! common exception handler #include "../../entry-common.S" diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 7ba3dcbe750..8c0dc2700c6 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -140,7 +140,7 @@ call_dpf: mov.l 1f, r0 mov.l @r0, r6 ! address mov.l 3f, r0 - sti + jmp @r0 mov r15, r4 ! regs diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 8f96d21fcb1..29136a35d7c 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -100,6 +100,11 @@ debug_trap: .align 2 ENTRY(exception_error) ! +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif sti mov.l 2f, r0 jmp @r0 @@ -109,10 +114,18 @@ ENTRY(exception_error) .align 2 1: .long break_point_trap_software 2: .long do_exception_error +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_on +#endif .align 2 ret_from_exception: preempt_stop() +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 4f, r0 + jsr @r0 + nop +#endif ENTRY(ret_from_irq) ! mov #OFF_SR, r0 @@ -143,6 +156,11 @@ need_resched: mov.l 1f, r0 mov.l r0, @(TI_PRE_COUNT,r8) +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 3f, r0 + jsr @r0 + nop +#endif sti mov.l 2f, r0 jsr @r0 @@ -150,9 +168,15 @@ need_resched: mov #0, r0 mov.l r0, @(TI_PRE_COUNT,r8) cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 4f, r0 + jsr @r0 + nop +#endif bra need_resched nop + noresched: bra __restore_all nop @@ -160,11 +184,20 @@ noresched: .align 2 1: .long PREEMPT_ACTIVE 2: .long schedule +#ifdef CONFIG_TRACE_IRQFLAGS +3: .long trace_hardirqs_on +4: .long trace_hardirqs_off +#endif #endif ENTRY(resume_userspace) ! r8: current_thread_info cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags tst #_TIF_WORK_MASK, r0 bt/s __restore_all @@ -210,6 +243,11 @@ work_resched: jsr @r1 ! schedule nop cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif ! mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags tst #_TIF_WORK_MASK, r0 @@ -221,6 +259,10 @@ work_resched: 1: .long schedule 2: .long do_notify_resume 3: .long restore_all +#ifdef CONFIG_TRACE_IRQFLAGS +4: .long trace_hardirqs_on +5: .long trace_hardirqs_off +#endif .align 2 syscall_exit_work: @@ -229,6 +271,11 @@ syscall_exit_work: tst #_TIF_SYSCALL_TRACE, r0 bt/s work_pending tst #_TIF_NEED_RESCHED, r0 +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r0 + jsr @r0 + nop +#endif sti ! XXX setup arguments... mov.l 4f, r0 ! do_syscall_trace @@ -265,7 +312,7 @@ syscall_trace_entry: mov.l r0, @(OFF_R0,r15) ! Return value __restore_all: - mov.l 1f,r0 + mov.l 1f, r0 jmp @r0 nop @@ -331,7 +378,13 @@ ENTRY(system_call) mov #OFF_TRA, r9 add r15, r9 mov.l r8, @r9 ! set TRA value to tra +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 5f, r10 + jsr @r10 + nop +#endif sti + ! get_current_thread_info r8, r10 mov.l @(TI_FLAGS,r8), r8 @@ -355,6 +408,11 @@ syscall_call: ! syscall_exit: cli +#ifdef CONFIG_TRACE_IRQFLAGS + mov.l 6f, r0 + jsr @r0 + nop +#endif ! get_current_thread_info r8, r0 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags @@ -369,3 +427,7 @@ syscall_exit: 2: .long NR_syscalls 3: .long sys_call_table 4: .long do_syscall_trace +#ifdef CONFIG_TRACE_IRQFLAGS +5: .long trace_hardirqs_on +6: .long trace_hardirqs_off +#endif diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c new file mode 100644 index 00000000000..0d5268afe80 --- /dev/null +++ b/arch/sh/kernel/stacktrace.c @@ -0,0 +1,43 @@ +/* + * arch/sh/kernel/stacktrace.c + * + * Stack trace management functions + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + */ +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + unsigned long *sp; + + if (!task) + task = current; + if (task == current) + sp = (unsigned long *)current_stack_pointer; + else + sp = (unsigned long *)task->thread.sp; + + while (!kstack_end(sp)) { + unsigned long addr = *sp++; + + if (__kernel_text_address(addr)) { + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = addr; + if (trace->nr_entries >= trace->max_entries) + break; + } + } +} diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index cfeefc10e25..716ebf568af 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -37,6 +37,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, int si_code; siginfo_t info; + trace_hardirqs_on(); + local_irq_enable(); + #ifdef CONFIG_SH_KGDB if (kgdb_nofault && kgdb_bus_err_hook) kgdb_bus_err_hook(); diff --git a/include/asm-sh/irqflags.h b/include/asm-sh/irqflags.h new file mode 100644 index 00000000000..9dedc1b693e --- /dev/null +++ b/include/asm-sh/irqflags.h @@ -0,0 +1,123 @@ +#ifndef __ASM_SH_IRQFLAGS_H +#define __ASM_SH_IRQFLAGS_H + +static inline void raw_local_irq_enable(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and %1, %0\n\t" +#ifdef CONFIG_CPU_HAS_SR_RB + "stc r6_bank, %1\n\t" + "or %1, %0\n\t" +#endif + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "1" (~0x000000f0) + : "memory" + ); +} + +static inline void raw_local_irq_disable(void) +{ + unsigned long flags; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "or #0xf0, %0\n\t" + "ldc %0, sr\n\t" + : "=&z" (flags) + : /* no inputs */ + : "memory" + ); +} + +static inline void set_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "or %2, %0\n\t" + "and %3, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "r" (0x10000000), "r" (0xffffff0f) + : "memory" + ); +} + +static inline void clear_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and %2, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "1" (~0x10000000) + : "memory" + ); +} + +static inline unsigned long __raw_local_save_flags(void) +{ + unsigned long flags; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and #0xf0, %0\n\t" + : "=&z" (flags) + : /* no inputs */ + : "memory" + ); + + return flags; +} + +#define raw_local_save_flags(flags) \ + do { (flags) = __raw_local_save_flags(); } while (0) + +static inline int raw_irqs_disabled_flags(unsigned long flags) +{ + return (flags != 0); +} + +static inline int raw_irqs_disabled(void) +{ + unsigned long flags = __raw_local_save_flags(); + + return raw_irqs_disabled_flags(flags); +} + +static inline unsigned long __raw_local_irq_save(void) +{ + unsigned long flags, __dummy; + + __asm__ __volatile__ ( + "stc sr, %1\n\t" + "mov %1, %0\n\t" + "or #0xf0, %0\n\t" + "ldc %0, sr\n\t" + "mov %1, %0\n\t" + "and #0xf0, %0\n\t" + : "=&z" (flags), "=&r" (__dummy) + : /* no inputs */ + : "memory" + ); + + return flags; +} + +#define raw_local_irq_save(flags) \ + do { (flags) = __raw_local_irq_save(); } while (0) + +static inline void raw_local_irq_restore(unsigned long flags) +{ + if ((flags & 0xf0) != 0xf0) + raw_local_irq_enable(); +} + +#endif /* __ASM_SH_IRQFLAGS_H */ diff --git a/include/asm-sh/rwsem.h b/include/asm-sh/rwsem.h index 9d2aea5e848..4931ba817d7 100644 --- a/include/asm-sh/rwsem.h +++ b/include/asm-sh/rwsem.h @@ -25,11 +25,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) @@ -39,6 +49,16 @@ extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); +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) + static inline void init_rwsem(struct rw_semaphore *sem) { sem->count = RWSEM_UNLOCKED_VALUE; @@ -141,6 +161,11 @@ static inline void __downgrade_write(struct rw_semaphore *sem) rwsem_downgrade_wake(sem); } +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) +{ + __down_write(sem); +} + /* * implement exchange and add functionality */ diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 3340126f4e0..b1e42e7f998 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -6,6 +6,7 @@ * Copyright (C) 2002 Paul Mundt */ +#include #include /* @@ -131,103 +132,6 @@ static inline unsigned long tas(volatile int *m) #define set_mb(var, value) do { xchg(&var, value); } while (0) -/* Interrupt Control */ -#ifdef CONFIG_CPU_HAS_SR_RB -static inline void local_irq_enable(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__("stc sr, %0\n\t" - "and %1, %0\n\t" - "stc r6_bank, %1\n\t" - "or %1, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x000000f0) - : "memory"); -} -#else -static inline void local_irq_enable(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ( - "stc sr, %0\n\t" - "and %1, %0\n\t" - "ldc %0, sr\n\t" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x000000f0) - : "memory"); -} -#endif - -static inline void local_irq_disable(void) -{ - unsigned long __dummy; - __asm__ __volatile__("stc sr, %0\n\t" - "or #0xf0, %0\n\t" - "ldc %0, sr" - : "=&z" (__dummy) - : /* no inputs */ - : "memory"); -} - -static inline void set_bl_bit(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ("stc sr, %0\n\t" - "or %2, %0\n\t" - "and %3, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "r" (0x10000000), "r" (0xffffff0f) - : "memory"); -} - -static inline void clear_bl_bit(void) -{ - unsigned long __dummy0, __dummy1; - - __asm__ __volatile__ ("stc sr, %0\n\t" - "and %2, %0\n\t" - "ldc %0, sr" - : "=&r" (__dummy0), "=r" (__dummy1) - : "1" (~0x10000000) - : "memory"); -} - -#define local_save_flags(x) \ - __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" ) - -#define irqs_disabled() \ -({ \ - unsigned long flags; \ - local_save_flags(flags); \ - (flags != 0); \ -}) - -static inline unsigned long local_irq_save(void) -{ - unsigned long flags, __dummy; - - __asm__ __volatile__("stc sr, %1\n\t" - "mov %1, %0\n\t" - "or #0xf0, %0\n\t" - "ldc %0, sr\n\t" - "mov %1, %0\n\t" - "and #0xf0, %0" - : "=&z" (flags), "=&r" (__dummy) - :/**/ - : "memory" ); - return flags; -} - -#define local_irq_restore(x) do { \ - if ((x & 0x000000f0) != 0x000000f0) \ - local_irq_enable(); \ -} while (0) - /* * Jump to P2 area. * When handling TLB or caches, we need to do it from P2 area. @@ -264,9 +168,6 @@ do { \ : "=&r" (__dummy)); \ } while (0) -/* For spinlocks etc */ -#define local_irq_save(x) x = local_irq_save() - static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) { unsigned long flags, retval; -- cgit v1.2.3