From ed800961a019240208de4ee5662d6f02381a18aa Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Sun, 11 Oct 2015 21:37:39 -0700 Subject: x86: Add more common routines to manipulate mrc cache This adds mrccache_reserve(), mrccache_get_region() and mrccache_save() APIs to the mrccache codes. They are ported from the ivybridge implementation, but with some changes. For example, in the mrccache_reserve(), ivybridge version only reserves the pure MRC data, which causes additional malloc() when saving the cache as the save API needs some meta data. Now we change it to save the whole MRC date plus the meta data to elinimate the need for the malloc() later. Signed-off-by: Bin Meng Acked-by: Simon Glass --- arch/x86/include/asm/mrccache.h | 51 +++++++++++++++++++++++ arch/x86/lib/mrccache.c | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) (limited to 'arch/x86') diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index 2fd908287db..bcf7117f09e 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Google, Inc + * Copyright (C) 2015 Bin Meng * * SPDX-License-Identifier: GPL-2.0+ */ @@ -11,6 +12,8 @@ #define MRC_DATA_SIGNATURE (('M' << 0) | ('R' << 8) | \ ('C' << 16) | ('D'<<24)) +#define MRC_DATA_HEADER_SIZE 32 + struct __packed mrc_data_container { u32 signature; /* "MRCD" */ u32 data_size; /* Size of the 'data' field */ @@ -48,4 +51,52 @@ struct mrc_data_container *mrccache_find_current(struct fmap_entry *entry); int mrccache_update(struct udevice *sf, struct fmap_entry *entry, struct mrc_data_container *cur); +/** + * mrccache_reserve() - reserve MRC data on the stack + * + * This copies MRC data pointed by gd->arch.mrc_output to a new place on the + * stack with length gd->arch.mrc_output_len, and updates gd->arch.mrc_output + * to point to the new place once the migration is done. + * + * This routine should be called by reserve_arch() before U-Boot is relocated + * when MRC cache is enabled. + * + * @return 0 always + */ +int mrccache_reserve(void); + +/** + * mrccache_get_region() - get MRC region on the SPI flash + * + * This gets MRC region whose offset and size are described in the device tree + * as a subnode to the SPI flash. If a non-NULL device pointer is supplied, + * this also probes the SPI flash device and returns its device pointer for + * the caller to use later. + * + * Be careful when calling this routine with a non-NULL device pointer: + * - driver model initialization must be complete + * - calling in the pre-relocation phase may bring some side effects during + * the SPI flash device probe (eg: for SPI controllers on a PCI bus, it + * triggers PCI bus enumeration during which insufficient memory issue + * might be exposed and it causes subsequent SPI flash probe fails). + * + * @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 + * device tree, -EPERM if MRC region subnode does not exist in the device + * tree, -EINVAL if MRC region properties format is incorrect, other error + * if SPI flash probe failed. + */ +int mrccache_get_region(struct udevice **devp, struct fmap_entry *entry); + +/** + * mrccache_save() - save MRC data to the SPI flash + * + * This saves MRC data stored previously by gd->arch.mrc_output to a proper + * place within the MRC region on the SPI flash. + * + * @return 0 if saved to SPI flash successfully, other error if failed + */ +int mrccache_save(void); + #endif /* _ASM_MRCCACHE_H */ diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 1c4b5a8d519..0efae6dbdf2 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -2,11 +2,13 @@ * From coreboot src/southbridge/intel/bd82x6x/mrccache.c * * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015 Bin Meng * * SPDX-License-Identifier: GPL-2.0 */ #include +#include #include #include #include @@ -14,6 +16,8 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + static struct mrc_data_container *next_mrc_block( struct mrc_data_container *cache) { @@ -155,3 +159,88 @@ int mrccache_update(struct udevice *sf, struct fmap_entry *entry, return 0; } + +int mrccache_reserve(void) +{ + struct mrc_data_container *cache; + u16 checksum; + + if (!gd->arch.mrc_output_len) + return 0; + + /* adjust stack pointer to store pure cache data plus the header */ + gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE); + cache = (struct mrc_data_container *)gd->start_addr_sp; + + cache->signature = MRC_DATA_SIGNATURE; + cache->data_size = gd->arch.mrc_output_len; + checksum = compute_ip_checksum(gd->arch.mrc_output, 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); + + /* gd->arch.mrc_output now points to the container */ + gd->arch.mrc_output = (char *)cache; + + gd->start_addr_sp &= ~0xf; + + return 0; +} + +int mrccache_get_region(struct udevice **devp, struct fmap_entry *entry) +{ + const void *blob = gd->fdt_blob; + int node, mrc_node; + int ret; + + /* Find the flash chip within the SPI controller node */ + node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); + if (node < 0) + return -ENOENT; + + /* Find the place where we put the MRC cache */ + mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache"); + if (mrc_node < 0) + return -EPERM; + + if (fdtdec_read_fmap_entry(blob, mrc_node, "rm-mrc-cache", entry)) + return -EINVAL; + + if (devp) { + ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, + devp); + debug("ret = %d\n", ret); + if (ret) + return ret; + } + + return 0; +} + +int mrccache_save(void) +{ + struct mrc_data_container *data; + struct fmap_entry entry; + struct udevice *sf; + int ret; + + if (!gd->arch.mrc_output_len) + return 0; + debug("Saving %d bytes of MRC output data to SPI flash\n", + gd->arch.mrc_output_len); + + ret = mrccache_get_region(&sf, &entry); + if (ret) + goto err_entry; + data = (struct mrc_data_container *)gd->arch.mrc_output; + ret = mrccache_update(sf, &entry, data); + if (!ret) + debug("Saved MRC data with checksum %04x\n", data->checksum); + +err_entry: + if (ret) + debug("%s: Failed: %d\n", __func__, ret); + return ret; +} -- cgit v1.2.3