clear-pkgs-linux-iot-lts2018/0901-trusty-fix-rcu_preempt...

158 lines
4.4 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Yan, Shaoou" <shaopu.yan@intel.com>
Date: Fri, 9 Dec 2016 05:33:22 +0000
Subject: [PATCH] trusty: fix rcu_preempt soft lockup crash issue
since we'll run a long TEE/Trusty task, e.g generate 3K RSA key pair,
the previous API not meet the requirement of "must be fast and non-blocking
for smp_call_function_single()", we replace smp_call_function_single()
with work_on_cpu() to bind cpu #0, which can fix the rcu_preempt softup
crash issue.
Change-Id: I63225c16be50b1ff21accb2ae51114d377c45059
Signed-off-by: Zhu, Bing <bing.zhu@intel.com>
Signed-off-by: Yan, shaopu <shaopu.yan@intel.com>
Reviewed-by: Ilkka Koskinen <ilkka.koskinen@intel.com>
---
drivers/trusty/trusty.c | 101 ++++++++++++++++++++--------------------
1 file changed, 50 insertions(+), 51 deletions(-)
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index cfef965402c4..679c5a9a7acf 100644
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -203,59 +203,22 @@ static ulong trusty_std_call_inner(struct device *dev, ulong smcnr,
return ret;
}
-static void trusty_std_call_inner_wrapper_remote(void *args)
-{
- struct trusty_smc_interface *p_args = args;
- struct device *dev = p_args->dev;
- ulong smcnr = p_args->args[0];
- ulong a0 = p_args->args[1];
- ulong a1 = p_args->args[2];
- ulong a2 = p_args->args[3];
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- ulong ret;
- unsigned long flags;
-
- local_irq_save(flags);
- atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_PREPARE,
- NULL);
- ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
- atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_RETURNED,
- NULL);
- local_irq_restore(flags);
-
- p_args->args[4] = ret;
-}
-
-static ulong trusty_std_call_inner_wrapper(struct device *dev, ulong smcnr,
- ulong a0, ulong a1, ulong a2)
-{
- int cpu = 0;
- int ret = 0;
- struct trusty_smc_interface s;
- s.dev = dev;
- s.args[0] = smcnr;
- s.args[1] = a0;
- s.args[2] = a1;
- s.args[3] = a2;
- s.args[4] = 0;
-
- ret = smp_call_function_single(cpu, trusty_std_call_inner_wrapper_remote, (void *)&s, 1);
-
- if (ret) {
- pr_err("%s: smp_call_function_single failed: %d\n", __func__, ret);
- }
-
- return s.args[4];
-}
-
static ulong trusty_std_call_helper(struct device *dev, ulong smcnr,
ulong a0, ulong a1, ulong a2)
{
ulong ret;
int sleep_time = 1;
+ unsigned long flags;
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
while (true) {
- ret = trusty_std_call_inner_wrapper(dev, smcnr, a0, a1, a2);
+ local_irq_save(flags);
+ atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_PREPARE,
+ NULL);
+ ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
+ atomic_notifier_call_chain(&s->notifier, TRUSTY_CALL_RETURNED,
+ NULL);
+ local_irq_restore(flags);
if ((int)ret != SM_ERR_BUSY)
break;
@@ -292,13 +255,33 @@ static void trusty_std_call_cpu_idle(struct trusty_state *s)
}
}
-/* must set CONFIG_DEBUG_ATOMIC_SLEEP=n
-** otherwise mutex_lock() will fail and crash
-*/
-s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
+
+struct trusty_std_call32_args {
+ struct device *dev;
+ u32 smcnr;
+ u32 a0;
+ u32 a1;
+ u32 a2;
+};
+
+static long trusty_std_call32_work(void *args)
{
int ret;
- struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+ struct device *dev;
+ u32 smcnr, a0, a1, a2;
+ struct trusty_state *s;
+ struct trusty_std_call32_args *work_args;
+
+ BUG_ON(!args);
+
+ work_args = args;
+ dev = work_args->dev;
+ s = platform_get_drvdata(to_platform_device(dev));
+
+ smcnr = work_args->smcnr;
+ a0 = work_args->a0;
+ a1 = work_args->a1;
+ a2 = work_args->a2;
BUG_ON(SMC_IS_FASTCALL(smcnr));
BUG_ON(SMC_IS_SMC64(smcnr));
@@ -334,6 +317,22 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
return ret;
}
+
+s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
+{
+ const int cpu = 0;
+ struct trusty_std_call32_args args = {
+ .dev = dev,
+ .smcnr = smcnr,
+ .a0 = a0,
+ .a1 = a1,
+ .a2 = a2,
+ };
+
+ /* bind cpu 0 for now since trusty OS is running on physical cpu #0*/
+ return work_on_cpu(cpu, trusty_std_call32_work, (void *) &args);
+}
+
EXPORT_SYMBOL(trusty_std_call32);
int trusty_call_notifier_register(struct device *dev, struct notifier_block *n)
--
https://clearlinux.org