Matthew Poremba has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/51849 )

Change subject: dev-amdgpu: Add GPU interrupt handler object
......................................................................

dev-amdgpu: Add GPU interrupt handler object

Add device interrupt handler for amdgpu device. The interrupt handler is
primarily used to signal that fences in the kernel driver can be passed.

Change-Id: I574fbfdef6e3bae310ec7f86058811e1e4886df6
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/51849
Maintainer: Matthew Poremba <matthew.pore...@amd.com>
Reviewed-by: Matt Sinclair <mattdsincl...@gmail.com>
Maintainer: Matt Sinclair <mattdsincl...@gmail.com>
Tested-by: kokoro <noreply+kok...@google.com>
---
M src/dev/amdgpu/AMDGPU.py
M src/dev/amdgpu/SConscript
M src/dev/amdgpu/amdgpu_device.cc
M src/dev/amdgpu/amdgpu_device.hh
A src/dev/amdgpu/ih_mmio.hh
A src/dev/amdgpu/interrupt_handler.cc
A src/dev/amdgpu/interrupt_handler.hh
7 files changed, 639 insertions(+), 4 deletions(-)

Approvals:
  Matt Sinclair: Looks good to me, approved; Looks good to me, approved
  Matthew Poremba: Looks good to me, approved
  kokoro: Regressions pass




diff --git a/src/dev/amdgpu/AMDGPU.py b/src/dev/amdgpu/AMDGPU.py
index 9ca9b3b..471a67c 100644
--- a/src/dev/amdgpu/AMDGPU.py
+++ b/src/dev/amdgpu/AMDGPU.py
@@ -28,8 +28,10 @@
 # POSSIBILITY OF SUCH DAMAGE.

 from m5.params import *
+from m5.proxy import *
 from m5.objects.PciDevice import PciDevice
 from m5.objects.PciDevice import PciMemBar, PciMemUpperBar, PciLegacyIoBar
+from m5.objects.Device import DmaDevice

 # PCI device model for an AMD Vega 10 based GPU. The PCI codes and BARs
 # correspond to a Vega Frontier Edition hardware device. None of the PCI
@@ -71,3 +73,14 @@
     trace_file = Param.String("MMIO trace collected on hardware")
checkpoint_before_mmios = Param.Bool(False, "Take a checkpoint before the" " device begins sending MMIOs")
+
+ # The cp is needed here to handle certain packets the device may receive. + # The config script should not create a new cp here but rather assign the
+    # same cp that is assigned to the Shader SimObject.
+    cp = Param.GPUCommandProcessor(NULL, "Command Processor")
+    device_ih = Param.AMDGPUInterruptHandler("GPU Interrupt handler")
+
+class AMDGPUInterruptHandler(DmaDevice):
+    type = 'AMDGPUInterruptHandler'
+    cxx_header = "dev/amdgpu/interrupt_handler.hh"
+    cxx_class = 'gem5::AMDGPUInterruptHandler'
diff --git a/src/dev/amdgpu/SConscript b/src/dev/amdgpu/SConscript
index 87a560e..f149812 100644
--- a/src/dev/amdgpu/SConscript
+++ b/src/dev/amdgpu/SConscript
@@ -33,9 +33,11 @@
     Return()

 # Controllers
-SimObject('AMDGPU.py', sim_objects=['AMDGPUDevice'], tags='x86 isa')
+SimObject('AMDGPU.py', sim_objects=['AMDGPUDevice', 'AMDGPUInterruptHandler']
+                     , tags='x86 isa')

 Source('amdgpu_device.cc', tags='x86 isa')
+Source('interrupt_handler.cc', tags='x86 isa')
 Source('mmio_reader.cc', tags='x86 isa')

 DebugFlag('AMDGPUDevice', tags='x86 isa')
diff --git a/src/dev/amdgpu/amdgpu_device.cc b/src/dev/amdgpu/amdgpu_device.cc
index a4edef4..fb140d4 100644
--- a/src/dev/amdgpu/amdgpu_device.cc
+++ b/src/dev/amdgpu/amdgpu_device.cc
@@ -34,6 +34,7 @@
 #include <fstream>

 #include "debug/AMDGPUDevice.hh"
+#include "dev/amdgpu/interrupt_handler.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
 #include "params/AMDGPUDevice.hh"
@@ -196,8 +197,19 @@
 void
 AMDGPUDevice::writeMMIO(PacketPtr pkt, Addr offset)
 {
+    Addr aperture = getMmioAperture(offset);
+    Addr aperture_offset = offset - aperture;
+
     DPRINTF(AMDGPUDevice, "Wrote MMIO %#lx\n", offset);
-    mmioReader.writeFromTrace(pkt, MMIO_BAR, offset);
+
+    switch (aperture) {
+      case IH_BASE:
+        deviceIH->writeMMIO(pkt, aperture_offset >> IH_OFFSET_SHIFT);
+        break;
+      default:
+        DPRINTF(AMDGPUDevice, "Unknown MMIO aperture for %#x\n", offset);
+        break;
+    }
 }

 Tick
@@ -263,6 +275,19 @@
 }

 void
+AMDGPUDevice::setDoorbellType(uint32_t offset, QueueType qt)
+{
+    DPRINTF(AMDGPUDevice, "Setting doorbell type for %x\n", offset);
+    doorbells[offset] = qt;
+}
+
+void
+AMDGPUDevice::intrPost()
+{
+    PciDevice::intrPost();
+}
+
+void
 AMDGPUDevice::serialize(CheckpointOut &cp) const
 {
     // Serialize the PciDevice base class
diff --git a/src/dev/amdgpu/amdgpu_device.hh b/src/dev/amdgpu/amdgpu_device.hh
index b0ea86a..fb72172 100644
--- a/src/dev/amdgpu/amdgpu_device.hh
+++ b/src/dev/amdgpu/amdgpu_device.hh
@@ -44,6 +44,8 @@
 namespace gem5
 {

+class AMDGPUInterruptHandler;
+
 /**
* Device model for an AMD GPU. This models the interface between the PCI bus * and the various IP blocks behind it. It translates requests to the various
@@ -77,6 +79,14 @@
     void writeMMIO(PacketPtr pkt, Addr offset);

     /**
+     * Structures to hold registers, doorbells, and some frame memory
+     */
+    using GPURegMap = std::unordered_map<uint32_t, uint64_t>;
+    GPURegMap frame_regs;
+    GPURegMap regs;
+    std::unordered_map<uint32_t, QueueType> doorbells;
+
+    /**
      * VGA ROM methods
      */
     AddrRange romRange;
@@ -91,10 +101,13 @@
     AMDMMIOReader mmioReader;

     /**
-     * Device registers - Maps register address to register value
+     * Blocks of the GPU
      */
-    std::unordered_map<uint32_t, uint64_t> regs;
+    AMDGPUInterruptHandler *deviceIH;

+    /**
+     * Initial checkpoint support variables.
+     */
     bool checkpoint_before_mmios;
     int init_interrupt_count;

@@ -185,6 +198,41 @@
         assert(vmid > 0 && vmid < vmContexts.size());
         return vmContexts[vmid].ptStart;
     }
+
+    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;
+        }
+    }
+
+    /**
+     * Setters to set values from other GPU blocks.
+     */
+    void setDoorbellType(uint32_t offset, QueueType qt);
 };

 } // namespace gem5
diff --git a/src/dev/amdgpu/ih_mmio.hh b/src/dev/amdgpu/ih_mmio.hh
new file mode 100644
index 0000000..c7e94fd
--- /dev/null
+++ b/src/dev/amdgpu/ih_mmio.hh
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * 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_IH_MMIO_HH__
+#define __DEV_AMDGPU_IH_MMIO_HH__
+
+/**
+ * MMIO offsets for interrupt handler. These values were taken from the linux
+ * header for IH. The header files can be found here:
+ *
+ * https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/rocm-4.3.x/
+ *      drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_0_offset.h
+ */
+#define mmIH_RB_CNTL                                            0x0080
+#define mmIH_RB_BASE                                            0x0081
+#define mmIH_RB_BASE_HI                                         0x0082
+#define mmIH_RB_RPTR                                            0x0083
+#define mmIH_RB_WPTR                                            0x0084
+#define mmIH_RB_WPTR_ADDR_HI                                    0x0085
+#define mmIH_RB_WPTR_ADDR_LO                                    0x0086
+#define mmIH_DOORBELL_RPTR                                      0x0087
+
+#endif // __DEV_AMDGPU_IH_MMIO_HH__
diff --git a/src/dev/amdgpu/interrupt_handler.cc b/src/dev/amdgpu/interrupt_handler.cc
new file mode 100644
index 0000000..ea0931f
--- /dev/null
+++ b/src/dev/amdgpu/interrupt_handler.cc
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2021 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * 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/interrupt_handler.hh"
+
+#include "debug/AMDGPUDevice.hh"
+#include "dev/amdgpu/ih_mmio.hh"
+#include "mem/packet_access.hh"
+
+// For generating interrupts, the object causing interrupt communicates with +// the Interrupt Handler (IH), which submits a 256-bit Interrupt packet to the
+// system memory. The location where the IH submits the packet is the
+// IH Ring buffer in the system memory. The IH updates the Write Pointer
+// and the host consumes the ring buffer and once done, updates the Read
+// Pointer through the doorbell.
+
+// IH_RB_BaseAddr, IH_RB_WptrAddr (Lo/Hi), IH_RB_RptrAddr (Lo/Hi), etc. are
+// not GART addresses but system dma addresses and thus don't require
+// translations through the GART table.
+
+namespace gem5
+{
+
+AMDGPUInterruptHandler::AMDGPUInterruptHandler(
+ const AMDGPUInterruptHandlerParams &p)
+    : DmaDevice(p)
+{
+    memset(&regs, 0, sizeof(AMDGPUIHRegs));
+}
+
+AddrRangeList
+AMDGPUInterruptHandler::getAddrRanges() const
+{
+    AddrRangeList ranges;
+    return ranges;
+}
+
+void
+AMDGPUInterruptHandler::intrPost()
+{
+    if (gpuDevice)
+        gpuDevice->intrPost();
+}
+
+void
+AMDGPUInterruptHandler::prepareInterruptCookie(ContextID cntxt_id,
+                                                uint32_t ring_id,
+                                                uint32_t client_id,
+                                                uint32_t source_id)
+{
+    /**
+     * Setup the fields in the interrupt cookie (see header file for more
+     * detail on the fields). The timestamp here is a bogus value. It seems
+     * the driver does not really care what this value is. Additionally the
+     * model does not currently have anything to keep track of time. It is
+ * possible that tick/cycle count can be used in the future if this ends
+     * up being important. The remaining fields are passed from whichever
+     * block is sending the interrupt.
+     */
+    AMDGPUInterruptCookie *cookie = new AMDGPUInterruptCookie();
+    memset(cookie, 0, sizeof(AMDGPUInterruptCookie));
+    cookie->timestamp_Lo = 0x40;
+    cookie->clientId = client_id;
+    cookie->sourceId = source_id;
+    cookie->ringId = ring_id;
+    cookie->source_data_dw1 = cntxt_id;
+    interruptQueue.push(cookie);
+}
+
+void
+AMDGPUInterruptHandler::DmaEvent::process()
+{
+    if (data == 1) {
+        DPRINTF(AMDGPUDevice, "Completed interrupt cookie write\n");
+        deviceIh->submitWritePointer();
+    } else if (data == 2) {
+ DPRINTF(AMDGPUDevice, "Completed interrupt write pointer update\n");
+        deviceIh->intrPost();
+    } else {
+ fatal("Interrupt Handler DMA event returned bad value: %d\n", data);
+    }
+}
+
+void
+AMDGPUInterruptHandler::submitWritePointer()
+{
+    uint8_t *dataPtr = new uint8_t[sizeof(uint32_t)];
+    regs.IH_Wptr += INTR_COOKIE_SIZE;
+    Addr paddr = regs.WptrAddr;
+    std::memcpy(dataPtr, &regs.IH_Wptr, sizeof(uint32_t));
+
+    dmaEvent = new AMDGPUInterruptHandler::DmaEvent(this, 2);
+    dmaWrite(paddr, sizeof(uint32_t), dmaEvent, dataPtr);
+}
+
+void
+AMDGPUInterruptHandler::submitInterruptCookie()
+{
+    assert(!interruptQueue.empty());
+    auto cookie = interruptQueue.front();
+    size_t cookieSize = INTR_COOKIE_SIZE * sizeof(uint32_t);
+
+    uint8_t *dataPtr = new uint8_t[cookieSize];
+    std::memcpy(dataPtr, cookie, cookieSize);
+    Addr paddr = regs.baseAddr + regs.IH_Wptr;
+
+    DPRINTF(AMDGPUDevice, "InterruptHandler rptr: 0x%x wptr: 0x%x\n",
+                          regs.IH_Rptr, regs.IH_Wptr);
+    dmaEvent = new AMDGPUInterruptHandler::DmaEvent(this, 1);
+    dmaWrite(paddr, cookieSize, dmaEvent, dataPtr);
+
+    interruptQueue.pop();
+}
+
+void
+AMDGPUInterruptHandler::writeMMIO(PacketPtr pkt, Addr mmio_offset)
+{
+    switch (mmio_offset) {
+      case mmIH_RB_CNTL:
+        setCntl(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_BASE:
+        setBase(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_BASE_HI:
+        setBaseHi(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_RPTR:
+        setRptr(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_WPTR:
+        setWptr(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_WPTR_ADDR_LO:
+        setWptrAddrLo(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_RB_WPTR_ADDR_HI:
+        setWptrAddrHi(pkt->getLE<uint32_t>());
+        break;
+      case mmIH_DOORBELL_RPTR:
+        setDoorbellOffset(pkt->getLE<uint32_t>());
+        if (bits(pkt->getLE<uint32_t>(), 28, 28)) {
+            gpuDevice->setDoorbellType(getDoorbellOffset() << 2,
+                                       InterruptHandler);
+        }
+        break;
+      default:
+        DPRINTF(AMDGPUDevice, "IH Unknown MMIO %#x\n", mmio_offset);
+        break;
+    }
+}
+
+void
+AMDGPUInterruptHandler::setCntl(const uint32_t &data)
+{
+    regs.IH_Cntl = data;
+}
+
+void
+AMDGPUInterruptHandler::setBase(const uint32_t &data)
+{
+    regs.IH_Base = data << 8;
+    regs.baseAddr |= regs.IH_Base;
+}
+
+void
+AMDGPUInterruptHandler::setBaseHi(const uint32_t &data)
+{
+    regs.IH_Base_Hi = data;
+    regs.baseAddr |= ((uint64_t)regs.IH_Base_Hi) << 32;
+}
+
+void
+AMDGPUInterruptHandler::setRptr(const uint32_t &data)
+{
+    regs.IH_Rptr = data;
+}
+
+void
+AMDGPUInterruptHandler::setWptr(const uint32_t &data)
+{
+    regs.IH_Wptr = data;
+}
+
+void
+AMDGPUInterruptHandler::setWptrAddrLo(const uint32_t &data)
+{
+    regs.IH_Wptr_Addr_Lo = data;
+    regs.WptrAddr |= regs.IH_Wptr_Addr_Lo;
+}
+
+void
+AMDGPUInterruptHandler::setWptrAddrHi(const uint32_t &data)
+{
+    regs.IH_Wptr_Addr_Hi = data;
+    regs.WptrAddr |= ((uint64_t)regs.IH_Wptr_Addr_Hi) << 32;
+}
+
+void
+AMDGPUInterruptHandler::setDoorbellOffset(const uint32_t &data)
+{
+    regs.IH_Doorbell = data & 0x3ffffff;
+}
+
+void
+AMDGPUInterruptHandler::updateRptr(const uint32_t &data)
+{
+    regs.IH_Rptr = data; // update ring buffer rptr offset
+}
+
+void
+AMDGPUInterruptHandler::serialize(CheckpointOut &cp) const
+{
+    uint32_t ih_cntl = regs.IH_Cntl;
+    uint32_t ih_base = regs.IH_Base;
+    uint32_t ih_base_hi = regs.IH_Base_Hi;
+    Addr ih_baseAddr = regs.baseAddr;
+    uint32_t ih_rptr = regs.IH_Rptr;
+    uint32_t ih_wptr = regs.IH_Wptr;
+    uint32_t ih_wptr_addr_lo = regs.IH_Wptr_Addr_Lo;
+    uint32_t ih_wptr_addr_hi = regs.IH_Wptr_Addr_Hi;
+    Addr ih_wptrAddr = regs.WptrAddr;
+    uint32_t ih_doorbellOffset = regs.IH_Doorbell;
+
+    SERIALIZE_SCALAR(ih_cntl);
+    SERIALIZE_SCALAR(ih_base);
+    SERIALIZE_SCALAR(ih_base_hi);
+    SERIALIZE_SCALAR(ih_baseAddr);
+    SERIALIZE_SCALAR(ih_rptr);
+    SERIALIZE_SCALAR(ih_wptr);
+    SERIALIZE_SCALAR(ih_wptr_addr_lo);
+    SERIALIZE_SCALAR(ih_wptr_addr_hi);
+    SERIALIZE_SCALAR(ih_wptrAddr);
+    SERIALIZE_SCALAR(ih_doorbellOffset);
+}
+
+void
+AMDGPUInterruptHandler::unserialize(CheckpointIn &cp)
+{
+    uint32_t ih_cntl;
+    uint32_t ih_base;
+    uint32_t ih_base_hi;
+    Addr ih_baseAddr;
+    uint32_t ih_rptr;
+    uint32_t ih_wptr;
+    uint32_t ih_wptr_addr_lo;
+    uint32_t ih_wptr_addr_hi;
+    Addr ih_wptrAddr;
+    uint32_t ih_doorbellOffset;
+
+    UNSERIALIZE_SCALAR(ih_cntl);
+    UNSERIALIZE_SCALAR(ih_base);
+    UNSERIALIZE_SCALAR(ih_base_hi);
+    UNSERIALIZE_SCALAR(ih_baseAddr);
+    UNSERIALIZE_SCALAR(ih_rptr);
+    UNSERIALIZE_SCALAR(ih_wptr);
+    UNSERIALIZE_SCALAR(ih_wptr_addr_lo);
+    UNSERIALIZE_SCALAR(ih_wptr_addr_hi);
+    UNSERIALIZE_SCALAR(ih_wptrAddr);
+    UNSERIALIZE_SCALAR(ih_doorbellOffset);
+
+    regs.IH_Cntl = ih_cntl;
+    regs.IH_Base = ih_base;
+    regs.IH_Base_Hi = ih_base_hi;
+    regs.baseAddr = ih_baseAddr;
+    regs.IH_Rptr = ih_rptr;
+    regs.IH_Wptr = ih_wptr;
+    regs.IH_Wptr_Addr_Lo = ih_wptr_addr_lo;
+    regs.IH_Wptr_Addr_Hi = ih_wptr_addr_hi;
+    regs.WptrAddr = ih_wptrAddr;
+    regs.IH_Doorbell = ih_doorbellOffset;
+}
+
+} // namespace gem5
diff --git a/src/dev/amdgpu/interrupt_handler.hh b/src/dev/amdgpu/interrupt_handler.hh
new file mode 100644
index 0000000..c64076d
--- /dev/null
+++ b/src/dev/amdgpu/interrupt_handler.hh
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * 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_INTERRUPT_HANDLER__
+#define __DEV_AMDGPU_INTERRUPT_HANDLER__
+
+#include <bitset>
+#include <iostream>
+#include <queue>
+#include <vector>
+
+#include "base/addr_range.hh"
+#include "base/flags.hh"
+#include "base/types.hh"
+#include "dev/amdgpu/amdgpu_device.hh"
+#include "dev/dma_device.hh"
+#include "params/AMDGPUInterruptHandler.hh"
+
+namespace gem5
+{
+
+/*
+ * MSI-style interrupts. Send a "cookie" response to clear interrupts.
+ * From [1] we know the size of the struct is 8 dwords. Then we can look at
+ * the register shift offsets in [2] to guess the rest. Or we can also look
+ * at [3].
+ *
+ * [1] https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/
+ *         drivers/gpu/drm/amd/amdkfd/kfd_device.c#L316
+ * [2] https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/ + * drivers/gpu/drm/amd/include/asic_reg/oss/osssys_4_0_sh_mask.h#L122 + * [3] https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/
+           drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h#L46
+ *
+ */
+typedef struct
+{
+    uint32_t clientId : 8;
+    uint32_t sourceId : 8;
+    uint32_t ringId : 8;
+    uint32_t vmId : 4;
+    uint32_t reserved1 : 3;
+    uint32_t vmid_type : 1;
+    uint32_t timestamp_Lo;
+    uint32_t timestamp_Hi : 16;
+    uint32_t reserved2 : 15;
+    uint32_t timestamp_src : 1;
+    uint32_t pasid : 16;
+    uint32_t reserved3 : 15;
+    uint32_t pasid_src : 1;
+    uint32_t source_data_dw1;
+    uint32_t source_data_dw2;
+    uint32_t source_data_dw3;
+    uint32_t source_data_dw4;
+} AMDGPUInterruptCookie;
+
+typedef struct
+{
+    uint32_t IH_Cntl;
+    uint32_t IH_Base;
+    uint32_t IH_Base_Hi;
+    Addr baseAddr;
+    uint32_t IH_Rptr;
+    uint32_t IH_Wptr;
+    uint32_t IH_Wptr_Addr_Lo;
+    uint32_t IH_Wptr_Addr_Hi;
+    Addr WptrAddr;
+    uint32_t IH_Doorbell;
+} AMDGPUIHRegs;
+
+constexpr uint32_t INTR_COOKIE_SIZE = 32; // in bytes
+
+class AMDGPUInterruptHandler : public DmaDevice
+{
+  public:
+    class DmaEvent : public Event
+    {
+      private:
+        AMDGPUInterruptHandler *deviceIh;
+        uint32_t data;
+
+      public:
+        DmaEvent(AMDGPUInterruptHandler *deviceIh, uint32_t data)
+            : Event(), deviceIh(deviceIh), data(data)
+        {
+            setFlags(Event::AutoDelete);
+        }
+        void process();
+        const char *description() const {
+            return "AMDGPUInterruptHandler Dma";
+        }
+
+        void setData(uint32_t _data) { data = _data; }
+        uint32_t getData() { return data; }
+    };
+
+    struct SenderState : public Packet::SenderState
+    {
+        SenderState(Packet::SenderState *sender_state, Addr addr)
+            : saved(sender_state), _addr(addr)
+        {
+        }
+        Packet::SenderState *saved;
+        Addr _addr;
+    };
+
+    AMDGPUInterruptHandler(const AMDGPUInterruptHandlerParams &p);
+
+    Tick write(PacketPtr pkt) override { return 0; }
+    Tick read(PacketPtr pkt) override { return 0; }
+    AddrRangeList getAddrRanges() const override;
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+    void setGPUDevice(AMDGPUDevice *gpu_device) { gpuDevice = gpu_device; }
+    void prepareInterruptCookie(ContextID cntxtId, uint32_t ring_id,
+        uint32_t client_id, uint32_t source_id);
+    void submitInterruptCookie();
+    void submitWritePointer();
+    void intrPost();
+
+    /**
+     * Methods for setting the values of interrupt handler MMIO registers.
+     */
+    void writeMMIO(PacketPtr pkt, Addr mmio_offset);
+
+    uint32_t getDoorbellOffset() const { return regs.IH_Doorbell; }
+    void setCntl(const uint32_t &data);
+    void setBase(const uint32_t &data);
+    void setBaseHi(const uint32_t &data);
+    void setRptr(const uint32_t &data);
+    void setWptr(const uint32_t &data);
+    void setWptrAddrLo(const uint32_t &data);
+    void setWptrAddrHi(const uint32_t &data);
+    void setDoorbellOffset(const uint32_t &data);
+    void updateRptr(const uint32_t &data);
+
+  private:
+    AMDGPUDevice *gpuDevice;
+    AMDGPUIHRegs regs;
+    std::queue<AMDGPUInterruptCookie*> interruptQueue;
+    AMDGPUInterruptHandler::DmaEvent *dmaEvent;
+};
+
+} // namespace gem5
+
+#endif // __DEV_AMDGPU_INTERRUPT_HANDLER__

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/51849
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: I574fbfdef6e3bae310ec7f86058811e1e4886df6
Gerrit-Change-Number: 51849
Gerrit-PatchSet: 15
Gerrit-Owner: Matthew Poremba <matthew.pore...@amd.com>
Gerrit-Reviewer: Kyle Roarty <kyleroarty1...@gmail.com>
Gerrit-Reviewer: Matt Sinclair <mattdsincl...@gmail.com>
Gerrit-Reviewer: Matthew Poremba <matthew.pore...@amd.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-MessageType: merged
_______________________________________________
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