diff options
author | Eric Auger <eric.auger@redhat.com> | 2021-03-09 11:27:37 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-03-12 12:40:10 +0000 |
commit | f14fb6c2db961c3665a61b342ab329b7bd20d1e7 (patch) | |
tree | 57f311ed8f4d445ad5c1474751e76206e25bf972 /softmmu/dma-helpers.c | |
parent | 41ce9a912641cd7f820bcfccea15e30efc32104e (diff) |
dma: Introduce dma_aligned_pow2_mask()
Currently get_naturally_aligned_size() is used by the intel iommu
to compute the maximum invalidation range based on @size which is
a power of 2 while being aligned with the @start address and less
than the maximum range defined by @gaw.
This helper is also useful for other iommu devices (virtio-iommu,
SMMUv3) to make sure IOMMU UNMAP notifiers only are called with
power of 2 range sizes.
Let's move this latter into dma-helpers.c and rename it into
dma_aligned_pow2_mask(). Also rewrite the helper so that it
accomodates UINT64_MAX values for the size mask and max mask.
It now returns a mask instead of a size. Change the caller.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Message-id: 20210309102742.30442-3-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'softmmu/dma-helpers.c')
-rw-r--r-- | softmmu/dma-helpers.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c index 29001b5459..7d766a5e89 100644 --- a/softmmu/dma-helpers.c +++ b/softmmu/dma-helpers.c @@ -330,3 +330,29 @@ void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie, { block_acct_start(blk_get_stats(blk), cookie, sg->size, type); } + +uint64_t dma_aligned_pow2_mask(uint64_t start, uint64_t end, int max_addr_bits) +{ + uint64_t max_mask = UINT64_MAX, addr_mask = end - start; + uint64_t alignment_mask, size_mask; + + if (max_addr_bits != 64) { + max_mask = (1ULL << max_addr_bits) - 1; + } + + alignment_mask = start ? (start & -start) - 1 : max_mask; + alignment_mask = MIN(alignment_mask, max_mask); + size_mask = MIN(addr_mask, max_mask); + + if (alignment_mask <= size_mask) { + /* Increase the alignment of start */ + return alignment_mask; + } else { + /* Find the largest page mask from size */ + if (addr_mask == UINT64_MAX) { + return UINT64_MAX; + } + return (1ULL << (63 - clz64(addr_mask + 1))) - 1; + } +} + |