diff options
| -rw-r--r-- | drivers/iommu/arm-smmu.c | 69 |
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 | ||
| 1235 | static 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 | |||
| 1223 | static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, | 1279 | static 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"); |
