Currently the amdgpu simulated device is assumed to be a Vega10. As a result there are a few things that are hardcoded. One of those is the number of SDMAs. In order to add a newer device, such as MI100+, we need to enable a flexible number of SDMAs. In order to support a variable number of SDMAs and with the MMIO offsets of each device being potentially different, the MMIO interface for SDMAs is changed to use an SDMA class method dispatch table with forwards a 32-bit value from the MMIO packet to the MMIO functions in SDMA of the format `void method(uint32_t)`. Several changes are made to enable this: - Allow the SDMA to have a variable MMIO base and size. These are configured in python. - An SDMA class method dispatch table which contains the MMIO offset relative to the SDMA's MMIO base address. - An updated writeMMIO method to iterate over the SDMA MMIO address ranges and call the appropriate SDMA MMIO method which matches the MMIO offset. - Moved all SDMA related MMIO data bit twiddling, masking, etc. into the MMIO methods themselves instead of in the writeMMIO method in SDMAEngine. Change-Id: Ifce626f84d52f9e27e4438ba4e685e30dbf06dbc Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/70040 Maintainer: Matt Sinclair <mattdsinclair@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Matt Sinclair <mattdsinclair@gmail.com>
205 lines
6.5 KiB
C++
205 lines
6.5 KiB
C++
/*
|
|
* 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
|
|
{
|
|
|
|
/**
|
|
* Defines from driver code. Taken from
|
|
* https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/blob/roc-4.3.x/
|
|
* drivers/gpu/drm/amd/include/soc15_ih_clientid.h
|
|
*/
|
|
enum soc15_ih_clientid
|
|
{
|
|
SOC15_IH_CLIENTID_RLC = 0x07,
|
|
SOC15_IH_CLIENTID_SDMA0 = 0x08,
|
|
SOC15_IH_CLIENTID_SDMA1 = 0x09,
|
|
SOC15_IH_CLIENTID_SDMA2 = 0x01,
|
|
SOC15_IH_CLIENTID_SDMA3 = 0x04,
|
|
SOC15_IH_CLIENTID_SDMA4 = 0x05,
|
|
SOC15_IH_CLIENTID_SDMA5 = 0x11,
|
|
SOC15_IH_CLIENTID_SDMA6 = 0x13,
|
|
SOC15_IH_CLIENTID_SDMA7 = 0x18,
|
|
SOC15_IH_CLIENTID_GRBM_CP = 0x14
|
|
};
|
|
|
|
enum ihSourceId
|
|
{
|
|
CP_EOP = 181,
|
|
TRAP_ID = 224
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
*
|
|
*/
|
|
constexpr uint32_t INTR_COOKIE_SIZE = 32; // in bytes
|
|
|
|
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;
|
|
static_assert(sizeof(AMDGPUInterruptCookie) == INTR_COOKIE_SIZE);
|
|
|
|
/**
|
|
* Struct to contain all interrupt handler related registers.
|
|
*/
|
|
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;
|
|
|
|
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__
|