diff --git a/runtime/os_interface/linux/drm_memory_manager.cpp b/runtime/os_interface/linux/drm_memory_manager.cpp index bd04b73983..6191da90f3 100644 --- a/runtime/os_interface/linux/drm_memory_manager.cpp +++ b/runtime/os_interface/linux/drm_memory_manager.cpp @@ -223,10 +223,32 @@ DrmAllocation *DrmMemoryManager::allocateGraphicsMemoryWithAlignment(const Alloc bo->setAllocationType(allocType); } + uint64_t reservedGpuAddress = 0; + size_t reserveSizeAligned = 0; + if (allocationData.type == GraphicsAllocation::AllocationType::SVM_CPU) { + //add 2MB padding in case reserved addr is not 2MB aligned + reserveSizeAligned = alignUp(cSize, cAlignment) + cAlignment; + reservedGpuAddress = GmmHelper::canonize(gfxPartition.heapAllocate(HeapIndex::HEAP_STANDARD, reserveSizeAligned)); + if (!reservedGpuAddress) { + bo->close(); + delete bo; + alignedFreeWrapper(res); + return nullptr; + } + bo->gpuAddress = alignUp(reservedGpuAddress, cAlignment); + bo->isAllocated = false; + } + emitPinningRequest(bo, allocationData); auto allocation = new DrmAllocation(allocationData.type, bo, res, bo->gpuAddress, cSize, MemoryPool::System4KBPages, allocationData.flags.multiOsContextCapable); allocation->setDriverAllocatedCpuPtr(isLimitedRange() ? res : nullptr); + + if (GraphicsAllocation::AllocationType::SVM_CPU == allocationData.type) { + allocation->setDriverAllocatedCpuPtr(res); + allocation->setReservedAddressRange(reinterpret_cast(reservedGpuAddress), reserveSizeAligned); + } + return allocation; } diff --git a/unit_tests/mocks/linux/mock_drm_memory_manager.h b/unit_tests/mocks/linux/mock_drm_memory_manager.h index ee9dc9afc8..174a7c89ea 100644 --- a/unit_tests/mocks/linux/mock_drm_memory_manager.h +++ b/unit_tests/mocks/linux/mock_drm_memory_manager.h @@ -57,6 +57,7 @@ class TestedDrmMemoryManager : public MemoryManagerCreate { using DrmMemoryManager::sharingBufferObjects; using DrmMemoryManager::supportsMultiStorageResources; using MemoryManager::allocateGraphicsMemoryInDevicePool; + using MemoryManager::useInternal32BitAllocator; TestedDrmMemoryManager(ExecutionEnvironment &executionEnvironment) : MemoryManagerCreate(gemCloseWorkerMode::gemCloseWorkerInactive, false, diff --git a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp index 1c517d8e6d..ee3ac1cbf7 100644 --- a/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp +++ b/unit_tests/os_interface/linux/drm_memory_manager_tests.cpp @@ -3124,3 +3124,55 @@ TEST_F(DrmMemoryManagerWithExplicitExpectationsTest, whenObtainFdFromHandleIsCal EXPECT_EQ(this->mock->inputFlags, DRM_CLOEXEC | DRM_RDWR); EXPECT_EQ(1337, fdHandle); } + +TEST_F(DrmMemoryManagerTest, givenSvmCpuAllocationWhenSizeAndAlignmentProvidedThenAllocateMemoryAndReserveGpuVa) { + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.gemWait = 1; + mock->ioctl_expected.gemClose = 1; + + TestedDrmMemoryManager::AllocationData allocationData; + allocationData.size = 2 * MemoryConstants::megaByte; + allocationData.alignment = 2 * MemoryConstants::megaByte; + allocationData.type = GraphicsAllocation::AllocationType::SVM_CPU; + + DrmAllocation *allocation = memoryManager->allocateGraphicsMemoryWithAlignment(allocationData); + ASSERT_NE(nullptr, allocation); + + EXPECT_EQ(GraphicsAllocation::AllocationType::SVM_CPU, allocation->getAllocationType()); + + EXPECT_EQ(allocationData.size, allocation->getUnderlyingBufferSize()); + EXPECT_NE(nullptr, allocation->getUnderlyingBuffer()); + EXPECT_EQ(allocation->getUnderlyingBuffer(), allocation->getDriverAllocatedCpuPtr()); + + EXPECT_NE(0llu, allocation->getGpuAddress()); + EXPECT_NE(reinterpret_cast(allocation->getUnderlyingBuffer()), allocation->getGpuAddress()); + + auto bo = allocation->getBO(); + ASSERT_NE(nullptr, bo); + + EXPECT_NE(0llu, bo->peekAddress()); + + EXPECT_LT(GmmHelper::canonize(memoryManager->gfxPartition.getHeapBase(HeapIndex::HEAP_STANDARD)), bo->peekAddress()); + EXPECT_GT(GmmHelper::canonize(memoryManager->gfxPartition.getHeapLimit(HeapIndex::HEAP_STANDARD)), bo->peekAddress()); + + EXPECT_EQ(reinterpret_cast(allocation->getGpuAddress()), alignUp(allocation->getReservedAddressPtr(), allocationData.alignment)); + EXPECT_EQ(alignUp(allocationData.size, allocationData.alignment) + allocationData.alignment, allocation->getReservedAddressSize()); + + memoryManager->freeGraphicsMemory(allocation); +} + +TEST_F(DrmMemoryManagerTest, givenSvmCpuAllocationWhenSizeAndAlignmentProvidedButFailsToReserveGpuVaThenNullAllocationIsReturned) { + mock->ioctl_expected.gemUserptr = 1; + mock->ioctl_expected.gemWait = 0; + mock->ioctl_expected.gemClose = 1; + + memoryManager->gfxPartition.heapInit(HeapIndex::HEAP_STANDARD, 0, 0); + + TestedDrmMemoryManager::AllocationData allocationData; + allocationData.size = 2 * MemoryConstants::megaByte; + allocationData.alignment = 2 * MemoryConstants::megaByte; + allocationData.type = GraphicsAllocation::AllocationType::SVM_CPU; + + DrmAllocation *allocation = memoryManager->allocateGraphicsMemoryWithAlignment(allocationData); + EXPECT_EQ(nullptr, allocation); +}