Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00204223 authored by Mohammed Siddiq's avatar Mohammed Siddiq
Browse files

icnss2: Add API to perform SMMU unmap



During IPA pipe setup, physical address is  mapped
to IOVA using SMMU API. At the time of IPA cleanup SMMU
unmap API is not called.
Add and export ICNSS API to unmap SMMU mapped memory.
This API should be called during IPA cleanup from host
driver.

Change-Id: If7ad8eee69699adb4cbe6dba8025cb41628b4bb3
Signed-off-by: default avatarMohammed Siddiq <msiddiq@codeaurora.org>
parent 5e0ff5c0
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -2530,7 +2530,7 @@ int icnss_smmu_map(struct device *dev,
	}

	len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE);
	iova = roundup(priv->smmu_iova_ipa_start, PAGE_SIZE);
	iova = roundup(priv->smmu_iova_ipa_current, PAGE_SIZE);

	if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) {
		icnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
@@ -2540,6 +2540,8 @@ int icnss_smmu_map(struct device *dev,
		return -ENOMEM;
	}

	icnss_pr_dbg("IOMMU Map: iova %lx, len %zu\n", iova, len);

	ret = iommu_map(priv->iommu_domain, iova,
			rounddown(paddr, PAGE_SIZE), len,
			IOMMU_READ | IOMMU_WRITE);
@@ -2548,13 +2550,59 @@ int icnss_smmu_map(struct device *dev,
		return ret;
	}

	priv->smmu_iova_ipa_start = iova + len;
	priv->smmu_iova_ipa_current = iova + len;
	*iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));

	icnss_pr_dbg("IOVA addr mapped to physical addr %lx\n", *iova_addr);
	return 0;
}
EXPORT_SYMBOL(icnss_smmu_map);

int icnss_smmu_unmap(struct device *dev,
		     uint32_t iova_addr, size_t size)
{
	struct icnss_priv *priv = dev_get_drvdata(dev);
	unsigned long iova;
	size_t len, unmapped_len;

	if (!priv) {
		icnss_pr_err("Invalid drvdata: dev %pK, data %pK\n",
			     dev, priv);
		return -EINVAL;
	}

	if (!iova_addr) {
		icnss_pr_err("iova_addr is NULL, size %zu\n",
			     size);
		return -EINVAL;
	}

	len = roundup(size + iova_addr - rounddown(iova_addr, PAGE_SIZE),
		      PAGE_SIZE);
	iova = rounddown(iova_addr, PAGE_SIZE);

	if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) {
		icnss_pr_err("Out of IOVA space during unmap, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
			     iova,
			     &priv->smmu_iova_ipa_start,
			     priv->smmu_iova_ipa_len);
		return -ENOMEM;
	}

	icnss_pr_dbg("IOMMU Unmap: iova %lx, len %zu\n",
		     iova, len);

	unmapped_len = iommu_unmap(priv->iommu_domain, iova, len);
	if (unmapped_len != len) {
		icnss_pr_err("Failed to unmap, %zu\n", unmapped_len);
		return -EINVAL;
	}

	priv->smmu_iova_ipa_current = iova;
	return 0;
}
EXPORT_SYMBOL(icnss_smmu_unmap);

unsigned int icnss_socinfo_get_serial_number(struct device *dev)
{
	return socinfo_get_serial_number();
@@ -2948,6 +2996,7 @@ static int icnss_smmu_dt_parse(struct icnss_priv *priv)
			icnss_pr_err("SMMU IOVA IPA not found\n");
		} else {
			priv->smmu_iova_ipa_start = res->start;
			priv->smmu_iova_ipa_current = res->start;
			priv->smmu_iova_ipa_len = resource_size(res);
			icnss_pr_dbg("SMMU IOVA IPA start: %pa, len: %zx\n",
				     &priv->smmu_iova_ipa_start,
+1 −0
Original line number Diff line number Diff line
@@ -304,6 +304,7 @@ struct icnss_priv {
	u32 mem_base_size;
	struct iommu_domain *iommu_domain;
	dma_addr_t smmu_iova_ipa_start;
	dma_addr_t smmu_iova_ipa_current;
	size_t smmu_iova_ipa_len;
	struct qmi_handle qmi;
	struct list_head event_list;
+2 −0
Original line number Diff line number Diff line
@@ -155,6 +155,8 @@ extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev);
extern struct iommu_domain *icnss_smmu_get_domain(struct device *dev);
extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr,
			  uint32_t *iova_addr, size_t size);
extern int icnss_smmu_unmap(struct device *dev,
			    uint32_t iova_addr, size_t size);
extern unsigned int icnss_socinfo_get_serial_number(struct device *dev);
extern bool icnss_is_qmi_disable(struct device *dev);
extern bool icnss_is_fw_ready(void);