summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp176
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp3
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h2
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp174
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h56
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp7
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h1
14 files changed, 291 insertions, 199 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 51c40f620..122c1d5e1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -3,9 +3,11 @@
3// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 3// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3
4// or any later version Refer to the license.txt file included. 4// or any later version Refer to the license.txt file included.
5 5
6#include <bit>
6#include <cstdlib> 7#include <cstdlib>
7#include <cstring> 8#include <cstring>
8 9
10#include <fmt/format.h>
9#include "common/assert.h" 11#include "common/assert.h"
10#include "common/logging/log.h" 12#include "common/logging/log.h"
11#include "common/scope_exit.h" 13#include "common/scope_exit.h"
@@ -22,8 +24,19 @@ namespace Service::Nvidia::Devices {
22nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_, 24nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,
23 NvCore::Container& core_) 25 NvCore::Container& core_)
24 : nvdevice{system_}, events_interface{events_interface_}, core{core_}, 26 : nvdevice{system_}, events_interface{events_interface_}, core{core_},
25 syncpoint_manager{core_.GetSyncpointManager()} {} 27 syncpoint_manager{core_.GetSyncpointManager()} {
26nvhost_ctrl::~nvhost_ctrl() = default; 28 events_interface.RegisterForSignal(this);
29}
30
31nvhost_ctrl::~nvhost_ctrl() {
32 events_interface.UnregisterForSignal(this);
33 for (auto& event : events) {
34 if (!event.registered) {
35 continue;
36 }
37 events_interface.FreeEvent(event.kevent);
38 }
39}
27 40
28NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 41NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
29 std::vector<u8>& output) { 42 std::vector<u8>& output) {
@@ -87,7 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
87 SCOPE_EXIT({ 100 SCOPE_EXIT({
88 std::memcpy(output.data(), &params, sizeof(params)); 101 std::memcpy(output.data(), &params, sizeof(params));
89 if (must_unmark_fail) { 102 if (must_unmark_fail) {
90 events_interface.fails[event_id] = 0; 103 events[event_id].fails = 0;
91 } 104 }
92 }); 105 });
93 106
@@ -116,12 +129,12 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
116 auto& gpu = system.GPU(); 129 auto& gpu = system.GPU();
117 const u32 target_value = params.fence.value; 130 const u32 target_value = params.fence.value;
118 131
119 auto lock = events_interface.Lock(); 132 auto lock = NvEventsLock();
120 133
121 u32 slot = [&]() { 134 u32 slot = [&]() {
122 if (is_allocation) { 135 if (is_allocation) {
123 params.value.raw = 0; 136 params.value.raw = 0;
124 return events_interface.FindFreeEvent(fence_id); 137 return FindFreeNvEvent(fence_id);
125 } else { 138 } else {
126 return params.value.raw; 139 return params.value.raw;
127 } 140 }
@@ -130,7 +143,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
130 must_unmark_fail = true; 143 must_unmark_fail = true;
131 144
132 const auto check_failing = [&]() { 145 const auto check_failing = [&]() {
133 if (events_interface.fails[slot] > 2) { 146 if (events[slot].fails > 2) {
134 { 147 {
135 auto lk = system.StallProcesses(); 148 auto lk = system.StallProcesses();
136 gpu.WaitFence(fence_id, target_value); 149 gpu.WaitFence(fence_id, target_value);
@@ -142,6 +155,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
142 return false; 155 return false;
143 }; 156 };
144 157
158 if (slot >= MaxNvEvents) {
159 return NvResult::BadParameter;
160 }
161
145 if (params.timeout == 0) { 162 if (params.timeout == 0) {
146 if (check_failing()) { 163 if (check_failing()) {
147 return NvResult::Success; 164 return NvResult::Success;
@@ -149,17 +166,13 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
149 return NvResult::Timeout; 166 return NvResult::Timeout;
150 } 167 }
151 168
152 if (slot >= MaxNvEvents) { 169 auto& event = events[slot];
153 return NvResult::BadParameter;
154 }
155
156 auto* event = events_interface.events[slot];
157 170
158 if (!event) { 171 if (!event.registered) {
159 return NvResult::BadParameter; 172 return NvResult::BadParameter;
160 } 173 }
161 174
162 if (events_interface.IsBeingUsed(slot)) { 175 if (event.IsBeingUsed()) {
163 return NvResult::BadParameter; 176 return NvResult::BadParameter;
164 } 177 }
165 178
@@ -169,9 +182,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
169 182
170 params.value.raw = 0; 183 params.value.raw = 0;
171 184
172 events_interface.status[slot].store(EventState::Waiting, std::memory_order_release); 185 event.status.store(EventState::Waiting, std::memory_order_release);
173 events_interface.assigned_syncpt[slot] = fence_id; 186 event.assigned_syncpt = fence_id;
174 events_interface.assigned_value[slot] = target_value; 187 event.assigned_value = target_value;
175 if (is_allocation) { 188 if (is_allocation) {
176 params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id)); 189 params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id));
177 params.value.event_allocated.Assign(1); 190 params.value.event_allocated.Assign(1);
@@ -189,15 +202,17 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
189 return NvResult::BadParameter; 202 return NvResult::BadParameter;
190 } 203 }
191 204
192 if (!events_interface.registered[slot]) { 205 auto& event = events[slot];
206
207 if (!event.registered) {
193 return NvResult::Success; 208 return NvResult::Success;
194 } 209 }
195 210
196 if (events_interface.IsBeingUsed(slot)) { 211 if (event.IsBeingUsed()) {
197 return NvResult::Busy; 212 return NvResult::Busy;
198 } 213 }
199 214
200 events_interface.Free(slot); 215 FreeNvEvent(slot);
201 return NvResult::Success; 216 return NvResult::Success;
202} 217}
203 218
@@ -210,15 +225,15 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
210 return NvResult::BadParameter; 225 return NvResult::BadParameter;
211 } 226 }
212 227
213 auto lock = events_interface.Lock(); 228 auto lock = NvEventsLock();
214 229
215 if (events_interface.registered[event_id]) { 230 if (events[event_id].registered) {
216 const auto result = FreeEvent(event_id); 231 const auto result = FreeEvent(event_id);
217 if (result != NvResult::Success) { 232 if (result != NvResult::Success) {
218 return result; 233 return result;
219 } 234 }
220 } 235 }
221 events_interface.Create(event_id); 236 CreateNvEvent(event_id);
222 return NvResult::Success; 237 return NvResult::Success;
223} 238}
224 239
@@ -229,7 +244,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
229 const u32 event_id = params.user_event_id & 0x00FF; 244 const u32 event_id = params.user_event_id & 0x00FF;
230 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); 245 LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
231 246
232 auto lock = events_interface.Lock(); 247 auto lock = NvEventsLock();
233 return FreeEvent(event_id); 248 return FreeEvent(event_id);
234} 249}
235 250
@@ -244,44 +259,121 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v
244 return NvResult::BadParameter; 259 return NvResult::BadParameter;
245 } 260 }
246 261
247 auto lock = events_interface.Lock(); 262 auto lock = NvEventsLock();
248 263
249 if (events_interface.status[event_id].exchange( 264 auto& event = events[event_id];
250 EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { 265 if (event.status.exchange(EventState::Cancelling, std::memory_order_acq_rel) ==
251 system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], 266 EventState::Waiting) {
252 events_interface.assigned_value[event_id]); 267 system.GPU().CancelSyncptInterrupt(event.assigned_syncpt, event.assigned_value);
253 syncpoint_manager.RefreshSyncpoint(events_interface.assigned_syncpt[event_id]); 268 syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt);
254 } 269 }
255 events_interface.fails[event_id]++; 270 event.fails++;
256 events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release); 271 event.status.store(EventState::Cancelled, std::memory_order_release);
257 events_interface.events[event_id]->GetWritableEvent().Clear(); 272 event.kevent->GetWritableEvent().Clear();
258 273
259 return NvResult::Success; 274 return NvResult::Success;
260} 275}
261 276
262Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { 277Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) {
263 const auto event = SyncpointEventValue{.raw = event_id}; 278 const auto desired_event = SyncpointEventValue{.raw = event_id};
264 279
265 const bool allocated = event.event_allocated.Value() != 0; 280 const bool allocated = desired_event.event_allocated.Value() != 0;
266 const u32 slot{allocated ? event.partial_slot.Value() : static_cast<u32>(event.slot)}; 281 const u32 slot{allocated ? desired_event.partial_slot.Value()
282 : static_cast<u32>(desired_event.slot)};
267 if (slot >= MaxNvEvents) { 283 if (slot >= MaxNvEvents) {
268 ASSERT(false); 284 ASSERT(false);
269 return nullptr; 285 return nullptr;
270 } 286 }
271 287
272 const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() 288 const u32 syncpoint_id{allocated ? desired_event.syncpoint_id_for_allocation.Value()
273 : event.syncpoint_id.Value()}; 289 : desired_event.syncpoint_id.Value()};
274 290
275 auto lock = events_interface.Lock(); 291 auto lock = NvEventsLock();
276 292
277 if (events_interface.registered[slot] && 293 auto& event = events[slot];
278 events_interface.assigned_syncpt[slot] == syncpoint_id) { 294 if (event.registered && event.assigned_syncpt == syncpoint_id) {
279 ASSERT(events_interface.events[slot]); 295 ASSERT(event.kevent);
280 return events_interface.events[slot]; 296 return event.kevent;
281 } 297 }
282 // Is this possible in hardware? 298 // Is this possible in hardware?
283 ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id); 299 ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id);
284 return nullptr; 300 return nullptr;
285} 301}
286 302
303std::unique_lock<std::mutex> nvhost_ctrl::NvEventsLock() {
304 return std::unique_lock<std::mutex>(events_mutex);
305}
306
307void nvhost_ctrl::CreateNvEvent(u32 event_id) {
308 auto& event = events[event_id];
309 ASSERT(!event.kevent);
310 ASSERT(!event.registered);
311 ASSERT(!event.IsBeingUsed());
312 event.kevent = events_interface.CreateEvent(fmt::format("NVCTRL::NvEvent_{}", event_id));
313 event.status = EventState::Available;
314 event.registered = true;
315 const u64 mask = 1ULL << event_id;
316 event.fails = 0;
317 events_mask |= mask;
318 event.assigned_syncpt = 0;
319}
320
321void nvhost_ctrl::FreeNvEvent(u32 event_id) {
322 auto& event = events[event_id];
323 ASSERT(event.kevent);
324 ASSERT(event.registered);
325 ASSERT(!event.IsBeingUsed());
326 events_interface.FreeEvent(event.kevent);
327 event.kevent = nullptr;
328 event.status = EventState::Available;
329 event.registered = false;
330 const u64 mask = ~(1ULL << event_id);
331 events_mask &= mask;
332}
333
334u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) {
335 u32 slot{MaxNvEvents};
336 u32 free_slot{MaxNvEvents};
337 for (u32 i = 0; i < MaxNvEvents; i++) {
338 auto& event = events[i];
339 if (event.registered) {
340 if (!event.IsBeingUsed()) {
341 slot = i;
342 if (event.assigned_syncpt == syncpoint_id) {
343 return slot;
344 }
345 }
346 } else if (free_slot == MaxNvEvents) {
347 free_slot = i;
348 }
349 }
350 if (free_slot < MaxNvEvents) {
351 CreateNvEvent(free_slot);
352 return free_slot;
353 }
354
355 if (slot < MaxNvEvents) {
356 return slot;
357 }
358
359 LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event");
360 return 0;
361}
362
363void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) {
364 const u32 max = MaxNvEvents - std::countl_zero(events_mask);
365 const u32 min = std::countr_zero(events_mask);
366 for (u32 i = min; i < max; i++) {
367 auto& event = events[i];
368 if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) {
369 continue;
370 }
371 if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) ==
372 EventState::Waiting) {
373 event.kevent->GetWritableEvent().Signal();
374 }
375 event.status.store(EventState::Signalled, std::memory_order_release);
376 }
377}
378
287} // namespace Service::Nvidia::Devices 379} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 9fd46ea5f..f2fc5d047 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -53,7 +53,49 @@ public:
53 }; 53 };
54 static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); 54 static_assert(sizeof(SyncpointEventValue) == sizeof(u32));
55 55
56 void SignalNvEvent(u32 syncpoint_id, u32 value);
57
56private: 58private:
59 struct InternalEvent {
60 // Mask representing registered events
61
62 // Each kernel event associated to an NV event
63 Kernel::KEvent* kevent{};
64 // The status of the current NVEvent
65 std::atomic<EventState> status{};
66
67 // Tells the NVEvent that it has failed.
68 u32 fails{};
69 // When an NVEvent is waiting on GPU interrupt, this is the sync_point
70 // associated with it.
71 u32 assigned_syncpt{};
72 // This is the value of the GPU interrupt for which the NVEvent is waiting
73 // for.
74 u32 assigned_value{};
75
76 // Tells if an NVEvent is registered or not
77 bool registered{};
78
79 bool IsBeingUsed() {
80 const auto current_status = status.load(std::memory_order_acquire);
81 return current_status == EventState::Waiting ||
82 current_status == EventState::Cancelling ||
83 current_status == EventState::Signalling;
84 }
85 };
86
87 std::unique_lock<std::mutex> NvEventsLock();
88
89 void CreateNvEvent(u32 event_id);
90
91 void FreeNvEvent(u32 event_id);
92
93 u32 FindFreeNvEvent(u32 syncpoint_id);
94
95 std::array<InternalEvent, MaxNvEvents> events{};
96 std::mutex events_mutex;
97 u64 events_mask{};
98
57 struct IocSyncptReadParams { 99 struct IocSyncptReadParams {
58 u32_le id{}; 100 u32_le id{};
59 u32_le value{}; 101 u32_le value{};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index e353408eb..ced57dfe6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -13,10 +13,13 @@ namespace Service::Nvidia::Devices {
13 13
14nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) 14nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)
15 : nvdevice{system_}, events_interface{events_interface_} { 15 : nvdevice{system_}, events_interface{events_interface_} {
16 error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); 16 error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier");
17 unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); 17 unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent");
18}
19nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
20 events_interface.FreeEvent(error_notifier_event);
21 events_interface.FreeEvent(unknown_event);
18} 22}
19nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
20 23
21NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 24NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& output) { 25 std::vector<u8>& output) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index e7921ade2..cb54ee5a4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -30,13 +30,17 @@ nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_,
30 channel_fence.id = syncpoint_manager.AllocateSyncpoint(); 30 channel_fence.id = syncpoint_manager.AllocateSyncpoint();
31 channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id); 31 channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);
32 sm_exception_breakpoint_int_report_event = 32 sm_exception_breakpoint_int_report_event =
33 events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); 33 events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt");
34 sm_exception_breakpoint_pause_report_event = 34 sm_exception_breakpoint_pause_report_event =
35 events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); 35 events_interface.CreateEvent("GpuChannelSMExceptionBreakpointPause");
36 error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); 36 error_notifier_event = events_interface.CreateEvent("GpuChannelErrorNotifier");
37} 37}
38 38
39nvhost_gpu::~nvhost_gpu() = default; 39nvhost_gpu::~nvhost_gpu() {
40 events_interface.FreeEvent(sm_exception_breakpoint_int_report_event);
41 events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event);
42 events_interface.FreeEvent(error_notifier_event);
43}
40 44
41NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 45NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
42 std::vector<u8>& output) { 46 std::vector<u8>& output) {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index aa1a00832..00947ea19 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -10,6 +10,8 @@
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12 12
13u32 nvhost_nvdec::next_id{};
14
13nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core) 15nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core)
14 : nvhost_nvdec_common{system_, core} {} 16 : nvhost_nvdec_common{system_, core} {}
15nvhost_nvdec::~nvhost_nvdec() = default; 17nvhost_nvdec::~nvhost_nvdec() = default;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index fef4b3216..3261ce1d4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -24,7 +24,7 @@ public:
24 void OnClose(DeviceFD fd) override; 24 void OnClose(DeviceFD fd) override;
25 25
26private: 26private:
27 u32 next_id{}; 27 static u32 next_id;
28}; 28};
29 29
30} // namespace Service::Nvidia::Devices 30} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index e76c9e5ed..77e6a1cd6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -45,6 +45,8 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
45} 45}
46} // Anonymous namespace 46} // Anonymous namespace
47 47
48std::unordered_map<DeviceFD, u32> nvhost_nvdec_common::fd_to_id{};
49
48nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_) 50nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_)
49 : nvdevice{system_}, core{core_}, 51 : nvdevice{system_}, core{core_},
50 syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {} 52 syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()} {}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 74231d5c5..53029af6a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -115,7 +115,7 @@ protected:
115 115
116 Kernel::KEvent* QueryEvent(u32 event_id) override; 116 Kernel::KEvent* QueryEvent(u32 event_id) override;
117 117
118 std::unordered_map<DeviceFD, u32> fd_to_id{}; 118 static std::unordered_map<DeviceFD, u32> fd_to_id;
119 s32_le nvmap_fd{}; 119 s32_le nvmap_fd{};
120 u32_le submit_timeout{}; 120 u32_le submit_timeout{};
121 NvCore::Container& core; 121 NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 358e89aa8..c89ff6b27 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -8,6 +8,9 @@
8#include "video_core/renderer_base.h" 8#include "video_core/renderer_base.h"
9 9
10namespace Service::Nvidia::Devices { 10namespace Service::Nvidia::Devices {
11
12u32 nvhost_vic::next_id{};
13
11nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core) 14nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core)
12 : nvhost_nvdec_common{system_, core} {} 15 : nvhost_nvdec_common{system_, core} {}
13 16
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index 252b1e6f2..59e23b41e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -23,6 +23,6 @@ public:
23 void OnClose(DeviceFD fd) override; 23 void OnClose(DeviceFD fd) override;
24 24
25private: 25private:
26 u32 next_id{}; 26 static u32 next_id;
27}; 27};
28} // namespace Service::Nvidia::Devices 28} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index f4914d539..ff8c7c13c 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -3,7 +3,6 @@
3// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3 3// SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3
4// or any later version Refer to the license.txt file included. 4// or any later version Refer to the license.txt file included.
5 5
6#include <bit>
7#include <utility> 6#include <utility>
8 7
9#include <fmt/format.h> 8#include <fmt/format.h>
@@ -30,101 +29,39 @@
30 29
31namespace Service::Nvidia { 30namespace Service::Nvidia {
32 31
33EventInterface::EventInterface(Module& module_) : module{module_} { 32EventInterface::EventInterface(Module& module_) : module{module_} {}
34 events_mask = 0;
35 for (u32 i = 0; i < MaxNvEvents; i++) {
36 status[i] = EventState::Available;
37 events[i] = nullptr;
38 registered[i] = false;
39 }
40}
41 33
42EventInterface::~EventInterface() { 34EventInterface::~EventInterface() = default;
43 auto lk = Lock();
44 for (u32 i = 0; i < MaxNvEvents; i++) {
45 if (registered[i]) {
46 module.service_context.CloseEvent(events[i]);
47 events[i] = nullptr;
48 registered[i] = false;
49 }
50 }
51 for (auto* event : basic_events) {
52 module.service_context.CloseEvent(event);
53 }
54}
55 35
56std::unique_lock<std::mutex> EventInterface::Lock() { 36void EventInterface::RegisterForSignal(Devices::nvhost_ctrl* device) {
57 return std::unique_lock<std::mutex>(events_mutex); 37 std::unique_lock<std::mutex> lk(guard);
38 on_signal.push_back(device);
58} 39}
59 40
60void EventInterface::Signal(u32 event_id) { 41void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) {
61 if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) == 42 std::unique_lock<std::mutex> lk(guard);
62 EventState::Waiting) { 43 auto it = std::find(on_signal.begin(), on_signal.end(), device);
63 events[event_id]->GetWritableEvent().Signal(); 44 if (it != on_signal.end()) {
45 on_signal.erase(it);
64 } 46 }
65 status[event_id].store(EventState::Signalled, std::memory_order_release);
66}
67
68void EventInterface::Create(u32 event_id) {
69 ASSERT(!events[event_id]);
70 ASSERT(!registered[event_id]);
71 ASSERT(!IsBeingUsed(event_id));
72 events[event_id] =
73 module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id));
74 status[event_id] = EventState::Available;
75 registered[event_id] = true;
76 const u64 mask = 1ULL << event_id;
77 fails[event_id] = 0;
78 events_mask |= mask;
79 assigned_syncpt[event_id] = 0;
80}
81
82void EventInterface::Free(u32 event_id) {
83 ASSERT(events[event_id]);
84 ASSERT(registered[event_id]);
85 ASSERT(!IsBeingUsed(event_id));
86 module.service_context.CloseEvent(events[event_id]);
87 events[event_id] = nullptr;
88 status[event_id] = EventState::Available;
89 registered[event_id] = false;
90 const u64 mask = ~(1ULL << event_id);
91 events_mask &= mask;
92} 47}
93 48
94u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { 49void EventInterface::Signal(u32 syncpoint_id, u32 value) {
95 u32 slot{MaxNvEvents}; 50 std::unique_lock<std::mutex> lk(guard);
96 u32 free_slot{MaxNvEvents}; 51 for (auto* device : on_signal) {
97 for (u32 i = 0; i < MaxNvEvents; i++) { 52 device->SignalNvEvent(syncpoint_id, value);
98 if (registered[i]) {
99 if (!IsBeingUsed(i)) {
100 slot = i;
101 if (assigned_syncpt[i] == syncpoint_id) {
102 return slot;
103 }
104 }
105 } else if (free_slot == MaxNvEvents) {
106 free_slot = i;
107 }
108 } 53 }
109 if (free_slot < MaxNvEvents) {
110 Create(free_slot);
111 return free_slot;
112 }
113
114 if (slot < MaxNvEvents) {
115 return slot;
116 }
117
118 LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event");
119 return 0;
120} 54}
121 55
122Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { 56Kernel::KEvent* EventInterface::CreateEvent(std::string name) {
123 Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); 57 Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name));
124 basic_events.push_back(new_event);
125 return new_event; 58 return new_event;
126} 59}
127 60
61void EventInterface::FreeEvent(Kernel::KEvent* event) {
62 module.service_context.CloseEvent(event);
63}
64
128void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 65void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
129 Core::System& system) { 66 Core::System& system) {
130 auto module_ = std::make_shared<Module>(system); 67 auto module_ = std::make_shared<Module>(system);
@@ -138,18 +75,50 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
138 75
139Module::Module(Core::System& system) 76Module::Module(Core::System& system)
140 : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { 77 : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} {
141 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, container); 78 builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) {
142 devices["/dev/nvhost-gpu"] = 79 std::shared_ptr<Devices::nvdevice> device =
143 std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); 80 std::make_shared<Devices::nvhost_as_gpu>(system, container);
144 devices["/dev/nvhost-ctrl-gpu"] = 81 return open_files.emplace(fd, device).first;
145 std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); 82 };
146 devices["/dev/nvmap"] = std::make_shared<Devices::nvmap>(system, container); 83 builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) {
147 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, container); 84 std::shared_ptr<Devices::nvdevice> device =
148 devices["/dev/nvhost-ctrl"] = 85 std::make_shared<Devices::nvhost_gpu>(system, events_interface, container);
149 std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); 86 return open_files.emplace(fd, device).first;
150 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, container); 87 };
151 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); 88 builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) {
152 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, container); 89 std::shared_ptr<Devices::nvdevice> device =
90 std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
91 return open_files.emplace(fd, device).first;
92 };
93 builders["/dev/nvmap"] = [this, &system](DeviceFD fd) {
94 std::shared_ptr<Devices::nvdevice> device =
95 std::make_shared<Devices::nvmap>(system, container);
96 return open_files.emplace(fd, device).first;
97 };
98 builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) {
99 std::shared_ptr<Devices::nvdevice> device =
100 std::make_shared<Devices::nvdisp_disp0>(system, container);
101 return open_files.emplace(fd, device).first;
102 };
103 builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) {
104 std::shared_ptr<Devices::nvdevice> device =
105 std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container);
106 return open_files.emplace(fd, device).first;
107 };
108 builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) {
109 std::shared_ptr<Devices::nvdevice> device =
110 std::make_shared<Devices::nvhost_nvdec>(system, container);
111 return open_files.emplace(fd, device).first;
112 };
113 builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) {
114 std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system);
115 return open_files.emplace(fd, device).first;
116 };
117 builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) {
118 std::shared_ptr<Devices::nvdevice> device =
119 std::make_shared<Devices::nvhost_vic>(system, container);
120 return open_files.emplace(fd, device).first;
121 };
153} 122}
154 123
155Module::~Module() = default; 124Module::~Module() = default;
@@ -169,18 +138,18 @@ NvResult Module::VerifyFD(DeviceFD fd) const {
169} 138}
170 139
171DeviceFD Module::Open(const std::string& device_name) { 140DeviceFD Module::Open(const std::string& device_name) {
172 if (devices.find(device_name) == devices.end()) { 141 auto it = builders.find(device_name);
142 if (it == builders.end()) {
173 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); 143 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
174 return INVALID_NVDRV_FD; 144 return INVALID_NVDRV_FD;
175 } 145 }
176 146
177 auto device = devices[device_name];
178 const DeviceFD fd = next_fd++; 147 const DeviceFD fd = next_fd++;
148 auto& builder = it->second;
149 auto device = builder(fd)->second;
179 150
180 device->OnOpen(fd); 151 device->OnOpen(fd);
181 152
182 open_files[fd] = std::move(device);
183
184 return fd; 153 return fd;
185} 154}
186 155
@@ -256,14 +225,7 @@ NvResult Module::Close(DeviceFD fd) {
256} 225}
257 226
258void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { 227void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
259 const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); 228 events_interface.Signal(syncpoint_id, value);
260 const u32 min = std::countr_zero(events_interface.events_mask);
261 for (u32 i = min; i < max; i++) {
262 if (events_interface.assigned_syncpt[i] == syncpoint_id &&
263 events_interface.assigned_value[i] == value) {
264 events_interface.Signal(i);
265 }
266 }
267} 229}
268 230
269NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) { 231NvResult Module::QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event) {
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 96adf2ffb..3983794bb 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -5,6 +5,7 @@
5 5
6#pragma once 6#pragma once
7 7
8#include <functional>
8#include <memory> 9#include <memory>
9#include <string> 10#include <string>
10#include <unordered_map> 11#include <unordered_map>
@@ -38,7 +39,8 @@ class SyncpointManager;
38 39
39namespace Devices { 40namespace Devices {
40class nvdevice; 41class nvdevice;
41} 42class nvhost_ctrl;
43} // namespace Devices
42 44
43class Module; 45class Module;
44 46
@@ -47,47 +49,19 @@ public:
47 EventInterface(Module& module_); 49 EventInterface(Module& module_);
48 ~EventInterface(); 50 ~EventInterface();
49 51
50 // Mask representing registered events 52 void RegisterForSignal(Devices::nvhost_ctrl*);
51 u64 events_mask{}; 53 void UnregisterForSignal(Devices::nvhost_ctrl*);
52 // Each kernel event associated to an NV event
53 std::array<Kernel::KEvent*, MaxNvEvents> events{};
54 // The status of the current NVEvent
55 std::array<std::atomic<EventState>, MaxNvEvents> status{};
56 // Tells if an NVEvent is registered or not
57 std::array<bool, MaxNvEvents> registered{};
58 // Tells the NVEvent that it has failed.
59 std::array<u32, MaxNvEvents> fails{};
60 // When an NVEvent is waiting on GPU interrupt, this is the sync_point
61 // associated with it.
62 std::array<u32, MaxNvEvents> assigned_syncpt{};
63 // This is the value of the GPU interrupt for which the NVEvent is waiting
64 // for.
65 std::array<u32, MaxNvEvents> assigned_value{};
66 // Constant to denote an unasigned syncpoint.
67 static constexpr u32 unassigned_syncpt = 0xFFFFFFFF;
68
69 bool IsBeingUsed(u32 event_id) {
70 const auto current_status = status[event_id].load(std::memory_order_acquire);
71 return current_status == EventState::Waiting || current_status == EventState::Cancelling ||
72 current_status == EventState::Signalling;
73 }
74
75 std::unique_lock<std::mutex> Lock();
76
77 void Signal(u32 event_id);
78
79 void Create(u32 event_id);
80 54
81 void Free(u32 event_id); 55 void Signal(u32 syncpoint_id, u32 value);
82 56
83 u32 FindFreeEvent(u32 syncpoint_id); 57 Kernel::KEvent* CreateEvent(std::string name);
84 58
85 Kernel::KEvent* CreateNonCtrlEvent(std::string name); 59 void FreeEvent(Kernel::KEvent* event);
86 60
87private: 61private:
88 std::mutex events_mutex;
89 Module& module; 62 Module& module;
90 std::vector<Kernel::KEvent*> basic_events; 63 std::mutex guard;
64 std::list<Devices::nvhost_ctrl*> on_signal;
91}; 65};
92 66
93class Module final { 67class Module final {
@@ -97,9 +71,9 @@ public:
97 71
98 /// Returns a pointer to one of the available devices, identified by its name. 72 /// Returns a pointer to one of the available devices, identified by its name.
99 template <typename T> 73 template <typename T>
100 std::shared_ptr<T> GetDevice(const std::string& name) { 74 std::shared_ptr<T> GetDevice(DeviceFD fd) {
101 auto itr = devices.find(name); 75 auto itr = open_files.find(fd);
102 if (itr == devices.end()) 76 if (itr == open_files.end())
103 return nullptr; 77 return nullptr;
104 return std::static_pointer_cast<T>(itr->second); 78 return std::static_pointer_cast<T>(itr->second);
105 } 79 }
@@ -132,8 +106,9 @@ private:
132 /// Id to use for the next open file descriptor. 106 /// Id to use for the next open file descriptor.
133 DeviceFD next_fd = 1; 107 DeviceFD next_fd = 1;
134 108
109 using FilesContainerType = std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>>;
135 /// Mapping of file descriptors to the devices they reference. 110 /// Mapping of file descriptors to the devices they reference.
136 std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; 111 FilesContainerType open_files;
137 112
138 /// Mapping of device node names to their implementation. 113 /// Mapping of device node names to their implementation.
139 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; 114 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
@@ -147,6 +122,7 @@ private:
147 122
148 void CreateEvent(u32 event_id); 123 void CreateEvent(u32 event_id);
149 void FreeEvent(u32 event_id); 124 void FreeEvent(u32 event_id);
125 std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
150}; 126};
151 127
152/// Registers all NVDRV services with the specified service manager. 128/// Registers all NVDRV services with the specified service manager.
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 4246e5e25..8c3013f83 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -105,10 +105,15 @@ NVFlinger::~NVFlinger() {
105 display.GetLayer(layer).Core().NotifyShutdown(); 105 display.GetLayer(layer).Core().NotifyShutdown();
106 } 106 }
107 } 107 }
108
109 if (nvdrv) {
110 nvdrv->Close(disp_fd);
111 }
108} 112}
109 113
110void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 114void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
111 nvdrv = std::move(instance); 115 nvdrv = std::move(instance);
116 disp_fd = nvdrv->Open("/dev/nvdisp_disp0");
112} 117}
113 118
114std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { 119std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
@@ -276,7 +281,7 @@ void NVFlinger::Compose() {
276 // Now send the buffer to the GPU for drawing. 281 // Now send the buffer to the GPU for drawing.
277 // TODO(Subv): Support more than just disp0. The display device selection is probably based 282 // TODO(Subv): Support more than just disp0. The display device selection is probably based
278 // on which display we're drawing (Default, Internal, External, etc) 283 // on which display we're drawing (Default, Internal, External, etc)
279 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); 284 auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
280 ASSERT(nvdisp); 285 ASSERT(nvdisp);
281 286
282 Common::Rectangle<int> crop_rect{ 287 Common::Rectangle<int> crop_rect{
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3bbe5d92b..b62615de2 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -116,6 +116,7 @@ private:
116 void SplitVSync(std::stop_token stop_token); 116 void SplitVSync(std::stop_token stop_token);
117 117
118 std::shared_ptr<Nvidia::Module> nvdrv; 118 std::shared_ptr<Nvidia::Module> nvdrv;
119 s32 disp_fd;
119 120
120 std::list<VI::Display> displays; 121 std::list<VI::Display> displays;
121 122