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 a1bc7e7..871bcdd 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -526,4 +526,13 @@
 u32 ps3_get_hw_thread_id(int cpu);
 u64 ps3_get_spe_id(void *arg);
 
+/* 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 bf44ae9..a25255e 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -328,6 +328,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)
@@ -339,6 +342,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 51ab9e7..843c985 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -243,7 +243,8 @@
 		goto bail;
 
 	/* On a kernel SLB miss we can only check for a valid exception entry */
-	if (!user_mode(regs) && (address >= TASK_SIZE)) {
+	if (!user_mode(regs) && (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 3f509f8..9e917a7 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -195,6 +195,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;