blob: 7afabd8dd4fe2994ddd1f4a82bb7f51f36e79e3d [file] [edit]
// Copyright 2018 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 <lib/magma_service/mock/mock_bus_mapper.h>
#include <lib/magma_service/test_util/msd_stubs.h>
#include <gtest/gtest.h>
#include "src/graphics/drivers/msd-vsi-vip/src/address_space_layout.h"
#include "src/graphics/drivers/msd-vsi-vip/src/mapped_batch.h"
#include "src/graphics/drivers/msd-vsi-vip/src/msd_vsi_connection.h"
class TestMsdVsiConnection : public ::testing::Test, public MsdVsiConnection::Owner {
public:
Ringbuffer* GetRingbuffer() override { return nullptr; }
magma::Status SubmitBatch(std::unique_ptr<MappedBatch> batch, bool do_flush) override {
return MAGMA_STATUS_UNIMPLEMENTED;
}
void SetUp() override {
static constexpr uint32_t kAddressSpaceIndex = 1;
address_space_ = AddressSpace::Create(&mock_address_space_owner_, kAddressSpaceIndex);
EXPECT_NE(address_space_, nullptr);
connection_ = std::make_shared<MsdVsiConnection>(this, address_space_, 0 /* client_id */);
EXPECT_NE(connection_, nullptr);
}
protected:
class MockAddressSpaceOwner : public AddressSpace::Owner {
public:
MockAddressSpaceOwner() : bus_mapper_((1ul << (20 - 1))) {}
magma::PlatformBusMapper* GetBusMapper() override { return &bus_mapper_; }
void AddressSpaceReleased(AddressSpace* address_space) override {}
private:
MockBusMapper bus_mapper_;
};
class TestNotificationHandler : public msd::testing::StubNotificationHandler {
public:
TestNotificationHandler(uint32_t& callback_count) : callback_count_(callback_count) {}
// msd::NotificationHandler implementation.
void ContextKilled() override { callback_count_++; }
private:
uint32_t& callback_count_;
};
std::shared_ptr<MsdVsiConnection> connection_;
MockAddressSpaceOwner mock_address_space_owner_;
std::shared_ptr<AddressSpace> address_space_;
uint32_t callback_count_ = 0;
};
TEST_F(TestMsdVsiConnection, MapBufferGpu) {
constexpr uint64_t kBufferSizeInPages = 1;
constexpr uint64_t kGpuAddr = 0x10000;
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
EXPECT_EQ(MAGMA_STATUS_OK,
connection_->MapBufferGpu(buffer, kGpuAddr, 0, kBufferSizeInPages).get());
std::shared_ptr<GpuMapping> mapping = address_space_->FindGpuMapping(kGpuAddr);
ASSERT_NE(mapping, nullptr);
EXPECT_EQ(mapping->BufferId(), buffer->platform_buffer()->id());
}
TEST_F(TestMsdVsiConnection, ReleaseMapping) {
constexpr uint64_t kBufferSizeInPages = 2;
constexpr uint64_t kGpuAddr1 = 0x10000;
constexpr uint64_t kGpuAddr2 = 0x20000;
TestNotificationHandler notification(callback_count_);
connection_->SetNotificationCallback(&notification);
// Add separate mappings for the buffer's pages.
// Add the first mapping.
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
std::shared_ptr<GpuMapping> mapping1;
EXPECT_TRUE(AddressSpace::MapBufferGpu(address_space_, buffer, kGpuAddr1, 0, 1 /* page_count */,
&mapping1));
ASSERT_TRUE(mapping1);
EXPECT_TRUE(address_space_->AddMapping(mapping1));
// Add the second mapping.
std::shared_ptr<GpuMapping> mapping2;
EXPECT_TRUE(AddressSpace::MapBufferGpu(address_space_, buffer, kGpuAddr2, 0, 1 /* page_count */,
&mapping2));
ASSERT_TRUE(mapping2);
EXPECT_TRUE(address_space_->AddMapping(mapping2));
// Release our reference to the first mapping before calling |ReleaseMapping|.
mapping1.reset();
EXPECT_TRUE(connection_->ReleaseMapping(buffer->platform_buffer(), kGpuAddr1));
EXPECT_EQ(0u, callback_count_);
const std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>>& mappings1 =
connection_->mappings_to_release();
EXPECT_EQ(1u, mappings1.size());
// Calling |ReleaseMapping| while holding a reference to the mapping triggers the killed callback
EXPECT_TRUE(connection_->ReleaseMapping(buffer->platform_buffer(), kGpuAddr2));
EXPECT_EQ(1u, callback_count_);
const std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>>& mappings2 =
connection_->mappings_to_release();
// Still holds the first mapping.
EXPECT_EQ(1u, mappings2.size());
}
TEST_F(TestMsdVsiConnection, ReleaseBuffer) {
constexpr uint64_t kBufferSizeInPages = 1;
constexpr uint64_t kGpuAddr = 0x10000;
TestNotificationHandler notification(callback_count_);
connection_->SetNotificationCallback(&notification);
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(AddressSpace::MapBufferGpu(address_space_, buffer, kGpuAddr, 0, kBufferSizeInPages,
&mapping));
ASSERT_TRUE(mapping);
EXPECT_TRUE(address_space_->AddMapping(mapping));
mapping.reset();
connection_->ReleaseBuffer(buffer->platform_buffer());
EXPECT_EQ(0u, callback_count_);
const std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>>& mappings =
connection_->mappings_to_release();
EXPECT_EQ(1u, mappings.size());
}
TEST_F(TestMsdVsiConnection, ReleaseBufferWhileMapped) {
constexpr uint64_t kBufferSizeInPages = 1;
constexpr uint64_t kGpuAddr = 0x10000;
TestNotificationHandler notification(callback_count_);
connection_->SetNotificationCallback(&notification);
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
std::shared_ptr<GpuMapping> mapping;
EXPECT_TRUE(AddressSpace::MapBufferGpu(address_space_, buffer, kGpuAddr, 0, kBufferSizeInPages,
&mapping));
ASSERT_TRUE(mapping);
EXPECT_TRUE(address_space_->AddMapping(mapping));
// Releasing the buffer while holding the mapping triggers the killed callback
connection_->ReleaseBuffer(buffer->platform_buffer());
EXPECT_EQ(1u, callback_count_);
const std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>>& mappings =
connection_->mappings_to_release();
EXPECT_EQ(0u, mappings.size());
}
TEST_F(TestMsdVsiConnection, AddressSpaceDirty) {
constexpr uint64_t kBufferSizeInPages = 1;
constexpr uint64_t kGpuAddr = 0x10000;
EXPECT_FALSE(connection_->address_space_dirty());
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
EXPECT_EQ(MAGMA_STATUS_OK,
connection_->MapBufferGpu(buffer, kGpuAddr, 0, kBufferSizeInPages).get());
EXPECT_TRUE(connection_->address_space_dirty());
EXPECT_EQ(MAGMA_STATUS_UNIMPLEMENTED,
connection_->SubmitBatch(std::make_unique<NullBatch>()).get());
EXPECT_FALSE(connection_->address_space_dirty());
}
// Tests that the client can map only within the client reserved region.
TEST_F(TestMsdVsiConnection, OnlyMapAllowedGpuAddresses) {
constexpr uint64_t kBufferSizeInPages = 2;
std::shared_ptr<MsdVsiBuffer> buffer =
MsdVsiBuffer::Create(kBufferSizeInPages * magma::page_size(), "test");
// Test mapping at the beginning of the client reserved region.
uint32_t gpu_addr = AddressSpaceLayout::client_gpu_addr_base();
EXPECT_EQ(MAGMA_STATUS_OK,
connection_->MapBufferGpu(buffer, gpu_addr, 0, kBufferSizeInPages).get());
// Test mapping at the end of the client reserved region.
uint32_t client_reserved_gpu_addr_end = AddressSpaceLayout::client_gpu_addr_base() +
AddressSpaceLayout::client_gpu_addr_size() -
magma::page_size();
gpu_addr = client_reserved_gpu_addr_end - (kBufferSizeInPages * magma::page_size());
EXPECT_EQ(MAGMA_STATUS_OK,
connection_->MapBufferGpu(buffer, gpu_addr, 0, kBufferSizeInPages).get());
// Test mapping that extends beyond the end of the client reserved region.
gpu_addr = client_reserved_gpu_addr_end - magma::page_size();
EXPECT_NE(MAGMA_STATUS_OK,
connection_->MapBufferGpu(buffer, gpu_addr, 0, kBufferSizeInPages).get());
}