<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>