Michal Suchanek b9207c
From e66ca3db5917f4bcad039d3a3df9f1003797c249 Mon Sep 17 00:00:00 2001
Michal Suchanek b9207c
From: Matt Brown <matthew.brown.dev@gmail.com>
Michal Suchanek b9207c
Date: Fri, 4 Aug 2017 11:12:18 +1000
Michal Suchanek b9207c
Subject: [PATCH] powerpc/powernv: Use darn instruction for get_random_seed()
Michal Suchanek b9207c
 on Power9
Michal Suchanek b9207c
Michal Suchanek b9207c
References: bsc#1065729
Michal Suchanek b9207c
Patch-mainline: v4.14-rc1
Michal Suchanek b9207c
Git-commit: e66ca3db5917f4bcad039d3a3df9f1003797c249
Michal Suchanek b9207c
Michal Suchanek b9207c
This adds powernv_get_random_darn() which utilises the darn instruction,
Michal Suchanek b9207c
introduced in ISA v3.0/POWER9.
Michal Suchanek b9207c
Michal Suchanek b9207c
The darn instruction can potentially return an error, which is supported
Michal Suchanek b9207c
by the get_random_seed() API, in normal usage if we see an error we just
Michal Suchanek b9207c
return that to the caller.
Michal Suchanek b9207c
Michal Suchanek b9207c
However when detecting whether darn is functional at boot we try up to
Michal Suchanek b9207c
10 times, before deciding that darn doesn't work and failing the
Michal Suchanek b9207c
registration of get_random_seed(). That way an intermittent failure
Michal Suchanek b9207c
at boot doesn't deprive the system of randomness until the next reboot.
Michal Suchanek b9207c
Michal Suchanek b9207c
Signed-off-by: Matt Brown <matthew.brown.dev@gmail.com>
Michal Suchanek b9207c
[mpe: Move init into a function, tweak change log]
Michal Suchanek b9207c
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Michal Suchanek b9207c
Acked-by: Michal Suchanek <msuchanek@suse.de>
Michal Suchanek b9207c
---
Michal Suchanek b9207c
 arch/powerpc/include/asm/ppc-opcode.h |  4 +++
Michal Suchanek b9207c
 arch/powerpc/platforms/powernv/rng.c  | 39 +++++++++++++++++++++++++++
Michal Suchanek b9207c
 2 files changed, 43 insertions(+)
Michal Suchanek b9207c
Michal Suchanek b9207c
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
Michal Suchanek b9207c
index fa9ebaead91e..041ba15aa2b9 100644
Michal Suchanek b9207c
--- a/arch/powerpc/include/asm/ppc-opcode.h
Michal Suchanek b9207c
+++ b/arch/powerpc/include/asm/ppc-opcode.h
Michal Suchanek b9207c
@@ -193,6 +193,7 @@
Michal Suchanek b9207c
 #define PPC_INST_CLRBHRB		0x7c00035c
Michal Suchanek b9207c
 #define PPC_INST_COPY			0x7c20060c
Michal Suchanek b9207c
 #define PPC_INST_CP_ABORT		0x7c00068c
Michal Suchanek b9207c
+#define PPC_INST_DARN			0x7c0005e6
Michal Suchanek b9207c
 #define PPC_INST_DCBA			0x7c0005ec
Michal Suchanek b9207c
 #define PPC_INST_DCBA_MASK		0xfc0007fe
Michal Suchanek b9207c
 #define PPC_INST_DCBAL			0x7c2005ec
Michal Suchanek b9207c
@@ -395,6 +396,9 @@
Michal Suchanek b9207c
 #define	PPC_CP_ABORT		stringify_in_c(.long PPC_INST_CP_ABORT)
Michal Suchanek b9207c
 #define	PPC_COPY(a, b)		stringify_in_c(.long PPC_INST_COPY | \
Michal Suchanek b9207c
 					___PPC_RA(a) | ___PPC_RB(b))
Michal Suchanek b9207c
+#define PPC_DARN(t, l)		stringify_in_c(.long PPC_INST_DARN |  \
Michal Suchanek b9207c
+						___PPC_RT(t)	   |  \
Michal Suchanek b9207c
+						(((l) & 0x3) << 16))
Michal Suchanek b9207c
 #define	PPC_DCBAL(a, b)		stringify_in_c(.long PPC_INST_DCBAL | \
Michal Suchanek b9207c
 					__PPC_RA(a) | __PPC_RB(b))
Michal Suchanek b9207c
 #define	PPC_DCBZL(a, b)		stringify_in_c(.long PPC_INST_DCBZL | \
Michal Suchanek b9207c
diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c
Michal Suchanek b9207c
index 1a9d84371a4d..c5ce3a8bd4c9 100644
Michal Suchanek b9207c
--- a/arch/powerpc/platforms/powernv/rng.c
Michal Suchanek b9207c
+++ b/arch/powerpc/platforms/powernv/rng.c
Michal Suchanek b9207c
@@ -16,11 +16,13 @@
Michal Suchanek b9207c
 #include <linux/slab.h>
Michal Suchanek b9207c
 #include <linux/smp.h>
Michal Suchanek b9207c
 #include <asm/archrandom.h>
Michal Suchanek b9207c
+#include <asm/cputable.h>
Michal Suchanek b9207c
 #include <asm/io.h>
Michal Suchanek b9207c
 #include <asm/prom.h>
Michal Suchanek b9207c
 #include <asm/machdep.h>
Michal Suchanek b9207c
 #include <asm/smp.h>
Michal Suchanek b9207c
 
Michal Suchanek b9207c
+#define DARN_ERR 0xFFFFFFFFFFFFFFFFul
Michal Suchanek b9207c
 
Michal Suchanek b9207c
 struct powernv_rng {
Michal Suchanek b9207c
 	void __iomem *regs;
Michal Suchanek b9207c
@@ -67,6 +69,41 @@ int powernv_get_random_real_mode(unsigned long *v)
Michal Suchanek b9207c
 	return 1;
Michal Suchanek b9207c
 }
Michal Suchanek b9207c
 
Michal Suchanek b9207c
+int powernv_get_random_darn(unsigned long *v)
Michal Suchanek b9207c
+{
Michal Suchanek b9207c
+	unsigned long val;
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	/* Using DARN with L=1 - 64-bit conditioned random number */
Michal Suchanek b9207c
+	asm volatile(PPC_DARN(%0, 1) : "=r"(val));
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	if (val == DARN_ERR)
Michal Suchanek b9207c
+		return 0;
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	*v = val;
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	return 1;
Michal Suchanek b9207c
+}
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+static int initialise_darn(void)
Michal Suchanek b9207c
+{
Michal Suchanek b9207c
+	unsigned long val;
Michal Suchanek b9207c
+	int i;
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	if (!cpu_has_feature(CPU_FTR_ARCH_300))
Michal Suchanek b9207c
+		return -ENODEV;
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	for (i = 0; i < 10; i++) {
Michal Suchanek b9207c
+		if (powernv_get_random_darn(&val)) {
Michal Suchanek b9207c
+			ppc_md.get_random_seed = powernv_get_random_darn;
Michal Suchanek b9207c
+			return 0;
Michal Suchanek b9207c
+		}
Michal Suchanek b9207c
+	}
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	pr_warn("Unable to use DARN for get_random_seed()\n");
Michal Suchanek b9207c
+
Michal Suchanek b9207c
+	return -EIO;
Michal Suchanek b9207c
+}
Michal Suchanek b9207c
+
Michal Suchanek b9207c
 int powernv_get_random_long(unsigned long *v)
Michal Suchanek b9207c
 {
Michal Suchanek b9207c
 	struct powernv_rng *rng;
Michal Suchanek b9207c
@@ -150,6 +187,8 @@ static __init int rng_init(void)
Michal Suchanek b9207c
 		of_platform_device_create(dn, NULL, NULL);
Michal Suchanek b9207c
 	}
Michal Suchanek b9207c
 
Michal Suchanek b9207c
+	initialise_darn();
Michal Suchanek b9207c
+
Michal Suchanek b9207c
 	return 0;
Michal Suchanek b9207c
 }
Michal Suchanek b9207c
 machine_subsys_initcall(powernv, rng_init);
Michal Suchanek b9207c
-- 
Michal Suchanek b9207c
2.35.3
Michal Suchanek b9207c