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>
This commit is contained in:
Eric Auger 2020-07-28 17:08:11 +02:00 committed by Peter Maydell
parent c0f9ef7037
commit d52915616c
5 changed files with 69 additions and 31 deletions

View file

@ -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)