<p>Marshall Dawson has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/22727">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">soc/amd/common: Add S3 supporting functions<br><br>Add functions that the wrapper will call to get and save the S3 data.<br>The wrapper requires two types of data saved:<br> * Non-volatile: information that is the minimum required for bringing<br> the memory controller back online<br> * Volatile: may be stored in DRAM; information required to complete<br> the system restoration process.<br><br>For each type, the code stores AGESA's reported size followed by the<br>data itself.<br><br>AGESA does not save and restore MTRR settings, so this patch saves the<br>current register settings and adds a function to restore them on a<br>per-core basis. (It is assumed each core is properly in sync during<br>a suspend.) AGESA restores the Top Of Memory and TOM2 registers.<br><br>Change-Id: Ie60162ea10f053393bc84e927dbd80c9279e6b63<br>Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com><br>---<br>M src/soc/amd/common/Makefile.inc<br>M src/soc/amd/common/s3_resume.c<br>M src/soc/amd/common/s3_resume.h<br>3 files changed, 287 insertions(+), 10 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/27/22727/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/src/soc/amd/common/Makefile.inc b/src/soc/amd/common/Makefile.inc<br>index 926262c..fe46233 100644<br>--- a/src/soc/amd/common/Makefile.inc<br>+++ b/src/soc/amd/common/Makefile.inc<br>@@ -9,6 +9,7 @@<br> romstage-y += agesawrapper.c<br> romstage-y += def_callouts.c<br> romstage-y += heapmanager.c<br>+romstage-$(CONFIG_HAVE_ACPI_RESUME) += s3_resume.c<br> <br> ramstage-y += agesawrapper.c<br> ramstage-y += amd_late_init.c<br>diff --git a/src/soc/amd/common/s3_resume.c b/src/soc/amd/common/s3_resume.c<br>index 44c86e6..678f65b 100644<br>--- a/src/soc/amd/common/s3_resume.c<br>+++ b/src/soc/amd/common/s3_resume.c<br>@@ -1,7 +1,8 @@<br> /*<br> * This file is part of the coreboot project.<br> *<br>- * Copyright (C) 2012 Advanced Micro Devices, Inc.<br>+ * Copyright (C) 2012-2017 Advanced Micro Devices, Inc.<br>+ * Copyright (C) 2014 Google Inc.<br> *<br> * This program is free software; you can redistribute it and/or modify<br> * it under the terms of the GNU General Public License as published by<br>@@ -13,27 +14,283 @@<br> * GNU General Public License for more details.<br> */<br> <br>+#include <cpu/x86/msr.h><br>+#include <cpu/x86/mtrr.h><br>+#include <cpu/amd/mtrr.h><br>+#include <cpu/x86/cache.h><br>+#include <cbmem.h><br>+#include <fmap.h><br> #include <console/console.h><br> #include <spi-generic.h><br> #include <spi_flash.h><br>+#include <region_file.h><br>+#include <security/vboot/vboot_common.h><br>+#include <string.h><br>+#include <soc/iomap.h><br> #include "s3_resume.h"<br>+#include <BiosCallOuts.h><br>+#include <agesa_headers.h><br> <br>-void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len)<br>+#if !IS_ENABLED(CONFIG_SPI_FLASH)<br>+#error "CONFIG_SPI_FLASH must be enabled"<br>+#endif<br>+<br>+int spi_save_s3_info(struct region dst, struct region src)<br> {<br> struct spi_flash flash;<br>+ int status;<br>+<br>+ if (src.size == 0)<br>+ return 0;<br> <br> spi_init();<br> if (spi_flash_probe(0, 0, &flash)) {<br>- printk(BIOS_DEBUG, "Could not find SPI device\n");<br>- /* Dont make flow stop. */<br>+ printk(BIOS_DEBUG, "S3 SPI: couldn't find SPI device\n");<br>+ return -1;<br>+ }<br>+<br>+ /* need to write the data plus the size below */<br>+ if (src.size + sizeof(src.size) > dst.size) {<br>+ printk(BIOS_DEBUG, "S3 SPI: src is larger than dest.\n");<br>+ return -1;<br>+ }<br>+<br>+ status = spi_flash_volatile_group_begin(&flash);<br>+ if (status)<br>+ goto error;<br>+<br>+ status = spi_flash_erase(&flash, dst.offset, dst.size);<br>+ if (status)<br>+ goto error;<br>+<br>+ /* write size first */<br>+ status = spi_flash_write(&flash, dst.offset, sizeof(src.size),<br>+ (void *)&src.size);<br>+ if (status)<br>+ goto error;<br>+<br>+ /* write buffer */<br>+ status = spi_flash_write(&flash, dst.offset + sizeof(dst.size),<br>+ src.size, (void *)src.offset);<br>+<br>+error:<br>+ spi_flash_volatile_group_end(&flash);<br>+ return status;<br>+}<br>+<br>+static int lookup_region_by_name(const char *name, struct region *r)<br>+{<br>+ /* todo: make Intel MRC cache location common, convert AMD to use it. */<br>+ if (fmap_locate_area(name, r) == 0)<br>+ return 0;<br>+<br>+ if (IS_ENABLED(CONFIG_VBOOT)) {<br>+ printk(BIOS_ERR, "Error: vboot requires flash map for S3\n");<br>+ return -1;<br>+ }<br>+<br>+ /* Fall back to Kconfig values */<br>+ if (!CONFIG_S3_DATA_POS || !CONFIG_S3_DATA_SIZE)<br>+ return -1;<br>+<br>+ r->offset = CONFIG_S3_DATA_POS;<br>+ r->size = CONFIG_S3_DATA_SIZE;<br>+ return 0;<br>+}<br>+<br>+static void get_s3nv_region(struct region *nv)<br>+{<br>+ int status = lookup_region_by_name("RW_MRC_CACHE", nv);<br>+ if (status) {<br>+ nv->offset = 0;<br>+ nv->size = 0;<br>+ return;<br>+ }<br>+}<br>+<br>+static void get_s3vol_region(struct region *vol)<br>+{<br>+ struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase();<br>+ if (!heap) {<br>+ printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n");<br>+ return;<br>+ }<br>+ vol->offset = (size_t)heap->s3_vol_data;<br>+ vol->size = S3_VOLATILE_SIZE;<br>+}<br>+<br>+static void get_s3mtrr_region(struct region *mtrr)<br>+{<br>+ struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase();<br>+ if (!heap) {<br>+ printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n");<br>+ return;<br>+ }<br>+ mtrr->offset = (size_t)&heap->s3_mtrrs;<br>+ mtrr->size = sizeof(struct all_mtrrs);<br>+}<br>+<br>+void restore_mtrr(void)<br>+{<br>+ u32 i;<br>+ msr_t msr;<br>+ struct all_mtrrs *mtrrs;<br>+ int num_vmtrrs;<br>+<br>+ struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase();<br>+ if (!heap) {<br>+ printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n");<br>+ return;<br>+ }<br>+ mtrrs = (struct all_mtrrs *)&heap->s3_mtrrs;<br>+<br>+ msr = rdmsr(MTRR_CAP_MSR);<br>+ num_vmtrrs = msr.lo & MTRR_CAP_VCNT;<br>+<br>+ disable_cache();<br>+<br>+ /* Enable access to AMD RdDram and WrDram extension bits */<br>+ msr = rdmsr(SYSCFG_MSR);<br>+ msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;<br>+ wrmsr(SYSCFG_MSR, msr);<br>+<br>+ /* Now restore the Fixed MTRRs */<br>+ wrmsr(MTRR_FIX_64K_00000, mtrrs->_64k_00);<br>+ wrmsr(MTRR_FIX_16K_80000, mtrrs->_16k_80);<br>+ wrmsr(MTRR_FIX_16K_A0000, mtrrs->_16k_a0);<br>+ wrmsr(MTRR_FIX_4K_C0000, mtrrs->_4k_c0);<br>+ wrmsr(MTRR_FIX_4K_C8000, mtrrs->_4k_c8);<br>+ wrmsr(MTRR_FIX_4K_D0000, mtrrs->_4k_d0);<br>+ wrmsr(MTRR_FIX_4K_D8000, mtrrs->_4k_d8);<br>+ wrmsr(MTRR_FIX_4K_E0000, mtrrs->_4k_e0);<br>+ wrmsr(MTRR_FIX_4K_E8000, mtrrs->_4k_e8);<br>+ wrmsr(MTRR_FIX_4K_F0000, mtrrs->_4k_f0);<br>+ wrmsr(MTRR_FIX_4K_F8000, mtrrs->_4k_f8);<br>+<br>+ for (i = 0 ; i < num_vmtrrs ; i++) {<br>+ wrmsr(MTRR_PHYS_BASE(i), mtrrs->vmtrr[i].base);<br>+ wrmsr(MTRR_PHYS_MASK(i), mtrrs->vmtrr[i].mask);<br>+ }<br>+<br>+ wrmsr(SYSCFG_MSR, mtrrs->sys_cfg);<br>+}<br>+<br>+static int save_mtrr(struct all_mtrrs *mtrrs)<br>+{<br>+ u32 i;<br>+ msr_t msr;<br>+ int num_vmtrrs;<br>+<br>+ msr = rdmsr(MTRR_CAP_MSR);<br>+ num_vmtrrs = msr.lo & MTRR_CAP_VCNT; /* no. of supported var. MTRRs */<br>+<br>+ if (num_vmtrrs > MAX_VAR_MTRRS) {<br>+ printk(BIOS_ERR, "Error: Increase MAX_VAR_MTRRS for S3\n");<br>+ return -1;<br>+ }<br>+<br>+ /* Start saving */<br>+ mtrrs->sys_cfg = rdmsr(SYSCFG_MSR);<br>+<br>+ /* Enable access to AMD RdDram and WrDram extension bits */<br>+ msr = rdmsr(SYSCFG_MSR);<br>+ msr.lo |= SYSCFG_MSR_MtrrFixDramModEn;<br>+ wrmsr(SYSCFG_MSR, msr);<br>+<br>+ /* Save the Fixed MTRRs */<br>+ mtrrs->_64k_00 = rdmsr(MTRR_FIX_64K_00000);<br>+ mtrrs->_16k_80 = rdmsr(MTRR_FIX_16K_80000);<br>+ mtrrs->_16k_a0 = rdmsr(MTRR_FIX_16K_A0000);<br>+ mtrrs->_4k_c0 = rdmsr(MTRR_FIX_4K_C0000);<br>+ mtrrs->_4k_c8 = rdmsr(MTRR_FIX_4K_C8000);<br>+ mtrrs->_4k_d0 = rdmsr(MTRR_FIX_4K_D0000);<br>+ mtrrs->_4k_d8 = rdmsr(MTRR_FIX_4K_D8000);<br>+ mtrrs->_4k_e0 = rdmsr(MTRR_FIX_4K_E0000);<br>+ mtrrs->_4k_e8 = rdmsr(MTRR_FIX_4K_E8000);<br>+ mtrrs->_4k_f0 = rdmsr(MTRR_FIX_4K_F0000);<br>+ mtrrs->_4k_f8 = rdmsr(MTRR_FIX_4K_F8000);<br>+<br>+ /* Disable access to AMD RdDram and WrDram extension bits */<br>+ msr = rdmsr(SYSCFG_MSR);<br>+ msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;<br>+ wrmsr(SYSCFG_MSR, msr);<br>+<br>+ for (i = 0 ; i < num_vmtrrs ; i++) {<br>+ mtrrs->vmtrr[i].base = rdmsr(MTRR_PHYS_BASE(i));<br>+ mtrrs->vmtrr[i].mask = rdmsr(MTRR_PHYS_MASK(i));<br>+ }<br>+<br>+ /* AGESA restores TOM and TOM2 */<br>+<br>+ return 0;<br>+}<br>+<br>+void get_s3_info(S3_DATA_TYPE type, struct region *info)<br>+{<br>+ struct region rgn = { .offset = 0, .size = 0 };<br>+<br>+ switch (type) {<br>+ case S3_DATA_TYPE_NV:<br>+ get_s3nv_region(&rgn);<br>+ rgn.offset += FLASH_BASE_ADDR;<br>+ printk(BIOS_SPEW, "S3 NV data @0x%zx\n", rgn.offset);<br>+ break;<br>+ case S3_DATA_TYPE_VOLATILE:<br>+ get_s3vol_region(&rgn);<br>+ printk(BIOS_SPEW, "S3 volatile data @0x%zx\n", rgn.offset);<br>+ break;<br>+ default:<br>+ printk(BIOS_ERR, "Error: %s called with bad type %d\n",<br>+ __func__, type);<br> return;<br> }<br> <br>- spi_flash_volatile_group_begin(&flash);<br>+ info->size = *(size_t *)rgn.offset;<br>+ info->offset = rgn.offset + sizeof(info->size);<br>+}<br> <br>- spi_flash_erase(&flash, pos, size);<br>- spi_flash_write(&flash, pos, sizeof(len), &len);<br>- spi_flash_write(&flash, pos + sizeof(len), len, buf);<br>+int save_s3_info(struct region nv, struct region vol)<br>+{<br>+ struct region dst;<br>+ void *data;<br> <br>- spi_flash_volatile_group_end(&flash);<br>+ printk(BIOS_SPEW, "%s(): S3 NV data @0x%zx (0x%zx bytes)"<br>+ " volatile data @0x%zx (0x%zx bytes)\n",<br>+ __func__, nv.offset, nv.size,<br>+ vol.offset, vol.size);<br>+<br>+ get_s3vol_region(&dst);<br>+ if (vol.size && (dst.offset == 0 || dst.size == 0)) {<br>+ printk(BIOS_ERR, "Error: can't access S3 volatile save area\n");<br>+ return -1;<br>+ }<br>+<br>+ /* write size followed by AGESA's volatile data */<br>+ data = (void *)(dst.offset + sizeof(size_t));<br>+ memset((void *)dst.offset, 0, S3_VOLATILE_SIZE);<br>+<br>+ *(size_t *)dst.offset = vol.size;<br>+ memcpy(data, (void *)vol.offset, vol.size);<br>+<br>+ get_s3mtrr_region(&dst);<br>+ if (!dst.offset || !dst.size) {<br>+ printk(BIOS_ERR, "Error: can't access S3 MTRR save area\n");<br>+ return -1;<br>+ }<br>+<br>+ if (save_mtrr((void *)dst.offset))<br>+ return -1;<br>+<br>+ get_s3nv_region(&dst);<br>+ if (!dst.offset || !dst.size) {<br>+ printk(BIOS_ERR, "Error: can't find S3 NV save area\n");<br>+ return -1;<br>+ }<br>+<br>+ if (spi_save_s3_info(dst, nv)) {<br>+ printk(BIOS_ERR, "Error: can't save S3 NV data\n");<br>+ return -1;<br>+ }<br>+<br>+ return 0;<br> }<br>diff --git a/src/soc/amd/common/s3_resume.h b/src/soc/amd/common/s3_resume.h<br>index 8dc60da..1abb79d 100644<br>--- a/src/soc/amd/common/s3_resume.h<br>+++ b/src/soc/amd/common/s3_resume.h<br>@@ -17,6 +17,20 @@<br> #define __S3_RESUME_H__<br> <br> #include <cpu/x86/msr.h><br>+#include <commonlib/region.h><br>+<br>+/* todo: Make the Intel MRC flash region management common and then use that<br>+ * instead of redefining it here.<br>+ */<br>+#define DEFAULT_MRC_CACHE "RW_MRC_CACHE"<br>+#define VARIABLE_MRC_CACHE "RW_VAR_MRC_CACHE"<br>+#define RECOVERY_MRC_CACHE "RECOVERY_MRC_CACHE"<br>+#define UNIFIED_MRC_CACHE "UNIFIED_MRC_CACHE"<br>+<br>+typedef enum {<br>+ S3_DATA_TYPE_NV = 0,<br>+ S3_DATA_TYPE_VOLATILE,<br>+} S3_DATA_TYPE;<br> <br> #define S3_VOLATILE_SIZE 0x1000<br> <br>@@ -42,6 +56,11 @@<br> struct vmtrr_pair vmtrr[MAX_VAR_MTRRS];<br> };<br> <br>-void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len);<br>+void restore_mtrr(void);<br>+<br>+int save_s3_info(struct region nv, struct region vol);<br>+void get_s3_info(S3_DATA_TYPE type, struct region *info);<br>+<br>+int spi_save_s3_info(struct region dst, struct region src);<br> <br> #endif /* __S3_RESUME_H__ */<br></pre><p>To view, visit <a href="https://review.coreboot.org/22727">change 22727</a>. To unsubscribe, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/22727"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ie60162ea10f053393bc84e927dbd80c9279e6b63 </div>
<div style="display:none"> Gerrit-Change-Number: 22727 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com> </div>