| // 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. |
| |
| #ifndef MSD_ARM_DEVICE_H |
| #define MSD_ARM_DEVICE_H |
| |
| #include <zircon/compiler.h> |
| |
| #include <deque> |
| #include <list> |
| #include <mutex> |
| #include <thread> |
| #include <vector> |
| |
| #include "address_manager.h" |
| #include "device_request.h" |
| #include "gpu_features.h" |
| #include "job_scheduler.h" |
| #include "magma_util/macros.h" |
| #include "magma_util/register_io.h" |
| #include "magma_util/thread.h" |
| #include "msd.h" |
| #include "msd_arm_connection.h" |
| #include "performance_counters.h" |
| #include "platform_device.h" |
| #include "platform_interrupt.h" |
| #include "platform_semaphore.h" |
| #include "power_manager.h" |
| |
| class MsdArmDevice : public msd_device_t, |
| public JobScheduler::Owner, |
| public MsdArmConnection::Owner, |
| public AddressManager::Owner, |
| public PerformanceCounters::Owner { |
| public: |
| // 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<MsdArmDevice> Create(void* device_handle, bool start_device_thread); |
| |
| MsdArmDevice(); |
| |
| virtual ~MsdArmDevice(); |
| |
| static MsdArmDevice* cast(msd_device_t* dev) |
| { |
| DASSERT(dev); |
| DASSERT(dev->magic_ == kMagic); |
| return static_cast<MsdArmDevice*>(dev); |
| } |
| |
| bool Init(void* device_handle); |
| std::shared_ptr<MsdArmConnection> Open(msd_client_id_t client_id); |
| |
| struct DumpState { |
| struct CorePowerState { |
| const char* core_type; |
| const char* status_type; |
| uint64_t bitmask; |
| }; |
| std::vector<CorePowerState> power_states; |
| // Only accounts for recent past. |
| uint64_t total_time_ms; |
| uint64_t active_time_ms; |
| |
| uint32_t gpu_fault_status; |
| uint64_t gpu_fault_address; |
| uint32_t gpu_status; |
| uint64_t cycle_count; |
| uint64_t timestamp; |
| |
| struct JobSlotStatus { |
| uint32_t status; |
| uint64_t head; |
| uint64_t tail; |
| uint32_t config; |
| }; |
| |
| std::vector<JobSlotStatus> job_slot_status; |
| struct AddressSpaceStatus { |
| uint32_t status; |
| uint32_t fault_status; |
| uint64_t fault_address; |
| }; |
| std::vector<AddressSpaceStatus> address_space_status; |
| }; |
| static void DumpRegisters(const GpuFeatures& features, magma::RegisterIo* io, |
| DumpState* dump_state); |
| void Dump(DumpState* dump_state); |
| void DumpToString(std::string& dump_string); |
| void FormatDump(DumpState& dump_state, std::string& dump_string); |
| void DumpStatusToLog(); |
| |
| // MsdArmConnection::Owner implementation. |
| void ScheduleAtom(std::shared_ptr<MsdArmAtom> atom) override; |
| void CancelAtoms(std::shared_ptr<MsdArmConnection> connection) override; |
| AddressSpaceObserver* GetAddressSpaceObserver() override { return address_manager_.get(); } |
| ArmMaliCacheCoherencyStatus cache_coherency_status() override |
| { |
| return cache_coherency_status_; |
| } |
| magma::PlatformBusMapper* GetBusMapper() override { return bus_mapper_.get(); } |
| |
| magma_status_t QueryInfo(uint64_t id, uint64_t* value_out); |
| |
| void RequestPerfCounterOperation(uint32_t type); |
| |
| // PerformanceCounters::Owner implementation. |
| AddressManager* address_manager() override { return address_manager_.get(); } |
| MsdArmConnection::Owner* connection_owner() override { return this; } |
| |
| private: |
| #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)) |
| |
| friend class TestMsdArmDevice; |
| |
| class DumpRequest; |
| class GpuInterruptRequest; |
| class JobInterruptRequest; |
| class MmuInterruptRequest; |
| class ScheduleAtomRequest; |
| class CancelAtomsRequest; |
| class PerfCounterRequest; |
| |
| magma::RegisterIo* register_io() override |
| { |
| DASSERT(register_io_); |
| return register_io_.get(); |
| } |
| |
| void set_register_io(std::unique_ptr<magma::RegisterIo> register_io) |
| { |
| register_io_ = std::move(register_io); |
| } |
| |
| void Destroy(); |
| void StartDeviceThread(); |
| int DeviceThreadLoop(); |
| int GpuInterruptThreadLoop(); |
| int JobInterruptThreadLoop(); |
| int MmuInterruptThreadLoop(); |
| bool InitializeInterrupts(); |
| void EnableInterrupts(); |
| void DisableInterrupts(); |
| void EnqueueDeviceRequest(std::unique_ptr<DeviceRequest> request, bool enqueue_front = false); |
| void SuspectedGpuHang(); |
| static void InitializeHardwareQuirks(GpuFeatures* features, magma::RegisterIo* registers); |
| |
| magma::Status ProcessDumpStatusToLog(); |
| magma::Status ProcessGpuInterrupt(); |
| magma::Status ProcessJobInterrupt(); |
| magma::Status ProcessMmuInterrupt(); |
| magma::Status ProcessScheduleAtoms(); |
| magma::Status ProcessCancelAtoms(std::weak_ptr<MsdArmConnection> connection); |
| magma::Status ProcessPerfCounterRequest(uint32_t type); |
| |
| void ExecuteAtomOnDevice(MsdArmAtom* atom, magma::RegisterIo* registers); |
| |
| // JobScheduler::Owner implementation. |
| void RunAtom(MsdArmAtom* atom) override; |
| void AtomCompleted(MsdArmAtom* atom, ArmMaliResultCode result) override; |
| void HardStopAtom(MsdArmAtom* atom) override; |
| void SoftStopAtom(MsdArmAtom* atom) override; |
| void ReleaseMappingsForAtom(MsdArmAtom* atom) override; |
| magma::PlatformPort* GetPlatformPort() override; |
| void UpdateGpuActive(bool active) override; |
| |
| static const uint32_t kMagic = 0x64657669; //"devi" |
| |
| std::thread device_thread_; |
| std::unique_ptr<magma::PlatformThreadId> device_thread_id_; |
| std::atomic_bool device_thread_quit_flag_{false}; |
| |
| std::atomic_bool interrupt_thread_quit_flag_{false}; |
| std::thread gpu_interrupt_thread_; |
| std::thread job_interrupt_thread_; |
| std::thread mmu_interrupt_thread_; |
| |
| std::unique_ptr<magma::PlatformSemaphore> device_request_semaphore_; |
| std::unique_ptr<magma::PlatformPort> device_port_; |
| std::mutex device_request_mutex_; |
| std::list<std::unique_ptr<DeviceRequest>> device_request_list_; |
| |
| std::mutex schedule_mutex_; |
| __TA_GUARDED(schedule_mutex_) std::vector<std::shared_ptr<MsdArmAtom>> atoms_to_schedule_; |
| |
| std::unique_ptr<magma::PlatformDevice> platform_device_; |
| std::unique_ptr<magma::RegisterIo> register_io_; |
| std::unique_ptr<magma::PlatformInterrupt> gpu_interrupt_; |
| std::unique_ptr<magma::PlatformInterrupt> job_interrupt_; |
| std::unique_ptr<magma::PlatformInterrupt> mmu_interrupt_; |
| |
| GpuFeatures gpu_features_; |
| ArmMaliCacheCoherencyStatus cache_coherency_status_ = kArmMaliCacheCoherencyNone; |
| |
| std::unique_ptr<PowerManager> power_manager_; |
| std::unique_ptr<AddressManager> address_manager_; |
| std::unique_ptr<JobScheduler> scheduler_; |
| std::unique_ptr<magma::PlatformBusMapper> bus_mapper_; |
| uint64_t cycle_counter_refcount_ = 0; |
| |
| std::unique_ptr<PerformanceCounters> perf_counters_; |
| }; |
| |
| #endif // MSD_ARM_DEVICE_H |