1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 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()
*/
}
|