sh: Rework irqflags tracing to fix up CONFIG_PROVE_LOCKING.
authorStuart Menefy <stuart.menefy@st.com>
Wed, 29 Jul 2009 14:01:24 +0000 (23:01 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 29 Jul 2009 14:01:24 +0000 (23:01 +0900)
This cleans up the irqflags tracing code quite a bit and ties it
in to various missing callsites that caused an imbalance when
CONFIG_PROVE_LOCKING was enabled.

Previously this was catching on:

 987 #ifdef CONFIG_PROVE_LOCKING
 988     DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
 989     DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
 990 #endif
 991     retval = -EAGAIN;

with hardirqs being doubly enabled, and subsequently bailing out
with the following call trace:

Call trace:
[<88035224>] __lock_acquire+0x616/0x6a6
[<88015a8c>] do_fork+0xf8/0x2b0
[<880331ec>] trace_hardirqs_on_caller+0xd4/0x114
[<88241074>] _spin_unlock_irq+0x20/0x64
[<88035224>] __lock_acquire+0x616/0x6a6
[<8800386c>] kernel_thread+0x48/0x70
[<88024ecc>] ____call_usermodehelper+0x0/0x110
[<88024ecc>] ____call_usermodehelper+0x0/0x110
[<88003894>] kernel_thread_helper+0x0/0x14
[<88024bac>] __call_usermodehelper+0x38/0x70
[<88025dc0>] worker_thread+0x150/0x274
[<88035b9c>] lock_release+0x0/0x198
[<88024b74>] __call_usermodehelper+0x0/0x70
[<88028cf0>] autoremove_wake_function+0x0/0x30
[<88028bf2>] kthread+0x3e/0x70
[<88025c70>] worker_thread+0x0/0x274
[<8800389c>] kernel_thread_helper+0x8/0x14
[<88028bb4>] kthread+0x0/0x70
[<88003894>] kernel_thread_helper+0x0/0x14

Reported-by: Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Matt Fleming <matt@console-pimps.org>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/Kconfig.debug
arch/sh/include/asm/entry-macros.S
arch/sh/kernel/entry-common.S
arch/sh/kernel/io_trapped.c
drivers/serial/sh-sci.c

index b440fd9367141cb023ad1db2ef5d9afc0f55cb73..a6dce41296e745530c6cf4093bb50cb8afc9c5e8 100644 (file)
@@ -38,7 +38,7 @@ config EARLY_SCIF_CONSOLE_PORT
        default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763 || \
                                CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7366 || \
                                CPU_SUBTYPE_SH7343
-       default "0xffea0000" if CPU_SUBTYPE_SH7785
+       default "0xffeb0000" if CPU_SUBTYPE_SH7785
        default "0xffeb0000" if CPU_SUBTYPE_SH7786
        default "0xfffe8000" if CPU_SUBTYPE_SH7203
        default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
index 3a4752a657220e10729a00fbdb3507b3aa7df1b8..1bdd93891cd7567ce2baad7963106436cad6852c 100644 (file)
 #endif 
        .endm
 
+#ifdef CONFIG_TRACE_IRQFLAGS
+
+       .macro  TRACE_IRQS_ON
+       mov.l   r0, @-r15
+       mov.l   r1, @-r15
+       mov.l   r2, @-r15
+       mov.l   r3, @-r15
+       mov.l   r4, @-r15
+       mov.l   r5, @-r15
+       mov.l   r6, @-r15
+       mov.l   r7, @-r15
+
+       mov.l   7834f, r0
+       jsr     @r0
+        nop
+
+       mov.l   @r15+, r7
+       mov.l   @r15+, r6
+       mov.l   @r15+, r5
+       mov.l   @r15+, r4
+       mov.l   @r15+, r3
+       mov.l   @r15+, r2
+       mov.l   @r15+, r1
+       mov.l   @r15+, r0
+       mov.l   7834f, r0
+
+       bra     7835f
+        nop
+       .balign 4
+7834:  .long   trace_hardirqs_on
+7835:
+       .endm
+       .macro  TRACE_IRQS_OFF
+
+       mov.l   r0, @-r15
+       mov.l   r1, @-r15
+       mov.l   r2, @-r15
+       mov.l   r3, @-r15
+       mov.l   r4, @-r15
+       mov.l   r5, @-r15
+       mov.l   r6, @-r15
+       mov.l   r7, @-r15
+
+       mov.l   7834f, r0
+       jsr     @r0
+        nop
+
+       mov.l   @r15+, r7
+       mov.l   @r15+, r6
+       mov.l   @r15+, r5
+       mov.l   @r15+, r4
+       mov.l   @r15+, r3
+       mov.l   @r15+, r2
+       mov.l   @r15+, r1
+       mov.l   @r15+, r0
+       mov.l   7834f, r0
+
+       bra     7835f
+        nop
+       .balign 4
+7834:  .long   trace_hardirqs_off
+7835:
+       .endm
+
+#else
+       .macro  TRACE_IRQS_ON
+       .endm
+
+       .macro  TRACE_IRQS_OFF
+       .endm
+#endif
+
 #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
 # define PREF(x)       pref    @x
 #else
index d62175650c54802725dec9730d1c1676058f5426..fc26ccd82789f0bc44e053f8d27e637e302d3a7a 100644 (file)
@@ -45,7 +45,7 @@
  */
 
 #if defined(CONFIG_PREEMPT)
-#  define preempt_stop()       cli
+#  define preempt_stop()       cli ; TRACE_IRQS_OFF
 #else
 #  define preempt_stop()
 #  define resume_kernel                __restore_all
        .align  2
 ENTRY(exception_error)
        !
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   2f, r0
-       jsr     @r0
-        nop
-#endif
+       TRACE_IRQS_ON
        sti
        mov.l   1f, r0
        jmp     @r0
@@ -67,22 +63,23 @@ ENTRY(exception_error)
 
        .align  2
 1:     .long   do_exception_error
-#ifdef CONFIG_TRACE_IRQFLAGS
-2:     .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
        mov.l   @(r0,r15), r0   ! get status register
+
+       shlr2   r0
+       and     #0x3c, r0
+       cmp/eq  #0x3c, r0
+       bt      9f
+       TRACE_IRQS_ON
+9:
+       mov     #OFF_SR, r0
+       mov.l   @(r0,r15), r0   ! get status register
        shll    r0
        shll    r0              ! kernel space?
        get_current_thread_info r8, r0
@@ -125,11 +122,7 @@ noresched:
 ENTRY(resume_userspace)
        ! r8: current_thread_info
        cli
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   5f, r0
-       jsr     @r0
-        nop
-#endif
+       TRACE_IRQS_OfF
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
        tst     #(_TIF_WORK_MASK & 0xff), r0
        bt/s    __restore_all
@@ -156,11 +149,7 @@ work_resched:
        jsr     @r1                             ! schedule
         nop
        cli
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   5f, r0
-       jsr     @r0
-        nop
-#endif
+       TRACE_IRQS_OFF
        !
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
        tst     #(_TIF_WORK_MASK & 0xff), r0
@@ -172,10 +161,6 @@ work_resched:
 1:     .long   schedule
 2:     .long   do_notify_resume
 3:     .long   resume_userspace
-#ifdef CONFIG_TRACE_IRQFLAGS
-4:     .long   trace_hardirqs_on
-5:     .long   trace_hardirqs_off
-#endif
 
        .align  2
 syscall_exit_work:
@@ -184,11 +169,7 @@ syscall_exit_work:
        tst     #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
        bt/s    work_pending
         tst    #_TIF_NEED_RESCHED, r0
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   5f, r0
-       jsr     @r0
-        nop
-#endif
+       TRACE_IRQS_ON
        sti
        mov     r15, r4
        mov.l   8f, r0                  ! do_syscall_trace_leave
@@ -321,11 +302,7 @@ ENTRY(system_call)
        bt/s    debug_trap              ! it's a debug trap..
         nop
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   5f, r10
-       jsr     @r10
-        nop
-#endif
+       TRACE_IRQS_ON
        sti
 
        !
@@ -355,11 +332,7 @@ syscall_call:
        !
 syscall_exit:
        cli
-#ifdef CONFIG_TRACE_IRQFLAGS
-       mov.l   6f, r0
-       jsr     @r0
-        nop
-#endif
+       TRACE_IRQS_OFF
        !
        get_current_thread_info r8, r0
        mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
@@ -377,9 +350,5 @@ syscall_exit:
 #endif
 2:     .long   NR_syscalls
 3:     .long   sys_call_table
-#ifdef CONFIG_TRACE_IRQFLAGS
-5:     .long   trace_hardirqs_on
-6:     .long   trace_hardirqs_off
-#endif
 7:     .long   do_syscall_trace_enter
 8:     .long   do_syscall_trace_leave
index 77dfecb643739d5e6abd8ec153289c1ba90a4d6a..e27a19e1f46ec2d06893784e971fe705e38bf91c 100644 (file)
@@ -112,14 +112,15 @@ void __iomem *match_trapped_io_handler(struct list_head *list,
        struct trapped_io *tiop;
        struct resource *res;
        int k, len;
+       unsigned long flags;
 
-       spin_lock_irq(&trapped_lock);
+       spin_lock_irqsave(&trapped_lock, flags);
        list_for_each_entry(tiop, list, list) {
                voffs = 0;
                for (k = 0; k < tiop->num_resources; k++) {
                        res = tiop->resource + k;
                        if (res->start == offset) {
-                               spin_unlock_irq(&trapped_lock);
+                               spin_unlock_irqrestore(&trapped_lock, flags);
                                return tiop->virt_base + voffs;
                        }
 
@@ -127,7 +128,7 @@ void __iomem *match_trapped_io_handler(struct list_head *list,
                        voffs += roundup(len, PAGE_SIZE);
                }
        }
-       spin_unlock_irq(&trapped_lock);
+       spin_unlock_irqrestore(&trapped_lock, flags);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(match_trapped_io_handler);
index 8e2feb563347151d220ed23155074dc5e0f0c761..4cbb87ad070ac122d1e7a635c81afd7c19e32c61 100644 (file)
@@ -662,10 +662,11 @@ static irqreturn_t sci_rx_interrupt(int irq, void *port)
 static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
 {
        struct uart_port *port = ptr;
+       unsigned long flags;
 
-       spin_lock_irq(&port->lock);
+       spin_lock_irqsave(&port->lock, flags);
        sci_transmit_chars(port);
-       spin_unlock_irq(&port->lock);
+       spin_unlock_irqrestore(&port->lock, flags);
 
        return IRQ_HANDLED;
 }