diff options
Diffstat (limited to 'drivers/iommu/arm/arm-smmu/arm-smmu.c')
-rw-r--r-- | drivers/iommu/arm/arm-smmu/arm-smmu.c | 76 |
1 files changed, 45 insertions, 31 deletions
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index dad7fa86fbd4..d8c6bfde6a61 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -333,14 +333,6 @@ static void arm_smmu_tlb_inv_walk_s1(unsigned long iova, size_t size, arm_smmu_tlb_sync_context(cookie); } -static void arm_smmu_tlb_inv_leaf_s1(unsigned long iova, size_t size, - size_t granule, void *cookie) -{ - arm_smmu_tlb_inv_range_s1(iova, size, granule, cookie, - ARM_SMMU_CB_S1_TLBIVAL); - arm_smmu_tlb_sync_context(cookie); -} - static void arm_smmu_tlb_add_page_s1(struct iommu_iotlb_gather *gather, unsigned long iova, size_t granule, void *cookie) @@ -357,14 +349,6 @@ static void arm_smmu_tlb_inv_walk_s2(unsigned long iova, size_t size, arm_smmu_tlb_sync_context(cookie); } -static void arm_smmu_tlb_inv_leaf_s2(unsigned long iova, size_t size, - size_t granule, void *cookie) -{ - arm_smmu_tlb_inv_range_s2(iova, size, granule, cookie, - ARM_SMMU_CB_S2_TLBIIPAS2L); - arm_smmu_tlb_sync_context(cookie); -} - static void arm_smmu_tlb_add_page_s2(struct iommu_iotlb_gather *gather, unsigned long iova, size_t granule, void *cookie) @@ -373,8 +357,8 @@ static void arm_smmu_tlb_add_page_s2(struct iommu_iotlb_gather *gather, ARM_SMMU_CB_S2_TLBIIPAS2L); } -static void arm_smmu_tlb_inv_any_s2_v1(unsigned long iova, size_t size, - size_t granule, void *cookie) +static void arm_smmu_tlb_inv_walk_s2_v1(unsigned long iova, size_t size, + size_t granule, void *cookie) { arm_smmu_tlb_inv_context_s2(cookie); } @@ -401,21 +385,18 @@ static void arm_smmu_tlb_add_page_s2_v1(struct iommu_iotlb_gather *gather, static const struct iommu_flush_ops arm_smmu_s1_tlb_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context_s1, .tlb_flush_walk = arm_smmu_tlb_inv_walk_s1, - .tlb_flush_leaf = arm_smmu_tlb_inv_leaf_s1, .tlb_add_page = arm_smmu_tlb_add_page_s1, }; static const struct iommu_flush_ops arm_smmu_s2_tlb_ops_v2 = { .tlb_flush_all = arm_smmu_tlb_inv_context_s2, .tlb_flush_walk = arm_smmu_tlb_inv_walk_s2, - .tlb_flush_leaf = arm_smmu_tlb_inv_leaf_s2, .tlb_add_page = arm_smmu_tlb_add_page_s2, }; static const struct iommu_flush_ops arm_smmu_s2_tlb_ops_v1 = { .tlb_flush_all = arm_smmu_tlb_inv_context_s2, - .tlb_flush_walk = arm_smmu_tlb_inv_any_s2_v1, - .tlb_flush_leaf = arm_smmu_tlb_inv_any_s2_v1, + .tlb_flush_walk = arm_smmu_tlb_inv_walk_s2_v1, .tlb_add_page = arm_smmu_tlb_add_page_s2_v1, }; @@ -617,7 +598,10 @@ void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) reg |= ARM_SMMU_SCTLR_E; - arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg); + if (smmu->impl && smmu->impl->write_sctlr) + smmu->impl->write_sctlr(smmu, idx, reg); + else + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, reg); } static int arm_smmu_alloc_context_bank(struct arm_smmu_domain *smmu_domain, @@ -783,8 +767,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, goto out_clear_smmu; } - if (smmu_domain->non_strict) - pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; + if (smmu_domain->pgtbl_cfg.quirks) + pgtbl_cfg.quirks |= smmu_domain->pgtbl_cfg.quirks; pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); if (!pgtbl_ops) { @@ -929,9 +913,16 @@ static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) { struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx; - u32 reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, s2cr->type) | - FIELD_PREP(ARM_SMMU_S2CR_CBNDX, s2cr->cbndx) | - FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, s2cr->privcfg); + u32 reg; + + if (smmu->impl && smmu->impl->write_s2cr) { + smmu->impl->write_s2cr(smmu, idx); + return; + } + + reg = FIELD_PREP(ARM_SMMU_S2CR_TYPE, s2cr->type) | + FIELD_PREP(ARM_SMMU_S2CR_CBNDX, s2cr->cbndx) | + FIELD_PREP(ARM_SMMU_S2CR_PRIVCFG, s2cr->privcfg); if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs && smmu->smrs[idx].valid) @@ -1501,15 +1492,24 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); return 0; + case DOMAIN_ATTR_IO_PGTABLE_CFG: { + struct io_pgtable_domain_attr *pgtbl_cfg = data; + *pgtbl_cfg = smmu_domain->pgtbl_cfg; + + return 0; + } default: return -ENODEV; } break; case IOMMU_DOMAIN_DMA: switch (attr) { - case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: - *(int *)data = smmu_domain->non_strict; + case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: { + bool non_strict = smmu_domain->pgtbl_cfg.quirks & + IO_PGTABLE_QUIRK_NON_STRICT; + *(int *)data = non_strict; return 0; + } default: return -ENODEV; } @@ -1541,6 +1541,17 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, else smmu_domain->stage = ARM_SMMU_DOMAIN_S1; break; + case DOMAIN_ATTR_IO_PGTABLE_CFG: { + struct io_pgtable_domain_attr *pgtbl_cfg = data; + + if (smmu_domain->smmu) { + ret = -EPERM; + goto out_unlock; + } + + smmu_domain->pgtbl_cfg = *pgtbl_cfg; + break; + } default: ret = -ENODEV; } @@ -1548,7 +1559,10 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, case IOMMU_DOMAIN_DMA: switch (attr) { case DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE: - smmu_domain->non_strict = *(int *)data; + if (*(int *)data) + smmu_domain->pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT; + else + smmu_domain->pgtbl_cfg.quirks &= ~IO_PGTABLE_QUIRK_NON_STRICT; break; default: ret = -ENODEV; |