1) wraps the s3 parts of chipset code/memory init code with if CONFIG_HAVE_ACPI_RESUM...
authorRudolf Marek <r.marek@assembler.cz>
Mon, 22 Nov 2010 22:00:52 +0000 (22:00 +0000)
committerRudolf Marek <r.marek@assembler.cz>
Mon, 22 Nov 2010 22:00:52 +0000 (22:00 +0000)
2) the patch implements get_cbmem_toc in chipset specific way if defined.
On Intel targets it should be unchanged. On K8T890 the the cbmem_toc is read from NVRAM. Why you ask? Because we cannot do it as on intel, because the framebuffer might be there making it hard to look for it in memory (and remember we need it so early that everying is uncached)

3) The patch removes hardcoded limits for suspend/resume save area (it was 1MB) on intel. Now it computes right numbers itself.

4) it impelements saving the memory during CAR to reserved range in sane way. First the sysinfo area (CAR data) is copied, then the rest after car is disabled (cached copy is used). I changed bit also the the copy of CAR area is now done uncached for target which I feel is more right.

I think I did not change the Intel suspend/resume behaviour but best would be if someone can test it. Please note this patch was unfinished on my drive since ages and it would be very nice to get it in to prevent bit rotten it again.
Now I feel it is done good way and should not break anything. I did a test with abuild and it seems fine.

Signed-off-by: Rudolf Marek <r.marek@assembler.cz>
Acked-by: Tobias Diedrich <ranma+coreboot@tdiedrich.de>
Acked-by: Stefan Reinauer <stepan@coreboot.org>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@6117 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

18 files changed:
src/arch/i386/boot/acpi.c
src/arch/i386/boot/tables.c
src/cpu/amd/car/post_cache_as_ram.c
src/include/cbmem.h
src/lib/cbmem.c
src/mainboard/asus/a8v-e_deluxe/romstage.c
src/mainboard/asus/a8v-e_se/romstage.c
src/mainboard/asus/m2v-mx_se/Kconfig
src/mainboard/asus/m2v-mx_se/mainboard.c
src/mainboard/asus/m2v-mx_se/romstage.c
src/mainboard/asus/m2v/romstage.c
src/northbridge/amd/amdk8/northbridge.c
src/northbridge/amd/amdk8/raminit_f.c
src/northbridge/amd/amdk8/raminit_f_dqs.c
src/southbridge/via/k8t890/k8t890.h
src/southbridge/via/k8t890/k8t890_early_car.c
src/southbridge/via/k8t890/k8t890_host_ctrl.c
src/southbridge/via/vt8237r/vt8237r_early_smbus.c

index 5264e13e0df6bb7b32d40d5cbf336468ad04d197..957ec4559a0459b763f1c563200c70d9b0eef6d4 100644 (file)
@@ -470,17 +470,6 @@ void suspend_resume(void)
 {
        void *wake_vec;
 
-#if 0
-#if CONFIG_MEM_TRAIN_SEQ != 0
-       #error "So far it works on AMD and CONFIG_MEM_TRAIN_SEQ == 0"
-#endif
-
-#if CONFIG_RAMBASE < 0x1F00000
-       #error "For ACPI RESUME you need to have CONFIG_RAMBASE at least 31MB"
-       #error "Chipset support (S3_NVRAM_EARLY and ACPI_IS_WAKEUP_EARLY functions and memory ctrl)"
-       #error "And coreboot memory reserved in mainboard.c"
-#endif
-#endif
        /* If we happen to be resuming find wakeup vector and jump to OS. */
        wake_vec = acpi_find_wakeup_vector();
        if (wake_vec)
index 69e0539126faf81231e13058476af6ca76fd493c..d816e767500f1fb6cbbde5813f36153f3a7df816 100644 (file)
@@ -214,7 +214,7 @@ struct lb_memory *write_tables(void)
         * 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
 
 #if CONFIG_MULTIBOOT
index 4a1398a4d3fb52f2040d19cc13b750a12c019f8d..e8f0c92f45ed5af9bb0083930031c7e0b7420e39 100644 (file)
@@ -27,6 +27,45 @@ static void inline __attribute__((always_inline))  memcopy(void *dest, const voi
                        : "0" (bytes / 4), "g" (bytes), "1" ((long)dest), "2" ((long)src)
                        : "memory", "cc");
 }
+
+#if CONFIG_HAVE_ACPI_RESUME == 1
+
+static inline void *backup_resume(void) {
+       unsigned long high_ram_base;
+       void *resume_backup_memory;
+       int suspend = acpi_is_wakeup_early();
+
+       if (!suspend)
+               return NULL;
+
+       /* Start address of high memory tables */
+       high_ram_base = (u32) get_cbmem_toc();
+
+       print_debug_pcar("CBMEM TOC is at: ", (uint32_t)high_ram_base);
+       print_debug_pcar("CBMEM TOC 0-size: ",(uint32_t)(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: ", (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
+       }
+
+       return resume_backup_memory;
+}
+#endif
+
 /* Disable Erratum 343 Workaround, see RevGuide for Fam10h, Pub#41322 Rev 3.33 */
 
 static void vErrata343(void)
@@ -43,7 +82,9 @@ static void vErrata343(void)
 
 static void post_cache_as_ram(void)
 {
-
+#if CONFIG_HAVE_ACPI_RESUME == 1
+       void *resume_backup_memory;
+#endif
 #if 1
        {
        /* Check value of esp to verify if we have enough rom for stack in Cache as RAM */
@@ -66,17 +107,16 @@ static void post_cache_as_ram(void)
        #error "You need to set CONFIG_RAMTOP greater than 1M"
 #endif
 
-       /* So we can access RAM from [1M, CONFIG_RAMTOP) */
-       set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
+#if CONFIG_HAVE_ACPI_RESUME == 1
+       resume_backup_memory = backup_resume();
+#endif
 
-//     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... ");
 
        /* 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
-//     dump_mem((CONFIG_RAMTOP) - 0x8000, (CONFIG_RAMTOP) - 0x7c00);
 
        __asm__ volatile (
                /* set new esp */ /* before CONFIG_RAMBASE */
@@ -94,9 +134,25 @@ static void post_cache_as_ram(void)
        print_debug_pcar("testx = ", testx);
 
        print_debug("Disabling cache as ram now \n");
+
        disable_cache_as_ram_bsp();
 
+       disable_cache();
+       set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
+       enable_cache();
+
+#if CONFIG_HAVE_ACPI_RESUME == 1
+       /* 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);
+       }
+#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 */
        memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE);
@@ -105,8 +161,6 @@ static void post_cache_as_ram(void)
 #endif
        print_debug("Done\n");
 
-//     dump_mem((CONFIG_RAMTOP) - 0x8000, (CONFIG_RAMTOP) - 0x7c00);
-
        set_sysinfo_in_ram(1); // So other core0 could start to train mem
 
 #if CONFIG_MEM_TRAIN_SEQ == 1
index d814a7285ac2b55573d2bf892a47d1ad3f346b8a..933f900e6aa56da30b4c2ed6104274faf2a120ad 100644 (file)
@@ -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,6 @@ void *cbmem_find(u32 id);
 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 5490a1fef6dd6195a3f83047abf0d2c3487c1978..d85c74881014e44a7d550b6908fb37f2e6d9aed3 100644 (file)
@@ -36,11 +36,32 @@ struct cbmem_entry {
        u64 size;
 } __attribute__((packed));
 
-#ifndef __PRE_RAM__
-struct cbmem_entry *bss_cbmem_toc;
-#define get_cbmem_toc()        bss_cbmem_toc
+
+#ifdef __PRE_RAM__
+
+/* note this should be done as weak function but we do #include
+   of C files in the romstage breaking this (in same compile
+   unit is weak and non weak function
+struct cbmem_entry *__attribute__((weak)) get_cbmem_toc(void)
+*/
+#ifndef get_cbmem_toc
+       #define get_cbmem_toc() (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE)
+#endif
+
 #else
-#define get_cbmem_toc()        (struct cbmem_entry *)(get_top_of_ram() - HIGH_MEMORY_SIZE)
+
+static struct cbmem_entry *bss_cbmem_toc;
+
+struct cbmem_entry *__attribute__((weak)) get_cbmem_toc(void)
+{
+       return bss_cbmem_toc;
+}
+
+void __attribute__((weak)) set_cbmem_toc(struct cbmem_entry * x)
+{
+       /* do nothing, this should be called by chipset to save TOC in NVRAM */
+}
+
 #endif
 
 /**
@@ -70,6 +91,10 @@ void cbmem_init(u64 baseaddr, u64 size)
                for (;;) ;
        }
 
+       /* we don't need to call this in romstage, usefull only from ramstage */
+#ifndef __PRE_RAM__
+       set_cbmem_toc((struct cbmem_entry *)(unsigned long)baseaddr);
+#endif
        memset(cbmem_toc, 0, CBMEM_TOC_RESERVED);
 
        cbmem_toc[0] = (struct cbmem_entry) {
index bf096e1033ea86e835a8df1d1c848cea38f0271e..1167832c6a94b3c4592d9860f3349268c5599fa0 100644 (file)
@@ -79,7 +79,6 @@ void soft_reset(void)
        }
 }
 
-// defines S3_NVRAM_EARLY:
 #include "southbridge/via/k8t890/k8t890_early_car.c"
 #include "northbridge/amd/amdk8/amdk8.h"
 #include "northbridge/amd/amdk8/incoherent_ht.c"
index bf096e1033ea86e835a8df1d1c848cea38f0271e..1167832c6a94b3c4592d9860f3349268c5599fa0 100644 (file)
@@ -79,7 +79,6 @@ void soft_reset(void)
        }
 }
 
-// defines S3_NVRAM_EARLY:
 #include "southbridge/via/k8t890/k8t890_early_car.c"
 #include "northbridge/amd/amdk8/amdk8.h"
 #include "northbridge/amd/amdk8/incoherent_ht.c"
index 9e3b2649a6cc8924b7d3d6930884d70776724f5f..8fd9ec089edd896df5e6ecf50690aa44b697294c 100644 (file)
@@ -35,6 +35,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
        select RAMINIT_SYSINFO
        select VGA
        select TINY_BOOTBLOCK
+       select HAVE_ACPI_RESUME
        select HAVE_MAINBOARD_RESOURCES
        select QRANK_DIMM_SUPPORT
        select SET_FIDVID
index dcf97c37a7f650350e9c024025e25c5cce1800e9..614af3908ed40570e463f258f34445853083171d 100644 (file)
@@ -34,13 +34,6 @@ int add_mainboard_resources(struct lb_memory *mem)
        lb_add_memory_range(mem, LB_MEM_RESERVED,
                uma_memory_base, uma_memory_size);
 #endif
-
-#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 0849c862ba0f9ebf479a29e4ff287e6d00b23e93..65fdd115aa32994be895c8888439052920fbe7b2 100644 (file)
@@ -62,7 +62,6 @@ static inline int spd_read_byte(unsigned device, unsigned address)
        return smbus_read_byte(device, address);
 }
 
-// defines S3_NVRAM_EARLY:
 #include "southbridge/via/k8t890/k8t890_early_car.c"
 #include "northbridge/amd/amdk8/amdk8.h"
 #include "northbridge/amd/amdk8/incoherent_ht.c"
@@ -75,6 +74,15 @@ static inline int spd_read_byte(unsigned device, unsigned address)
 
 #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 d56ca9ce11f062f6f2647f7c7f7078d4883f42dd..4c86f55657552a336a944d8d7ffd1dfb86c631d1 100644 (file)
@@ -64,7 +64,6 @@ static inline int spd_read_byte(unsigned device, unsigned address)
        return smbus_read_byte(device, address);
 }
 
-// defines S3_NVRAM_EARLY:
 #include "southbridge/via/k8t890/k8t890_early_car.c"
 #include "northbridge/amd/amdk8/amdk8.h"
 #include "northbridge/amd/amdk8/incoherent_ht.c"
index cc99e5123b9a59c2aa6afc70aa4f3f548d349907..f592880b9203f33eeb8f87695d9becd3813ce809 100644 (file)
@@ -819,7 +819,8 @@ static u32 hoist_memory(unsigned long hole_startk, int node_id)
 #endif
 
 #if CONFIG_WRITE_HIGH_TABLES==1
-#define HIGH_TABLES_SIZE 64    /* maximum size of high tables in KB */
+#include <cbmem.h>
+#define HIGH_TABLES_SIZE ((HIGH_MEMORY_SIZE + 1024) / 1024)
 extern uint64_t high_tables_base, high_tables_size;
 #endif
 
index 0a1db664e13bc18ac4dce0a27b5f7f77cd37c61c..fac30a849bce33ed2ab4d2a7eaec1f42ce81143e 100644 (file)
@@ -2988,14 +2988,15 @@ static void set_hw_mem_hole(int controllers, const struct mem_controller *ctrl)
 
 }
 #endif
-
+#if CONFIG_HAVE_ACPI_RESUME == 1
 #include "exit_from_self.c"
+#endif
 
 static void sdram_enable(int controllers, const struct mem_controller *ctrl,
                          struct sys_info *sysinfo)
 {
        int i;
-#ifdef ACPI_IS_WAKEUP_EARLY
+#if CONFIG_HAVE_ACPI_RESUME == 1
        int suspend = acpi_is_wakeup_early();
 #else
        int suspend = 0;
index 5303a67b322faee207b61c0120680a59f8bc60bd..8ddd44fadba68f454a900ec962c5541b1e983490 100644 (file)
@@ -1826,25 +1826,7 @@ static void set_sysinfo_in_ram(unsigned val)
        set_htic_bit(0, val, 9);
 }
 
-#ifdef S3_NVRAM_EARLY
-// Don't define these prototypes as the real functions are already included
-// at this point.
-//
-//int s3_save_nvram_early(u32 dword, int size, int  nvram_pos);
-//int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos);
-#else
-static inline int s3_save_nvram_early(u32 dword, int size, int  nvram_pos)
-{
-       return nvram_pos;
-}
-
-static inline int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos)
-{
-       die("No memory NVRAM loader for DQS data! Unable to restore memory state\n");
-
-       return nvram_pos; /* Make GCC happy */
-}
-#endif
+#if CONFIG_HAVE_ACPI_RESUME == 1
 
 #if CONFIG_MEM_TRAIN_SEQ == 0
 static int save_index_to_pos(unsigned int dev, int size, int index, int nvram_pos)
@@ -1930,6 +1912,7 @@ static void dqs_restore_MC_NVRAM(unsigned int dev)
        reg |= pci_read_config32(dev, DRAM_CONFIG_HIGH);
        pci_write_config32(dev, DRAM_CONFIG_HIGH, reg);
 }
+#endif
 
 #if CONFIG_MEM_TRAIN_SEQ == 0
 #if K8_REV_F_SUPPORT_F0_F1_WORKAROUND == 1
@@ -1998,7 +1981,9 @@ static void dqs_timing(int controllers, const struct mem_controller *ctrl, struc
                if(train_DqsRcvrEn(ctrl+i, 2, sysinfo)) goto out;
                printk(BIOS_DEBUG, " done\n");
                sysinfo->mem_trained[i]=1;
+#if CONFIG_HAVE_ACPI_RESUME == 1
                dqs_save_MC_NVRAM((ctrl+i)->f2);
+#endif
        }
 
 out:
index ce60d904cc581b45eb7e769deeb4a94285407da5..faa6a81d3da33c618be458d10aad1f952cb33fc3 100644 (file)
@@ -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 aa224a9469375fb1b501e25fe38242b2ad035e9d..94162cb90cdaec6097db81bf2df18226118f2af3 100644 (file)
  */
 
 #include <stdlib.h>
+#include <cbmem.h>
+#include <arch/io.h>
 #include "k8t890.h"
 
 /* The 256 bytes of NVRAM for S3 storage, 256B aligned */
 #define K8T890_NVRAM_IO_BASE   0xf00
 #define K8T890_MULTIPLE_FN_EN  0x4f
 
-/* we provide S3 NVRAM to system */
-#define S3_NVRAM_EARLY 1
-
-
 /* AMD K8 LDT0, LDT1, LDT2 Link Control Registers */
 static u8 ldtreg[3] = {0x86, 0xa6, 0xc6};
 
@@ -155,3 +153,9 @@ static inline int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos)
        printk(BIOS_DEBUG, "Loading %x of size %d to nvram pos:%d\n", * old_dword, size, nvram_pos-size);
        return nvram_pos;
 }
+
+/* this should be a function
+struct cbmem_entry *get_cbmem_toc(void) {
+*/
+
+#define get_cbmem_toc() ((struct cbmem_entry *) inl(K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC))
index a1c42b7d59a4a54b911a349702166ef2d07c874f..43d01ee36926ceba0bbbdc6a2e5513fe3e840d30 100644 (file)
@@ -22,6 +22,8 @@
 #include <device/pci_ops.h>
 #include <device/pci_ids.h>
 #include <console/console.h>
+#include <cbmem.h>
+#include <arch/io.h>
 #include "k8t890.h"
 
 /* this may be later merged */
@@ -111,6 +113,14 @@ static void host_ctrl_enable_k8m890(struct device *dev) {
        pci_write_config8(dev, 0xa6, 0x83);
 
 }
+#if 0
+struct cbmem_entry *get_cbmem_toc(void) {
+               return (struct cbmem_entry *) inl(K8T890_NVRAM_IO_BASE+K8T890_NVRAM_CBMEM_TOC);
+}
+#endif
+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,
index 07dffac4c00d6864badcb9ee119e0d2d5b40cc55..a298e84676282e669d8ed24f2cc351ef6cef9128 100644 (file)
@@ -316,9 +316,7 @@ void enable_rom_decode(void)
        pci_write_config8(dev, 0x41, 0x7f);
 }
 
-#ifdef CONFIG_NORTHBRIDGE_AMD_K8 /* CN700 doesn't have the support yet */
-#define ACPI_IS_WAKEUP_EARLY 1
-
+#if CONFIG_HAVE_ACPI_RESUME == 1
 static int acpi_is_wakeup_early(void) {
        device_t dev;
        u16 tmp;