From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Date: Tue, 8 Oct 2013 11:39:31 +0000 (+0100)
Subject: MIPS: Print correct PC in trace dump after NMI exception
X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=83e4da1ed45441c3aadc39ac47d33895ab23c841;p=linux.git

MIPS: Print correct PC in trace dump after NMI exception

An NMI exception delivered from YAMON delivers the PC in ErrorPC
instead of EPC. It's also necessary to clear the Status.BEV
bit for the page fault exception handler to work properly.

[ralf@linux-mips: Let the assembler do the loading of the mask value rather
than the convoluted explicit %hi/%lo manual relocation sequence from the
original patch.]

Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/6035/
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Markos Chandras <markos.chandras@imgtec.com>
Patchwork: https://patchwork.linux-mips.org/patch/6084/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---

diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 31fa856829cbf..47d7583cd67ff 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -374,12 +374,20 @@ NESTED(except_vec_nmi, 0, sp)
 NESTED(nmi_handler, PT_SIZE, sp)
 	.set	push
 	.set	noat
+	/*
+	 * Clear ERL - restore segment mapping
+	 * Clear BEV - required for page fault exception handler to work
+	 */
+	mfc0	k0, CP0_STATUS
+	ori     k0, k0, ST0_EXL
+	li	k1, ~(ST0_BEV | ST0_ERL)
+	and     k0, k0, k1
+	mtc0    k0, CP0_STATUS
+	_ehb
 	SAVE_ALL
 	move	a0, sp
 	jal	nmi_exception_handler
-	RESTORE_ALL
-	.set	mips3
-	eret
+	/* nmi_exception_handler never returns */
 	.set	pop
 	END(nmi_handler)
 
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index f2ae9cb57ff0b..a17b6efb8bfe2 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -330,6 +330,7 @@ void show_regs(struct pt_regs *regs)
 void show_registers(struct pt_regs *regs)
 {
 	const int field = 2 * sizeof(unsigned long);
+	mm_segment_t old_fs = get_fs();
 
 	__show_regs(regs);
 	print_modules();
@@ -344,9 +345,13 @@ void show_registers(struct pt_regs *regs)
 			printk("*HwTLS: %0*lx\n", field, tls);
 	}
 
+	if (!user_mode(regs))
+		/* Necessary for getting the correct stack content */
+		set_fs(KERNEL_DS);
 	show_stacktrace(current, regs);
 	show_code((unsigned int __user *) regs->cp0_epc);
 	printk("\n");
+	set_fs(old_fs);
 }
 
 static int regs_to_trapnr(struct pt_regs *regs)
@@ -1488,10 +1493,14 @@ int register_nmi_notifier(struct notifier_block *nb)
 
 void __noreturn nmi_exception_handler(struct pt_regs *regs)
 {
+	char str[100];
+
 	raw_notifier_call_chain(&nmi_chain, 0, regs);
 	bust_spinlocks(1);
-	printk("NMI taken!!!!\n");
-	die("NMI", regs);
+	snprintf(str, 100, "CPU%d NMI taken, CP0_EPC=%lx\n",
+		 smp_processor_id(), regs->cp0_epc);
+	regs->cp0_epc = read_c0_errorepc();
+	die(str, regs);
 }
 
 #define VECTORSPACING 0x100	/* for EI/VI mode */