Marshall Dawson has uploaded this change for review.

View Change

soc/amd: Add agesa_HeapRebase callout

One of AGESA's optional callout functions allows it to use a heap area
managed by coreboot. Add the function here; note that AGESA does not
yet call out to agesa_HeapRebase.

AGESA treats the heap as follows:
* It assumes an initial heap base address of 4 MB. An abstracted call
to AgesaHeapRebase is made for an opportunity to override the base.
* If necessary, AGESA programs a variable MTRR in order to keep its
heap in CAR.
* At the end of AmdInitPost, AGESA migrates the heap to 0xb0000 (temp
mem) and removes blocks that will not be used later.
* After AmdInitPost, coreboot initializes cbmem and uses a region there
for requested heap space.
* During AmdInitEnv, AGESA migrates its heap information from temp mem
to the cbmem region (main ram).

To support this callout, define a region that may be used while CAR is
still present. The heap base may then either be in CAR or cbmem. Make
the default cbmem (i.e. for postcar, ramstage). Add a function that
can indicate the base should be in CAR instead. This currently needs
to be called before an AGESA Entry Point call in bootblock and romstage.
(Only a single one will be required once AGESA moves out of bootblock.)
Add a call from EmptyHeap that switches the heap base to cbmem.

Future work may include:
* The AMD standard CAR setup code doesn't allow enough space to use a
a CAR_GLOBAL variable. Consider redoing the AMD CAR setup and
teardown functionality, and use a CAR_GLOBAL region instead.
* Move the heap migration and reduction from the AGESA blob into
coreboot (eliminate the concept of temp ram).

BUG=b:74518368
TEST=Boot Kahlee with experimental PI blob

Change-Id: Ieda202a6064302b21707bd7ddfabc132cd85ed45
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
---
M src/soc/amd/common/block/include/amdblocks/BiosCallOuts.h
M src/soc/amd/common/block/include/amdblocks/agesawrapper.h
M src/soc/amd/common/block/pi/Kconfig
M src/soc/amd/common/block/pi/def_callouts.c
M src/soc/amd/common/block/pi/heapmanager.c
M src/soc/amd/stoneyridge/bootblock/bootblock.c
M src/soc/amd/stoneyridge/include/soc/cpu.h
M src/soc/amd/stoneyridge/romstage.c
8 files changed, 86 insertions(+), 2 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/58/25458/1
diff --git a/src/soc/amd/common/block/include/amdblocks/BiosCallOuts.h b/src/soc/amd/common/block/include/amdblocks/BiosCallOuts.h
index 34131cf..d317c66 100644
--- a/src/soc/amd/common/block/include/amdblocks/BiosCallOuts.h
+++ b/src/soc/amd/common/block/include/amdblocks/BiosCallOuts.h
@@ -33,6 +33,7 @@
UINT32 NextNodeOffset;
} BIOS_BUFFER_NODE;

+AGESA_STATUS agesa_HeapRebase(UINT32 Func, UINTN Data, VOID *ConfigPtr);
AGESA_STATUS agesa_AllocateBuffer(UINT32 Func, UINTN Data, VOID *ConfigPtr);
AGESA_STATUS agesa_DeallocateBuffer(UINT32 Func, UINTN Data, VOID *ConfigPtr);
AGESA_STATUS agesa_LocateBuffer(UINT32 Func, UINTN Data, VOID *ConfigPtr);
diff --git a/src/soc/amd/common/block/include/amdblocks/agesawrapper.h b/src/soc/amd/common/block/include/amdblocks/agesawrapper.h
index 986d6f8..00452dd4 100644
--- a/src/soc/amd/common/block/include/amdblocks/agesawrapper.h
+++ b/src/soc/amd/common/block/include/amdblocks/agesawrapper.h
@@ -63,4 +63,8 @@
void SetFchMidParams(FCH_INTERFACE *params);
void SetNbMidParams(GNB_MID_CONFIGURATION *params);

+#define AGESA_HEAP_IN_CAR 1
+#define AGESA_HEAP_IN_DRAM 0
+void set_agesa_heap_loc(int premem);
+
#endif /* __AGESAWRAPPER_H__ */
diff --git a/src/soc/amd/common/block/pi/Kconfig b/src/soc/amd/common/block/pi/Kconfig
index bd5926f..5c4a00b 100644
--- a/src/soc/amd/common/block/pi/Kconfig
+++ b/src/soc/amd/common/block/pi/Kconfig
@@ -4,3 +4,32 @@
default n
help
This option builds functions that interface AMD's AGESA.
+
+if SOC_AMD_COMMON_BLOCK_PI
+
+config PI_AGESA_CAR_HEAP_BASE
+ hex
+ default 0x400000
+ help
+ The AGESA PI blob may be built to allow an optional callout for
+ AgesaHeapRebase. If called, this option determines the location
+ for the heap prior to DRAM availability.
+
+config PI_AGESA_CAR_HEAP_SIZE
+ hex
+ default 0x20000
+ help
+ This option determines the amount of space allowed for AGESA heap
+ prior to DRAM availability.
+
+config PI_AGESA_HEAP_SET_MTRR
+ bool
+ default n if PI_AGESA_CAR_HEAP_BASE = 0x400000
+ default y
+ help
+ AGESA is compiled with a default pre-DRAM heap base of 4 MB. It
+ will set a variable MTRR for this range if not overridden by
+ coreboot. If coreboot indicates a heap base of 4MB, AGESA can't
+ detect the override and will still program an MTRR.
+
+endif
diff --git a/src/soc/amd/common/block/pi/def_callouts.c b/src/soc/amd/common/block/pi/def_callouts.c
index beb2d18..bc8a2f6 100644
--- a/src/soc/amd/common/block/pi/def_callouts.c
+++ b/src/soc/amd/common/block/pi/def_callouts.c
@@ -30,6 +30,7 @@
{ AGESA_DO_RESET, agesa_Reset },
{ AGESA_FCH_OEM_CALLOUT, agesa_fch_initreset },
{ AGESA_HALT_THIS_AP, agesa_HaltThisAp },
+ { AGESA_HEAP_REBASE, agesa_HeapRebase },
{ AGESA_GNB_PCIE_SLOT_RESET, agesa_PcieSlotResetControl }
};
#else
@@ -49,6 +50,7 @@
#endif /* ENV_RAMSTAGE */

/* Optional callouts */
+ { AGESA_HEAP_REBASE, agesa_HeapRebase },
{ AGESA_GET_IDS_INIT_DATA, agesa_EmptyIdsInitData },
//AgesaHeapRebase - Hook ID?
{ AGESA_HOOKBEFORE_DRAM_INIT, agesa_NoopUnsupported },
diff --git a/src/soc/amd/common/block/pi/heapmanager.c b/src/soc/amd/common/block/pi/heapmanager.c
index a469a45..5545b00 100644
--- a/src/soc/amd/common/block/pi/heapmanager.c
+++ b/src/soc/amd/common/block/pi/heapmanager.c
@@ -11,7 +11,10 @@
* GNU General Public License for more details.
*/

-
+#include <arch/early_variables.h>
+#include <cpu/x86/msr.h>
+#include <cpu/x86/mtrr.h>
+#include <soc/cpu.h>
#include <amdblocks/agesawrapper.h>
#include <amdlib.h>
#include <arch/acpi.h>
@@ -19,13 +22,38 @@
#include <cbmem.h>
#include <string.h>

+static int use_pre_cbmem_heap CAR_GLOBAL;
+
static void *agesa_heap_base(void)
{
- return cbmem_add(CBMEM_ID_RESUME_SCRATCH, BIOS_HEAP_SIZE);
+ /* todo: remove ENV_BOOTBLOCK when AGESA is out of bootblock */
+ if (ENV_BOOTBLOCK || car_get_var(use_pre_cbmem_heap))
+ return (void *)CONFIG_PI_AGESA_CAR_HEAP_BASE;
+ else
+ return cbmem_add(CBMEM_ID_RESUME_SCRATCH, BIOS_HEAP_SIZE);
+}
+
+/* Setting is 0 automatically. No need to initialize with AGESA_HEAP_IN_DRAM. */
+void set_agesa_heap_loc(int loc)
+{
+ msr_t mtrr_cap = rdmsr(MTRR_CAP_MSR);
+ int mtrr;
+
+ car_set_var(use_pre_cbmem_heap, loc);
+ if (loc == AGESA_HEAP_IN_DRAM)
+ return;
+
+ if (!IS_ENABLED(CONFIG_PI_AGESA_HEAP_SET_MTRR))
+ return;
+
+ mtrr = (mtrr_cap.lo & MTRR_CAP_VCNT) - SOC_EARLY_VMTRR_AGESA_HEAP;
+ set_var_mtrr(mtrr, CONFIG_PI_AGESA_CAR_HEAP_BASE,
+ CONFIG_PI_AGESA_CAR_HEAP_SIZE, MTRR_TYPE_WRBACK);
}

static void EmptyHeap(int unused)
{
+ set_agesa_heap_loc(AGESA_HEAP_IN_DRAM);
void *BiosManagerPtr = agesa_heap_base();
memset(BiosManagerPtr, 0, BIOS_HEAP_SIZE);
}
@@ -35,6 +63,21 @@
#endif
ROMSTAGE_CBMEM_INIT_HOOK(EmptyHeap)

+AGESA_STATUS agesa_HeapRebase(UINT32 Func, UINTN Data, VOID *ConfigPtr)
+{
+ AGESA_REBASE_PARAMS *RebaseParams;
+
+ RebaseParams = (AGESA_REBASE_PARAMS *)ConfigPtr;
+ RebaseParams->HeapAddress = (UINTN)agesa_heap_base();
+
+ if (RebaseParams->HeapAddress) {
+ return AGESA_SUCCESS;
+ } else {
+ printk(BIOS_ERR, "Error: AGESA heap has no base\n");
+ return AGESA_ERROR;
+ }
+}
+
AGESA_STATUS agesa_AllocateBuffer (UINT32 Func, UINTN Data, VOID *ConfigPtr)
{
UINT32 AvailableHeapSize;
diff --git a/src/soc/amd/stoneyridge/bootblock/bootblock.c b/src/soc/amd/stoneyridge/bootblock/bootblock.c
index db5c9b6..6fa9239 100644
--- a/src/soc/amd/stoneyridge/bootblock/bootblock.c
+++ b/src/soc/amd/stoneyridge/bootblock/bootblock.c
@@ -121,6 +121,8 @@
if (boot_cpu() && IS_ENABLED(CONFIG_SOC_AMD_PSP_SELECTABLE_SMU_FW))
load_smu_fw1();

+ set_agesa_heap_loc(AGESA_HEAP_IN_CAR);
+
post_code(0x37);
do_agesawrapper(agesawrapper_amdinitreset, "amdinitreset");

diff --git a/src/soc/amd/stoneyridge/include/soc/cpu.h b/src/soc/amd/stoneyridge/include/soc/cpu.h
index bf8ed49..d4acae7 100644
--- a/src/soc/amd/stoneyridge/include/soc/cpu.h
+++ b/src/soc/amd/stoneyridge/include/soc/cpu.h
@@ -26,6 +26,7 @@
* todo: Revisit this once AGESA no longer programs MTRRs.
*/
#define SOC_EARLY_VMTRR_FLASH 2
+#define SOC_EARLY_VMTRR_AGESA_HEAP 1

void stoney_init_cpus(struct device *dev);

diff --git a/src/soc/amd/stoneyridge/romstage.c b/src/soc/amd/stoneyridge/romstage.c
index 490fd9e..fc50d98 100644
--- a/src/soc/amd/stoneyridge/romstage.c
+++ b/src/soc/amd/stoneyridge/romstage.c
@@ -47,6 +47,8 @@

console_init();

+ set_agesa_heap_loc(AGESA_HEAP_IN_CAR); /* Re-init for romstage */
+
if (!s3_resume) {
post_code(0x40);
do_agesawrapper(agesawrapper_amdinitpost, "amdinitpost");

To view, visit change 25458. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ieda202a6064302b21707bd7ddfabc132cd85ed45
Gerrit-Change-Number: 25458
Gerrit-PatchSet: 1
Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com>