Karthik Ramasubramanian has uploaded this change for review. ( https://review.coreboot.org/29541
Change subject: drivers/elog: Group event log state information ......................................................................
drivers/elog: Group event log state information
Group event log state information together to manage them better during different stages of coreboot.
BUG=b:117884485 BRANCH=None TEST=Add an event log from romstage, boot to ChromeOS
Change-Id: I62792c0f5063c89ad11b512f1777c7ab8a2c13e5 Signed-off-by: Karthikeyan Ramasubramanian kramasub@google.com --- M src/drivers/elog/elog.c 1 file changed, 102 insertions(+), 58 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/41/29541/1
diff --git a/src/drivers/elog/elog.c b/src/drivers/elog/elog.c index d3c01c2..d1a9f4f 100644 --- a/src/drivers/elog/elog.c +++ b/src/drivers/elog/elog.c @@ -16,6 +16,7 @@ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) #include <arch/acpi.h> #endif +#include <arch/early_variables.h> #include <bootstate.h> #include <cbmem.h> #include <console/console.h> @@ -42,33 +43,38 @@ #endif
#define NV_NEEDS_ERASE (~(size_t)0) -/* - * Static variables for ELOG state - */ -static u16 full_threshold; -static u16 shrink_size; - -/* - * The non-volatile storage chases the mirrored copy. When nv_last_write - * is less than the mirrored last write the non-volatile storage needs - * to be updated. - */ -static size_t mirror_last_write; -static size_t nv_last_write; - -static struct region_device nv_dev; -/* Device that mirrors the eventlog in memory. */ -static struct mem_region_device mirror_dev; - -static enum { +enum elog_init_state { ELOG_UNINITIALIZED = 0, ELOG_INITIALIZED, ELOG_BROKEN, -} elog_initialized = ELOG_UNINITIALIZED; +}; + +struct elog_state { + u16 full_threshold; + u16 shrink_size; + + /* + * The non-volatile storage chases the mirrored copy. When nv_last_write + * is less than the mirrored last write the non-volatile storage needs + * to be updated. + */ + size_t mirror_last_write; + size_t nv_last_write; + + struct region_device nv_dev; + /* Device that mirrors the eventlog in memory. */ + struct mem_region_device mirror_dev; + + enum elog_init_state elog_initialized; +}; + +static struct elog_state g_elog_state CAR_GLOBAL;
static inline struct region_device *mirror_dev_get(void) { - return &mirror_dev.rdev; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + return &g_elog_statep->mirror_dev.rdev; }
static size_t elog_events_start(void) @@ -79,7 +85,9 @@
static size_t elog_events_total_space(void) { - return region_device_sz(&nv_dev) - elog_events_start(); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + return region_device_sz(&g_elog_statep->nv_dev) - elog_events_start(); }
static struct event_header *elog_get_event_buffer(size_t offset, size_t size) @@ -89,8 +97,11 @@
static struct event_header *elog_get_next_event_buffer(size_t size) { - elog_debug("ELOG: new event at offset 0x%zx\n", mirror_last_write); - return elog_get_event_buffer(mirror_last_write, size); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + elog_debug("ELOG: new event at offset 0x%zx\n", + g_elog_statep->mirror_last_write); + return elog_get_event_buffer(g_elog_statep->mirror_last_write, size); }
static void elog_put_event_buffer(struct event_header *event) @@ -100,53 +111,72 @@
static size_t elog_mirror_reset_last_write(void) { + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); /* Return previous write value. */ - size_t prev = mirror_last_write; - mirror_last_write = 0; + size_t prev = g_elog_statep->mirror_last_write; + + g_elog_statep->mirror_last_write = 0; return prev; }
static void elog_mirror_increment_last_write(size_t size) { - mirror_last_write += size; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + g_elog_statep->mirror_last_write += size; }
static void elog_nv_reset_last_write(void) { - nv_last_write = 0; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + g_elog_statep->nv_last_write = 0; }
static void elog_nv_increment_last_write(size_t size) { - nv_last_write += size; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + g_elog_statep->nv_last_write += size; }
static void elog_nv_needs_possible_erase(void) { + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + /* If last write is 0 it means it is already erased. */ - if (nv_last_write != 0) - nv_last_write = NV_NEEDS_ERASE; + if (g_elog_statep->nv_last_write != 0) + g_elog_statep->nv_last_write = NV_NEEDS_ERASE; }
static bool elog_should_shrink(void) { - return mirror_last_write >= full_threshold; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + return g_elog_statep->mirror_last_write >= + g_elog_statep->full_threshold; }
static bool elog_nv_needs_erase(void) { - return nv_last_write == NV_NEEDS_ERASE; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + return g_elog_statep->nv_last_write == NV_NEEDS_ERASE; }
static bool elog_nv_needs_update(void) { - return nv_last_write != mirror_last_write; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + return g_elog_statep->nv_last_write != g_elog_statep->mirror_last_write; }
static size_t elog_nv_region_to_update(size_t *offset) { - *offset = nv_last_write; - return mirror_last_write - nv_last_write; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + + *offset = g_elog_statep->nv_last_write; + return g_elog_statep->mirror_last_write - g_elog_statep->nv_last_write; }
/* @@ -318,6 +348,7 @@ { void *address; const struct region_device *rdev = mirror_dev_get(); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state);
if (!size) return; @@ -331,7 +362,7 @@ return;
/* Write the data to flash */ - if (rdev_writeat(&nv_dev, address, offset, size) != size) + if (rdev_writeat(&g_elog_statep->nv_dev, address, offset, size) != size) printk(BIOS_ERR, "ELOG: NV Write failed at 0x%zx, size 0x%zx\n", offset, size);
@@ -344,11 +375,12 @@ */ static void elog_nv_erase(void) { - size_t size = region_device_sz(&nv_dev); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + size_t size = region_device_sz(&g_elog_statep->nv_dev); elog_debug("%s()\n", __func__);
/* Erase the sectors in this region */ - if (rdev_eraseat(&nv_dev, 0, size) != size) + if (rdev_eraseat(&g_elog_statep->nv_dev, 0, size) != size) printk(BIOS_ERR, "ELOG: erase failure.\n"); }
@@ -406,11 +438,13 @@ elog_debug("elog_scan_flash()\n"); void *mirror_buffer; const struct region_device *rdev = mirror_dev_get(); - size_t size = region_device_sz(&nv_dev); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + size_t size = region_device_sz(&g_elog_statep->nv_dev);
/* Fill memory buffer by reading from SPI */ mirror_buffer = rdev_mmap_full(rdev); - if (rdev_readat(&nv_dev, mirror_buffer, 0, size) != size) { + if (rdev_readat(&g_elog_statep->nv_dev, mirror_buffer, 0, size) != + size) { rdev_munmap(rdev, mirror_buffer); printk(BIOS_ERR, "ELOG: NV read failure.\n"); return -1; @@ -574,8 +608,10 @@
static int elog_shrink(void) { + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + if (elog_should_shrink()) - return elog_shrink_by_size(shrink_size); + return elog_shrink_by_size(g_elog_statep->shrink_size); return 0; }
@@ -584,16 +620,19 @@ */ static inline u8 *elog_flash_offset_to_address(void) { + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + /* Only support memory-mapped devices. */ if (!IS_ENABLED(CONFIG_BOOT_DEVICE_MEMORY_MAPPED)) return NULL;
- if (!region_device_sz(&nv_dev)) + if (!region_device_sz(&g_elog_statep->nv_dev)) return NULL;
/* Get a view into the read-only boot device. */ - return rdev_mmap(boot_device_ro(), region_device_offset(&nv_dev), - region_device_sz(&nv_dev)); + return rdev_mmap(boot_device_ro(), + region_device_offset(&g_elog_statep->nv_dev), + region_device_sz(&g_elog_statep->nv_dev)); }
/* @@ -605,7 +644,8 @@ struct smbios_type15 *t = (struct smbios_type15 *)*current; int len = sizeof(struct smbios_type15); uintptr_t log_address; - size_t elog_size = region_device_sz(&nv_dev); + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + size_t elog_size = region_device_sz(&g_elog_statep->nv_dev);
if (IS_ENABLED(CONFIG_ELOG_CBMEM)) { /* Save event log buffer into CBMEM for the OS to read */ @@ -659,7 +699,8 @@ { size_t total_size; size_t reserved_space = ELOG_MIN_AVAILABLE_ENTRIES * MAX_EVENT_SIZE; - struct region_device *rdev = &nv_dev; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state); + struct region_device *rdev = &g_elog_statep->nv_dev;
elog_debug("%s()\n", __func__);
@@ -682,10 +723,10 @@ total_size = MIN(4*KiB, region_device_sz(rdev)); rdev_chain(rdev, rdev, 0, total_size);
- full_threshold = total_size - reserved_space; - shrink_size = total_size * ELOG_SHRINK_PERCENTAGE / 100; + g_elog_statep->full_threshold = total_size - reserved_space; + g_elog_statep->shrink_size = total_size * ELOG_SHRINK_PERCENTAGE / 100;
- if (reserved_space > shrink_size) { + if (reserved_space > g_elog_statep->shrink_size) { printk(BIOS_ERR, "ELOG: SHRINK_PERCENTAGE too small\n"); return -1; } @@ -698,6 +739,7 @@ size_t offset; size_t size; bool erase_needed; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state);
/* Determine if any updates are required. */ if (!elog_nv_needs_update()) @@ -729,7 +771,7 @@ if (elog_scan_flash() < 0) { printk(BIOS_ERR, "ELOG: Sync back from NV storage failed.\n"); elog_debug_dump_buffer("ELOG: Buffer from NV:\n"); - elog_initialized = ELOG_BROKEN; + g_elog_statep->elog_initialized = ELOG_BROKEN; return -1; }
@@ -758,8 +800,9 @@ { void *mirror_buffer; size_t elog_size; + struct elog_state *g_elog_statep = car_get_var_ptr(&g_elog_state);
- switch (elog_initialized) { + switch (g_elog_statep->elog_initialized) { case ELOG_UNINITIALIZED: break; case ELOG_INITIALIZED: @@ -767,7 +810,7 @@ case ELOG_BROKEN: return -1; } - elog_initialized = ELOG_BROKEN; + g_elog_statep->elog_initialized = ELOG_BROKEN;
elog_debug("elog_init()\n");
@@ -775,19 +818,20 @@ if (elog_find_flash() < 0) return -1;
- elog_size = region_device_sz(&nv_dev); + elog_size = region_device_sz(&g_elog_statep->nv_dev); mirror_buffer = malloc(elog_size); if (!mirror_buffer) { printk(BIOS_ERR, "ELOG: Unable to allocate backing store\n"); return -1; } - mem_region_device_rw_init(&mirror_dev, mirror_buffer, elog_size); + mem_region_device_rw_init(&g_elog_statep->mirror_dev, mirror_buffer, + elog_size);
/* * Mark as initialized to allow elog_init() to be called and deemed * successful in the prepare/shrink path which adds events. */ - elog_initialized = ELOG_INITIALIZED; + g_elog_statep->elog_initialized = ELOG_INITIALIZED;
/* Load the log from flash and prepare the flash if necessary. */ if (elog_scan_flash() < 0 && elog_prepare_empty() < 0) { @@ -796,8 +840,8 @@ }
printk(BIOS_INFO, "ELOG: area is %zu bytes, full threshold %d," - " shrink size %d\n", region_device_sz(&nv_dev), - full_threshold, shrink_size); + " shrink size %d\n", region_device_sz(&g_elog_statep->nv_dev), + g_elog_statep->full_threshold, g_elog_statep->shrink_size);
if (elog_do_add_boot_count()) { elog_add_event_dword(ELOG_TYPE_BOOT, boot_count_read());