All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Andy Gross <agross@kernel.org>,
	Bjorn Andersson <andersson@kernel.org>,
	Konrad Dybcio <konrad.dybcio@linaro.org>,
	Maximilian Luz <luzmaximilian@gmail.com>,
	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	kernel@quicinc.com,
	Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Subject: [PATCH v2 02/11] firmware: qcom: scm: add a dedicated SCM memory allocator
Date: Thu, 28 Sep 2023 11:20:31 +0200	[thread overview]
Message-ID: <20230928092040.9420-3-brgl@bgdev.pl> (raw)
In-Reply-To: <20230928092040.9420-1-brgl@bgdev.pl>

From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

We have several SCM calls that require passing buffers to the trustzone
on top of the SMC core which allocated memory for calls that require
more than 4 arguments.

Currently every user does their own thing which leads to code
duplication. Many users call dma_alloc_coherent() for every call which
is terribly unperformant (speed- and size-wise).

As all but one calls allocate memory just for the duration of the call,
we don't need a lot of memory. A single pool for that purpose is enough.
Let's create a genalloc pool dealing out chunks of coherent, page-aligned
memory suitable for SCM calls that also provides a function for mapping
virtual to physical addresses.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
---
 drivers/firmware/qcom/Makefile         |   2 +-
 drivers/firmware/qcom/qcom_scm-mem.c   | 134 +++++++++++++++++++++++++
 drivers/firmware/qcom/qcom_scm.c       |   5 +
 drivers/firmware/qcom/qcom_scm.h       |   7 ++
 include/linux/firmware/qcom/qcom_scm.h |   7 ++
 5 files changed, 154 insertions(+), 1 deletion(-)
 create mode 100644 drivers/firmware/qcom/qcom_scm-mem.c

diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index c9f12ee8224a..b9b117f22e9f 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -4,6 +4,6 @@
 #
 
 obj-$(CONFIG_QCOM_SCM)		+= qcom-scm.o
-qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
+qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o qcom_scm-mem.o
 obj-$(CONFIG_QCOM_QSEECOM)	+= qcom_qseecom.o
 obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
diff --git a/drivers/firmware/qcom/qcom_scm-mem.c b/drivers/firmware/qcom/qcom_scm-mem.c
new file mode 100644
index 000000000000..eafecbe23770
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_scm-mem.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Linaro Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/genalloc.h>
+#include <linux/gfp.h>
+#include <linux/moduleparam.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "qcom_scm.h"
+
+static size_t qcom_scm_mem_pool_size = SZ_2M;
+module_param_named(qcom_scm_mem_pool_size, qcom_scm_mem_pool_size,
+		   ulong, 0400);
+
+struct {
+	struct device *dev;
+	void *vbase;
+	phys_addr_t pbase;
+	size_t size;
+	struct gen_pool *pool;
+	struct radix_tree_root chunks;
+	spinlock_t lock;
+} qcom_scm_mem;
+
+struct qcom_scm_mem_chunk {
+	phys_addr_t paddr;
+	size_t size;
+};
+
+void *qcom_scm_mem_alloc(size_t size, gfp_t gfp)
+{
+	struct qcom_scm_mem_chunk *chunk;
+	unsigned long vaddr;
+	int ret;
+
+	if (!size)
+		return ZERO_SIZE_PTR;
+
+	size = roundup(size, 1 << PAGE_SHIFT);
+
+	chunk = kzalloc(sizeof(*chunk), gfp);
+	if (!chunk)
+		return NULL;
+
+	vaddr = gen_pool_alloc(qcom_scm_mem.pool, size);
+	if (!vaddr) {
+		kfree(chunk);
+		return NULL;
+	}
+
+	chunk->paddr = gen_pool_virt_to_phys(qcom_scm_mem.pool,
+					     (unsigned long)vaddr);
+	chunk->size = size;
+
+	scoped_guard(spinlock_irqsave, &qcom_scm_mem.lock) {
+		ret = radix_tree_insert(&qcom_scm_mem.chunks, vaddr, chunk);
+		if (ret) {
+			gen_pool_free(qcom_scm_mem.pool, (unsigned long)vaddr,
+				      chunk->size);
+			kfree(chunk);
+			return NULL;
+		}
+	}
+
+	return (void *)vaddr;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_mem_alloc);
+
+void qcom_scm_mem_free(void *vaddr)
+{
+	struct qcom_scm_mem_chunk *chunk;
+
+	if (!vaddr)
+		return;
+
+	scoped_guard(spinlock_irqsave, &qcom_scm_mem.lock)
+		chunk = radix_tree_delete_item(&qcom_scm_mem.chunks,
+					       (unsigned long)vaddr, NULL);
+
+	if (!chunk) {
+		WARN(1, "Virtual address %p not allocated for SCM", vaddr);
+		return;
+	}
+
+	gen_pool_free(qcom_scm_mem.pool, (unsigned long)vaddr, chunk->size);
+	kfree(chunk);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_mem_free);
+
+phys_addr_t qcom_scm_mem_to_phys(void *vaddr)
+{
+	struct qcom_scm_mem_chunk *chunk;
+
+	guard(spinlock_irqsave)(&qcom_scm_mem.lock);
+
+	chunk = radix_tree_lookup(&qcom_scm_mem.chunks, (unsigned long)vaddr);
+	if (!chunk)
+		return 0;
+
+	return chunk->paddr;
+}
+
+int qcom_scm_mem_enable(struct device *dev)
+{
+	INIT_RADIX_TREE(&qcom_scm_mem.chunks, GFP_ATOMIC);
+	spin_lock_init(&qcom_scm_mem.lock);
+	qcom_scm_mem.dev = dev;
+	qcom_scm_mem.size = qcom_scm_mem_pool_size;
+
+	qcom_scm_mem.vbase = dmam_alloc_coherent(dev, qcom_scm_mem.size,
+						 &qcom_scm_mem.pbase,
+						 GFP_KERNEL);
+	if (!qcom_scm_mem.vbase)
+		return -ENOMEM;
+
+	qcom_scm_mem.pool = devm_gen_pool_create(dev, PAGE_SHIFT, -1,
+						 "qcom-scm-mem");
+	if (!qcom_scm_mem.pool)
+		return -ENOMEM;
+
+	gen_pool_set_algo(qcom_scm_mem.pool, gen_pool_best_fit, NULL);
+
+	return gen_pool_add_virt(qcom_scm_mem.pool,
+				 (unsigned long)qcom_scm_mem.vbase,
+				 qcom_scm_mem.pbase, qcom_scm_mem.size, -1);
+}
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index c2c7fafef34b..258aa0782754 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -1880,6 +1880,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
 	if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled"))
 		qcom_scm_disable_sdi();
 
+	ret = qcom_scm_mem_enable(scm->dev);
+	if (ret)
+		return dev_err_probe(scm->dev, ret,
+				     "Failed to enable SCM memory\n");
+
 	/*
 	 * Initialize the QSEECOM interface.
 	 *
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index 7b68fa820495..8c97e3906afa 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -4,6 +4,10 @@
 #ifndef __QCOM_SCM_INT_H
 #define __QCOM_SCM_INT_H
 
+#include <linux/types.h>
+
+struct device;
+
 enum qcom_scm_convention {
 	SMC_CONVENTION_UNKNOWN,
 	SMC_CONVENTION_LEGACY,
@@ -165,4 +169,7 @@ static inline int qcom_scm_remap_error(int err)
 	return -EINVAL;
 }
 
+int qcom_scm_mem_enable(struct device *dev);
+phys_addr_t qcom_scm_mem_to_phys(void *vaddr);
+
 #endif
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index ccaf28846054..291ef8fd21b0 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -5,7 +5,9 @@
 #ifndef __QCOM_SCM_H
 #define __QCOM_SCM_H
 
+#include <linux/cleanup.h>
 #include <linux/err.h>
+#include <linux/gfp.h>
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
@@ -61,6 +63,11 @@ enum qcom_scm_ice_cipher {
 
 bool qcom_scm_is_available(void);
 
+void *qcom_scm_mem_alloc(size_t size, gfp_t gfp);
+void qcom_scm_mem_free(void *vaddr);
+
+DEFINE_FREE(qcom_scm_mem, void *, if (_T) qcom_scm_mem_free(_T));
+
 int qcom_scm_set_cold_boot_addr(void *entry);
 int qcom_scm_set_warm_boot_addr(void *entry);
 void qcom_scm_cpu_power_down(u32 flags);
-- 
2.39.2


  parent reply	other threads:[~2023-09-28  9:21 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-28  9:20 [PATCH v2 00/11] arm64: qcom: add and enable SHM Bridge support Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 01/11] firmware: qcom: move Qualcomm code into its own directory Bartosz Golaszewski
2023-09-28 17:08   ` Elliot Berman
2023-10-03  7:57   ` Krzysztof Kozlowski
2023-09-28  9:20 ` Bartosz Golaszewski [this message]
2023-09-28 18:19   ` [PATCH v2 02/11] firmware: qcom: scm: add a dedicated SCM memory allocator Jeff Johnson
2023-09-28 18:23     ` Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 03/11] firmware: qcom: scm: switch to using the SCM allocator Bartosz Golaszewski
2023-09-28 19:11   ` Elliot Berman
2023-09-29  8:15   ` Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 04/11] firmware: qcom: scm: make qcom_scm_assign_mem() use " Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 05/11] firmware: qcom: scm: make qcom_scm_ice_set_key() " Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 06/11] firmware: qcom: scm: make qcom_scm_pas_init_image() " Bartosz Golaszewski
2023-09-29 19:16   ` Andrew Halaney
2023-09-29 19:22     ` Bartosz Golaszewski
2023-09-29 20:44       ` Andrew Halaney
2023-09-29 22:48         ` Elliot Berman
2023-10-02 13:24           ` Andrew Halaney
2023-10-02 14:15             ` Andrew Halaney
2023-10-02 14:23               ` Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 07/11] firmware: qcom: scm: make qcom_scm_lmh_dcvsh() " Bartosz Golaszewski
2023-09-28  9:20 ` [RFT PATCH v2 08/11] firmware: qcom: scm: make qcom_scm_qseecom_app_get_id() " Bartosz Golaszewski
2023-09-28  9:20 ` [RFT PATCH v2 09/11] firmware: qcom: qseecom: convert to using " Bartosz Golaszewski
2023-09-28  9:20 ` [PATCH v2 10/11] firmware: qcom-scm: add support for SHM bridge operations Bartosz Golaszewski
2023-09-28 17:09   ` Elliot Berman
2023-09-28  9:20 ` [PATCH v2 11/11] firmware: qcom: scm: enable SHM bridge Bartosz Golaszewski
2023-09-28 17:10   ` Elliot Berman
2023-09-28 18:28     ` Bartosz Golaszewski
2023-09-28 19:00   ` Jeff Johnson
2023-09-29 19:00   ` Bartosz Golaszewski
2023-10-04 22:24   ` Maximilian Luz
2023-10-05  7:12     ` Bartosz Golaszewski
2023-10-05  9:12       ` Maximilian Luz
2023-09-29 15:29 ` [PATCH v2 00/11] arm64: qcom: add and enable SHM Bridge support Andrew Halaney
2023-09-29 18:56   ` Bartosz Golaszewski
2023-09-29 19:18     ` Andrew Halaney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230928092040.9420-3-brgl@bgdev.pl \
    --to=brgl@bgdev.pl \
    --cc=agross@kernel.org \
    --cc=andersson@kernel.org \
    --cc=bartosz.golaszewski@linaro.org \
    --cc=kernel@quicinc.com \
    --cc=konrad.dybcio@linaro.org \
    --cc=krzysztof.kozlowski@linaro.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luzmaximilian@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.