summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/soc/amd/common/block/apob/apob_cache.c59
-rw-r--r--src/soc/amd/common/block/include/amdblocks/apob_cache.h2
2 files changed, 60 insertions, 1 deletions
diff --git a/src/soc/amd/common/block/apob/apob_cache.c b/src/soc/amd/common/block/apob/apob_cache.c
index c2c4908a31..f61785dd8c 100644
--- a/src/soc/amd/common/block/apob/apob_cache.c
+++ b/src/soc/amd/common/block/apob/apob_cache.c
@@ -5,12 +5,16 @@
#include <assert.h>
#include <boot_device.h>
#include <bootstate.h>
+#include <commonlib/helpers.h>
#include <commonlib/region.h>
#include <console/console.h>
+#include <delay.h>
#include <fmap.h>
#include <spi_flash.h>
#include <stdint.h>
#include <string.h>
+#include <thread.h>
+#include <timer.h>
#include <timestamp.h>
#define DEFAULT_MRC_CACHE "RW_MRC_CACHE"
@@ -72,6 +76,50 @@ static int get_nv_rdev(struct region_device *r)
return 0;
}
+static struct apob_thread_context {
+ uint8_t buffer[DEFAULT_MRC_CACHE_SIZE] __attribute__((aligned(64)));
+ struct thread_handle handle;
+ struct region_device apob_rdev;
+} global_apob_thread;
+
+static enum cb_err apob_thread_entry(void *arg)
+{
+ ssize_t size;
+ struct apob_thread_context *thread = arg;
+
+ printk(BIOS_DEBUG, "APOB thread running\n");
+ size = rdev_readat(&thread->apob_rdev, thread->buffer, 0,
+ region_device_sz(&thread->apob_rdev));
+
+ printk(BIOS_DEBUG, "APOB thread done\n");
+
+ if (size == region_device_sz(&thread->apob_rdev))
+ return CB_SUCCESS;
+
+ return CB_ERR;
+}
+
+void start_apob_cache_read(void)
+{
+ struct apob_thread_context *thread = &global_apob_thread;
+
+ if (!CONFIG(COOP_MULTITASKING))
+ return;
+
+ /* We don't perform any comparison on S3 resume */
+ if (acpi_is_wakeup_s3())
+ return;
+
+ if (get_nv_rdev(&thread->apob_rdev) != 0)
+ return;
+
+ assert(ARRAY_SIZE(thread->buffer) == region_device_sz(&thread->apob_rdev));
+
+ printk(BIOS_DEBUG, "Starting APOB preload\n");
+ if (thread_run(&thread->handle, apob_thread_entry, thread))
+ printk(BIOS_ERR, "Failed to start APOB preload thread\n");
+}
+
static void *get_apob_from_nv_rdev(struct region_device *read_rdev)
{
struct apob_base_header apob_header;
@@ -111,7 +159,11 @@ static void soc_update_apob_cache(void *unused)
timestamp_add_now(TS_AMD_APOB_READ_START);
- apob_rom = get_apob_from_nv_rdev(&read_rdev);
+ if (CONFIG(COOP_MULTITASKING) && thread_join(&global_apob_thread.handle) == CB_SUCCESS)
+ apob_rom = (struct apob_base_header *)global_apob_thread.buffer;
+ else
+ apob_rom = get_apob_from_nv_rdev(&read_rdev);
+
if (apob_rom == NULL) {
update_needed = true;
} else if (memcmp(apob_src_ram, apob_rom, apob_src_ram->size)) {
@@ -177,4 +229,9 @@ void *soc_fill_apob_cache(void)
*/
return get_apob_nv_address();
}
+
+/*
+ * BS_POST_DEVICE was chosen because this gives start_apob_cache_read plenty of time to read
+ * the APOB from SPI.
+ */
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, soc_update_apob_cache, NULL);
diff --git a/src/soc/amd/common/block/include/amdblocks/apob_cache.h b/src/soc/amd/common/block/include/amdblocks/apob_cache.h
index 79228e5de2..e91720fa61 100644
--- a/src/soc/amd/common/block/include/amdblocks/apob_cache.h
+++ b/src/soc/amd/common/block/include/amdblocks/apob_cache.h
@@ -3,6 +3,8 @@
#ifndef AMD_BLOCK_APOB_CACHE_H
#define AMD_BLOCK_APOB_CACHE_H
+/* Start loading the APOB as soon as possible so it is ready by the time we need it. */
+void start_apob_cache_read(void);
void *soc_fill_apob_cache(void);
#endif /* AMD_BLOCK_APOB_CACHE_H */