clear-pkgs-linux-iot-lts2018/0894-trusty-implement-trust...

180 lines
5.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Zhu, Bing" <bing.zhu@intel.com>
Date: Fri, 15 Jul 2016 13:24:42 +0800
Subject: [PATCH] trusty: implement trusty OS timer proxy for performance
enhancement
Previously VMX timer causes 14 times of vmexit/vmresume switches every
10ms and VMX timer stops when processor enters C3+ sleep state. With
linux proxiedtimer implementation, we can reduces vmexit/vmresume
switches down to 4. But a drawback is that Trusty OS has no timer
during the boot time (before Linux kernel bringup), because Trusty OS
also intends to be used to provide services for bootloader, like GVB
and FRP(factor reset protection). We plan to solve it in other ways,
e.g. taking control of lapic timer before Linux kernel boot.
Change-Id: I4baa827ecca51fcca5315a1e973a7533553073a0
Signed-off-by: Zhu, Bing <bing.zhu@intel.com>
Signed-off-by: Feng, Wang <feng.f.wang@intel.com>
Signed-off-by: weideng <wei.a.deng@intel.com>
Tracked-On: OAM-39152
---
drivers/trusty/trusty-irq.c | 2 -
drivers/trusty/trusty.c | 87 +++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/drivers/trusty/trusty-irq.c b/drivers/trusty/trusty-irq.c
index b325bff33774..2c2a792a3636 100644
--- a/drivers/trusty/trusty-irq.c
+++ b/drivers/trusty/trusty-irq.c
@@ -631,8 +631,6 @@ static int trusty_irq_probe(struct platform_device *pdev)
for (irq = 0; irq >= 0;)
irq = trusty_irq_init_one(is, irq, false);
- irq_register_done();
-
is->cpu_notifier.notifier_call = trusty_irq_cpu_notify;
ret = register_hotcpu_notifier(&is->cpu_notifier);
if (ret) {
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index 12a90224eb27..8daf817634d8 100644
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -26,11 +26,23 @@
#include <linux/trusty/trusty.h>
#define TRUSTY_VMCALL_SMC 0x74727500
+#define TRUSTY_LKTIMER_INTERVAL 10 /* 10 ms */
+#define TRUSTY_LKTIMER_VECTOR 0x31 /* INT_PIT */
+
+enum lktimer_mode {
+ ONESHOT_TIMER,
+ PERIODICAL_TIMER,
+};
struct trusty_state {
+ struct device *dev;
struct mutex smc_lock;
struct atomic_notifier_head notifier;
struct completion cpu_idle_completion;
+ struct timer_list timer;
+ struct work_struct timer_work;
+ enum lktimer_mode timer_mode;
+ unsigned long timer_interval;
char *version_str;
u32 api_version;
};
@@ -40,6 +52,72 @@ struct trusty_smc_interface {
ulong args[5];
};
+static void trusty_lktimer_work_func(struct work_struct *work)
+{
+ int ret;
+ unsigned int vector;
+ struct trusty_state *s =
+ container_of(work, struct trusty_state, timer_work);
+
+ dev_dbg(s->dev, "%s\n", __func__);
+
+ /* need vector number only for the first time */
+ vector = TRUSTY_LKTIMER_VECTOR;
+
+ do {
+ ret = trusty_std_call32(s->dev, SMC_SC_NOP, vector, 0, 0);
+ vector = 0;
+ } while (ret == SM_ERR_NOP_INTERRUPTED);
+
+ if (ret != SM_ERR_NOP_DONE)
+ dev_err(s->dev, "%s: SMC_SC_NOP failed %d", __func__, ret);
+
+ dev_notice_once(s->dev, "LK OS proxy timer works\n");
+}
+
+static void trusty_lktimer_func(unsigned long data)
+{
+ struct trusty_state *s = (struct trusty_state *)data;
+
+ /* binding it physical CPU0 only because trusty OS runs on it */
+ schedule_work_on(0, &s->timer_work);
+
+ /* reactivate the timer again in periodic mode */
+ if (s->timer_mode == PERIODICAL_TIMER)
+ mod_timer(&s->timer,
+ jiffies + msecs_to_jiffies(s->timer_interval));
+}
+
+static void trusty_init_lktimer(struct trusty_state *s)
+{
+ INIT_WORK(&s->timer_work, trusty_lktimer_work_func);
+ setup_timer(&s->timer, trusty_lktimer_func, (unsigned long)s);
+}
+
+/* note that this function is not thread-safe */
+static void trusty_configure_lktimer(struct trusty_state *s,
+ enum lktimer_mode mode, unsigned long interval)
+{
+ if (mode != ONESHOT_TIMER && mode != PERIODICAL_TIMER) {
+ pr_err("%s: invalid timer mode: %d\n", __func__, mode);
+ return;
+ }
+
+ s->timer_mode = mode;
+ s->timer_interval = interval;
+ mod_timer(&s->timer, jiffies + msecs_to_jiffies(s->timer_interval));
+}
+
+/*
+ * this should be called when removing trusty dev and
+ * when LK/Trusty crashes, to disable proxy timer.
+ */
+static void trusty_del_lktimer(struct trusty_state *s)
+{
+ del_timer_sync(&s->timer);
+ flush_work(&s->timer_work);
+}
+
static inline ulong smc(ulong r0, ulong r1, ulong r2, ulong r3)
{
__asm__ __volatile__(
@@ -246,6 +324,9 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
WARN_ONCE(ret == SM_ERR_PANIC, "trusty crashed");
+ if (ret == SM_ERR_PANIC)
+ trusty_del_lktimer(s);
+
if (smcnr == SMC_SC_NOP)
complete(&s->cpu_idle_completion);
else
@@ -384,6 +465,7 @@ static int trusty_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&s->notifier);
init_completion(&s->cpu_idle_completion);
platform_set_drvdata(pdev, s);
+ s->dev = &pdev->dev;
trusty_init_version(s, &pdev->dev);
@@ -391,6 +473,10 @@ static int trusty_probe(struct platform_device *pdev)
if (ret < 0)
goto err_api_version;
+ trusty_init_lktimer(s);
+ trusty_configure_lktimer(s,
+ PERIODICAL_TIMER, TRUSTY_LKTIMER_INTERVAL);
+
return 0;
err_api_version:
@@ -417,6 +503,7 @@ static int trusty_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_trusty_version);
kfree(s->version_str);
}
+ trusty_del_lktimer(s);
kfree(s);
return 0;
}
--
https://clearlinux.org