diff options
Diffstat (limited to 'hw/arm/smmuv3.c')
-rw-r--r-- | hw/arm/smmuv3.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index bd1f970..fdd6332 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -861,7 +861,8 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) uint16_t vmid = CMD_VMID(cmd); bool leaf = CMD_LEAF(cmd); uint8_t tg = CMD_TG(cmd); - hwaddr num_pages = 1; + uint64_t first_page = 0, last_page; + uint64_t num_pages = 1; int asid = -1; if (tg) { @@ -874,9 +875,24 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) if (type == SMMU_CMD_TLBI_NH_VA) { asid = CMD_ASID(cmd); } - 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); + + /* Split invalidations into ^2 range invalidations */ + last_page = num_pages - 1; + while (num_pages) { + uint8_t granule = tg * 2 + 10; + uint64_t mask, count; + + mask = dma_aligned_pow2_mask(first_page, last_page, 64 - granule); + count = mask + 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); + + num_pages -= count; + first_page += count; + addr += count * BIT_ULL(granule); + } } static int smmuv3_cmdq_consume(SMMUv3State *s) |