| /* |
| * 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_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__ |