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 <amhetre@nvidia.com> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Acked-by: Noah Wager <noah.wager@canonical.com> Acked-by: Jacob Martin <jacob.martin@canonical.com> Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
committed by
Noah Wager
parent
7d7589445b
commit
b4b2a0f973
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user