@@ -79,6 +79,13 @@ REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
REG32(CR2, 0x2c)
REG32(STATUSR, 0x40)
+REG32(GBPA, 0x44)
+ FIELD(GBPA, ABORT, 20, 1)
+ FIELD(GBPA, UPDATE, 31, 1)
+
+/* Use incoming. */
+#define SMMU_GBPA_RESET_VAL 0x1000
+
REG32(IRQ_CTRL, 0x50)
FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1)
FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1)
@@ -45,6 +45,7 @@ struct SMMUv3State {
uint32_t cr[3];
uint32_t cr0ack;
uint32_t statusr;
+ uint32_t gbpa;
uint32_t irq_ctrl;
uint32_t gerror;
uint32_t gerrorn;
@@ -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)