x86: Update mrccache to support multiple caches

With Apollo Lake we need to support a normal cache, which almost never
changes and a much smaller 'variable' cache which changes every time.

Update the code to add a cache type, use an array for the caches and use a
for loop to iterate over the caches.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Simon Glass 2019-12-06 21:42:07 -07:00 committed by Bin Meng
parent 83f288f236
commit 515e8174f5
8 changed files with 105 additions and 47 deletions

View file

@ -83,7 +83,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data)
struct mrc_region entry;
int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
mrc_cache = mrccache_find_current(&entry);
@ -169,12 +169,14 @@ int dram_init(void)
pei_data->data_to_save);
/* S3 resume: don't save scrambler seed or MRC data */
if (pei_data->boot_mode != SLEEP_STATE_S3) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
/*
* This will be copied to SDRAM in reserve_arch(), then written
* to SPI flash in mrccache_save()
*/
gd->arch.mrc_output = (char *)pei_data->data_to_save;
gd->arch.mrc_output_len = pei_data->data_to_save_size;
mrc->buf = (char *)pei_data->data_to_save;
mrc->len = pei_data->data_to_save_size;
}
gd->arch.pei_meminfo = pei_data->meminfo;

View file

@ -116,7 +116,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data)
ret = read_seed_from_cmos(pei_data);
if (ret)
return ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
mrc_cache = mrccache_find_current(&entry);
@ -538,12 +538,14 @@ int dram_init(void)
/* S3 resume: don't save scrambler seed or MRC data */
if (pei_data->boot_mode != PEI_BOOT_RESUME) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
/*
* This will be copied to SDRAM in reserve_arch(), then written
* to SPI flash in mrccache_save()
*/
gd->arch.mrc_output = (char *)pei_data->mrc_output;
gd->arch.mrc_output_len = pei_data->mrc_output_len;
mrc->buf = (char *)pei_data->mrc_output;
mrc->len = pei_data->mrc_output_len;
ret = write_seeds_to_cmos(pei_data);
if (ret)
debug("Failed to write seeds to CMOS: %d\n", ret);

View file

@ -24,7 +24,7 @@ static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params)
struct mrc_region entry;
int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return ret;
@ -154,9 +154,11 @@ int dram_init(void)
#ifdef CONFIG_ENABLE_MRC_CACHE
cache = malloc(sizeof(struct mrc_timings));
if (cache) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings));
gd->arch.mrc_output = cache;
gd->arch.mrc_output_len = sizeof(struct mrc_timings);
mrc->buf = cache;
mrc->len = sizeof(struct mrc_timings);
}
#endif

View file

@ -67,6 +67,21 @@ struct mtrr_request {
uint64_t size;
};
/**
* struct mrc_output - holds the MRC data
*
* @buf: MRC training data to save for the next boot. This is set to point to
* the raw data after SDRAM init is complete. Then mrccache_setup()
* turns it into a proper cache record with a checksum
* @len: Length of @buf
* @cache: Resulting cache record
*/
struct mrc_output {
char *buf;
uint len;
struct mrc_data_container *cache;
};
/* Architecture-specific global data */
struct arch_global_data {
u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16);
@ -91,10 +106,8 @@ struct arch_global_data {
struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS];
int mtrr_req_count;
int has_mtrr;
/* MRC training data to save for the next boot */
char *mrc_output;
unsigned int mrc_output_len;
struct mrc_data_container *mrc_cache;
/* MRC training data */
struct mrc_output mrc[MRC_TYPE_COUNT];
ulong table; /* Table pointer from previous loader */
int turbo_state; /* Current turbo state */
struct irq_routing_table *pirq_routing_table;

View file

@ -27,6 +27,13 @@ struct mrc_region {
u32 length;
};
/* Types of MRC data */
enum mrc_type_t {
MRC_TYPE_NORMAL,
MRC_TYPE_COUNT,
};
struct udevice;
/**
@ -84,6 +91,7 @@ int mrccache_reserve(void);
* triggers PCI bus enumeration during which insufficient memory issue
* might be exposed and it causes subsequent SPI flash probe fails).
*
* @type: Type of MRC data to use
* @devp: Returns pointer to the SPI flash device
* @entry: Position and size of MRC cache in SPI flash
* @return 0 if success, -ENOENT if SPI flash node does not exist in the
@ -91,7 +99,8 @@ int mrccache_reserve(void);
* tree, -EINVAL if MRC region properties format is incorrect, other error
* if SPI flash probe failed.
*/
int mrccache_get_region(struct udevice **devp, struct mrc_region *entry);
int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
struct mrc_region *entry);
/**
* mrccache_save() - save MRC data to the SPI flash

View file

@ -64,7 +64,7 @@ void *fsp_prepare_mrc_cache(void)
struct mrc_region entry;
int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry);
if (ret)
return NULL;

View file

@ -15,9 +15,11 @@ int dram_init(void)
if (ret)
return ret;
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
&gd->arch.mrc_output_len);
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len);
}
return 0;
}

View file

@ -174,38 +174,45 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry,
return 0;
}
static void mrccache_setup(void *data)
static void mrccache_setup(struct mrc_output *mrc, void *data)
{
struct mrc_data_container *cache = data;
u16 checksum;
cache->signature = MRC_DATA_SIGNATURE;
cache->data_size = gd->arch.mrc_output_len;
checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
cache->data_size = mrc->len;
checksum = compute_ip_checksum(mrc->buf, cache->data_size);
debug("Saving %d bytes for MRC output data, checksum %04x\n",
cache->data_size, checksum);
cache->checksum = checksum;
cache->reserved = 0;
memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
memcpy(cache->data, mrc->buf, cache->data_size);
gd->arch.mrc_cache = cache;
mrc->cache = cache;
}
int mrccache_reserve(void)
{
if (!gd->arch.mrc_output_len)
return 0;
int i;
/* adjust stack pointer to store pure cache data plus the header */
gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE);
mrccache_setup((void *)gd->start_addr_sp);
for (i = 0; i < MRC_TYPE_COUNT; i++) {
struct mrc_output *mrc = &gd->arch.mrc[i];
gd->start_addr_sp &= ~0xf;
if (!mrc->len)
continue;
/* adjust stack pointer to store pure cache data plus header */
gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE);
mrccache_setup(mrc, (void *)gd->start_addr_sp);
gd->start_addr_sp &= ~0xf;
}
return 0;
}
int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
struct mrc_region *entry)
{
struct udevice *dev;
ofnode mrc_node;
@ -246,31 +253,33 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
if (devp)
*devp = dev;
debug("MRC cache in '%s', offset %x, len %x, base %x\n",
dev->name, entry->offset, entry->length, entry->base);
debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n",
type, dev->name, entry->offset, entry->length, entry->base);
return 0;
}
int mrccache_save(void)
static int mrccache_save_type(enum mrc_type_t type)
{
struct mrc_data_container *cache;
struct mrc_output *mrc;
struct mrc_region entry;
struct udevice *sf;
int ret;
if (!gd->arch.mrc_output_len)
mrc = &gd->arch.mrc[type];
if (!mrc->len)
return 0;
debug("Saving %#x bytes of MRC output data to SPI flash\n",
gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry);
log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n",
mrc->len, type);
ret = mrccache_get_region(type, &sf, &entry);
if (ret)
return log_msg_ret("Cannot get region", ret);
ret = device_probe(sf);
if (ret)
return log_msg_ret("Cannot probe device", ret);
cache = gd->arch.mrc_cache;
cache = mrc->cache;
ret = mrccache_update(sf, &entry, cache);
if (!ret)
debug("Saved MRC data with checksum %04x\n", cache->checksum);
@ -280,17 +289,36 @@ int mrccache_save(void)
return 0;
}
int mrccache_save(void)
{
int i;
for (i = 0; i < MRC_TYPE_COUNT; i++) {
int ret;
ret = mrccache_save_type(i);
if (ret)
return ret;
}
return 0;
}
int mrccache_spl_save(void)
{
void *data;
int size;
int i;
size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE;
data = malloc(size);
if (!data)
return log_msg_ret("Allocate MRC cache block", -ENOMEM);
mrccache_setup(data);
gd->arch.mrc_output = data;
for (i = 0; i < MRC_TYPE_COUNT; i++) {
struct mrc_output *mrc = &gd->arch.mrc[i];
void *data;
int size;
size = mrc->len + MRC_DATA_HEADER_SIZE;
data = malloc(size);
if (!data)
return log_msg_ret("Allocate MRC cache block", -ENOMEM);
mrccache_setup(mrc, data);
}
return mrccache_save();
}