summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/Kconfig8
-rw-r--r--arch/sh/Kconfig.debug4
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S16
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S2
-rw-r--r--arch/sh/kernel/entry-common.S64
-rw-r--r--arch/sh/kernel/stacktrace.c43
-rw-r--r--arch/sh/mm/fault.c3
-rw-r--r--include/asm-sh/irqflags.h123
-rw-r--r--include/asm-sh/rwsem.h27
-rw-r--r--include/asm-sh/system.h101
11 files changed, 289 insertions, 103 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index aa1ebc561b84..013732074d35 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 dcceec95a2d5..66a25ef4ef1b 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 50d54c24d76a..99c7e5249f7a 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 298d9191909d..34d51b3745ea 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 7ba3dcbe7504..8c0dc2700c69 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 8f96d21fcb1c..29136a35d7c7 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 000000000000..0d5268afe80f
--- /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 <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;
+ }
+ }
+}
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index cfeefc10e254..716ebf568af2 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 000000000000..9dedc1b693e3
--- /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 9d2aea5e8488..4931ba817d73 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 3340126f4e0f..b1e42e7f998b 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -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;