Matthew Poremba has uploaded this change for review. (
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
---
A src/dev/amdgpu/interrupt_handler.cc
A src/dev/amdgpu/interrupt_handler.hh
M src/dev/amdgpu/SConscript
M src/dev/amdgpu/amdgpu_device.cc
M src/dev/amdgpu/AMDGPU.py
5 files changed, 442 insertions(+), 0 deletions(-)
diff --git a/src/dev/amdgpu/AMDGPU.py b/src/dev/amdgpu/AMDGPU.py
index f72f512..3785f2e 100644
--- a/src/dev/amdgpu/AMDGPU.py
+++ b/src/dev/amdgpu/AMDGPU.py
@@ -30,8 +30,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
@@ -73,3 +75,11 @@
trace_file = Param.String("MMIO trace collected on hardware")
checkpoint_before_mmios = Param.Bool(False, "Take a checkpoint before
the"
" device begins sending
MMIOs")
+
+ 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 eeff32e..8a4a710 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('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 94a5a6a..b3995cf 100644
--- a/src/dev/amdgpu/amdgpu_device.cc
+++ b/src/dev/amdgpu/amdgpu_device.cc
@@ -265,6 +265,12 @@
}
void
+AMDGPUDevice::intrPost()
+{
+ PciDevice::intrPost();
+}
+
+void
AMDGPUDevice::serialize(CheckpointOut &cp) const
{
// Serialize the PciDevice base class
diff --git a/src/dev/amdgpu/interrupt_handler.cc
b/src/dev/amdgpu/interrupt_handler.cc
new file mode 100644
index 0000000..945de4f
--- /dev/null
+++ b/src/dev/amdgpu/interrupt_handler.cc
@@ -0,0 +1,254 @@
+/*
+ * 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/interrupt_handler.hh"
+
+#include "debug/AMDGPUDevice.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)
+{
+ regs = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+}
+
+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)
+{
+ 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();
+ }
+}
+
+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, ®s.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::setCntl(const uint32_t &data)
+{
+ regs.IH_Cntl = data;
+}
+
+void
+AMDGPUInterruptHandler::setBase(const uint32_t &data)
+{
+ regs.IH_Base = data << 8; // from regspec - 256 bytes aligned
+ 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..9d73fa3
--- /dev/null
+++ b/src/dev/amdgpu/interrupt_handler.hh
@@ -0,0 +1,159 @@
+/*
+ * 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_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
+{
+
+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();
+
+ 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: 1
Gerrit-Owner: 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