aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitchel Humpherys <mitchelh@codeaurora.org>2014-10-29 17:13:40 -0400
committerWill Deacon <will.deacon@arm.com>2015-01-19 13:18:38 -0500
commit859a732e4f713270152c78df6e09accbde006734 (patch)
treec884b95807acf8df3b4927ae6ceec92bdc0e1d72
parent54c523127bcca986c6f9b04c7b56a949ea011899 (diff)
iommu/arm-smmu: add support for iova_to_phys through ATS1PR
Currently, we provide the iommu_ops.iova_to_phys service by doing a table walk in software to translate IO virtual addresses to physical addresses. On SMMUs that support it, it can be useful to ask the SMMU itself to do the translation. This can be used to warm the TLBs for an SMMU. It can also be useful for testing and hardware validation. Since the address translation registers are optional on SMMUv2, only enable hardware translations when using SMMUv1 or when SMMU_IDR0.S1TS=1 and SMMU_IDR0.ATOSNS=0, as described in the ARM SMMU v1-v2 spec. Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org> [will: reworked on top of generic iopgtbl changes] Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--drivers/iommu/arm-smmu.c69
1 files changed, 67 insertions, 2 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 006f006c35e9..1d6d43bb3395 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -34,6 +34,7 @@
34#include <linux/interrupt.h> 34#include <linux/interrupt.h>
35#include <linux/io.h> 35#include <linux/io.h>
36#include <linux/iommu.h> 36#include <linux/iommu.h>
37#include <linux/iopoll.h>
37#include <linux/module.h> 38#include <linux/module.h>
38#include <linux/of.h> 39#include <linux/of.h>
39#include <linux/pci.h> 40#include <linux/pci.h>
@@ -100,6 +101,7 @@
100#define ID0_S2TS (1 << 29) 101#define ID0_S2TS (1 << 29)
101#define ID0_NTS (1 << 28) 102#define ID0_NTS (1 << 28)
102#define ID0_SMS (1 << 27) 103#define ID0_SMS (1 << 27)
104#define ID0_ATOSNS (1 << 26)
103#define ID0_CTTW (1 << 14) 105#define ID0_CTTW (1 << 14)
104#define ID0_NUMIRPT_SHIFT 16 106#define ID0_NUMIRPT_SHIFT 16
105#define ID0_NUMIRPT_MASK 0xff 107#define ID0_NUMIRPT_MASK 0xff
@@ -189,6 +191,8 @@
189#define ARM_SMMU_CB_TTBCR 0x30 191#define ARM_SMMU_CB_TTBCR 0x30
190#define ARM_SMMU_CB_S1_MAIR0 0x38 192#define ARM_SMMU_CB_S1_MAIR0 0x38
191#define ARM_SMMU_CB_S1_MAIR1 0x3c 193#define ARM_SMMU_CB_S1_MAIR1 0x3c
194#define ARM_SMMU_CB_PAR_LO 0x50
195#define ARM_SMMU_CB_PAR_HI 0x54
192#define ARM_SMMU_CB_FSR 0x58 196#define ARM_SMMU_CB_FSR 0x58
193#define ARM_SMMU_CB_FAR_LO 0x60 197#define ARM_SMMU_CB_FAR_LO 0x60
194#define ARM_SMMU_CB_FAR_HI 0x64 198#define ARM_SMMU_CB_FAR_HI 0x64
@@ -198,6 +202,9 @@
198#define ARM_SMMU_CB_S1_TLBIVAL 0x620 202#define ARM_SMMU_CB_S1_TLBIVAL 0x620
199#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 203#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
200#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 204#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
205#define ARM_SMMU_CB_ATS1PR_LO 0x800
206#define ARM_SMMU_CB_ATS1PR_HI 0x804
207#define ARM_SMMU_CB_ATSR 0x8f0
201 208
202#define SCTLR_S1_ASIDPNE (1 << 12) 209#define SCTLR_S1_ASIDPNE (1 << 12)
203#define SCTLR_CFCFG (1 << 7) 210#define SCTLR_CFCFG (1 << 7)
@@ -209,6 +216,10 @@
209#define SCTLR_M (1 << 0) 216#define SCTLR_M (1 << 0)
210#define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE) 217#define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE)
211 218
219#define CB_PAR_F (1 << 0)
220
221#define ATSR_ACTIVE (1 << 0)
222
212#define RESUME_RETRY (0 << 0) 223#define RESUME_RETRY (0 << 0)
213#define RESUME_TERMINATE (1 << 0) 224#define RESUME_TERMINATE (1 << 0)
214 225
@@ -282,6 +293,7 @@ struct arm_smmu_device {
282#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2) 293#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2)
283#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3) 294#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
284#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4) 295#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
296#define ARM_SMMU_FEAT_TRANS_OPS (1 << 5)
285 u32 features; 297 u32 features;
286 298
287#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) 299#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
@@ -1220,8 +1232,52 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
1220 return ret; 1232 return ret;
1221} 1233}
1222 1234
1235static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
1236 dma_addr_t iova)
1237{
1238 struct arm_smmu_domain *smmu_domain = domain->priv;
1239 struct arm_smmu_device *smmu = smmu_domain->smmu;
1240 struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
1241 struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
1242 struct device *dev = smmu->dev;
1243 void __iomem *cb_base;
1244 u32 tmp;
1245 u64 phys;
1246
1247 cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
1248
1249 if (smmu->version == 1) {
1250 u32 reg = iova & ~0xfff;
1251 writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO);
1252 } else {
1253 u32 reg = iova & ~0xfff;
1254 writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO);
1255 reg = (iova & ~0xfff) >> 32;
1256 writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_HI);
1257 }
1258
1259 if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
1260 !(tmp & ATSR_ACTIVE), 5, 50)) {
1261 dev_err(dev,
1262 "iova to phys timed out on 0x%pad. Falling back to software table walk.\n",
1263 &iova);
1264 return ops->iova_to_phys(ops, iova);
1265 }
1266
1267 phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO);
1268 phys |= ((u64)readl_relaxed(cb_base + ARM_SMMU_CB_PAR_HI)) << 32;
1269
1270 if (phys & CB_PAR_F) {
1271 dev_err(dev, "translation fault!\n");
1272 dev_err(dev, "PAR = 0x%llx\n", phys);
1273 return 0;
1274 }
1275
1276 return (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
1277}
1278
1223static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, 1279static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
1224 dma_addr_t iova) 1280 dma_addr_t iova)
1225{ 1281{
1226 phys_addr_t ret; 1282 phys_addr_t ret;
1227 unsigned long flags; 1283 unsigned long flags;
@@ -1232,8 +1288,12 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
1232 return 0; 1288 return 0;
1233 1289
1234 spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); 1290 spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
1235 ret = ops->iova_to_phys(ops, iova); 1291 if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS)
1292 ret = arm_smmu_iova_to_phys_hard(domain, iova);
1293 else
1294 ret = ops->iova_to_phys(ops, iova);
1236 spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); 1295 spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
1296
1237 return ret; 1297 return ret;
1238} 1298}
1239 1299
@@ -1496,6 +1556,11 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
1496 return -ENODEV; 1556 return -ENODEV;
1497 } 1557 }
1498 1558
1559 if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) {
1560 smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
1561 dev_notice(smmu->dev, "\taddress translation ops\n");
1562 }
1563
1499 if (id & ID0_CTTW) { 1564 if (id & ID0_CTTW) {
1500 smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; 1565 smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
1501 dev_notice(smmu->dev, "\tcoherent table walk\n"); 1566 dev_notice(smmu->dev, "\tcoherent table walk\n");