123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- From 46cdec8cbce15ca11ad9a49a3ee415a78f781997 Mon Sep 17 00:00:00 2001
- From: Angel Pons <th3fanbus@gmail.com>
- Date: Sat, 7 May 2022 00:26:10 +0200
- Subject: [PATCH 08/26] nb/intel/haswell: Add native raminit scaffolding
- Implement some scaffolding for Haswell native raminit, like bootmode
- selection, handling of MRC cache and CPU detection.
- Change-Id: Icd96649fa045ea7f0f32ae9bfe1e60498d93975b
- Signed-off-by: Angel Pons <th3fanbus@gmail.com>
- ---
- .../intel/haswell/native_raminit/Makefile.inc | 1 +
- .../haswell/native_raminit/raminit_main.c | 104 ++++++++++
- .../haswell/native_raminit/raminit_native.c | 189 +++++++++++++++++-
- .../haswell/native_raminit/raminit_native.h | 34 ++++
- 4 files changed, 322 insertions(+), 6 deletions(-)
- create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_main.c
- create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_native.h
- diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
- index 8cfb4fb33e..90af951c5a 100644
- --- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
- +++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
- @@ -1,3 +1,4 @@
- ## SPDX-License-Identifier: GPL-2.0-or-later
-
- +romstage-y += raminit_main.c
- romstage-y += raminit_native.c
- diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
- new file mode 100644
- index 0000000000..9b42c25b40
- --- /dev/null
- +++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
- @@ -0,0 +1,104 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#include <assert.h>
- +#include <console/console.h>
- +#include <cpu/intel/haswell/haswell.h>
- +#include <delay.h>
- +#include <device/pci_ops.h>
- +#include <northbridge/intel/haswell/chip.h>
- +#include <northbridge/intel/haswell/haswell.h>
- +#include <northbridge/intel/haswell/raminit.h>
- +#include <string.h>
- +#include <types.h>
- +
- +#include "raminit_native.h"
- +
- +struct task_entry {
- + enum raminit_status (*task)(struct sysinfo *);
- + bool is_enabled;
- + const char *name;
- +};
- +
- +static const struct task_entry cold_boot[] = {
- +};
- +
- +/* Return a generic stepping value to make stepping checks simpler */
- +static enum generic_stepping get_stepping(const uint32_t cpuid)
- +{
- + switch (cpuid) {
- + case CPUID_HASWELL_A0:
- + die("Haswell stepping A0 is not supported\n");
- + case CPUID_HASWELL_B0:
- + case CPUID_HASWELL_ULT_B0:
- + case CPUID_CRYSTALWELL_B0:
- + return STEPPING_B0;
- + case CPUID_HASWELL_C0:
- + case CPUID_HASWELL_ULT_C0:
- + case CPUID_CRYSTALWELL_C0:
- + return STEPPING_C0;
- + default:
- + /** TODO: Add Broadwell support someday **/
- + die("Unknown CPUID 0x%x\n", cpuid);
- + }
- +}
- +
- +static void initialize_ctrl(struct sysinfo *ctrl)
- +{
- + const struct northbridge_intel_haswell_config *cfg = config_of_soc();
- + const enum raminit_boot_mode bootmode = ctrl->bootmode;
- +
- + memset(ctrl, 0, sizeof(*ctrl));
- +
- + ctrl->cpu = cpu_get_cpuid();
- + ctrl->stepping = get_stepping(ctrl->cpu);
- + ctrl->dq_pins_interleaved = cfg->dq_pins_interleaved;
- + ctrl->bootmode = bootmode;
- +}
- +
- +static enum raminit_status try_raminit(struct sysinfo *ctrl)
- +{
- + const struct task_entry *const schedule = cold_boot;
- + const size_t length = ARRAY_SIZE(cold_boot);
- +
- + enum raminit_status status = RAMINIT_STATUS_UNSPECIFIED_ERROR;
- +
- + for (size_t i = 0; i < length; i++) {
- + const struct task_entry *const entry = &schedule[i];
- + assert(entry);
- + assert(entry->name);
- + if (!entry->is_enabled)
- + continue;
- +
- + assert(entry->task);
- + printk(RAM_DEBUG, "\nExecuting raminit task %s\n", entry->name);
- + status = entry->task(ctrl);
- + printk(RAM_DEBUG, "\n");
- + if (status) {
- + printk(BIOS_ERR, "raminit failed on step %s\n", entry->name);
- + break;
- + }
- + }
- +
- + return status;
- +}
- +
- +void raminit_main(const enum raminit_boot_mode bootmode)
- +{
- + /*
- + * The mighty_ctrl struct. Will happily nuke the pre-RAM stack
- + * if left unattended. Make it static and pass pointers to it.
- + */
- + static struct sysinfo mighty_ctrl;
- +
- + mighty_ctrl.bootmode = bootmode;
- + initialize_ctrl(&mighty_ctrl);
- +
- + /** TODO: Try more than once **/
- + enum raminit_status status = try_raminit(&mighty_ctrl);
- +
- + if (status != RAMINIT_STATUS_SUCCESS)
- + die("Memory initialization was met with utmost failure and misery\n");
- +
- + /** TODO: Implement the required magic **/
- + die("NATIVE RAMINIT: More Magic (tm) required.\n");
- +}
- diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
- index b6efb6b40d..0869db3902 100644
- --- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
- +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
- @@ -1,13 +1,45 @@
- /* SPDX-License-Identifier: GPL-2.0-or-later */
-
- +#include <arch/cpu.h>
- +#include <assert.h>
- +#include <cbmem.h>
- +#include <cf9_reset.h>
- #include <console/console.h>
- +#include <cpu/x86/msr.h>
- #include <delay.h>
- +#include <device/pci_ops.h>
- +#include <mrc_cache.h>
- #include <northbridge/intel/haswell/haswell.h>
- #include <northbridge/intel/haswell/raminit.h>
- #include <southbridge/intel/lynxpoint/me.h>
- #include <southbridge/intel/lynxpoint/pch.h>
- #include <types.h>
-
- +#include "raminit_native.h"
- +
- +static void wait_txt_clear(void)
- +{
- + const struct cpuid_result cpuid = cpuid_ext(1, 0);
- +
- + /* Check if TXT is supported */
- + if (!(cpuid.ecx & BIT(6)))
- + return;
- +
- + /* Some TXT public bit */
- + if (!(read32p(0xfed30010) & 1))
- + return;
- +
- + /* Wait for TXT clear */
- + do {} while (!(read8p(0xfed40000) & (1 << 7)));
- +}
- +
- +static enum raminit_boot_mode get_boot_mode(void)
- +{
- + const uint16_t pmcon_2 = pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2);
- + const uint16_t bitmask = GEN_PMCON_2_DISB | GEN_PMCON_2_MEM_SR;
- + return (pmcon_2 & bitmask) == bitmask ? BOOTMODE_WARM : BOOTMODE_COLD;
- +}
- +
- static bool early_init_native(int s3resume)
- {
- printk(BIOS_DEBUG, "Starting native platform initialisation\n");
- @@ -24,6 +56,120 @@ static bool early_init_native(int s3resume)
- return cpu_replaced;
- }
-
- +#define MRC_CACHE_VERSION 1
- +
- +struct mrc_data {
- + const void *buffer;
- + size_t buffer_len;
- +};
- +
- +static void save_mrc_data(struct mrc_data *md)
- +{
- + mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION, md->buffer, md->buffer_len);
- +}
- +
- +static struct mrc_data prepare_mrc_cache(void)
- +{
- + struct mrc_data md = {0};
- + md.buffer = mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
- + MRC_CACHE_VERSION,
- + &md.buffer_len);
- + return md;
- +}
- +
- +static const char *const bm_names[] = {
- + "BOOTMODE_COLD",
- + "BOOTMODE_WARM",
- + "BOOTMODE_S3",
- + "BOOTMODE_FAST",
- +};
- +
- +static void clear_disb(void)
- +{
- + pci_and_config16(PCH_LPC_DEV, GEN_PMCON_2, ~GEN_PMCON_2_DISB);
- +}
- +
- +static void raminit_reset(void)
- +{
- + clear_disb();
- + system_reset();
- +}
- +
- +static enum raminit_boot_mode do_actual_raminit(
- + struct mrc_data *md,
- + const bool s3resume,
- + const bool cpu_replaced,
- + const enum raminit_boot_mode orig_bootmode)
- +{
- + enum raminit_boot_mode bootmode = orig_bootmode;
- +
- + bool save_data_valid = md->buffer && md->buffer_len == USHRT_MAX; /** TODO: sizeof() **/
- +
- + if (s3resume) {
- + if (bootmode == BOOTMODE_COLD) {
- + printk(BIOS_EMERG, "Memory may not be in self-refresh for S3 resume\n");
- + printk(BIOS_EMERG, "S3 resume and cold boot are mutually exclusive\n");
- + raminit_reset();
- + }
- + /* Only a true mad hatter would replace a CPU in S3 */
- + if (cpu_replaced) {
- + printk(BIOS_EMERG, "Oh no, CPU was replaced during S3\n");
- + /*
- + * No reason to continue, memory consistency is most likely lost
- + * and ME will probably request a reset through DID response too.
- + */
- + /** TODO: Figure out why past self commented this out **/
- + //raminit_reset();
- + }
- + bootmode = BOOTMODE_S3;
- + if (!save_data_valid) {
- + printk(BIOS_EMERG, "No training data, S3 resume is impossible\n");
- + /* Failed S3 resume, reset to come up cleanly */
- + raminit_reset();
- + }
- + }
- + if (!s3resume && cpu_replaced) {
- + printk(BIOS_NOTICE, "CPU was replaced, forcing a cold boot\n");
- + /*
- + * Looks like the ME will get angry if raminit takes too long.
- + * It will report that the CPU has been replaced on next boot.
- + * Try to continue anyway. This should not happen in most cases.
- + */
- + /** TODO: Figure out why past self commented this out **/
- + //save_data_valid = false;
- + }
- + if (bootmode == BOOTMODE_COLD) {
- + /* If possible, promote to a fast boot */
- + if (save_data_valid)
- + bootmode = BOOTMODE_FAST;
- +
- + clear_disb();
- + } else if (bootmode == BOOTMODE_WARM) {
- + /* If a warm reset happened before raminit is done, force a cold boot */
- + if (mchbar_read32(SSKPD) == 0 && mchbar_read32(SSKPD + 4) == 0) {
- + printk(BIOS_NOTICE, "Warm reset occurred early in cold boot\n");
- + save_data_valid = false;
- + }
- + if (!save_data_valid)
- + bootmode = BOOTMODE_COLD;
- + }
- + assert(save_data_valid != (bootmode == BOOTMODE_COLD));
- + if (save_data_valid) {
- + printk(BIOS_INFO, "Using cached memory parameters\n");
- + die("RAMINIT: Fast boot is not yet implemented\n");
- + }
- + printk(RAM_DEBUG, "Initial bootmode: %s\n", bm_names[orig_bootmode]);
- + printk(RAM_DEBUG, "Current bootmode: %s\n", bm_names[bootmode]);
- +
- + /*
- + * And now, the actual memory initialization thing.
- + */
- + printk(RAM_DEBUG, "\nStarting native raminit\n");
- + raminit_main(bootmode);
- +
- + return bootmode;
- +}
- +
- void perform_raminit(const int s3resume)
- {
- /*
- @@ -32,17 +178,48 @@ void perform_raminit(const int s3resume)
- */
- const bool cpu_replaced = early_init_native(s3resume);
-
- - (void)cpu_replaced;
- + wait_txt_clear();
- + wrmsr(0x2e6, (msr_t) {.lo = 0, .hi = 0});
- +
- + const enum raminit_boot_mode orig_bootmode = get_boot_mode();
- +
- + struct mrc_data md = prepare_mrc_cache();
- +
- + const enum raminit_boot_mode bootmode =
- + do_actual_raminit(&md, s3resume, cpu_replaced, orig_bootmode);
- +
- + /** TODO: report_memory_config **/
-
- - /** TODO: Move after raminit */
- if (intel_early_me_uma_size() > 0) {
- - /** TODO: Update status once raminit is implemented **/
- - uint8_t me_status = ME_INIT_STATUS_ERROR;
- + /*
- + * The 'other' success value is to report loss of memory
- + * consistency to ME if warm boot was downgraded to cold.
- + */
- + uint8_t me_status;
- + if (BOOTMODE_WARM == orig_bootmode && BOOTMODE_COLD == bootmode)
- + me_status = ME_INIT_STATUS_SUCCESS_OTHER;
- + else
- + me_status = ME_INIT_STATUS_SUCCESS;
- +
- + /** TODO: Remove this once raminit is implemented **/
- + me_status = ME_INIT_STATUS_ERROR;
- intel_early_me_init_done(me_status);
- }
-
- + post_code(0x3b);
- +
- intel_early_me_status();
-
- - /** TODO: Implement the required magic **/
- - die("NATIVE RAMINIT: More Magic (tm) required.\n");
- + const bool cbmem_was_initted = !cbmem_recovery(s3resume);
- + if (s3resume && !cbmem_was_initted) {
- + /* Failed S3 resume, reset to come up cleanly */
- + printk(BIOS_CRIT, "Failed to recover CBMEM in S3 resume.\n");
- + system_reset();
- + }
- +
- + /* Save training data on non-S3 resumes */
- + if (!s3resume)
- + save_mrc_data(&md);
- +
- + /** TODO: setup_sdram_meminfo **/
- }
- diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
- new file mode 100644
- index 0000000000..885f0184f4
- --- /dev/null
- +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
- @@ -0,0 +1,34 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef HASWELL_RAMINIT_NATIVE_H
- +#define HASWELL_RAMINIT_NATIVE_H
- +
- +enum raminit_boot_mode {
- + BOOTMODE_COLD,
- + BOOTMODE_WARM,
- + BOOTMODE_S3,
- + BOOTMODE_FAST,
- +};
- +
- +enum raminit_status {
- + RAMINIT_STATUS_SUCCESS = 0,
- + RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
- +};
- +
- +enum generic_stepping {
- + STEPPING_A0 = 1,
- + STEPPING_B0 = 2,
- + STEPPING_C0 = 3,
- +};
- +
- +struct sysinfo {
- + enum raminit_boot_mode bootmode;
- + enum generic_stepping stepping;
- + uint32_t cpu; /* CPUID value */
- +
- + bool dq_pins_interleaved;
- +};
- +
- +void raminit_main(enum raminit_boot_mode bootmode);
- +
- +#endif
- --
- 2.39.2
|