x86: Add more common routines to manipulate mrc cache
authorBin Meng <bmeng.cn@gmail.com>
Mon, 12 Oct 2015 04:37:39 +0000 (21:37 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 21 Oct 2015 13:46:27 +0000 (07:46 -0600)
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>
Acked-by: Simon Glass <sjg@chromium.org>
arch/x86/include/asm/mrccache.h
arch/x86/lib/mrccache.c

index 2fd908287dbcaaeaba19dc95349d847e475607de..bcf7117f09e404b25d32d53a7ca979247b506283 100644 (file)
@@ -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 */
index 1c4b5a8d519c479430c9e9431ca08d64ff026998..0efae6dbdf24231ab80d8ec181f0db4f31008e05 100644 (file)
@@ -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;
+}