aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/core/nvram.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/core/nvram.c')
-rw-r--r--roms/skiboot/core/nvram.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/roms/skiboot/core/nvram.c b/roms/skiboot/core/nvram.c
new file mode 100644
index 000000000..773d20280
--- /dev/null
+++ b/roms/skiboot/core/nvram.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * NVRAM support
+ *
+ * Copyright 2013-2018 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <fsp.h>
+#include <opal.h>
+#include <lock.h>
+#include <device.h>
+#include <platform.h>
+#include <nvram.h>
+#include <timebase.h>
+
+static void *nvram_image;
+static uint32_t nvram_size;
+
+static bool nvram_ready; /* has the nvram been loaded? */
+static bool nvram_valid; /* is the nvram format ok? */
+
+static int64_t opal_read_nvram(uint64_t buffer, uint64_t size, uint64_t offset)
+{
+ if (!nvram_ready)
+ return OPAL_HARDWARE;
+
+ if (!opal_addr_valid((void *)buffer))
+ return OPAL_PARAMETER;
+
+ if (offset >= nvram_size || (offset + size) > nvram_size)
+ return OPAL_PARAMETER;
+
+ memcpy((void *)buffer, nvram_image + offset, size);
+ return OPAL_SUCCESS;
+}
+opal_call(OPAL_READ_NVRAM, opal_read_nvram, 3);
+
+static int64_t opal_write_nvram(uint64_t buffer, uint64_t size, uint64_t offset)
+{
+ if (!nvram_ready)
+ return OPAL_HARDWARE;
+
+ if (!opal_addr_valid((void *)buffer))
+ return OPAL_PARAMETER;
+
+ if (offset >= nvram_size || (offset + size) > nvram_size)
+ return OPAL_PARAMETER;
+ memcpy(nvram_image + offset, (void *)buffer, size);
+ if (platform.nvram_write)
+ platform.nvram_write(offset, nvram_image + offset, size);
+
+ /* The host OS has written to the NVRAM so we can't be sure that it's
+ * well formatted.
+ */
+ nvram_valid = false;
+
+ return OPAL_SUCCESS;
+}
+opal_call(OPAL_WRITE_NVRAM, opal_write_nvram, 3);
+
+bool nvram_validate(void)
+{
+ if (!nvram_valid) {
+ if (!nvram_check(nvram_image, nvram_size))
+ nvram_valid = true;
+ }
+
+ return nvram_valid;
+}
+
+static void nvram_reformat(void)
+{
+ if (nvram_format(nvram_image, nvram_size)) {
+ prerror("NVRAM: Failed to format NVRAM!\n");
+ nvram_valid = false;
+ return;
+ }
+
+ /* Write the whole thing back */
+ if (platform.nvram_write)
+ platform.nvram_write(0, nvram_image, nvram_size);
+
+ nvram_validate();
+}
+
+void nvram_reinit(void)
+{
+ /* It's possible we failed to load nvram at boot. */
+ if (!nvram_ready)
+ nvram_init();
+ else if (!nvram_validate())
+ nvram_reformat();
+}
+
+void nvram_read_complete(bool success)
+{
+ struct dt_node *np;
+
+ /* Read not successful, error out and free the buffer */
+ if (!success) {
+ free(nvram_image);
+ nvram_size = 0;
+ return;
+ }
+
+ if (!nvram_validate())
+ nvram_reformat();
+
+ /* Add nvram node */
+ np = dt_new(opal_node, "nvram");
+ dt_add_property_cells(np, "#bytes", nvram_size);
+ dt_add_property_string(np, "compatible", "ibm,opal-nvram");
+
+ /* Mark ready */
+ nvram_ready = true;
+}
+
+bool nvram_wait_for_load(void)
+{
+ uint64_t started;
+
+ /* Short cut */
+ if (nvram_ready)
+ return true;
+
+ /* Tell the caller it will never happen */
+ if (!platform.nvram_info)
+ return false;
+
+ /*
+ * One of two things has happened here.
+ * 1. nvram_wait_for_load() was called before nvram_init()
+ * 2. The read of NVRAM failed.
+ * Either way, this is quite a bad event.
+ */
+ if (!nvram_image && !nvram_size) {
+ prlog(PR_CRIT, "NVRAM: Possible wait before nvram_init()!\n");
+ return false;
+ }
+
+ started = mftb();
+
+ while (!nvram_ready) {
+ opal_run_pollers();
+ /* If the read fails, tell the caller */
+ if (!nvram_image && !nvram_size)
+ return false;
+ }
+
+ prlog(PR_DEBUG, "NVRAM: Waited %lums for nvram to load\n",
+ tb_to_msecs(mftb() - started));
+
+ return true;
+}
+
+bool nvram_has_loaded(void)
+{
+ return nvram_ready;
+}
+
+void nvram_init(void)
+{
+ int rc;
+
+ if (!platform.nvram_info)
+ return;
+ rc = platform.nvram_info(&nvram_size);
+ if (rc) {
+ prerror("NVRAM: Error %d retrieving nvram info\n", rc);
+ return;
+ }
+ prlog(PR_INFO, "NVRAM: Size is %d KB\n", nvram_size >> 10);
+ if (nvram_size > 0x100000) {
+ prlog(PR_WARNING, "NVRAM: Cropping to 1MB !\n");
+ nvram_size = 0x100000;
+ }
+
+ /*
+ * We allocate the nvram image with 4k alignment to make the
+ * FSP backend job's easier
+ */
+ nvram_image = memalign(0x1000, nvram_size);
+ if (!nvram_image) {
+ prerror("NVRAM: Failed to allocate nvram image\n");
+ nvram_size = 0;
+ return;
+ }
+
+ /* Read it in */
+ rc = platform.nvram_start_read(nvram_image, 0, nvram_size);
+ if (rc) {
+ prerror("NVRAM: Failed to read NVRAM from FSP !\n");
+ nvram_size = 0;
+ free(nvram_image);
+ return;
+ }
+
+ /*
+ * We'll get called back later (or recursively from
+ * nvram_start_read) in nvram_read_complete()
+ */
+}