summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/elog/Kconfig10
-rw-r--r--src/drivers/elog/elog.c54
-rw-r--r--src/drivers/elog/elog_internal.h3
3 files changed, 54 insertions, 13 deletions
diff --git a/src/drivers/elog/Kconfig b/src/drivers/elog/Kconfig
index 7912ab8c79..02274c4a09 100644
--- a/src/drivers/elog/Kconfig
+++ b/src/drivers/elog/Kconfig
@@ -66,6 +66,16 @@ config ELOG_SHRINK_SIZE
Default is 1K.
+config ELOG_CBMEM
+ bool "Store a copy of ELOG in CBMEM"
+ default n
+ help
+ This option will have ELOG store a copy of the flash event log
+ in a CBMEM region and export that address in SMBIOS to the OS.
+ This is useful if the ELOG location is not in memory mapped flash,
+ but it means that events added at runtime via the SMI handler
+ will not be reflected in the CBMEM copy of the log.
+
endif
config ELOG_GSMI
diff --git a/src/drivers/elog/elog.c b/src/drivers/elog/elog.c
index 2f6beefd3f..e6baace623 100644
--- a/src/drivers/elog/elog.c
+++ b/src/drivers/elog/elog.c
@@ -18,6 +18,7 @@
*/
#include <arch/acpi.h>
+#include <cbmem.h>
#include <console/console.h>
#include <pc80/mc146818rtc.h>
#include <smbios.h>
@@ -267,18 +268,23 @@ static int elog_is_event_valid(struct elog_descriptor *elog, u32 offset)
*/
static void elog_flash_write(u8 *address, u8 *buffer, u32 size)
{
+ struct elog_descriptor *flash = elog_get_flash();
u32 offset;
if (!address || !buffer || !size || !elog_spi)
return;
- offset = elog_flash_address_to_offset(address);
+ offset = flash->flash_base;
+ offset += address - (u8*)flash->backing_store;
elog_debug("elog_flash_write(address=0x%p offset=0x%08x buffer=0x%p "
"size=%u)\n", address, offset, buffer, size);
/* Write the data to flash */
elog_spi->write(elog_spi, offset, size, buffer);
+
+ /* Update the copy in memory */
+ memcpy(address, buffer, size);
}
/*
@@ -287,12 +293,14 @@ static void elog_flash_write(u8 *address, u8 *buffer, u32 size)
*/
static void elog_flash_erase(u8 *address, u32 size)
{
+ struct elog_descriptor *flash = elog_get_flash();
u32 offset;
if (!address || !size || !elog_spi)
return;
- offset = elog_flash_address_to_offset(address);
+ offset = flash->flash_base;
+ offset += address - (u8*)flash->backing_store;
elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
address, offset, size);
@@ -395,6 +403,10 @@ static void elog_init_descriptor(struct elog_descriptor *elog,
elog->backing_store = buffer;
elog->total_size = size;
+ /* Fill memory buffer by reading from SPI */
+ if (type == ELOG_DESCRIPTOR_FLASH)
+ elog_spi->read(elog_spi, elog->flash_base, size, buffer);
+
/* Get staging header from backing store */
elog->staging_header = header;
memcpy(header, buffer, sizeof(struct elog_header));
@@ -444,11 +456,12 @@ static int elog_setup_descriptors(u32 flash_base, u32 area_size)
return -1;
}
- area = elog_flash_offset_to_address(flash_base);
+ area = malloc(area_size);
if (!area) {
printk(BIOS_ERR, "ELOG: Unable to determine flash address\n");
return -1;
}
+ elog_get_flash()->flash_base = flash_base;
elog_init_descriptor(elog_get_flash(), ELOG_DESCRIPTOR_FLASH,
area, area_size, staging_header);
@@ -472,6 +485,7 @@ static void elog_flash_erase_area(void)
elog_debug("elog_flash_erase_area()\n");
elog_flash_erase(elog->backing_store, elog->total_size);
+ memset(elog->backing_store, ELOG_TYPE_EOL, elog->total_size);
elog_reinit_descriptor(elog);
}
@@ -516,12 +530,13 @@ static int elog_sync_flash_to_mem(void)
/* Fill with empty pattern first */
memset(mem->backing_store, ELOG_TYPE_EOL, mem->total_size);
- /* Copy the header to memory */
- memcpy(mem->backing_store, flash->backing_store,
- sizeof(struct elog_header));
+ /* Read the header from SPI to memory */
+ elog_spi->read(elog_spi, flash->flash_base,
+ sizeof(struct elog_header), mem->backing_store);
- /* Copy the valid flash contents to memory */
- memcpy(mem->data, flash->data, flash->next_event_offset);
+ /* Read the valid flash contents from SPI to memory */
+ elog_spi->read(elog_spi, flash->flash_base + sizeof(struct elog_header),
+ flash->next_event_offset, mem->data);
elog_reinit_descriptor(mem);
@@ -679,26 +694,40 @@ static int elog_spi_init(void)
return elog_spi ? 0 : -1;
}
+#ifndef __SMM__
/*
* Fill out SMBIOS Type 15 table entry so the
* event log can be discovered at runtime.
*/
int elog_smbios_write_type15(unsigned long *current, int handle)
{
+ struct elog_descriptor *flash = elog_get_flash();
struct smbios_type15 *t = (struct smbios_type15 *)*current;
int len = sizeof(struct smbios_type15);
+#if CONFIG_ELOG_CBMEM
+ /* Save event log buffer into CBMEM for the OS to read */
+ void *cbmem = cbmem_add(CBMEM_ID_ELOG, flash->total_size);
+ if (!cbmem)
+ return 0;
+ memcpy(cbmem, flash->backing_store, flash->total_size);
+#endif
+
memset(t, 0, len);
t->type = SMBIOS_EVENT_LOG;
t->length = len - 2;
t->handle = handle;
- t->area_length = elog_get_flash()->total_size - 1;
+ t->area_length = flash->total_size - 1;
t->header_offset = 0;
t->data_offset = sizeof(struct elog_header);
t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
t->change_token = 0;
- t->address = (u32)elog_get_flash()->backing_store;
+#if CONFIG_ELOG_CBMEM
+ t->address = (u32)cbmem;
+#else
+ t->address = (u32)elog_flash_offset_to_address(flash->flash_base);
+#endif
t->header_format = ELOG_HEADER_TYPE_OEM;
t->log_type_descriptors = 0;
t->log_type_descriptor_length = 2;
@@ -706,6 +735,7 @@ int elog_smbios_write_type15(unsigned long *current, int handle)
*current += len;
return len;
}
+#endif
/*
* Clear the entire event log
@@ -790,9 +820,9 @@ int elog_init(void)
elog_initialized = 1;
- printk(BIOS_INFO, "ELOG: MEM @0x%p FLASH @0x%p\n",
+ printk(BIOS_INFO, "ELOG: MEM @0x%p FLASH @0x%p [SPI 0x%08x]\n",
elog_get_mem()->backing_store,
- elog_get_flash()->backing_store);
+ elog_get_flash()->backing_store, elog_get_flash()->flash_base);
printk(BIOS_INFO, "ELOG: areas are %d bytes, full threshold %d,"
" shrink size %d\n", CONFIG_ELOG_AREA_SIZE,
diff --git a/src/drivers/elog/elog_internal.h b/src/drivers/elog/elog_internal.h
index 6d9a0d4bb5..f6aa051007 100644
--- a/src/drivers/elog/elog_internal.h
+++ b/src/drivers/elog/elog_internal.h
@@ -78,8 +78,9 @@ struct elog_descriptor {
elog_header_state header_state;
elog_event_buffer_state event_buffer_state;
struct elog_header *staging_header;
- void *backing_store;
+ void *backing_store;
u8 *data;
+ u32 flash_base;
u16 total_size;
u16 data_size;
u16 next_event_offset;