plat/arm/fvp: Support performing SDEI platform setup in runtime
This patch introduces dynamic configuration for SDEI setup and is supported
when the new build flag SDEI_IN_FCONF is enabled. Instead of using C arrays
and processing the configuration at compile time, the config is moved to
dts files. It will be retrieved at runtime during SDEI init, using the fconf
layer.
Change-Id: If5c35a7517ba00a9f258d7f3e7c8c20cee169a31
Signed-off-by: Balint Dobszay <balint.dobszay@arm.com>
Co-authored-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/plat/arm/common/aarch64/arm_sdei.c b/plat/arm/common/aarch64/arm_sdei.c
index 493134b..3c74a46 100644
--- a/plat/arm/common/aarch64/arm_sdei.c
+++ b/plat/arm/common/aarch64/arm_sdei.c
@@ -1,16 +1,51 @@
/*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* SDEI configuration for ARM platforms */
-#include <platform_def.h>
-
#include <bl31/ehf.h>
+#include <common/debug.h>
#include <services/sdei.h>
+#if SDEI_IN_FCONF
+#include <plat/arm/common/fconf_sdei_getter.h>
+#endif
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+
+#if SDEI_IN_FCONF
+/* Private event mappings */
+static sdei_ev_map_t arm_sdei_private[PLAT_SDEI_DP_EVENT_MAX_CNT + 1] = { 0 };
+
+/* Shared event mappings */
+static sdei_ev_map_t arm_sdei_shared[PLAT_SDEI_DS_EVENT_MAX_CNT] = { 0 };
+
+void plat_sdei_setup(void)
+{
+ uint32_t i;
+
+ arm_sdei_private[0] = (sdei_ev_map_t)SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI);
+
+ for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_cnt); i++) {
+ arm_sdei_private[i + 1] = (sdei_ev_map_t)SDEI_PRIVATE_EVENT(
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_nums[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_intrs[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, private_ev_flags[i]));
+ }
+
+ for (i = 0; i < FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_cnt); i++) {
+ arm_sdei_shared[i] = (sdei_ev_map_t)SDEI_SHARED_EVENT( \
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_nums[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_intrs[i]),
+ FCONF_GET_PROPERTY(sdei, dyn_config, shared_ev_flags[i]));
+ }
+ INFO("FCONF: SDEI platform setup\n");
+}
+#else
/* Private event mappings */
static sdei_ev_map_t arm_sdei_private[] = {
PLAT_ARM_PRIVATE_SDEI_EVENTS
@@ -21,5 +56,11 @@
PLAT_ARM_SHARED_SDEI_EVENTS
};
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+#endif /* SDEI_IN_FCONF */
+
/* Export ARM SDEI events */
REGISTER_SDEI_MAP(arm_sdei_private, arm_sdei_shared);
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 3b0c39d..387c131 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -263,6 +263,9 @@
ifeq (${SDEI_SUPPORT},1)
BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c
+ifeq (${SDEI_IN_FCONF},1)
+BL31_SOURCES += plat/arm/common/fconf/fconf_sdei_getter.c
+endif
endif
# RAS sources
diff --git a/plat/arm/common/fconf/fconf_sdei_getter.c b/plat/arm/common/fconf/fconf_sdei_getter.c
new file mode 100644
index 0000000..c26e316
--- /dev/null
+++ b/plat/arm/common/fconf/fconf_sdei_getter.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <plat/arm/common/fconf_sdei_getter.h>
+
+#define PRIVATE_EVENT_NUM(i) private_events[3 * (i)]
+#define PRIVATE_EVENT_INTR(i) private_events[3 * (i) + 1]
+#define PRIVATE_EVENT_FLAGS(i) private_events[3 * (i) + 2]
+
+#define SHARED_EVENT_NUM(i) shared_events[3 * (i)]
+#define SHARED_EVENT_INTR(i) shared_events[3 * (i) + 1]
+#define SHARED_EVENT_FLAGS(i) shared_events[3 * (i) + 2]
+
+struct sdei_dyn_config_t sdei_dyn_config;
+
+int fconf_populate_sdei_dyn_config(uintptr_t config)
+{
+ uint32_t i;
+ int node, err;
+ uint32_t private_events[PLAT_SDEI_DP_EVENT_MAX_CNT * 3];
+ uint32_t shared_events[PLAT_SDEI_DS_EVENT_MAX_CNT * 3];
+
+ const void *dtb = (void *)config;
+
+ /* Check that the node offset points to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, "arm,sdei-1.0");
+ if (node < 0) {
+ ERROR("FCONF: Can't find 'arm,sdei-1.0' compatible node in dtb\n");
+ return node;
+ }
+
+ /* Read number of private mappings */
+ err = fdt_read_uint32(dtb, node, "private_event_count",
+ &sdei_dyn_config.private_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.private_ev_cnt > PLAT_SDEI_DP_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'private_event_count': %u\n",
+ sdei_dyn_config.private_ev_cnt);
+ return -1;
+ }
+
+ /* Read private mappings */
+ err = fdt_read_uint32_array(dtb, node, "private_events",
+ sdei_dyn_config.private_ev_cnt * 3, private_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'private_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.private_ev_cnt; i++) {
+ sdei_dyn_config.private_ev_nums[i] = PRIVATE_EVENT_NUM(i);
+ sdei_dyn_config.private_ev_intrs[i] = PRIVATE_EVENT_INTR(i);
+ sdei_dyn_config.private_ev_flags[i] = PRIVATE_EVENT_FLAGS(i);
+ }
+
+ /* Read number of shared mappings */
+ err = fdt_read_uint32(dtb, node, "shared_event_count",
+ &sdei_dyn_config.shared_ev_cnt);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_event_count'\n");
+ return err;
+ }
+
+ /* Check if the value is in range */
+ if (sdei_dyn_config.shared_ev_cnt > PLAT_SDEI_DS_EVENT_MAX_CNT) {
+ ERROR("FCONF: Invalid value for 'shared_event_count': %u\n",
+ sdei_dyn_config.shared_ev_cnt);
+ return -1;
+ }
+
+ /* Read shared mappings */
+ err = fdt_read_uint32_array(dtb, node, "shared_events",
+ sdei_dyn_config.shared_ev_cnt * 3, shared_events);
+ if (err < 0) {
+ ERROR("FCONF: Read cell failed for 'shared_events': %d\n", err);
+ return err;
+ }
+
+ /* Move data to fconf struct */
+ for (i = 0; i < sdei_dyn_config.shared_ev_cnt; i++) {
+ sdei_dyn_config.shared_ev_nums[i] = SHARED_EVENT_NUM(i);
+ sdei_dyn_config.shared_ev_intrs[i] = SHARED_EVENT_INTR(i);
+ sdei_dyn_config.shared_ev_flags[i] = SHARED_EVENT_FLAGS(i);
+ }
+
+ return 0;
+}
+
+FCONF_REGISTER_POPULATOR(HW_CONFIG, sdei, fconf_populate_sdei_dyn_config);