blob: 649f5aae5a0ee22154822ecaaed6e8eac58be4ed [file] [log] [blame]
// Copyright 2016 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 GARNET_LIB_MAGMA_SRC_SYS_DRIVER_MAGMA_SYSTEM_DEVICE_H_
#define GARNET_LIB_MAGMA_SRC_SYS_DRIVER_MAGMA_SYSTEM_DEVICE_H_
#include "magma_system_connection.h"
#include "msd.h"
#include "platform_connection.h"
#include "platform_event.h"
#include "platform_thread.h"
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <vector>
using msd_device_unique_ptr_t = std::unique_ptr<msd_device_t, decltype(&msd_device_destroy)>;
static inline msd_device_unique_ptr_t MsdDeviceUniquePtr(msd_device_t* msd_dev)
{
return msd_device_unique_ptr_t(msd_dev, &msd_device_destroy);
}
class MagmaSystemBuffer;
class MagmaSystemSemaphore;
class MagmaSystemDevice {
public:
static std::unique_ptr<MagmaSystemDevice> Create(msd_device_unique_ptr_t msd_device)
{
msd_connection_t* connection =
msd_device_open(msd_device.get(), magma::PlatformThreadId().id());
if (!connection)
return DRETP(nullptr, "couldn't open connection");
return std::make_unique<MagmaSystemDevice>(std::move(msd_device),
MsdConnectionUniquePtr(connection));
}
MagmaSystemDevice(msd_device_unique_ptr_t msd_dev, msd_connection_unique_ptr_t msd_connection)
: msd_dev_(std::move(msd_dev)), msd_connection_(std::move(msd_connection))
{
connection_map_ = std::make_unique<std::unordered_map<std::thread::id, Connection>>();
}
// Opens a connection to the device. On success |connection_handle_out| will contain the
// connection handle to be passed to the client
static std::shared_ptr<magma::PlatformConnection>
Open(std::shared_ptr<MagmaSystemDevice>, msd_client_id_t client_id, uint32_t capabilities);
msd_device_t* msd_dev() { return msd_dev_.get(); }
// Returns the device id. 0 is invalid.
uint32_t GetDeviceId();
void PageFlip(MagmaSystemConnection* connection, std::shared_ptr<MagmaSystemBuffer> buf,
magma_system_image_descriptor* image_desc, uint32_t wait_semaphore_count,
uint32_t signal_semaphore_count,
std::vector<std::shared_ptr<MagmaSystemSemaphore>> semaphores,
std::unique_ptr<magma::PlatformSemaphore> buffer_presented_semaphore);
// Returns the last flipped buffer.
std::shared_ptr<MagmaSystemBuffer> PageFlipAndEnable(std::shared_ptr<MagmaSystemBuffer> buf,
magma_system_image_descriptor* image_desc,
bool enable);
bool page_flip_enabled() { return page_flip_enable_; }
// Takes ownership of handle and either wraps it up in new MagmaSystemBuffer or
// closes it and returns an existing MagmaSystemBuffer backed by the same memory
std::shared_ptr<MagmaSystemBuffer> ImportBuffer(uint32_t handle);
void ReleaseBuffer(uint64_t id);
// Called on driver thread
void Shutdown();
// Called on driver thread
void StartConnectionThread(std::shared_ptr<magma::PlatformConnection> platform_connection);
// Called on connection thread
void ConnectionClosed(std::thread::id thread_id);
void DumpStatus() { msd_device_dump_status(msd_dev()); }
magma::Status Query(uint32_t id, uint64_t* value_out)
{
return msd_device_query(msd_dev(), id, value_out);
}
private:
msd_device_unique_ptr_t msd_dev_;
msd_connection_unique_ptr_t msd_connection_; // for presenting buffers
std::unordered_map<uint64_t, std::weak_ptr<MagmaSystemBuffer>> buffer_map_;
std::mutex buffer_map_mutex_;
bool page_flip_enable_ = true;
std::mutex page_flip_mutex_;
struct DeferredFlip {
std::vector<std::shared_ptr<MagmaSystemSemaphore>> wait;
std::vector<std::shared_ptr<MagmaSystemSemaphore>> signal;
};
std::vector<DeferredFlip> deferred_flip_semaphores_;
std::vector<uint64_t> deferred_flip_buffers_;
std::shared_ptr<MagmaSystemBuffer> last_flipped_buffer_;
struct Connection {
std::thread thread;
std::shared_ptr<magma::PlatformEvent> shutdown_event;
};
std::unique_ptr<std::unordered_map<std::thread::id, Connection>> connection_map_;
std::mutex connection_list_mutex_;
};
#endif // GARNET_LIB_MAGMA_SRC_SYS_DRIVER_MAGMA_SYSTEM_DEVICE_H_