aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/agesa/state_machine.c
diff options
context:
space:
mode:
authorKyösti Mälkki <kyosti.malkki@gmail.com>2016-11-25 11:21:02 +0200
committerKyösti Mälkki <kyosti.malkki@gmail.com>2017-08-02 04:46:29 +0000
commit28c4d2f7e03f0f989bee9fba9b6268611b3f07e6 (patch)
tree0a1a36aa595936c44d79645612dfee2cb0a93547 /src/northbridge/amd/agesa/state_machine.c
parentc7dcec6a1bd082513161fd2966da41a23beebcc6 (diff)
AGESA: Introduce AGESA_LEGACY_WRAPPER and its counterpart
We define AGESA_LEGACY_WRAPPER a method of calling AGESA via functions in agesawrapper.c file. The approach implemented there makes it very inconvenient to do board-specific customisation or present common platform-specific features. Seems like it also causes assertion errors on AGESA side. The flag is applied here to all boards and then individually removed one at a time, as things get tested. New method is not to call AGESA internal functions directly, but via the dispatcher. AGESA call parameters are routed to hooks in both platform and board -directories, to allow for easy capture or modification as needed. For each AGESA dispatcher call made, eventlog entries are replayed to the console log. Also relocations of AGESA heap that took place are recorded. New method is expected to be compatible with binaryPI. Change-Id: Iac3d7f8b0354e9f02c2625576f36fe06b05eb4ce Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com> Reviewed-on: https://review.coreboot.org/18628 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/northbridge/amd/agesa/state_machine.c')
-rw-r--r--src/northbridge/amd/agesa/state_machine.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/northbridge/amd/agesa/state_machine.c b/src/northbridge/amd/agesa/state_machine.c
new file mode 100644
index 0000000000..0406eeea66
--- /dev/null
+++ b/src/northbridge/amd/agesa/state_machine.c
@@ -0,0 +1,318 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011-2012 Advanced Micro Devices, Inc.
+ * Copyright (C) 2016 Kyösti Mälkki
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include <arch/acpi.h>
+#include <bootstate.h>
+
+#include <northbridge/amd/agesa/state_machine.h>
+#include <northbridge/amd/agesa/agesa_helper.h>
+#include <northbridge/amd/agesa/BiosCallOuts.h>
+#include "amdlib.h"
+#include <cpu/amd/agesa/s3_resume.h>
+
+#include "AMD.h"
+#include "heapManager.h"
+#include "Dispatcher.h"
+
+
+#if ENV_ROMSTAGE
+#include <PlatformMemoryConfiguration.h>
+CONST PSO_ENTRY ROMDATA DefaultPlatformMemoryConfiguration[] = {PSO_END};
+#endif
+
+void agesa_set_interface(struct sysinfo *cb)
+{
+ memset(&cb->StdHeader, 0, sizeof(AMD_CONFIG_PARAMS));
+
+ cb->StdHeader.CalloutPtr = GetBiosCallout;
+}
+
+AGESA_STATUS module_dispatch(AGESA_STRUCT_NAME func,
+ AMD_CONFIG_PARAMS *StdHeader)
+{
+ MODULE_ENTRY dispatcher = AmdAgesaDispatcher;
+
+ StdHeader->Func = func;
+ return dispatcher(StdHeader);
+}
+
+static AGESA_STATUS amd_create_struct(AMD_INTERFACE_PARAMS *aip,
+ AGESA_STRUCT_NAME func, void *buf, size_t len)
+{
+ aip->AgesaFunctionName = func;
+ aip->AllocationMethod = 0;
+ aip->NewStructPtr = buf;
+ aip->NewStructSize = len;
+ if (buf != NULL && len != 0)
+ aip->AllocationMethod = ByHost;
+
+ return module_dispatch(AMD_CREATE_STRUCT, &aip->StdHeader);
+}
+
+static AGESA_STATUS amd_release_struct(AMD_INTERFACE_PARAMS *aip)
+{
+ /* Cannot release AMD_LATE_PARAMS until ACPI tables are done. */
+ if (aip->AgesaFunctionName == AMD_INIT_LATE)
+ return AGESA_SUCCESS;
+
+ return module_dispatch(AMD_RELEASE_STRUCT, &aip->StdHeader);
+}
+
+/* By design, for each valid AGESA_STRUCT_NAME, AMD_CONFIG_PARAMS
+ * can be evaluated to apply correct typecast based on Func field.
+ */
+
+static AGESA_STATUS amd_dispatch(struct sysinfo *cb,
+ AGESA_STRUCT_NAME func, AMD_CONFIG_PARAMS *StdHeader)
+{
+ AGESA_STATUS status = AGESA_UNSUPPORTED;
+
+ switch (func)
+ {
+#if ENV_ROMSTAGE
+ case AMD_INIT_RESET:
+ {
+ AMD_RESET_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitReset(cb, param);
+ board_BeforeInitReset(cb, param);
+ status = module_dispatch(func, StdHeader);
+ break;
+ }
+
+ case AMD_INIT_EARLY:
+ {
+ AMD_EARLY_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitEarly(cb, param);
+ board_BeforeInitEarly(cb, param);
+ status = module_dispatch(func, StdHeader);
+ break;
+ }
+
+ case AMD_INIT_POST:
+ {
+ AMD_POST_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitPost(cb, param);
+ board_BeforeInitPost(cb, param);
+ status = module_dispatch(func, StdHeader);
+ platform_AfterInitPost(cb, param);
+ break;
+ }
+
+ case AMD_INIT_RESUME:
+ {
+ AMD_RESUME_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitResume(cb, param);
+ status = module_dispatch(func, StdHeader);
+ platform_AfterInitResume(cb, param);
+ break;
+ }
+
+ case AMD_INIT_ENV:
+ {
+ AMD_ENV_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitEnv(cb, param);
+ board_BeforeInitEnv(cb, param);
+ status = module_dispatch(func, StdHeader);
+ platform_AfterInitEnv(cb, param);
+ break;
+ }
+
+ case AMD_S3LATE_RESTORE:
+ {
+ AMD_S3LATE_PARAMS *param = (void *)StdHeader;
+ platform_BeforeS3LateRestore(cb, param);
+ status = module_dispatch(func, StdHeader);
+ platform_AfterS3LateRestore(cb, param);
+ break;
+ }
+#endif
+#if ENV_RAMSTAGE
+ case AMD_INIT_MID:
+ {
+ AMD_MID_PARAMS *param = (void *)StdHeader;
+ platform_BeforeInitMid(cb, param);
+ board_BeforeInitMid(cb, param);
+ status = module_dispatch(func, StdHeader);
+ break;
+ }
+
+ case AMD_S3_SAVE:
+ {
+ AMD_S3SAVE_PARAMS *param = (void *)StdHeader;
+ status = module_dispatch(func, StdHeader);
+ platform_AfterS3Save(cb, param);
+ break;
+ }
+ case AMD_INIT_LATE:
+ {
+ AMD_LATE_PARAMS *param = (void *)StdHeader;
+ status = module_dispatch(func, StdHeader);
+ platform_AfterInitLate(cb, param);
+ completion_InitLate(cb, param);
+ break;
+ }
+#endif
+ default:
+ {
+ break;
+ }
+
+ }
+ return status;
+}
+
+/* DEBUG trace helper */
+
+struct agesa_state
+{
+ u8 apic_id;
+
+ AGESA_STRUCT_NAME func;
+ const char *function_name;
+};
+
+static void state_on_entry(struct agesa_state *task, AGESA_STRUCT_NAME func,
+ const char *struct_name)
+{
+ task->apic_id = (u8) (cpuid_ebx(1) >> 24);
+ task->func = func;
+ task->function_name = struct_name;
+
+ printk(BIOS_DEBUG, "\nAPIC %02d: ** Enter %s [%08x]\n",
+ task->apic_id, task->function_name, task->func);
+}
+
+static void state_on_exit(struct agesa_state *task,
+ AMD_CONFIG_PARAMS *StdHeader)
+{
+ printk(BIOS_DEBUG, "APIC %02d: Heap in %s (%d) at 0x%08x\n",
+ task->apic_id, heap_status_name(StdHeader->HeapStatus),
+ StdHeader->HeapStatus, (u32)StdHeader->HeapBasePtr);
+
+ printk(BIOS_DEBUG, "APIC %02d: ** Exit %s [%08x]\n",
+ task->apic_id, task->function_name, task->func);
+}
+
+int agesa_execute_state(struct sysinfo *cb, AGESA_STRUCT_NAME func)
+{
+ AMD_INTERFACE_PARAMS aip;
+ union {
+ AMD_RESET_PARAMS reset;
+ } agesa_params;
+ void *buf = NULL;
+ size_t len = 0;
+ const char *state_name = agesa_struct_name(func);
+
+ AGESA_STATUS status, final;
+
+ struct agesa_state task;
+ memset(&task, 0, sizeof(task));
+ state_on_entry(&task, func, state_name);
+
+ aip.StdHeader = cb->StdHeader;
+
+ /* For these calls, heap is not available. */
+ if (func == AMD_INIT_RESET) {
+ buf = (void *) &agesa_params;
+ len = sizeof(agesa_params);
+ memcpy(buf, &cb->StdHeader, sizeof(cb->StdHeader));
+ }
+
+ status = amd_create_struct(&aip, func, buf, len);
+ ASSERT(status == AGESA_SUCCESS);
+
+ /* Must call the function buffer was allocated for.*/
+ AMD_CONFIG_PARAMS *StdHeader = aip.NewStructPtr;
+ ASSERT(StdHeader->Func == func);
+
+ final = amd_dispatch(cb, func, StdHeader);
+
+ agesawrapper_trace(final, StdHeader, state_name);
+ ASSERT(final < AGESA_FATAL);
+
+ status = amd_release_struct(&aip);
+ ASSERT(status == AGESA_SUCCESS);
+
+ state_on_exit(&task, &aip.StdHeader);
+
+ return (final < AGESA_FATAL) ? 0 : -1;
+}
+
+#if ENV_RAMSTAGE
+
+static void amd_bs_ramstage_init(void *arg)
+{
+ struct sysinfo *cb = arg;
+
+ agesa_set_interface(cb);
+}
+
+void sb_After_Pci_Restore_Init(void);
+
+static void amd_bs_dev_enable(void *arg)
+{
+ struct sysinfo *cb = arg;
+
+ if (!acpi_is_wakeup_s3())
+ agesa_execute_state(cb, AMD_INIT_MID);
+
+ /* FIXME */
+ if (IS_ENABLED(CONFIG_AMD_SB_CIMX) && acpi_is_wakeup_s3())
+ sb_After_Pci_Restore_Init();
+}
+
+static void amd_bs_post_device(void *arg)
+{
+ struct sysinfo *cb = arg;
+
+ if (acpi_is_wakeup_s3())
+ return;
+
+ agesa_execute_state(cb, AMD_INIT_LATE);
+
+ if (!acpi_s3_resume_allowed())
+ return;
+
+ agesa_execute_state(cb, AMD_S3_SAVE);
+}
+
+static struct sysinfo state_machine;
+
+BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, amd_bs_ramstage_init,
+ &state_machine);
+
+BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, amd_bs_dev_enable,
+ &state_machine);
+
+BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, amd_bs_post_device,
+ &state_machine);
+
+#endif /* ENV_RAMSTAGE */
+
+/* Empty stubs for cases board does not need to override anything. */
+void __attribute__((weak))
+board_BeforeInitReset(struct sysinfo *cb, AMD_RESET_PARAMS *Reset) { }
+void __attribute__((weak))
+board_BeforeInitEarly(struct sysinfo *cb, AMD_EARLY_PARAMS *Early) { }
+void __attribute__((weak))
+board_BeforeInitPost(struct sysinfo *cb, AMD_POST_PARAMS *Post) { }
+void __attribute__((weak))
+board_BeforeInitEnv(struct sysinfo *cb, AMD_ENV_PARAMS *Env) { }
+void __attribute__((weak))
+board_BeforeInitMid(struct sysinfo *cb, AMD_MID_PARAMS *Mid) { }