2020-04-19 23:04:05 +02:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
2020-03-27 20:36:02 +01:00
|
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
2020-11-17 19:17:26 +01:00
|
|
|
// Copyright © 2019-2020 Ryujinx Team and Contributors
|
2020-03-27 20:36:02 +01:00
|
|
|
|
2021-03-24 21:09:21 +01:00
|
|
|
#include <soc.h>
|
2020-08-09 15:36:47 +02:00
|
|
|
#include <kernel/types/KProcess.h>
|
2020-09-14 16:13:36 +02:00
|
|
|
#include <services/nvdrv/driver.h>
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
#include "nvhost_ctrl.h"
|
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
namespace skyline::service::nvdrv::device {
|
2020-11-17 19:17:26 +01:00
|
|
|
SyncpointEvent::SyncpointEvent(const DeviceState &state) : event(std::make_shared<type::KEvent>(state, false)) {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Metadata about a syncpoint event, used by QueryEvent and SyncpointEventWait
|
|
|
|
*/
|
|
|
|
union SyncpointEventValue {
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
u8 _pad0_ : 4;
|
|
|
|
u32 syncpointIdAsync : 28;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct {
|
|
|
|
union {
|
|
|
|
u8 eventSlotAsync;
|
|
|
|
u16 eventSlotNonAsync;
|
|
|
|
};
|
|
|
|
u16 syncpointIdNonAsync : 12;
|
|
|
|
bool nonAsync : 1;
|
|
|
|
u8 _pad12_ : 3;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
static_assert(sizeof(SyncpointEventValue) == sizeof(u32));
|
|
|
|
|
|
|
|
void SyncpointEvent::Signal() {
|
|
|
|
std::lock_guard lock(mutex);
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
auto oldState{state};
|
2021-01-11 20:17:06 +01:00
|
|
|
state = State::Signalling;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
// We should only signal the KEvent if the event is actively being waited on
|
2020-08-09 15:36:47 +02:00
|
|
|
if (oldState == State::Waiting)
|
|
|
|
event->Signal();
|
|
|
|
|
2021-01-11 20:17:06 +01:00
|
|
|
state = State::Signalled;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
2021-03-24 21:09:21 +01:00
|
|
|
void SyncpointEvent::Cancel(soc::host1x::Host1X &host1x) {
|
2020-11-17 19:17:26 +01:00
|
|
|
std::lock_guard lock(mutex);
|
|
|
|
|
2021-03-24 21:09:21 +01:00
|
|
|
host1x.syncpoints.at(fence.id).DeregisterWaiter(waiterId);
|
2020-08-09 15:36:47 +02:00
|
|
|
Signal();
|
|
|
|
event->ResetSignal();
|
|
|
|
}
|
|
|
|
|
2021-03-24 21:09:21 +01:00
|
|
|
void SyncpointEvent::Wait(soc::host1x::Host1X &host1x, const Fence &pFence) {
|
2020-11-17 19:17:26 +01:00
|
|
|
std::lock_guard lock(mutex);
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2021-02-06 13:36:58 +01:00
|
|
|
fence = pFence;
|
2020-11-17 19:17:26 +01:00
|
|
|
state = State::Waiting;
|
2021-03-24 21:09:21 +01:00
|
|
|
waiterId = host1x.syncpoints.at(fence.id).RegisterWaiter(fence.value, [this] { Signal(); });
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
2020-09-18 02:45:57 +02:00
|
|
|
NvHostCtrl::NvHostCtrl(const DeviceState &state) : NvDevice(state) {}
|
2020-07-14 16:15:28 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
u32 NvHostCtrl::FindFreeSyncpointEvent(u32 syncpointId) {
|
|
|
|
u32 eventSlot{constant::NvHostEventCount}; //!< Holds the slot of the last populated event in the event array
|
|
|
|
u32 freeSlot{constant::NvHostEventCount}; //!< Holds the slot of the first unused event id
|
|
|
|
std::lock_guard lock(syncpointEventMutex);
|
2020-08-09 15:36:47 +02:00
|
|
|
|
|
|
|
for (u32 i{}; i < constant::NvHostEventCount; i++) {
|
2020-11-17 19:17:26 +01:00
|
|
|
if (syncpointEvents[i]) {
|
|
|
|
auto event{syncpointEvents[i]};
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
if (event->state == SyncpointEvent::State::Cancelled || event->state == SyncpointEvent::State::Available || event->state == SyncpointEvent::State::Signalled) {
|
|
|
|
eventSlot = i;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
|
|
|
// This event is already attached to the requested syncpoint, so use it
|
2020-11-17 19:17:26 +01:00
|
|
|
if (event->fence.id == syncpointId)
|
|
|
|
return eventSlot;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
2020-11-17 19:17:26 +01:00
|
|
|
} else if (freeSlot == constant::NvHostEventCount) {
|
|
|
|
freeSlot = i;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use an unused event if possible
|
2020-11-17 19:17:26 +01:00
|
|
|
if (freeSlot < constant::NvHostEventCount) {
|
|
|
|
syncpointEvents[eventSlot] = std::make_shared<SyncpointEvent>(state);
|
|
|
|
return freeSlot;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Recycle an existing event if all else fails
|
2020-11-17 19:17:26 +01:00
|
|
|
if (eventSlot < constant::NvHostEventCount)
|
|
|
|
return eventSlot;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
|
|
|
throw exception("Failed to find a free nvhost event!");
|
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
NvStatus NvHostCtrl::SyncpointEventWaitImpl(span<u8> buffer, bool async) {
|
2020-08-09 15:36:47 +02:00
|
|
|
struct Data {
|
2020-11-17 19:17:26 +01:00
|
|
|
Fence fence; // In
|
|
|
|
u32 timeout; // In
|
|
|
|
SyncpointEventValue value; // InOut
|
2020-09-25 02:05:12 +02:00
|
|
|
} &data = buffer.as<Data>();
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2021-03-24 21:09:21 +01:00
|
|
|
if (data.fence.id >= soc::host1x::SyncpointCount)
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::BadValue;
|
|
|
|
|
|
|
|
if (data.timeout == 0)
|
|
|
|
return NvStatus::Timeout;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
auto driver{nvdrv::driver.lock()};
|
|
|
|
auto &hostSyncpoint{driver->hostSyncpoint};
|
2020-08-09 15:36:47 +02:00
|
|
|
|
|
|
|
// Check if the syncpoint has already expired using the last known values
|
2020-09-19 16:45:17 +02:00
|
|
|
if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) {
|
|
|
|
data.value.val = hostSyncpoint.ReadSyncpointMinValue(data.fence.id);
|
|
|
|
return NvStatus::Success;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sync the syncpoint with the GPU then check again
|
2020-09-26 07:17:57 +02:00
|
|
|
auto minVal{hostSyncpoint.UpdateMin(data.fence.id)};
|
2020-09-19 16:45:17 +02:00
|
|
|
if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) {
|
|
|
|
data.value.val = minVal;
|
|
|
|
return NvStatus::Success;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
u32 eventSlot{};
|
2020-08-09 15:36:47 +02:00
|
|
|
if (async) {
|
2020-11-17 19:17:26 +01:00
|
|
|
if (data.value.val >= constant::NvHostEventCount)
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::BadValue;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
eventSlot = data.value.val;
|
2020-08-09 15:36:47 +02:00
|
|
|
} else {
|
2020-09-19 16:45:17 +02:00
|
|
|
data.fence.value = 0;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
eventSlot = FindFreeSyncpointEvent(data.fence.id);
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
std::lock_guard lock(syncpointEventMutex);
|
|
|
|
|
|
|
|
auto event{syncpointEvents[eventSlot]};
|
|
|
|
if (!event)
|
|
|
|
return NvStatus::BadValue;
|
|
|
|
|
|
|
|
std::lock_guard eventLock(event->mutex);
|
|
|
|
|
|
|
|
if (event->state == SyncpointEvent::State::Cancelled || event->state == SyncpointEvent::State::Available || event->state == SyncpointEvent::State::Signalled) {
|
|
|
|
state.logger->Debug("Waiting on syncpoint event: {} with fence: ({}, {})", eventSlot, data.fence.id, data.fence.value);
|
2021-03-24 21:09:21 +01:00
|
|
|
event->Wait(state.soc->host1x, data.fence);
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-09-19 16:45:17 +02:00
|
|
|
data.value.val = 0;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
|
|
|
if (async) {
|
2020-09-19 16:45:17 +02:00
|
|
|
data.value.syncpointIdAsync = data.fence.id;
|
2020-08-09 15:36:47 +02:00
|
|
|
} else {
|
2020-09-19 16:45:17 +02:00
|
|
|
data.value.syncpointIdNonAsync = data.fence.id;
|
|
|
|
data.value.nonAsync = true;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
data.value.val |= eventSlot;
|
2020-08-09 15:36:47 +02:00
|
|
|
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::Timeout;
|
2020-08-09 15:36:47 +02:00
|
|
|
} else {
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::BadValue;
|
2020-08-09 15:36:47 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-09-25 02:05:12 +02:00
|
|
|
NvStatus NvHostCtrl::GetConfig(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::BadValue;
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
NvStatus NvHostCtrl::SyncpointClearEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
|
|
|
auto eventSlot{buffer.as<u16>()};
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
if (eventSlot >= constant::NvHostEventCount)
|
2020-09-19 16:45:17 +02:00
|
|
|
return NvStatus::BadValue;
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
std::lock_guard lock(syncpointEventMutex);
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
auto event{syncpointEvents[eventSlot]};
|
|
|
|
if (!event)
|
|
|
|
return NvStatus::BadValue;
|
|
|
|
|
|
|
|
std::lock_guard eventLock(event->mutex);
|
|
|
|
|
|
|
|
if (event->state == SyncpointEvent::State::Waiting) {
|
|
|
|
event->state = SyncpointEvent::State::Cancelling;
|
|
|
|
state.logger->Debug("Cancelling waiting syncpoint event: {}", eventSlot);
|
2021-03-24 21:09:21 +01:00
|
|
|
event->Cancel(state.soc->host1x);
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
event->state = SyncpointEvent::State::Cancelled;
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-09-26 07:17:57 +02:00
|
|
|
auto driver{nvdrv::driver.lock()};
|
|
|
|
auto &hostSyncpoint{driver->hostSyncpoint};
|
2020-11-17 19:17:26 +01:00
|
|
|
hostSyncpoint.UpdateMin(event->fence.id);
|
2020-09-19 16:45:17 +02:00
|
|
|
|
|
|
|
return NvStatus::Success;
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
NvStatus NvHostCtrl::SyncpointEventWait(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
|
|
|
return SyncpointEventWaitImpl(buffer, false);
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
NvStatus NvHostCtrl::SyncpointEventWaitAsync(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
|
|
|
return SyncpointEventWaitImpl(buffer, true);
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
NvStatus NvHostCtrl::SyncpointRegisterEvent(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
|
|
|
|
auto eventSlot{buffer.as<u32>()};
|
|
|
|
state.logger->Debug("Registering syncpoint event: {}", eventSlot);
|
|
|
|
|
|
|
|
if (eventSlot >= constant::NvHostEventCount)
|
|
|
|
return NvStatus::BadValue;
|
|
|
|
|
|
|
|
std::lock_guard lock(syncpointEventMutex);
|
2020-08-12 21:02:24 +02:00
|
|
|
|
2020-11-17 19:17:26 +01:00
|
|
|
auto &event{syncpointEvents[eventSlot]};
|
2020-08-12 21:02:24 +02:00
|
|
|
if (event)
|
|
|
|
throw exception("Recreating events is unimplemented");
|
2020-11-17 19:17:26 +01:00
|
|
|
|
|
|
|
event = std::make_shared<SyncpointEvent>(state);
|
2020-09-19 16:45:17 +02:00
|
|
|
|
|
|
|
return NvStatus::Success;
|
2020-08-12 21:02:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<type::KEvent> NvHostCtrl::QueryEvent(u32 eventId) {
|
2020-11-17 19:17:26 +01:00
|
|
|
SyncpointEventValue eventValue{.val = eventId};
|
|
|
|
std::lock_guard lock(syncpointEventMutex);
|
|
|
|
|
|
|
|
auto event{syncpointEvents.at(eventValue.nonAsync ? eventValue.eventSlotNonAsync : eventValue.eventSlotAsync)};
|
2020-08-12 21:02:24 +02:00
|
|
|
|
|
|
|
if (event && event->fence.id == (eventValue.nonAsync ? eventValue.syncpointIdNonAsync : eventValue.syncpointIdAsync))
|
|
|
|
return event->event;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
|
|
|
}
|