blob: 99ea8cb4bfb566204a1c238e7dee8453a9343d96 [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 "no_hardware.h"
#include <memory>
#include <mutex>
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/platform-defs.h>
#include <ddktl/device.h>
#include <fuchsia/gpu/magma/c/fidl.h>
#include <hw/reg.h>
#include <lib/fidl-utils/bind.h>
#include "img-sys-device.h"
#include "magma_util/macros.h"
#include "sys_driver/magma_driver.h"
namespace {
static fuchsia_gpu_magma_Device_ops_t device_fidl_ops = {
.Query = fidl::Binder<NoHardwareGpu>::BindMember<&NoHardwareGpu::Query>,
.Connect = fidl::Binder<NoHardwareGpu>::BindMember<&NoHardwareGpu::Connect>,
.DumpState = fidl::Binder<NoHardwareGpu>::BindMember<&NoHardwareGpu::DumpState>,
.TestRestart = fidl::Binder<NoHardwareGpu>::BindMember<&NoHardwareGpu::Restart>,
};
} // namespace
NoHardwareGpu::~NoHardwareGpu()
{
std::lock_guard<std::mutex> lock(magma_mutex_);
StopMagma();
}
bool NoHardwareGpu::StartMagma()
{
magma_system_device_ = magma_driver_->CreateDevice(static_cast<ImgSysDevice*>(this));
return !!magma_system_device_;
}
void NoHardwareGpu::StopMagma()
{
if (magma_system_device_) {
magma_system_device_->Shutdown();
magma_system_device_.reset();
}
}
void NoHardwareGpu::DdkRelease() { delete this; }
zx_status_t NoHardwareGpu::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn)
{
return fuchsia_gpu_magma_Device_dispatch(this, txn, msg, &device_fidl_ops);
}
zx_status_t NoHardwareGpu::PowerUp()
{
DLOG("NoHardwareGpu::PowerUp");
return ZX_OK;
}
zx_status_t NoHardwareGpu::PowerDown()
{
DLOG("NoHardwareGpu::PowerDown()");
return ZX_OK;
}
zx_status_t NoHardwareGpu::Bind()
{
{
std::lock_guard<std::mutex> lock(magma_mutex_);
magma_driver_ = MagmaDriver::Create();
if (!magma_driver_) {
magma::log(magma::LOG_WARNING, "Failed to create MagmaDriver\n");
return ZX_ERR_INTERNAL;
}
if (!StartMagma()) {
magma::log(magma::LOG_WARNING, "Failed to start Magma system device\n");
return ZX_ERR_INTERNAL;
}
}
return DdkAdd("msd-img-rgx-no-hardware");
}
zx_status_t NoHardwareGpu::Query(uint64_t query_id, fidl_txn_t* transaction)
{
DLOG("NoHardwareGpu::Query");
std::lock_guard<std::mutex> lock(magma_mutex_);
uint64_t result;
switch (query_id) {
case MAGMA_QUERY_DEVICE_ID:
result = magma_system_device_->GetDeviceId();
break;
case MAGMA_QUERY_IS_TEST_RESTART_SUPPORTED:
result = 1;
break;
default:
if (!magma_system_device_->Query(query_id, &result))
return DRET_MSG(ZX_ERR_INVALID_ARGS, "unhandled query param 0x%" PRIx64, result);
}
DLOG("query query_id 0x%" PRIx64 " returning 0x%" PRIx64, query_id, result);
zx_status_t status = fuchsia_gpu_magma_DeviceQuery_reply(transaction, result);
if (status != ZX_OK)
return DRET_MSG(ZX_ERR_INTERNAL, "magma_DeviceQuery_reply failed: %d", status);
return ZX_OK;
}
zx_status_t NoHardwareGpu::Connect(uint64_t client_id, fidl_txn_t* transaction)
{
DLOG("NoHardwareGpu::Connect");
std::lock_guard<std::mutex> lock(magma_mutex_);
auto connection = MagmaSystemDevice::Open(magma_system_device_, client_id);
if (!connection)
return DRET_MSG(ZX_ERR_INVALID_ARGS, "MagmaSystemDevice::Open failed");
zx_status_t status = fuchsia_gpu_magma_DeviceConnect_reply(
transaction, connection->GetClientEndpoint(), connection->GetClientNotificationEndpoint());
if (status != ZX_OK)
return DRET_MSG(ZX_ERR_INTERNAL, "magma_DeviceConnect_reply failed: %d", status);
magma_system_device_->StartConnectionThread(std::move(connection));
return ZX_OK;
}
zx_status_t NoHardwareGpu::DumpState(uint32_t dump_type)
{
DLOG("NoHardwareGpu::DumpState");
std::lock_guard<std::mutex> lock(magma_mutex_);
if (dump_type & ~(MAGMA_DUMP_TYPE_NORMAL | MAGMA_DUMP_TYPE_PERF_COUNTERS |
MAGMA_DUMP_TYPE_PERF_COUNTER_ENABLE))
return DRET_MSG(ZX_ERR_INVALID_ARGS, "Invalid dump type %x", dump_type);
if (magma_system_device_)
magma_system_device_->DumpStatus(dump_type);
return ZX_OK;
}
zx_status_t NoHardwareGpu::Restart()
{
DLOG("NoHardwareGpu::Restart");
std::lock_guard<std::mutex> lock(magma_mutex_);
StopMagma();
if (!StartMagma()) {
return DRET_MSG(ZX_ERR_INTERNAL, "StartMagma failed\n");
}
return ZX_OK;
}
extern "C" zx_status_t no_hardware_gpu_bind(void* ctx, zx_device_t* parent)
{
auto dev = std::make_unique<NoHardwareGpu>(parent);
zx_status_t status = dev->Bind();
if (status == ZX_OK) {
// devmgr is now in charge of the memory for dev
dev.release();
}
return status;
}
namespace {
static zx_driver_ops_t no_hardware_gpu_driver_ops = {
.version = DRIVER_OPS_VERSION,
.init = nullptr,
.bind = no_hardware_gpu_bind,
.create = nullptr,
.release = nullptr,
};
} // namespace
// clang-format off
ZIRCON_DRIVER_BEGIN(no_hardware_gpu, no_hardware_gpu_driver_ops, "zircon", "0.1", 1)
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_TEST_PARENT),
ZIRCON_DRIVER_END(no_hardware_gpu)