Address some regressions with UMA

This commit is contained in:
CamilleLaVey 2026-10-01 20:56:23 -04:00
parent 7db354a25a
commit 5c7520f572
6 changed files with 62 additions and 54 deletions

View file

@ -211,14 +211,19 @@ DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) {
while ((address = smmu.Allocate(aligned_up)) == 0) {
// Free handles until the allocation succeeds
std::scoped_lock queueLock(unmap_queue_lock);
if (auto freeHandleDesc{unmap_queue.front()}) {
// Handles in the unmap queue are guaranteed not to be pinned so don't bother
// checking if they are before unmapping
std::scoped_lock freeLock(freeHandleDesc->mutex);
if (handle_description->d_address)
UnmapHandle(*freeHandleDesc);
} else {
if (unmap_queue.empty()) {
LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!");
return 0;
}
// Handles in the unmap queue are guaranteed not to be pinned so don't bother
// checking if they are before unmapping
const std::shared_ptr<Handle> freeHandleDesc = unmap_queue.front();
std::scoped_lock freeLock(freeHandleDesc->mutex);
if (freeHandleDesc->d_address) {
UnmapHandle(*freeHandleDesc);
} else {
unmap_queue.pop_front();
freeHandleDesc->unmap_queue_entry.reset();
}
}

View file

@ -233,9 +233,9 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
if (allocation.page_size != params.page_size || allocation.size != (u64(params.pages) * params.page_size))
return NvResult::BadValue;
for (const auto mapping_offset : allocation.mappings)
if (!FreeMappingLocked(mapping_offset))
return NvResult::BadValue;
for (const auto mapping_offset : allocation.mappings) {
void(FreeMappingLocked(mapping_offset));
}
// Unset sparse flag if required
if (allocation.sparse)
@ -375,39 +375,16 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
mapping_map.insert_or_assign(params.offset, Mapping(params.handle, device_address, params.offset, size, false, big_page, false));
}
map_buffer_offsets.insert(params.offset);
return NvResult::Success;
}
NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
LOG_DEBUG(Service_NVDRV, "called, offset={:#x}", params.offset);
std::scoped_lock lock(mutex);
if (auto const offset_it = map_buffer_offsets.find(params.offset); offset_it != map_buffer_offsets.end()) {
LOG_DEBUG(Service_NVDRV, "called, offset={:#x}", params.offset);
if (!vm.initialised) {
return NvResult::BadValue;
}
auto const it = mapping_map.find(params.offset);
auto const mapping = it->second;
if (!mapping.fixed) {
auto& allocator{mapping.big_page ? *vm.big_page_allocator : *vm.small_page_allocator};
u32 page_size_bits{mapping.big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS};
allocator.Free(u32(mapping.offset >> page_size_bits), u32(mapping.size >> page_size_bits));
}
// Sparse mappings shouldn't be fully unmapped, just returned to their sparse state
// Only FreeSpace can unmap them fully
if (mapping.sparse_alloc) {
gmmu->MapSparse(params.offset, mapping.size, mapping.big_page);
} else {
gmmu->Unmap(params.offset, mapping.size);
}
nvmap.UnpinHandle(mapping.handle);
mapping_map.erase(params.offset);
map_buffer_offsets.erase(params.offset);
if (!vm.initialised) {
return NvResult::BadValue;
}
void(FreeMappingLocked(params.offset));
return NvResult::Success;
}

View file

@ -113,8 +113,6 @@ private:
};
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
::Common::unordered_set<s64_le> map_buffer_offsets{};
struct IoctlMapBufferEx {
MappingFlags flags{}; // bit0: fixed_offset, bit2: cacheable
u32_le kind{}; // -1 is default