Alex Dutu has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/53066 )

Change subject: dev-amdgpu: Add VM class for apertures, TranslationGens
......................................................................

dev-amdgpu: Add VM class for apertures, TranslationGens

Create a VM class to reduce clutter in the amdgpu_device.* files. This
new file is in charge of reading/writting MMIOs related to VM contexts
and apertures. It also provides ranges checks for various apertures and
breaks out the MMIO interface so that there are not overloaded macro
definitions in the device MMIO methods.

The new translation generator classes for the various apertures are also
added to this class.

Change-Id: Ic224c1aa485685685b1136a46eed50bcf99d2350
---
M src/dev/amdgpu/sdma_engine.cc
M src/dev/amdgpu/amdgpu_defines.hh
M src/dev/amdgpu/SConscript
A src/dev/amdgpu/amdgpu_vm.cc
A src/dev/amdgpu/amdgpu_vm.hh
M src/dev/amdgpu/amdgpu_device.cc
M src/dev/amdgpu/amdgpu_device.hh
M src/arch/amdgpu/vega/tlb.cc
8 files changed, 754 insertions(+), 182 deletions(-)



diff --git a/src/arch/amdgpu/vega/tlb.cc b/src/arch/amdgpu/vega/tlb.cc
index ca7e6a0..8cbf8d9 100644
--- a/src/arch/amdgpu/vega/tlb.cc
+++ b/src/arch/amdgpu/vega/tlb.cc
@@ -621,7 +621,7 @@
         DPRINTF(GPUTLB, "Doing a page walk for address %#x\n",
                 virtPageAddr);

-        Addr base = gpuDevice->getPageTableBase(1);
+        Addr base = gpuDevice->getVM().getPageTableBase(1);
         Addr vaddr = pkt->req->getVaddr();
         walker->setDevRequestor(gpuDevice->vramRequestorId());

@@ -822,7 +822,7 @@
             PageTableEntry pte;

             // Initialize walker state for VMID
-            Addr base = tlb->gpuDevice->getPageTableBase(1);
+            Addr base = tlb->gpuDevice->getVM().getPageTableBase(1);
tlb->walker->setDevRequestor(tlb->gpuDevice->vramRequestorId());

             // Do page table walk
diff --git a/src/dev/amdgpu/SConscript b/src/dev/amdgpu/SConscript
index 830a991..ebf7977 100644
--- a/src/dev/amdgpu/SConscript
+++ b/src/dev/amdgpu/SConscript
@@ -38,6 +38,7 @@
 SimObject('AMDGPU.py', tags='x86 isa')

 Source('amdgpu_device.cc', tags='x86 isa')
+Source('amdgpu_vm.cc', tags='x86 isa')
 Source('interrupt_handler.cc', tags='x86 isa')
 Source('memory_manager.cc', tags='x86 isa')
 Source('mmio_reader.cc', tags='x86 isa')
diff --git a/src/dev/amdgpu/amdgpu_defines.hh b/src/dev/amdgpu/amdgpu_defines.hh
index 778b64c..9e62644 100644
--- a/src/dev/amdgpu/amdgpu_defines.hh
+++ b/src/dev/amdgpu/amdgpu_defines.hh
@@ -34,6 +34,8 @@
 #ifndef __DEV_AMDGPU_AMDGPU_DEFINES_HH__
 #define __DEV_AMDGPU_AMDGPU_DEFINES_HH__

+#include "base/types.hh"
+
 namespace gem5
 {

@@ -49,6 +51,9 @@
     RLC
 };

+// AMD GPUs support 16 different virtual address spaces
+static constexpr int AMDGPU_VM_COUNT = 16;
+
 /* Names of BARs used by the device. */
 constexpr int FRAMEBUFFER_BAR = 0;
 constexpr int DOORBELL_BAR = 2;
diff --git a/src/dev/amdgpu/amdgpu_device.cc b/src/dev/amdgpu/amdgpu_device.cc
index c41a505..d3b0577 100644
--- a/src/dev/amdgpu/amdgpu_device.cc
+++ b/src/dev/amdgpu/amdgpu_device.cc
@@ -36,6 +36,7 @@
 #include <fstream>

 #include "debug/AMDGPUDevice.hh"
+#include "dev/amdgpu/amdgpu_vm.hh"
 #include "dev/amdgpu/interrupt_handler.hh"
 #include "dev/amdgpu/sdma_engine.hh"
 #include "mem/packet.hh"
@@ -74,9 +75,6 @@
     sdma1->setGPUDevice(this);
     sdma1->setId(1);
     deviceIH->setGPUDevice(this);
-
-    // Zero out context0
-    memset(&vmContext0, 0, sizeof(SysVMContext));
 }

 void
@@ -190,8 +188,24 @@
 void
 AMDGPUDevice::readMMIO(PacketPtr pkt, Addr offset)
 {
+    Addr aperture = gpuvm.getMmioAperture(offset);
+    Addr aperture_offset = offset - aperture;
+
+    // By default read from MMIO trace. Overwrite the packet for a select
+    // few more dynamic MMIOs.
     DPRINTF(AMDGPUDevice, "Read MMIO %#lx\n", offset);
     mmioReader.readFromTrace(pkt, MMIO_BAR, offset);
+
+    switch (aperture) {
+      case GRBM_BASE:
+        gpuvm.readMMIO(pkt, aperture_offset >> GRBM_OFFSET_SHIFT);
+        break;
+      case MMHUB_BASE:
+        gpuvm.readMMIO(pkt, aperture_offset >> MMHUB_OFFSET_SHIFT);
+        break;
+      default:
+        break;
+    }
 }

 void
@@ -199,14 +213,15 @@
 {
     DPRINTF(AMDGPUDevice, "Wrote framebuffer address %#lx\n", offset);

-    Addr aperture = getFrameAperture(offset);
+    Addr aperture = gpuvm.getFrameAperture(offset);
     Addr aperture_offset = offset - aperture;

     // Record the value
     frame_regs[aperture_offset] = pkt->getLE<uint32_t>();
-    if (aperture == gartBase) {
+    if (aperture == gpuvm.gartBase()) {
DPRINTF(AMDGPUDevice, "GART translation %p -> %p\n", aperture_offset,
             bits(frame_regs[aperture_offset], 48, 12));
+        gpuvm.gartTable[aperture_offset] = pkt->getLE<uint32_t>();
     }
 }

@@ -242,7 +257,7 @@
 void
 AMDGPUDevice::writeMMIO(PacketPtr pkt, Addr offset)
 {
-    Addr aperture = getMmioAperture(offset);
+    Addr aperture = gpuvm.getMmioAperture(offset);
     Addr aperture_offset = offset - aperture;

     DPRINTF(AMDGPUDevice, "Wrote MMIO %#lx\n", offset);
diff --git a/src/dev/amdgpu/amdgpu_device.hh b/src/dev/amdgpu/amdgpu_device.hh
index eddf406..e1e2f00 100644
--- a/src/dev/amdgpu/amdgpu_device.hh
+++ b/src/dev/amdgpu/amdgpu_device.hh
@@ -38,6 +38,7 @@

 #include "base/bitunion.hh"
 #include "dev/amdgpu/amdgpu_defines.hh"
+#include "dev/amdgpu/amdgpu_vm.hh"
 #include "dev/amdgpu/memory_manager.hh"
 #include "dev/amdgpu/mmio_reader.hh"
 #include "dev/io_device.hh"
@@ -112,6 +113,7 @@
     SDMAEngine *sdma0;
     SDMAEngine *sdma1;
     std::unordered_map<uint32_t, SDMAEngine *> sdmaEngs;
+    AMDGPUVM gpuvm;

     /**
      * Initial checkpoint support variables
@@ -119,58 +121,6 @@
     bool checkpoint_before_mmios;
     int init_interrupt_count;

-    typedef struct GEM5_PACKED
-    {
-        // Page table addresses: from (Base + Start) to (End)
-        union
-        {
-            struct
-            {
-                uint32_t ptBaseL;
-                uint32_t ptBaseH;
-            };
-            Addr ptBase;
-        };
-        union
-        {
-            struct
-            {
-                uint32_t ptStartL;
-                uint32_t ptStartH;
-            };
-            Addr ptStart;
-        };
-        union
-        {
-            struct
-            {
-                uint32_t ptEndL;
-                uint32_t ptEndH;
-            };
-            Addr ptEnd;
-        };
-    } VMContext; // VM Context
-
-    typedef struct SysVMContext : VMContext
-    {
-        Addr agpBase;
-        Addr agpTop;
-        Addr agpBot;
-        Addr fbBase;
-        Addr fbTop;
-        Addr fbOffset;
-        Addr sysAddrL;
-        Addr sysAddrH;
-    } SysVMContext; // System VM Context
-
-    SysVMContext vmContext0;
-    std::vector<VMContext> vmContexts;
-
-    // MMHUB aperture. These addresses are set by the GPU. For now we wait
-    // until the driver reads them before setting them.
-    uint64_t mmhubBase = 0x0;
-    uint64_t mmhubTop = 0x0;
-
// GART aperture. This is the initial 1-level privledged page table that
     // resides in framebuffer memory.
     uint32_t gartBase = 0x0;
@@ -198,125 +148,25 @@
     void serialize(CheckpointOut &cp) const override;
     void unserialize(CheckpointIn &cp) override;

+    /**
+     * Get handles to GPU blocks.
+     */
     AMDGPUInterruptHandler* getIH() { return deviceIH; }
     SDMAEngine* getSDMAEngine(Addr offset);
+    AMDGPUVM &getVM() { return gpuvm; }
+    AMDGPUMemoryManager* getMemMgr() { return gpuMemMgr; }
+    GPUCommandProcessor* CP() { return cp; }
+
+    /**
+     * Set handles to GPU blocks.
+     */
+    void setDoorbellType(uint32_t offset, QueueType qt);
+    void setSDMAEngine(Addr offset, SDMAEngine *eng);

     /**
      * Methods related to translations and system/device memory.
      */
     RequestorID vramRequestorId() { return gpuMemMgr->getRequestorID(); }
-
-    Addr
-    getPageTableBase(uint16_t vmid)
-    {
-        assert(vmid > 0 && vmid < vmContexts.size());
-        return vmContexts[vmid].ptBase;
-    }
-
-    Addr
-    getPageTableStart(uint16_t vmid)
-    {
-        assert(vmid > 0 && vmid < vmContexts.size());
-        return vmContexts[vmid].ptStart;
-    }
-
-    AMDGPUMemoryManager* getMemMgr() { return gpuMemMgr; }
-    GPURegMap& getGartTable() { return frame_regs; }
-
-    /**
-     * Methods for resolving apertures
-     */
-    bool
-    inAGP(Addr vaddr)
-    {
- return ((vaddr >= vmContext0.agpBot) && (vaddr <= vmContext0.agpTop));
-    }
-
-    Addr getAGPBot() { return vmContext0.agpBot; }
-    Addr getAGPTop() { return vmContext0.agpTop; }
-    Addr getAGPBase() { return vmContext0.agpBase; }
-
-    bool
-    inMMHUB(Addr vaddr)
-    {
-        return ((vaddr >= getMMHUBBase()) && (vaddr <= getMMHUBTop()));
-    }
-
-    Addr getMMHUBBase() { return mmhubBase; }
-    Addr getMMHUBTop() { return mmhubTop; }
-
-    bool
-    inFB(Addr vaddr)
-    {
- return ((vaddr >= vmContext0.fbBase) && (vaddr <= vmContext0.fbTop));
-    }
-
-    Addr getFBBase() { return vmContext0.fbBase; }
-    Addr getFBTop() { return vmContext0.fbTop; }
-    Addr getFBOffset() { return vmContext0.fbOffset; }
-
-    bool
-    inSys(Addr vaddr)
-    {
-        return ((vaddr >= vmContext0.sysAddrL) &&
-                (vaddr <= vmContext0.sysAddrH));
-    }
-
-    Addr getSysAddrRangeLow () { return vmContext0.sysAddrL; }
-    Addr getSysAddrRangeHigh () { return vmContext0.sysAddrH; }
-
-    Addr
-    getMmioAperture(Addr addr)
-    {
-        // Aperture ranges:
-        // NBIO               0x0     - 0x4280
-        // IH                 0x4280  - 0x4980
-        // SDMA0              0x4980  - 0x5180
-        // SDMA1              0x5180  - 0x5980
-        // GRBM               0x8000  - 0xD000
-        // GFX                0x28000 - 0x3F000
-        // MMHUB              0x68000 - 0x6a120
-
-        if (IH_BASE <= addr && addr < IH_BASE + IH_SIZE)
-            return IH_BASE;
-        else if (SDMA0_BASE <= addr && addr < SDMA0_BASE + SDMA_SIZE)
-            return SDMA0_BASE;
-        else if (SDMA1_BASE <= addr && addr < SDMA1_BASE + SDMA_SIZE)
-            return SDMA1_BASE;
-        else if (GRBM_BASE <= addr && addr < GRBM_BASE + GRBM_SIZE)
-            return GRBM_BASE;
-        else if (GFX_BASE <= addr && addr < GFX_BASE + GFX_SIZE)
-            return GFX_BASE;
-        else if (MMHUB_BASE <= addr && addr < MMHUB_BASE + MMHUB_SIZE)
-            return MMHUB_BASE;
-        else {
- warn_once("Accessing unsupported MMIO aperture! Assuming NBIO\n");
-            return NBIO_BASE;
-        }
-
-    }
-
-    // Gettig mapped aperture base addresses
-    Addr
-    getFrameAperture(Addr addr)
-    {
-        if (addr < gartBase) {
-            warn_once("Accessing unsupported frame apperture!\n");
-            return ~0;
-        } else if (gartBase <= addr && addr < (gartBase + gartSize)) {
-            return gartBase;
-        } else {
-            warn_once("Accessing unsupported frame apperture!\n");
-            return ~0;
-        }
-
-    }
-
-    /**
-     *
-     */
-    void setDoorbellType(uint32_t offset, QueueType qt);
-    void setSDMAEngine(Addr offset, SDMAEngine *eng);
 };

 } // namespace gem5
diff --git a/src/dev/amdgpu/amdgpu_vm.cc b/src/dev/amdgpu/amdgpu_vm.cc
new file mode 100644
index 0000000..b245aaf
--- /dev/null
+++ b/src/dev/amdgpu/amdgpu_vm.cc
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2021 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dev/amdgpu/amdgpu_vm.hh"
+
+#include "arch/amdgpu/vega/pagetable_walker.hh"
+#include "arch/generic/mmu.hh"
+#include "base/trace.hh"
+#include "debug/AMDGPUDevice.hh"
+#include "dev/amdgpu/amdgpu_defines.hh"
+#include "mem/packet_access.hh"
+
+namespace gem5
+{
+
+AMDGPUVM::AMDGPUVM()
+{
+    // Zero out contexts
+    memset(&vmContext0, 0, sizeof(AMDGPUSysVMContext));
+
+    vmContexts.resize(AMDGPU_VM_COUNT);
+    for (int i = 0; i < AMDGPU_VM_COUNT; ++i) {
+        memset(&vmContexts[0], 0, sizeof(AMDGPUVMContext));
+    }
+}
+
+Addr
+AMDGPUVM::gartBase()
+{
+    return vmContext0.ptBase;
+}
+
+Addr
+AMDGPUVM::gartSize()
+{
+    return vmContext0.ptEnd - vmContext0.ptStart;
+}
+
+void
+AMDGPUVM::readMMIO(PacketPtr pkt, Addr offset)
+{
+    uint32_t value = pkt->getLE<uint32_t>();
+
+    switch (offset) {
+      // MMHUB MMIOs
+      case mmMMHUB_VM_INVALIDATE_ENG17_SEM:
+        DPRINTF(AMDGPUDevice, "Marking invalidate ENG17 SEM acquired\n");
+        pkt->setLE<uint32_t>(1);
+        break;
+      case mmMMHUB_VM_INVALIDATE_ENG17_REQ:
+        // TODO mark which VMIDs were requested here.
+        break;
+      case mmMMHUB_VM_INVALIDATE_ENG17_ACK:
+ // TODO: This should actually do invalidations and track which VMID(s)
+        // were invalidated.
+ DPRINTF(AMDGPUDevice, "Telling driver invalidate ENG17 is complete\n");
+        pkt->setLE<uint32_t>(1);
+        break;
+      case mmMMHUB_VM_FB_LOCATION_BASE:
+        mmhubBase = ((Addr)bits(value, 23, 0) << 24);
+        DPRINTF(AMDGPUDevice, "MMHUB FB base set to %#x\n", mmhubBase);
+        break;
+      case mmMMHUB_VM_FB_LOCATION_TOP:
+        mmhubTop = ((Addr)bits(value, 23, 0) << 24) | 0xFFFFFFULL;
+        DPRINTF(AMDGPUDevice, "MMHUB FB top set to %#x\n", mmhubTop);
+        break;
+      // GRBM MMIOs
+      case mmVM_INVALIDATE_ENG17_ACK:
+        DPRINTF(AMDGPUDevice, "Overwritting invalidation ENG17 ACK\n");
+        pkt->setLE<uint32_t>(1);
+        break;
+      default:
+        DPRINTF(AMDGPUDevice, "GPUVM read of unknown MMIO %#x\n", offset);
+        break;
+    }
+}
+
+void
+AMDGPUVM::writeMMIO(PacketPtr pkt, Addr offset)
+{
+    switch (offset) {
+      // VMID0 MMIOs
+      case mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32:
+        vmContext0.ptBaseL = pkt->getLE<uint32_t>();
+        // Clear extra bits not part of address
+        vmContext0.ptBaseL = insertBits(vmContext0.ptBaseL, 0, 0, 0);
+        break;
+      case mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32:
+        vmContext0.ptBaseH = pkt->getLE<uint32_t>();
+        break;
+      case mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32:
+        vmContext0.ptStartL = pkt->getLE<uint32_t>();
+        break;
+      case mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32:
+        vmContext0.ptStartH = pkt->getLE<uint32_t>();
+        break;
+      case mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32:
+        vmContext0.ptEndL = pkt->getLE<uint32_t>();
+        break;
+      case mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32:
+        vmContext0.ptEndH = pkt->getLE<uint32_t>();
+        break;
+      case mmMC_VM_AGP_TOP: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.agpTop = (((Addr)bits(val, 23, 0)) << 24) | 0xffffff;
+        } break;
+      case mmMC_VM_AGP_BOT: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.agpBot = ((Addr)bits(val, 23, 0)) << 24;
+        } break;
+      case mmMC_VM_AGP_BASE: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.agpBase = ((Addr)bits(val, 23, 0)) << 24;
+        } break;
+      case mmMC_VM_FB_LOCATION_TOP: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.fbTop = (((Addr)bits(val, 23, 0)) << 24) | 0xffffff;
+        } break;
+      case mmMC_VM_FB_LOCATION_BASE: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.fbBase = ((Addr)bits(val, 23, 0)) << 24;
+        } break;
+      case mmMC_VM_FB_OFFSET: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.fbOffset = ((Addr)bits(val, 23, 0)) << 24;
+        } break;
+      case mmMC_VM_SYSTEM_APERTURE_LOW_ADDR: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.sysAddrL = ((Addr)bits(val, 29, 0)) << 18;
+        } break;
+      case mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR: {
+        uint32_t val = pkt->getLE<uint32_t>();
+        vmContext0.sysAddrH = ((Addr)bits(val, 29, 0)) << 18;
+        } break;
+      default:
+        break;
+    }
+}
+
+void
+AMDGPUVM::serialize(CheckpointOut &cp) const
+{
+    Addr vm0PTBase = vmContext0.ptBase;
+    Addr vm0PTStart = vmContext0.ptStart;
+    Addr vm0PTEnd = vmContext0.ptEnd;
+    SERIALIZE_SCALAR(vm0PTBase);
+    SERIALIZE_SCALAR(vm0PTStart);
+    SERIALIZE_SCALAR(vm0PTEnd);
+
+    SERIALIZE_SCALAR(vmContext0.agpBase);
+    SERIALIZE_SCALAR(vmContext0.agpTop);
+    SERIALIZE_SCALAR(vmContext0.agpBot);
+    SERIALIZE_SCALAR(vmContext0.fbBase);
+    SERIALIZE_SCALAR(vmContext0.fbTop);
+    SERIALIZE_SCALAR(vmContext0.fbOffset);
+    SERIALIZE_SCALAR(vmContext0.sysAddrL);
+    SERIALIZE_SCALAR(vmContext0.sysAddrH);
+
+    SERIALIZE_SCALAR(mmhubBase);
+    SERIALIZE_SCALAR(mmhubTop);
+
+    Addr ptBase[AMDGPU_VM_COUNT];
+    Addr ptStart[AMDGPU_VM_COUNT];
+    Addr ptEnd[AMDGPU_VM_COUNT];
+    for (int i = 0; i < AMDGPU_VM_COUNT; i++) {
+        ptBase[i] = vmContexts[i].ptBase;
+        ptStart[i] = vmContexts[i].ptStart;
+        ptEnd[i] = vmContexts[i].ptEnd;
+    }
+    SERIALIZE_ARRAY(ptBase, AMDGPU_VM_COUNT);
+    SERIALIZE_ARRAY(ptStart, AMDGPU_VM_COUNT);
+    SERIALIZE_ARRAY(ptEnd, AMDGPU_VM_COUNT);
+}
+
+void
+AMDGPUVM::unserialize(CheckpointIn &cp)
+{
+    // Unserialize requires fields not be packed
+    Addr vm0PTBase;
+    Addr vm0PTStart;
+    Addr vm0PTEnd;
+    UNSERIALIZE_SCALAR(vm0PTBase);
+    UNSERIALIZE_SCALAR(vm0PTStart);
+    UNSERIALIZE_SCALAR(vm0PTEnd);
+    vmContext0.ptBase = vm0PTBase;
+    vmContext0.ptStart = vm0PTStart;
+    vmContext0.ptEnd = vm0PTEnd;
+
+    UNSERIALIZE_SCALAR(vmContext0.agpBase);
+    UNSERIALIZE_SCALAR(vmContext0.agpTop);
+    UNSERIALIZE_SCALAR(vmContext0.agpBot);
+    UNSERIALIZE_SCALAR(vmContext0.fbBase);
+    UNSERIALIZE_SCALAR(vmContext0.fbTop);
+    UNSERIALIZE_SCALAR(vmContext0.fbOffset);
+    UNSERIALIZE_SCALAR(vmContext0.sysAddrL);
+    UNSERIALIZE_SCALAR(vmContext0.sysAddrH);
+
+    UNSERIALIZE_SCALAR(mmhubBase);
+    UNSERIALIZE_SCALAR(mmhubTop);
+
+    Addr ptBase[AMDGPU_VM_COUNT];
+    Addr ptStart[AMDGPU_VM_COUNT];
+    Addr ptEnd[AMDGPU_VM_COUNT];
+    UNSERIALIZE_ARRAY(ptBase, AMDGPU_VM_COUNT);
+    UNSERIALIZE_ARRAY(ptStart, AMDGPU_VM_COUNT);
+    UNSERIALIZE_ARRAY(ptEnd, AMDGPU_VM_COUNT);
+    for (int i = 0; i < AMDGPU_VM_COUNT; i++) {
+        vmContexts[i].ptBase = ptBase[i];
+        vmContexts[i].ptStart = ptStart[i];
+        vmContexts[i].ptEnd = ptEnd[i];
+    }
+}
+
+void
+AMDGPUVM::AGPTranslationGen::translate(Range &range) const
+{
+    assert(vm->inAGP(range.vaddr));
+
+    Addr next = roundUp(range.vaddr, AMDGPU_AGP_PAGE_SIZE);
+    if (next == range.vaddr)
+        next += AMDGPU_AGP_PAGE_SIZE;
+
+    range.size = std::min(range.size, next - range.vaddr);
+    range.paddr = range.vaddr - vm->getAGPBot() + vm->getAGPBase();
+
+    printf("AMDGPUVM: AGP translation %#lx -> %#lx\n",
+            range.vaddr, range.paddr);
+}
+
+void
+AMDGPUVM::GARTTranslationGen::translate(Range &range) const
+{
+    Addr next = roundUp(range.vaddr, AMDGPU_GART_PAGE_SIZE);
+    if (next == range.vaddr)
+        next += AMDGPU_GART_PAGE_SIZE; // TODO: This seems wrong
+    range.size = std::min(range.size, next - range.vaddr);
+
+    Addr gart_addr = bits(range.vaddr, 63, 12);
+
+ // This table is a bit hard to iterate over. If we cross a page, the next
+    // PTE is not necessarily the next entry but actually 7 entries away.
+    Addr lsb = bits(gart_addr, 2, 0);
+    gart_addr += lsb * 7;
+
+ // GART is a single level translation, so the value at the "virtual" addr
+    // is the PTE containing the physical address.
+    auto result = vm->gartTable.find(gart_addr);
+    if (result == vm->gartTable.end()) {
+ // There is no reason to fault as there is no recovery mechanism for
+        // invalid GART entries. Simply panic in this case
+        warn("GART translation for %p not found", range.vaddr);
+
+ // Some PM4 packets have register addresses which we ignore. In that
+        // case just return the vaddr rather than faulting.
+        range.paddr = range.vaddr;
+    } else {
+        Addr pte = result->second;
+        Addr lower_bits = bits(range.vaddr, 11, 0);
+        range.paddr = (bits(pte, 47, 12) << 12) | lower_bits;
+    }
+
+    printf("AMDGPUVM: GART translation %#lx -> %#lx\n",
+            range.vaddr, range.paddr);
+}
+
+void
+AMDGPUVM::MMHUBTranslationGen::translate(Range &range) const
+{
+    assert(vm->inMMHUB(range.vaddr));
+
+    Addr next = roundUp(range.vaddr, AMDGPU_MMHUB_PAGE_SIZE);
+    if (next == range.vaddr)
+        next += AMDGPU_MMHUB_PAGE_SIZE;
+
+    range.size = std::min(range.size, next - range.vaddr);
+    range.paddr = range.vaddr - vm->getMMHUBBase();
+
+    printf("AMDGPUVM: MMHUB translation %#lx -> %#lx\n",
+            range.vaddr, range.paddr);
+}
+
+void
+AMDGPUVM::UserTranslationGen::translate(Range &range) const
+{
+    // Get base address of the page table for this vmid
+    Addr base = vm->getPageTableBase(vmid);
+    Addr start = vm->getPageTableStart(vmid);
+ printf("User tl base %#lx start %#lx walker %p\n", base, start, walker);
+
+    bool dummy;
+    unsigned logBytes;
+    Addr paddr;
+    Fault fault = walker->startFunctional(base, paddr, logBytes,
+                                          BaseMMU::Mode::Read, dummy);
+    if (fault != NoFault) {
+        fatal("User translation fault");
+    }
+
+    // GPU page size is variable. Use logBytes to determine size.
+    const Addr page_size = 1 << logBytes;
+    Addr next = roundUp(range.vaddr, page_size);
+    if (next == range.vaddr)
+        // We don't know the size of the next page, use default.
+        next += AMDGPU_USER_PAGE_SIZE;
+
+    range.size = std::min(range.size, next - range.vaddr);
+    range.paddr = insertBits(paddr, logBytes - 1, 0, range.vaddr);
+}
+
+} // namespace gem5
diff --git a/src/dev/amdgpu/amdgpu_vm.hh b/src/dev/amdgpu/amdgpu_vm.hh
new file mode 100644
index 0000000..b57b9ec
--- /dev/null
+++ b/src/dev/amdgpu/amdgpu_vm.hh
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2021 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEV_AMDGPU_AMDGPU_VM_HH__
+#define __DEV_AMDGPU_AMDGPU_VM_HH__
+
+#include <vector>
+
+#include "arch/amdgpu/vega/pagetable_walker.hh"
+#include "base/intmath.hh"
+#include "dev/amdgpu/amdgpu_defines.hh"
+#include "mem/packet.hh"
+#include "mem/translation_gen.hh"
+#include "sim/serialize.hh"
+
+/**
+ * MMIO offsets for graphics register bus manager (GRBM). These values were
+ * taken from linux header files. The header files can be found here:
+ *
+ * https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/
+ *      asic_reg/gc/gc_9_0_offset.h
+ * https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/
+ *      asic_reg/mmhub/mmhub_1_0_offset.h
+ */
+
+#define mmVM_INVALIDATE_ENG17_ACK 0x08c6 +#define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 0x08eb +#define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 0x08ec +#define mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32 0x090b +#define mmVM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32 0x090c +#define mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32 0x092b +#define mmVM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32 0x092c
+
+#define mmMC_VM_FB_OFFSET 0x096b +#define mmMC_VM_FB_LOCATION_BASE 0x0980 +#define mmMC_VM_FB_LOCATION_TOP 0x0981 +#define mmMC_VM_AGP_TOP 0x0982 +#define mmMC_VM_AGP_BOT 0x0983 +#define mmMC_VM_AGP_BASE 0x0984 +#define mmMC_VM_SYSTEM_APERTURE_LOW_ADDR 0x0985 +#define mmMC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x0986
+
+#define mmMMHUB_VM_INVALIDATE_ENG17_SEM 0x06e2 +#define mmMMHUB_VM_INVALIDATE_ENG17_REQ 0x06f4 +#define mmMMHUB_VM_INVALIDATE_ENG17_ACK 0x0706 +#define mmMMHUB_VM_FB_LOCATION_BASE 0x082c +#define mmMMHUB_VM_FB_LOCATION_TOP 0x082d
+
+// AMD GPUs support 16 different virtual address spaces
+static constexpr int AMDGPU_VM_COUNT = 16;
+
+// These apertures have a fixed page size
+static constexpr int AMDGPU_AGP_PAGE_SIZE = 4096;
+static constexpr int AMDGPU_GART_PAGE_SIZE = 4096;
+static constexpr int AMDGPU_MMHUB_PAGE_SIZE = 4096;
+
+// Vega page size can be any power of 2 between 4kB and 1GB.
+static constexpr int AMDGPU_USER_PAGE_SIZE = 4096;
+
+namespace gem5
+{
+
+class AMDGPUVM : public Serializable
+{
+  private:
+    typedef struct GEM5_PACKED
+    {
+        // Page table addresses: from (Base + Start) to (End)
+        union
+        {
+            struct
+            {
+                uint32_t ptBaseL;
+                uint32_t ptBaseH;
+            };
+            Addr ptBase;
+        };
+        union
+        {
+            struct
+            {
+                uint32_t ptStartL;
+                uint32_t ptStartH;
+            };
+            Addr ptStart;
+        };
+        union
+        {
+            struct
+            {
+                uint32_t ptEndL;
+                uint32_t ptEndH;
+            };
+            Addr ptEnd;
+        };
+    } AMDGPUVMContext;
+
+    typedef struct AMDGPUSysVMContext : AMDGPUVMContext
+    {
+        Addr agpBase;
+        Addr agpTop;
+        Addr agpBot;
+        Addr fbBase;
+        Addr fbTop;
+        Addr fbOffset;
+        Addr sysAddrL;
+        Addr sysAddrH;
+    } AMDGPUSysVMContext;
+
+    AMDGPUSysVMContext vmContext0;
+    std::vector<AMDGPUVMContext> vmContexts;
+
+    // MMHUB aperture. These addresses mirror the framebuffer, so addresses
+    // can be calculated by subtracting the base address.
+    uint64_t mmhubBase = 0x0;
+    uint64_t mmhubTop = 0x0;
+
+  public:
+    AMDGPUVM();
+
+    /**
+     * Return base address of GART table in framebuffer.
+     */
+    Addr gartBase();
+    /**
+     * Return size of GART in number of PTEs.
+     */
+    Addr gartSize();
+
+    /**
+ * Copy of GART table. Typically resides in device memory, however we use
+     * a copy in gem5 to simplify the interface.
+     */
+    std::unordered_map<uint64_t, uint32_t> gartTable;
+
+    void readMMIO(PacketPtr pkt, Addr offset);
+    void writeMMIO(PacketPtr pkt, Addr offset);
+
+    /**
+     * Methods for resolving apertures
+     */
+    bool
+    inAGP(Addr vaddr)
+    {
+ return ((vaddr >= vmContext0.agpBot) && (vaddr <= vmContext0.agpTop));
+    }
+
+    Addr getAGPBot() { return vmContext0.agpBot; }
+    Addr getAGPTop() { return vmContext0.agpTop; }
+    Addr getAGPBase() { return vmContext0.agpBase; }
+
+    bool
+    inMMHUB(Addr vaddr)
+    {
+        return ((vaddr >= getMMHUBBase()) && (vaddr <= getMMHUBTop()));
+    }
+
+    Addr getMMHUBBase() { return mmhubBase; }
+    Addr getMMHUBTop() { return mmhubTop; }
+
+    bool
+    inFB(Addr vaddr)
+    {
+ return ((vaddr >= vmContext0.fbBase) && (vaddr <= vmContext0.fbTop));
+    }
+
+    Addr getFBBase() { return vmContext0.fbBase; }
+    Addr getFBTop() { return vmContext0.fbTop; }
+    Addr getFBOffset() { return vmContext0.fbOffset; }
+
+    bool
+    inSys(Addr vaddr)
+    {
+        return ((vaddr >= vmContext0.sysAddrL) &&
+                (vaddr <= vmContext0.sysAddrH));
+    }
+
+    Addr getSysAddrRangeLow () { return vmContext0.sysAddrL; }
+    Addr getSysAddrRangeHigh () { return vmContext0.sysAddrH; }
+
+    Addr
+    getMmioAperture(Addr addr)
+    {
+        // Aperture ranges:
+        // NBIO               0x0     - 0x4280
+        // IH                 0x4280  - 0x4980
+        // SDMA0              0x4980  - 0x5180
+        // SDMA1              0x5180  - 0x5980
+        // GRBM               0x8000  - 0xD000
+        // GFX                0x28000 - 0x3F000
+        // MMHUB              0x68000 - 0x6a120
+
+        if (IH_BASE <= addr && addr < IH_BASE + IH_SIZE)
+            return IH_BASE;
+        else if (SDMA0_BASE <= addr && addr < SDMA0_BASE + SDMA_SIZE)
+            return SDMA0_BASE;
+        else if (SDMA1_BASE <= addr && addr < SDMA1_BASE + SDMA_SIZE)
+            return SDMA1_BASE;
+        else if (GRBM_BASE <= addr && addr < GRBM_BASE + GRBM_SIZE)
+            return GRBM_BASE;
+        else if (GFX_BASE <= addr && addr < GFX_BASE + GFX_SIZE)
+            return GFX_BASE;
+        else if (MMHUB_BASE <= addr && addr < MMHUB_BASE + MMHUB_SIZE)
+            return MMHUB_BASE;
+        else {
+ warn_once("Accessing unsupported MMIO aperture! Assuming NBIO\n");
+            return NBIO_BASE;
+        }
+
+    }
+
+    // Gettig mapped aperture base addresses
+    Addr
+    getFrameAperture(Addr addr)
+    {
+        if (addr < gartBase()) {
+            warn_once("Accessing unsupported frame apperture!\n");
+            return ~0;
+ } else if (gartBase() <= addr && addr < (gartBase() + gartSize())) {
+            return gartBase();
+        } else {
+            warn_once("Accessing unsupported frame apperture!\n");
+            return ~0;
+        }
+
+    }
+
+    /**
+     * Page table base/start accessors for user VMIDs.
+     */
+    Addr
+    getPageTableBase(uint16_t vmid)
+    {
+        assert(vmid > 0 && vmid < vmContexts.size());
+        return vmContexts[vmid].ptBase;
+    }
+
+    Addr
+    getPageTableStart(uint16_t vmid)
+    {
+        assert(vmid > 0 && vmid < vmContexts.size());
+        return vmContexts[vmid].ptStart;
+    }
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+    /**
+     * Translation range generators
+     *
+     * AGP - Legacy interface to device memory. Addr range is set via MMIO
+     * GART - Legacy privledged translation table. Table in device memory
+     * MMHUB - Shadow range of VRAM
+     */
+    class AGPTranslationGen : public TranslationGen
+    {
+      private:
+        AMDGPUVM *vm;
+
+        void translate(Range &range) const override;
+
+      public:
+        AGPTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size)
+            : TranslationGen(vaddr, size), vm(_vm)
+        {}
+    };
+
+    class GARTTranslationGen : public TranslationGen
+    {
+      private:
+        AMDGPUVM *vm;
+
+        void translate(Range &range) const override;
+
+      public:
+        GARTTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size)
+            : TranslationGen(vaddr, size), vm(_vm)
+        {}
+    };
+
+    class MMHUBTranslationGen : public TranslationGen
+    {
+      private:
+        AMDGPUVM *vm;
+
+        void translate(Range &range) const override;
+
+      public:
+        MMHUBTranslationGen(AMDGPUVM *_vm, Addr vaddr, Addr size)
+            : TranslationGen(vaddr, size), vm(_vm)
+        {}
+    };
+
+    class UserTranslationGen : public TranslationGen
+    {
+      private:
+        AMDGPUVM *vm;
+        VegaISA::Walker *walker;
+        int vmid;
+
+        void translate(Range &range) const override;
+
+      public:
+ UserTranslationGen(AMDGPUVM *_vm, VegaISA::Walker *_walker, int _vmid,
+                           Addr vaddr, Addr size)
+            : TranslationGen(vaddr, size), vm(_vm), walker(_walker),
+              vmid(_vmid)
+        {}
+    };
+};
+
+} // namespace gem5
+
+#endif // __DEV_AMDGPU_AMDGPU_VM_HH__
diff --git a/src/dev/amdgpu/sdma_engine.cc b/src/dev/amdgpu/sdma_engine.cc
index 92172d6..806689c 100644
--- a/src/dev/amdgpu/sdma_engine.cc
+++ b/src/dev/amdgpu/sdma_engine.cc
@@ -92,7 +92,7 @@
 Addr
 SDMAEngine::getGARTAddr(Addr addr) const
 {
-    if (!gpuDevice->inAGP(addr)) {
+    if (!gpuDevice->getVM().inAGP(addr)) {
         Addr low_bits = bits(addr, 11, 0);
         addr = (((addr >> 12) << 3) << 12) | low_bits;
     }
@@ -497,8 +497,8 @@
     }

     // lastly we write read data to the destination address
-    if (gpuDevice->inMMHUB(pkt->dest)) {
-        Addr mmhubAddr = pkt->dest - gpuDevice->getMMHUBBase();
+    if (gpuDevice->getVM().inMMHUB(pkt->dest)) {
+        Addr mmhubAddr = pkt->dest - gpuDevice->getVM().getMMHUBBase();
gpuDevice->getMemMgr()->writeRequest(mmhubAddr, (uint8_t *)dmaBuffer,
                                            bufferSize);

@@ -565,14 +565,13 @@
     DPRINTF(SDMAEngine, "Tmp addr %#lx -> %#lx\n", pkt->dest, tmp_addr);

     // Writing generated data to the destination address.
-    if ((gpuDevice->inMMHUB(pkt->dest) && cur_vmid == 0) ||
-        (gpuDevice->inMMHUB(tmp_addr) && cur_vmid != 0)) {
-        //Addr mmhubAddr = pkt->dest - gpuDevice->getMMHUBBase();
+    if ((gpuDevice->getVM().inMMHUB(pkt->dest) && cur_vmid == 0) ||
+        (gpuDevice->getVM().inMMHUB(tmp_addr) && cur_vmid != 0)) {
         Addr mmhubAddr = 0;
         if (cur_vmid == 0) {
-            mmhubAddr = pkt->dest - gpuDevice->getMMHUBBase();
+            mmhubAddr = pkt->dest - gpuDevice->getVM().getMMHUBBase();
         } else {
-            mmhubAddr = tmp_addr - gpuDevice->getMMHUBBase();
+            mmhubAddr = tmp_addr - gpuDevice->getVM().getMMHUBBase();
         }
         DPRINTF(SDMAEngine, "Copying to MMHUB address %#lx\n", mmhubAddr);
gpuDevice->getMemMgr()->writeRequest(mmhubAddr, dmaBuffer, pkt->count);
@@ -799,8 +798,8 @@
     }

     // Writing generated data to the destination address.
-    if (gpuDevice->inMMHUB(pkt->dest)) {
-        Addr mmhubAddr = pkt->dest - gpuDevice->getMMHUBBase();
+    if (gpuDevice->getVM().inMMHUB(pkt->dest)) {
+        Addr mmhubAddr = pkt->dest - gpuDevice->getVM().getMMHUBBase();
gpuDevice->getMemMgr()->writeRequest(mmhubAddr, (uint8_t *)dmaBuffer,
                                            sizeof(uint64_t) * pkt->count);


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/53066
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Ic224c1aa485685685b1136a46eed50bcf99d2350
Gerrit-Change-Number: 53066
Gerrit-PatchSet: 1
Gerrit-Owner: Alex Dutu <alexandru.d...@amd.com>
Gerrit-CC: Matthew Poremba <matthew.pore...@amd.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to