]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - arch/powerpc/kernel/process.c
dump_stack: unify debug information printed by show_regs()
[linux-3.10.git] / arch / powerpc / kernel / process.c
index 3665d287780fc6d8542907d4d98c77ece0eb6a0b..13a8d9d0b5cbd9d098861725e28607cfb7c36515 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/runlatch.h>
 #include <asm/syscalls.h>
 #include <asm/switch_to.h>
+#include <asm/tm.h>
 #include <asm/debug.h>
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
+/* Transactional Memory debug */
+#ifdef TM_DEBUG_SW
+#define TM_DEBUG(x...) printk(KERN_INFO x)
+#else
+#define TM_DEBUG(x...) do { } while(0)
+#endif
+
 extern unsigned long _get_SP(void);
 
 #ifndef CONFIG_SMP
@@ -271,7 +279,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address,
        force_sig_info(SIGTRAP, &info, current);
 }
 #else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
-void do_dabr(struct pt_regs *regs, unsigned long address,
+void do_break (struct pt_regs *regs, unsigned long address,
                    unsigned long error_code)
 {
        siginfo_t info;
@@ -281,11 +289,11 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
                        11, SIGSEGV) == NOTIFY_STOP)
                return;
 
-       if (debugger_dabr_match(regs))
+       if (debugger_break_match(regs))
                return;
 
-       /* Clear the DABR */
-       set_dabr(0, 0);
+       /* Clear the breakpoint */
+       hw_breakpoint_disable();
 
        /* Deliver the signal to userspace */
        info.si_signo = SIGTRAP;
@@ -296,7 +304,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address,
 }
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
-static DEFINE_PER_CPU(unsigned long, current_dabr);
+static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk);
 
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 /*
@@ -364,39 +372,216 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread)
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
-       if (thread->dabr) {
-               thread->dabr = 0;
-               thread->dabrx = 0;
-               set_dabr(0, 0);
-       }
+       thread->hw_brk.address = 0;
+       thread->hw_brk.type = 0;
+       set_breakpoint(&thread->hw_brk);
 }
 #endif /* !CONFIG_HAVE_HW_BREAKPOINT */
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
-int set_dabr(unsigned long dabr, unsigned long dabrx)
-{
-       __get_cpu_var(current_dabr) = dabr;
-
-       if (ppc_md.set_dabr)
-               return ppc_md.set_dabr(dabr, dabrx);
-
-       /* XXX should we have a CPU_FTR_HAS_DABR ? */
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
        mtspr(SPRN_DAC1, dabr);
 #ifdef CONFIG_PPC_47x
        isync();
 #endif
+       return 0;
+}
 #elif defined(CONFIG_PPC_BOOK3S)
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
        mtspr(SPRN_DABR, dabr);
        mtspr(SPRN_DABRX, dabrx);
+       return 0;
+}
+#else
+static inline int __set_dabr(unsigned long dabr, unsigned long dabrx)
+{
+       return -EINVAL;
+}
 #endif
+
+static inline int set_dabr(struct arch_hw_breakpoint *brk)
+{
+       unsigned long dabr, dabrx;
+
+       dabr = brk->address | (brk->type & HW_BRK_TYPE_DABR);
+       dabrx = ((brk->type >> 3) & 0x7);
+
+       if (ppc_md.set_dabr)
+               return ppc_md.set_dabr(dabr, dabrx);
+
+       return __set_dabr(dabr, dabrx);
+}
+
+static inline int set_dawr(struct arch_hw_breakpoint *brk)
+{
+       unsigned long dawr, dawrx, mrd;
+
+       dawr = brk->address;
+
+       dawrx  = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)) \
+                                  << (63 - 58); //* read/write bits */
+       dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) \
+                                  << (63 - 59); //* translate */
+       dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) \
+                                  >> 3; //* PRIM bits */
+       /* dawr length is stored in field MDR bits 48:53.  Matches range in
+          doublewords (64 bits) baised by -1 eg. 0b000000=1DW and
+          0b111111=64DW.
+          brk->len is in bytes.
+          This aligns up to double word size, shifts and does the bias.
+       */
+       mrd = ((brk->len + 7) >> 3) - 1;
+       dawrx |= (mrd & 0x3f) << (63 - 53);
+
+       if (ppc_md.set_dawr)
+               return ppc_md.set_dawr(dawr, dawrx);
+       mtspr(SPRN_DAWR, dawr);
+       mtspr(SPRN_DAWRX, dawrx);
        return 0;
 }
 
+int set_breakpoint(struct arch_hw_breakpoint *brk)
+{
+       __get_cpu_var(current_brk) = *brk;
+
+       if (cpu_has_feature(CPU_FTR_DAWR))
+               return set_dawr(brk);
+
+       return set_dabr(brk);
+}
+
 #ifdef CONFIG_PPC64
 DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
 #endif
 
+static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
+                             struct arch_hw_breakpoint *b)
+{
+       if (a->address != b->address)
+               return false;
+       if (a->type != b->type)
+               return false;
+       if (a->len != b->len)
+               return false;
+       return true;
+}
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline void tm_reclaim_task(struct task_struct *tsk)
+{
+       /* We have to work out if we're switching from/to a task that's in the
+        * middle of a transaction.
+        *
+        * In switching we need to maintain a 2nd register state as
+        * oldtask->thread.ckpt_regs.  We tm_reclaim(oldproc); this saves the
+        * checkpointed (tbegin) state in ckpt_regs and saves the transactional
+        * (current) FPRs into oldtask->thread.transact_fpr[].
+        *
+        * We also context switch (save) TFHAR/TEXASR/TFIAR in here.
+        */
+       struct thread_struct *thr = &tsk->thread;
+
+       if (!thr->regs)
+               return;
+
+       if (!MSR_TM_ACTIVE(thr->regs->msr))
+               goto out_and_saveregs;
+
+       /* Stash the original thread MSR, as giveup_fpu et al will
+        * modify it.  We hold onto it to see whether the task used
+        * FP & vector regs.
+        */
+       thr->tm_orig_msr = thr->regs->msr;
+
+       TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, "
+                "ccr=%lx, msr=%lx, trap=%lx)\n",
+                tsk->pid, thr->regs->nip,
+                thr->regs->ccr, thr->regs->msr,
+                thr->regs->trap);
+
+       tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED);
+
+       TM_DEBUG("--- tm_reclaim on pid %d complete\n",
+                tsk->pid);
+
+out_and_saveregs:
+       /* Always save the regs here, even if a transaction's not active.
+        * This context-switches a thread's TM info SPRs.  We do it here to
+        * be consistent with the restore path (in recheckpoint) which
+        * cannot happen later in _switch().
+        */
+       tm_save_sprs(thr);
+}
+
+static inline void tm_recheckpoint_new_task(struct task_struct *new)
+{
+       unsigned long msr;
+
+       if (!cpu_has_feature(CPU_FTR_TM))
+               return;
+
+       /* Recheckpoint the registers of the thread we're about to switch to.
+        *
+        * If the task was using FP, we non-lazily reload both the original and
+        * the speculative FP register states.  This is because the kernel
+        * doesn't see if/when a TM rollback occurs, so if we take an FP
+        * unavoidable later, we are unable to determine which set of FP regs
+        * need to be restored.
+        */
+       if (!new->thread.regs)
+               return;
+
+       /* The TM SPRs are restored here, so that TEXASR.FS can be set
+        * before the trecheckpoint and no explosion occurs.
+        */
+       tm_restore_sprs(&new->thread);
+
+       if (!MSR_TM_ACTIVE(new->thread.regs->msr))
+               return;
+       msr = new->thread.tm_orig_msr;
+       /* Recheckpoint to restore original checkpointed register state. */
+       TM_DEBUG("*** tm_recheckpoint of pid %d "
+                "(new->msr 0x%lx, new->origmsr 0x%lx)\n",
+                new->pid, new->thread.regs->msr, msr);
+
+       /* This loads the checkpointed FP/VEC state, if used */
+       tm_recheckpoint(&new->thread, msr);
+
+       /* This loads the speculative FP/VEC state, if used */
+       if (msr & MSR_FP) {
+               do_load_up_transact_fpu(&new->thread);
+               new->thread.regs->msr |=
+                       (MSR_FP | new->thread.fpexc_mode);
+       }
+#ifdef CONFIG_ALTIVEC
+       if (msr & MSR_VEC) {
+               do_load_up_transact_altivec(&new->thread);
+               new->thread.regs->msr |= MSR_VEC;
+       }
+#endif
+       /* We may as well turn on VSX too since all the state is restored now */
+       if (msr & MSR_VSX)
+               new->thread.regs->msr |= MSR_VSX;
+
+       TM_DEBUG("*** tm_recheckpoint of pid %d complete "
+                "(kernel msr 0x%lx)\n",
+                new->pid, mfmsr());
+}
+
+static inline void __switch_to_tm(struct task_struct *prev)
+{
+       if (cpu_has_feature(CPU_FTR_TM)) {
+               tm_enable();
+               tm_reclaim_task(prev);
+       }
+}
+#else
+#define tm_recheckpoint_new_task(new)
+#define __switch_to_tm(prev)
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
 struct task_struct *__switch_to(struct task_struct *prev,
        struct task_struct *new)
 {
@@ -407,6 +592,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
        struct ppc64_tlb_batch *batch;
 #endif
 
+       __switch_to_tm(prev);
+
 #ifdef CONFIG_SMP
        /* avoid complexity of lazy save/restore of fpu
         * by just saving it every time we switch out if
@@ -481,8 +668,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
  * schedule DABR
  */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
-       if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
-               set_dabr(new->thread.dabr, new->thread.dabrx);
+       if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
+               set_breakpoint(&new->thread.hw_brk);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif
 
@@ -522,6 +709,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
         * of sync. Hard disable here.
         */
        hard_irq_disable();
+
+       tm_recheckpoint_new_task(new);
+
        last = _switch(old_thread, new_thread);
 
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -641,6 +831,8 @@ void show_regs(struct pt_regs * regs)
 {
        int i, trap;
 
+       show_regs_print_info(KERN_DEFAULT);
+
        printk("NIP: "REG" LR: "REG" CTR: "REG"\n",
               regs->nip, regs->link, regs->ctr);
        printk("REGS: %p TRAP: %04lx   %s  (%s)\n",
@@ -660,12 +852,6 @@ void show_regs(struct pt_regs * regs)
 #else
                printk("DAR: "REG", DSISR: %08lx\n", regs->dar, regs->dsisr);
 #endif
-       printk("TASK = %p[%d] '%s' THREAD: %p",
-              current, task_pid_nr(current), current->comm, task_thread_info(current));
-
-#ifdef CONFIG_SMP
-       printk(" CPU: %d", raw_smp_processor_id());
-#endif /* CONFIG_SMP */
 
        for (i = 0;  i < 32;  i++) {
                if ((i % REGS_PER_LINE) == 0)
@@ -682,6 +868,9 @@ void show_regs(struct pt_regs * regs)
         */
        printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
        printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
+#endif
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       printk("PACATMSCRATCH [%llx]\n", get_paca()->tm_scratch);
 #endif
        show_stack(current, (unsigned long *) regs->gpr[1]);
        if (!user_mode(regs))
@@ -733,8 +922,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long arg, struct task_struct *p,
-               struct pt_regs *regs)
+               unsigned long arg, struct task_struct *p)
 {
        struct pt_regs *childregs, *kregs;
        extern void ret_from_fork(void);
@@ -745,7 +933,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        /* Copy registers */
        sp -= sizeof(struct pt_regs);
        childregs = (struct pt_regs *) sp;
-       if (!regs) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                struct thread_info *ti = (void *)task_stack_page(p);
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
@@ -759,6 +947,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                ti->flags |= _TIF_RESTOREALL;
                f = ret_from_kernel_thread;
        } else {
+               struct pt_regs *regs = current_pt_regs();
                CHECK_FULL_REGS(regs);
                *childregs = *regs;
                if (usp)
@@ -813,6 +1002,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                p->thread.dscr_inherit = current->thread.dscr_inherit;
                p->thread.dscr = current->thread.dscr;
        }
+       if (cpu_has_feature(CPU_FTR_HAS_PPR))
+               p->thread.ppr = INIT_PPR;
 #endif
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
@@ -892,7 +1083,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
                regs->msr = MSR_USER32;
        }
 #endif
-
        discard_lazy_cpu_state();
 #ifdef CONFIG_VSX
        current->thread.used_vsr = 0;
@@ -912,6 +1102,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
        current->thread.spefscr = 0;
        current->thread.used_spe = 0;
 #endif /* CONFIG_SPE */
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       if (cpu_has_feature(CPU_FTR_TM))
+               regs->msr |= MSR_TM;
+       current->thread.tm_tfhar = 0;
+       current->thread.tm_texasr = 0;
+       current->thread.tm_tfiar = 0;
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 }
 
 #define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
@@ -1026,29 +1223,6 @@ int get_unalign_ctl(struct task_struct *tsk, unsigned long adr)
        return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr);
 }
 
-int sys_clone(unsigned long clone_flags, unsigned long usp,
-             int __user *parent_tidp, void __user *child_threadptr,
-             int __user *child_tidp, int p6,
-             struct pt_regs *regs)
-{
-       return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp);
-}
-
-int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3,
-            unsigned long p4, unsigned long p5, unsigned long p6,
-            struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, 0, regs, 0, NULL, NULL);
-}
-
-int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
-             unsigned long p4, unsigned long p5, unsigned long p6,
-             struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
-                       regs, 0, NULL, NULL);
-}
-
 static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
                                  unsigned long nbytes)
 {
@@ -1184,12 +1358,6 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
        } while (count++ < kstack_depth_to_print);
 }
 
-void dump_stack(void)
-{
-       show_stack(current, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
 #ifdef CONFIG_PPC64
 /* Called with hard IRQs off */
 void __ppc64_runlatch_on(void)