diff options
Diffstat (limited to 'roms/skiboot/core/nvram.c')
-rw-r--r-- | roms/skiboot/core/nvram.c | 203 |
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() + */ +} |