diff mbox series

[v5] powerpc/powernv: wire up rng during setup_arch

Message ID 20220621140849.127227-1-Jason@zx2c4.com (mailing list archive)
State Accepted
Headers show
Series [v5] powerpc/powernv: wire up rng during setup_arch | expand

Checks

Context Check Description
snowpatch_ozlabs/github-powerpc_selftests success Successfully ran 10 jobs.
snowpatch_ozlabs/github-powerpc_ppctests success Successfully ran 10 jobs.

Commit Message

Jason A. Donenfeld June 21, 2022, 2:08 p.m. UTC
The platform's RNG must be available before random_init() in order to be
useful for initial seeding, which in turn means that it needs to be
called from setup_arch(), rather than from an init call. Fortunately,
each platform already has a setup_arch function pointer, which means we
can wire it up that way. Complicating things, however, is that POWER8
systems need some per-cpu state and kmalloc, which isn't available at
this stage. So we split things up into an early phase and a later
opportunistic phase. This commit also removes some noisy log messages
that don't add much.

Cc: stable@vger.kernel.org
Cc: Michael Ellerman <mpe@ellerman.id.au>
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Fixes: a4da0d50b2a0 ("powerpc: Implement arch_get_random_long/int() for powernv")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 arch/powerpc/platforms/powernv/powernv.h |  2 +
 arch/powerpc/platforms/powernv/rng.c     | 47 ++++++++++++++++--------
 arch/powerpc/platforms/powernv/setup.c   |  2 +
 3 files changed, 35 insertions(+), 16 deletions(-)

Comments

Christophe Leroy June 21, 2022, 6:33 p.m. UTC | #1
Le 21/06/2022 à 16:08, Jason A. Donenfeld a écrit :
> The platform's RNG must be available before random_init() in order to be
> useful for initial seeding, which in turn means that it needs to be
> called from setup_arch(), rather than from an init call. Fortunately,
> each platform already has a setup_arch function pointer, which means we
> can wire it up that way. Complicating things, however, is that POWER8
> systems need some per-cpu state and kmalloc, which isn't available at
> this stage. So we split things up into an early phase and a later
> opportunistic phase. This commit also removes some noisy log messages
> that don't add much.

Regarding the kmalloc(), I have not looked at it in details, but usually 
you can use memblock_alloc() when kmalloc is not available yet.

Christophe
Jason A. Donenfeld June 21, 2022, 6:47 p.m. UTC | #2
Hi Christophe,

On Tue, Jun 21, 2022 at 06:33:11PM +0000, Christophe Leroy wrote:
> Le 21/06/2022 à 16:08, Jason A. Donenfeld a écrit :
> > The platform's RNG must be available before random_init() in order to be
> > useful for initial seeding, which in turn means that it needs to be
> > called from setup_arch(), rather than from an init call. Fortunately,
> > each platform already has a setup_arch function pointer, which means we
> > can wire it up that way. Complicating things, however, is that POWER8
> > systems need some per-cpu state and kmalloc, which isn't available at
> > this stage. So we split things up into an early phase and a later
> > opportunistic phase. This commit also removes some noisy log messages
> > that don't add much.
> 
> Regarding the kmalloc(), I have not looked at it in details, but usually 
> you can use memblock_alloc() when kmalloc is not available yet.

That seems a bit excessive, especially as those allocations are long
lived. And we don't even *need* it that early, but just before
random_init(). Michael is running this v5 on the test rig overnight, so
we'll learn in the Australian morning whether this finally did the trick
(I hope).

Jason
Christophe Leroy June 21, 2022, 7:22 p.m. UTC | #3
Le 21/06/2022 à 20:47, Jason A. Donenfeld a écrit :
> Hi Christophe,
> 
> On Tue, Jun 21, 2022 at 06:33:11PM +0000, Christophe Leroy wrote:
>> Le 21/06/2022 à 16:08, Jason A. Donenfeld a écrit :
>>> The platform's RNG must be available before random_init() in order to be
>>> useful for initial seeding, which in turn means that it needs to be
>>> called from setup_arch(), rather than from an init call. Fortunately,
>>> each platform already has a setup_arch function pointer, which means we
>>> can wire it up that way. Complicating things, however, is that POWER8
>>> systems need some per-cpu state and kmalloc, which isn't available at
>>> this stage. So we split things up into an early phase and a later
>>> opportunistic phase. This commit also removes some noisy log messages
>>> that don't add much.
>>
>> Regarding the kmalloc(), I have not looked at it in details, but usually
>> you can use memblock_alloc() when kmalloc is not available yet.
> 
> That seems a bit excessive, especially as those allocations are long
> lived. And we don't even *need* it that early, but just before
> random_init(). Michael is running this v5 on the test rig overnight, so
> we'll learn in the Australian morning whether this finally did the trick
> (I hope).
> 

The fact that they are long lived make them a good candidate for 
memblock_alloc().

But fair enough, if they are not required that early then just do it later.

Christophe
Michael Ellerman June 22, 2022, 2:27 a.m. UTC | #4
Christophe Leroy <christophe.leroy@csgroup.eu> writes:
> Le 21/06/2022 à 20:47, Jason A. Donenfeld a écrit :
>> On Tue, Jun 21, 2022 at 06:33:11PM +0000, Christophe Leroy wrote:
>>> Le 21/06/2022 à 16:08, Jason A. Donenfeld a écrit :
>>>> The platform's RNG must be available before random_init() in order to be
>>>> useful for initial seeding, which in turn means that it needs to be
>>>> called from setup_arch(), rather than from an init call. Fortunately,
>>>> each platform already has a setup_arch function pointer, which means we
>>>> can wire it up that way. Complicating things, however, is that POWER8
>>>> systems need some per-cpu state and kmalloc, which isn't available at
>>>> this stage. So we split things up into an early phase and a later
>>>> opportunistic phase. This commit also removes some noisy log messages
>>>> that don't add much.
>>>
>>> Regarding the kmalloc(), I have not looked at it in details, but usually
>>> you can use memblock_alloc() when kmalloc is not available yet.
>> 
>> That seems a bit excessive, especially as those allocations are long
>> lived. And we don't even *need* it that early, but just before
>> random_init(). Michael is running this v5 on the test rig overnight, so
>> we'll learn in the Australian morning whether this finally did the trick
>> (I hope).
>
> The fact that they are long lived make them a good candidate for 
> memblock_alloc().
>
> But fair enough, if they are not required that early then just do it later.

memblock works but then we trip on ioremap vs early_ioremap.

Fixing that is a bit of a pain as we'd have to stop using of_iomap() and
we'd also need to switch the mappings to ioremap() later in boot.

We'd also have to defer the percpu initialisation.

So it's all just a bit of a pain when we actually only need to get the
hook ready before random_init() which is called much later in boot when
slab/ioremap/percpu are all ready.

cheers
Michael Ellerman June 26, 2022, 12:28 a.m. UTC | #5
On Tue, 21 Jun 2022 16:08:49 +0200, Jason A. Donenfeld wrote:
> The platform's RNG must be available before random_init() in order to be
> useful for initial seeding, which in turn means that it needs to be
> called from setup_arch(), rather than from an init call. Fortunately,
> each platform already has a setup_arch function pointer, which means we
> can wire it up that way. Complicating things, however, is that POWER8
> systems need some per-cpu state and kmalloc, which isn't available at
> this stage. So we split things up into an early phase and a later
> opportunistic phase. This commit also removes some noisy log messages
> that don't add much.
> 
> [...]

Applied to powerpc/fixes.

[1/1] powerpc/powernv: wire up rng during setup_arch
      https://git.kernel.org/powerpc/c/f3eac426657d985b97c92fa5f7ae1d43f04721f3

cheers
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index e297bf4abfcb..fd3f5e1eb10b 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -42,4 +42,6 @@  ssize_t memcons_copy(struct memcons *mc, char *to, loff_t pos, size_t count);
 u32 __init memcons_get_size(struct memcons *mc);
 struct memcons *__init memcons_init(struct device_node *node, const char *mc_prop_name);
 
+void powernv_rng_init(void);
+
 #endif /* _POWERNV_H */
diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c
index e3d44b36ae98..e332e72e1857 100644
--- a/arch/powerpc/platforms/powernv/rng.c
+++ b/arch/powerpc/platforms/powernv/rng.c
@@ -17,6 +17,7 @@ 
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/smp.h>
+#include "powernv.h"
 
 #define DARN_ERR 0xFFFFFFFFFFFFFFFFul
 
@@ -28,7 +29,6 @@  struct powernv_rng {
 
 static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 
-
 int powernv_hwrng_present(void)
 {
 	struct powernv_rng *rng;
@@ -98,9 +98,6 @@  static int __init initialise_darn(void)
 			return 0;
 		}
 	}
-
-	pr_warn("Unable to use DARN for get_random_seed()\n");
-
 	return -EIO;
 }
 
@@ -163,32 +160,50 @@  static __init int rng_create(struct device_node *dn)
 
 	rng_init_per_cpu(rng, dn);
 
-	pr_info_once("Registering arch random hook.\n");
-
 	ppc_md.get_random_seed = powernv_get_random_long;
 
 	return 0;
 }
 
-static __init int rng_init(void)
+static int __init powernv_get_random_long_early(unsigned long *v)
 {
 	struct device_node *dn;
-	int rc;
+
+	if (!slab_is_available())
+		return 0;
+
+	if (cmpxchg(&ppc_md.get_random_seed, powernv_get_random_long_early,
+		    NULL) != powernv_get_random_long_early)
+		return 0;
 
 	for_each_compatible_node(dn, NULL, "ibm,power-rng") {
-		rc = rng_create(dn);
-		if (rc) {
-			pr_err("Failed creating rng for %pOF (%d).\n",
-				dn, rc);
+		if (rng_create(dn))
 			continue;
-		}
-
 		/* Create devices for hwrng driver */
 		of_platform_device_create(dn, NULL, NULL);
 	}
 
-	initialise_darn();
+	if (!ppc_md.get_random_seed)
+		return 0;
+	return ppc_md.get_random_seed(v);
+}
+
+void __init powernv_rng_init(void)
+{
+	/* Prefer darn over the rest. */
+	if (!initialise_darn())
+		return;
+
+	if (of_find_compatible_node(NULL, NULL, "ibm,power-rng"))
+		ppc_md.get_random_seed = powernv_get_random_long_early;
+}
 
+static int __init powernv_rng_late_init(void)
+{
+	unsigned long v;
+	/* In case it wasn't called during init for some other reason. */
+	if (ppc_md.get_random_seed == powernv_get_random_long_early)
+		powernv_get_random_long_early(&v);
 	return 0;
 }
-machine_subsys_initcall(powernv, rng_init);
+machine_subsys_initcall(powernv, powernv_rng_late_init);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 824c3ad7a0fa..a5fcb6796b22 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -203,6 +203,8 @@  static void __init pnv_setup_arch(void)
 	pnv_check_guarded_cores();
 
 	/* XXX PMCS */
+
+	powernv_rng_init();
 }
 
 static void __init pnv_init(void)