msm: iommu: Selectively invalidate TLB entries

When mapping or unmapping within a domain, only invalidate
the TLB entries associated with the VA of the mapping being
modified (and the ASID associated with the related context)
rather than invalidating the entire TLB.

Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index e6420f0..753cc33 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -105,6 +105,38 @@
 	return ret;
 }
 
+static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
+{
+	struct msm_priv *priv = domain->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	int ret = 0;
+	int asid;
+
+	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
+		if (!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent)
+			BUG();
+
+		iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+		if (!iommu_drvdata)
+			BUG();
+
+		ret = __enable_clocks(iommu_drvdata);
+		if (ret)
+			goto fail;
+
+		asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
+					   ctx_drvdata->num);
+
+		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
+			   asid | (va & TLBIVA_VA));
+		mb();
+		__disable_clocks(iommu_drvdata);
+	}
+fail:
+	return ret;
+}
+
 static void __reset_context(void __iomem *base, int ctx)
 {
 	SET_BPRCOSH(base, ctx, 0);
@@ -522,7 +554,7 @@
 		clean_pte(sl_pte, sl_pte + 16);
 	}
 
-	ret = __flush_iotlb(domain);
+	ret = __flush_iotlb_va(domain, va);
 fail:
 	spin_unlock_irqrestore(&msm_iommu_lock, flags);
 	return ret;
@@ -620,7 +652,7 @@
 		}
 	}
 
-	ret = __flush_iotlb(domain);
+	ret = __flush_iotlb_va(domain, va);
 fail:
 	spin_unlock_irqrestore(&msm_iommu_lock, flags);
 	return ret;
@@ -655,9 +687,6 @@
 	if (ret)
 		goto fail;
 
-	/* Invalidate context TLB */
-	SET_CTX_TLBIALL(base, ctx, 0);
-	mb();
 	SET_V2PPR(base, ctx, va & V2Pxx_VA);
 
 	mb();