blob: 674f909899fc6989eedcdb7875ea01ac8e92d913 [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.
#ifndef SRC_GRAPHICS_DRIVERS_MISC_GOLDFISH_ADDRESS_SPACE_ADDRESS_SPACE_DEVICE_H_
#define SRC_GRAPHICS_DRIVERS_MISC_GOLDFISH_ADDRESS_SPACE_ADDRESS_SPACE_DEVICE_H_
#include <fuchsia/hardware/goldfish/llcpp/fidl.h>
#include <lib/mmio/mmio.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/bti.h>
#include <lib/zx/pmt.h>
#include <zircon/types.h>
#include <map>
#include <ddk/device.h>
#include <ddk/io-buffer.h>
#include <ddktl/device.h>
#include <ddktl/protocol/goldfish/addressspace.h>
#include <ddktl/protocol/pci.h>
#include <fbl/mutex.h>
namespace goldfish {
class AddressSpaceDevice;
using DeviceType = ddk::Device<AddressSpaceDevice, ddk::Messageable>;
class AddressSpaceChildDriver;
using ChildDriverType = ddk::Device<AddressSpaceChildDriver, ddk::Messageable>;
class AddressSpaceDevice
: public DeviceType,
public ddk::GoldfishAddressSpaceProtocol<AddressSpaceDevice, ddk::base_protocol>,
public llcpp::fuchsia::hardware::goldfish::AddressSpaceDevice::Interface {
public:
static zx_status_t Create(void* ctx, zx_device_t* parent);
explicit AddressSpaceDevice(zx_device_t* parent);
~AddressSpaceDevice();
zx_status_t Bind();
uint32_t AllocateBlock(uint64_t* size, uint64_t* offset);
uint32_t DeallocateBlock(uint64_t offset);
zx_status_t PinBlock(uint64_t offset, uint64_t size, zx_paddr_t* paddr, zx::pmt* pmt,
zx::vmo* vmo);
zx_status_t CreateChildDriver(ddk::IoBuffer* io_buffer, uint32_t* handle);
uint32_t DestroyChildDriver(uint32_t handle);
uint32_t ChildDriverPing(uint32_t handle);
// |ddk.protocol.GoldfishAddressSpace|
zx_status_t GoldfishAddressSpaceOpenChildDriver(address_space_child_driver_type_t type,
zx::channel request) {
return OpenChildDriver(
static_cast<llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverType>(type),
std::move(request));
}
// |llcpp::fuchsia::hardware::goldfish::AddressSpaceDevice::Interface|
void OpenChildDriver(llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverType type,
zx::channel request, OpenChildDriverCompleter::Sync completer) override {
zx_status_t result = OpenChildDriver(type, std::move(request));
completer.Close(result);
}
// Device protocol implementation.
void DdkRelease();
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
private:
zx_status_t OpenChildDriver(llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverType type,
zx::channel request);
uint32_t CommandMmioLocked(uint32_t cmd) TA_REQ(mmio_lock_);
ddk::PciProtocolClient pci_;
zx::bti bti_;
zx::vmo dma_region_;
uint64_t dma_region_paddr_;
fbl::Mutex mmio_lock_;
std::optional<ddk::MmioBuffer> mmio_ TA_GUARDED(mmio_lock_);
DISALLOW_COPY_ASSIGN_AND_MOVE(AddressSpaceDevice);
};
class AddressSpaceChildDriver
: public ChildDriverType,
public llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriver::Interface {
public:
explicit AddressSpaceChildDriver(
llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverType type,
AddressSpaceDevice* device, uint64_t dma_region_paddr, ddk::IoBuffer&& io_buffer,
uint32_t child_device_handle);
// AddressSpaceChildDriver is destroyed when the fidl channel it binds to
// is disconnected by the client (the goldfish Vulkan ICD) when the client
// gets destroyed.
// This destructor unpins all the pinned memory when it destroys the block
// maps. Client (ICD) guarantees that all the blocks allocated / claimed
// by this device (including host-visible memory, user-space ring buffers)
// will not be accessed anymore after the ICD is destoryed, so it's safe
// to unpin the memory.
~AddressSpaceChildDriver();
zx_status_t Bind();
// |llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriver::Interface|
void AllocateBlock(uint64_t size, AllocateBlockCompleter::Sync completer) override;
void DeallocateBlock(uint64_t paddr, DeallocateBlockCompleter::Sync completer) override;
void ClaimSharedBlock(uint64_t offset, uint64_t size,
ClaimSharedBlockCompleter::Sync completer) override;
void UnclaimSharedBlock(uint64_t offset, UnclaimSharedBlockCompleter::Sync completer) override;
void Ping(llcpp::fuchsia::hardware::goldfish::AddressSpaceChildDriverPingMessage ping,
PingCompleter::Sync completer) override;
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
void DdkRelease();
struct Block {
public:
Block(uint64_t offset, uint64_t size, zx::pmt pmt);
~Block();
uint64_t offset;
uint64_t size;
zx::pmt pmt;
};
private:
AddressSpaceDevice* const device_;
const uint64_t dma_region_paddr_;
ddk::IoBuffer io_buffer_;
const uint32_t handle_;
// TODO(TC-383): This should be std::unordered_map.
using BlockMap = std::map<uint64_t, Block>;
BlockMap allocated_blocks_;
BlockMap claimed_blocks_;
DISALLOW_COPY_ASSIGN_AND_MOVE(AddressSpaceChildDriver);
};
} // namespace goldfish
#endif // SRC_GRAPHICS_DRIVERS_MISC_GOLDFISH_ADDRESS_SPACE_ADDRESS_SPACE_DEVICE_H_