Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4583
-gerrit
commit 28237b76dbf9596f82151dbc36d38e1b1593b9a0 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Sun Dec 29 12:07:54 2013 +0200
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'.
Change-Id: Ie45b576aec6a2e006bfcb26b52fdb77c24f72e3b Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- src/cpu/amd/car/cache_as_ram.inc | 5 +- src/cpu/amd/car/post_cache_as_ram.c | 176 ++++++++++++++++++------------------ src/include/cpu/amd/car.h | 4 +- 3 files changed, 92 insertions(+), 93 deletions(-)
diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc index dd02f6c..dadf8f7 100644 --- a/src/cpu/amd/car/cache_as_ram.inc +++ b/src/cpu/amd/car/cache_as_ram.inc @@ -424,10 +424,9 @@ CAR_FAM10_ap_out: cache_as_ram_switch_stack: /* Return address. */ popl %eax - /* Resume memory. */ + /* New stack. */ popl %eax - subl $(( (CONFIG_DCACHE_RAM_BASE + CONFIG_DCACHE_RAM_SIZE)- (CONFIG_RAMTOP) )), %esp - pushl %eax + movl %eax, %esp call cache_as_ram_new_stack
all_mtrr_msrs: diff --git a/src/cpu/amd/car/post_cache_as_ram.c b/src/cpu/amd/car/post_cache_as_ram.c index 51caec5..2321f11 100644 --- a/src/cpu/amd/car/post_cache_as_ram.c +++ b/src/cpu/amd/car/post_cache_as_ram.c @@ -9,58 +9,78 @@ #include "cbmem.h" #include "cpu/amd/car/disable_cache_as_ram.c"
-static inline void print_debug_pcar(const char *strval, uint32_t val) -{ - printk(BIOS_DEBUG, "%s%08x\n", strval, val); -} +#if CONFIG_RAMTOP <= 0x100000 + #error "You need to set CONFIG_RAMTOP greater than 1M" +#endif
-/* from linux kernel 2.6.32 asm/string_32.h */ +#define PRINTK_IN_CAR 1
-static void inline __attribute__((always_inline)) memcopy(void *dest, const void *src, unsigned long bytes) -{ - int d0, d1, d2; - asm volatile("cld ; rep ; movsl\n\t" - "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 +#if PRINTK_IN_CAR +#define print_car_debug(x) print_debug(x) +#else +#define print_car_debug(x) +#endif
-static inline void *backup_resume(void) { - void *resume_backup_memory; - int suspend = acpi_is_wakeup_early(); +extern char _car_data_start[]; +extern char _car_data_end[];
- if (!suspend) - return NULL; +static size_t car_data_size(void) +{ + size_t car_size = &_car_data_end[0] - &_car_data_start[0]; + return ALIGN(car_size, 64); +}
- if (cbmem_recovery(1)) - return NULL; +static size_t backup_size(void) +{ + size_t car_size = &_car_data_end[0] - &_car_data_start[0]; + return ALIGN(car_size + 1024, 1024); +}
- resume_backup_memory = cbmem_find(CBMEM_ID_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); +}
- /* 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. - */ +static void memset_(void *d, int val, size_t len) +{ +#if PRINTK_IN_CAR + printk(BIOS_SPEW, " Fill [%08x-%08x] ... ", (u32) d, (u32) (d + len - 1)); +#endif + memset(d, val, len); +}
+static void prepare_romstage_ramstack(void *resume_backup_memory) +{ + size_t backup_top = backup_size(); + print_car_debug("Prepare CAR migration and stack regions..."); +#if CONFIG_HAVE_ACPI_RESUME if (resume_backup_memory) { - print_debug_pcar("Will copy coreboot region to: ", (uint32_t) resume_backup_memory); - /* copy only backup only memory used for CAR */ - memcopy(resume_backup_memory+HIGH_MEMORY_SAVE-CONFIG_DCACHE_RAM_SIZE, - (void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), - CONFIG_DCACHE_RAM_SIZE); //inline + memcpy_(resume_backup_memory + HIGH_MEMORY_SAVE - backup_top, + (void *)(CONFIG_RAMTOP - backup_top), backup_top); } - - return resume_backup_memory; +#endif + memset_((void *)(CONFIG_RAMTOP - backup_top), 0, backup_top); + 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 CONFIG_HAVE_ACPI_RESUME + 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); + } #endif + if (!resume_backup_memory) + memset_((void*)0, 0, CONFIG_RAMTOP - backup_top); + print_car_debug("Done\n"); +}
/* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
@@ -79,48 +99,41 @@ static void vErrata343(void) void post_cache_as_ram(void) { void *resume_backup_memory = NULL; -#if 1 - { - /* Check value of esp to verify if we have enough room for stack in Cache as RAM */ - unsigned v_esp; - __asm__ volatile ( - "movl %%esp, %0\n\t" - : "=a" (v_esp) - ); - print_debug_pcar("v_esp=", v_esp); - } -#endif - - /* 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(); + int s3resume = acpi_is_wakeup_early(); + if (s3resume) { + cbmem_recovery(s3resume); + resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); + } #endif - - print_debug("Copying data from cache to RAM -- switching to use RAM as stack... "); + prepare_romstage_ramstack(resume_backup_memory);
/* from here don't store more data in CAR */ vErrata343();
- memcopy((void *)((CONFIG_RAMTOP)-CONFIG_DCACHE_RAM_SIZE), (void *)CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); //inline - cache_as_ram_switch_stack(resume_backup_memory); -} + size_t car_size = car_data_size(); + void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
-void -cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused))) -{ - /* We can put data to stack again */ + print_car_debug("Copying data from cache to RAM... "); + memcpy_(migrated_car, &_car_data_start[0], car_size); + print_car_debug("Done\n");
- /* only global variable sysinfo in cache need to be offset */ - print_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);
- print_debug("Disabling cache as ram now \n"); + /* We do not come back. */ +}
+void cache_as_ram_new_stack (void) +{ + void *resume_backup_memory = NULL; + +#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(); @@ -128,24 +141,11 @@ cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused))) enable_cache();
#if CONFIG_HAVE_ACPI_RESUME - /* now copy the rest of the area, using the WB method because we already - run normal RAM */ - if (resume_backup_memory) { - memcopy(resume_backup_memory, - (void *)(CONFIG_RAMBASE), - (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE); + if (acpi_is_wakeup_early()) { + resume_backup_memory = cbmem_find(CBMEM_ID_RESUME); } #endif - - 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"); + prepare_ramstage_region(resume_backup_memory);
set_sysinfo_in_ram(1); // So other core0 could start to train mem
@@ -153,5 +153,5 @@ cache_as_ram_new_stack (void *resume_backup_memory __attribute__ ((unused))) copy_and_run(); /* We will not return */
- print_debug("should not be here -\n"); + print_car_debug("should not be here -\n"); } diff --git a/src/include/cpu/amd/car.h b/src/include/cpu/amd/car.h index a001c93..c00310a 100644 --- a/src/include/cpu/amd/car.h +++ b/src/include/cpu/amd/car.h @@ -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 post_cache_as_ram(void);
-void cache_as_ram_switch_stack(void *resume_backup_memory); -void cache_as_ram_new_stack(void *resume_backup_memory); +void cache_as_ram_switch_stack(void *stacktop); +void cache_as_ram_new_stack(void);
#if CONFIG_CPU_AMD_AGESA void disable_cache_as_ram(void);