[PATCH v4 02/15] firmware/psci: Add psci_early_test_conduit()

Steven Price
2024-07-01T09:55:24Z

From: Jean-Philippe Brucker <jean-philippe@linaro.org>

Add a function to test early if PSCI is present and what conduit it
uses. Because the PSCI conduit corresponds to the SMCCC one, this will
let the kernel know whether it can use SMC instructions to discuss with
the Realm Management Monitor (RMM), early enough to enable RAM and
serial access when running in a Realm.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Steven Price <steven.price@arm.com>
---
v4: New patch
---
drivers/firmware/psci/psci.c | 25 +++++++++++++++++++++++++
include/linux/psci.h | 5 +++++
2 files changed, 30 insertions(+)

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index d9629ff87861..a40dcaf17822 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -13,6 +13,7 @@
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/of.h>
+#include <linux/of_fdt.h>
#include <linux/pm.h>
#include <linux/printk.h>
#include <linux/psci.h>
@@ -767,6 +768,30 @@ int __init psci_dt_init(void)
return ret;
}

+/*
+ * Test early if PSCI is supported, and if its conduit matches @conduit
+ */
+bool __init psci_early_test_conduit(enum arm_smccc_conduit conduit)
+{
+ int len;
+ int psci_node;
+ const char *method;
+ unsigned long dt_root;
+
+ /* DT hasn't been unflattened yet, we have to work with the flat blob */
+ dt_root = of_get_flat_dt_root();
+ psci_node = of_get_flat_dt_subnode_by_name(dt_root, "psci");
+ if (psci_node <= 0)
+ return false;
+
+ method = of_get_flat_dt_prop(psci_node, "method", &len);
+ if (!method)
+ return false;
+
+ return (conduit == SMCCC_CONDUIT_SMC && strncmp(method, "smc", len) == 0) ||
+ (conduit == SMCCC_CONDUIT_HVC && strncmp(method, "hvc", len) == 0);
+}
+
#ifdef CONFIG_ACPI
/*
* We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 4ca0060a3fc4..a1fc1703ba20 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -45,8 +45,13 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void);

#if defined(CONFIG_ARM_PSCI_FW)
int __init psci_dt_init(void);
+bool __init psci_early_test_conduit(enum arm_smccc_conduit conduit);
#else
static inline int psci_dt_init(void) { return 0; }
+static inline bool psci_early_test_conduit(enum arm_smccc_conduit conduit)
+{
+ return false;
+}
#endif

#if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI)
--
2.34.1