summaryrefslogtreecommitdiffstats
path: root/hw/arm/smmuv3.c
diff options
context:
space:
mode:
authorEric Auger2020-07-28 17:08:11 +0200
committerPeter Maydell2020-08-24 11:02:06 +0200
commitd52915616c059ed273caa2d496b58e5d215c5962 (patch)
treec854e261fd162af4be9f7ed42db96b31524b799c /hw/arm/smmuv3.c
parenthw/arm/smmuv3: Introduce smmuv3_s1_range_inval() helper (diff)
downloadqemu-d52915616c059ed273caa2d496b58e5d215c5962.tar.gz
qemu-d52915616c059ed273caa2d496b58e5d215c5962.tar.xz
qemu-d52915616c059ed273caa2d496b58e5d215c5962.zip
hw/arm/smmuv3: Get prepared for range invalidation
Enhance the smmu_iotlb_inv_iova() helper with range invalidation. This uses the new fields passed in the NH_VA and NH_VAA commands: the size of the range, the level and the granule. As NH_VA and NH_VAA both use those fields, their decoding and handling is factorized in a new smmuv3_s1_range_inval() helper. Signed-off-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20200728150815.11446-8-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm/smmuv3.c')
-rw-r--r--hw/arm/smmuv3.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index e4a2cea7ad..89ab11fc36 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -785,42 +785,49 @@ epilogue:
* @n: notifier to be called
* @asid: address space ID or negative value if we don't care
* @iova: iova
+ * @tg: translation granule (if communicated through range invalidation)
+ * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
*/
static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
IOMMUNotifier *n,
- int asid,
- dma_addr_t iova)
+ int asid, dma_addr_t iova,
+ uint8_t tg, uint64_t num_pages)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
- SMMUEventInfo event = {.inval_ste_allowed = true};
- SMMUTransTableInfo *tt;
- SMMUTransCfg *cfg;
IOMMUTLBEntry entry;
+ uint8_t granule = tg;
- cfg = smmuv3_get_config(sdev, &event);
- if (!cfg) {
- return;
- }
+ if (!tg) {
+ SMMUEventInfo event = {.inval_ste_allowed = true};
+ SMMUTransCfg *cfg = smmuv3_get_config(sdev, &event);
+ SMMUTransTableInfo *tt;
- if (asid >= 0 && cfg->asid != asid) {
- return;
- }
+ if (!cfg) {
+ return;
+ }
- tt = select_tt(cfg, iova);
- if (!tt) {
- return;
+ if (asid >= 0 && cfg->asid != asid) {
+ return;
+ }
+
+ tt = select_tt(cfg, iova);
+ if (!tt) {
+ return;
+ }
+ granule = tt->granule_sz;
}
entry.target_as = &address_space_memory;
entry.iova = iova;
- entry.addr_mask = (1 << tt->granule_sz) - 1;
+ entry.addr_mask = num_pages * (1 << granule) - 1;
entry.perm = IOMMU_NONE;
memory_region_notify_one(n, &entry);
}
-/* invalidate an asid/iova tuple in all mr's */
-static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova)
+/* invalidate an asid/iova range tuple in all mr's */
+static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova,
+ uint8_t tg, uint64_t num_pages)
{
SMMUDevice *sdev;
@@ -828,28 +835,39 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova)
IOMMUMemoryRegion *mr = &sdev->iommu;
IOMMUNotifier *n;
- trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova);
+ trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova,
+ tg, num_pages);
IOMMU_NOTIFIER_FOREACH(n, mr) {
- smmuv3_notify_iova(mr, n, asid, iova);
+ smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages);
}
}
}
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);
uint8_t type = CMD_TYPE(cmd);
uint16_t vmid = CMD_VMID(cmd);
bool leaf = CMD_LEAF(cmd);
+ uint8_t tg = CMD_TG(cmd);
+ hwaddr num_pages = 1;
int asid = -1;
+ if (tg) {
+ scale = CMD_SCALE(cmd);
+ num = CMD_NUM(cmd);
+ ttl = CMD_TTL(cmd);
+ num_pages = (num + 1) * (1 << (scale));
+ }
+
if (type == SMMU_CMD_TLBI_NH_VA) {
asid = CMD_ASID(cmd);
}
- trace_smmuv3_s1_range_inval(vmid, asid, addr, leaf);
- smmuv3_inv_notifiers_iova(s, asid, addr);
- smmu_iotlb_inv_iova(s, asid, addr);
+ 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);
}
static int smmuv3_cmdq_consume(SMMUv3State *s)