sh: stacktrace/lockdep/irqflags tracing support.
authorPaul Mundt <lethal@linux-sh.org>
Mon, 4 Dec 2006 09:17:28 +0000 (18:17 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 6 Dec 2006 01:45:40 +0000 (10:45 +0900)
Wire up all of the essentials for lockdep..

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/kernel/Makefile
arch/sh/kernel/cpu/sh2/entry.S
arch/sh/kernel/cpu/sh3/entry.S
arch/sh/kernel/entry-common.S
arch/sh/kernel/stacktrace.c [new file with mode: 0644]
arch/sh/mm/fault.c
include/asm-sh/irqflags.h [new file with mode: 0644]
include/asm-sh/rwsem.h
include/asm-sh/system.h

index aa1ebc561b842dd6ab71d04d812a01125a1ea333..013732074d351aaee2550cb6f4b0e65af0726b60 100644 (file)
@@ -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"
index dcceec95a2d554362306139163db97b78eb45b08..66a25ef4ef1b8bf233e7936f049c91617933596f 100644 (file)
@@ -1,5 +1,9 @@
 menu "Kernel hacking"
 
+config TRACE_IRQFLAGS_SUPPORT
+       bool
+       default y
+
 source "lib/Kconfig.debug"
 
 config SH_STANDARD_BIOS
index 50d54c24d76ae76b445894587a3d018c2c78171f..99c7e5249f7a6ca16a68911955e90e3abb357855 100644 (file)
@@ -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
index 298d9191909da7d745ab97d5b9389809e0befeea..34d51b3745eac80e35fccbb804f571b991595013 100644 (file)
@@ -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"
index 7ba3dcbe7504af4144f274db34f7e7d867df863e..8c0dc2700c69ebc79df3085e0c2e93ce2099a6bb 100644 (file)
@@ -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
 
index 8f96d21fcb1c4722c570a991f83df7e6c131b0b6..29136a35d7c78823c69e8f031da22e6dc2e953b9 100644 (file)
@@ -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 (file)
index 0000000..0d5268a
--- /dev/null
@@ -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 <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+/*
+ * 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;
+               }
+       }
+}
index cfeefc10e2546fdad34552ab7dcbe8c3a8c58382..716ebf568af20d2e2e7e303161d11304886ff794 100644 (file)
@@ -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 (file)
index 0000000..9dedc1b
--- /dev/null
@@ -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 */
index 9d2aea5e848854c170c21f901f999ea13a0e9492..4931ba817d734aa8192374ef9e563d69b48f4c94 100644 (file)
@@ -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
  */
index 3340126f4e0fc7785cef0ed7e4c191583fdc6e35..b1e42e7f998b5639a41f57281a35d1d89c7c1ab6 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2002 Paul Mundt
  */
 
+#include <linux/irqflags.h>
 #include <asm/types.h>
 
 /*
@@ -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;