blob: 5cd39dbce21f0db2461fb4d88fe8791d07621cb7 [file] [log] [blame]
// Copyright 2017 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 <fidl/fuchsia.gpu.magma/cpp/wire.h>
#include <fuchsia/hardware/intelgpucore/cpp/banjo.h>
#include <lib/ddk/binding_driver.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/magma/platform/zircon/zircon_platform_status.h>
#include <lib/magma/util/dlog.h>
#include <lib/magma_service/msd_defs.h>
#include <lib/magma_service/sys_driver/dfv1/magma_device_impl.h>
#include <lib/zx/channel.h>
#include <lib/zx/resource.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zircon/process.h>
#include <zircon/types.h>
#include <atomic>
#include <set>
#include <thread>
#include <ddktl/device.h>
#include <ddktl/fidl.h>
#include <ddktl/protocol/empty-protocol.h>
#include "msd_intel_pci_device.h"
#if MAGMA_TEST_DRIVER
zx_status_t magma_indriver_test(magma::PlatformPciDevice* platform_device);
#endif
class IntelDevice;
using DdkDeviceType =
ddk::Device<IntelDevice, msd::MagmaDeviceImpl, ddk::Unbindable, ddk::Initializable>;
class IntelDevice : public DdkDeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_GPU> {
public:
explicit IntelDevice(zx_device_t* parent_device) : DdkDeviceType(parent_device) {}
int MagmaStart() FIT_REQUIRES(magma_mutex()) {
DLOG("magma_start");
set_magma_system_device(msd::MagmaSystemDevice::Create(
magma_driver(),
magma_driver()->CreateDevice(reinterpret_cast<msd::DeviceHandle*>(&gpu_core_protocol_))));
if (!magma_system_device())
return DRET_MSG(ZX_ERR_NO_RESOURCES, "Failed to create device");
DLOG("Created device %p", magma_system_device());
InitSystemDevice();
return ZX_OK;
}
void DdkInit(ddk::InitTxn txn);
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
zx_status_t Init();
private:
intel_gpu_core_protocol_t gpu_core_protocol_;
};
void IntelDevice::DdkInit(ddk::InitTxn txn) {
set_zx_device(zxdev());
txn.Reply(InitChildDevices());
}
void IntelDevice::DdkUnbind(ddk::UnbindTxn txn) {
// This will tear down client connections and cause them to return errors.
MagmaStop();
txn.Reply();
}
void IntelDevice::DdkRelease() {
MAGMA_LOG(INFO, "Starting device_release");
delete this;
MAGMA_LOG(INFO, "Finished device_release");
}
zx_status_t IntelDevice::Init() {
ddk::IntelGpuCoreProtocolClient gpu_core_client;
zx_status_t status =
ddk::IntelGpuCoreProtocolClient::CreateFromDevice(parent(), &gpu_core_client);
if (status != ZX_OK)
return DRET_MSG(status, "device_get_protocol failed: %d", status);
gpu_core_client.GetProto(&gpu_core_protocol_);
std::lock_guard<std::mutex> lock(magma_mutex());
set_magma_driver(msd::Driver::Create());
#if MAGMA_TEST_DRIVER
DLOG("running magma indriver test");
{
auto platform_device = MsdIntelPciDevice::CreateShim(&gpu_core_protocol_);
set_unit_test_status(magma_indriver_test(platform_device.get()));
}
#endif
status = MagmaStart();
if (status != ZX_OK)
return status;
status = DdkAdd(ddk::DeviceAddArgs("magma_gpu").set_flags(DEVICE_ADD_NON_BINDABLE));
if (status != ZX_OK)
return DRET_MSG(status, "device_add failed");
return ZX_OK;
}
static zx_status_t sysdrv_bind(void* ctx, zx_device_t* parent) {
DLOG("sysdrv_bind start zx_device %p", parent);
magma::PlatformBusMapper::SetInfoResource(zx::unowned_resource(get_info_resource(parent)));
auto gpu = std::make_unique<IntelDevice>(parent);
if (!gpu)
return ZX_ERR_NO_MEMORY;
zx_status_t status = gpu->Init();
if (status != ZX_OK) {
return status;
}
// DdkAdd in Init took ownership of device.
(void)gpu.release();
DLOG("initialized magma system driver");
return ZX_OK;
}
static constexpr zx_driver_ops_t msd_driver_ops = []() {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.bind = sysdrv_bind;
return ops;
}();
ZIRCON_DRIVER(gpu, msd_driver_ops, "magma", "0.1");