Implement the host side of host1x syncpoints

This will be extended in the future to support interfacing with the GPU.
This commit is contained in:
Billy Laws 2020-07-23 20:20:42 +01:00 committed by ◱ PixelyIon
parent 3c5cc33a34
commit 8dc9a10324
6 changed files with 152 additions and 1 deletions

View File

@ -105,6 +105,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_ctrl.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_channel.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp
${source_DIR}/skyline/services/nvdrv/devices/nvhost_syncpoint.cpp
${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp ${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp
${source_DIR}/skyline/services/visrv/IDisplayService.cpp ${source_DIR}/skyline/services/visrv/IDisplayService.cpp
${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp ${source_DIR}/skyline/services/visrv/IApplicationDisplayService.cpp

View File

@ -54,7 +54,7 @@ namespace skyline::service::nvdrv {
return fdIndex++; return fdIndex++;
} }
INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::nvdrv_INvDrvServices, "INvDrvServices", { INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : hostSyncpoint(state), BaseService(state, manager, Service::nvdrv_INvDrvServices, "INvDrvServices", {
{0x0, SFUNC(INvDrvServices::Open)}, {0x0, SFUNC(INvDrvServices::Open)},
{0x1, SFUNC(INvDrvServices::Ioctl)}, {0x1, SFUNC(INvDrvServices::Ioctl)},
{0x2, SFUNC(INvDrvServices::Close)}, {0x2, SFUNC(INvDrvServices::Close)},

View File

@ -8,6 +8,7 @@
#include <kernel/types/KTransferMemory.h> #include <kernel/types/KTransferMemory.h>
#include <gpu.h> #include <gpu.h>
#include "devices/nvdevice.h" #include "devices/nvdevice.h"
#include "devices/nvhost_syncpoint.h"
namespace skyline::service::nvdrv { namespace skyline::service::nvdrv {
/** /**
@ -43,6 +44,8 @@ namespace skyline::service::nvdrv {
} }
public: public:
NvHostSyncpoint hostSyncpoint;
/** /**
* @brief Returns a particular device with a specific type * @brief Returns a particular device with a specific type
* @tparam objectClass The class of the device to return * @tparam objectClass The class of the device to return

View File

@ -0,0 +1,25 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <common.h>
#include "nvhost_syncpoint.h"
namespace skyline::service::nvdrv::device {
/**
* @brief This holds information about a fence
*/
struct NvFence {
u32 id{};
u32 value{};
/**
* @brief Synchronizes the fence's value with its underlying syncpoint
*/
static inline void UpdateValue(const NvHostSyncpoint &hostSyncpoint) {
//TODO: Implement this
}
};
static_assert(sizeof(NvFence) == 0x8);
}

View File

@ -0,0 +1,54 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "nvhost_syncpoint.h"
namespace skyline::service::nvdrv {
NvHostSyncpoint::NvHostSyncpoint(const DeviceState &state) : state(state) {
constexpr u32 VBlank0SyncpointId{26};
constexpr u32 VBlank1SyncpointId{27};
// Reserve both vblank syncpoints as client managed since the userspace driver has direct access to them
ReserveSyncpoint(VBlank0SyncpointId, true);
ReserveSyncpoint(VBlank1SyncpointId, true);
}
u32 NvHostSyncpoint::ReserveSyncpoint(u32 id, bool clientManaged) {
if (id >= constant::MaxHwSyncpointCount)
throw exception("Requested syncpoint ID is too high");
if (syncpoints.at(id).assigned)
throw exception("Requested syncpoint is in use");
syncpoints.at(id).assigned = true;
syncpoints.at(id).clientManaged = clientManaged;
return id;
}
u32 NvHostSyncpoint::FindFreeSyncpoint() {
for (u32 i = 0; i < constant::MaxHwSyncpointCount; i++)
if (!syncpoints[i].assigned)
return i;
throw exception("Failed to find a free syncpoint!");
}
u32 NvHostSyncpoint::AllocateSyncpoint(bool clientManaged) {
std::lock_guard lock(reservationLock);
return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged);
}
bool NvHostSyncpoint::HasSyncpointExpired(u32 id, u32 threshold) {
const SyncpointInfo &syncpoint = syncpoints.at(id);
if (syncpoint.clientManaged)
return static_cast<i32>(syncpoint.counterMin - threshold) >= 0;
else
return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold);
}
u32 NvHostSyncpoint::IncrementSyncpointMaxExt(u32 id, u32 amount) {
return syncpoints.at(id).counterMax += amount;
}
}

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <common.h>
#include <array>
namespace skyline {
namespace constant {
constexpr size_t MaxHwSyncpointCount = 192;
}
namespace service::nvdrv {
/**
* @todo Implement the GPU side of this
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints
* @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c
*/
class NvHostSyncpoint {
private:
/**
* @brief This holds information about a single syncpoint
*/
struct SyncpointInfo {
std::atomic<u32> counterMin;
std::atomic<u32> counterMax;
bool clientManaged;
bool assigned;
};
const DeviceState &state;
std::array<SyncpointInfo, skyline::constant::MaxHwSyncpointCount> syncpoints{};
Mutex reservationLock;
/**
* @note reservationLock should be locked when calling this
*/
u32 ReserveSyncpoint(u32 id, bool clientManaged);
/**
* @return The ID of the first free syncpoint
*/
u32 FindFreeSyncpoint();
public:
NvHostSyncpoint(const DeviceState &state);
/**
* @brief Finds a free syncpoint and reserves it
* @return The ID of the reserved syncpoint
*/
u32 AllocateSyncpoint(bool clientManaged);
/**
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/syncpt.c#L259
*/
bool HasSyncpointExpired(u32 id, u32 threshold);
/**
* @brief Atomically increments the maximum value of a syncpoint by the given amount
* @return The new value of the syncpoint
*/
u32 IncrementSyncpointMaxExt(u32 id, u32 amount);
};
}
}