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 <adurbin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/188715
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
This commit is contained in:
Aaron Durbin 2014-03-06 10:22:22 -06:00 committed by chrome-internal-fetch
commit 3fa832840e

View file

@ -21,26 +21,75 @@
#include <stdlib.h>
#include <string.h>
#include <arch/byteorder.h>
#include <boot/coreboot_tables.h>
#include <cbmem.h>
#include <cbfs.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <vendorcode/google/chromeos/chromeos.h>
#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);