Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 14 Aug 2008 03:48:25 +0000 (20:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 14 Aug 2008 03:48:25 +0000 (20:48 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  sparc64: Handle stack trace attempts before irqstacks are setup.
  sparc64: Implement IRQ stacks.
  sparc: remove include of linux/of_device.h from asm/of_device.h
  sparc64: Fix recursion in stack overflow detection handling.
  sparc/drivers: use linux/of_device.h instead of asm/of_device.h
  sparc64: Don't MAGIC_SYSRQ ifdef smp_fetch_global_regs and support code.

17 files changed:
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/of_device.h
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/kstack.h [new file with mode: 0644]
arch/sparc64/kernel/process.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/stacktrace.c
arch/sparc64/kernel/traps.c
arch/sparc64/lib/mcount.S
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
drivers/input/serio/i8042-sparcio.h
drivers/sbus/sbus.c
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c

index 3473e25231d96e3fe63a0227cf3103d409074cf4..e3dd9303643dd8f161fd5fd5234abac5a5b77a31 100644 (file)
@@ -93,4 +93,8 @@ static inline unsigned long get_softint(void)
 void __trigger_all_cpu_backtrace(void);
 #define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
 
+extern void *hardirq_stack[NR_CPUS];
+extern void *softirq_stack[NR_CPUS];
+#define __ARCH_HAS_DO_SOFTIRQ
+
 #endif
index e5f5aedc2293e6b857ef0f5753050aa5c733bb91..bba777a416d3bf31b7ab4b5bb5a393ea7cc2c9f7 100644 (file)
@@ -30,8 +30,7 @@ struct of_device
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-/* These are just here during the transition */
-#include <linux/of_device.h>
+/* This is just here during the transition */
 #include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
index ba43d85e8dded537cfeb4a23c510456e4f2c956f..9b6689d9d57097239641d51653dc921e2607b997 100644 (file)
@@ -682,10 +682,32 @@ void ack_bad_irq(unsigned int virt_irq)
               ino, virt_irq);
 }
 
+void *hardirq_stack[NR_CPUS];
+void *softirq_stack[NR_CPUS];
+
+static __attribute__((always_inline)) void *set_hardirq_stack(void)
+{
+       void *orig_sp, *sp = hardirq_stack[smp_processor_id()];
+
+       __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
+       if (orig_sp < sp ||
+           orig_sp > (sp + THREAD_SIZE)) {
+               sp += THREAD_SIZE - 192 - STACK_BIAS;
+               __asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
+       }
+
+       return orig_sp;
+}
+static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
+{
+       __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
+}
+
 void handler_irq(int irq, struct pt_regs *regs)
 {
        unsigned long pstate, bucket_pa;
        struct pt_regs *old_regs;
+       void *orig_sp;
 
        clear_softint(1 << irq);
 
@@ -703,6 +725,8 @@ void handler_irq(int irq, struct pt_regs *regs)
                               "i" (PSTATE_IE)
                             : "memory");
 
+       orig_sp = set_hardirq_stack();
+
        while (bucket_pa) {
                struct irq_desc *desc;
                unsigned long next_pa;
@@ -719,10 +743,38 @@ void handler_irq(int irq, struct pt_regs *regs)
                bucket_pa = next_pa;
        }
 
+       restore_hardirq_stack(orig_sp);
+
        irq_exit();
        set_irq_regs(old_regs);
 }
 
+void do_softirq(void)
+{
+       unsigned long flags;
+
+       if (in_interrupt())
+               return;
+
+       local_irq_save(flags);
+
+       if (local_softirq_pending()) {
+               void *orig_sp, *sp = softirq_stack[smp_processor_id()];
+
+               sp += THREAD_SIZE - 192 - STACK_BIAS;
+
+               __asm__ __volatile__("mov %%sp, %0\n\t"
+                                    "mov %1, %%sp"
+                                    : "=&r" (orig_sp)
+                                    : "r" (sp));
+               __do_softirq();
+               __asm__ __volatile__("mov %0, %%sp"
+                                    : : "r" (orig_sp));
+       }
+
+       local_irq_restore(flags);
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 void fixup_irqs(void)
 {
diff --git a/arch/sparc64/kernel/kstack.h b/arch/sparc64/kernel/kstack.h
new file mode 100644 (file)
index 0000000..4248d96
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef _KSTACK_H
+#define _KSTACK_H
+
+#include <linux/thread_info.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+/* SP must be STACK_BIAS adjusted already.  */
+static inline bool kstack_valid(struct thread_info *tp, unsigned long sp)
+{
+       unsigned long base = (unsigned long) tp;
+
+       if (sp >= (base + sizeof(struct thread_info)) &&
+           sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+               return true;
+
+       if (hardirq_stack[tp->cpu]) {
+               base = (unsigned long) hardirq_stack[tp->cpu];
+               if (sp >= base &&
+                   sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+                       return true;
+               base = (unsigned long) softirq_stack[tp->cpu];
+               if (sp >= base &&
+                   sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+                       return true;
+       }
+       return false;
+}
+
+/* Does "regs" point to a valid pt_regs trap frame?  */
+static inline bool kstack_is_trap_frame(struct thread_info *tp, struct pt_regs *regs)
+{
+       unsigned long base = (unsigned long) tp;
+       unsigned long addr = (unsigned long) regs;
+
+       if (addr >= base &&
+           addr <= (base + THREAD_SIZE - sizeof(*regs)))
+               goto check_magic;
+
+       if (hardirq_stack[tp->cpu]) {
+               base = (unsigned long) hardirq_stack[tp->cpu];
+               if (addr >= base &&
+                   addr <= (base + THREAD_SIZE - sizeof(*regs)))
+                       goto check_magic;
+               base = (unsigned long) softirq_stack[tp->cpu];
+               if (addr >= base &&
+                   addr <= (base + THREAD_SIZE - sizeof(*regs)))
+                       goto check_magic;
+       }
+       return false;
+
+check_magic:
+       if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC)
+               return true;
+       return false;
+
+}
+
+#endif /* _KSTACK_H */
index 7f5debdc5fed6ad2a4ae86b1ff78836efe8dce03..15f4178592e762d4bbff775679ae80c70e91423d 100644 (file)
@@ -52,6 +52,8 @@
 #include <asm/irq_regs.h>
 #include <asm/smp.h>
 
+#include "kstack.h"
+
 static void sparc64_yield(int cpu)
 {
        if (tlb_type != hypervisor)
@@ -235,19 +237,6 @@ void show_regs(struct pt_regs *regs)
 struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
 static DEFINE_SPINLOCK(global_reg_snapshot_lock);
 
-static bool kstack_valid(struct thread_info *tp, struct reg_window *rw)
-{
-       unsigned long thread_base, fp;
-
-       thread_base = (unsigned long) tp;
-       fp = (unsigned long) rw;
-
-       if (fp < (thread_base + sizeof(struct thread_info)) ||
-           fp >= (thread_base + THREAD_SIZE))
-               return false;
-       return true;
-}
-
 static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
                              int this_cpu)
 {
@@ -264,11 +253,11 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
 
                rw = (struct reg_window *)
                        (regs->u_regs[UREG_FP] + STACK_BIAS);
-               if (kstack_valid(tp, rw)) {
+               if (kstack_valid(tp, (unsigned long) rw)) {
                        global_reg_snapshot[this_cpu].i7 = rw->ins[7];
                        rw = (struct reg_window *)
                                (rw->ins[6] + STACK_BIAS);
-                       if (kstack_valid(tp, rw))
+                       if (kstack_valid(tp, (unsigned long) rw))
                                global_reg_snapshot[this_cpu].rpc = rw->ins[7];
                }
        } else {
@@ -828,7 +817,7 @@ out:
 unsigned long get_wchan(struct task_struct *task)
 {
        unsigned long pc, fp, bias = 0;
-       unsigned long thread_info_base;
+       struct thread_info *tp;
        struct reg_window *rw;
         unsigned long ret = 0;
        int count = 0; 
@@ -837,14 +826,12 @@ unsigned long get_wchan(struct task_struct *task)
             task->state == TASK_RUNNING)
                goto out;
 
-       thread_info_base = (unsigned long) task_stack_page(task);
+       tp = task_thread_info(task);
        bias = STACK_BIAS;
        fp = task_thread_info(task)->ksp + bias;
 
        do {
-               /* Bogus frame pointer? */
-               if (fp < (thread_info_base + sizeof(struct thread_info)) ||
-                   fp >= (thread_info_base + THREAD_SIZE))
+               if (!kstack_valid(tp, fp))
                        break;
                rw = (struct reg_window *) fp;
                pc = rw->ins[7];
index 27b81775a4decd16c43f32df32c8347407d82bb4..743ccad61c60921b36c9bf42a556dac79ac4e23c 100644 (file)
@@ -858,9 +858,7 @@ void smp_tsb_sync(struct mm_struct *mm)
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_pending;
 extern unsigned long xcall_flush_tlb_kernel_range;
-#ifdef CONFIG_MAGIC_SYSRQ
 extern unsigned long xcall_fetch_glob_regs;
-#endif
 extern unsigned long xcall_receive_signal;
 extern unsigned long xcall_new_mmu_context_version;
 #ifdef CONFIG_KGDB
@@ -1005,12 +1003,10 @@ void kgdb_roundup_cpus(unsigned long flags)
 }
 #endif
 
-#ifdef CONFIG_MAGIC_SYSRQ
 void smp_fetch_global_regs(void)
 {
        smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0);
 }
-#endif
 
 /* We know that the window frames of the user have been flushed
  * to the stack before we get here because all callers of us
index e9d7f0660f2e044643182cb2e85f9fde7dc5006b..4e21d4a57d3b3f2ea536ed5707d61fbf6bc94181 100644 (file)
@@ -5,10 +5,12 @@
 #include <asm/ptrace.h>
 #include <asm/stacktrace.h>
 
+#include "kstack.h"
+
 void save_stack_trace(struct stack_trace *trace)
 {
-       unsigned long ksp, fp, thread_base;
        struct thread_info *tp = task_thread_info(current);
+       unsigned long ksp, fp;
 
        stack_trace_flush();
 
@@ -18,23 +20,18 @@ void save_stack_trace(struct stack_trace *trace)
        );
 
        fp = ksp + STACK_BIAS;
-       thread_base = (unsigned long) tp;
        do {
                struct sparc_stackf *sf;
                struct pt_regs *regs;
                unsigned long pc;
 
-               /* Bogus frame pointer? */
-               if (fp < (thread_base + sizeof(struct thread_info)) ||
-                   fp > (thread_base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+               if (!kstack_valid(tp, fp))
                        break;
 
                sf = (struct sparc_stackf *) fp;
                regs = (struct pt_regs *) (sf + 1);
 
-               if (((unsigned long)regs <=
-                    (thread_base + THREAD_SIZE - sizeof(*regs))) &&
-                   (regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+               if (kstack_is_trap_frame(tp, regs)) {
                        if (!(regs->tstate & TSTATE_PRIV))
                                break;
                        pc = regs->tpc;
index 404e8561e2d0cec8b6d52a38be95d360624b0be7..3d924121c7960dd5b577c291a9a2dd716a272b2d 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/prom.h>
 
 #include "entry.h"
+#include "kstack.h"
 
 /* When an irrecoverable trap occurs at tl > 0, the trap entry
  * code logs the trap state registers at every level in the trap
@@ -2115,14 +2116,12 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
                struct pt_regs *regs;
                unsigned long pc;
 
-               /* Bogus frame pointer? */
-               if (fp < (thread_base + sizeof(struct thread_info)) ||
-                   fp >= (thread_base + THREAD_SIZE))
+               if (!kstack_valid(tp, fp))
                        break;
                sf = (struct sparc_stackf *) fp;
                regs = (struct pt_regs *) (sf + 1);
 
-               if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+               if (kstack_is_trap_frame(tp, regs)) {
                        if (!(regs->tstate & TSTATE_PRIV))
                                break;
                        pc = regs->tpc;
index 7735a7a60533fa225256ad0bd2d94a00be26033a..fad90ddb3a28f1aae9a6a44e849b7393bbf87ac3 100644 (file)
@@ -48,12 +48,45 @@ mcount:
        sub             %g3, STACK_BIAS, %g3
        cmp             %sp, %g3
        bg,pt           %xcc, 1f
-        sethi          %hi(panicstring), %g3
+        nop
+       lduh            [%g6 + TI_CPU], %g1
+       sethi           %hi(hardirq_stack), %g3
+       or              %g3, %lo(hardirq_stack), %g3
+       sllx            %g1, 3, %g1
+       ldx             [%g3 + %g1], %g7
+       sub             %g7, STACK_BIAS, %g7
+       cmp             %sp, %g7
+       bleu,pt         %xcc, 2f
+        sethi          %hi(THREAD_SIZE), %g3
+       add             %g7, %g3, %g7
+       cmp             %sp, %g7
+       blu,pn          %xcc, 1f
+2:      sethi          %hi(softirq_stack), %g3
+       or              %g3, %lo(softirq_stack), %g3
+       ldx             [%g3 + %g1], %g7
+       cmp             %sp, %g7
+       bleu,pt         %xcc, 2f
+        sethi          %hi(THREAD_SIZE), %g3
+       add             %g7, %g3, %g7
+       cmp             %sp, %g7
+       blu,pn          %xcc, 1f
+        nop
+       /* If we are already on ovstack, don't hop onto it
+        * again, we are already trying to output the stack overflow
+        * message.
+        */
        sethi           %hi(ovstack), %g7               ! cant move to panic stack fast enough
         or             %g7, %lo(ovstack), %g7
-       add             %g7, OVSTACKSIZE, %g7
+       add             %g7, OVSTACKSIZE, %g3
+       sub             %g3, STACK_BIAS + 192, %g3
        sub             %g7, STACK_BIAS, %g7
-       mov             %g7, %sp
+       cmp             %sp, %g7
+       blu,pn          %xcc, 2f
+        cmp            %sp, %g3
+       bleu,pn         %xcc, 1f
+        nop
+2:     mov             %g3, %sp
+       sethi           %hi(panicstring), %g3
        call            prom_printf
         or             %g3, %lo(panicstring), %o0
        call            prom_halt
index 4e821b3ecb039faa71991809c0d4139354ee2a8d..217de3ea29e842cff4c0eff6be2b82c5a13f25fe 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/sstate.h>
 #include <asm/mdesc.h>
 #include <asm/cpudata.h>
+#include <asm/irq.h>
 
 #define MAX_PHYS_ADDRESS       (1UL << 42UL)
 #define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
@@ -1771,6 +1772,16 @@ void __init paging_init(void)
        if (tlb_type == hypervisor)
                sun4v_mdesc_init();
 
+       /* Once the OF device tree and MDESC have been setup, we know
+        * the list of possible cpus.  Therefore we can allocate the
+        * IRQ stacks.
+        */
+       for_each_possible_cpu(i) {
+               /* XXX Use node local allocations... XXX */
+               softirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+               hardirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+       }
+
        /* Setup bootmem... */
        last_valid_pfn = end_pfn = bootmem_init(phys_base);
 
index ff1dc44d363e1cd1349d1b5ad7e26dda18dd394c..86773e89dc1bbf29cf71831948e6d79b5d43188b 100644 (file)
@@ -480,7 +480,6 @@ xcall_sync_tick:
        b               rtrap_xcall
         ldx            [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 
-#ifdef CONFIG_MAGIC_SYSRQ
        .globl          xcall_fetch_glob_regs
 xcall_fetch_glob_regs:
        sethi           %hi(global_reg_snapshot), %g1
@@ -511,7 +510,6 @@ xcall_fetch_glob_regs:
        membar          #StoreStore
        stx             %g3, [%g1 + GR_SNAP_THREAD]
        retry
-#endif /* CONFIG_MAGIC_SYSRQ */
 
 #ifdef DCACHE_ALIASING_POSSIBLE
        .align          32
index 66bafe308b0cd053252e4f0cbf8b3644dfd7c5a5..692a79ec2a22327e98c94ef4946fe2f69b6747da 100644 (file)
@@ -1,10 +1,11 @@
 #ifndef _I8042_SPARCIO_H
 #define _I8042_SPARCIO_H
 
+#include <linux/of_device.h>
+
 #include <asm/io.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 
 static int i8042_kbd_irq = -1;
 static int i8042_aux_irq = -1;
index 73a86d09bba8d71dd84641e58dbde5d1c1278d03..9c129248466c024dd7b03411b6f4351d707823e0 100644 (file)
@@ -7,13 +7,13 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
 
index aeeec5588afd48c2573097417f6fc428d0f6b39d..e41766d08035643e18b72a2cfb88bf471355d885 100644 (file)
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/of_device.h>
 
 #include <asm/hypervisor.h>
 #include <asm/spitfire.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 #include <asm/irq.h>
 
 #if defined(CONFIG_MAGIC_SYSRQ)
index 15ee497e1c78805e3030cd41f383864070884980..29b4458abf744601f39a672bcb0333f5c92b519d 100644 (file)
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 
 #if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
index e24e68235088855c719c629f37a020f5d78d0e54..a378464f92927e83fde05e4e236eaa4f413f1aa5 100644 (file)
 #include <linux/serial_reg.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 
 #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
index 0f3d69b86d6795de97bc81239d20fb78cbb920e9..3cb4c8aee13fa74461648ff3a4ec9f12380fbba3 100644 (file)
 #include <linux/serio.h>
 #endif
 #include <linux/init.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
-#include <asm/of_device.h>
 
 #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ