core: gpu interrupt dispatcher

This commit is contained in:
psucien 2024-05-10 21:48:01 +02:00
parent 581688c1ac
commit 923baf0164
9 changed files with 161 additions and 68 deletions

View file

@ -3,6 +3,7 @@
#include "common/assert.h"
#include "common/io_file.h"
#include "common/thread.h"
#include "video_core/amdgpu/liverpool.h"
#include "video_core/amdgpu/pm4_cmds.h"
@ -11,6 +12,8 @@ namespace AmdGpu {
Liverpool::Liverpool() = default;
void Liverpool::ProcessCmdList(u32* cmdbuf, u32 size_in_bytes) {
Common::SetCurrentThreadName("CommandProcessor_Gfx");
auto* header = reinterpret_cast<PM4Header*>(cmdbuf);
u32 processed_cmd_size = 0;
@ -70,54 +73,12 @@ void Liverpool::ProcessCmdList(u32* cmdbuf, u32 size_in_bytes) {
}
case PM4ItOpcode::EventWriteEos: {
const auto* event_eos = reinterpret_cast<PM4CmdEventWriteEos*>(header);
switch (event_eos->command.Value()) {
case PM4CmdEventWriteEos::Command::SingalFence: {
event_eos->SignalFence();
break;
}
default: {
UNREACHABLE();
}
}
event_eos->SignalFence();
break;
}
case PM4ItOpcode::EventWriteEop: {
const auto* event_eop = reinterpret_cast<PM4CmdEventWriteEop*>(header);
const InterruptSelect irq_sel = event_eop->int_sel;
const DataSelect data_sel = event_eop->data_sel;
// Write back data if required
switch (data_sel) {
case DataSelect::Data32Low: {
*reinterpret_cast<u32*>(event_eop->Address()) = event_eop->DataDWord();
break;
}
case DataSelect::Data64: {
*event_eop->Address() = event_eop->DataQWord();
break;
}
default: {
UNREACHABLE();
}
}
switch (irq_sel) {
case InterruptSelect::None: {
// No interrupt
break;
}
case InterruptSelect::IrqWhenWriteConfirm: {
if (eop_callback) {
eop_callback();
} else {
UNREACHABLE_MSG("EOP callback is not registered");
}
break;
}
default: {
UNREACHABLE();
}
}
event_eop->SignalFence();
break;
}
case PM4ItOpcode::DmaData: {
@ -143,11 +104,9 @@ void Liverpool::ProcessCmdList(u32* cmdbuf, u32 size_in_bytes) {
case PM4ItOpcode::WaitRegMem: {
const auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(header);
ASSERT(wait_reg_mem->engine.Value() == PM4CmdWaitRegMem::Engine::Me);
ASSERT(wait_reg_mem->function.Value() == PM4CmdWaitRegMem::Function::Equal);
{
std::unique_lock lock{m_reg_mem};
cv_reg_mem.wait(lock, [&]() { return wait_reg_mem->Test(); });
while (!wait_reg_mem->Test()) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(1ms);
}
break;
}

View file

@ -624,17 +624,11 @@ public:
// reworked with mutiple queues introduction
cp.get();
}
void SetEopCallback(auto const& cb) {
eop_callback = cb;
}
private:
void ProcessCmdList(u32* cmdbuf, u32 size_in_bytes);
std::function<void(void)> eop_callback{};
std::future<void> cp{};
std::condition_variable cv_reg_mem{};
std::mutex m_reg_mem{};
};
static_assert(GFX6_3D_REG_INDEX(ps_program) == 0x2C08);

View file

@ -6,6 +6,7 @@
#include <cstring>
#include "common/bit_field.h"
#include "common/types.h"
#include "core/platform.h"
#include "video_core/amdgpu/pm4_opcodes.h"
namespace AmdGpu {
@ -282,8 +283,9 @@ struct PM4CmdEventWriteEop {
u32 data_lo; ///< Value that will be written to memory when event occurs
u32 data_hi; ///< Value that will be written to memory when event occurs
u64* Address() const {
return reinterpret_cast<u64*>(address_lo | u64(address_hi) << 32);
template <typename T>
T* Address() const {
return reinterpret_cast<T*>(address_lo | u64(address_hi) << 32);
}
u32 DataDWord() const {
@ -293,6 +295,36 @@ struct PM4CmdEventWriteEop {
u64 DataQWord() const {
return data_lo | u64(data_hi) << 32;
}
void SignalFence() const {
switch (data_sel.Value()) {
case DataSelect::Data32Low: {
*Address<u32>() = DataDWord();
break;
}
case DataSelect::Data64: {
*Address<u64>() = DataQWord();
break;
}
default: {
UNREACHABLE();
}
}
switch (int_sel.Value()) {
case InterruptSelect::None: {
// No interrupt
break;
}
case InterruptSelect::IrqWhenWriteConfirm: {
Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxEop);
break;
}
default: {
UNREACHABLE();
}
}
}
};
struct PM4DmaData {
@ -434,8 +466,15 @@ struct PM4CmdEventWriteEos {
}
void SignalFence() const {
ASSERT_MSG(command.Value() == Command::SingalFence, "Invalid action on packet");
*Address() = DataDWord();
switch (command.Value()) {
case Command::SingalFence: {
*Address() = DataDWord();
break;
}
default: {
UNREACHABLE();
}
}
}
};