From b4b2a0f9739edf0cadf1037fb29606e8abe85ec0 Mon Sep 17 00:00:00 2001 From: Ashish Mhetre Date: Sat, 14 Sep 2024 16:26:08 +0000 Subject: [PATCH] Revert "NVIDIA: SAUCE: iommu: arm-smmu: io-pgtable: Add dma_sync API" BugLink: https://bugs.launchpad.net/bugs/2080908 dma_sync need to be issued immediately after PTE is cleared and before TLB INV. Otherwise, once TLB INV is issued the SMMU can do page table walks which will lead to invalid PTEs as sync hasn't been done. This reverts commit 6a05695a1b2fe318bc87ae46109d50f8e21f2904. http://nvbugs/4029665 Signed-off-by: Ashish Mhetre Signed-off-by: Laxman Dewangan Acked-by: Noah Wager Acked-by: Jacob Martin Signed-off-by: Noah Wager --- drivers/iommu/arm/arm-smmu/arm-smmu.c | 19 ------ drivers/iommu/io-pgtable-arm.c | 96 --------------------------- drivers/iommu/iommu.c | 6 -- include/linux/io-pgtable.h | 2 - include/linux/iommu.h | 3 +- 5 files changed, 1 insertion(+), 125 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 0a34cf4b4574..c2a96622749a 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -764,8 +764,6 @@ static int arm_smmu_init_domain_context(struct arm_smmu_domain *smmu_domain, .iommu_dev = smmu->dev, }; - pgtbl_cfg.coherent_walk = true; - if (smmu->impl && smmu->impl->init_context) { ret = smmu->impl->init_context(smmu_domain, &pgtbl_cfg, dev); if (ret) @@ -1247,22 +1245,6 @@ static size_t arm_smmu_unmap_pages(struct iommu_domain *domain, unsigned long io return ret; } -static int arm_smmu_dma_sync(struct iommu_domain *domain, unsigned long iova, - size_t size) -{ - struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; - size_t ret; - - if (!ops) - return 0; - - ret = ops->dma_sync(ops, iova, size); - - return ret; - -} - static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); @@ -1640,7 +1622,6 @@ static struct iommu_ops arm_smmu_ops = { .unmap_pages = arm_smmu_unmap_pages, .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, - .dma_sync = arm_smmu_dma_sync, .iova_to_phys = arm_smmu_iova_to_phys, .enable_nesting = arm_smmu_enable_nesting, .set_pgtable_quirks = arm_smmu_set_pgtable_quirks, diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 48112c53fdcd..5ef6cae0c2b5 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -63,9 +63,6 @@ /* Calculate the block/page mapping size at level l for pagetable in d. */ #define ARM_LPAE_BLOCK_SIZE(l,d) (1ULL << ARM_LPAE_LVL_SHIFT(l,d)) -#define ARM_LPAE_BLOCK_MASK(l, d) \ - (~(ARM_LPAE_BLOCK_SIZE(l, d) - 1)) - /* Page table bits */ #define ARM_LPAE_PTE_TYPE_SHIFT 0 #define ARM_LPAE_PTE_TYPE_MASK 0x3 @@ -274,13 +271,6 @@ static void __arm_lpae_sync_pte(arm_lpae_iopte *ptep, int num_entries, sizeof(*ptep) * num_entries, DMA_TO_DEVICE); } -static void __arm_lpae_sync_pgtable(arm_lpae_iopte *ptep, - struct io_pgtable_cfg *cfg, size_t size) -{ - dma_sync_single_for_device(cfg->iommu_dev, __arm_lpae_dma_addr(ptep), - size, DMA_TO_DEVICE); -} - static void __arm_lpae_clear_pte(arm_lpae_iopte *ptep, struct io_pgtable_cfg *cfg) { @@ -714,91 +704,6 @@ static size_t arm_lpae_unmap_pages(struct io_pgtable_ops *ops, unsigned long iov data->start_level, ptep); } -static unsigned long arm_lpae_block_addr_end(int lvl, - struct arm_lpae_io_pgtable *data, - unsigned long addr, unsigned long end) -{ - unsigned long boundary = (addr + ARM_LPAE_BLOCK_SIZE(lvl, data)) - & ARM_LPAE_BLOCK_MASK(lvl, data); - - return (boundary - 1 < end - 1) ? boundary : end; -} - -static void __arm_lpae_dma_sync(struct arm_lpae_io_pgtable *data, - unsigned long iova, size_t size, int lvl, - arm_lpae_iopte *ptep) -{ - arm_lpae_iopte pte; - arm_lpae_iopte *pte_entry; - struct io_pgtable_cfg *cfg = &data->iop.cfg; - size_t unmapped_size = 0; - size_t blk_size = ARM_LPAE_BLOCK_SIZE(lvl, data); - - /* If we are on the last level then sync. - * We don't do sync flags on last level because its not worth it - * performance wise - * */ - if ((lvl == ARM_LPAE_MAX_LEVELS - 1)) { - pte_entry = ptep + ARM_LPAE_LVL_IDX(iova, lvl, data); - __arm_lpae_sync_pgtable(pte_entry, cfg, - size / blk_size * sizeof(*ptep)); - return; - } - - while (unmapped_size < size) { - /* - * We can map the difference between our address and the end - * address of the table - */ - size_t end_map_address = arm_lpae_block_addr_end(lvl, data, - iova, iova + size); - size_t map_size = end_map_address - iova; - - if (map_size > size) - map_size = size; - - pte_entry = ptep + ARM_LPAE_LVL_IDX(iova, lvl, data); - pte = READ_ONCE(*pte_entry); - - if (pte) { - if ((pte & ARM_LPAE_PTE_SW_SYNC) == 0) { - pte |= ARM_LPAE_PTE_SW_SYNC; - *pte_entry = pte; - if (!cfg->coherent_walk) - __arm_lpae_sync_pte(pte_entry, 1, cfg); - __arm_lpae_sync_pgtable(pte_entry, cfg, - sizeof(*ptep)); - } - } else { - __arm_lpae_sync_pgtable(pte_entry, cfg, sizeof(*ptep)); - } - - if (pte && !iopte_leaf(pte, lvl, data->iop.fmt)) { - pte_entry = iopte_deref(pte, data); - __arm_lpae_dma_sync(data, iova, map_size, lvl + 1, - pte_entry); - } - - unmapped_size += map_size; - iova += map_size; - } -} - -static int arm_lpae_dma_sync(struct io_pgtable_ops *ops, unsigned long iova, - size_t size) -{ - struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); - arm_lpae_iopte *ptep = data->pgd; - int lvl = data->start_level; - - if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias))) - return 0; - - __arm_lpae_dma_sync(data, iova, size, lvl, ptep); - - return 0; -} - static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, unsigned long iova) { @@ -912,7 +817,6 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) data->iop.ops = (struct io_pgtable_ops) { .map_pages = arm_lpae_map_pages, .unmap_pages = arm_lpae_unmap_pages, - .dma_sync = arm_lpae_dma_sync, .iova_to_phys = arm_lpae_iova_to_phys, }; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 2f657f218ef2..e606d250d1d5 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2675,9 +2675,6 @@ static int __iommu_map(struct iommu_domain *domain, unsigned long iova, else trace_map(orig_iova, orig_paddr, orig_size); - if (domain->ops->dma_sync) - domain->ops->dma_sync(domain, orig_iova, orig_size); - return ret; } @@ -2761,9 +2758,6 @@ static size_t __iommu_unmap(struct iommu_domain *domain, unmapped += unmapped_page; } - if (ops->dma_sync) - ops->dma_sync(domain, orig_iova, size); - trace_unmap(orig_iova, size, unmapped); return unmapped; } diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h index 3475989d8776..86cf1f7ae389 100644 --- a/include/linux/io-pgtable.h +++ b/include/linux/io-pgtable.h @@ -188,8 +188,6 @@ struct io_pgtable_ops { size_t (*unmap_pages)(struct io_pgtable_ops *ops, unsigned long iova, size_t pgsize, size_t pgcount, struct iommu_iotlb_gather *gather); - int (*dma_sync)(struct io_pgtable_ops *ops, unsigned long iova, - size_t size); phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, unsigned long iova); int (*read_and_clear_dirty)(struct io_pgtable_ops *ops, diff --git a/include/linux/iommu.h b/include/linux/iommu.h index e5b2fa0bf639..e699bc07e692 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -567,8 +567,7 @@ struct iommu_domain_ops { struct iommu_iotlb_gather *iotlb_gather); int (*cache_invalidate_user)(struct iommu_domain *domain, struct iommu_user_data_array *array); - int (*dma_sync)(struct iommu_domain *domain, unsigned long iova, - size_t size); + phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);