blob: b34481b486bd7e90e5e23b26b507546a7690d52e (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
// SPDX-FileCopyrightText: 2022 yuzu emulator team and Skyline Team and Contributors
// (https://github.com/skyline-emu/)
// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3
// or any later version Refer to the license.txt file included.
#include "common/assert.h"
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
#include "video_core/host1x/host1x.h"
namespace Service::Nvidia::NvCore {
SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {
constexpr u32 VBlank0SyncpointId{26};
constexpr u32 VBlank1SyncpointId{27};
// Reserve both vblank syncpoints as client managed as they use Continuous Mode
// Refer to section 14.3.5.3 of the TRM for more information on Continuous Mode
// https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/drm/dc.c#L660
ReserveSyncpoint(VBlank0SyncpointId, true);
ReserveSyncpoint(VBlank1SyncpointId, true);
for (u32 syncpointId : channel_syncpoints) {
if (syncpointId) {
ReserveSyncpoint(syncpointId, false);
}
}
}
SyncpointManager::~SyncpointManager() = default;
u32 SyncpointManager::ReserveSyncpoint(u32 id, bool clientManaged) {
if (syncpoints.at(id).reserved) {
UNREACHABLE_MSG("Requested syncpoint is in use");
return 0;
}
syncpoints.at(id).reserved = true;
syncpoints.at(id).interfaceManaged = clientManaged;
return id;
}
u32 SyncpointManager::FindFreeSyncpoint() {
for (u32 i{1}; i < syncpoints.size(); i++) {
if (!syncpoints[i].reserved) {
return i;
}
}
UNREACHABLE_MSG("Failed to find a free syncpoint!");
return 0;
}
u32 SyncpointManager::AllocateSyncpoint(bool clientManaged) {
std::lock_guard lock(reservation_lock);
return ReserveSyncpoint(FindFreeSyncpoint(), clientManaged);
}
bool SyncpointManager::IsSyncpointAllocated(u32 id) {
return (id <= SyncpointCount) && syncpoints[id].reserved;
}
bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) {
const SyncpointInfo& syncpoint{syncpoints.at(id)};
if (!syncpoint.reserved) {
UNREACHABLE();
return 0;
}
// If the interface manages counters then we don't keep track of the maximum value as it handles
// sanity checking the values then
if (syncpoint.interfaceManaged) {
return static_cast<s32>(syncpoint.counterMin - threshold) >= 0;
} else {
return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold);
}
}
u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) {
if (!syncpoints.at(id).reserved) {
UNREACHABLE();
return 0;
}
return syncpoints.at(id).counterMax += amount;
}
u32 SyncpointManager::ReadSyncpointMinValue(u32 id) {
if (!syncpoints.at(id).reserved) {
UNREACHABLE();
return 0;
}
return syncpoints.at(id).counterMin;
}
u32 SyncpointManager::UpdateMin(u32 id) {
if (!syncpoints.at(id).reserved) {
UNREACHABLE();
return 0;
}
syncpoints.at(id).counterMin = host1x.GetSyncpointManager().GetHostSyncpointValue(id);
return syncpoints.at(id).counterMin;
}
NvFence SyncpointManager::GetSyncpointFence(u32 id) {
if (!syncpoints.at(id).reserved) {
UNREACHABLE();
return NvFence{};
}
return {.id = static_cast<s32>(id), .value = syncpoints.at(id).counterMax};
}
} // namespace Service::Nvidia::NvCore
|