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.poremba@amd.com>
Reviewed-by: Matt Sinclair <mattdsinclair@gmail.com>
Maintainer: Matt Sinclair <mattdsinclair@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Matthew Poremba
2021-10-20 15:20:59 -05:00
parent 8da24ea088
commit b7826f1329
7 changed files with 622 additions and 4 deletions

View File

@@ -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 @@ class AMDGPUDevice(PciDevice):
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'

View File

@@ -33,9 +33,11 @@ if not env['BUILD_GPU']:
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')

View File

@@ -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 @@ AMDGPUDevice::writeDoorbell(PacketPtr pkt, Addr offset)
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
@@ -262,6 +274,19 @@ AMDGPUDevice::write(PacketPtr pkt)
return pioDelay;
}
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
{

View File

@@ -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
@@ -76,6 +78,14 @@ class AMDGPUDevice : public PciDevice
void writeDoorbell(PacketPtr pkt, Addr offset);
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
*/
@@ -91,10 +101,13 @@ class AMDGPUDevice : public PciDevice
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 @@ class AMDGPUDevice : public PciDevice
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

51
src/dev/amdgpu/ih_mmio.hh Normal file
View File

@@ -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__

View File

@@ -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

View File

@@ -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__