diff options
Diffstat (limited to 'hw/arm/smmuv3.c')
| -rw-r--r-- | hw/arm/smmuv3.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 955b89c8d5..270c80b665 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -285,6 +285,7 @@ static void smmuv3_init_regs(SMMUv3State *s) s->gerror = 0; s->gerrorn = 0; s->statusr = 0; + s->gbpa = SMMU_GBPA_RESET_VAL; } static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf, @@ -659,7 +660,11 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr, qemu_mutex_lock(&s->mutex); if (!smmu_enabled(s)) { - status = SMMU_TRANS_DISABLE; + if (FIELD_EX32(s->gbpa, GBPA, ABORT)) { + status = SMMU_TRANS_ABORT; + } else { + status = SMMU_TRANS_DISABLE; + } goto epilogue; } @@ -1170,6 +1175,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset, case A_GERROR_IRQ_CFG2: s->gerror_irq_cfg2 = data; return MEMTX_OK; + case A_GBPA: + /* + * If UPDATE is not set, the write is ignored. This is the only + * permitted behavior in SMMUv3.2 and later. + */ + if (data & R_GBPA_UPDATE_MASK) { + /* Ignore update bit as write is synchronous. */ + s->gbpa = data & ~R_GBPA_UPDATE_MASK; + } + return MEMTX_OK; case A_STRTAB_BASE: /* 64b */ s->strtab_base = deposit64(s->strtab_base, 0, 32, data); return MEMTX_OK; @@ -1318,6 +1333,9 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset, case A_STATUSR: *data = s->statusr; return MEMTX_OK; + case A_GBPA: + *data = s->gbpa; + return MEMTX_OK; case A_IRQ_CTRL: case A_IRQ_CTRL_ACK: *data = s->irq_ctrl; @@ -1482,6 +1500,25 @@ static const VMStateDescription vmstate_smmuv3_queue = { }, }; +static bool smmuv3_gbpa_needed(void *opaque) +{ + SMMUv3State *s = opaque; + + /* Only migrate GBPA if it has different reset value. */ + return s->gbpa != SMMU_GBPA_RESET_VAL; +} + +static const VMStateDescription vmstate_gbpa = { + .name = "smmuv3/gbpa", + .version_id = 1, + .minimum_version_id = 1, + .needed = smmuv3_gbpa_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT32(gbpa, SMMUv3State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_smmuv3 = { .name = "smmuv3", .version_id = 1, @@ -1512,6 +1549,10 @@ static const VMStateDescription vmstate_smmuv3 = { VMSTATE_END_OF_LIST(), }, + .subsections = (const VMStateDescription * []) { + &vmstate_gbpa, + NULL + } }; static void smmuv3_instance_init(Object *obj) |