@@ -21,6 +21,29 @@
#include <io.h>
#include <cpu.h>
#include <nx.h>
+#include <chip.h>
+#include <phys-map.h>
+#include <xscom-p9-regs.h>
+
+/*
+ * On P9 the DARN instruction is used to access the HW RNG. There is still
+ * an NX RNG BAR, but it is used to configure which NX a core will source
+ * random numbers from rather than being a MMIO window.
+ */
+static void nx_init_p9_rng(uint32_t chip_id)
+{
+ uint64_t bar, tmp;
+
+ if (chip_quirk(QUIRK_NO_RNG))
+ return;
+
+ phys_map_get(chip_id, NX_RNG, 0, &bar, NULL);
+ xscom_write(chip_id, P9X_NX_MMIO_BAR, bar | P9X_NX_MMIO_BAR_EN);
+
+ /* Read config register for pace info */
+ xscom_read(chip_id, P9X_NX_RNG_CFG, &tmp);
+ prlog(PR_INFO, "NX RNG[%x] pace:%lli\n", chip_id, 0xffff & (tmp >> 2));
+}
void nx_create_rng_node(struct dt_node *node)
{
@@ -44,8 +67,7 @@ void nx_create_rng_node(struct dt_node *node)
xcfg = pb_base + NX_P8_RNG_CFG;
addr_mask = NX_P8_RNG_BAR_ADDR;
} else if (dt_node_is_compatible(node, "ibm,power9-nx")) {
- prlog(PR_INFO, "NX%d: POWER9 nx-rng not yet supported\n",
- gcid);
+ nx_init_p9_rng(gcid);
return;
} else {
prerror("NX%d: Unknown NX type!\n", gcid);
@@ -25,40 +25,36 @@
#include <xscom-p9-regs.h>
#include <phys-map.h>
-extern void nx_p9_rng_init(void);
-
-void nx_p9_rng_init(void)
+static void p9_darn_init(void)
{
+ struct dt_node *nx;
struct proc_chip *chip;
struct cpu_thread *c;
- uint64_t bar, tmp;
+ uint64_t bar, default_bar;
- if (proc_gen != proc_gen_p9)
- return;
if (chip_quirk(QUIRK_NO_RNG))
return;
/*
- * Two things we need to setup here:
- *
- * 1) The per chip BAR for the NX RNG region. The location of
- * this is determined by the global MMIO Map.
-
- * 2) The per core BAR for the DARN BAR, which points to the
- * per chip RNG region set in 1.
- *
+ * To allow the DARN instruction to function there must be at least
+ * one NX available in the system. Otherwise using DARN will result
+ * in a checkstop. I suppose we could mask the FIR...
*/
+ dt_for_each_compatible(dt_root, nx, "ibm,power9-nx")
+ break;
+ if (!nx) {
+ assert(nx);
+ return;
+ }
+
+ phys_map_get(dt_get_chip_id(nx), NX_RNG, 0, &default_bar, NULL);
+
for_each_chip(chip) {
- /* 1) NX RNG BAR */
- phys_map_get(chip->id, NX_RNG, 0, &bar, NULL);
- xscom_write(chip->id, P9X_NX_MMIO_BAR,
- bar | P9X_NX_MMIO_BAR_EN);
- /* Read config register for pace info */
- xscom_read(chip->id, P9X_NX_RNG_CFG, &tmp);
- prlog(PR_INFO, "NX RNG[%x] pace:%lli\n", chip->id,
- 0xffff & (tmp >> 2));
+ /* is this NX enabled? */
+ xscom_read(chip->id, P9X_NX_MMIO_BAR, &bar);
+ if (!(bar & ~P9X_NX_MMIO_BAR_EN))
+ bar = default_bar;
- /* 2) DARN BAR */
for_each_available_core_in_chip(c, chip->id) {
uint64_t addr;
addr = XSCOM_ADDR_P9_EX(pir_to_core_id(c->pir),
@@ -80,8 +76,6 @@ void nx_init(void)
{
struct dt_node *node;
- nx_p9_rng_init();
-
dt_for_each_compatible(dt_root, node, "ibm,power-nx") {
nx_init_one(node);
}
@@ -89,4 +83,7 @@ void nx_init(void)
dt_for_each_compatible(dt_root, node, "ibm,power9-nx") {
nx_init_one(node);
}
+
+ if (proc_gen == proc_gen_p9)
+ p9_darn_init();
}
The NX rng BAR is used by each core to source random numbers for the DARN instruction. Currently we configure each core to use the NX rng of the chip that it exists on. Unfortunately, the NX can be deconfigured by hostboot and in this case we need to use the NX of a different chip. This patch moves the BAR assignments for the NX into the normal nx-rng init path. This lets us check if the normal (chip local) NX is active when configuring which NX a core should use so that we can fallback gracefully. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> --- hw/nx-rng.c | 26 ++++++++++++++++++++++++-- hw/nx.c | 47 ++++++++++++++++++++++------------------------- 2 files changed, 46 insertions(+), 27 deletions(-)