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

