blob: 09e502c6b51c17563658a38eee69d0a6d5deae93 [file] [log] [blame]
// 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 GPU_MAPPING_H_
#define GPU_MAPPING_H_
#include "magma_util/macros.h"
#include "platform_bus_mapper.h"
#include <cstdint>
#include <memory>
#include <vector>
class MsdArmBuffer;
class MsdArmConnection;
// 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_; }
uint64_t size() const { return size_; }
uint64_t flags() const { return flags_; }
uint64_t pinned_page_count() const { return pinned_page_count_; }
void shrink_pinned_pages(uint64_t pages_removed,
std::unique_ptr<magma::PlatformBusMapper::BusMapping> bus_mapping)
{
DASSERT(pinned_page_count_ >= pages_removed);
pinned_page_count_ -= pages_removed;
if (bus_mapping) {
DASSERT(pinned_page_count_ == bus_mapping->page_count());
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();
bus_mappings_.push_back(std::move(bus_mapping));
}
}
void grow_pinned_pages(std::unique_ptr<magma::PlatformBusMapper::BusMapping> bus_mapping)
{
pinned_page_count_ += bus_mapping->page_count();
bus_mappings_.push_back(std::move(bus_mapping));
}
std::weak_ptr<MsdArmBuffer> buffer() const;
void Remove() { owner_->RemoveMapping(addr_); }
bool UpdateCommittedMemory() { return owner_->UpdateCommittedMemory(this); }
const std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>>& bus_mappings()
{
return bus_mappings_;
}
private:
friend class TestConnection;
const uint64_t addr_;
const uint64_t page_offset_;
const uint64_t size_;
const uint64_t flags_;
Owner* const owner_;
uint64_t pinned_page_count_ = 0;
std::weak_ptr<MsdArmBuffer> buffer_;
std::vector<std::unique_ptr<magma::PlatformBusMapper::BusMapping>> bus_mappings_;
};
#endif // GPU_MAPPING_H_