dev-arm: Rewrite SMMUv3 Commands

This patch is rewriting the SMMUv3::processCommand method for the
following reasons:

* Command names were not matching spec
* Command encoding/opcode was wrong

The patch is not adding any new command: there is still a subset of
unimplemented commands; those are:

* CMD_TLBI_EL3_ALL
* CMD_TLBI_EL3_VA
* CMD_TLBI_EL2_ALL
* CMD_TLBI_EL2_VA
* CMD_TLBI_EL2_VAA
* CMD_TLBI_EL2_ASID

which require StreamWorld support, and

* CMD_ATC_INV
* CMD_PRI_RESP
* CMD_RESUME
* CMD_STALL_TERM

which require in sequence: ATS, PRI, Stall Model support

Change-Id: Ia2dd47b5588738402d9584a00cfc88c94c253ad0
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Michiel van Tol <michiel.vantol@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19668
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/dev/arm/smmu_v3.cc b/src/dev/arm/smmu_v3.cc
index 2c974b5..2853929 100644
--- a/src/dev/arm/smmu_v3.cc
+++ b/src/dev/arm/smmu_v3.cc
@@ -383,7 +383,7 @@
 void
 SMMUv3::processCommand(const SMMUCommand &cmd)
 {
-    switch (cmd.type) {
+    switch (cmd.dw0.type) {
         case CMD_PRF_CONFIG:
             DPRINTF(SMMUv3, "CMD_PREFETCH_CONFIG - ignored\n");
             break;
@@ -392,29 +392,128 @@
             DPRINTF(SMMUv3, "CMD_PREFETCH_ADDR - ignored\n");
             break;
 
-        case CMD_INV_STE:
-            DPRINTF(SMMUv3, "CMD_INV_STE sid=%#x\n", cmd.data[0]);
-            configCache.invalidateSID(cmd.data[0]);
+        case CMD_CFGI_STE: {
+            DPRINTF(SMMUv3, "CMD_CFGI_STE sid=%#x\n", cmd.dw0.sid);
+            configCache.invalidateSID(cmd.dw0.sid);
             break;
+        }
 
-        case CMD_INV_CD:
-            DPRINTF(SMMUv3, "CMD_INV_CD sid=%#x ssid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            configCache.invalidateSSID(cmd.data[0], cmd.data[1]);
+        case CMD_CFGI_STE_RANGE: {
+            const auto range = cmd.dw1.range;
+            if (range == 31) {
+                // CMD_CFGI_ALL is an alias of CMD_CFGI_STE_RANGE with
+                // range = 31
+                DPRINTF(SMMUv3, "CMD_CFGI_ALL\n");
+                configCache.invalidateAll();
+            } else {
+                DPRINTF(SMMUv3, "CMD_CFGI_STE_RANGE\n");
+                const auto start_sid = cmd.dw0.sid & ~((1 << (range + 1)) - 1);
+                const auto end_sid = start_sid + (1 << (range + 1)) - 1;
+                for (auto sid = start_sid; sid <= end_sid; sid++)
+                    configCache.invalidateSID(sid);
+            }
             break;
+        }
 
-        case CMD_INV_CD_ALL:
-            DPRINTF(SMMUv3, "CMD_INV_CD_ALL sid=%#x\n", cmd.data[0]);
-            configCache.invalidateSID(cmd.data[0]);
+        case CMD_CFGI_CD: {
+            DPRINTF(SMMUv3, "CMD_CFGI_CD sid=%#x ssid=%#x\n",
+                    cmd.dw0.sid, cmd.dw0.ssid);
+            configCache.invalidateSSID(cmd.dw0.sid, cmd.dw0.ssid);
             break;
+        }
 
-        case CMD_INV_ALL:
-            DPRINTF(SMMUv3, "CMD_INV_ALL\n");
-            configCache.invalidateAll();
+        case CMD_CFGI_CD_ALL: {
+            DPRINTF(SMMUv3, "CMD_CFGI_CD_ALL sid=%#x\n", cmd.dw0.sid);
+            configCache.invalidateSID(cmd.dw0.sid);
             break;
+        }
 
-        case CMD_TLBI_ALL:
-            DPRINTF(SMMUv3, "CMD_TLBI_ALL\n");
+        case CMD_TLBI_NH_ALL: {
+            DPRINTF(SMMUv3, "CMD_TLBI_NH_ALL vmid=%#x\n", cmd.dw0.vmid);
+            for (auto slave_interface : slaveInterfaces) {
+                slave_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
+                slave_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
+            }
+            tlb.invalidateVMID(cmd.dw0.vmid);
+            walkCache.invalidateVMID(cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_NH_ASID: {
+            DPRINTF(SMMUv3, "CMD_TLBI_NH_ASID asid=%#x vmid=%#x\n",
+                    cmd.dw0.asid, cmd.dw0.vmid);
+            for (auto slave_interface : slaveInterfaces) {
+                slave_interface->microTLB->invalidateASID(
+                    cmd.dw0.asid, cmd.dw0.vmid);
+                slave_interface->mainTLB->invalidateASID(
+                    cmd.dw0.asid, cmd.dw0.vmid);
+            }
+            tlb.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
+            walkCache.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_NH_VAA: {
+            const Addr addr = cmd.addr();
+            DPRINTF(SMMUv3, "CMD_TLBI_NH_VAA va=%#08x vmid=%#x\n",
+                    addr, cmd.dw0.vmid);
+            for (auto slave_interface : slaveInterfaces) {
+                slave_interface->microTLB->invalidateVAA(
+                    addr, cmd.dw0.vmid);
+                slave_interface->mainTLB->invalidateVAA(
+                    addr, cmd.dw0.vmid);
+            }
+            tlb.invalidateVAA(addr, cmd.dw0.vmid);
+
+            if (!cmd.dw1.leaf)
+                walkCache.invalidateVAA(addr, cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_NH_VA: {
+            const Addr addr = cmd.addr();
+            DPRINTF(SMMUv3, "CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n",
+                    addr, cmd.dw0.asid, cmd.dw0.vmid);
+            for (auto slave_interface : slaveInterfaces) {
+                slave_interface->microTLB->invalidateVA(
+                    addr, cmd.dw0.asid, cmd.dw0.vmid);
+                slave_interface->mainTLB->invalidateVA(
+                    addr, cmd.dw0.asid, cmd.dw0.vmid);
+            }
+            tlb.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid);
+
+            if (!cmd.dw1.leaf)
+                walkCache.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_S2_IPA: {
+            const Addr addr = cmd.addr();
+            DPRINTF(SMMUv3, "CMD_TLBI_S2_IPA ipa=%#08x vmid=%#x\n",
+                    addr, cmd.dw0.vmid);
+            // This does not invalidate TLBs containing
+            // combined Stage1 + Stage2 translations, as per the spec.
+            ipaCache.invalidateIPA(addr, cmd.dw0.vmid);
+
+            if (!cmd.dw1.leaf)
+                walkCache.invalidateVMID(cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_S12_VMALL: {
+            DPRINTF(SMMUv3, "CMD_TLBI_S12_VMALL vmid=%#x\n", cmd.dw0.vmid);
+            for (auto slave_interface : slaveInterfaces) {
+                slave_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
+                slave_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
+            }
+            tlb.invalidateVMID(cmd.dw0.vmid);
+            ipaCache.invalidateVMID(cmd.dw0.vmid);
+            walkCache.invalidateVMID(cmd.dw0.vmid);
+            break;
+        }
+
+        case CMD_TLBI_NSNH_ALL: {
+            DPRINTF(SMMUv3, "CMD_TLBI_NSNH_ALL\n");
             for (auto slave_interface : slaveInterfaces) {
                 slave_interface->microTLB->invalidateAll();
                 slave_interface->mainTLB->invalidateAll();
@@ -423,106 +522,15 @@
             ipaCache.invalidateAll();
             walkCache.invalidateAll();
             break;
+        }
 
-        case CMD_TLBI_ASID:
-            DPRINTF(SMMUv3, "CMD_TLBI_ASID asid=%#x vmid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateASID(
-                    cmd.data[0], cmd.data[1]);
-                slave_interface->mainTLB->invalidateASID(
-                    cmd.data[0], cmd.data[1]);
-            }
-            tlb.invalidateASID(cmd.data[0], cmd.data[1]);
-            walkCache.invalidateASID(cmd.data[0], cmd.data[1]);
-            break;
-
-        case CMD_TLBI_VAAL:
-            DPRINTF(SMMUv3, "CMD_TLBI_VAAL va=%#08x vmid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateVAA(
-                    cmd.data[0], cmd.data[1]);
-                slave_interface->mainTLB->invalidateVAA(
-                    cmd.data[0], cmd.data[1]);
-            }
-            tlb.invalidateVAA(cmd.data[0], cmd.data[1]);
-            break;
-
-        case CMD_TLBI_VAA:
-            DPRINTF(SMMUv3, "CMD_TLBI_VAA va=%#08x vmid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateVAA(
-                    cmd.data[0], cmd.data[1]);
-                slave_interface->mainTLB->invalidateVAA(
-                    cmd.data[0], cmd.data[1]);
-            }
-            tlb.invalidateVAA(cmd.data[0], cmd.data[1]);
-            walkCache.invalidateVAA(cmd.data[0], cmd.data[1]);
-            break;
-
-        case CMD_TLBI_VAL:
-            DPRINTF(SMMUv3, "CMD_TLBI_VAL va=%#08x asid=%#x vmid=%#x\n",
-                cmd.data[0], cmd.data[1], cmd.data[2]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateVA(
-                    cmd.data[0], cmd.data[1], cmd.data[2]);
-                slave_interface->mainTLB->invalidateVA(
-                    cmd.data[0], cmd.data[1], cmd.data[2]);
-            }
-            tlb.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
-            break;
-
-        case CMD_TLBI_VA:
-            DPRINTF(SMMUv3, "CMD_TLBI_VA va=%#08x asid=%#x vmid=%#x\n",
-                cmd.data[0], cmd.data[1], cmd.data[2]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateVA(
-                    cmd.data[0], cmd.data[1], cmd.data[2]);
-                slave_interface->mainTLB->invalidateVA(
-                    cmd.data[0], cmd.data[1], cmd.data[2]);
-            }
-            tlb.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
-            walkCache.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
-            break;
-
-        case CMD_TLBI_VM_IPAL:
-            DPRINTF(SMMUv3, "CMD_TLBI_VM_IPAL ipa=%#08x vmid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            // This does not invalidate TLBs containing
-            // combined Stage1 + Stage2 translations, as per the spec.
-            ipaCache.invalidateIPA(cmd.data[0], cmd.data[1]);
-            walkCache.invalidateVMID(cmd.data[1]);
-            break;
-
-        case CMD_TLBI_VM_IPA:
-            DPRINTF(SMMUv3, "CMD_TLBI_VM_IPA ipa=%#08x vmid=%#x\n",
-                cmd.data[0], cmd.data[1]);
-            // This does not invalidate TLBs containing
-            // combined Stage1 + Stage2 translations, as per the spec.
-            ipaCache.invalidateIPA(cmd.data[0], cmd.data[1]);
-            walkCache.invalidateVMID(cmd.data[1]);
-            break;
-
-        case CMD_TLBI_VM_S12:
-            DPRINTF(SMMUv3, "CMD_TLBI_VM_S12 vmid=%#x\n", cmd.data[0]);
-            for (auto slave_interface : slaveInterfaces) {
-                slave_interface->microTLB->invalidateVMID(cmd.data[0]);
-                slave_interface->mainTLB->invalidateVMID(cmd.data[0]);
-            }
-            tlb.invalidateVMID(cmd.data[0]);
-            ipaCache.invalidateVMID(cmd.data[0]);
-            walkCache.invalidateVMID(cmd.data[0]);
-            break;
-
-        case CMD_RESUME_S:
-            DPRINTF(SMMUv3, "CMD_RESUME_S\n");
+        case CMD_RESUME:
+            DPRINTF(SMMUv3, "CMD_RESUME\n");
             panic("resume unimplemented");
             break;
 
         default:
-            warn("Unimplemented command %#x\n", cmd.type);
+            warn("Unimplemented command %#x\n", cmd.dw0.type);
             break;
     }
 }
diff --git a/src/dev/arm/smmu_v3_defs.hh b/src/dev/arm/smmu_v3_defs.hh
index d993fd7..655835f 100644
--- a/src/dev/arm/smmu_v3_defs.hh
+++ b/src/dev/arm/smmu_v3_defs.hh
@@ -321,28 +321,58 @@
 };
 
 enum SMMUCommandType {
-    CMD_PRF_CONFIG   = 0x1000,
-    CMD_PRF_ADDR     = 0x1001,
-    CMD_INV_STE      = 0x1100,
-    CMD_INV_CD       = 0x1101,
-    CMD_INV_CD_ALL   = 0x1102,
-    CMD_INV_ALL      = 0x1104,
-    CMD_TLBI_ALL     = 0x1110,
-    CMD_TLBI_ASID    = 0x1111,
-    CMD_TLBI_VAAL    = 0x1112,
-    CMD_TLBI_VAA     = 0x1113,
-    CMD_TLBI_VAL     = 0x1114,
-    CMD_TLBI_VA      = 0x1115,
-    CMD_TLBI_VM_IPAL = 0x1120,
-    CMD_TLBI_VM_IPA  = 0x1121,
-    CMD_TLBI_VM_S12  = 0x1122,
-    CMD_RESUME_S     = 0x1200,
+    CMD_PRF_CONFIG     = 0x01,
+    CMD_PRF_ADDR       = 0x02,
+    CMD_CFGI_STE       = 0x03,
+    CMD_CFGI_STE_RANGE = 0x04,
+    CMD_CFGI_CD        = 0x05,
+    CMD_CFGI_CD_ALL    = 0x06,
+    CMD_TLBI_NH_ALL    = 0x10,
+    CMD_TLBI_NH_ASID   = 0x11,
+    CMD_TLBI_NH_VAA    = 0x13,
+    CMD_TLBI_NH_VA     = 0x12,
+    CMD_TLBI_EL3_ALL   = 0x18,
+    CMD_TLBI_EL3_VA    = 0x1A,
+    CMD_TLBI_EL2_ALL   = 0x20,
+    CMD_TLBI_EL2_ASID  = 0x21,
+    CMD_TLBI_EL2_VA    = 0x22,
+    CMD_TLBI_EL2_VAA   = 0x23,
+    CMD_TLBI_S2_IPA    = 0x2a,
+    CMD_TLBI_S12_VMALL = 0x28,
+    CMD_TLBI_NSNH_ALL  = 0x30,
+    CMD_ATC_INV        = 0x40,
+    CMD_PRI_RESP       = 0x41,
+    CMD_RESUME         = 0x44,
+    CMD_STALL_TERM     = 0x45,
+    CMD_SYNC           = 0x46,
 };
 
 struct SMMUCommand
 {
-    uint32_t type;
-    uint32_t data[3];
+    BitUnion64(DWORD0)
+        Bitfield<7, 0>   type;
+        Bitfield<10>     ssec;
+        Bitfield<11>     ssv;
+        Bitfield<31, 12> ssid;
+        Bitfield<47, 32> vmid;
+        Bitfield<63, 48> asid;
+        Bitfield<63, 32> sid;
+    EndBitUnion(DWORD0)
+    DWORD0 dw0;
+
+    BitUnion64(DWORD1)
+        Bitfield<0>      leaf;
+        Bitfield<4, 0>   size;
+        Bitfield<4, 0>   range;
+        Bitfield<63, 12> address;
+    EndBitUnion(DWORD1)
+    DWORD1 dw1;
+
+    uint64_t addr() const
+    {
+        uint64_t address = (uint64_t)(dw1.address) << 12;
+        return address;
+    }
 };
 
 enum SMMUEventTypes {