| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "helper/platform_device_helper.h" |
| #include "msd.h" |
| #include "platform_buffer.h" |
| #include "gtest/gtest.h" |
| |
| namespace { |
| |
| class TestMsd { |
| public: |
| ~TestMsd() |
| { |
| if (connection_) { |
| msd_connection_close(connection_); |
| } |
| if (device_) { |
| msd_device_destroy(device_); |
| } |
| if (driver_) { |
| msd_driver_destroy(driver_); |
| } |
| } |
| |
| bool Init() |
| { |
| driver_ = msd_driver_create(); |
| if (!driver_) |
| return DRETF(false, "msd_driver_create failed"); |
| |
| device_ = msd_driver_create_device(driver_, GetTestDeviceHandle()); |
| if (!device_) |
| return DRETF(false, "msd_driver_create_device failed"); |
| |
| return true; |
| } |
| |
| bool Connect() |
| { |
| connection_ = msd_device_open(device_, 0); |
| if (!connection_) |
| return DRETF(false, "msd_device_open failed"); |
| return true; |
| } |
| |
| bool CreateBuffer(uint32_t size_in_pages, msd_buffer_t** buffer_out) |
| { |
| auto platform_buf = magma::PlatformBuffer::Create(size_in_pages * PAGE_SIZE, "test"); |
| if (!platform_buf) |
| return DRETF(false, "couldn't create platform buffer size_in_pages %u", size_in_pages); |
| |
| uint32_t duplicate_handle; |
| if (!platform_buf->duplicate_handle(&duplicate_handle)) |
| return DRETF(false, "couldn't duplicate handle"); |
| |
| msd_buffer_t* buffer = msd_buffer_import(duplicate_handle); |
| if (!buffer) |
| return DRETF(false, "msd_buffer_import failed"); |
| |
| *buffer_out = buffer; |
| return true; |
| } |
| |
| msd_connection_t* connection() { return connection_; } |
| |
| private: |
| msd_driver_t* driver_ = nullptr; |
| msd_device_t* device_ = nullptr; |
| msd_connection_t* connection_ = nullptr; |
| }; |
| |
| } // namespace |
| |
| TEST(MsdBuffer, ImportAndDestroy) |
| { |
| auto platform_buf = magma::PlatformBuffer::Create(4096, "test"); |
| ASSERT_NE(platform_buf, nullptr); |
| |
| uint32_t duplicate_handle; |
| ASSERT_TRUE(platform_buf->duplicate_handle(&duplicate_handle)); |
| |
| auto msd_buffer = msd_buffer_import(duplicate_handle); |
| ASSERT_NE(msd_buffer, nullptr); |
| |
| msd_buffer_destroy(msd_buffer); |
| } |
| |
| TEST(MsdBuffer, MapAndUnmap) |
| { |
| msd_driver_t* driver = msd_driver_create(); |
| ASSERT_TRUE(driver); |
| |
| std::unique_ptr<magma::PlatformHandle> buffer_handle; |
| msd_buffer_t* buffer = nullptr; |
| |
| constexpr uint32_t kBufferSizeInPages = 1; |
| |
| { |
| auto platform_buf = magma::PlatformBuffer::Create(kBufferSizeInPages * PAGE_SIZE, "test"); |
| ASSERT_TRUE(platform_buf); |
| |
| uint32_t raw_handle; |
| EXPECT_TRUE(platform_buf->duplicate_handle(&raw_handle)); |
| buffer_handle = magma::PlatformHandle::Create(raw_handle); |
| ASSERT_TRUE(buffer_handle); |
| |
| EXPECT_TRUE(platform_buf->duplicate_handle(&raw_handle)); |
| buffer = msd_buffer_import(raw_handle); |
| ASSERT_TRUE(buffer); |
| } |
| |
| // There should be at least two handles, the msd buffer and the "checker handle". |
| uint32_t handle_count; |
| EXPECT_TRUE(buffer_handle->GetCount(&handle_count)); |
| EXPECT_GE(2u, handle_count); |
| |
| msd_device_t* device = msd_driver_create_device(driver, GetTestDeviceHandle()); |
| ASSERT_TRUE(device); |
| |
| msd_connection_t* connection = msd_device_open(device, 0); |
| ASSERT_TRUE(connection); |
| |
| std::vector<uint64_t> gpu_addr{0, PAGE_SIZE * 1024}; |
| |
| // Mapping should keep alive the msd buffer. |
| for (uint32_t i = 0; i < gpu_addr.size(); i++) { |
| EXPECT_EQ(MAGMA_STATUS_OK, msd_connection_map_buffer_gpu(connection, buffer, |
| gpu_addr[i], // gpu addr |
| 0, // page offset |
| kBufferSizeInPages, // page count |
| MAGMA_GPU_MAP_FLAG_READ | |
| MAGMA_GPU_MAP_FLAG_WRITE)); |
| } |
| |
| // Verify we haven't lost any handles. |
| EXPECT_TRUE(buffer_handle->GetCount(&handle_count)); |
| EXPECT_GE(2u, handle_count); |
| |
| // Try to unmap a region that doesn't exist. |
| EXPECT_NE(MAGMA_STATUS_OK, |
| msd_connection_unmap_buffer_gpu(connection, buffer, PAGE_SIZE * 2048)); |
| |
| // Unmap the valid regions. |
| magma_status_t status; |
| for (uint32_t i = 0; i < gpu_addr.size(); i++) { |
| status = msd_connection_unmap_buffer_gpu(connection, buffer, gpu_addr[i]); |
| EXPECT_TRUE(status == MAGMA_STATUS_UNIMPLEMENTED || status == MAGMA_STATUS_OK); |
| } |
| |
| if (status != MAGMA_STATUS_OK) { |
| // If unmap unsupported, mappings should be released here. |
| msd_connection_release_buffer(connection, buffer); |
| } |
| |
| // Mapping should keep alive the msd buffer. |
| for (uint32_t i = 0; i < gpu_addr.size(); i++) { |
| EXPECT_EQ(MAGMA_STATUS_OK, msd_connection_map_buffer_gpu(connection, buffer, |
| gpu_addr[i], // gpu addr |
| 0, // page offset |
| kBufferSizeInPages, // page count |
| MAGMA_GPU_MAP_FLAG_READ | |
| MAGMA_GPU_MAP_FLAG_WRITE)); |
| } |
| |
| msd_buffer_destroy(buffer); |
| msd_connection_close(connection); |
| msd_device_destroy(device); |
| msd_driver_destroy(driver); |
| } |
| |
| TEST(MsdBuffer, MapAndAutoUnmap) |
| { |
| msd_driver_t* driver = msd_driver_create(); |
| ASSERT_TRUE(driver); |
| |
| std::unique_ptr<magma::PlatformHandle> buffer_handle; |
| msd_buffer_t* buffer = nullptr; |
| |
| constexpr uint32_t kBufferSizeInPages = 1; |
| |
| { |
| auto platform_buf = magma::PlatformBuffer::Create(kBufferSizeInPages * PAGE_SIZE, "test"); |
| ASSERT_TRUE(platform_buf); |
| |
| uint32_t raw_handle; |
| EXPECT_TRUE(platform_buf->duplicate_handle(&raw_handle)); |
| buffer_handle = magma::PlatformHandle::Create(raw_handle); |
| ASSERT_TRUE(buffer_handle); |
| |
| EXPECT_TRUE(platform_buf->duplicate_handle(&raw_handle)); |
| buffer = msd_buffer_import(raw_handle); |
| ASSERT_TRUE(buffer); |
| } |
| |
| // There should be at least two handles, the msd buffer and the "checker handle". |
| uint32_t handle_count; |
| EXPECT_TRUE(buffer_handle->GetCount(&handle_count)); |
| EXPECT_GE(2u, handle_count); |
| |
| msd_device_t* device = msd_driver_create_device(driver, GetTestDeviceHandle()); |
| ASSERT_TRUE(device); |
| |
| msd_connection_t* connection = msd_device_open(device, 0); |
| ASSERT_TRUE(connection); |
| |
| // Mapping should keep alive the msd buffer. |
| EXPECT_EQ(MAGMA_STATUS_OK, |
| msd_connection_map_buffer_gpu(connection, buffer, |
| 0, // gpu addr |
| 0, // page offset |
| kBufferSizeInPages, // page count |
| MAGMA_GPU_MAP_FLAG_READ | MAGMA_GPU_MAP_FLAG_WRITE)); |
| |
| // Verify we haven't lost any handles. |
| EXPECT_TRUE(buffer_handle->GetCount(&handle_count)); |
| EXPECT_GE(2u, handle_count); |
| |
| // Mapping auto released either here... |
| msd_connection_release_buffer(connection, buffer); |
| |
| // OR here. |
| msd_buffer_destroy(buffer); |
| |
| // Buffer should be now be released. |
| EXPECT_TRUE(buffer_handle->GetCount(&handle_count)); |
| EXPECT_EQ(1u, handle_count); |
| |
| msd_connection_close(connection); |
| msd_device_destroy(device); |
| msd_driver_destroy(driver); |
| } |
| |
| TEST(MsdBuffer, Commit) |
| { |
| msd_driver_t* driver = msd_driver_create(); |
| ASSERT_TRUE(driver); |
| |
| constexpr uint32_t kBufferSizeInPages = 1; |
| |
| auto platform_buf = magma::PlatformBuffer::Create(kBufferSizeInPages * PAGE_SIZE, "test"); |
| ASSERT_NE(platform_buf, nullptr); |
| |
| uint32_t duplicate_handle; |
| ASSERT_TRUE(platform_buf->duplicate_handle(&duplicate_handle)); |
| |
| msd_buffer_t* buffer = msd_buffer_import(duplicate_handle); |
| ASSERT_TRUE(buffer); |
| |
| msd_device_t* device = msd_driver_create_device(driver, GetTestDeviceHandle()); |
| ASSERT_TRUE(device); |
| |
| msd_connection_t* connection = msd_device_open(device, 0); |
| ASSERT_TRUE(connection); |
| |
| // Bad offset |
| magma_status_t status; |
| status = msd_connection_commit_buffer(connection, buffer, |
| kBufferSizeInPages, // page offset |
| 1 // page count |
| ); |
| EXPECT_NE(MAGMA_STATUS_OK, status); |
| |
| // Bad page count |
| status = msd_connection_commit_buffer(connection, buffer, |
| 0, // page offset |
| kBufferSizeInPages + 1 // page count |
| ); |
| EXPECT_NE(MAGMA_STATUS_OK, status); |
| |
| // Full |
| status = msd_connection_commit_buffer(connection, buffer, |
| 0, // page offset |
| kBufferSizeInPages // page count |
| ); |
| EXPECT_TRUE(status == MAGMA_STATUS_OK || status == MAGMA_STATUS_UNIMPLEMENTED); |
| |
| // Partial |
| status = msd_connection_commit_buffer(connection, buffer, |
| 0, // page offset |
| 1 // page count |
| ); |
| EXPECT_TRUE(status == MAGMA_STATUS_OK || status == MAGMA_STATUS_UNIMPLEMENTED); |
| |
| msd_buffer_destroy(buffer); |
| msd_connection_close(connection); |
| msd_device_destroy(device); |
| msd_driver_destroy(driver); |
| } |
| |
| TEST(MsdBuffer, MapDoesntFit) |
| { |
| TestMsd test; |
| ASSERT_TRUE(test.Init()); |
| ASSERT_TRUE(test.Connect()); |
| |
| constexpr uint32_t kBufferSizeInPages = 2; |
| |
| msd_buffer_t* buffer; |
| ASSERT_TRUE(test.CreateBuffer(kBufferSizeInPages, &buffer)); |
| |
| constexpr uint64_t kGpuAddressSpaceSize = 1ull << 48; |
| magma_status_t status = msd_connection_map_buffer_gpu( |
| test.connection(), buffer, |
| kGpuAddressSpaceSize - kBufferSizeInPages / 2 * PAGE_SIZE, // gpu addr |
| 0, // page offset |
| kBufferSizeInPages, // page count |
| MAGMA_GPU_MAP_FLAG_READ | MAGMA_GPU_MAP_FLAG_WRITE); |
| EXPECT_TRUE(status == MAGMA_STATUS_INVALID_ARGS || status == MAGMA_STATUS_INTERNAL_ERROR); |
| |
| msd_buffer_destroy(buffer); |
| } |