diff options
22 files changed, 213 insertions, 12 deletions
diff --git a/src/cpu/amd/agesa/Kconfig b/src/cpu/amd/agesa/Kconfig index 95db82f982..6a7ec8750f 100644 --- a/src/cpu/amd/agesa/Kconfig +++ b/src/cpu/amd/agesa/Kconfig @@ -29,6 +29,7 @@ config CPU_AMD_AGESA select UDELAY_LAPIC select LAPIC_MONOTONIC_TIMER select SPI_FLASH if HAVE_ACPI_RESUME + select POSTCAR_STAGE if !AGESA_LEGACY_WRAPPER if CPU_AMD_AGESA diff --git a/src/cpu/amd/agesa/Makefile.inc b/src/cpu/amd/agesa/Makefile.inc index c8e125e445..f4ec2ce0b0 100644 --- a/src/cpu/amd/agesa/Makefile.inc +++ b/src/cpu/amd/agesa/Makefile.inc @@ -24,11 +24,13 @@ ifeq ($(CONFIG_AGESA_LEGACY), y) cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram_legacy.inc else cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram.S -romstage-y += romstage.c +romstage-y += romstage.c mtrr_fixme.c endif romstage-$(CONFIG_AGESA_LEGACY_WRAPPER) += heapmanager.c +postcar-y += cache_as_ram.S + ramstage-y += heapmanager.c ramstage-$(CONFIG_AGESA_LEGACY_WRAPPER) += amd_late_init.c diff --git a/src/cpu/amd/agesa/cache_as_ram.S b/src/cpu/amd/agesa/cache_as_ram.S index b96a5e70e4..50242f7a54 100644 --- a/src/cpu/amd/agesa/cache_as_ram.S +++ b/src/cpu/amd/agesa/cache_as_ram.S @@ -29,6 +29,7 @@ .code32 .globl _cache_as_ram_setup, _cache_as_ram_setup_end +.globl chipset_teardown_car _cache_as_ram_setup: @@ -105,20 +106,44 @@ _cache_as_ram_setup: movd %mm0, %eax /* bist */ pushl %eax call romstage_main - movl %eax, %esp -/* Register %esp is new stacktop for remaining of romstage. - * It is the only register preserved in AMD_DISABLE_STACK. +#if IS_ENABLED(CONFIG_POSTCAR_STAGE) + +/* We do not return. Execution continues with run_postcar_phase() + * calling to chipset_teardown_car below. + */ + jmp postcar_entry_failure + +chipset_teardown_car: + +/* + * Retrieve return address from stack as it will get trashed below if + * execution is utilizing the cache-as-ram stack. */ + pop %esp + +#else + + movl %eax, %esp + +/* Register %esp is new stacktop for remaining of romstage. */ + +#endif -disable_cache_as_ram: /* Disable cache */ movl %cr0, %eax orl $CR0_CacheDisable, %eax movl %eax, %cr0 +/* Register %esp is preserved in AMD_DISABLE_STACK. */ AMD_DISABLE_STACK +#if IS_ENABLED(CONFIG_POSTCAR_STAGE) + + jmp *%esp + +#else + /* enable cache */ movl %cr0, %eax andl $0x9fffffff, %eax @@ -126,9 +151,22 @@ disable_cache_as_ram: call romstage_after_car +#endif + /* Should never see this postcode */ post_code(0xaf) + stop: + hlt + jmp stop + +/* These are here for linking purposes. */ +.weak early_all_cores, romstage_main +early_all_cores: +romstage_main: +postcar_entry_failure: + /* Should never see this postcode */ + post_code(0xae) jmp stop _cache_as_ram_setup_end: diff --git a/src/cpu/amd/agesa/mtrr_fixme.c b/src/cpu/amd/agesa/mtrr_fixme.c new file mode 100644 index 0000000000..1fbb55318d --- /dev/null +++ b/src/cpu/amd/agesa/mtrr_fixme.c @@ -0,0 +1,100 @@ +/* + * This file is part of the coreboot project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/cpu.h> +#include <cbmem.h> +#include <console/console.h> +#include <cpu/amd/mtrr.h> +#include <cpu/cpu.h> +#include <cpu/x86/cache.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/mtrr.h> +#include <northbridge/amd/agesa/agesa_helper.h> + +static void set_range_uc(u32 base, u32 size) +{ + int i, max_var_mtrrs; + msr_t msr; + msr = rdmsr(MTRR_CAP_MSR); + max_var_mtrrs = msr.lo & MTRR_CAP_VCNT; + + for (i = 0; i < max_var_mtrrs; i++) { + msr = rdmsr(MTRR_PHYS_MASK(i)); + if (!(msr.lo & MTRR_PHYS_MASK_VALID)) + break; + } + if (i == max_var_mtrrs) + die("Run out of unused MTRRs\n"); + + msr.hi = 0; + msr.lo = base | MTRR_TYPE_UNCACHEABLE; + wrmsr(MTRR_PHYS_BASE(i), msr); + + msr.hi = (1 << (cpu_phys_address_size() - 32)) - 1; + msr.lo = ~(size - 1) | MTRR_PHYS_MASK_VALID; + wrmsr(MTRR_PHYS_MASK(i), msr); +} + +void fixup_cbmem_to_UC(int s3resume) +{ + if (s3resume) + return; + + /* For normal path, INIT_POST has returned with all + * memory set WB cacheable. But we need CBMEM as UC + * to make CAR teardown with invalidation without + * writeback possible. + */ + + uintptr_t top_of_ram = (uintptr_t) cbmem_top(); + top_of_ram = ALIGN_UP(top_of_ram, 4 * MiB); + + set_range_uc(top_of_ram - 4 * MiB, 4 * MiB); + set_range_uc(top_of_ram - 8 * MiB, 4 * MiB); +} + +void recover_postcar_frame(struct postcar_frame *pcf, int s3resume) +{ + msr_t base, mask; + int i; + + /* Replicate non-UC MTRRs as left behind by AGESA. + */ + for (i = 0; i < pcf->max_var_mtrrs; i++) { + mask = rdmsr(MTRR_PHYS_MASK(i)); + base = rdmsr(MTRR_PHYS_BASE(i)); + u32 size = ~(mask.lo & ~0xfff) + 1; + u8 type = base.lo & 0x7; + base.lo &= ~0xfff; + + if (!(mask.lo & MTRR_PHYS_MASK_VALID) || + (type == MTRR_TYPE_UNCACHEABLE)) + continue; + + postcar_frame_add_mtrr(pcf, base.lo, size, type); + } + + /* For S3 resume path, INIT_RESUME does not return with + * memory covering CBMEM set as WB cacheable. For better + * speed make them WB after CAR teardown. + */ + if (s3resume) { + uintptr_t top_of_ram = (uintptr_t) cbmem_top(); + top_of_ram = ALIGN_DOWN(top_of_ram, 4*MiB); + + postcar_frame_add_mtrr(pcf, top_of_ram - 4*MiB, 4*MiB, + MTRR_TYPE_WRBACK); + postcar_frame_add_mtrr(pcf, top_of_ram - 8*MiB, 4*MiB, + MTRR_TYPE_WRBACK); + } +} diff --git a/src/cpu/amd/agesa/romstage.c b/src/cpu/amd/agesa/romstage.c index f8b1e439d6..1b9757a934 100644 --- a/src/cpu/amd/agesa/romstage.c +++ b/src/cpu/amd/agesa/romstage.c @@ -18,7 +18,6 @@ #include <cbmem.h> #include <cpu/amd/car.h> #include <cpu/x86/bist.h> -#include <cpu/x86/mtrr.h> #include <console/console.h> #include <halt.h> #include <program_loading.h> @@ -54,6 +53,7 @@ static void fill_sysinfo(struct sysinfo *cb) void * asmlinkage romstage_main(unsigned long bist) { + struct postcar_frame pcf; struct sysinfo romstage_state; struct sysinfo *cb = &romstage_state; u8 initial_apic_id = (u8) (cpuid_ebx(1) >> 24); @@ -100,6 +100,9 @@ void * asmlinkage romstage_main(unsigned long bist) } + if (IS_ENABLED(CONFIG_POSTCAR_STAGE)) + fixup_cbmem_to_UC(cb->s3resume); + cbmem_initted = !cbmem_recovery(cb->s3resume); if (cb->s3resume && !cbmem_initted) { @@ -107,16 +110,25 @@ void * asmlinkage romstage_main(unsigned long bist) halt(); } - uintptr_t stack_top = romstage_ram_stack_base(HIGH_ROMSTAGE_STACK_SIZE, - ROMSTAGE_STACK_CBMEM); - stack_top += HIGH_ROMSTAGE_STACK_SIZE; - romstage_handoff_init(cb->s3resume); - printk(BIOS_DEBUG, "Move CAR stack.\n"); - return (void*)stack_top; + if (!IS_ENABLED(CONFIG_POSTCAR_STAGE)) { + uintptr_t stack_top = romstage_ram_stack_base( + HIGH_ROMSTAGE_STACK_SIZE, ROMSTAGE_STACK_CBMEM); + stack_top += HIGH_ROMSTAGE_STACK_SIZE; + printk(BIOS_DEBUG, "Move CAR stack.\n"); + return (void*)stack_top; + } + + postcar_frame_init(&pcf, HIGH_ROMSTAGE_STACK_SIZE); + recover_postcar_frame(&pcf, cb->s3resume); + + run_postcar_phase(&pcf); + /* We do not return. */ + return NULL; } +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) void asmlinkage romstage_after_car(void) { struct sysinfo romstage_state; @@ -131,3 +143,4 @@ void asmlinkage romstage_after_car(void) run_ramstage(); } +#endif diff --git a/src/cpu/amd/pi/Kconfig b/src/cpu/amd/pi/Kconfig index 51897b6dd8..d71b8321a0 100644 --- a/src/cpu/amd/pi/Kconfig +++ b/src/cpu/amd/pi/Kconfig @@ -27,6 +27,7 @@ config CPU_AMD_PI select UDELAY_LAPIC select LAPIC_MONOTONIC_TIMER select SPI_FLASH if HAVE_ACPI_RESUME + select POSTCAR_STAGE if !BINARYPI_LEGACY_WRAPPER if CPU_AMD_PI diff --git a/src/cpu/amd/pi/Makefile.inc b/src/cpu/amd/pi/Makefile.inc index df79c82d61..ba9ac265e9 100644 --- a/src/cpu/amd/pi/Makefile.inc +++ b/src/cpu/amd/pi/Makefile.inc @@ -18,6 +18,7 @@ subdirs-$(CONFIG_CPU_AMD_PI_00730F01) += 00730F01 subdirs-$(CONFIG_CPU_AMD_PI_00660F01) += 00660F01 cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram.S +postcar-y += ../agesa/cache_as_ram.S ifeq ($(CONFIG_BINARYPI_LEGACY_WRAPPER), y) romstage-y += romstage.c @@ -25,6 +26,7 @@ ramstage-y += amd_late_init.c romstage-y += ../agesa/heapmanager.c else romstage-y += ../agesa/romstage.c +romstage-y += ../agesa/mtrr_fixme.c endif ramstage-y += ../agesa/heapmanager.c diff --git a/src/northbridge/amd/agesa/agesa_helper.h b/src/northbridge/amd/agesa/agesa_helper.h index 6b7275c6e1..044393d4b9 100644 --- a/src/northbridge/amd/agesa/agesa_helper.h +++ b/src/northbridge/amd/agesa/agesa_helper.h @@ -17,6 +17,7 @@ #define _AGESA_HELPER_H_ #include <stddef.h> +#include <arch/cpu.h> enum { PICK_DMI, /* DMI Interface */ @@ -53,5 +54,7 @@ void EmptyHeap(void); #define HIGH_MEMORY_SCRATCH 0x30000 +void fixup_cbmem_to_UC(int s3resume); +void recover_postcar_frame(struct postcar_frame *pcf, int s3resume); #endif /* _AGESA_HELPER_H_ */ diff --git a/src/northbridge/amd/pi/Makefile.inc b/src/northbridge/amd/pi/Makefile.inc index b4d8c95f45..93c87ecc68 100644 --- a/src/northbridge/amd/pi/Makefile.inc +++ b/src/northbridge/amd/pi/Makefile.inc @@ -35,5 +35,6 @@ romstage-y += ../agesa/def_callouts.c ../agesa/eventlog.c ramstage-y += ../agesa/def_callouts.c ../agesa/eventlog.c ../agesa/acpi_tables.c romstage-y += ramtop.c +postcar-y += ramtop.c ramstage-y += ramtop.c endif diff --git a/src/southbridge/amd/agesa/hudson/Makefile.inc b/src/southbridge/amd/agesa/hudson/Makefile.inc index 89236a6c0a..2bf6f02539 100644 --- a/src/southbridge/amd/agesa/hudson/Makefile.inc +++ b/src/southbridge/amd/agesa/hudson/Makefile.inc @@ -24,6 +24,7 @@ ramstage-$(CONFIG_SPI_FLASH) += spi.c ramstage-y += resume.c ramtop.c romstage-y += ramtop.c +postcar-y += ramtop.c romstage-y += imc.c ramstage-y += imc.c diff --git a/src/southbridge/amd/cimx/sb700/Makefile.inc b/src/southbridge/amd/cimx/sb700/Makefile.inc index 0b9ee9ce33..0b7614befe 100644 --- a/src/southbridge/amd/cimx/sb700/Makefile.inc +++ b/src/southbridge/amd/cimx/sb700/Makefile.inc @@ -21,6 +21,8 @@ romstage-y += smbus.c smbus_spd.c romstage-y += reset.c romstage-y += ramtop.c +postcar-y += ramtop.c + ramstage-y += late.c ramstage-y += reset.c ramstage-y += ramtop.c diff --git a/src/southbridge/amd/cimx/sb800/Makefile.inc b/src/southbridge/amd/cimx/sb800/Makefile.inc index 0511fb3074..a5287fa231 100644 --- a/src/southbridge/amd/cimx/sb800/Makefile.inc +++ b/src/southbridge/amd/cimx/sb800/Makefile.inc @@ -30,6 +30,7 @@ ramstage-$(CONFIG_SB800_IMC_FAN_CONTROL) += fan.c ramstage-$(CONFIG_SPI_FLASH) += spi.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += fadt.c +postcar-y += ramtop.c romstage-y += ramtop.c ramstage-y += ramtop.c diff --git a/src/southbridge/amd/cimx/sb900/Makefile.inc b/src/southbridge/amd/cimx/sb900/Makefile.inc index b09180cfa7..ff9ada66fb 100644 --- a/src/southbridge/amd/cimx/sb900/Makefile.inc +++ b/src/southbridge/amd/cimx/sb900/Makefile.inc @@ -22,6 +22,8 @@ romstage-y += smbus.c smbus_spd.c romstage-y += reset.c romstage-y += ramtop.c +postcar-y += ramtop.c + ramstage-y += cfg.c ramstage-y += early.c ramstage-y += late.c diff --git a/src/vendorcode/amd/agesa/f12/gcccar.inc b/src/vendorcode/amd/agesa/f12/gcccar.inc index 6a81fc7add..c08c9f1291 100644 --- a/src/vendorcode/amd/agesa/f12/gcccar.inc +++ b/src/vendorcode/amd/agesa/f12/gcccar.inc @@ -678,7 +678,11 @@ fam12_enable_stack_hook_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif mov %bx, %ax # Restore INVD -> WBINVD bit _WRMSR diff --git a/src/vendorcode/amd/agesa/f14/gcccar.inc b/src/vendorcode/amd/agesa/f14/gcccar.inc index 10214a8f03..678990f5b6 100644 --- a/src/vendorcode/amd/agesa/f14/gcccar.inc +++ b/src/vendorcode/amd/agesa/f14/gcccar.inc @@ -826,7 +826,11 @@ fam14_enable_stack_hook_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif bts $INVD_WBINVD, %eax # Turn on Conversion of INVD to WBINVD _WRMSR diff --git a/src/vendorcode/amd/agesa/f15/gcccar.inc b/src/vendorcode/amd/agesa/f15/gcccar.inc index 427c7e5622..5076272e11 100644 --- a/src/vendorcode/amd/agesa/f15/gcccar.inc +++ b/src/vendorcode/amd/agesa/f15/gcccar.inc @@ -433,7 +433,11 @@ fam10_enable_stack_hook_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif mov %bx, %ax # Restore INVD -> WBINVD bit _WRMSR diff --git a/src/vendorcode/amd/agesa/f15tn/gcccar.inc b/src/vendorcode/amd/agesa/f15tn/gcccar.inc index 7ac9613fca..8e15503551 100644 --- a/src/vendorcode/amd/agesa/f15tn/gcccar.inc +++ b/src/vendorcode/amd/agesa/f15tn/gcccar.inc @@ -1263,7 +1263,11 @@ fam15_disable_stack_remote_read_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif #.if (bh == 01h) || (bh == 03h) ; Is this TN or KM? cmp $01, %bh diff --git a/src/vendorcode/amd/agesa/f16kb/gcccar.inc b/src/vendorcode/amd/agesa/f16kb/gcccar.inc index 26e61da34b..8ad4d1ddc4 100644 --- a/src/vendorcode/amd/agesa/f16kb/gcccar.inc +++ b/src/vendorcode/amd/agesa/f16kb/gcccar.inc @@ -615,7 +615,11 @@ fam16_disable_stack_remote_read_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif #Do Standard Family 16 work mov $HWCR, %ecx # MSR:C001_0015h diff --git a/src/vendorcode/amd/pi/00630F01/binaryPI/gcccar.inc b/src/vendorcode/amd/pi/00630F01/binaryPI/gcccar.inc index 4092dbf971..fc7d0e461f 100644 --- a/src/vendorcode/amd/pi/00630F01/binaryPI/gcccar.inc +++ b/src/vendorcode/amd/pi/00630F01/binaryPI/gcccar.inc @@ -916,7 +916,11 @@ fam15_disable_stack_remote_read_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif #.if (bh == 01h) || (bh == 03h) ; Is this TN or KV? cmp $01, %bh diff --git a/src/vendorcode/amd/pi/00660F01/binaryPI/gcccar.inc b/src/vendorcode/amd/pi/00660F01/binaryPI/gcccar.inc index 8d208d6521..45ed2948e7 100644 --- a/src/vendorcode/amd/pi/00660F01/binaryPI/gcccar.inc +++ b/src/vendorcode/amd/pi/00660F01/binaryPI/gcccar.inc @@ -651,7 +651,11 @@ fam15_disable_stack_remote_read_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif # #.if (bh == 01h) || (bh == 03h) ; Is this TN or KM? # cmp $01, %bh diff --git a/src/vendorcode/amd/pi/00730F01/binaryPI/gcccar.inc b/src/vendorcode/amd/pi/00730F01/binaryPI/gcccar.inc index 4761e48231..5a4f7b9290 100644 --- a/src/vendorcode/amd/pi/00730F01/binaryPI/gcccar.inc +++ b/src/vendorcode/amd/pi/00730F01/binaryPI/gcccar.inc @@ -615,7 +615,11 @@ fam16_disable_stack_remote_read_exit: # This shouldn't be used with S3 resume IF the stack/cache area is # not reserved and over system memory. #-------------------------------------------------------------------------- +#if !IS_ENABLED(CONFIG_POSTCAR_STAGE) wbinvd +#else + invd +#endif #Do Standard Family 16 work mov $HWCR, %ecx # MSR:C001_0015h diff --git a/src/vendorcode/amd/pi/Makefile.inc b/src/vendorcode/amd/pi/Makefile.inc index bcf078deee..0192faad4a 100644 --- a/src/vendorcode/amd/pi/Makefile.inc +++ b/src/vendorcode/amd/pi/Makefile.inc @@ -85,7 +85,9 @@ export AGESA_CFLAGS := $(AGESA_CFLAGS) CC_bootblock := $(CC_bootblock) $(AGESA_INC) $(AGESA_CFLAGS) CC_romstage := $(CC_romstage) $(AGESA_INC) $(AGESA_CFLAGS) +CC_postcar:= $(CC_postcar) -I$(AGESA_ROOT)/binaryPI CC_ramstage := $(CC_ramstage) $(AGESA_INC) $(AGESA_CFLAGS) + CC_x86_32 := $(CC_x86_32) $(AGESA_INC) $(AGESA_CFLAGS) CC_x86_64 := $(CC_x86_64) $(AGESA_INC) $(AGESA_CFLAGS) |