| // 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 SRC_GRAPHICS_DRIVERS_MSD_ARM_MALI_SRC_GPU_MAPPING_H_ |
| #define SRC_GRAPHICS_DRIVERS_MSD_ARM_MALI_SRC_GPU_MAPPING_H_ |
| |
| #include <lib/magma/platform/platform_bus_mapper.h> |
| #include <lib/magma/util/short_macros.h> |
| |
| #include <cstdint> |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| #include "drivers/msd-arm-mali/src/region.h" |
| |
| class MsdArmBuffer; |
| class MsdArmConnection; |
| |
| struct BusMappingCompare { |
| bool operator()(const std::unique_ptr<magma::PlatformBusMapper::BusMapping>& a, |
| const std::unique_ptr<magma::PlatformBusMapper::BusMapping>& b) const { |
| return a->page_offset() < b->page_offset(); |
| } |
| }; |
| |
| // A buffer may be mapped into a connection at multiple virtual addresses. The |
| // connection owns the GpuMapping, so |owner_| is always valid. The buffer |
| // deletes all the mappings it owns before it's destroyed, so that's why |
| // |buffer_| is always valid. |
| class GpuMapping { |
| public: |
| class Owner { |
| public: |
| virtual bool RemoveMapping(uint64_t address) = 0; |
| virtual bool UpdateCommittedMemory(GpuMapping* mapping) = 0; |
| }; |
| |
| GpuMapping(uint64_t addr, uint64_t page_offset, uint64_t size, uint64_t flags, Owner* owner, |
| std::shared_ptr<MsdArmBuffer> buffer); |
| |
| ~GpuMapping(); |
| |
| uint64_t gpu_va() const { return addr_; } |
| uint64_t page_offset() const { return page_offset_; } // In CPU pages. |
| uint64_t size() const { return size_; } |
| uint64_t flags() const { return flags_; } |
| |
| void ReplaceBusMappings(std::unique_ptr<magma::PlatformBusMapper::BusMapping> bus_mapping) { |
| if (bus_mapping) { |
| DASSERT(bus_mapping->page_offset() >= page_offset_); |
| DASSERT(bus_mapping->page_offset() + bus_mapping->page_count() <= |
| page_offset_ + (size_ / PAGE_SIZE)); |
| if (magma::kDebug) { |
| // Check that the physical addresses of pages haven't changed |
| // (e.g. due to being mapped to a new place with the iommu). |
| for (auto& mapping : bus_mappings_) { |
| for (uint32_t i = 0; i < mapping->page_count(); i++) { |
| if (mapping->page_offset() + i < bus_mapping->page_offset()) |
| continue; |
| uint64_t new_offset = mapping->page_offset() + i - bus_mapping->page_offset(); |
| if (new_offset >= bus_mapping->page_count()) |
| continue; |
| DASSERT(bus_mapping->Get()[new_offset] == mapping->Get()[i]); |
| } |
| } |
| } |
| } |
| bus_mappings_.clear(); |
| Region bus_mapping_region; |
| if (bus_mapping) { |
| bus_mapping_region = |
| Region::FromStartAndLength(bus_mapping->page_offset(), bus_mapping->page_count()); |
| bus_mappings_.insert(std::move(bus_mapping)); |
| } |
| committed_region_in_buffer_ = bus_mapping_region; |
| } |
| void AddBusMapping(std::unique_ptr<magma::PlatformBusMapper::BusMapping> bus_mapping) { |
| DASSERT(bus_mapping); |
| auto bus_mapping_region = |
| Region::FromStartAndLength(bus_mapping->page_offset(), bus_mapping->page_count()); |
| if (!committed_region_in_buffer_.empty()) { |
| DASSERT(bus_mapping_region.IsAdjacentTo(committed_region_in_buffer())); |
| } |
| bus_mappings_.insert(std::move(bus_mapping)); |
| committed_region_in_buffer_.Union(bus_mapping_region); |
| } |
| |
| std::weak_ptr<MsdArmBuffer> buffer() const; |
| void Remove() { owner_->RemoveMapping(addr_); } |
| bool UpdateCommittedMemory() { return owner_->UpdateCommittedMemory(this); } |
| |
| const std::set<std::unique_ptr<magma::PlatformBusMapper::BusMapping>, BusMappingCompare>& |
| bus_mappings() { |
| return bus_mappings_; |
| } |
| |
| uint64_t pages_to_grow_on_fault() const { return pages_to_grow_on_fault_; } |
| void set_pages_to_grow_on_fault(uint64_t pages) { pages_to_grow_on_fault_ = pages; } |
| |
| // Returns committed region in pages relative to the start of the mapping. |
| Region committed_region() const { |
| return Region::FromStartAndLength(committed_region_in_buffer_.start() - page_offset_, |
| committed_region_in_buffer_.length()); |
| } |
| Region committed_region_in_buffer() const { return committed_region_in_buffer_; } |
| |
| private: |
| friend class TestConnection; |
| const uint64_t addr_; |
| const uint64_t page_offset_; |
| // In bytes |
| const uint64_t size_; |
| const uint64_t flags_; |
| // By default try to grow in units of 64 pages to avoid needing to fault too often. |
| uint64_t pages_to_grow_on_fault_ = 64; |
| // Region in pages relative to the beginning of the buffer. This is stored as an optimization so |
| // we don't have to union the regions in bus_mappings_ whenever this is queried. |
| Region committed_region_in_buffer_; |
| Owner* const owner_; |
| std::weak_ptr<MsdArmBuffer> buffer_; |
| // Bus mappings must be contiguous and completely cover committed_region_in_buffer_. |
| std::set<std::unique_ptr<magma::PlatformBusMapper::BusMapping>, BusMappingCompare> bus_mappings_; |
| }; |
| |
| #endif // SRC_GRAPHICS_DRIVERS_MSD_ARM_MALI_SRC_GPU_MAPPING_H_ |