diff options
| author | Fernando Sahmkow <fsahmkow27@gmail.com> | 2021-11-05 01:44:11 +0100 | 
|---|---|---|
| committer | Fernando Sahmkow <fsahmkow27@gmail.com> | 2022-10-06 21:00:51 +0200 | 
| commit | af35dbcf633d35450b333eb33334b3dd1bc050a1 (patch) | |
| tree | 94e721b8a23f9659d616f70157574d6826263070 /src/core | |
| parent | de0e8eff429b4374c18e3325ad3747db55bddddd (diff) | |
NVDRV: Fix Open/Close and make sure each device is correctly created.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 176 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl.h | 42 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 174 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 56 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/nvflinger.h | 1 | 
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 @@  // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3  // or any later version Refer to the license.txt file included. +#include <bit>  #include <cstdlib>  #include <cstring> +#include <fmt/format.h>  #include "common/assert.h"  #include "common/logging/log.h"  #include "common/scope_exit.h" @@ -22,8 +24,19 @@ namespace Service::Nvidia::Devices {  nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,                           NvCore::Container& core_)      : nvdevice{system_}, events_interface{events_interface_}, core{core_}, -      syncpoint_manager{core_.GetSyncpointManager()} {} -nvhost_ctrl::~nvhost_ctrl() = default; +      syncpoint_manager{core_.GetSyncpointManager()} { +    events_interface.RegisterForSignal(this); +} + +nvhost_ctrl::~nvhost_ctrl() { +    events_interface.UnregisterForSignal(this); +    for (auto& event : events) { +        if (!event.registered) { +            continue; +        } +        events_interface.FreeEvent(event.kevent); +    } +}  NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,                               std::vector<u8>& output) { @@ -87,7 +100,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector      SCOPE_EXIT({          std::memcpy(output.data(), ¶ms, sizeof(params));          if (must_unmark_fail) { -            events_interface.fails[event_id] = 0; +            events[event_id].fails = 0;          }      }); @@ -116,12 +129,12 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector      auto& gpu = system.GPU();      const u32 target_value = params.fence.value; -    auto lock = events_interface.Lock(); +    auto lock = NvEventsLock();      u32 slot = [&]() {          if (is_allocation) {              params.value.raw = 0; -            return events_interface.FindFreeEvent(fence_id); +            return FindFreeNvEvent(fence_id);          } else {              return params.value.raw;          } @@ -130,7 +143,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector      must_unmark_fail = true;      const auto check_failing = [&]() { -        if (events_interface.fails[slot] > 2) { +        if (events[slot].fails > 2) {              {                  auto lk = system.StallProcesses();                  gpu.WaitFence(fence_id, target_value); @@ -142,6 +155,10 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector          return false;      }; +    if (slot >= MaxNvEvents) { +        return NvResult::BadParameter; +    } +      if (params.timeout == 0) {          if (check_failing()) {              return NvResult::Success; @@ -149,17 +166,13 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector          return NvResult::Timeout;      } -    if (slot >= MaxNvEvents) { -        return NvResult::BadParameter; -    } - -    auto* event = events_interface.events[slot]; +    auto& event = events[slot]; -    if (!event) { +    if (!event.registered) {          return NvResult::BadParameter;      } -    if (events_interface.IsBeingUsed(slot)) { +    if (event.IsBeingUsed()) {          return NvResult::BadParameter;      } @@ -169,9 +182,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector      params.value.raw = 0; -    events_interface.status[slot].store(EventState::Waiting, std::memory_order_release); -    events_interface.assigned_syncpt[slot] = fence_id; -    events_interface.assigned_value[slot] = target_value; +    event.status.store(EventState::Waiting, std::memory_order_release); +    event.assigned_syncpt = fence_id; +    event.assigned_value = target_value;      if (is_allocation) {          params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id));          params.value.event_allocated.Assign(1); @@ -189,15 +202,17 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {          return NvResult::BadParameter;      } -    if (!events_interface.registered[slot]) { +    auto& event = events[slot]; + +    if (!event.registered) {          return NvResult::Success;      } -    if (events_interface.IsBeingUsed(slot)) { +    if (event.IsBeingUsed()) {          return NvResult::Busy;      } -    events_interface.Free(slot); +    FreeNvEvent(slot);      return NvResult::Success;  } @@ -210,15 +225,15 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve          return NvResult::BadParameter;      } -    auto lock = events_interface.Lock(); +    auto lock = NvEventsLock(); -    if (events_interface.registered[event_id]) { +    if (events[event_id].registered) {          const auto result = FreeEvent(event_id);          if (result != NvResult::Success) {              return result;          }      } -    events_interface.Create(event_id); +    CreateNvEvent(event_id);      return NvResult::Success;  } @@ -229,7 +244,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,      const u32 event_id = params.user_event_id & 0x00FF;      LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); -    auto lock = events_interface.Lock(); +    auto lock = NvEventsLock();      return FreeEvent(event_id);  } @@ -244,44 +259,121 @@ NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::v          return NvResult::BadParameter;      } -    auto lock = events_interface.Lock(); +    auto lock = NvEventsLock(); -    if (events_interface.status[event_id].exchange( -            EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) { -        system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id], -                                           events_interface.assigned_value[event_id]); -        syncpoint_manager.RefreshSyncpoint(events_interface.assigned_syncpt[event_id]); +    auto& event = events[event_id]; +    if (event.status.exchange(EventState::Cancelling, std::memory_order_acq_rel) == +        EventState::Waiting) { +        system.GPU().CancelSyncptInterrupt(event.assigned_syncpt, event.assigned_value); +        syncpoint_manager.RefreshSyncpoint(event.assigned_syncpt);      } -    events_interface.fails[event_id]++; -    events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release); -    events_interface.events[event_id]->GetWritableEvent().Clear(); +    event.fails++; +    event.status.store(EventState::Cancelled, std::memory_order_release); +    event.kevent->GetWritableEvent().Clear();      return NvResult::Success;  }  Kernel::KEvent* nvhost_ctrl::QueryEvent(u32 event_id) { -    const auto event = SyncpointEventValue{.raw = event_id}; +    const auto desired_event = SyncpointEventValue{.raw = event_id}; -    const bool allocated = event.event_allocated.Value() != 0; -    const u32 slot{allocated ? event.partial_slot.Value() : static_cast<u32>(event.slot)}; +    const bool allocated = desired_event.event_allocated.Value() != 0; +    const u32 slot{allocated ? desired_event.partial_slot.Value() +                             : static_cast<u32>(desired_event.slot)};      if (slot >= MaxNvEvents) {          ASSERT(false);          return nullptr;      } -    const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value() -                                     : event.syncpoint_id.Value()}; +    const u32 syncpoint_id{allocated ? desired_event.syncpoint_id_for_allocation.Value() +                                     : desired_event.syncpoint_id.Value()}; -    auto lock = events_interface.Lock(); +    auto lock = NvEventsLock(); -    if (events_interface.registered[slot] && -        events_interface.assigned_syncpt[slot] == syncpoint_id) { -        ASSERT(events_interface.events[slot]); -        return events_interface.events[slot]; +    auto& event = events[slot]; +    if (event.registered && event.assigned_syncpt == syncpoint_id) { +        ASSERT(event.kevent); +        return event.kevent;      }      // Is this possible in hardware?      ASSERT_MSG(false, "Slot:{}, SyncpointID:{}, requested", slot, syncpoint_id);      return nullptr;  } +std::unique_lock<std::mutex> nvhost_ctrl::NvEventsLock() { +    return std::unique_lock<std::mutex>(events_mutex); +} + +void nvhost_ctrl::CreateNvEvent(u32 event_id) { +    auto& event = events[event_id]; +    ASSERT(!event.kevent); +    ASSERT(!event.registered); +    ASSERT(!event.IsBeingUsed()); +    event.kevent = events_interface.CreateEvent(fmt::format("NVCTRL::NvEvent_{}", event_id)); +    event.status = EventState::Available; +    event.registered = true; +    const u64 mask = 1ULL << event_id; +    event.fails = 0; +    events_mask |= mask; +    event.assigned_syncpt = 0; +} + +void nvhost_ctrl::FreeNvEvent(u32 event_id) { +    auto& event = events[event_id]; +    ASSERT(event.kevent); +    ASSERT(event.registered); +    ASSERT(!event.IsBeingUsed()); +    events_interface.FreeEvent(event.kevent); +    event.kevent = nullptr; +    event.status = EventState::Available; +    event.registered = false; +    const u64 mask = ~(1ULL << event_id); +    events_mask &= mask; +} + +u32 nvhost_ctrl::FindFreeNvEvent(u32 syncpoint_id) { +    u32 slot{MaxNvEvents}; +    u32 free_slot{MaxNvEvents}; +    for (u32 i = 0; i < MaxNvEvents; i++) { +        auto& event = events[i]; +        if (event.registered) { +            if (!event.IsBeingUsed()) { +                slot = i; +                if (event.assigned_syncpt == syncpoint_id) { +                    return slot; +                } +            } +        } else if (free_slot == MaxNvEvents) { +            free_slot = i; +        } +    } +    if (free_slot < MaxNvEvents) { +        CreateNvEvent(free_slot); +        return free_slot; +    } + +    if (slot < MaxNvEvents) { +        return slot; +    } + +    LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); +    return 0; +} + +void nvhost_ctrl::SignalNvEvent(u32 syncpoint_id, u32 value) { +    const u32 max = MaxNvEvents - std::countl_zero(events_mask); +    const u32 min = std::countr_zero(events_mask); +    for (u32 i = min; i < max; i++) { +        auto& event = events[i]; +        if (event.assigned_syncpt != syncpoint_id || event.assigned_value != value) { +            continue; +        } +        if (event.status.exchange(EventState::Signalling, std::memory_order_acq_rel) == +            EventState::Waiting) { +            event.kevent->GetWritableEvent().Signal(); +        } +        event.status.store(EventState::Signalled, std::memory_order_release); +    } +} +  } // 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:      };      static_assert(sizeof(SyncpointEventValue) == sizeof(u32)); +    void SignalNvEvent(u32 syncpoint_id, u32 value); +  private: +    struct InternalEvent { +        // Mask representing registered events + +        // Each kernel event associated to an NV event +        Kernel::KEvent* kevent{}; +        // The status of the current NVEvent +        std::atomic<EventState> status{}; + +        // Tells the NVEvent that it has failed. +        u32 fails{}; +        // When an NVEvent is waiting on GPU interrupt, this is the sync_point +        // associated with it. +        u32 assigned_syncpt{}; +        // This is the value of the GPU interrupt for which the NVEvent is waiting +        // for. +        u32 assigned_value{}; + +        // Tells if an NVEvent is registered or not +        bool registered{}; + +        bool IsBeingUsed() { +            const auto current_status = status.load(std::memory_order_acquire); +            return current_status == EventState::Waiting || +                   current_status == EventState::Cancelling || +                   current_status == EventState::Signalling; +        } +    }; + +    std::unique_lock<std::mutex> NvEventsLock(); + +    void CreateNvEvent(u32 event_id); + +    void FreeNvEvent(u32 event_id); + +    u32 FindFreeNvEvent(u32 syncpoint_id); + +    std::array<InternalEvent, MaxNvEvents> events{}; +    std::mutex events_mutex; +    u64 events_mask{}; +      struct IocSyncptReadParams {          u32_le id{};          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 {  nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)      : nvdevice{system_}, events_interface{events_interface_} { -    error_notifier_event = events_interface.CreateNonCtrlEvent("CtrlGpuErrorNotifier"); -    unknown_event = events_interface.CreateNonCtrlEvent("CtrlGpuUknownEvent"); +    error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); +    unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); +} +nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { +    events_interface.FreeEvent(error_notifier_event); +    events_interface.FreeEvent(unknown_event);  } -nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;  NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,                                   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_,      channel_fence.id = syncpoint_manager.AllocateSyncpoint();      channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);      sm_exception_breakpoint_int_report_event = -        events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointInt"); +        events_interface.CreateEvent("GpuChannelSMExceptionBreakpointInt");      sm_exception_breakpoint_pause_report_event = -        events_interface.CreateNonCtrlEvent("GpuChannelSMExceptionBreakpointPause"); -    error_notifier_event = events_interface.CreateNonCtrlEvent("GpuChannelErrorNotifier"); +        events_interface.CreateEvent("GpuChannelSMExceptionBreakpointPause"); +    error_notifier_event = events_interface.CreateEvent("GpuChannelErrorNotifier");  } -nvhost_gpu::~nvhost_gpu() = default; +nvhost_gpu::~nvhost_gpu() { +    events_interface.FreeEvent(sm_exception_breakpoint_int_report_event); +    events_interface.FreeEvent(sm_exception_breakpoint_pause_report_event); +    events_interface.FreeEvent(error_notifier_event); +}  NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,                              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 @@  namespace Service::Nvidia::Devices { +u32 nvhost_nvdec::next_id{}; +  nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core)      : nvhost_nvdec_common{system_, core} {}  nvhost_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:      void OnClose(DeviceFD fd) override;  private: -    u32 next_id{}; +    static u32 next_id;  };  } // 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  }  } // Anonymous namespace +std::unordered_map<DeviceFD, u32> nvhost_nvdec_common::fd_to_id{}; +  nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_)      : nvdevice{system_}, core{core_},        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:      Kernel::KEvent* QueryEvent(u32 event_id) override; -    std::unordered_map<DeviceFD, u32> fd_to_id{}; +    static std::unordered_map<DeviceFD, u32> fd_to_id;      s32_le nvmap_fd{};      u32_le submit_timeout{};      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 @@  #include "video_core/renderer_base.h"  namespace Service::Nvidia::Devices { + +u32 nvhost_vic::next_id{}; +  nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core)      : nvhost_nvdec_common{system_, core} {} 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:      void OnClose(DeviceFD fd) override;  private: -    u32 next_id{}; +    static u32 next_id;  };  } // 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 @@  // SPDX-License-Identifier: GPL-3.0-or-later Licensed under GPLv3  // or any later version Refer to the license.txt file included. -#include <bit>  #include <utility>  #include <fmt/format.h> @@ -30,101 +29,39 @@  namespace Service::Nvidia { -EventInterface::EventInterface(Module& module_) : module{module_} { -    events_mask = 0; -    for (u32 i = 0; i < MaxNvEvents; i++) { -        status[i] = EventState::Available; -        events[i] = nullptr; -        registered[i] = false; -    } -} +EventInterface::EventInterface(Module& module_) : module{module_} {} -EventInterface::~EventInterface() { -    auto lk = Lock(); -    for (u32 i = 0; i < MaxNvEvents; i++) { -        if (registered[i]) { -            module.service_context.CloseEvent(events[i]); -            events[i] = nullptr; -            registered[i] = false; -        } -    } -    for (auto* event : basic_events) { -        module.service_context.CloseEvent(event); -    } -} +EventInterface::~EventInterface() = default; -std::unique_lock<std::mutex> EventInterface::Lock() { -    return std::unique_lock<std::mutex>(events_mutex); +void EventInterface::RegisterForSignal(Devices::nvhost_ctrl* device) { +    std::unique_lock<std::mutex> lk(guard); +    on_signal.push_back(device);  } -void EventInterface::Signal(u32 event_id) { -    if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) == -        EventState::Waiting) { -        events[event_id]->GetWritableEvent().Signal(); +void EventInterface::UnregisterForSignal(Devices::nvhost_ctrl* device) { +    std::unique_lock<std::mutex> lk(guard); +    auto it = std::find(on_signal.begin(), on_signal.end(), device); +    if (it != on_signal.end()) { +        on_signal.erase(it);      } -    status[event_id].store(EventState::Signalled, std::memory_order_release); -} - -void EventInterface::Create(u32 event_id) { -    ASSERT(!events[event_id]); -    ASSERT(!registered[event_id]); -    ASSERT(!IsBeingUsed(event_id)); -    events[event_id] = -        module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id)); -    status[event_id] = EventState::Available; -    registered[event_id] = true; -    const u64 mask = 1ULL << event_id; -    fails[event_id] = 0; -    events_mask |= mask; -    assigned_syncpt[event_id] = 0; -} - -void EventInterface::Free(u32 event_id) { -    ASSERT(events[event_id]); -    ASSERT(registered[event_id]); -    ASSERT(!IsBeingUsed(event_id)); -    module.service_context.CloseEvent(events[event_id]); -    events[event_id] = nullptr; -    status[event_id] = EventState::Available; -    registered[event_id] = false; -    const u64 mask = ~(1ULL << event_id); -    events_mask &= mask;  } -u32 EventInterface::FindFreeEvent(u32 syncpoint_id) { -    u32 slot{MaxNvEvents}; -    u32 free_slot{MaxNvEvents}; -    for (u32 i = 0; i < MaxNvEvents; i++) { -        if (registered[i]) { -            if (!IsBeingUsed(i)) { -                slot = i; -                if (assigned_syncpt[i] == syncpoint_id) { -                    return slot; -                } -            } -        } else if (free_slot == MaxNvEvents) { -            free_slot = i; -        } +void EventInterface::Signal(u32 syncpoint_id, u32 value) { +    std::unique_lock<std::mutex> lk(guard); +    for (auto* device : on_signal) { +        device->SignalNvEvent(syncpoint_id, value);      } -    if (free_slot < MaxNvEvents) { -        Create(free_slot); -        return free_slot; -    } - -    if (slot < MaxNvEvents) { -        return slot; -    } - -    LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event"); -    return 0;  } -Kernel::KEvent* EventInterface::CreateNonCtrlEvent(std::string name) { +Kernel::KEvent* EventInterface::CreateEvent(std::string name) {      Kernel::KEvent* new_event = module.service_context.CreateEvent(std::move(name)); -    basic_events.push_back(new_event);      return new_event;  } +void EventInterface::FreeEvent(Kernel::KEvent* event) { +    module.service_context.CloseEvent(event); +} +  void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,                         Core::System& system) {      auto module_ = std::make_shared<Module>(system); @@ -138,18 +75,50 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger  Module::Module(Core::System& system)      : service_context{system, "nvdrv"}, events_interface{*this}, container{system.GPU()} { -    devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, container); -    devices["/dev/nvhost-gpu"] = -        std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); -    devices["/dev/nvhost-ctrl-gpu"] = -        std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); -    devices["/dev/nvmap"] = std::make_shared<Devices::nvmap>(system, container); -    devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, container); -    devices["/dev/nvhost-ctrl"] = -        std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); -    devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, container); -    devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); -    devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, container); +    builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_as_gpu>(system, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvmap>(system, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvdisp_disp0>(system, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_nvdec>(system, container); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system); +        return open_files.emplace(fd, device).first; +    }; +    builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { +        std::shared_ptr<Devices::nvdevice> device = +            std::make_shared<Devices::nvhost_vic>(system, container); +        return open_files.emplace(fd, device).first; +    };  }  Module::~Module() = default; @@ -169,18 +138,18 @@ NvResult Module::VerifyFD(DeviceFD fd) const {  }  DeviceFD Module::Open(const std::string& device_name) { -    if (devices.find(device_name) == devices.end()) { +    auto it = builders.find(device_name); +    if (it == builders.end()) {          LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);          return INVALID_NVDRV_FD;      } -    auto device = devices[device_name];      const DeviceFD fd = next_fd++; +    auto& builder = it->second; +    auto device = builder(fd)->second;      device->OnOpen(fd); -    open_files[fd] = std::move(device); -      return fd;  } @@ -256,14 +225,7 @@ NvResult Module::Close(DeviceFD fd) {  }  void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { -    const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask); -    const u32 min = std::countr_zero(events_interface.events_mask); -    for (u32 i = min; i < max; i++) { -        if (events_interface.assigned_syncpt[i] == syncpoint_id && -            events_interface.assigned_value[i] == value) { -            events_interface.Signal(i); -        } -    } +    events_interface.Signal(syncpoint_id, value);  }  NvResult 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 @@  #pragma once +#include <functional>  #include <memory>  #include <string>  #include <unordered_map> @@ -38,7 +39,8 @@ class SyncpointManager;  namespace Devices {  class nvdevice; -} +class nvhost_ctrl; +} // namespace Devices  class Module; @@ -47,47 +49,19 @@ public:      EventInterface(Module& module_);      ~EventInterface(); -    // Mask representing registered events -    u64 events_mask{}; -    // Each kernel event associated to an NV event -    std::array<Kernel::KEvent*, MaxNvEvents> events{}; -    // The status of the current NVEvent -    std::array<std::atomic<EventState>, MaxNvEvents> status{}; -    // Tells if an NVEvent is registered or not -    std::array<bool, MaxNvEvents> registered{}; -    // Tells the NVEvent that it has failed. -    std::array<u32, MaxNvEvents> fails{}; -    // When an NVEvent is waiting on GPU interrupt, this is the sync_point -    // associated with it. -    std::array<u32, MaxNvEvents> assigned_syncpt{}; -    // This is the value of the GPU interrupt for which the NVEvent is waiting -    // for. -    std::array<u32, MaxNvEvents> assigned_value{}; -    // Constant to denote an unasigned syncpoint. -    static constexpr u32 unassigned_syncpt = 0xFFFFFFFF; - -    bool IsBeingUsed(u32 event_id) { -        const auto current_status = status[event_id].load(std::memory_order_acquire); -        return current_status == EventState::Waiting || current_status == EventState::Cancelling || -               current_status == EventState::Signalling; -    } - -    std::unique_lock<std::mutex> Lock(); - -    void Signal(u32 event_id); - -    void Create(u32 event_id); +    void RegisterForSignal(Devices::nvhost_ctrl*); +    void UnregisterForSignal(Devices::nvhost_ctrl*); -    void Free(u32 event_id); +    void Signal(u32 syncpoint_id, u32 value); -    u32 FindFreeEvent(u32 syncpoint_id); +    Kernel::KEvent* CreateEvent(std::string name); -    Kernel::KEvent* CreateNonCtrlEvent(std::string name); +    void FreeEvent(Kernel::KEvent* event);  private: -    std::mutex events_mutex;      Module& module; -    std::vector<Kernel::KEvent*> basic_events; +    std::mutex guard; +    std::list<Devices::nvhost_ctrl*> on_signal;  };  class Module final { @@ -97,9 +71,9 @@ public:      /// Returns a pointer to one of the available devices, identified by its name.      template <typename T> -    std::shared_ptr<T> GetDevice(const std::string& name) { -        auto itr = devices.find(name); -        if (itr == devices.end()) +    std::shared_ptr<T> GetDevice(DeviceFD fd) { +        auto itr = open_files.find(fd); +        if (itr == open_files.end())              return nullptr;          return std::static_pointer_cast<T>(itr->second);      } @@ -132,8 +106,9 @@ private:      /// Id to use for the next open file descriptor.      DeviceFD next_fd = 1; +    using FilesContainerType = std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>>;      /// Mapping of file descriptors to the devices they reference. -    std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files; +    FilesContainerType open_files;      /// Mapping of device node names to their implementation.      std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; @@ -147,6 +122,7 @@ private:      void CreateEvent(u32 event_id);      void FreeEvent(u32 event_id); +    std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;  };  /// 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() {              display.GetLayer(layer).Core().NotifyShutdown();          }      } + +    if (nvdrv) { +        nvdrv->Close(disp_fd); +    }  }  void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {      nvdrv = std::move(instance); +    disp_fd = nvdrv->Open("/dev/nvdisp_disp0");  }  std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { @@ -276,7 +281,7 @@ void NVFlinger::Compose() {          // Now send the buffer to the GPU for drawing.          // TODO(Subv): Support more than just disp0. The display device selection is probably based          // on which display we're drawing (Default, Internal, External, etc) -        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); +        auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);          ASSERT(nvdisp);          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:      void SplitVSync(std::stop_token stop_token);      std::shared_ptr<Nvidia::Module> nvdrv; +    s32 disp_fd;      std::list<VI::Display> displays; | 
