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

Commit d6cdca1d authored by Naman Padhiar's avatar Naman Padhiar
Browse files

icnss: 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: I2b84c43d892a567fab8b705ca6313706de61fa64
Signed-off-by: default avatarNaman Padhiar <npadhiar@codeaurora.org>
parent dd22fab7
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -2187,7 +2187,7 @@ int icnss_smmu_map(struct device *dev,
	}

	len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE);
	iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE);
	iova = roundup(penv->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",
@@ -2197,6 +2197,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);
@@ -2205,13 +2207,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();
@@ -3384,6 +3432,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,
+2 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 */

#ifndef __ICNSS_PRIVATE_H__
@@ -292,6 +292,7 @@ struct icnss_priv {
	void __iomem *mem_base_va;
	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;
+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 */
#ifndef _ICNSS_WLAN_H_
#define _ICNSS_WLAN_H_
@@ -134,6 +134,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);