From patchwork Sun Apr 25 22:41:28 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: WIP - suspend/resume on AMD64 using CBMEM Date: Sun, 25 Apr 2010 22:41:28 -0000 From: Rudolf Marek X-Patchwork-Id: 1266 Message-Id: <4BD4C518.2090902@assembler.cz> To: Coreboot -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello, Attached patch implements again suspend/resume without reserved memory. The RAMBASE-RAMTOP is backuped to cbmem as ID_SUSPEND/RESUME and then before jumping to OS restore orig mem data again. I have a question regarding the size of HIGH tables memory and the size of CBMEM. Most NB have it hardcoded for high tables - perhaps it is time to fix it too? The problem with the CBMEM toc location was solved using the NVRAM for data pointer. I think when this patch is in good shape, one can try to get Suspend/Resume working on SB710/RS785. I tested Windows 7 (the build 7100?) and linux - both resumed from suspend ;) Any comments? Rudolf -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkvUxRcACgkQ3J9wPJqZRNX5zwCeKIGdBWrmqzz+lrpFyNG0fELO 6O0AoOLwo9/rF17q6rji8K4ycs0hEW3S =Otx4 -----END PGP SIGNATURE----- Index: src/southbridge/via/vt8237r/vt8237r_early_smbus.c =================================================================== --- src/southbridge/via/vt8237r/vt8237r_early_smbus.c (revision 5492) +++ src/southbridge/via/vt8237r/vt8237r_early_smbus.c (working copy) @@ -295,8 +295,7 @@ pci_write_config8(dev, 0x41, 0x7f); } -#ifdef CONFIG_NORTHBRIDGE_AMD_K8 /* CN700 doesn't have the support yet */ -#define ACPI_IS_WAKEUP_EARLY 1 +//#ifdef CONFIG_NORTHBRIDGE_AMD_K8 /* CN700 doesn't have the support yet */ static int acpi_is_wakeup_early(void) { device_t dev; @@ -326,7 +325,7 @@ print_debug_hex8(tmp); return ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0 ; } -#endif +//#endif #if defined(__GNUC__) void vt8237_early_spi_init(void) Index: src/southbridge/via/k8t890/k8t890.h =================================================================== --- src/southbridge/via/k8t890/k8t890.h (revision 5493) +++ src/southbridge/via/k8t890/k8t890.h (working copy) @@ -31,6 +31,7 @@ /* The 256 bytes of NVRAM for S3 storage, 256B aligned */ #define K8T890_NVRAM_IO_BASE 0xf00 +#define K8T890_NVRAM_CBMEM_TOC 0xfc #define K8T890_MMCONFIG_MBAR 0x61 #define K8T890_MULTIPLE_FN_EN 0x4f Index: src/southbridge/via/k8t890/k8t890_early_car.c =================================================================== --- src/southbridge/via/k8t890/k8t890_early_car.c (revision 5493) +++ src/southbridge/via/k8t890/k8t890_early_car.c (working copy) @@ -23,6 +23,8 @@ */ #include +#include +#include #include "k8t890.h" /* The 256 bytes of NVRAM for S3 storage, 256B aligned */ @@ -155,3 +157,11 @@ printk(BIOS_DEBUG, "Loading %x of size %d to nvram pos:%d\n", * old_dword, size, nvram_pos-size); return nvram_pos; } + +struct cbmem_entry *get_cbmem_toc(void) { + return (struct cbmem_entry *) inl(K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC); +} + +void set_cbmem_toc(struct cbmem_entry *toc) { + outl((u32) toc, K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC); +} Index: src/southbridge/via/k8t890/k8t890_host_ctrl.c =================================================================== --- src/southbridge/via/k8t890/k8t890_host_ctrl.c (revision 5493) +++ src/southbridge/via/k8t890/k8t890_host_ctrl.c (working copy) @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "k8t890.h" /* this may be later merged */ @@ -112,6 +114,14 @@ } +struct cbmem_entry *get_cbmem_toc(void) { + return (struct cbmem_entry *) inl(K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC); +} + +void set_cbmem_toc(struct cbmem_entry *toc) { + outl((u32) toc, K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC); +} + static const struct device_operations host_ctrl_ops_t = { .read_resources = pci_dev_read_resources, .set_resources = pci_dev_set_resources, Index: src/include/cbmem.h =================================================================== --- src/include/cbmem.h (revision 5492) +++ src/include/cbmem.h (working copy) @@ -24,7 +24,7 @@ #define HIGH_MEMORY_TABLES ( 64 * 1024 ) #if CONFIG_HAVE_ACPI_RESUME -#define HIGH_MEMORY_SIZE ( 1024 * 1024 ) +#define HIGH_MEMORY_SIZE ((CONFIG_RAMTOP - CONFIG_RAMBASE) + HIGH_MEMORY_TABLES) #define HIGH_MEMORY_SAVE ( HIGH_MEMORY_SIZE - HIGH_MEMORY_TABLES ) #else #define HIGH_MEMORY_SIZE HIGH_MEMORY_TABLES @@ -48,4 +48,9 @@ void cbmem_list(void); void cbmem_arch_init(void); +struct cbmem_entry *get_cbmem_toc(void); +void set_cbmem_toc(struct cbmem_entry *); + + + #endif Index: src/cpu/amd/car/post_cache_as_ram.c =================================================================== --- src/cpu/amd/car/post_cache_as_ram.c (revision 5492) +++ src/cpu/amd/car/post_cache_as_ram.c (working copy) @@ -4,6 +4,11 @@ #include #include "cpu/amd/car/disable_cache_as_ram.c" + unsigned int range_to_mtrr(unsigned int reg, + unsigned long range_startk, unsigned long range_sizek, + unsigned long next_range_startk, unsigned char type, unsigned address_bits); + + static inline void print_debug_pcar(const char *strval, uint32_t val) { printk(BIOS_DEBUG, "%s%08x\n", strval, val); @@ -24,6 +29,58 @@ : "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src) : "memory", "cc"); } + +#if CONFIG_HAVE_ACPI_RESUME + +static inline void *backup_resume(void) { + msr_t msr; + int megs = 1; + unsigned long high_ram_base; + void *resume_backup_memory; +#ifdef ACPI_IS_WAKEUP_EARLY + int suspend = acpi_is_wakeup_early(); +#else + int suspend = 0; +#endif + if (!suspend) + return NULL; + + + /* Start address of high memory tables */ + high_ram_base = (u32) get_cbmem_toc(); + + print_debug_pcar("CBMEM TOC is at: ", high_ram_base); + msr = rdmsr(TOP_MEM); + range_to_mtrr(0, 0, msr.lo >> 10, 0, MTRR_TYPE_UNCACHEABLE, 40); + + +// set_var_mtrr(0, 0x00000000, (high_ram_base + HIGH_MEMORY_SIZE + 4096) / 1024 , MTRR_TYPE_UNCACHEABLE); +// range_to_mtrr(0, 0, (high_ram_base + HIGH_MEMORY_SIZE + 4096) / 1024 , 0, MTRR_TYPE_UNCACHEABLE, 40); + + print_debug_pcar("CBMEM TOC 0-size: ", high_ram_base + HIGH_MEMORY_SIZE + 4096); + + cbmem_reinit((u64)high_ram_base); + + 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) { + print_debug_pcar("Will copy coreboot region to: ", 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 + } + + return resume_backup_memory; +} +#endif + /* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */ static void vErrata343(void) @@ -40,7 +97,8 @@ static void post_cache_as_ram(void) { - + void *resume_backup_memory; + msr_t msr; #if 1 { /* Check value of esp to verify if we have enough rom for stack in Cache as RAM */ @@ -63,8 +121,11 @@ #error "You need to set CONFIG_RAMTOP greater than 1M" #endif +#if CONFIG_HAVE_ACPI_RESUME + resume_backup_memory = backup_resume(); +#endif /* So we can access RAM from [1M, CONFIG_RAMTOP) */ - set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); + set_var_mtrr(0, 0x00000000, (CONFIG_RAMTOP >> 10), MTRR_TYPE_WRBACK); // dump_mem(CONFIG_DCACHE_RAM_BASE+CONFIG_DCACHE_RAM_SIZE-0x8000, CONFIG_DCACHE_RAM_BASE+CONFIG_DCACHE_RAM_SIZE-0x7c00); print_debug("Copying data from cache to RAM -- switching to use RAM as stack... "); @@ -93,6 +154,20 @@ print_debug("Disabling cache as ram now \n"); disable_cache_as_ram_bsp(); +#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) { + msr = rdmsr(TOP_MEM); + range_to_mtrr(0, 0, msr.lo >>10 , 0, MTRR_TYPE_WRBACK, 40); +// set_var_mtrr(0, 0x00000000, ((u32)resume_backup_memory + HIGH_MEMORY_SIZE + 4096) / 1024, MTRR_TYPE_WRBACK); + + memcopy(resume_backup_memory, + (void *)(CONFIG_RAMBASE), + (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE); + } +#endif + print_debug("Clearing initial memory region: "); #if CONFIG_HAVE_ACPI_RESUME == 1 /* clear only coreboot used region of memory. Note: this may break ECC enabled boards */ Index: src/mainboard/asus/m2v-mx_se/Kconfig =================================================================== --- src/mainboard/asus/m2v-mx_se/Kconfig (revision 5492) +++ src/mainboard/asus/m2v-mx_se/Kconfig (working copy) @@ -34,6 +34,7 @@ select BOARD_ROMSIZE_KB_512 select VGA select TINY_BOOTBLOCK + select HAVE_ACPI_RESUME select HAVE_MAINBOARD_RESOURCES config MAINBOARD_DIR Index: src/mainboard/asus/m2v-mx_se/romstage.c =================================================================== --- src/mainboard/asus/m2v-mx_se/romstage.c (revision 5492) +++ src/mainboard/asus/m2v-mx_se/romstage.c (working copy) @@ -23,6 +23,7 @@ */ #define RAMINIT_SYSINFO 1 +#define ACPI_IS_WAKEUP_EARLY 1 #define CACHE_AS_RAM_ADDRESS_DEBUG 0 @@ -100,6 +101,15 @@ #define SB_VFSMAF 0 + +// Now, this needs to be included because it relies on the symbol +// __PRE_RAM__ being set during CAR stage (in order to compile the +// BSS free versions of the functions). Either rewrite the code +// to be always BSS free, or invent a flag that's better suited than +// __PRE_RAM__ to determine whether we're in ram init stage (stage 1) +// +#include "lib/cbmem.c" + /* this function might fail on some K8 CPUs with errata #181 */ static void ldtstop_sb(void) { Index: src/mainboard/asus/m2v-mx_se/mainboard.c =================================================================== --- src/mainboard/asus/m2v-mx_se/mainboard.c (revision 5494) +++ src/mainboard/asus/m2v-mx_se/mainboard.c (working copy) @@ -49,8 +49,6 @@ #if CONFIG_HAVE_ACPI_RESUME == 1 lb_add_memory_range(mem, LB_MEM_RESERVED, - CONFIG_RAMBASE, ((CONFIG_RAMTOP) - CONFIG_RAMBASE)); - lb_add_memory_range(mem, LB_MEM_RESERVED, CONFIG_DCACHE_RAM_BASE, CONFIG_DCACHE_RAM_SIZE); #endif return 0; Index: src/lib/cbmem.c =================================================================== --- src/lib/cbmem.c (revision 5492) +++ src/lib/cbmem.c (working copy) @@ -46,7 +46,9 @@ struct cbmem_entry *bss_cbmem_toc; #define get_cbmem_toc() bss_cbmem_toc #else -#define get_cbmem_toc() (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE) + +//#define get_cbmem_toc() (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE) + #endif /** @@ -75,6 +77,8 @@ for (;;) ; } + set_cbmem_toc(baseaddr); + memset(cbmem_toc, 0, CBMEM_TOC_RESERVED); cbmem_toc[0] = (struct cbmem_entry) { Index: src/northbridge/amd/amdk8/northbridge.c =================================================================== --- src/northbridge/amd/amdk8/northbridge.c (revision 5492) +++ src/northbridge/amd/amdk8/northbridge.c (working copy) @@ -835,7 +835,10 @@ #endif #if CONFIG_WRITE_HIGH_TABLES==1 -#define HIGH_TABLES_SIZE 64 // maximum size of high tables in KB +//fixme? +#include +#define HIGH_TABLES_SIZE ((HIGH_MEMORY_SIZE + 1024) / 1024) + extern uint64_t high_tables_base, high_tables_size; #if CONFIG_GFXUMA == 1 extern uint64_t uma_memory_base, uma_memory_size; Index: src/northbridge/amd/amdk8/raminit_f_dqs.c =================================================================== --- src/northbridge/amd/amdk8/raminit_f_dqs.c (revision 5492) +++ src/northbridge/amd/amdk8/raminit_f_dqs.c (working copy) @@ -1684,7 +1684,7 @@ return r; } -static unsigned int range_to_mtrr(unsigned int reg, + unsigned int range_to_mtrr(unsigned int reg, unsigned long range_startk, unsigned long range_sizek, unsigned long next_range_startk, unsigned char type, unsigned address_bits) { @@ -1701,13 +1701,13 @@ align = max_align; } sizek = 1 << align; -#if CONFIG_MEM_TRAIN_SEQ != 1 +//#if CONFIG_MEM_TRAIN_SEQ != 1 printk(BIOS_DEBUG, "Setting variable MTRR %d, base: %4ldMB, range: %4ldMB, type %s\n", reg, range_startk >>10, sizek >> 10, (type==MTRR_TYPE_UNCACHEABLE)?"UC": ((type==MTRR_TYPE_WRBACK)?"WB":"Other") ); -#endif +//#endif set_var_mtrr_dqs(reg++, range_startk, sizek, type, address_bits); range_startk += sizek; range_sizek -= sizek; Index: src/arch/i386/boot/tables.c =================================================================== --- src/arch/i386/boot/tables.c (revision 5492) +++ src/arch/i386/boot/tables.c (working copy) @@ -221,7 +221,7 @@ * it begin there during reboot time. We don't need the pointer, nor * the result right now. If it fails, ACPI resume will be disabled. */ - cbmem_add(CBMEM_ID_RESUME, 1024 * (1024-64)); + cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE); #endif // Remove before sending upstream