summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-07 18:41:55 -0400
committerGravatar FernandoS272019-07-05 15:49:13 -0400
commite0027eba854b9cf097360e898457e164e6ae0b4d (patch)
tree3dfffe7615e1371aae0d31c98982608a62171701 /src
parentnv_services: Create GPU channels correctly (diff)
downloadyuzu-e0027eba854b9cf097360e898457e164e6ae0b4d.tar.gz
yuzu-e0027eba854b9cf097360e898457e164e6ae0b4d.tar.xz
yuzu-e0027eba854b9cf097360e898457e164e6ae0b4d.zip
nv_services: Implement NvQueryEvent, NvCtrlEventWait, NvEventRegister, NvEventUnregister
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp91
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h7
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp17
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h14
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp26
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h52
7 files changed, 192 insertions, 17 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index b39fb9ef9..ef6731a8f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -7,11 +7,15 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" 13#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
14#include "video_core/gpu.h"
11 15
12namespace Service::Nvidia::Devices { 16namespace Service::Nvidia::Devices {
13 17
14nvhost_ctrl::nvhost_ctrl() = default; 18nvhost_ctrl::nvhost_ctrl(EventsInterface& events_interface) : events_interface{events_interface} {}
15nvhost_ctrl::~nvhost_ctrl() = default; 19nvhost_ctrl::~nvhost_ctrl() = default;
16 20
17u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) { 21u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
@@ -27,6 +31,8 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
27 return IocCtrlEventWait(input, output, true); 31 return IocCtrlEventWait(input, output, true);
28 case IoctlCommand::IocCtrlEventRegisterCommand: 32 case IoctlCommand::IocCtrlEventRegisterCommand:
29 return IocCtrlEventRegister(input, output); 33 return IocCtrlEventRegister(input, output);
34 case IoctlCommand::IocCtrlEventUnregisterCommand:
35 return IocCtrlEventUnregister(input, output);
30 } 36 }
31 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 37 UNIMPLEMENTED_MSG("Unimplemented ioctl");
32 return 0; 38 return 0;
@@ -44,20 +50,85 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
44 bool is_async) { 50 bool is_async) {
45 IocCtrlEventWaitParams params{}; 51 IocCtrlEventWaitParams params{};
46 std::memcpy(&params, input.data(), sizeof(params)); 52 std::memcpy(&params, input.data(), sizeof(params));
47 LOG_WARNING(Service_NVDRV, 53 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
48 "(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}", 54 params.syncpt_id, params.threshold, params.timeout, is_async);
49 params.syncpt_id, params.threshold, params.timeout, is_async);
50 55
51 // TODO(Subv): Implement actual syncpt waiting. 56 if (params.syncpt_id >= MaxSyncPoints) {
52 params.value = 0; 57 return NvResult::BadParameter;
58 }
59
60 auto& gpu = Core::System::GetInstance().GPU();
61 u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id);
62 if (current_syncpoint_value >= params.threshold) {
63 params.value = current_syncpoint_value;
64 std::memcpy(output.data(), &params, sizeof(params));
65 return NvResult::Success;
66 }
67
68 if (!is_async) {
69 params.value = 0;
70 }
71
72 if (params.timeout == 0) {
73 std::memcpy(output.data(), &params, sizeof(params));
74 return NvResult::Timeout;
75 }
76
77 u32 event_index;
78 if (is_async) {
79 event_index = params.value;
80 if (event_index >= 64) {
81 std::memcpy(output.data(), &params, sizeof(params));
82 return NvResult::BadParameter;
83 }
84 } else {
85 event_index = events_interface.GetFreeEvent();
86 }
87
88 EventState status = events_interface.status[event_index];
89 if (event_index < MaxNvEvents || status == EventState::Free ||
90 status == EventState::Registered) {
91 events_interface.SetEventStatus(event_index, EventState::Waiting);
92 events_interface.assigned_syncpt[event_index] = params.syncpt_id;
93 events_interface.assigned_value[event_index] = params.threshold;
94 if (is_async) {
95 params.value = params.syncpt_id << 4;
96 } else {
97 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
98 }
99 params.value |= event_index;
100 gpu.RegisterEvent(event_index, params.syncpt_id, params.threshold);
101 std::memcpy(output.data(), &params, sizeof(params));
102 return NvResult::Timeout;
103 }
53 std::memcpy(output.data(), &params, sizeof(params)); 104 std::memcpy(output.data(), &params, sizeof(params));
54 return 0; 105 return NvResult::BadParameter;
55} 106}
56 107
57u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { 108u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
58 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 109 IocCtrlEventRegisterParams params{};
59 // TODO(bunnei): Implement this. 110 std::memcpy(&params, input.data(), sizeof(params));
60 return 0; 111 if (params.user_event_id >= MaxNvEvents) {
112 return NvResult::BadParameter;
113 }
114 if (events_interface.registered[params.user_event_id]) {
115 return NvResult::BadParameter;
116 }
117 events_interface.RegisterEvent(params.user_event_id);
118 return NvResult::Success;
119}
120
121u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) {
122 IocCtrlEventUnregisterParams params{};
123 std::memcpy(&params, input.data(), sizeof(params));
124 if (params.user_event_id >= MaxNvEvents) {
125 return NvResult::BadParameter;
126 }
127 if (!events_interface.registered[params.user_event_id]) {
128 return NvResult::BadParameter;
129 }
130 events_interface.UnregisterEvent(params.user_event_id);
131 return NvResult::Success;
61} 132}
62 133
63} // namespace Service::Nvidia::Devices 134} // 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 6d0de2212..2985e7f75 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -8,12 +8,13 @@
8#include <vector> 8#include <vector>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h" 10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11#include "core/hle/service/nvdrv/nvdrv.h"
11 12
12namespace Service::Nvidia::Devices { 13namespace Service::Nvidia::Devices {
13 14
14class nvhost_ctrl final : public nvdevice { 15class nvhost_ctrl final : public nvdevice {
15public: 16public:
16 nvhost_ctrl(); 17 nvhost_ctrl(EventsInterface& events_interface);
17 ~nvhost_ctrl() override; 18 ~nvhost_ctrl() override;
18 19
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 20 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
@@ -135,6 +136,10 @@ private:
135 u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async); 136 u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
136 137
137 u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output); 138 u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
139
140 u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
141
142 EventsInterface& events_interface;
138}; 143};
139 144
140} // namespace Service::Nvidia::Devices 145} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index b60fc748b..76482d16e 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -10,10 +10,15 @@
10#include "core/hle/kernel/readable_event.h" 10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h" 11#include "core/hle/kernel/writable_event.h"
12#include "core/hle/service/nvdrv/interface.h" 12#include "core/hle/service/nvdrv/interface.h"
13#include "core/hle/service/nvdrv/nvdata.h"
13#include "core/hle/service/nvdrv/nvdrv.h" 14#include "core/hle/service/nvdrv/nvdrv.h"
14 15
15namespace Service::Nvidia { 16namespace Service::Nvidia {
16 17
18void NVDRV::SignalGPUInterrupt(const u32 event_id) {
19 nvdrv->SignalEvent(event_id);
20}
21
17void NVDRV::Open(Kernel::HLERequestContext& ctx) { 22void NVDRV::Open(Kernel::HLERequestContext& ctx) {
18 LOG_DEBUG(Service_NVDRV, "called"); 23 LOG_DEBUG(Service_NVDRV, "called");
19 24
@@ -66,13 +71,19 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
66void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { 71void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
67 IPC::RequestParser rp{ctx}; 72 IPC::RequestParser rp{ctx};
68 u32 fd = rp.Pop<u32>(); 73 u32 fd = rp.Pop<u32>();
69 u32 event_id = rp.Pop<u32>(); 74 // TODO(Blinkhawk): Figure the meaning of the flag at bit 16
75 u32 event_id = rp.Pop<u32>() & 0x000000FF;
70 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); 76 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
71 77
72 IPC::ResponseBuilder rb{ctx, 3, 1}; 78 IPC::ResponseBuilder rb{ctx, 3, 1};
73 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
74 rb.PushCopyObjects(query_event.readable); 80 if (event_id < 64) {
75 rb.Push<u32>(0); 81 rb.PushCopyObjects(nvdrv->GetEvent(event_id));
82 rb.Push<u32>(NvResult::Success);
83 } else {
84 rb.Push<u32>(0);
85 rb.Push<u32>(NvResult::BadParameter);
86 }
76} 87}
77 88
78void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { 89void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 5b4889910..421b01017 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -19,6 +19,8 @@ public:
19 NVDRV(std::shared_ptr<Module> nvdrv, const char* name); 19 NVDRV(std::shared_ptr<Module> nvdrv, const char* name);
20 ~NVDRV() override; 20 ~NVDRV() override;
21 21
22 void SignalGPUInterrupt(const u32 event_id);
23
22private: 24private:
23 void Open(Kernel::HLERequestContext& ctx); 25 void Open(Kernel::HLERequestContext& ctx);
24 void Ioctl(Kernel::HLERequestContext& ctx); 26 void Ioctl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index fd5f79f36..6dbc90e4c 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -6,6 +6,7 @@
6namespace Service::Nvidia { 6namespace Service::Nvidia {
7 7
8constexpr u32 MaxSyncPoints = 192; 8constexpr u32 MaxSyncPoints = 192;
9constexpr u32 MaxNvEvents = 64;
9 10
10struct Fence { 11struct Fence {
11 s32 id; 12 s32 id;
@@ -19,9 +20,18 @@ struct MultiFence {
19 std::array<Fence, 4> fences; 20 std::array<Fence, 4> fences;
20}; 21};
21 22
22enum class NvResult : u32 { 23enum NvResult : u32 {
23 Success = 0, 24 Success = 0,
24 TryAgain = 11, 25 BadParameter = 4,
26 Timeout = 5,
27 ResourceError = 15,
28};
29
30enum class EventState {
31 Free = 0,
32 Registered = 1,
33 Waiting = 2,
34 Busy = 3,
25}; 35};
26 36
27} // namespace Service::Nvidia 37} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 6e4b8f2c6..618bcbc7c 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -4,7 +4,10 @@
4 4
5#include <utility> 5#include <utility>
6 6
7#include <fmt/format.h>
7#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
8#include "core/hle/service/nvdrv/devices/nvdevice.h" 11#include "core/hle/service/nvdrv/devices/nvdevice.h"
9#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 12#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
10#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" 13#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
@@ -33,13 +36,21 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
33} 36}
34 37
35Module::Module() { 38Module::Module() {
39 auto& kernel = Core::System::GetInstance().Kernel();
40 for (u32 i = 0; i < MaxNvEvents; i++) {
41 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
42 events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(
43 kernel, Kernel::ResetType::Automatic, event_label);
44 events_interface.status[i] = EventState::Free;
45 events_interface.registered[i] = false;
46 }
36 auto nvmap_dev = std::make_shared<Devices::nvmap>(); 47 auto nvmap_dev = std::make_shared<Devices::nvmap>();
37 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev); 48 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev);
38 devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(nvmap_dev); 49 devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(nvmap_dev);
39 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(); 50 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>();
40 devices["/dev/nvmap"] = nvmap_dev; 51 devices["/dev/nvmap"] = nvmap_dev;
41 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); 52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
42 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(); 53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(events_interface);
43 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(); 54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
44 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(); 55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>();
45 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(); 56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>();
@@ -77,4 +88,17 @@ ResultCode Module::Close(u32 fd) {
77 return RESULT_SUCCESS; 88 return RESULT_SUCCESS;
78} 89}
79 90
91void Module::SignalEvent(const u32 event_id) {
92 if (event_id >= 64) {
93 LOG_ERROR(Service_NVDRV, "Unexpected Event signalled!");
94 return;
95 }
96 events_interface.LiberateEvent(event_id);
97 events_interface.events[event_id].writable->Signal();
98}
99
100Kernel::SharedPtr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) {
101 return events_interface.events[event_id].readable;
102}
103
80} // namespace Service::Nvidia 104} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index bacd7cdb7..9a4cdc60f 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -15,12 +15,58 @@ namespace Service::NVFlinger {
15class NVFlinger; 15class NVFlinger;
16} 16}
17 17
18namespace Kernel {
19class WritableEvent;
20}
21
18namespace Service::Nvidia { 22namespace Service::Nvidia {
19 23
20namespace Devices { 24namespace Devices {
21class nvdevice; 25class nvdevice;
22} 26}
23 27
28struct EventsInterface {
29 u64 events_mask;
30 std::array<Kernel::EventPair, MaxNvEvents> events;
31 std::array<EventState, MaxNvEvents> status;
32 std::array<bool, MaxNvEvents> registered;
33 std::array<u32, MaxNvEvents> assigned_syncpt;
34 std::array<u32, MaxNvEvents> assigned_value;
35 u32 GetFreeEvent() {
36 u64 mask = events_mask;
37 for (u32 i = 0; i < MaxNvEvents; i++) {
38 if (mask & 0x1) {
39 if (status[i] == EventState::Registered || status[i] == EventState::Free) {
40 return i;
41 }
42 }
43 mask = mask >> 1;
44 }
45 return 0xFFFFFFFF;
46 }
47 void SetEventStatus(const u32 event_id, EventState new_status) {
48 status[event_id] = new_status;
49 if (new_status == EventState::Registered) {
50 registered[event_id] = true;
51 }
52 }
53 void RegisterEvent(const u32 event_id) {
54 registered[event_id] = true;
55 if (status[event_id] == EventState::Free) {
56 status[event_id] = EventState::Registered;
57 }
58 }
59 void UnregisterEvent(const u32 event_id) {
60 registered[event_id] = false;
61 if (status[event_id] == EventState::Registered) {
62 status[event_id] = EventState::Free;
63 }
64 }
65 void LiberateEvent(const u32 event_id) {
66 status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
67 }
68};
69
24class Module final { 70class Module final {
25public: 71public:
26 Module(); 72 Module();
@@ -42,6 +88,10 @@ public:
42 /// Closes a device file descriptor and returns operation success. 88 /// Closes a device file descriptor and returns operation success.
43 ResultCode Close(u32 fd); 89 ResultCode Close(u32 fd);
44 90
91 void SignalEvent(const u32 event_id);
92
93 Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent(const u32 event_id);
94
45private: 95private:
46 /// Id to use for the next open file descriptor. 96 /// Id to use for the next open file descriptor.
47 u32 next_fd = 1; 97 u32 next_fd = 1;
@@ -51,6 +101,8 @@ private:
51 101
52 /// Mapping of device node names to their implementation. 102 /// Mapping of device node names to their implementation.
53 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; 103 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
104
105 EventsInterface events_interface;
54}; 106};
55 107
56/// Registers all NVDRV services with the specified service manager. 108/// Registers all NVDRV services with the specified service manager.