blob: d06465f927ff1f5c53e1f2830f62929afc03c76d [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 MSD_INTEL_DEVICE_H
#define MSD_INTEL_DEVICE_H
#include <list>
#include <mutex>
#include <thread>
#include "device_request.h"
#include "engine_command_streamer.h"
#include "global_context.h"
#include "gpu_progress.h"
#include "gtt.h"
#include "interrupt_manager.h"
#include "magma_util/macros.h"
#include "magma_util/register_io.h"
#include "magma_util/thread.h"
#include "msd.h"
#include "msd_intel_connection.h"
#include "msd_intel_pci_device.h"
#include "platform_semaphore.h"
#include "platform_trace.h"
#include "sequencer.h"
class MsdIntelDevice : public msd_device_t,
public EngineCommandStreamer::Owner,
public Gtt::Owner,
public InterruptManager::Owner,
public MsdIntelConnection::Owner {
public:
using DeviceRequest = DeviceRequest<MsdIntelDevice>;
// Creates a device for the given |device_handle| and returns ownership.
// If |start_device_thread| is false, then StartDeviceThread should be called
// to enable device request processing.
static std::unique_ptr<MsdIntelDevice> Create(void* device_handle, bool start_device_thread);
virtual ~MsdIntelDevice();
// This takes ownership of the connection so that ownership can be
// transferred across the MSD ABI by the caller
std::unique_ptr<MsdIntelConnection> Open(msd_client_id_t client_id);
uint32_t device_id() { return device_id_; }
uint32_t revision() { return revision_; }
uint32_t subslice_total() { return subslice_total_; }
uint32_t eu_total() { return eu_total_; }
static MsdIntelDevice* cast(msd_device_t* dev)
{
DASSERT(dev);
DASSERT(dev->magic_ == kMagic);
return static_cast<MsdIntelDevice*>(dev);
}
bool Init(void* device_handle);
struct DumpState {
struct RenderCommandStreamer {
uint32_t sequence_number;
uint64_t active_head_pointer;
std::vector<MappedBatch*> inflight_batches;
} render_cs;
bool fault_present;
uint8_t fault_engine;
uint8_t fault_src;
uint8_t fault_type;
uint64_t fault_gpu_address;
bool global;
};
void Dump(DumpState* dump_state);
void DumpToString(std::string& dump_string);
void DumpStatusToLog();
private:
MsdIntelDevice();
#define CHECK_THREAD_IS_CURRENT(x) \
if (x) \
DASSERT(magma::ThreadIdCheck::IsCurrent(*x))
#define CHECK_THREAD_NOT_CURRENT(x) \
if (x) \
DASSERT(!magma::ThreadIdCheck::IsCurrent(*x))
// EngineCommandStreamer::Owner
magma::RegisterIo* register_io() override
{
CHECK_THREAD_IS_CURRENT(device_thread_id_);
DASSERT(register_io_);
return register_io_.get();
}
// InterruptManager::Owner
magma::RegisterIo* register_io_for_interrupt() override
{
DASSERT(register_io_);
return register_io_.get();
}
magma::PlatformPciDevice* platform_device() override
{
DASSERT(platform_device_);
return platform_device_.get();
}
// EngineCommandStreamer::Owner
Sequencer* sequencer() override
{
CHECK_THREAD_IS_CURRENT(device_thread_id_);
DASSERT(sequencer_);
return sequencer_.get();
}
// EngineCommandStreamer::Owner
HardwareStatusPage* hardware_status_page(EngineCommandStreamerId id) override;
void batch_submitted(uint32_t sequence_number) override
{
DASSERT(progress_);
progress_->Submitted(sequence_number, std::chrono::steady_clock::now());
}
// MsdIntelConnection::Owner
magma::Status SubmitBatch(std::unique_ptr<MappedBatch> batch) override;
void DestroyContext(std::shared_ptr<ClientContext> client_context) override;
magma::PlatformBusMapper* GetBusMapper() override { return bus_mapper_.get(); }
void StartDeviceThread();
void Destroy();
bool BaseInit(void* device_handle);
bool RenderEngineInit(bool exec_init_batch);
bool RenderEngineReset();
bool InitContextForRender(MsdIntelContext* context);
void ProcessCompletedCommandBuffers();
void HangCheckTimeout();
magma::Status ProcessBatch(std::unique_ptr<MappedBatch> batch);
magma::Status ProcessDestroyContext(std::shared_ptr<ClientContext> client_context);
magma::Status ProcessReleaseBuffer(std::shared_ptr<AddressSpace> address_space,
std::shared_ptr<MsdIntelBuffer> buffer);
magma::Status ProcessInterrupts(uint64_t interrupt_time_ns, uint32_t master_interrupt_control,
uint32_t render_interrupt_status);
magma::Status ProcessDumpStatusToLog();
void EnqueueDeviceRequest(std::unique_ptr<DeviceRequest> request, bool enqueue_front = false);
bool WaitIdle();
uint32_t GetCurrentFrequency();
void RequestMaxFreq();
static void DumpFault(DumpState* dump_out, uint32_t fault);
static void DumpFaultAddress(DumpState* dump_out, magma::RegisterIo* register_io);
void FormatDump(DumpState& dump_state, std::string& dump_string);
int DeviceThreadLoop();
void FrequencyMonitorDeviceThreadLoop();
static void InterruptCallback(void* data, uint32_t master_interrupt_control);
void QuerySliceInfo(uint32_t* subslice_total_out, uint32_t* eu_total_out);
std::shared_ptr<GlobalContext> global_context() { return global_context_; }
RenderEngineCommandStreamer* render_engine_cs() { return render_engine_cs_.get(); }
std::shared_ptr<AddressSpace> gtt() { return gtt_; }
std::shared_ptr<magma::PlatformBuffer> scratch_buffer() { return scratch_buffer_; }
static const uint32_t kMagic = 0x64657669; //"devi"
uint32_t device_id_{};
uint32_t revision_{};
uint32_t subslice_total_{};
uint32_t eu_total_{};
std::thread device_thread_;
std::thread freq_monitor_device_thread_;
std::unique_ptr<magma::PlatformThreadId> device_thread_id_;
std::atomic_bool device_thread_quit_flag_{false};
std::unique_ptr<GpuProgress> progress_;
std::unique_ptr<MsdIntelPciDevice> platform_device_;
std::unique_ptr<magma::RegisterIo> register_io_;
std::shared_ptr<Gtt> gtt_;
std::unique_ptr<RenderEngineCommandStreamer> render_engine_cs_;
std::shared_ptr<GlobalContext> global_context_;
std::unique_ptr<Sequencer> sequencer_;
std::shared_ptr<magma::PlatformBuffer> scratch_buffer_;
std::unique_ptr<InterruptManager> interrupt_manager_;
std::unique_ptr<magma::PlatformBusMapper> bus_mapper_;
class BatchRequest;
class DestroyContextRequest;
class ReleaseBufferRequest;
class InterruptRequest;
class DumpRequest;
// Thread-shared data members
std::unique_ptr<magma::PlatformSemaphore> device_request_semaphore_;
std::mutex device_request_mutex_;
std::list<std::unique_ptr<DeviceRequest>> device_request_list_;
struct FreqMonitorContext {
std::unique_ptr<magma::PlatformSemaphore> semaphore{magma::PlatformSemaphore::Create()};
std::atomic_bool tracing_enabled{false};
};
std::shared_ptr<FreqMonitorContext> freq_monitor_context_;
std::unique_ptr<magma::PlatformTraceObserver> trace_observer_;
friend class TestMsdIntelDevice;
friend class TestCommandBuffer;
friend class TestExec;
};
#endif // MSD_INTEL_DEVICE_H