iommu/arm-smmu: Implement hardware iova-to-phys
The hardware address translation operations (ATOS) can be useful for
debugging; however hardware may have limitations which prevent useage
of this functionality under all scenarios.
In the particular case of qcom,smmu-v2, halting the client is required
during atos. Additionally, nonatomic clock/regulator operations must
be performed.
Change-Id: I1a021026b9ee41ba2c1761bd5d5b7a13399c6417
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1ec2853..ff2d51f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1308,7 +1308,7 @@
return ret;
}
-static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
+static phys_addr_t __arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
dma_addr_t iova)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -1376,7 +1376,7 @@
spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
- ret = arm_smmu_iova_to_phys_hard(domain, iova);
+ ret = __arm_smmu_iova_to_phys_hard(domain, iova);
} else {
ret = ops->iova_to_phys(ops, iova);
}
@@ -1386,6 +1386,28 @@
return ret;
}
+/*
+ * This function can sleep, and cannot be called from atomic context. Will
+ * power on register block if required. This restriction does not apply to the
+ * original iova_to_phys() op.
+ */
+static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ phys_addr_t ret = 0;
+ unsigned long flags;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+ spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS &&
+ smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
+ ret = __arm_smmu_iova_to_phys_hard(domain, iova);
+
+ spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
+
+ return ret;
+}
+
static bool arm_smmu_capable(enum iommu_cap cap)
{
switch (cap) {
@@ -1565,6 +1587,7 @@
.unmap = arm_smmu_unmap,
.map_sg = default_iommu_map_sg,
.iova_to_phys = arm_smmu_iova_to_phys,
+ .iova_to_phys_hard = arm_smmu_iova_to_phys_hard,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
.device_group = arm_smmu_device_group,