From: Anton Blanchard Fix __get_SP() __get_SP used to be a function call which meant we allocated a stack frame before calling it. This meant the SP it returned was one frame below the current function. Lets call that bogusSP (and the real one SP). The new dump_stack was being tail call optimised so it remained one frame above bogusSP. dump_stack would then store below SP (as the ABI allows us to) and would stomp over the back link that bogusSP pointed to (__get_SP had set the back link up so it worked sometimes, just not all the time). Fix this by just making __get_SP an inline that returns the current SP. --- arch/ppc64/kernel/irq.c | 2 +- arch/ppc64/kernel/misc.S | 4 ---- arch/ppc64/kernel/process.c | 8 ++++---- arch/ppc64/kernel/stab.c | 2 +- include/asm-ppc64/processor.h | 3 ++- 5 files changed, 8 insertions(+), 11 deletions(-) diff -puN arch/ppc64/kernel/irq.c~ppc64-get_SP arch/ppc64/kernel/irq.c --- 25/arch/ppc64/kernel/irq.c~ppc64-get_SP 2004-02-21 20:58:31.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/irq.c 2004-02-21 20:58:31.000000000 -0800 @@ -579,7 +579,7 @@ int do_IRQ(struct pt_regs *regs) { long sp; - sp = (unsigned long)_get_SP() & (THREAD_SIZE-1); + sp = __get_SP() & (THREAD_SIZE-1); if (unlikely(sp < (sizeof(struct thread_info) + 8192))) { printk("do_IRQ: stack overflow: %ld\n", diff -puN arch/ppc64/kernel/misc.S~ppc64-get_SP arch/ppc64/kernel/misc.S --- 25/arch/ppc64/kernel/misc.S~ppc64-get_SP 2004-02-21 20:58:31.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/misc.S 2004-02-21 20:58:31.000000000 -0800 @@ -383,10 +383,6 @@ _GLOBAL(abs) neg r3,r3 10: blr -_GLOBAL(_get_SP) - mr r3,r1 /* Close enough */ - blr - _GLOBAL(_get_PVR) mfspr r3,PVR blr diff -puN arch/ppc64/kernel/process.c~ppc64-get_SP arch/ppc64/kernel/process.c --- 25/arch/ppc64/kernel/process.c~ppc64-get_SP 2004-02-21 20:58:31.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/process.c 2004-02-21 20:58:31.000000000 -0800 @@ -162,7 +162,7 @@ struct task_struct *__switch_to(struct t * for that first. */ if ((cur_cpu_spec->cpu_features & CPU_FTR_SLB) && - GET_ESID((unsigned long)_get_SP()) != GET_ESID(PAGE_OFFSET)) { + GET_ESID(__get_SP()) != GET_ESID(PAGE_OFFSET)) { union { unsigned long word0; slb_dword0 data; @@ -171,7 +171,7 @@ struct task_struct *__switch_to(struct t esid_data.word0 = 0; /* class bit is in valid field for slbie instruction */ esid_data.data.v = 1; - esid_data.data.esid = GET_ESID((unsigned long)_get_SP()); + esid_data.data.esid = GET_ESID(__get_SP()); asm volatile("isync; slbie %0; isync" : : "r" (esid_data)); } local_irq_restore(flags); @@ -528,7 +528,7 @@ void show_stack(struct task_struct *p, u if (p) { sp = p->thread.ksp; } else { - sp = (unsigned long)_get_SP(); + sp = __get_SP(); p = current; } } @@ -549,7 +549,7 @@ void show_stack(struct task_struct *p, u void dump_stack(void) { - show_stack(current, (unsigned long *)_get_SP()); + show_stack(current, (unsigned long *)__get_SP()); } EXPORT_SYMBOL(dump_stack); diff -puN arch/ppc64/kernel/stab.c~ppc64-get_SP arch/ppc64/kernel/stab.c --- 25/arch/ppc64/kernel/stab.c~ppc64-get_SP 2004-02-21 20:58:31.000000000 -0800 +++ 25-akpm/arch/ppc64/kernel/stab.c 2004-02-21 20:58:31.000000000 -0800 @@ -324,7 +324,7 @@ static void make_slbe(unsigned long esid castout_entry = 1; asm volatile("slbmfee %0,%1" : "=r" (esid_data) : "r" (entry)); } while (esid_data.data.v && - esid_data.data.esid == GET_ESID((unsigned long)_get_SP())); + esid_data.data.esid == GET_ESID(__get_SP())); get_paca()->xStab_data.next_round_robin = castout_entry; diff -puN include/asm-ppc64/processor.h~ppc64-get_SP include/asm-ppc64/processor.h --- 25/include/asm-ppc64/processor.h~ppc64-get_SP 2004-02-21 20:58:31.000000000 -0800 +++ 25-akpm/include/asm-ppc64/processor.h 2004-02-21 20:58:31.000000000 -0800 @@ -475,7 +475,8 @@ static inline void set_tb(unsigned int u mttbl(lower); } -extern unsigned long *_get_SP(void); +#define __get_SP() ({unsigned long sp; \ + asm volatile("mr %0,1": "=r" (sp)); sp;}) extern int have_of; _