diff mbox series

[v2] hw/arm/smmuv3: Add GBPA register

Message ID 20230126141120.448641-1-smostafa@google.com (mailing list archive)
State New, archived
Headers show
Series [v2] hw/arm/smmuv3: Add GBPA register | expand

Commit Message

Mostafa Saleh Jan. 26, 2023, 2:11 p.m. UTC
GBPA register can be used to globally abort all
transactions.

It is described in the SMMU manual in "6.3.14 SMMU_GBPA".
ABORT reset value is IMPLEMENTATION DEFINED, it is chosen to
be zero(Do not abort incoming transactions).

Other fields have default values of Use Incoming.

If UPDATE is not set, the write is ignored. This is the only permitted
behavior in SMMUv3.2 and later.(6.3.14.1 Update procedure)

As this patch adds a new state to the SMMU (GBPA), it is added
in a new subsection for forward migration compatibility.

Property "migrate-gbpa" was added to support backward compatibility.
However, if the GBPA.ABORT is set from SW at time of migration, the
GBPA migration will be forced to avoid inconsistencies where a qemu
instance is aborting transactions and it is migrated to another
instance bypassing them.

Signed-off-by: Mostafa Saleh <smostafa@google.com>

Changes in v2:
- GBPA is effective only when SMMU is not enabled.
- Ignore GBPA write when UPDATE is not set.
- Default value for SHCFG is "Use Incoming".
- Support migration.
---
 hw/arm/smmuv3-internal.h |  5 +++
 hw/arm/smmuv3.c          | 71 +++++++++++++++++++++++++++++++++++++++-
 include/hw/arm/smmuv3.h  |  2 ++
 3 files changed, 77 insertions(+), 1 deletion(-)

Comments

Peter Maydell Feb. 7, 2023, 2:03 p.m. UTC | #1
On Thu, 26 Jan 2023 at 14:12, Mostafa Saleh <smostafa@google.com> wrote:
>
> GBPA register can be used to globally abort all
> transactions.
>
> It is described in the SMMU manual in "6.3.14 SMMU_GBPA".
> ABORT reset value is IMPLEMENTATION DEFINED, it is chosen to
> be zero(Do not abort incoming transactions).
>
> Other fields have default values of Use Incoming.
>
> If UPDATE is not set, the write is ignored. This is the only permitted
> behavior in SMMUv3.2 and later.(6.3.14.1 Update procedure)
>
> As this patch adds a new state to the SMMU (GBPA), it is added
> in a new subsection for forward migration compatibility.
>
> Property "migrate-gbpa" was added to support backward compatibility.
> However, if the GBPA.ABORT is set from SW at time of migration, the
> GBPA migration will be forced to avoid inconsistencies where a qemu
> instance is aborting transactions and it is migrated to another
> instance bypassing them.

Nothing ever sets the migrate-gpba property to anything
except its default 'true' value, so this (a) means that
it breaks migration compat and (b) seems a bit unneccessary.

Can we say "migrate the field only if it is something other
than its reset value", not have the property, and get
migration compatibility that way ?

Otherwise the patch looks OK.

thanks
-- PMM
Mostafa Saleh Feb. 7, 2023, 6:07 p.m. UTC | #2
Hi Peter,

On Tue, Feb 07, 2023 at 02:03:02PM +0000, Peter Maydell wrote:
> On Thu, 26 Jan 2023 at 14:12, Mostafa Saleh <smostafa@google.com> wrote:
> >
> > GBPA register can be used to globally abort all
> > transactions.
> >
> > It is described in the SMMU manual in "6.3.14 SMMU_GBPA".
> > ABORT reset value is IMPLEMENTATION DEFINED, it is chosen to
> > be zero(Do not abort incoming transactions).
> >
> > Other fields have default values of Use Incoming.
> >
> > If UPDATE is not set, the write is ignored. This is the only permitted
> > behavior in SMMUv3.2 and later.(6.3.14.1 Update procedure)
> >
> > As this patch adds a new state to the SMMU (GBPA), it is added
> > in a new subsection for forward migration compatibility.
> >
> > Property "migrate-gbpa" was added to support backward compatibility.
> > However, if the GBPA.ABORT is set from SW at time of migration, the
> > GBPA migration will be forced to avoid inconsistencies where a qemu
> > instance is aborting transactions and it is migrated to another
> > instance bypassing them.
> 
> Nothing ever sets the migrate-gpba property to anything
> except its default 'true' value, so this (a) means that
> it breaks migration compat and (b) seems a bit unneccessary.
> 
> Can we say "migrate the field only if it is something other
> than its reset value", not have the property, and get
> migration compatibility that way ?
> 
> Otherwise the patch looks OK.
> 
> thanks
> -- PMM

Thanks for reviewing the patch. I am not really familiar with migration,
My understanding that this would be set from cmdline(that is how I tested it).

But yes, you are right, this is actually unnecessary, we can just
migrate only if GBPA value is different from reset value.

I will send v3 with this change.

Thanks,
Mostafa
diff mbox series

Patch

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index bce161870f..3ff704248d 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -79,6 +79,11 @@  REG32(CR0ACK,              0x24)
 REG32(CR1,                 0x28)
 REG32(CR2,                 0x2c)
 REG32(STATUSR,             0x40)
+REG32(GBPA,                0x44)
+    FIELD(GBPA, SHCFG,        12, 2)
+    FIELD(GBPA, ABORT,        20, 1)
+    FIELD(GBPA, UPDATE,       31, 1)
+
 REG32(IRQ_CTRL,            0x50)
     FIELD(IRQ_CTRL, GERROR_IRQEN,        0, 1)
     FIELD(IRQ_CTRL, PRI_IRQEN,           1, 1)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 955b89c8d5..509aa923cd 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -21,6 +21,7 @@ 
 #include "hw/irq.h"
 #include "hw/sysbus.h"
 #include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
 #include "hw/qdev-core.h"
 #include "hw/pci/pci.h"
 #include "cpu.h"
@@ -285,6 +286,8 @@  static void smmuv3_init_regs(SMMUv3State *s)
     s->gerror = 0;
     s->gerrorn = 0;
     s->statusr = 0;
+    /* Use incoming as other fields. */
+    s->gbpa = FIELD_DP32(s->gbpa, GBPA, SHCFG, 1);
 }
 
 static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
@@ -659,7 +662,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 +1177,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 +1335,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 +1502,39 @@  static const VMStateDescription vmstate_smmuv3_queue = {
     },
 };
 
+static bool smmuv3_gbpa_needed(void *opaque)
+{
+    SMMUv3State *s = opaque;
+    bool is_abort = FIELD_EX32(s->gbpa, GBPA, ABORT);
+
+    /*
+     * We migrate GBPA if migrate_gbpa property is set.
+     * If it is not set, but the GBPA register is set to abort, we force to
+     * migrate it as this can lead to inconsistencies where a qemu instance
+     * is aborting transcations and it is migrated another instance bypassing
+     * them. So we force to send the GBPA in this case, if the other instance
+     * was older it would fail migration.
+     */
+    if (!s->migrate_gbpa && is_abort) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Forcing to migrate GBPA as it was set from SW.\n");
+        return true;
+    }
+
+    return s->migrate_gbpa;
+}
+
+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 +1565,21 @@  static const VMStateDescription vmstate_smmuv3 = {
 
         VMSTATE_END_OF_LIST(),
     },
+    .subsections = (const VMStateDescription * []) {
+        &vmstate_gbpa,
+        NULL
+    }
+};
+
+static Property smmuv3_properties[] = {
+    /*
+     * True to correctly migrate the GBPA register.
+     * False to get backward migration compatibility with older QEMU versions
+     * if possible.
+     */
+    DEFINE_PROP_BOOL("migrate-gbpa",
+                     SMMUv3State, migrate_gbpa, true),
+    DEFINE_PROP_END_OF_LIST()
 };
 
 static void smmuv3_instance_init(Object *obj)
@@ -1530,6 +1598,7 @@  static void smmuv3_class_init(ObjectClass *klass, void *data)
                                        &c->parent_phases);
     c->parent_realize = dc->realize;
     dc->realize = smmu_realize;
+    device_class_set_props(dc, smmuv3_properties);
 }
 
 static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index f1921fdf9e..075f09618c 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -46,6 +46,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;
@@ -57,6 +58,7 @@  struct SMMUv3State {
     uint64_t eventq_irq_cfg0;
     uint32_t eventq_irq_cfg1;
     uint32_t eventq_irq_cfg2;
+    bool migrate_gbpa;
 
     SMMUQueue eventq, cmdq;