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

Commit af098495 authored by Jia Ding's avatar Jia Ding
Browse files

cnss2: Add cnss_smmu_unmap API



Add cnss_smmu_unmap API so that wlan function driver
could unmap IOVA addresses that are IOMMU mapped.

Change-Id: I1e3aa287589f73a609cc51fe8c826d1edf2fefd1
Signed-off-by: default avatarJia Ding <jiad@codeaurora.org>
parent 4e2f7cbc
Loading
Loading
Loading
Loading
+49 −4
Original line number Diff line number Diff line
@@ -3443,12 +3443,17 @@ static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
					   "smmu_iova_ipa");
	if (res) {
		pci_priv->smmu_iova_ipa_start = res->start;
		pci_priv->smmu_iova_ipa_current = res->start;
		pci_priv->smmu_iova_ipa_len = resource_size(res);
		cnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: 0x%zx\n",
			    &pci_priv->smmu_iova_ipa_start,
			    pci_priv->smmu_iova_ipa_len);
	}

	pci_priv->iommu_geometry = of_property_read_bool(of_node,
							 "qcom,iommu-geometry");
	cnss_pr_dbg("iommu_geometry: %d\n", pci_priv->iommu_geometry);

	of_node_put(of_node);

	return 0;
@@ -3523,10 +3528,11 @@ int cnss_smmu_map(struct device *dev,
	plat_priv = pci_priv->plat_priv;

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

	if (iova >=
	    (pci_priv->smmu_iova_ipa_start + pci_priv->smmu_iova_ipa_len)) {
	if (pci_priv->iommu_geometry &&
	    iova >= pci_priv->smmu_iova_ipa_start +
		    pci_priv->smmu_iova_ipa_len) {
		cnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
			    iova,
			    &pci_priv->smmu_iova_ipa_start,
@@ -3553,6 +3559,8 @@ int cnss_smmu_map(struct device *dev,
		}
	}

	cnss_pr_dbg("IOMMU map: iova %lx, len %zu\n", iova, len);

	ret = iommu_map(pci_priv->iommu_domain, iova,
			rounddown(paddr, PAGE_SIZE), len, flag);
	if (ret) {
@@ -3560,13 +3568,50 @@ int cnss_smmu_map(struct device *dev,
		return ret;
	}

	pci_priv->smmu_iova_ipa_start = iova + len;
	pci_priv->smmu_iova_ipa_current = iova + len;
	*iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));
	cnss_pr_dbg("IOMMU map: iova_addr %lx\n", *iova_addr);

	return 0;
}
EXPORT_SYMBOL(cnss_smmu_map);

int cnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size)
{
	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
	unsigned long iova;
	size_t unmapped;
	size_t len;

	if (!pci_priv)
		return -ENODEV;

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

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

	cnss_pr_dbg("IOMMU unmap: iova %lx, len %zu\n", iova, len);

	unmapped = iommu_unmap(pci_priv->iommu_domain, iova, len);
	if (unmapped != len) {
		cnss_pr_err("IOMMU unmap failed, unmapped = %zu, requested = %zu\n",
			    unmapped, len);
		return -EINVAL;
	}

	pci_priv->smmu_iova_ipa_current = iova;
	return 0;
}
EXPORT_SYMBOL(cnss_smmu_unmap);

int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
{
	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+2 −0
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct cnss_pci_data {
	dma_addr_t smmu_iova_start;
	size_t smmu_iova_len;
	dma_addr_t smmu_iova_ipa_start;
	dma_addr_t smmu_iova_ipa_current;
	size_t smmu_iova_ipa_len;
	void __iomem *bar;
	struct cnss_msi_config *msi_config;
@@ -102,6 +103,7 @@ struct cnss_pci_data {
	u32 pcie_reg_size;
	struct cnss_misc_reg *wlaon_reg;
	u32 wlaon_reg_size;
	u8 iommu_geometry;
};

static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
+1 −0
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ extern int cnss_get_platform_cap(struct device *dev,
extern struct iommu_domain *cnss_smmu_get_domain(struct device *dev);
extern int cnss_smmu_map(struct device *dev,
			 phys_addr_t paddr, uint32_t *iova_addr, size_t size);
extern int cnss_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size);
extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info);
extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth);
extern int cnss_power_up(struct device *dev);