hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/arch/powerpc/platforms/powernv/rng.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright 2013, Michael Ellerman, IBM Corporation.
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of the GNU General Public License
6
- * as published by the Free Software Foundation; either version
7
- * 2 of the License, or (at your option) any later version.
84 */
95
106 #define pr_fmt(fmt) "powernv-rng: " fmt
....@@ -21,6 +17,7 @@
2117 #include <asm/prom.h>
2218 #include <asm/machdep.h>
2319 #include <asm/smp.h>
20
+#include "powernv.h"
2421
2522 #define DARN_ERR 0xFFFFFFFFFFFFFFFFul
2623
....@@ -31,7 +28,6 @@
3128 };
3229
3330 static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
34
-
3531
3632 int powernv_hwrng_present(void)
3733 {
....@@ -47,7 +43,11 @@
4743 unsigned long parity;
4844
4945 /* Calculate the parity of the value */
50
- asm ("popcntd %0,%1" : "=r" (parity) : "r" (val));
46
+ asm (".machine push; \
47
+ .machine power7; \
48
+ popcntd %0,%1; \
49
+ .machine pop;"
50
+ : "=r" (parity) : "r" (val));
5151
5252 /* xor our value with the previous mask */
5353 val ^= rng->mask;
....@@ -63,13 +63,15 @@
6363 struct powernv_rng *rng;
6464
6565 rng = raw_cpu_read(powernv_rng);
66
+ if (!rng)
67
+ return 0;
6668
6769 *v = rng_whiten(rng, __raw_rm_readq(rng->regs_real));
6870
6971 return 1;
7072 }
7173
72
-int powernv_get_random_darn(unsigned long *v)
74
+static int powernv_get_random_darn(unsigned long *v)
7375 {
7476 unsigned long val;
7577
....@@ -98,9 +100,6 @@
98100 return 0;
99101 }
100102 }
101
-
102
- pr_warn("Unable to use DARN for get_random_seed()\n");
103
-
104103 return -EIO;
105104 }
106105
....@@ -163,32 +162,59 @@
163162
164163 rng_init_per_cpu(rng, dn);
165164
166
- pr_info_once("Registering arch random hook.\n");
167
-
168165 ppc_md.get_random_seed = powernv_get_random_long;
169166
170167 return 0;
171168 }
172169
173
-static __init int rng_init(void)
170
+static int __init pnv_get_random_long_early(unsigned long *v)
174171 {
175172 struct device_node *dn;
176
- int rc;
177173
178
- for_each_compatible_node(dn, NULL, "ibm,power-rng") {
179
- rc = rng_create(dn);
180
- if (rc) {
181
- pr_err("Failed creating rng for %pOF (%d).\n",
182
- dn, rc);
183
- continue;
184
- }
174
+ if (!slab_is_available())
175
+ return 0;
185176
186
- /* Create devices for hwrng driver */
187
- of_platform_device_create(dn, NULL, NULL);
177
+ if (cmpxchg(&ppc_md.get_random_seed, pnv_get_random_long_early,
178
+ NULL) != pnv_get_random_long_early)
179
+ return 0;
180
+
181
+ for_each_compatible_node(dn, NULL, "ibm,power-rng")
182
+ rng_create(dn);
183
+
184
+ if (!ppc_md.get_random_seed)
185
+ return 0;
186
+ return ppc_md.get_random_seed(v);
187
+}
188
+
189
+void __init pnv_rng_init(void)
190
+{
191
+ struct device_node *dn;
192
+
193
+ /* Prefer darn over the rest. */
194
+ if (!initialise_darn())
195
+ return;
196
+
197
+ dn = of_find_compatible_node(NULL, NULL, "ibm,power-rng");
198
+ if (dn)
199
+ ppc_md.get_random_seed = pnv_get_random_long_early;
200
+
201
+ of_node_put(dn);
202
+}
203
+
204
+static int __init pnv_rng_late_init(void)
205
+{
206
+ struct device_node *dn;
207
+ unsigned long v;
208
+
209
+ /* In case it wasn't called during init for some other reason. */
210
+ if (ppc_md.get_random_seed == pnv_get_random_long_early)
211
+ pnv_get_random_long_early(&v);
212
+
213
+ if (ppc_md.get_random_seed == powernv_get_random_long) {
214
+ for_each_compatible_node(dn, NULL, "ibm,power-rng")
215
+ of_platform_device_create(dn, NULL, NULL);
188216 }
189
-
190
- initialise_darn();
191217
192218 return 0;
193219 }
194
-machine_subsys_initcall(powernv, rng_init);
220
+machine_subsys_initcall(powernv, pnv_rng_late_init);