From b2afb4313281fdf4a55a4f59c95dacd09413a83e Mon Sep 17 00:00:00 2001
From: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Date: Thu, 6 Nov 2014 17:15:32 +0530
Subject: powerpc, pseries: Emulate H_SET_DABR/XDABR as H_SET_MODE on POWER8
Patch-mainline: Never, this is a half-stub special implementation for SLE11SP4.
References: bsc#912129, FATE#317619

POWER8 system does not have DABR/DABRX registers, instead they have
DAWR/DAWRX register. Hence H_SET_MODE hcall is not defined on POWER8.
This patch emulates access to H_SET_DABR/XDABR hcalls as H_SET_MODE
hcall on POWER8 systems thus providing HW breakpoint support.

This patch selectively back ports some of the mainline commit IDs
such as bf99de36e, 8563bf52d and 9642382e8 for this purpose.

Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
Acked-by: Torsten Duwe <duwe@suse.de>
---
 arch/powerpc/include/asm/hvcall.h      |  3 +++
 arch/powerpc/include/asm/reg.h         |  7 +++++++
 arch/powerpc/platforms/pseries/setup.c | 37 ++++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 9711145..af25661 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -260,6 +260,9 @@
 #define H_SET_MODE		0x31C
 #define MAX_HCALL_OPCODE	H_SET_MODE
 
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_DAWR	2
+
 #ifndef __ASSEMBLY__
 
 /**
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c0eda55..5feaf74 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -198,6 +198,13 @@
 #define   CTRL_TE	0x00c00000	/* thread enable */
 #define   CTRL_RUNLATCH	0x1
 #define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
+#define   DAWRX_USER    __MASK(0)
+#define   DAWRX_KERNEL  __MASK(1)
+#define   DAWRX_HYP     __MASK(2)
+#define   DAWRX_WTI     __MASK(3)
+#define   DAWRX_WT      __MASK(4)
+#define   DAWRX_DR      __MASK(5)
+#define   DAWRX_DW      __MASK(6)
 #define   DABR_TRANSLATION	(1UL << 2)
 #define   DABR_DATA_WRITE	(1UL << 1)
 #define   DABR_DATA_READ	(1UL << 0)
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index f5d6b6d..1b288d6 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -418,13 +418,50 @@ static int __init pSeries_init_panel(void)
 }
 machine_arch_initcall(pseries, pSeries_init_panel);
 
+/*
+ * pseries_set_dawr
+ *
+ * POWER8 systems do not have the DABR or DABRX registers
+ * but instead they have DAWR and DAWRX registers. This
+ * function emulates H_SET_DABR or H_SET_XDABR hcall access
+ * through the new hcall H_SET_MODE.
+ */
+static int pseries_set_dawr(unsigned long dabr)
+{
+	unsigned long dawr = dabr, dawrx = 0;
+
+	/* DAWR privillege bits */
+	dawrx |= DAWRX_KERNEL;
+	dawrx |= DAWRX_USER;
+
+	/* DAWR read, write and translation bits */
+	if (dabr & DABR_DATA_READ)
+		dawrx |= DAWRX_DR;
+
+	if (dabr & DABR_DATA_WRITE)
+		dawrx |= DAWRX_DW;
+
+	if (dabr & DABR_TRANSLATION)
+		dawrx |= DAWRX_WT;
+	else
+		dawrx |= DAWRX_WTI;
+	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR, dawr, dawrx);
+}
+
 static int pseries_set_dabr(unsigned long dabr)
 {
+	if (firmware_has_feature(FW_FEATURE_SET_MODE) &&
+				!strcmp(cur_cpu_spec->platform, "power8"))
+		return pseries_set_dawr(dabr);
 	return plpar_hcall_norets(H_SET_DABR, dabr);
 }
 
 static int pseries_set_xdabr(unsigned long dabr)
 {
+	if (firmware_has_feature(FW_FEATURE_SET_MODE) &&
+				!strcmp(cur_cpu_spec->platform, "power8"))
+		return pseries_set_dawr(dabr);
+
 	/* We want to catch accesses from kernel and userspace */
 	return plpar_hcall_norets(H_SET_XDABR, dabr,
 			H_DABRX_KERNEL | H_DABRX_USER);
-- 
1.9.3

