diff mbox

[U-Boot,05/13] x86: Add more common routines to manipulate mrc cache

Message ID 1444624667-8818-6-git-send-email-bmeng.cn@gmail.com
State Accepted
Delegated to: Simon Glass
Headers show

Commit Message

Bin Meng Oct. 12, 2015, 4:37 a.m. UTC
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 <bmeng.cn@gmail.com>
---

 arch/x86/include/asm/mrccache.h | 51 +++++++++++++++++++++++
 arch/x86/lib/mrccache.c         | 89 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 140 insertions(+)

Comments

Simon Glass Oct. 18, 2015, 8:26 p.m. UTC | #1
On 11 October 2015 at 22:37, Bin Meng <bmeng.cn@gmail.com> wrote:
> 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 <bmeng.cn@gmail.com>
> ---
>
>  arch/x86/include/asm/mrccache.h | 51 +++++++++++++++++++++++
>  arch/x86/lib/mrccache.c         | 89 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 140 insertions(+)

Acked-by: Simon Glass <sjg@chromium.org>
Simon Glass Oct. 18, 2015, 9:38 p.m. UTC | #2
On 18 October 2015 at 14:26, Simon Glass <sjg@chromium.org> wrote:
> On 11 October 2015 at 22:37, Bin Meng <bmeng.cn@gmail.com> wrote:
>> 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 <bmeng.cn@gmail.com>
>> ---
>>
>>  arch/x86/include/asm/mrccache.h | 51 +++++++++++++++++++++++
>>  arch/x86/lib/mrccache.c         | 89 +++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 140 insertions(+)
>
> Acked-by: Simon Glass <sjg@chromium.org>

Applied to u-boot-x86, thanks!
diff mbox

Patch

diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h
index 2fd9082..bcf7117 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 <bmeng.cn@gmail.com>
  *
  * 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 1c4b5a8..0efae6d 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 <bmeng.cn@gmail.com>
  *
  * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <net.h>
@@ -14,6 +16,8 @@ 
 #include <spi_flash.h>
 #include <asm/mrccache.h>
 
+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;
+}