aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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");