blob: 54d631f348e2f6aade4c22054a11b75672224188 [file] [log] [blame]
// Copyright 2019 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 "garnet/drivers/gpu/msd-vsl-gc/src/address_space.h"
#include "garnet/drivers/gpu/msd-vsl-gc/src/ringbuffer.h"
#include "gtest/gtest.h"
#include "mock/mock_bus_mapper.h"
class RingbufferTest : public ::testing::Test {
public:
class MockAddressSpaceOwner : public magma::AddressSpaceOwner {
public:
// Put bus addresses close to the 40 bit limit
MockAddressSpaceOwner() : bus_mapper_((1ul << (40 - 1))) {}
magma::PlatformBusMapper* GetBusMapper() override { return &bus_mapper_; }
private:
MockBusMapper bus_mapper_;
};
static uint32_t* vaddr(Ringbuffer* ringbuffer) { return ringbuffer->vaddr(); }
};
TEST_F(RingbufferTest, Map) {
const uint32_t kRingbufferSize = magma::page_size();
auto ringbuffer = std::make_unique<Ringbuffer>(
MsdVslBuffer::Create(kRingbufferSize, "ringbuffer"), 0 /* start_offset */);
EXPECT_NE(ringbuffer, nullptr);
MockAddressSpaceOwner owner;
std::shared_ptr<AddressSpace> address_space = AddressSpace::Create(&owner);
ASSERT_NE(nullptr, address_space);
EXPECT_TRUE(ringbuffer->Map(address_space));
}
TEST_F(RingbufferTest, OffsetPopulatedEmpty) {
const uint32_t kRingbufferSize = 4096;
const uint32_t kStartOffset = 0;
auto ringbuffer = std::make_unique<Ringbuffer>(
MsdVslBuffer::Create(kRingbufferSize, "ringbuffer"), kStartOffset);
ASSERT_NE(ringbuffer, nullptr);
EXPECT_FALSE(ringbuffer->IsOffsetPopulated(0));
EXPECT_FALSE(ringbuffer->IsOffsetPopulated(4096));
}
TEST_F(RingbufferTest, OffsetPopulatedHeadBeforeTail) {
const uint32_t kRingbufferSize = 4096;
const uint32_t kStartOffset = 40;
auto ringbuffer = std::make_unique<Ringbuffer>(
MsdVslBuffer::Create(kRingbufferSize, "ringbuffer"), kStartOffset);
ASSERT_NE(ringbuffer, nullptr);
ringbuffer->update_tail(100);
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(40));
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(60));
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(96));
EXPECT_FALSE(ringbuffer->IsOffsetPopulated(100));
}
TEST_F(RingbufferTest, OffsetPopulatedTailBeforeHead) {
const uint32_t kRingbufferSize = 4096;
const uint32_t kStartOffset = 4000;
auto ringbuffer = std::make_unique<Ringbuffer>(
MsdVslBuffer::Create(kRingbufferSize, "ringbuffer"), kStartOffset);
ASSERT_NE(ringbuffer, nullptr);
ringbuffer->update_tail(100);
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(4000));
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(4092));
EXPECT_FALSE(ringbuffer->IsOffsetPopulated(4096));
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(0));
EXPECT_TRUE(ringbuffer->IsOffsetPopulated(96));
EXPECT_FALSE(ringbuffer->IsOffsetPopulated(100));
}
TEST_F(RingbufferTest, ReserveContiguous) {
const uint32_t kRingbufferSize = magma::page_size();
const uint32_t kStartOffset = 0;
auto ringbuffer = std::make_unique<Ringbuffer>(
MsdVslBuffer::Create(kRingbufferSize, "ringbuffer"), kStartOffset);
EXPECT_NE(ringbuffer, nullptr);
MockAddressSpaceOwner owner;
std::shared_ptr<AddressSpace> address_space = AddressSpace::Create(&owner);
ASSERT_NE(nullptr, address_space);
EXPECT_TRUE(ringbuffer->Map(address_space));
// Cannot request the same number of bytes as the ringbuffer size,
// as the ringbuffer holds 4 bytes less.
EXPECT_FALSE(ringbuffer->ReserveContiguous(kRingbufferSize));
// Request all the space available.
EXPECT_TRUE(
ringbuffer->ReserveContiguous(kRingbufferSize - sizeof(uint32_t) /* reserve_bytes */));
EXPECT_EQ(ringbuffer->tail(), 0u); // Tail should stay the same until we write something.
// Partially fill the ringbuffer, leaving |available_bytes| free.
const uint32_t available_bytes = 5 * sizeof(uint32_t);
const uint32_t bytes_written = kRingbufferSize - available_bytes - sizeof(uint32_t);
for (unsigned int i = 0; i < bytes_written / sizeof(uint32_t); i++) {
ringbuffer->Write32(0xFFFFFFFF /* value */);
}
EXPECT_EQ(ringbuffer->tail(), bytes_written);
// Ringbuffer state (# = occupied, x = unusable)
//
// Contents: | ####################################### | |x|
// Offset: HEAD (0) TAIL (4072) END
// Request slightly more space than is available.
EXPECT_FALSE(ringbuffer->ReserveContiguous(available_bytes + sizeof(uint32_t)));
// Request all the space available.
EXPECT_TRUE(ringbuffer->ReserveContiguous(available_bytes));
EXPECT_EQ(ringbuffer->tail(), bytes_written);
// Free up some space in the ringbuffer.
const uint32_t head_offset = 40;
ringbuffer->update_head(head_offset);
// Ringbuffer state
//
// Contents: | |x| ######################### | |
// Offset: START HEAD (40) TAIL (4072) END
// As the head is no longer at 0, we can write an additional 4 bytes contiguously.
EXPECT_TRUE(ringbuffer->ReserveContiguous(available_bytes + sizeof(uint32_t)));
EXPECT_EQ(ringbuffer->tail(), bytes_written);
// There are enough bytes, but not contiguously.
EXPECT_FALSE(ringbuffer->ReserveContiguous(head_offset));
// This will reset the tail to get enough contiguous bytes.
EXPECT_TRUE(ringbuffer->ReserveContiguous(head_offset - sizeof(uint32_t)));
EXPECT_EQ(ringbuffer->tail(), 0u);
}