Commit e66ca3db authored by Matt Brown's avatar Matt Brown Committed by Michael Ellerman

powerpc/powernv: Use darn instruction for get_random_seed() on Power9

This adds powernv_get_random_darn() which utilises the darn instruction,
introduced in ISA v3.0/POWER9.

The darn instruction can potentially return an error, which is supported
by the get_random_seed() API, in normal usage if we see an error we just
return that to the caller.

However when detecting whether darn is functional at boot we try up to
10 times, before deciding that darn doesn't work and failing the
registration of get_random_seed(). That way an intermittent failure
at boot doesn't deprive the system of randomness until the next reboot.
Signed-off-by: default avatarMatt Brown <matthew.brown.dev@gmail.com>
[mpe: Move init into a function, tweak change log]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 64d0a506
...@@ -193,6 +193,7 @@ ...@@ -193,6 +193,7 @@
#define PPC_INST_CLRBHRB 0x7c00035c #define PPC_INST_CLRBHRB 0x7c00035c
#define PPC_INST_COPY 0x7c20060c #define PPC_INST_COPY 0x7c20060c
#define PPC_INST_CP_ABORT 0x7c00068c #define PPC_INST_CP_ABORT 0x7c00068c
#define PPC_INST_DARN 0x7c0005e6
#define PPC_INST_DCBA 0x7c0005ec #define PPC_INST_DCBA 0x7c0005ec
#define PPC_INST_DCBA_MASK 0xfc0007fe #define PPC_INST_DCBA_MASK 0xfc0007fe
#define PPC_INST_DCBAL 0x7c2005ec #define PPC_INST_DCBAL 0x7c2005ec
...@@ -395,6 +396,9 @@ ...@@ -395,6 +396,9 @@
#define PPC_CP_ABORT stringify_in_c(.long PPC_INST_CP_ABORT) #define PPC_CP_ABORT stringify_in_c(.long PPC_INST_CP_ABORT)
#define PPC_COPY(a, b) stringify_in_c(.long PPC_INST_COPY | \ #define PPC_COPY(a, b) stringify_in_c(.long PPC_INST_COPY | \
___PPC_RA(a) | ___PPC_RB(b)) ___PPC_RA(a) | ___PPC_RB(b))
#define PPC_DARN(t, l) stringify_in_c(.long PPC_INST_DARN | \
___PPC_RT(t) | \
(((l) & 0x3) << 16))
#define PPC_DCBAL(a, b) stringify_in_c(.long PPC_INST_DCBAL | \ #define PPC_DCBAL(a, b) stringify_in_c(.long PPC_INST_DCBAL | \
__PPC_RA(a) | __PPC_RB(b)) __PPC_RA(a) | __PPC_RB(b))
#define PPC_DCBZL(a, b) stringify_in_c(.long PPC_INST_DCBZL | \ #define PPC_DCBZL(a, b) stringify_in_c(.long PPC_INST_DCBZL | \
......
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <asm/archrandom.h> #include <asm/archrandom.h>
#include <asm/cputable.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/smp.h> #include <asm/smp.h>
#define DARN_ERR 0xFFFFFFFFFFFFFFFFul
struct powernv_rng { struct powernv_rng {
void __iomem *regs; void __iomem *regs;
...@@ -67,6 +69,41 @@ int powernv_get_random_real_mode(unsigned long *v) ...@@ -67,6 +69,41 @@ int powernv_get_random_real_mode(unsigned long *v)
return 1; return 1;
} }
int powernv_get_random_darn(unsigned long *v)
{
unsigned long val;
/* Using DARN with L=1 - 64-bit conditioned random number */
asm volatile(PPC_DARN(%0, 1) : "=r"(val));
if (val == DARN_ERR)
return 0;
*v = val;
return 1;
}
static int initialise_darn(void)
{
unsigned long val;
int i;
if (!cpu_has_feature(CPU_FTR_ARCH_300))
return -ENODEV;
for (i = 0; i < 10; i++) {
if (powernv_get_random_darn(&val)) {
ppc_md.get_random_seed = powernv_get_random_darn;
return 0;
}
}
pr_warn("Unable to use DARN for get_random_seed()\n");
return -EIO;
}
int powernv_get_random_long(unsigned long *v) int powernv_get_random_long(unsigned long *v)
{ {
struct powernv_rng *rng; struct powernv_rng *rng;
...@@ -150,6 +187,8 @@ static __init int rng_init(void) ...@@ -150,6 +187,8 @@ static __init int rng_init(void)
of_platform_device_create(dn, NULL, NULL); of_platform_device_create(dn, NULL, NULL);
} }
initialise_darn();
return 0; return 0;
} }
machine_subsys_initcall(powernv, rng_init); machine_subsys_initcall(powernv, rng_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment