| /* | |
| * 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_PM4_PACKET_PROCESSOR__ | |
| #define __DEV_AMDGPU_PM4_PACKET_PROCESSOR__ | |
| #include <unordered_map> | |
| #include "dev/amdgpu/amdgpu_device.hh" | |
| #include "dev/amdgpu/pm4_defines.hh" | |
| #include "dev/amdgpu/pm4_queues.hh" | |
| #include "dev/dma_virt_device.hh" | |
| #include "params/PM4PacketProcessor.hh" | |
| namespace gem5 | |
| { | |
| class AMDGPUDevice; | |
| class PM4PacketProcessor : public DmaVirtDevice | |
| { | |
| AMDGPUDevice *gpuDevice; | |
| /* First graphics queue */ | |
| PrimaryQueue pq; | |
| /* First compute queue */ | |
| QueueDesc kiq; | |
| /* All PM4 queues, indexed by VMID */ | |
| std::unordered_map<uint16_t, PM4Queue *> queues; | |
| /* A map of PM4 queues based on doorbell offset */ | |
| std::unordered_map<uint32_t, PM4Queue *> queuesMap; | |
| public: | |
| PM4PacketProcessor(const PM4PacketProcessorParams &p); | |
| void setGPUDevice(AMDGPUDevice *gpu_device); | |
| /** | |
| * Inherited methods. | |
| */ | |
| 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; | |
| /** | |
| * Method for functional translation. | |
| */ | |
| TranslationGenPtr translate(Addr vaddr, Addr size) override; | |
| uint32_t getKiqDoorbellOffset() { return kiq.doorbell & 0x1ffffffc; } | |
| uint32_t getPqDoorbellOffset() { return pq.doorbellOffset; } | |
| Addr getGARTAddr(Addr addr) const; | |
| /** | |
| * Based on an offset communicated through doorbell write, the | |
| * PM4PacketProcessor identifies which queue needs processing. | |
| */ | |
| PM4Queue* getQueue(Addr offset, bool gfx = false); | |
| /** | |
| * The first graphics queue, the Primary Queueu a.k.a. RB0, needs to be | |
| * mapped since all queue details are communicated through MMIOs to | |
| * special registers. | |
| */ | |
| void mapPq(Addr offset); | |
| /** | |
| * The first compute queue, the Kernel Interface Queueu a.k.a. KIQ, needs | |
| * to be mapped since all queue details are communicated through MMIOs to | |
| * special registers. | |
| */ | |
| void mapKiq(Addr offset); | |
| /** | |
| * This method creates a new PM4Queue based on a queue descriptor and an | |
| * offset. | |
| */ | |
| void newQueue(QueueDesc *q, Addr offset, PM4MapQueues *pkt = nullptr, | |
| int id = -1); | |
| /** | |
| * This method start processing a PM4Queue from the current read pointer | |
| * to the newly communicated write pointer (i.e., wptrOffset). | |
| */ | |
| void process(PM4Queue *q, Addr wptrOffset); | |
| /** | |
| * Update read index on doorbell rings. We use write index, however read | |
| * index == write index when the queue is empty. This allows us to save | |
| * previous read index when a queue is remapped. The remapped queue will | |
| * read from the previous read index rather than reset to zero. | |
| */ | |
| void updateReadIndex(Addr offset, uint64_t rd_idx); | |
| /** | |
| * This method decodes the next packet in a PM4Queue. | |
| */ | |
| void decodeNext(PM4Queue *q); | |
| /** | |
| * This method calls other PM4 packet processing methods based on the | |
| * header of a PM4 packet. | |
| */ | |
| void decodeHeader(PM4Queue *q, PM4Header header); | |
| /* Methods that implement PM4 packets */ | |
| void writeData(PM4Queue *q, PM4WriteData *pkt); | |
| void writeDataDone(PM4Queue *q, PM4WriteData *pkt, Addr addr); | |
| void mapQueues(PM4Queue *q, PM4MapQueues *pkt); | |
| void unmapQueues(PM4Queue *q, PM4UnmapQueues *pkt); | |
| void doneMQDWrite(Addr mqdAddr, Addr addr); | |
| void mapProcess(PM4Queue *q, PM4MapProcess *pkt); | |
| void processMQD(PM4MapQueues *pkt, PM4Queue *q, Addr addr, QueueDesc *mqd, | |
| uint16_t vmid); | |
| void processSDMAMQD(PM4MapQueues *pkt, PM4Queue *q, Addr addr, | |
| SDMAQueueDesc *mqd, uint16_t vmid); | |
| void releaseMem(PM4Queue *q, PM4ReleaseMem *pkt); | |
| void releaseMemDone(PM4Queue *q, PM4ReleaseMem *pkt, Addr addr); | |
| void runList(PM4Queue *q, PM4RunList *pkt); | |
| void indirectBuffer(PM4Queue *q, PM4IndirectBuf *pkt); | |
| void switchBuffer(PM4Queue *q, PM4SwitchBuf *pkt); | |
| void setUconfigReg(PM4Queue *q, PM4SetUconfigReg *pkt); | |
| void waitRegMem(PM4Queue *q, PM4WaitRegMem *pkt); | |
| void queryStatus(PM4Queue *q, PM4QueryStatus *pkt); | |
| void queryStatusDone(PM4Queue *q, PM4QueryStatus *pkt); | |
| /* Methods that implement MMIO regs */ | |
| void writeMMIO(PacketPtr pkt, Addr mmio_offset); | |
| void setHqdVmid(uint32_t data); | |
| void setHqdActive(uint32_t data); | |
| void setHqdPqBase(uint32_t data); | |
| void setHqdPqBaseHi(uint32_t data); | |
| void setHqdPqDoorbellCtrl(uint32_t data); | |
| void setHqdPqPtr(uint32_t data); | |
| void setHqdPqWptrLo(uint32_t data); | |
| void setHqdPqWptrHi(uint32_t data); | |
| void setHqdPqRptrReportAddr(uint32_t data); | |
| void setHqdPqRptrReportAddrHi(uint32_t data); | |
| void setHqdPqWptrPollAddr(uint32_t data); | |
| void setHqdPqWptrPollAddrHi(uint32_t data); | |
| void setHqdIbCtrl(uint32_t data); | |
| void setRbVmid(uint32_t data); | |
| void setRbCntl(uint32_t data); | |
| void setRbWptrLo(uint32_t data); | |
| void setRbWptrHi(uint32_t data); | |
| void setRbRptrAddrLo(uint32_t data); | |
| void setRbRptrAddrHi(uint32_t data); | |
| void setRbWptrPollAddrLo(uint32_t data); | |
| void setRbWptrPollAddrHi(uint32_t data); | |
| void setRbBaseLo(uint32_t data); | |
| void setRbBaseHi(uint32_t data); | |
| void setRbDoorbellCntrl(uint32_t data); | |
| void setRbDoorbellRangeLo(uint32_t data); | |
| void setRbDoorbellRangeHi(uint32_t data); | |
| }; | |
| } // namespace gem5 | |
| #endif //__DEV_AMDGPU_PM4_PACKET_PROCESSOR__ |