blob: 452c1ffb3c3fa655bed34ad6d18c7c7c050eec01 [file]
// Copyright 2020 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/magma.h>
#include <lib/magma/util/short_macros.h>
#include <lib/magma/util/utils.h>
#include <lib/magma_client/test_util/inflight_list.h>
#include <lib/magma_client/test_util/magma_map_cpu.h>
#include <lib/magma_client/test_util/test_device_helper.h>
#include <magma_intel_gen_defs.h>
#include <thread>
#include <vector>
#include <gtest/gtest.h>
namespace {
constexpr uint64_t kMapFlags = MAGMA_MAP_FLAG_READ | MAGMA_MAP_FLAG_WRITE | MAGMA_MAP_FLAG_EXECUTE;
const size_t kPageSize = zx_system_get_page_size();
class TestConnection : public magma::TestDeviceBase {
public:
TestConnection() : magma::TestDeviceBase(MAGMA_VENDOR_ID_INTEL) {
magma_device_create_connection(device(), &connection_);
magma_status_t status = magma_device_query(device(), kMagmaIntelGenQueryExtraPageCount, nullptr,
&extra_page_count_);
if (status != MAGMA_STATUS_OK) {
fprintf(stderr, "Failed to query kMagmaIntelGenQueryExtraPageCount: %d\n", status);
extra_page_count_ = 0;
}
}
~TestConnection() {
if (connection_)
magma_connection_release(connection_);
}
void CheckWorkarounds(uint32_t register_offset, uint32_t expected_value) {
ASSERT_TRUE(connection_);
uint32_t context_id;
ASSERT_EQ(MAGMA_STATUS_OK, magma_connection_create_context(connection_, &context_id));
ASSERT_EQ(MAGMA_STATUS_OK, magma_connection_flush(connection_));
uint64_t size;
magma_buffer_t batch_buffer;
magma_buffer_id_t batch_buffer_id;
magma_buffer_t result_buffer;
magma_buffer_id_t result_buffer_id;
ASSERT_EQ(MAGMA_STATUS_OK, magma_connection_create_buffer(connection_, kPageSize, &size,
&batch_buffer, &batch_buffer_id));
ASSERT_EQ(MAGMA_STATUS_OK, magma_connection_create_buffer(connection_, kPageSize, &size,
&result_buffer, &result_buffer_id));
EXPECT_EQ(MAGMA_STATUS_OK, magma_connection_map_buffer(connection_, gpu_addr_, batch_buffer, 0,
magma::page_size(), kMapFlags));
gpu_addr_ += (1 + extra_page_count_) * kPageSize;
EXPECT_EQ(MAGMA_STATUS_OK, magma_connection_map_buffer(connection_, gpu_addr_, result_buffer, 0,
magma::page_size(), kMapFlags));
EXPECT_TRUE(InitBatchBuffer(batch_buffer, size, register_offset, gpu_addr_));
EXPECT_TRUE(ClearBuffer(result_buffer, size, 0xabcd1234));
magma_command_descriptor descriptor;
magma_exec_command_buffer command_buffer;
std::vector<magma_exec_resource> exec_resources;
EXPECT_TRUE(InitCommand(&descriptor, &command_buffer, &exec_resources, batch_buffer_id,
kPageSize, result_buffer_id, kPageSize));
EXPECT_EQ(MAGMA_STATUS_OK,
magma_connection_execute_command(connection_, context_id, &descriptor));
{
magma::InflightList list;
static constexpr int64_t kOneSecondInNs = 1000000000;
magma::Status status = list.WaitForCompletion(connection_, kOneSecondInNs);
EXPECT_EQ(MAGMA_STATUS_OK, status.get());
}
uint32_t result;
EXPECT_TRUE(ReadBufferAt(result_buffer, size, 0, &result));
EXPECT_EQ(expected_value, result)
<< " expected: 0x" << std::hex << expected_value << " got: 0x" << result;
magma_connection_release_buffer(connection_, result_buffer);
magma_connection_release_buffer(connection_, batch_buffer);
magma_connection_release_context(connection_, context_id);
ASSERT_EQ(MAGMA_STATUS_OK, magma_connection_flush(connection_));
}
bool ReadBufferAt(magma_buffer_t buffer, size_t size, uint32_t dword_offset,
uint32_t* result_out) {
void* vaddr;
if (!magma::MapCpuHelper(buffer, 0 /*offset*/, size, &vaddr))
return DRETF(false, "MapCpuHelper failed");
*result_out = reinterpret_cast<uint32_t*>(vaddr)[dword_offset];
if (!magma::UnmapCpuHelper(vaddr, size))
return DRETF(false, "UnmapCpuHelper failed");
return true;
}
bool ClearBuffer(magma_buffer_t buffer, size_t size, uint32_t value) {
void* vaddr;
if (!magma::MapCpuHelper(buffer, 0 /*offset*/, size, &vaddr))
return DRETF(false, "CpuMapHelper failed");
for (uint32_t i = 0; i < size / sizeof(uint32_t); i++) {
reinterpret_cast<uint32_t*>(vaddr)[i] = value;
}
if (!magma::UnmapCpuHelper(vaddr, size))
return DRETF(false, "UnmapCpuHelper failed");
return true;
}
bool InitBatchBuffer(magma_buffer_t buffer, size_t size, uint32_t register_offset,
uint64_t target_gpu_addr) {
void* vaddr;
if (!magma::MapCpuHelper(buffer, 0 /*offset*/, size, &vaddr))
return DRETF(false, "MapCpuHelper failed");
memset(vaddr, 0, size);
{
auto batch_ptr = reinterpret_cast<uint32_t*>(vaddr);
*batch_ptr++ = (0 << 29) // command type: MI_COMMAND
| (0x24 << 23) // command opcode: MI_STORE_REGISTER_MEM
| (2 << 0); // number of dwords - 2
*batch_ptr++ = register_offset;
*batch_ptr++ = magma::lower_32_bits(target_gpu_addr);
*batch_ptr++ = magma::upper_32_bits(target_gpu_addr);
*batch_ptr++ = (0 << 29) // command type: MI_COMMAND
| (0xA << 23); // command opcode: MI_BATCH_BUFFER_END
}
if (!magma::UnmapCpuHelper(vaddr, size))
return DRETF(false, "UnmapCpuHelper failed");
return true;
}
bool InitCommand(magma_command_descriptor* descriptor, magma_exec_command_buffer* command_buffer,
std::vector<magma_exec_resource>* exec_resources,
magma_buffer_id_t batch_buffer_id, uint64_t batch_buffer_size,
magma_buffer_id_t result_buffer_id, uint64_t result_buffer_size) {
exec_resources->clear();
exec_resources->push_back(
{.buffer_id = batch_buffer_id, .offset = 0, .length = batch_buffer_size});
exec_resources->push_back(
{.buffer_id = result_buffer_id, .offset = 0, .length = result_buffer_size});
command_buffer->resource_index = 0;
command_buffer->start_offset = 0;
descriptor->resource_count = static_cast<uint32_t>(exec_resources->size());
descriptor->command_buffer_count = 1;
descriptor->wait_semaphore_count = 0;
descriptor->signal_semaphore_count = 0;
descriptor->resources = exec_resources->data(), descriptor->command_buffers = command_buffer,
descriptor->semaphore_ids = nullptr;
descriptor->flags = 0;
return true;
}
private:
magma_connection_t connection_;
uint64_t extra_page_count_ = 0;
uint64_t gpu_addr_ = 0;
};
} // namespace
// TODO(https://fxbug.dev/42161918) - enable
TEST(Workarounds, DISABLED_Register0x7004) { TestConnection().CheckWorkarounds(0x7004, 0x29c2); }
TEST(Workarounds, Register0x7300) {
auto helper = magma::TestDeviceBase(0x8086);
if (helper.IsIntelGen12())
GTEST_SKIP();
TestConnection().CheckWorkarounds(0x7300, 0x810);
}