From 3fa832840eca5726ea9f67dff3a116580675d938 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Thu, 6 Mar 2014 10:22:22 -0600 Subject: [PATCH] baytrail: mirror payload to be loaded into high ram Previously the SPI mirroring was using the SMM default region. If the payload exceeds the SMM default region size the mirroring won't happen. This causes a slow down. Instead find a region to mirror into below 4GiB that is marked as available ram. Prior to this change 60ms payload times were observed with current depthcharge builds. With this change the load time is 24ms - 32ms depending on boot type. BUG=chrome-os-partner:25385 BRANCH=baytrail TEST=Booted and noted timing. Change-Id: I201f0fd6cf82f4521e5cb7fafac6ece27951995d Signed-off-by: Aaron Durbin Reviewed-on: https://chromium-review.googlesource.com/188715 Reviewed-by: Marc Jones --- src/soc/intel/baytrail/spi_loading.c | 63 +++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/soc/intel/baytrail/spi_loading.c b/src/soc/intel/baytrail/spi_loading.c index 5ac8aa1234..674fe6180d 100644 --- a/src/soc/intel/baytrail/spi_loading.c +++ b/src/soc/intel/baytrail/spi_loading.c @@ -21,26 +21,75 @@ #include #include #include +#include #include #include #include -#include #include #define CACHELINE_SIZE 64 #define INTRA_CACHELINE_MASK (CACHELINE_SIZE - 1) #define CACHELINE_MASK (~INTRA_CACHELINE_MASK) +static void *find_mirror_buffer(int len) +{ + int nentries; + int i; + struct lb_memory *mem; + void *buffer; + + len = ALIGN(len, 4096); + + mem = get_lb_mem(); + nentries = (mem->size - sizeof(*mem)) / sizeof(mem->map[0]); + + /* + * Find the highest RAM entry that accommodates the lenth provide + * while falling below 4GiB. + */ + buffer = NULL; + for (i = 0; i < nentries; i++) { + const uint64_t max_addr = 1ULL << 32; + uint64_t start; + uint64_t size; + struct lb_memory_range *r; + + r = &mem->map[i]; + + if (r->type != LB_MEM_RAM) + continue; + + start = unpack_lb64(r->start); + if (start >= max_addr) + continue; + + size = unpack_lb64(r->size); + if (size < len) + continue; + + /* Adjust size of buffer if range exceeds max address. */ + if (start + size > max_addr) + size = max_addr - start; + + if (size < len) + continue; + + buffer = (void *)(uintptr_t)(start + size - len); + } + + return buffer; +} + /* * Mirror the payload file to the default SMM location if it is small enough. * The default SMM region can be used since no one is using the memory at this * location at this stage in the boot. */ -static inline void *spi_mirror(void *file_start, int file_len) +static void *spi_mirror(void *file_start, int file_len) { int alignment_diff; char *src; - char *dest = (void *)SMM_DEFAULT_BASE; + char *dest; alignment_diff = (INTRA_CACHELINE_MASK & (long)file_start); @@ -56,11 +105,13 @@ static inline void *spi_mirror(void *file_start, int file_len) printk(BIOS_DEBUG, "Payload aligned size: 0x%x\n", file_len); + dest = find_mirror_buffer(file_len); + /* - * Just pass back the pointer to ROM space if the file is larger - * than the RAM mirror region. + * Just pass back the pointer to ROM space if a buffer could not + * be found to mirror into. */ - if (file_len > SMM_DEFAULT_SIZE) + if (dest == NULL) return file_start; src = (void *)(CACHELINE_MASK & (long)file_start);