224 lines
7.2 KiB
Diff
224 lines
7.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= <arve@android.com>
|
|
Date: Fri, 23 Jan 2015 17:55:48 -0800
|
|
Subject: [PATCH] trusty: Add smp support
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Add an unlocked nop call to allow multiple cpus to enter trusty.
|
|
Other standard calls are still serialized to avoid return codes
|
|
getting mixed up.
|
|
A new return code is used to indicate that the standard call is
|
|
running on another cpu.
|
|
|
|
Change-Id: I0eecb88fb28989e3f4942659d109eee8863f3227
|
|
Signed-off-by: Arve Hjønnevåg <arve@android.com>
|
|
---
|
|
drivers/trusty/trusty-irq.c | 31 ++++++++++++++++++++++++++++---
|
|
drivers/trusty/trusty.c | 27 ++++++++++++++++++++++++---
|
|
include/linux/trusty/sm_err.h | 3 +++
|
|
include/linux/trusty/smcall.h | 17 +++++++++++++++--
|
|
4 files changed, 70 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/trusty/trusty-irq.c b/drivers/trusty/trusty-irq.c
|
|
index ae9535af77dd..1f14f7f48bed 100644
|
|
--- a/drivers/trusty/trusty-irq.c
|
|
+++ b/drivers/trusty/trusty-irq.c
|
|
@@ -154,7 +154,7 @@ static int trusty_irq_call_notify(struct notifier_block *nb,
|
|
}
|
|
|
|
|
|
-static void trusty_irq_work_func(struct work_struct *work)
|
|
+static void trusty_irq_work_func_locked_nop(struct work_struct *work)
|
|
{
|
|
int ret;
|
|
struct trusty_irq_state *is =
|
|
@@ -162,8 +162,27 @@ static void trusty_irq_work_func(struct work_struct *work)
|
|
|
|
dev_dbg(is->dev, "%s\n", __func__);
|
|
|
|
- ret = trusty_std_call32(is->trusty_dev, SMC_SC_NOP, 0, 0, 0);
|
|
+ ret = trusty_std_call32(is->trusty_dev, SMC_SC_LOCKED_NOP, 0, 0, 0);
|
|
if (ret != 0)
|
|
+ dev_err(is->dev, "%s: SMC_SC_LOCKED_NOP failed %d",
|
|
+ __func__, ret);
|
|
+
|
|
+ dev_dbg(is->dev, "%s: done\n", __func__);
|
|
+}
|
|
+
|
|
+static void trusty_irq_work_func(struct work_struct *work)
|
|
+{
|
|
+ int ret;
|
|
+ struct trusty_irq_state *is =
|
|
+ container_of(work, struct trusty_irq_work, work)->is;
|
|
+
|
|
+ dev_dbg(is->dev, "%s\n", __func__);
|
|
+
|
|
+ do {
|
|
+ ret = trusty_std_call32(is->trusty_dev, SMC_SC_NOP, 0, 0, 0);
|
|
+ } while (ret == SM_ERR_NOP_INTERRUPTED);
|
|
+
|
|
+ if (ret != SM_ERR_NOP_DONE)
|
|
dev_err(is->dev, "%s: SMC_SC_NOP failed %d", __func__, ret);
|
|
|
|
dev_dbg(is->dev, "%s: done\n", __func__);
|
|
@@ -397,6 +416,7 @@ static int trusty_irq_probe(struct platform_device *pdev)
|
|
unsigned int cpu;
|
|
unsigned long irq_flags;
|
|
struct trusty_irq_state *is;
|
|
+ work_func_t work_func;
|
|
|
|
dev_dbg(&pdev->dev, "%s\n", __func__);
|
|
|
|
@@ -431,12 +451,17 @@ static int trusty_irq_probe(struct platform_device *pdev)
|
|
goto err_trusty_call_notifier_register;
|
|
}
|
|
|
|
+ if (trusty_get_api_version(is->trusty_dev) < TRUSTY_API_VERSION_SMP)
|
|
+ work_func = trusty_irq_work_func_locked_nop;
|
|
+ else
|
|
+ work_func = trusty_irq_work_func;
|
|
+
|
|
for_each_possible_cpu(cpu) {
|
|
struct trusty_irq_work *trusty_irq_work;
|
|
|
|
trusty_irq_work = per_cpu_ptr(is->irq_work, cpu);
|
|
trusty_irq_work->is = is;
|
|
- INIT_WORK(&trusty_irq_work->work, trusty_irq_work_func);
|
|
+ INIT_WORK(&trusty_irq_work->work, work_func);
|
|
}
|
|
|
|
for (irq = 0; irq >= 0;)
|
|
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
|
|
index 4b5d3552720b..2a7aeb4725c5 100644
|
|
--- a/drivers/trusty/trusty.c
|
|
+++ b/drivers/trusty/trusty.c
|
|
@@ -28,6 +28,7 @@
|
|
struct trusty_state {
|
|
struct mutex smc_lock;
|
|
struct atomic_notifier_head notifier;
|
|
+ struct completion cpu_idle_completion;
|
|
char *version_str;
|
|
u32 api_version;
|
|
};
|
|
@@ -161,6 +162,17 @@ static ulong trusty_std_call_helper(struct device *dev, ulong smcnr,
|
|
return ret;
|
|
}
|
|
|
|
+static void trusty_std_call_cpu_idle(struct trusty_state *s)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = wait_for_completion_timeout(&s->cpu_idle_completion, HZ * 10);
|
|
+ if (!ret) {
|
|
+ pr_warn("%s: timed out waiting for cpu idle to clear, retry anyway\n",
|
|
+ __func__);
|
|
+ }
|
|
+}
|
|
+
|
|
s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
|
|
{
|
|
int ret;
|
|
@@ -169,15 +181,20 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
|
|
BUG_ON(SMC_IS_FASTCALL(smcnr));
|
|
BUG_ON(SMC_IS_SMC64(smcnr));
|
|
|
|
- mutex_lock(&s->smc_lock);
|
|
+ if (smcnr != SMC_SC_NOP) {
|
|
+ mutex_lock(&s->smc_lock);
|
|
+ reinit_completion(&s->cpu_idle_completion);
|
|
+ }
|
|
|
|
dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) started\n",
|
|
__func__, smcnr, a0, a1, a2);
|
|
|
|
ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2);
|
|
- while (ret == SM_ERR_INTERRUPTED) {
|
|
+ while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) {
|
|
dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) interrupted\n",
|
|
__func__, smcnr, a0, a1, a2);
|
|
+ if (ret == SM_ERR_CPU_IDLE)
|
|
+ trusty_std_call_cpu_idle(s);
|
|
ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0);
|
|
}
|
|
dev_dbg(dev, "%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n",
|
|
@@ -185,7 +202,10 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
|
|
|
|
WARN_ONCE(ret == SM_ERR_PANIC, "trusty crashed");
|
|
|
|
- mutex_unlock(&s->smc_lock);
|
|
+ if (smcnr == SMC_SC_NOP)
|
|
+ complete(&s->cpu_idle_completion);
|
|
+ else
|
|
+ mutex_unlock(&s->smc_lock);
|
|
|
|
return ret;
|
|
}
|
|
@@ -315,6 +335,7 @@ static int trusty_probe(struct platform_device *pdev)
|
|
}
|
|
mutex_init(&s->smc_lock);
|
|
ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier);
|
|
+ init_completion(&s->cpu_idle_completion);
|
|
platform_set_drvdata(pdev, s);
|
|
|
|
trusty_init_version(s, &pdev->dev);
|
|
diff --git a/include/linux/trusty/sm_err.h b/include/linux/trusty/sm_err.h
|
|
index 7de09b46fddb..32ee08e499c3 100644
|
|
--- a/include/linux/trusty/sm_err.h
|
|
+++ b/include/linux/trusty/sm_err.h
|
|
@@ -36,5 +36,8 @@
|
|
#define SM_ERR_END_OF_INPUT -10
|
|
#define SM_ERR_PANIC -11 /* Secure OS crashed */
|
|
#define SM_ERR_FIQ_INTERRUPTED -12 /* Got interrupted by FIQ. Call back with SMC_SC_RESTART_FIQ on same CPU */
|
|
+#define SM_ERR_CPU_IDLE -13 /* SMC call waiting for another CPU */
|
|
+#define SM_ERR_NOP_INTERRUPTED -14 /* Got interrupted. Call back with new SMC_SC_NOP */
|
|
+#define SM_ERR_NOP_DONE -15 /* Cpu idle after SMC_SC_NOP (not an error) */
|
|
|
|
#endif
|
|
diff --git a/include/linux/trusty/smcall.h b/include/linux/trusty/smcall.h
|
|
index 7d8950a8890e..2e43803d9333 100644
|
|
--- a/include/linux/trusty/smcall.h
|
|
+++ b/include/linux/trusty/smcall.h
|
|
@@ -56,7 +56,7 @@
|
|
|
|
/* FC = Fast call, SC = Standard call */
|
|
#define SMC_SC_RESTART_LAST SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0)
|
|
-#define SMC_SC_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1)
|
|
+#define SMC_SC_LOCKED_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1)
|
|
|
|
/**
|
|
* SMC_SC_RESTART_FIQ - Re-enter trusty after it was interrupted by an fiq
|
|
@@ -70,6 +70,18 @@
|
|
*/
|
|
#define SMC_SC_RESTART_FIQ SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2)
|
|
|
|
+/**
|
|
+ * SMC_SC_NOP - Enter trusty to run pending work.
|
|
+ *
|
|
+ * No arguments.
|
|
+ *
|
|
+ * Returns SM_ERR_NOP_INTERRUPTED or SM_ERR_NOP_DONE.
|
|
+ * If SM_ERR_NOP_INTERRUPTED is returned, the call must be repeated.
|
|
+ *
|
|
+ * Enable by selecting api version TRUSTY_API_VERSION_SMP (2) or later.
|
|
+ */
|
|
+#define SMC_SC_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3)
|
|
+
|
|
/*
|
|
* Return from secure os to non-secure os with return value in r1
|
|
*/
|
|
@@ -107,7 +119,8 @@
|
|
* This call must be made before any calls that are affected by the api version.
|
|
*/
|
|
#define TRUSTY_API_VERSION_RESTART_FIQ (1)
|
|
-#define TRUSTY_API_VERSION_CURRENT (1)
|
|
+#define TRUSTY_API_VERSION_SMP (2)
|
|
+#define TRUSTY_API_VERSION_CURRENT (2)
|
|
#define SMC_FC_API_VERSION SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 11)
|
|
|
|
/* TRUSTED_OS entity calls */
|
|
--
|
|
https://clearlinux.org
|
|
|