diff mbox series

[RFC,1/1] arm-smmu: Add iommu support to share pgtable

Message ID 20231101071144.16309-2-quic_gkohli@quicinc.com (mailing list archive)
State New, archived
Headers show
Series Add custom alloc and free pgtable callback | expand

Commit Message

Gaurav Kohli Nov. 1, 2023, 7:11 a.m. UTC
HLOS can create s1 pagetable and request firmware to share the same
pgtable to different entity(vmid).

Use arm-smmu vendor implementation call to define custom
alloc/free pgtable callback, And use these callbacks to share
pgtable to different entity while creating pgtable.

Signed-off-by: Gaurav Kohli <quic_gkohli@quicinc.com>
---
 drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 81 ++++++++++++++++++++++
 drivers/iommu/arm/arm-smmu/arm-smmu.h      |  8 +++
 2 files changed, 89 insertions(+)
diff mbox series

Patch

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index c71afda79d64..e04079988787 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -4,6 +4,7 @@ 
  */
 
 #include <linux/acpi.h>
+#include <linux/dev_printk.h>
 #include <linux/adreno-smmu-priv.h>
 #include <linux/delay.h>
 #include <linux/of_device.h>
@@ -258,11 +259,91 @@  static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
 	{ }
 };
 
+static void *qcom_alloc_pages(void *cookie, size_t size, gfp_t gfp)
+{
+	struct page *p;
+	struct qcom_scm_vmperm perms[2];
+	u64 src  = BIT(QCOM_SCM_VMID_HLOS);
+	int ret;
+
+	struct arm_smmu_domain *domain = (void *)cookie;
+	/*
+	 * qcom_scm_assign_mem call during atomic allocation can sleep, Using GFP flags
+	 * to detect allocation path and return failure for atomic allocations.
+	 */
+	if (!gfpflags_allow_blocking(gfp)) {
+		dev_err(domain->smmu->dev,
+			"qcom_scm_assign_mem call are not allowed during atomic allocations\n");
+		return NULL;
+	}
+	p = alloc_page(gfp);
+	if (!p)
+		return NULL;
+
+	perms[0].vmid = QCOM_SCM_VMID_HLOS;
+	perms[0].perm = QCOM_SCM_PERM_RW;
+	perms[1].vmid = domain->secure_vmid;
+	perms[1].perm = QCOM_SCM_PERM_READ;
+	ret = qcom_scm_assign_mem(page_to_phys(p), PAGE_SIZE,
+				  &src, perms, 2);
+	if (ret < 0) {
+		dev_err(domain->smmu->dev,
+			"assign memory failed for vmid=%x ret=%d\n",
+			domain->secure_vmid, ret);
+		__free_page(p);
+		return NULL;
+	}
+
+	return page_address(p);
+}
+
+static void qcom_free_pages(void *cookie, void *pages, size_t size)
+{
+	struct qcom_scm_vmperm perms;
+	struct page *p;
+	u64 src;
+	int ret;
+
+	struct arm_smmu_domain *domain = (void *)cookie;
+
+	p = virt_to_page(pages);
+
+	perms.vmid = QCOM_SCM_VMID_HLOS;
+	perms.perm = QCOM_SCM_PERM_RWX;
+	src = BIT(domain->secure_vmid) | BIT(QCOM_SCM_VMID_HLOS);
+	ret = qcom_scm_assign_mem(page_to_phys(p), PAGE_SIZE,
+				  &src, &perms, 1);
+	/*
+	 * For assign failure scenario, it is not safe to use these pages by HLOS.
+	 * So returning from here instead of freeing the page.
+	 */
+	if (ret < 0) {
+		dev_err(domain->smmu->dev,
+			"assign memory failed to HLOS for vmid=%x ret=%d\n",
+			domain->secure_vmid, ret);
+		return;
+	}
+
+	__free_page(p);
+}
+
 static int qcom_smmu_init_context(struct arm_smmu_domain *smmu_domain,
 		struct io_pgtable_cfg *pgtbl_cfg, struct device *dev)
 {
+	u32 val;
+
 	smmu_domain->cfg.flush_walk_prefer_tlbiasid = true;
 
+	/*
+	 * For those client where qcom,iommu-vmid is not defined, default arm-smmu pgtable
+	 * alloc/free handler will be used.
+	 */
+	if (of_property_read_u32(dev->of_node, "qcom,iommu-vmid", &val) == 0) {
+		smmu_domain->secure_vmid = val;
+		pgtbl_cfg->alloc = qcom_alloc_pages;
+		pgtbl_cfg->free = qcom_free_pages;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 703fd5817ec1..98e1c5369e58 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -374,6 +374,14 @@  struct arm_smmu_domain {
 	struct mutex			init_mutex; /* Protects smmu pointer */
 	spinlock_t			cb_lock; /* Serialises ATS1* ops and TLB syncs */
 	struct iommu_domain		domain;
+	/*
+	 * Use to store parse vmid value for those clients which want HLOS
+	 * to share pgtable to different entity(VMID).
+	 * Fix Me: Ideally this should be implemented on arm-smmu vendor implementation
+	 * driver, but as per current design of arm_smmu_domain_alloc there is no way
+	 * to call implementation callbacks.
+	 */
+	u32				secure_vmid;
 };
 
 struct arm_smmu_master_cfg {