AMD (K8/fam10): Rewrite CAR migration in post_cache_as_ram
Old routine copied all of CAR region as-is right below CONFIG_RAMTOP.
Most of this region was reserved to interleave AP CPU address spaces
and unused on BSP CPU. The only part of CAR region requiring a copy
in RAM is the sysinfo structure.
Improved routine changes this as follows:
A region of size 'backup_size' below CONFIG_RAMTOP is cleared. In
case of S3 resume, OS context from this region is first copied to
high memory (CBMEM_ID_RESUME).
At stack switch, CAR stack is discarded. Top of the stack for BSP
is located at 'CONFIG_RAMTOP - car_size' for the remaining part
of the romstage. This region is part of 'backup_size' and was zeroed
before the switch took place.
Before CAR is torn down the region of CAR_GLOBALS (and CAR_CBMEM),
including the relevant sysinfo data for AP nodes memory training,
is copied at 'CONFIG_RAMTOP - car_size'.
NOTE: While CAR_GLOBAL variables are recovered, there are currently
no means to calculate their offsets in RAM.
NOTE: Boards with multiple CPU packages are likely already broken since
bbc880ee
amdk8/amdfam10: Use CAR_GLOBAL for sysinfo
This moved the copy of sysinfo in RAM from above the stack to below
the stack, but code for AP CPU's was not adjusted accordingly.
Change-Id: Ie45b576aec6a2e006bfcb26b52fdb77c24f72e3b
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/4583
Tested-by: build bot (Jenkins)
Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com>
This commit is contained in:
parent
3eefeea9d5
commit
abc083e06b
|
@ -424,10 +424,9 @@ CAR_FAM10_ap_out:
|
||||||
cache_as_ram_switch_stack:
|
cache_as_ram_switch_stack:
|
||||||
/* Return address. */
|
/* Return address. */
|
||||||
popl %eax
|
popl %eax
|
||||||
/* Resume memory. */
|
/* New stack. */
|
||||||
popl %eax
|
popl %eax
|
||||||
subl $(( (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)- (CONFIG_RAMTOP) )), %esp
|
movl %eax, %esp
|
||||||
pushl %eax
|
|
||||||
call cache_as_ram_new_stack
|
call cache_as_ram_new_stack
|
||||||
|
|
||||||
all_mtrr_msrs:
|
all_mtrr_msrs:
|
||||||
|
|
|
@ -10,58 +10,78 @@
|
||||||
#include "cbmem.h"
|
#include "cbmem.h"
|
||||||
#include "cpu/amd/car/disable_cache_as_ram.c"
|
#include "cpu/amd/car/disable_cache_as_ram.c"
|
||||||
|
|
||||||
static inline void print_debug_pcar(const char *strval, uint32_t val)
|
#if CONFIG_RAMTOP <= 0x100000
|
||||||
|
#error "You need to set CONFIG_RAMTOP greater than 1M"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRINTK_IN_CAR 1
|
||||||
|
|
||||||
|
#if PRINTK_IN_CAR
|
||||||
|
#define print_car_debug(x) print_debug(x)
|
||||||
|
#else
|
||||||
|
#define print_car_debug(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern char _car_data_start[];
|
||||||
|
extern char _car_data_end[];
|
||||||
|
|
||||||
|
static size_t car_data_size(void)
|
||||||
{
|
{
|
||||||
printk(BIOS_DEBUG, "%s%08x\n", strval, val);
|
size_t car_size = &_car_data_end[0] - &_car_data_start[0];
|
||||||
|
return ALIGN(car_size, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from linux kernel 2.6.32 asm/string_32.h */
|
static size_t backup_size(void)
|
||||||
|
|
||||||
static void inline __attribute__((always_inline)) memcopy(void *dest, const void *src, unsigned long bytes)
|
|
||||||
{
|
{
|
||||||
int d0, d1, d2;
|
size_t car_size = &_car_data_end[0] - &_car_data_start[0];
|
||||||
asm volatile("cld ; rep ; movsl\n\t"
|
return ALIGN(car_size + 1024, 1024);
|
||||||
"movl %4,%%ecx\n\t"
|
|
||||||
"andl $3,%%ecx\n\t"
|
|
||||||
"jz 1f\n\t"
|
|
||||||
"rep ; movsb\n\t"
|
|
||||||
"1:"
|
|
||||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
|
|
||||||
: "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src)
|
|
||||||
: "memory", "cc");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
static void memcpy_(void *d, const void *s, size_t len)
|
||||||
|
{
|
||||||
|
#if PRINTK_IN_CAR
|
||||||
|
printk(BIOS_SPEW, " Copy [%08x-%08x] to [%08x - %08x] ... ",
|
||||||
|
(u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1));
|
||||||
|
#endif
|
||||||
|
memcpy(d, s, len);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void *backup_resume(void) {
|
static void memset_(void *d, int val, size_t len)
|
||||||
void *resume_backup_memory;
|
{
|
||||||
int suspend = acpi_is_wakeup_early();
|
#if PRINTK_IN_CAR
|
||||||
|
printk(BIOS_SPEW, " Fill [%08x-%08x] ... ", (u32) d, (u32) (d + len - 1));
|
||||||
|
#endif
|
||||||
|
memset(d, val, len);
|
||||||
|
}
|
||||||
|
|
||||||
if (!suspend)
|
static void prepare_romstage_ramstack(void *resume_backup_memory)
|
||||||
return NULL;
|
{
|
||||||
|
size_t backup_top = backup_size();
|
||||||
if (cbmem_recovery(1))
|
print_car_debug("Prepare CAR migration and stack regions...");
|
||||||
return NULL;
|
|
||||||
|
|
||||||
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
|
|
||||||
|
|
||||||
/* copy 1MB - 64K to high tables ram_base to prevent memory corruption
|
|
||||||
* through stage 2. We could keep stuff like stack and heap in high tables
|
|
||||||
* memory completely, but that's a wonderful clean up task for another
|
|
||||||
* day.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (resume_backup_memory) {
|
if (resume_backup_memory) {
|
||||||
print_debug_pcar("Will copy coreboot region to: ", (uint32_t) resume_backup_memory);
|
memcpy_(resume_backup_memory + HIGH_MEMORY_SAVE - backup_top,
|
||||||
/* copy only backup only memory used for CAR */
|
(void *)(CONFIG_RAMTOP - backup_top), backup_top);
|
||||||
memcopy(resume_backup_memory+HIGH_MEMORY_SAVE-CONFIG_DCACHE_RAM_SIZE,
|
}
|
||||||
(void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE),
|
memset_((void *)(CONFIG_RAMTOP - backup_top), 0, backup_top);
|
||||||
CONFIG_DCACHE_RAM_SIZE); //inline
|
|
||||||
|
print_car_debug("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_ramstage_region(void *resume_backup_memory)
|
||||||
|
{
|
||||||
|
size_t backup_top = backup_size();
|
||||||
|
print_car_debug("Prepare ramstage memory region... ");
|
||||||
|
|
||||||
|
if (resume_backup_memory) {
|
||||||
|
memcpy_(resume_backup_memory, (void *) CONFIG_RAMBASE, HIGH_MEMORY_SAVE - backup_top);
|
||||||
|
memset_((void*) CONFIG_RAMBASE, 0, HIGH_MEMORY_SAVE - backup_top);
|
||||||
|
} else {
|
||||||
|
memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resume_backup_memory;
|
print_car_debug("Done\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
|
/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
|
||||||
|
|
||||||
|
@ -80,73 +100,53 @@ static void vErrata343(void)
|
||||||
void post_cache_as_ram(void)
|
void post_cache_as_ram(void)
|
||||||
{
|
{
|
||||||
void *resume_backup_memory = NULL;
|
void *resume_backup_memory = NULL;
|
||||||
#if 1
|
|
||||||
{
|
int s3resume = acpi_s3_resume_allowed() && acpi_is_wakeup_early();
|
||||||
/* Check value of esp to verify if we have enough room for stack in Cache as RAM */
|
if (s3resume) {
|
||||||
unsigned v_esp;
|
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
|
||||||
__asm__ volatile (
|
cbmem_recovery(s3resume);
|
||||||
"movl %%esp, %0\n\t"
|
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
|
||||||
: "=a" (v_esp)
|
#endif
|
||||||
);
|
|
||||||
print_debug_pcar("v_esp=", v_esp);
|
|
||||||
}
|
}
|
||||||
#endif
|
prepare_romstage_ramstack(resume_backup_memory);
|
||||||
|
|
||||||
/* copy data from cache as ram to
|
|
||||||
ram need to set CONFIG_RAMTOP to 2M and use var mtrr instead.
|
|
||||||
*/
|
|
||||||
#if CONFIG_RAMTOP <= 0x100000
|
|
||||||
#error "You need to set CONFIG_RAMTOP greater than 1M"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
|
||||||
resume_backup_memory = backup_resume();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
print_debug("Copying data from cache to RAM -- switching to use RAM as stack... ");
|
|
||||||
|
|
||||||
/* from here don't store more data in CAR */
|
/* from here don't store more data in CAR */
|
||||||
vErrata343();
|
vErrata343();
|
||||||
|
|
||||||
memcopy((void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), (void *)CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); //inline
|
size_t car_size = car_data_size();
|
||||||
cache_as_ram_switch_stack(resume_backup_memory);
|
void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
|
||||||
|
|
||||||
|
print_car_debug("Copying data from cache to RAM... ");
|
||||||
|
memcpy_(migrated_car, &_car_data_start[0], car_size);
|
||||||
|
print_car_debug("Done\n");
|
||||||
|
|
||||||
|
/* New stack grows right below migrated_car. */
|
||||||
|
print_car_debug("Switching to use RAM as stack... ");
|
||||||
|
cache_as_ram_switch_stack(migrated_car);
|
||||||
|
|
||||||
|
/* We do not come back. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void cache_as_ram_new_stack (void)
|
||||||
cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused)))
|
|
||||||
{
|
{
|
||||||
/* We can put data to stack again */
|
void *resume_backup_memory = NULL;
|
||||||
|
|
||||||
/* only global variable sysinfo in cache need to be offset */
|
|
||||||
print_debug("Done\n");
|
|
||||||
|
|
||||||
print_debug("Disabling cache as ram now \n");
|
|
||||||
|
|
||||||
|
#if PRINTK_IN_CAR
|
||||||
|
printk(BIOS_DEBUG, "Top about %08x ... Done\n", (u32) &resume_backup_memory);
|
||||||
|
#endif
|
||||||
|
print_car_debug("Disabling cache as ram now\n");
|
||||||
disable_cache_as_ram_bsp();
|
disable_cache_as_ram_bsp();
|
||||||
|
|
||||||
disable_cache();
|
disable_cache();
|
||||||
set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
|
set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
|
||||||
enable_cache();
|
enable_cache();
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
if (acpi_s3_resume_allowed() && acpi_is_wakeup_early()) {
|
||||||
/* now copy the rest of the area, using the WB method because we already
|
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
|
||||||
run normal RAM */
|
resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
|
||||||
if (resume_backup_memory) {
|
#endif
|
||||||
memcopy(resume_backup_memory,
|
|
||||||
(void *)(CONFIG_RAMBASE),
|
|
||||||
(CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
|
|
||||||
}
|
}
|
||||||
#endif
|
prepare_ramstage_region(resume_backup_memory);
|
||||||
|
|
||||||
print_debug("Clearing initial memory region: ");
|
|
||||||
|
|
||||||
#if CONFIG_HAVE_ACPI_RESUME
|
|
||||||
/* clear only coreboot used region of memory. Note: this may break ECC enabled boards */
|
|
||||||
memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
|
|
||||||
#else
|
|
||||||
memset((void*)0, 0, ((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_SIZE));
|
|
||||||
#endif
|
|
||||||
print_debug("Done\n");
|
|
||||||
|
|
||||||
set_sysinfo_in_ram(1); // So other core0 could start to train mem
|
set_sysinfo_in_ram(1); // So other core0 could start to train mem
|
||||||
|
|
||||||
|
@ -154,5 +154,5 @@ cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused)))
|
||||||
copy_and_run();
|
copy_and_run();
|
||||||
/* We will not return */
|
/* We will not return */
|
||||||
|
|
||||||
print_debug("should not be here -\n");
|
print_car_debug("should not be here -\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx);
|
||||||
void done_cache_as_ram_main(void);
|
void done_cache_as_ram_main(void);
|
||||||
void post_cache_as_ram(void);
|
void post_cache_as_ram(void);
|
||||||
|
|
||||||
void cache_as_ram_switch_stack(void *resume_backup_memory);
|
void cache_as_ram_switch_stack(void *stacktop);
|
||||||
void cache_as_ram_new_stack(void *resume_backup_memory);
|
void cache_as_ram_new_stack(void);
|
||||||
|
|
||||||
#if CONFIG_CPU_AMD_AGESA
|
#if CONFIG_CPU_AMD_AGESA
|
||||||
void disable_cache_as_ram(void);
|
void disable_cache_as_ram(void);
|
||||||
|
|
Loading…
Reference in New Issue