Move nvhost-gpu to new device API

The implementation of GPU channels and Host1X channels will be split up
as it allows a much cleaner implementation and less undefined behaviour
potential.
This commit is contained in:
Billy Laws 2021-07-17 17:47:08 +01:00 committed by ◱ Mark
parent 3d4f7d9b44
commit 39492d9365
4 changed files with 245 additions and 251 deletions

View File

@ -0,0 +1,133 @@
// SPDX-License-Identifier: MIT OR MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <soc.h>
#include <services/nvdrv/devices/deserialisation/deserialisation.h>
#include "gpu_channel.h"
namespace skyline::service::nvdrv::device::nvhost {
GpuChannel::GpuChannel(const DeviceState &state, Core &core, const SessionContext &ctx) :
NvDevice(state, core, ctx),
smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state, false)),
smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state, false)),
errorNotifierEvent(std::make_shared<type::KEvent>(state, false)) {
channelSyncpoint = core.syncpointManager.AllocateSyncpoint(false);
}
PosixResult GpuChannel::SetNvmapFd(In<core::NvMap::Handle::Id> id) {
return PosixResult::Success;
}
PosixResult GpuChannel::SetTimeout(In<u32> timeout) {
return PosixResult::Success;
}
PosixResult GpuChannel::SubmitGpfifo(In<u64> userAddress, In<u32> numEntries, InOut<SubmitGpfifoFlags> flags, InOut<Fence> fence, span<soc::gm20b::GpEntry> gpEntries) {
if (numEntries != gpEntries.size())
throw exception("GpEntry size mismatch!");
if (flags.fenceWait) {
if (flags.incrementWithValue)
return PosixResult::InvalidArgument;
if (core.syncpointManager.IsFenceSignalled(fence))
throw exception("Waiting on a fence through SubmitGpfifo is unimplemented");
}
state.soc->gm20b.gpfifo.Push(gpEntries);
fence.id = channelSyncpoint;
u32 increment{(flags.fenceIncrement ? 2 : 0) + (flags.incrementWithValue ? fence.threshold : 0)};
fence.threshold = core.syncpointManager.IncrementSyncpointMaxExt(channelSyncpoint, increment);
if (flags.fenceIncrement)
throw exception("Incrementing a fence through SubmitGpfifo is unimplemented");
flags.raw = 0;
return PosixResult::Success;
}
PosixResult GpuChannel::AllocObjCtx(In<u32> classId, In<u32> flags, Out<u64> objId) {
return PosixResult::Success;
}
PosixResult GpuChannel::ZcullBind(In<u64> gpuVa, In<u32> mode) {
return PosixResult::Success;
}
PosixResult GpuChannel::SetErrorNotifier(In<u64> offset, In<u64> size, In<u32> mem) {
return PosixResult::Success;
}
PosixResult GpuChannel::SetPriority(In<u32> priority) {
return PosixResult::Success;
}
PosixResult GpuChannel::AllocGpfifoEx2(In<u32> numEntries, In<u32> numJobs, In<u32> flags, Out<Fence> fence) {
state.soc->gm20b.gpfifo.Initialize(numEntries);
fence = core.syncpointManager.GetSyncpointFence(channelSyncpoint);
return PosixResult::Success;
}
PosixResult GpuChannel::SetTimeslice(In<u32> timeslice) {
return PosixResult::Success;
}
PosixResult GpuChannel::SetUserData(In<u64> userData) {
channelUserData = userData;
return PosixResult::Success;
}
PosixResult GpuChannel::GetUserData(Out<u64> userData) {
userData = channelUserData;
return PosixResult::Success;
}
std::shared_ptr<type::KEvent> GpuChannel::QueryEvent(u32 eventId) {
switch (eventId) {
case 1:
return smExceptionBreakpointIntReportEvent;
case 2:
return smExceptionBreakpointPauseReportEvent;
case 3:
return errorNotifierEvent;
default:
return nullptr;
}
}
#include <services/nvdrv/devices/deserialisation/macro_def.h>
static constexpr u32 GpuChannelUserMagic{0x47};
static constexpr u32 GpuChannelMagic{0x48};
VARIABLE_IOCTL_HANDLER_FUNC(GpuChannel, ({
IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x1),
SetNvmapFd, ARGS(In<core::NvMap::Handle::Id>))
IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x3),
SetTimeout, ARGS(In<u32>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x10), MAGIC(GpuChannelMagic), FUNC(0x9),
AllocObjCtx, ARGS(In<u32>, In<u32>, Out<u64>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x10), MAGIC(GpuChannelMagic), FUNC(0xB),
ZcullBind, ARGS(In<u64>, In<u32>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x18), MAGIC(GpuChannelMagic), FUNC(0xC),
SetErrorNotifier, ARGS(In<u64>, In<u64>, In<u32>))
IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0xD),
SetPriority, ARGS(In<u32>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x20), MAGIC(GpuChannelMagic), FUNC(0x1A),
AllocGpfifoEx2, ARGS(In<u32>, In<u32>, In<u32>, Out<Fence>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x1D),
SetTimeslice, ARGS(In<u32>))
IOCTL_CASE_ARGS(IN, SIZE(0x8), MAGIC(GpuChannelUserMagic), FUNC(0x14),
SetUserData, ARGS(In<u64>))
IOCTL_CASE_ARGS(OUT, SIZE(0x8), MAGIC(GpuChannelUserMagic), FUNC(0x15),
GetUserData, ARGS(Out<u64>))
}), ({
VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(GpuChannelMagic), FUNC(0x8),
SubmitGpfifo, ARGS(In<u64>, In<u32>, InOut<SubmitGpfifoFlags>, InOut<Fence>, AutoSizeSpan<soc::gm20b::GpEntry>))
}))
#include <services/nvdrv/devices/deserialisation/macro_undef.h>
}

View File

@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT OR MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <soc/gm20b/gpfifo.h>
#include <services/common/fence.h>
#include "services/nvdrv/devices/nvdevice.h"
namespace skyline::service::nvdrv::device::nvhost {
/**
* @brief nvhost::GpuChannel is used to create and submit commands to channels which are effectively GPU processes
* @url https://switchbrew.org/wiki/NV_services#Channels
*/
class GpuChannel : public NvDevice {
private:
u32 channelSyncpoint{};
u32 channelUserData{};
std::shared_ptr<type::KEvent> smExceptionBreakpointIntReportEvent;
std::shared_ptr<type::KEvent> smExceptionBreakpointPauseReportEvent;
std::shared_ptr<type::KEvent> errorNotifierEvent;
public:
/**
* @brief A bitfield of the flags that can be supplied for a specific GPFIFO submission
*/
union SubmitGpfifoFlags {
struct __attribute__((__packed__)) {
bool fenceWait : 1;
bool fenceIncrement : 1;
bool hwFormat : 1;
u8 _pad0_ : 1;
bool suppressWfi : 1;
u8 _pad1_ : 3;
bool incrementWithValue : 1;
};
u32 raw;
};
GpuChannel(const DeviceState &state, Core &core, const SessionContext &ctx);
/**
* @brief Sets the nvmap handle id to be used for channel submits (does nothing for GPU channels)
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD
*/
PosixResult SetNvmapFd(In<core::NvMap::Handle::Id> id);
/**
* @brief Sets the timeout for channel submits
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMEOUT
*/
PosixResult SetTimeout(In<u32> timeout);
/**
* @brief Submits GPFIFO entries for this channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO
*/
PosixResult SubmitGpfifo(In<u64> userAddress, In<u32> numEntries, InOut<SubmitGpfifoFlags> flags, InOut<Fence> fence, span<soc::gm20b::GpEntry> gpEntries);
/**
* @brief Allocates a graphic context object
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX
*/
PosixResult AllocObjCtx(In<u32> classId, In<u32> flags, Out<u64> objId);
/**
* @brief Binds a zcull context to the channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND
*/
PosixResult ZcullBind(In<u64> gpuVa, In<u32> mode);
/**
* @brief Initializes the error notifier for this channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER
*/
PosixResult SetErrorNotifier(In<u64> offset, In<u64> size, In<u32> mem);
/**
* @brief Sets the priority of the channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY
*/
PosixResult SetPriority(In<u32> priority);
/**
* @brief Allocates a GPFIFO entry
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2
*/
PosixResult AllocGpfifoEx2(In<u32> numEntries, In<u32> numJobs, In<u32> flags, Out<Fence> fence);
/**
* @brief Sets the timeslice of the channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMESLICE)
*/
PosixResult SetTimeslice(In<u32> timeslice);
/**
* @brief Sets the user specific data
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA
*/
PosixResult SetUserData(In<u64> userData);
/**
* @brief Sets the user specific data
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_GET_USER_DATA
*/
PosixResult GetUserData(Out<u64> userData);
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId) override;
PosixResult Ioctl(IoctlDescriptor cmd, span<u8> buffer) override;
};
}

View File

@ -1,144 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <soc.h>
#include <kernel/types/KProcess.h>
#include <services/nvdrv/driver.h>
#include "nvhost_channel.h"
namespace skyline::service::nvdrv::device {
NvHostChannel::NvHostChannel(const DeviceState &state) : smExceptionBreakpointIntReportEvent(std::make_shared<type::KEvent>(state, false)), smExceptionBreakpointPauseReportEvent(std::make_shared<type::KEvent>(state, false)), errorNotifierEvent(std::make_shared<type::KEvent>(state, false)), NvDevice(state) {
auto driver{nvdrv::driver.lock()};
auto &hostSyncpoint{driver->hostSyncpoint};
channelFence.id = hostSyncpoint.AllocateSyncpoint(false);
channelFence.UpdateValue(hostSyncpoint);
}
NvStatus NvHostChannel::SetNvmapFd(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetSubmitTimeout(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
soc::gm20b::GpEntry *entries; // In
u32 numEntries; // In
union {
struct __attribute__((__packed__)) {
bool fenceWait : 1;
bool fenceIncrement : 1;
bool hwFormat : 1;
u8 _pad0_ : 1;
bool suppressWfi : 1;
u8 _pad1_ : 3;
bool incrementWithValue : 1;
};
u32 raw;
} flags; // In
Fence fence; // InOut
} &data = buffer.as<Data>();
auto driver{nvdrv::driver.lock()};
auto &hostSyncpoint{driver->hostSyncpoint};
if (data.flags.fenceWait) {
if (data.flags.incrementWithValue)
return NvStatus::BadValue;
if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value))
throw exception("Waiting on a fence through SubmitGpfifo is unimplemented");
}
state.soc->gm20b.gpfifo.Push([&]() {
if (type == IoctlType::Ioctl2)
return inlineBuffer.cast<soc::gm20b::GpEntry>();
else
return span(data.entries, data.numEntries);
}());
data.fence.id = channelFence.id;
u32 increment{(data.flags.fenceIncrement ? 2 : 0) + (data.flags.incrementWithValue ? data.fence.value : 0)};
data.fence.value = hostSyncpoint.IncrementSyncpointMaxExt(data.fence.id, increment);
if (data.flags.fenceIncrement)
throw exception("Incrementing a fence through SubmitGpfifo is unimplemented");
data.flags.raw = 0;
return NvStatus::Success;
}
NvStatus NvHostChannel::AllocObjCtx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::ZcullBind(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetErrorNotifier(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
NvStatus NvHostChannel::SetPriority(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
switch (buffer.as<NvChannelPriority>()) {
case NvChannelPriority::Low:
timeslice = 1300;
break;
case NvChannelPriority::Medium:
timeslice = 2600;
break;
case NvChannelPriority::High:
timeslice = 5200;
break;
}
return NvStatus::Success;
}
NvStatus NvHostChannel::AllocGpfifoEx2(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
struct Data {
u32 numEntries; // In
u32 numJobs; // In
u32 flags; // In
Fence fence; // Out
u32 _res_[3]; // In
} &data = buffer.as<Data>();
state.soc->gm20b.gpfifo.Initialize(data.numEntries);
auto driver{nvdrv::driver.lock()};
channelFence.UpdateValue(driver->hostSyncpoint);
data.fence = channelFence;
return NvStatus::Success;
}
NvStatus NvHostChannel::SetTimeslice(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
timeslice = buffer.as<u32>();
return NvStatus::Success;
}
NvStatus NvHostChannel::SetUserData(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
return NvStatus::Success;
}
std::shared_ptr<type::KEvent> NvHostChannel::QueryEvent(u32 eventId) {
switch (eventId) {
case 1:
return smExceptionBreakpointIntReportEvent;
case 2:
return smExceptionBreakpointPauseReportEvent;
case 3:
return errorNotifierEvent;
default:
return nullptr;
}
}
}

View File

@ -1,107 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <services/common/fence.h>
#include "nvdevice.h"
namespace skyline::service::nvdrv::device {
/**
* @brief NvHostChannel is used as a common interface for all Channel devices
* @url https://switchbrew.org/wiki/NV_services#Channels
*/
class NvHostChannel : public NvDevice {
private:
enum class NvChannelPriority : u32 {
Low = 0x32,
Medium = 0x64,
High = 0x94,
};
Fence channelFence{};
u32 timeslice{};
std::shared_ptr<type::KEvent> smExceptionBreakpointIntReportEvent;
std::shared_ptr<type::KEvent> smExceptionBreakpointPauseReportEvent;
std::shared_ptr<type::KEvent> errorNotifierEvent;
public:
NvHostChannel(const DeviceState &state);
/**
* @brief Sets the nvmap file descriptor
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD
*/
NvStatus SetNvmapFd(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Sets the timeout for the channel
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT
*/
NvStatus SetSubmitTimeout(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Submits a command to the GPFIFO
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO
*/
NvStatus SubmitGpfifo(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Allocates a graphic context object
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX
*/
NvStatus AllocObjCtx(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Initializes the error notifier for this channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND
*/
NvStatus ZcullBind(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Initializes the error notifier for this channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER
*/
NvStatus SetErrorNotifier(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Sets the priority of the channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY
*/
NvStatus SetPriority(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Allocates a GPFIFO entry
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2
*/
NvStatus AllocGpfifoEx2(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Sets the timeslice of the channel
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMESLICE)
*/
NvStatus SetTimeslice(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
/**
* @brief Sets the user specific data
* @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA
*/
NvStatus SetUserData(IoctlType type, span<u8> buffer, span<u8> inlineBuffer);
std::shared_ptr<type::KEvent> QueryEvent(u32 eventId) override;
NVDEVICE_DECL(
NVFUNC(0x4801, NvHostChannel, SetNvmapFd),
NVFUNC(0x4803, NvHostChannel, SetSubmitTimeout),
NVFUNC(0x4808, NvHostChannel, SubmitGpfifo),
NVFUNC(0x4809, NvHostChannel, AllocObjCtx),
NVFUNC(0x480B, NvHostChannel, ZcullBind),
NVFUNC(0x480C, NvHostChannel, SetErrorNotifier),
NVFUNC(0x480D, NvHostChannel, SetPriority),
NVFUNC(0x481A, NvHostChannel, AllocGpfifoEx2),
NVFUNC(0x481B, NvHostChannel, SubmitGpfifo), // Our SubmitGpfifo implementation also handles SubmitGpfifoEx
NVFUNC(0x481D, NvHostChannel, SetTimeslice),
NVFUNC(0x4714, NvHostChannel, SetUserData)
)
};
}