ps3-debugging: Setup DABR register

For debugging only.

Helper routine to setup DABR (Data Address Breakpoint) register
for kernel use.
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index a19f831..2a5e9c0 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -528,4 +528,13 @@
 
 void ps3_early_mm_init(void);
 
+/* kernel debug routines */
+
+#define   DABR_TRANSLATION	(1UL << 2)
+#define   DABR_DATA_WRITE	(1UL << 1)
+#define   DABR_DATA_READ	(1UL << 0)
+
+int ps3_debug_setup_dabr(u64 address, unsigned int dabr_flags,
+	unsigned int dabrx);
+
 #endif
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 5dd056d..f48afdc 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -610,6 +610,9 @@
 {
 	siginfo_t info;
 
+	printk("%s:%d: address %016lxh, code %08lxh\n",
+		__func__, __LINE__, address, error_code);
+
 	current->thread.trap_nr = TRAP_HWBKPT;
 	if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
 			11, SIGSEGV) == NOTIFY_STOP)
@@ -621,6 +624,13 @@
 	/* Clear the breakpoint */
 	hw_breakpoint_disable();
 
+	if (!user_mode(regs)) {
+		show_regs(regs);
+		printk("%s:%d: done: address %016lxh\n", __func__, __LINE__,
+		address);
+		return;
+	}
+
 	/* Deliver the signal to userspace */
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 62a50d6..a211976 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -257,7 +257,8 @@
 	 * The kernel should never take an execute fault nor should it
 	 * take a page fault to a kernel address.
 	 */
-	if (!user_mode(regs) && (is_exec || (address >= TASK_SIZE))) {
+	if (!user_mode(regs) && (is_exec || (address >= TASK_SIZE)) &&
+		!(error_code & DSISR_DABRMATCH)) {
 		rc = SIGSEGV;
 		goto bail;
 	}
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 6244bc8..ed4fb3e 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -190,6 +190,38 @@
 	return lv1_set_dabr(dabr, dabrx) ? -1 : 0;
 }
 
+/**
+ * ps3_debug_setup_dabr - Setup the DABR for kernel use.
+ * @dabr_flags: DABR_DATA_WRITE, DABR_DATA_READ, DABR_TRANSLATION
+ * @dabrx: DABRX_BTI, DABRX_KERNEL, DABRX_USER
+ */
+
+int ps3_debug_setup_dabr(u64 address, unsigned int dabr_flags,
+	unsigned int dabrx)
+{
+	int result;
+	u64 reg;
+
+	BUG_ON(dabr_flags
+		& ~(DABR_DATA_WRITE | DABR_DATA_READ | DABR_TRANSLATION));
+
+	/* PS3 seems to need DABR_TRANSLATION set to work */
+
+	reg = (address & -8L) | dabr_flags | DABR_TRANSLATION;
+
+	printk("%s: address %016llxh, flags %xh = %016llxh\n", __func__,
+		address, dabr_flags, reg);
+
+	result = ps3_set_dabr(reg, dabrx);
+
+	if (result)
+		printk("%s: failed: %d %s\n", __func__, result,
+			ps3_result(result));
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_debug_setup_dabr);
+
 static void __init ps3_setup_arch(void)
 {
 	u64 tmp;