blob: 9854be1c54b1fefd63c0a46b7bc784cfc45e5882 [file] [log] [blame]
From 41cab33091954ec655e7fe567c345f5a44fea122 Mon Sep 17 00:00:00 2001
From: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Date: Fri, 14 Jan 2022 14:02:39 +0000
Subject: [PATCH 30/40] ANDROID: trusty: Separate out SMC based transport
This commit refactors SMC based transport operation like
smc_fastcalls, smc memory operations in a separate file.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Iebee505b7172f6247186e3bf1e0b50740b2e4dfa
Upstream-Status: Pending [Not submitted to upstream yet]
Signed-off-by: Rupinderjit Singh <rupinderjit.singh@arm.com
---
drivers/trusty/Makefile | 1 +
drivers/trusty/trusty-private.h | 61 ++++++++++++++
drivers/trusty/trusty-smc.c | 136 ++++++++++++++++++++++++++++++
drivers/trusty/trusty.c | 144 +++++++++-----------------------
4 files changed, 237 insertions(+), 105 deletions(-)
create mode 100644 drivers/trusty/trusty-private.h
create mode 100644 drivers/trusty/trusty-smc.c
diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile
index 2cf1cfccf97b..fbb53ee93003 100644
--- a/drivers/trusty/Makefile
+++ b/drivers/trusty/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_TRUSTY) += trusty-core.o
trusty-core-objs += trusty.o trusty-mem.o
+trusty-core-objs += trusty-smc.o
trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o
trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o
obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o
diff --git a/drivers/trusty/trusty-private.h b/drivers/trusty/trusty-private.h
new file mode 100644
index 000000000000..4d73c6ae35d4
--- /dev/null
+++ b/drivers/trusty/trusty-private.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 ARM Ltd.
+ */
+
+#ifndef _TRUSTY_PRIVATE_H
+#define _TRUSTY_PRIVATE_H
+
+#include <linux/types.h>
+
+struct trusty_work {
+ struct trusty_state *ts;
+ struct work_struct work;
+};
+
+struct trusty_msg_ops {
+ u32 (*send_direct_msg)(struct device *dev, unsigned long fid,
+ unsigned long a0, unsigned long a1,
+ unsigned long a2);
+};
+
+struct trusty_mem_ops {
+ int (*trusty_share_memory)(struct device *dev, u64 *id,
+ struct scatterlist *sglist,
+ unsigned int nents, pgprot_t pgprot, u64 tag);
+ int (*trusty_lend_memory)(struct device *dev, u64 *id,
+ struct scatterlist *sglist,
+ unsigned int nents, pgprot_t pgprot, u64 tag);
+ int (*trusty_reclaim_memory)(struct device *dev, u64 id,
+ struct scatterlist *sglist,
+ unsigned int nents);
+};
+
+struct trusty_state {
+ struct mutex smc_lock;
+ struct atomic_notifier_head notifier;
+ struct completion cpu_idle_completion;
+ char *version_str;
+ u32 api_version;
+ bool trusty_panicked;
+ struct device *dev;
+ struct workqueue_struct *nop_wq;
+ struct trusty_work __percpu *nop_works;
+ struct list_head nop_queue;
+ spinlock_t nop_lock; /* protects nop_queue */
+ struct device_dma_parameters dma_parms;
+ const struct trusty_msg_ops *msg_ops;
+ const struct trusty_mem_ops *mem_ops;
+};
+
+int trusty_init_api_version(struct trusty_state *s, struct device *dev,
+ u32 (*send_direct_msg)(struct device *dev,
+ unsigned long fid,
+ unsigned long a0,
+ unsigned long a1,
+ unsigned long a2));
+
+int trusty_smc_transport_setup(struct device *dev);
+void trusty_smc_transport_cleanup(struct device *dev);
+
+#endif /* _TRUSTY_PRIVATE_H */
diff --git a/drivers/trusty/trusty-smc.c b/drivers/trusty/trusty-smc.c
new file mode 100644
index 000000000000..8fa841e0e253
--- /dev/null
+++ b/drivers/trusty/trusty-smc.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 Google, Inc.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/trusty/smcall.h>
+#include <linux/trusty/trusty.h>
+
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+
+#include "trusty-smc.h"
+#include "trusty-private.h"
+
+static u32 trusty_smc_send_direct_msg(struct device *dev, unsigned long fid,
+ unsigned long a0, unsigned long a1,
+ unsigned long a2)
+{
+ return trusty_smc8(fid, a0, a1, a2, 0, 0, 0, 0).r0;
+}
+
+static int trusty_smc_share_memory(struct device *dev, u64 *id,
+ struct scatterlist *sglist,
+ unsigned int nents, pgprot_t pgprot, u64 tag)
+{
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+ int ret;
+ struct ns_mem_page_info pg_inf;
+ struct scatterlist *sg;
+ size_t count;
+
+ if (WARN_ON(nents < 1))
+ return -EINVAL;
+
+ if (nents != 1) {
+ dev_err(s->dev, "%s: old trusty version does not support "
+ "non-contiguous memory objects\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL);
+ if (count != nents) {
+ dev_err(s->dev, "failed to dma map sg_table\n");
+ return -EINVAL;
+ }
+
+ sg = sglist;
+ ret = trusty_encode_page_info(&pg_inf, phys_to_page(sg_dma_address(sg)),
+ pgprot);
+ if (ret) {
+ dev_err(s->dev, "%s: trusty_encode_page_info failed\n",
+ __func__);
+ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL);
+ return ret;
+ }
+
+ *id = pg_inf.compat_attr;
+ return 0;
+}
+
+static int trusty_smc_lend_memory(struct device *dev, u64 *id,
+ struct scatterlist *sglist,
+ unsigned int nents, pgprot_t pgprot, u64 tag)
+{
+ return -EOPNOTSUPP;
+}
+
+static int trusty_smc_reclaim_memory(struct device *dev, u64 id,
+ struct scatterlist *sglist,
+ unsigned int nents)
+{
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+ if (WARN_ON(nents < 1))
+ return -EINVAL;
+
+ if (WARN_ON(s->api_version >= TRUSTY_API_VERSION_MEM_OBJ))
+ return -EINVAL;
+
+ if (nents != 1) {
+ dev_err(s->dev, "%s: not supported\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL);
+
+ dev_dbg(s->dev, "%s: done\n", __func__);
+ return 0;
+}
+
+static const struct trusty_msg_ops trusty_smc_msg_ops = {
+ .send_direct_msg = &trusty_smc_send_direct_msg,
+};
+
+static const struct trusty_mem_ops trusty_smc_mem_ops = {
+ .trusty_share_memory = &trusty_smc_share_memory,
+ .trusty_lend_memory = &trusty_smc_lend_memory,
+ .trusty_reclaim_memory = &trusty_smc_reclaim_memory,
+};
+
+int trusty_smc_transport_setup(struct device *dev)
+{
+ int rc;
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+ rc = trusty_init_api_version(s, dev, &trusty_smc_send_direct_msg);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /*
+ * Initialize Trusty msg calls with Trusty SMC ABI
+ */
+ s->msg_ops = &trusty_smc_msg_ops;
+
+ /*
+ * Initialize Trusty memory operations with Trusty SMC ABI only when
+ * Trusty API version is below TRUSTY_API_VERSION_MEM_OBJ.
+ */
+ if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ)
+ s->mem_ops = &trusty_smc_mem_ops;
+
+ return 0;
+}
+
+void trusty_smc_transport_cleanup(struct device *dev)
+{
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+ if (s->msg_ops == &trusty_smc_msg_ops)
+ s->msg_ops = NULL;
+
+ if (s->mem_ops == &trusty_smc_mem_ops)
+ s->mem_ops = NULL;
+}
diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c
index 6bd30bc1bbc9..0486827a45ca 100644
--- a/drivers/trusty/trusty.c
+++ b/drivers/trusty/trusty.c
@@ -18,37 +18,10 @@
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include "trusty-smc.h"
+#include "trusty-private.h"
-struct trusty_state;
static struct platform_driver trusty_driver;
-struct trusty_work {
- struct trusty_state *ts;
- struct work_struct work;
-};
-
-struct trusty_state {
- struct mutex smc_lock;
- struct atomic_notifier_head notifier;
- struct completion cpu_idle_completion;
- char *version_str;
- u32 api_version;
- bool trusty_panicked;
- struct device *dev;
- struct workqueue_struct *nop_wq;
- struct trusty_work __percpu *nop_works;
- struct list_head nop_queue;
- spinlock_t nop_lock; /* protects nop_queue */
- struct device_dma_parameters dma_parms;
-};
-
-static inline unsigned long smc(unsigned long r0, unsigned long r1,
- unsigned long r2, unsigned long r3)
-{
- return trusty_smc8(r0, r1, r2, r3, 0, 0, 0, 0).r0;
-}
-
s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
{
struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
@@ -60,7 +33,7 @@ s32 trusty_fast_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
if (WARN_ON(SMC_IS_SMC64(smcnr)))
return SM_ERR_INVALID_PARAMETERS;
- return smc(smcnr, a0, a1, a2);
+ return s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2);
}
EXPORT_SYMBOL(trusty_fast_call32);
@@ -76,7 +49,7 @@ s64 trusty_fast_call64(struct device *dev, u64 smcnr, u64 a0, u64 a1, u64 a2)
if (WARN_ON(!SMC_IS_SMC64(smcnr)))
return SM_ERR_INVALID_PARAMETERS;
- return smc(smcnr, a0, a1, a2);
+ return s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2);
}
EXPORT_SYMBOL(trusty_fast_call64);
#endif
@@ -88,13 +61,16 @@ static unsigned long trusty_std_call_inner(struct device *dev,
{
unsigned long ret;
int retry = 5;
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
dev_dbg(dev, "%s(0x%lx 0x%lx 0x%lx 0x%lx)\n",
__func__, smcnr, a0, a1, a2);
while (true) {
- ret = smc(smcnr, a0, a1, a2);
+ ret = s->msg_ops->send_direct_msg(dev, smcnr, a0, a1, a2);
while ((s32)ret == SM_ERR_FIQ_INTERRUPTED)
- ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0);
+ ret = s->msg_ops->send_direct_msg(dev,
+ SMC_SC_RESTART_FIQ,
+ 0, 0, 0);
if ((int)ret != SM_ERR_BUSY || !retry)
break;
@@ -222,58 +198,17 @@ s32 trusty_std_call32(struct device *dev, u32 smcnr, u32 a0, u32 a1, u32 a2)
}
EXPORT_SYMBOL(trusty_std_call32);
-static int __trusty_share_memory(struct device *dev, u64 *id,
- struct scatterlist *sglist, unsigned int nents,
- pgprot_t pgprot, u64 tag, bool mem_share)
+int trusty_share_memory(struct device *dev, u64 *id,
+ struct scatterlist *sglist, unsigned int nents,
+ pgprot_t pgprot, u64 tag)
{
struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
- int ret;
- struct ns_mem_page_info pg_inf;
- struct scatterlist *sg;
- size_t count;
if (WARN_ON(dev->driver != &trusty_driver.driver))
return -EINVAL;
- if (WARN_ON(nents < 1))
- return -EINVAL;
-
- if (nents != 1 && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) {
- dev_err(s->dev, "%s: old trusty version does not support non-contiguous memory objects\n",
- __func__);
- return -EOPNOTSUPP;
- }
-
- if (mem_share == false && s->api_version < TRUSTY_API_VERSION_MEM_OBJ) {
- dev_err(s->dev, "%s: old trusty version does not support lending memory objects\n",
- __func__);
- return -EOPNOTSUPP;
- }
-
- count = dma_map_sg(dev, sglist, nents, DMA_BIDIRECTIONAL);
- if (count != nents) {
- dev_err(s->dev, "failed to dma map sg_table\n");
- return -EINVAL;
- }
-
- sg = sglist;
- ret = trusty_encode_page_info(&pg_inf, phys_to_page(sg_dma_address(sg)),
- pgprot);
- if (ret) {
- dev_err(s->dev, "%s: trusty_encode_page_info failed\n",
- __func__);
- return ret;
- }
-
- *id = pg_inf.compat_attr;
- return 0;
-}
-
-int trusty_share_memory(struct device *dev, u64 *id,
- struct scatterlist *sglist, unsigned int nents,
- pgprot_t pgprot, u64 tag)
-{
- return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, true);
+ return s->mem_ops->trusty_share_memory(dev, id, sglist, nents, pgprot,
+ tag);
}
EXPORT_SYMBOL(trusty_share_memory);
@@ -281,7 +216,13 @@ int trusty_lend_memory(struct device *dev, u64 *id,
struct scatterlist *sglist, unsigned int nents,
pgprot_t pgprot, u64 tag)
{
- return __trusty_share_memory(dev, id, sglist, nents, pgprot, tag, false);
+ struct trusty_state *s = platform_get_drvdata(to_platform_device(dev));
+
+ if (WARN_ON(dev->driver != &trusty_driver.driver))
+ return -EINVAL;
+
+ return s->mem_ops->trusty_lend_memory(dev, id, sglist, nents, pgprot,
+ tag);
}
EXPORT_SYMBOL(trusty_lend_memory);
@@ -316,22 +257,7 @@ int trusty_reclaim_memory(struct device *dev, u64 id,
if (WARN_ON(dev->driver != &trusty_driver.driver))
return -EINVAL;
- if (WARN_ON(nents < 1))
- return -EINVAL;
-
- if (s->api_version < TRUSTY_API_VERSION_MEM_OBJ) {
- if (nents != 1) {
- dev_err(s->dev, "%s: not supported\n", __func__);
- return -EOPNOTSUPP;
- }
-
- dma_unmap_sg(dev, sglist, nents, DMA_BIDIRECTIONAL);
-
- dev_dbg(s->dev, "%s: done\n", __func__);
- return 0;
- }
-
- return 0;
+ return s->mem_ops->trusty_reclaim_memory(dev, id, sglist, nents);
}
EXPORT_SYMBOL(trusty_reclaim_memory);
@@ -382,7 +308,7 @@ const char *trusty_version_str_get(struct device *dev)
}
EXPORT_SYMBOL(trusty_version_str_get);
-static void trusty_init_version(struct trusty_state *s, struct device *dev)
+static void trusty_init_version_str(struct trusty_state *s, struct device *dev)
{
int ret;
int i;
@@ -430,12 +356,17 @@ bool trusty_get_panic_status(struct device *dev)
}
EXPORT_SYMBOL(trusty_get_panic_status);
-static int trusty_init_api_version(struct trusty_state *s, struct device *dev)
+int trusty_init_api_version(struct trusty_state *s, struct device *dev,
+ u32 (*send_direct_msg)(struct device *dev,
+ unsigned long fid,
+ unsigned long a0,
+ unsigned long a1,
+ unsigned long a2))
{
u32 api_version;
- api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION,
- TRUSTY_API_VERSION_CURRENT, 0, 0);
+ api_version = send_direct_msg(dev, SMC_FC_API_VERSION,
+ TRUSTY_API_VERSION_CURRENT, 0, 0);
if (api_version == SM_ERR_UNDEFINED_SMC)
api_version = 0;
@@ -598,11 +529,12 @@ static int trusty_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, s);
- trusty_init_version(s, &pdev->dev);
+ /* Initialize SMC transport */
+ ret = trusty_smc_transport_setup(s->dev);
+ if (ret != 0 || s->msg_ops == NULL || s->mem_ops == NULL)
+ goto err_transport_setup;
- ret = trusty_init_api_version(s, &pdev->dev);
- if (ret < 0)
- goto err_api_version;
+ trusty_init_version_str(s, &pdev->dev);
s->nop_wq = alloc_workqueue("trusty-nop-wq", WQ_CPU_INTENSIVE, 0);
if (!s->nop_wq) {
@@ -648,9 +580,10 @@ static int trusty_probe(struct platform_device *pdev)
err_alloc_works:
destroy_workqueue(s->nop_wq);
err_create_nop_wq:
-err_api_version:
- s->dev->dma_parms = NULL;
kfree(s->version_str);
+ trusty_smc_transport_cleanup(s->dev);
+err_transport_setup:
+ s->dev->dma_parms = NULL;
device_for_each_child(&pdev->dev, NULL, trusty_remove_child);
mutex_destroy(&s->smc_lock);
kfree(s);
@@ -673,6 +606,7 @@ static int trusty_remove(struct platform_device *pdev)
free_percpu(s->nop_works);
destroy_workqueue(s->nop_wq);
+ trusty_smc_transport_cleanup(s->dev);
mutex_destroy(&s->smc_lock);
s->dev->dma_parms = NULL;
kfree(s->version_str);
--
2.34.1