summaryrefslogtreecommitdiffstats
path: root/hw/arm/smmuv3.c
diff options
context:
space:
mode:
authorEric Auger2021-05-10 14:47:47 +0200
committerPeter Maydell2021-05-25 16:44:45 +0200
commit219729cfbf9e979020bffedac6a790144173ec62 (patch)
tree7c5b94eb7aedc802ddec6f3d4a33ca4301d278ea /hw/arm/smmuv3.c
parentMerge remote-tracking branch 'remotes/stefanha-gitlab/tags/block-pull-request... (diff)
downloadqemu-219729cfbf9e979020bffedac6a790144173ec62.tar.gz
qemu-219729cfbf9e979020bffedac6a790144173ec62.tar.xz
qemu-219729cfbf9e979020bffedac6a790144173ec62.zip
hw/arm/smmuv3: Another range invalidation fix
6d9cd115b9 ("hw/arm/smmuv3: Enforce invalidation on a power of two range") failed to completely fix misalignment issues with range invalidation. For instance invalidations patterns like "invalidate 32 4kB pages starting from 0xff395000 are not correctly handled" due to the fact the previous fix only made sure the number of invalidated pages were a power of 2 but did not properly handle the start address was not aligned with the range. This can be noticed when boothing a fedora 33 with protected virtio-blk-pci. Signed-off-by: Eric Auger <eric.auger@redhat.com> Fixes: 6d9cd115b9 ("hw/arm/smmuv3: Enforce invalidation on a power of two range") Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm/smmuv3.c')
-rw-r--r--hw/arm/smmuv3.c50
1 files changed, 26 insertions, 24 deletions
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 7bed2ac520..01b60bee49 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -857,43 +857,45 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova,
static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
{
- uint8_t scale = 0, num = 0, ttl = 0;
- dma_addr_t addr = CMD_ADDR(cmd);
+ dma_addr_t end, addr = CMD_ADDR(cmd);
uint8_t type = CMD_TYPE(cmd);
uint16_t vmid = CMD_VMID(cmd);
+ uint8_t scale = CMD_SCALE(cmd);
+ uint8_t num = CMD_NUM(cmd);
+ uint8_t ttl = CMD_TTL(cmd);
bool leaf = CMD_LEAF(cmd);
uint8_t tg = CMD_TG(cmd);
- uint64_t first_page = 0, last_page;
- uint64_t num_pages = 1;
+ uint64_t num_pages;
+ uint8_t granule;
int asid = -1;
- if (tg) {
- scale = CMD_SCALE(cmd);
- num = CMD_NUM(cmd);
- ttl = CMD_TTL(cmd);
- num_pages = (num + 1) * BIT_ULL(scale);
- }
-
if (type == SMMU_CMD_TLBI_NH_VA) {
asid = CMD_ASID(cmd);
}
- /* Split invalidations into ^2 range invalidations */
- last_page = num_pages - 1;
- while (num_pages) {
- uint8_t granule = tg * 2 + 10;
- uint64_t mask, count;
+ if (!tg) {
+ trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, 1, ttl, leaf);
+ smmuv3_inv_notifiers_iova(s, asid, addr, tg, 1);
+ smmu_iotlb_inv_iova(s, asid, addr, tg, 1, ttl);
+ return;
+ }
+
+ /* RIL in use */
- mask = dma_aligned_pow2_mask(first_page, last_page, 64 - granule);
- count = mask + 1;
+ num_pages = (num + 1) * BIT_ULL(scale);
+ granule = tg * 2 + 10;
+
+ /* Split invalidations into ^2 range invalidations */
+ end = addr + (num_pages << granule) - 1;
- trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, count, ttl, leaf);
- smmuv3_inv_notifiers_iova(s, asid, addr, tg, count);
- smmu_iotlb_inv_iova(s, asid, addr, tg, count, ttl);
+ while (addr != end + 1) {
+ uint64_t mask = dma_aligned_pow2_mask(addr, end, 64);
- num_pages -= count;
- first_page += count;
- addr += count * BIT_ULL(granule);
+ num_pages = (mask + 1) >> granule;
+ trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf);
+ smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages);
+ smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl);
+ addr += mask + 1;
}
}