summaryrefslogtreecommitdiff
path: root/src/soc/intel
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/intel')
-rw-r--r--src/soc/intel/common/Kconfig11
-rw-r--r--src/soc/intel/common/Makefile.inc45
-rw-r--r--src/soc/intel/common/mma.c244
-rw-r--r--src/soc/intel/common/mma.h27
4 files changed, 327 insertions, 0 deletions
diff --git a/src/soc/intel/common/Kconfig b/src/soc/intel/common/Kconfig
index 17c2809246..547492bf2c 100644
--- a/src/soc/intel/common/Kconfig
+++ b/src/soc/intel/common/Kconfig
@@ -48,4 +48,15 @@ config SOC_INTEL_COMMON_ACPI_WAKE_SOURCE
bool
default n
+config MMA
+ bool "enable MMA (Memory Margin Analysis) support"
+ default n
+ help
+ Set this option to y to enable MMA (Memory Margin Analysis) support
+
+config MMA_BLOBS_PATH
+ string "Path to MMA blobs"
+ depends on MMA
+ default "3rdparty/blobs/mainboard/$(MAINBOARDDIR)/mma"
+
endif # SOC_INTEL_COMMON
diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc
index 53d3b71ab3..a7218b71db 100644
--- a/src/soc/intel/common/Makefile.inc
+++ b/src/soc/intel/common/Makefile.inc
@@ -5,12 +5,14 @@ verstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c
romstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c
romstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c
romstage-y += util.c
+romstage-$(CONFIG_MMA) += mma.c
ramstage-y += hda_verb.c
ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c
ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += nvm.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c
ramstage-y += util.c
+ramstage-$(CONFIG_MMA) += mma.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI_WAKE_SOURCE) += acpi_wake_source.c
# Create and add the MRC cache to the cbfs image
@@ -26,4 +28,47 @@ mrc.cache-position := $(CONFIG_MRC_SETTINGS_CACHE_BASE)
mrc.cache-type := mrc_cache
endif
+ifeq ($(CONFIG_MMA),y)
+MMA_BLOBS_PATH = $(call strip_quotes,$(CONFIG_MMA_BLOBS_PATH))
+MMA_TEST_NAMES = $(notdir $(wildcard $(MMA_BLOBS_PATH)/tests/*))
+MMA_TEST_CONFIG_NAMES = $(notdir $(wildcard $(MMA_BLOBS_PATH)/configs/*))
+
+#
+# MMA_CBFS_template is the template to be expanded by eval
+# where $(1) is file name
+# $(2) is file path
+# $(3) is file type, efi for test names (all .EFI files under $(MMA_BLOBS_PATH)/tests )
+# , mma for test param (all .BIN files under $(MMA_BLOBS_PATH)/configs/<test name>)
+#
+# $(MMA_BLOBS_PATH)/tests/<testX>.efi has coresponding test params
+# at $(MMA_BLOBS_PATH)/configs/<testX>/<XYZ>.bin
+#
+
+
+define MMA_CBFS_template =
+ cbfs-files-y += $(1)
+ $(1)-file := $(MMA_BLOBS_PATH)/$(2)/$(1)
+ $(1)-type := $(3)
+endef
+
+#
+# following loop calls MMA_CBFS_template for each .EFI file under $(MMA_BLOBS_PATH)/tests with type = efi
+#
+$(foreach mma_test,$(MMA_TEST_NAMES),$(eval $(call MMA_CBFS_template,$(mma_test),tests,efi)))
+
+
+#
+# following nested loops calls MMA_CBFS_template for each .BIN file under each MMA_TEST_CONFIG_NAMES
+#
+# foreach <testX> do following
+# foreach <XYZ>.bin in <testX> do following
+# call MMA_CBFS_template for each <XYZ>.bin under current <testX> with type = mma
+#
+
+$(foreach mma_test, $(MMA_TEST_CONFIG_NAMES),\
+ $(eval $(foreach mma_config,$(notdir $(wildcard $(MMA_BLOBS_PATH)/configs/$(mma_test)/*)),\
+ $(eval $(call MMA_CBFS_template,$(mma_config),configs/$(mma_test),mma)))))
+
+endif
+
endif
diff --git a/src/soc/intel/common/mma.c b/src/soc/intel/common/mma.c
new file mode 100644
index 0000000000..3ac47e8d69
--- /dev/null
+++ b/src/soc/intel/common/mma.c
@@ -0,0 +1,244 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <boot/coreboot_tables.h>
+#include <bootstate.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <lib.h>
+#include "mma.h"
+#include <soc/romstage.h>
+#include <string.h>
+
+#define MMA_TEST_METADATA_FILENAME "mma_test_metadata.bin"
+#define MMA_TEST_NAME_TAG "MMA_TEST_NAME"
+#define MMA_TEST_PARAM_TAG "MMA_TEST_PARAM"
+#define TEST_NAME_MAX_SIZE 30
+#define TEST_PARAM_MAX_SIZE 100
+#define FSP_MMA_RESULTS_GUID { 0x8f4e928, 0xf5f, 0x46d4, \
+ { 0x84, 0x10, 0x47, 0x9f, 0xda, 0x27, 0x9d, 0xb6 } }
+#define MMA_DATA_SIGNATURE (('M'<<0)|('M'<<8)|('A'<<16)|('D'<<24))
+
+struct mma_data_container {
+ u32 mma_signature; // "MMAD"
+ u8 mma_data[0]; // Variable size, platform/run time dependent.
+} __attribute__ ((packed));
+
+/*
+Format of the MMA test metadata file, stored under CBFS
+MMA_TEST_NAME=xxxxxx.efi;MMA_TEST_PARAM=xxxxxx.bin;
+*/
+
+/* Returns index in haystack after 'LABEL=' string is found, < 0 on error. */
+static int find_label(const char *haystack, size_t haystack_sz,
+ const char *label)
+{
+ size_t label_sz;
+ size_t i;
+ size_t search_sz;
+
+ label_sz = strlen(label);
+
+ if (label_sz + 1 >= haystack_sz)
+ return -1;
+
+ /* Handle '=' follow label. i.e. LABEL= */
+ search_sz = haystack_sz - label_sz - 1;
+ for (i = 0; i < search_sz; i++) {
+ if (!strncmp(&haystack[i], label, label_sz))
+ break;
+ }
+
+ if (i == search_sz)
+ return -1;
+
+ if (haystack[i + label_sz] != '=')
+ return -1;
+
+ return i + label_sz + 1;
+}
+/*
+ * Fill in value in dest field located by LABEL=.
+ * Returns 0 on success, < 0 on error.
+ */
+static int label_value(const char *haystack, size_t haystack_sz,
+ const char *label, char *dest, size_t dest_sz)
+{
+ size_t val_begin;
+ size_t val_end;
+ size_t val_sz;
+ int val_index;
+
+ memset(dest, 0, dest_sz);
+
+ /* Allow for NULL termination. */
+ dest_sz--;
+ val_index = find_label(haystack, haystack_sz, label);
+ if (val_index < 0)
+ return -1;
+
+ val_begin = val_index;
+ val_end = val_begin;
+ val_sz = 0;
+
+ for (val_end = val_begin; val_end < haystack_sz; val_end++) {
+ if (haystack[val_end] == ';') {
+ val_sz = val_end - val_begin;
+ break;
+ }
+ }
+
+ if (val_end == haystack_sz)
+ return -1;
+
+ if (dest_sz < val_sz)
+ return -1;
+
+ memcpy(dest, &haystack[val_begin], val_sz);
+
+ return 0;
+}
+
+void setup_mma(MEMORY_INIT_UPD *memory_params)
+{
+ void *mma_test_metadata, *mma_test_content, *mma_test_param;
+ size_t mma_test_metadata_file_len, mma_test_content_file_len,
+ mma_test_param_file_len;
+ char test_filename[TEST_NAME_MAX_SIZE],
+ test_param_filename[TEST_PARAM_MAX_SIZE];
+
+ printk(BIOS_DEBUG, "Entry setup_mma\n");
+
+ memory_params->MmaTestContentPtr = 0;
+ memory_params->MmaTestContentSize = 0;
+ memory_params->MmaTestConfigPtr = 0;
+ memory_params->MmaTestConfigSize = 0;
+
+ mma_test_metadata = cbfs_boot_map_with_leak(MMA_TEST_METADATA_FILENAME,
+ CBFS_TYPE_MMA , &mma_test_metadata_file_len);
+
+ if (!mma_test_metadata) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s\n",
+ MMA_TEST_METADATA_FILENAME);
+ return;
+ }
+
+ if (label_value(mma_test_metadata, mma_test_metadata_file_len,
+ MMA_TEST_NAME_TAG, test_filename, TEST_NAME_MAX_SIZE)) {
+ printk(BIOS_DEBUG, "MMA setup failed : Failed to get %s",
+ MMA_TEST_NAME_TAG);
+ return;
+ }
+
+ if (label_value(mma_test_metadata, mma_test_metadata_file_len,
+ MMA_TEST_PARAM_TAG, test_param_filename,
+ TEST_PARAM_MAX_SIZE)) {
+ printk(BIOS_DEBUG, "MMA setup failed : Failed to get %s",
+ MMA_TEST_PARAM_TAG);
+ return;
+ }
+
+ printk(BIOS_DEBUG, "Got MMA_TEST_NAME=%s MMA_TEST_PARAM=%s\n",
+ test_filename, test_param_filename);
+
+ mma_test_content = cbfs_boot_map_with_leak(test_filename,
+ CBFS_TYPE_EFI , &mma_test_content_file_len);
+ if (!mma_test_content) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s.\n",
+ test_filename);
+ return;
+ }
+
+ mma_test_param = cbfs_boot_map_with_leak(test_param_filename,
+ CBFS_TYPE_MMA , &mma_test_param_file_len);
+ if (!mma_test_param) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s.\n",
+ test_param_filename);
+ return;
+ }
+
+ memory_params->MmaTestContentPtr = (uintptr_t) mma_test_content;
+ memory_params->MmaTestContentSize = mma_test_content_file_len;
+ memory_params->MmaTestConfigPtr = (uintptr_t) mma_test_param;
+ memory_params->MmaTestConfigSize = mma_test_param_file_len;
+ memory_params->MrcFastBoot = 0x00;
+
+ printk(BIOS_DEBUG, "MMA Test name %s\n", test_filename);
+ printk(BIOS_DEBUG, "MMA Test Config name %s\n", test_param_filename);
+ printk(BIOS_DEBUG, "MMA passing following memory_params\n");
+ printk(BIOS_DEBUG, "memory_params->MmaTestContentPtr = %0x\n",
+ memory_params->MmaTestContentPtr);
+ printk(BIOS_DEBUG, "memory_params->MmaTestContentSize = %d\n",
+ memory_params->MmaTestContentSize);
+ printk(BIOS_DEBUG, "memory_params->MmaTestConfigPtr = %0x\n",
+ memory_params->MmaTestConfigPtr);
+ printk(BIOS_DEBUG, "memory_params->MmaTestConfigSize = %d\n",
+ memory_params->MmaTestConfigSize);
+ printk(BIOS_DEBUG, "memory_params->MrcFastBoot = %d\n",
+ memory_params->MrcFastBoot);
+ printk(BIOS_DEBUG, "MMA setup successfully\n");
+}
+
+static void save_mma_results_data(void *unused)
+{
+ void *mma_results_hob;
+ u32 mma_hob_size;
+ u32 *mma_hob_data;
+ struct mma_data_container *mma_data;
+ int cbmem_size;
+
+ const EFI_GUID mma_results_guid = FSP_MMA_RESULTS_GUID;
+
+ printk(BIOS_DEBUG, "Entry save_mma_results_data MMA save data.\n");
+
+ mma_results_hob = get_first_guid_hob(&mma_results_guid);
+ if (mma_results_hob == NULL) {
+ printk(BIOS_DEBUG,
+ "MMA results data Hob not present\n");
+ return;
+ }
+
+ mma_hob_data = GET_GUID_HOB_DATA(mma_results_hob);
+ mma_hob_size = GET_HOB_LENGTH(mma_results_hob);
+ cbmem_size = ALIGN(mma_hob_size, 16) +
+ sizeof(struct mma_data_container);
+ mma_data = cbmem_add(CBMEM_ID_MMA_DATA, cbmem_size);
+
+ if (mma_data == NULL) {
+ printk(BIOS_DEBUG,
+ "CBMEM was not available to save the MMA data.\n");
+ return;
+ }
+
+ /*clear the mma_data before coping the actual data */
+ memset(mma_data, 0, cbmem_size);
+
+ printk(BIOS_DEBUG,
+ "Copy MMA DATA to HOB(src addr %p, dest addr %p, %u bytes)\n",
+ mma_hob_data, mma_data, mma_hob_size);
+
+ mma_data->mma_signature = MMA_DATA_SIGNATURE;
+ memcpy(mma_data->mma_data, mma_hob_data, mma_hob_size);
+
+ printk(BIOS_DEBUG, "write MMA results data to cbmem success\n");
+}
+
+BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
+ save_mma_results_data, NULL);
diff --git a/src/soc/intel/common/mma.h b/src/soc/intel/common/mma.h
new file mode 100644
index 0000000000..ab25adab6f
--- /dev/null
+++ b/src/soc/intel/common/mma.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef _SOC_MMA_H_
+#define _SOC_MMA_H_
+
+#include <fsp/soc_binding.h>
+
+void setup_mma(MEMORY_INIT_UPD *memory_params);
+
+#endif