| // Copyright 2022 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. |
| |
| #include "msd_intel_register_io.h" |
| |
| #include <lib/magma/platform/platform_trace.h> |
| #include <lib/magma/util/dlog.h> |
| #include <lib/magma/util/short_macros.h> |
| |
| #include "registers.h" |
| |
| MsdIntelRegisterIo::MsdIntelRegisterIo(Owner* owner, std::unique_ptr<magma::PlatformMmio> mmio, |
| uint32_t device_id) |
| : owner_(owner), register_io_(std::move(mmio)) { |
| if (DeviceId::is_gen12(device_id)) { |
| forcewake_map_ = &forcewake_map_gen12_; |
| } |
| } |
| |
| std::shared_ptr<ForceWakeDomain> MsdIntelRegisterIo::GetForceWakeToken(ForceWakeDomain domain) { |
| // Ensure forcewake has been activated before we offer the first token. |
| if (forcewake_token_count(domain) == 0) { |
| DASSERT(owner_); |
| bool enabled = owner_->IsForceWakeDomainActive(domain); |
| DASSERT(enabled); |
| } |
| |
| DASSERT(static_cast<size_t>(domain) < per_forcewake_.size()); |
| |
| per_forcewake_[static_cast<int>(domain)].last_request_time = std::chrono::steady_clock::now(); |
| |
| return per_forcewake_[static_cast<int>(domain)].token; |
| } |
| |
| std::chrono::steady_clock::duration MsdIntelRegisterIo::GetForceWakeReleaseTimeout( |
| ForceWakeDomain forcewake_domain, uint64_t max_release_timeout_ms, |
| std::chrono::steady_clock::time_point now) { |
| // Don't timeout if a forcewake token is still held |
| if (forcewake_token_count(forcewake_domain) > 0) |
| return std::chrono::steady_clock::duration::max(); |
| |
| if (!owner_->IsForceWakeDomainActive(forcewake_domain)) |
| return std::chrono::steady_clock::duration::max(); |
| |
| DASSERT(static_cast<size_t>(forcewake_domain) < per_forcewake_.size()); |
| |
| auto last_request_time = per_forcewake_[static_cast<int>(forcewake_domain)].last_request_time; |
| DASSERT(last_request_time != std::chrono::steady_clock::time_point::max()); |
| |
| return last_request_time + std::chrono::milliseconds(max_release_timeout_ms) - now; |
| } |
| |
| void MsdIntelRegisterIo::CheckForcewake(uint32_t register_offset) { |
| // Skip the forcewake registers |
| switch (register_offset) { |
| case registers::ForceWakeRequest::kRenderOffset: |
| case registers::ForceWakeRequest::kGen9MediaOffset: |
| case registers::ForceWakeRequest::kGen12Vdbox0Offset: |
| case registers::ForceWakeStatus::kRenderStatusOffset: |
| case registers::ForceWakeStatus::kGen9MediaStatusOffset: |
| case registers::ForceWakeStatus::kGen12Vdbox0StatusOffset: |
| return; |
| } |
| |
| if (!forcewake_map_ || forcewake_map_->empty()) |
| return; |
| |
| TRACE_DURATION("magma", "CheckForcewake"); |
| |
| auto iter = forcewake_map_->upper_bound(register_offset); |
| if (iter == forcewake_map_->begin()) |
| return; |
| |
| iter = std::prev(iter); |
| DASSERT(iter->first == iter->second.start_offset); |
| |
| if (const Range& range = iter->second; |
| register_offset >= range.start_offset && register_offset <= range.end_offset) { |
| CheckForcewakeForRange(range, register_offset); |
| } |
| } |
| |
| void MsdIntelRegisterIo::CheckForcewakeForRange(const Range& range, uint32_t register_offset) { |
| if (forcewake_active_check_for_test_) { |
| owner_->IsForceWakeDomainActive(range.forcewake_domain); |
| } |
| if (forcewake_token_count(range.forcewake_domain) == 0) { |
| MAGMA_LOG(WARNING, "Access missing forcewake: register 0x%x domain %d range 0x%x - 0x%x", |
| register_offset, static_cast<int>(range.forcewake_domain), range.start_offset, |
| range.end_offset); |
| DASSERT(false); |
| } |
| } |
| |
| // static |
| constexpr std::pair<uint32_t, MsdIntelRegisterIo::Range> Entry(uint32_t start, uint32_t end, |
| ForceWakeDomain domain) { |
| return {start, {start, end, domain}}; |
| } |
| |
| // From: |
| // https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-tgl-vol13-generalassets.pdf |
| // p.1 |
| // Does not include GT or empty regions. |
| // Commented lines refer to engines that may be supported eventually. |
| // clang-format off |
| const std::map<uint32_t, MsdIntelRegisterIo::Range> MsdIntelRegisterIo::forcewake_map_gen12_ = { |
| Entry(0x2000, 0x26FF, ForceWakeDomain::RENDER), |
| Entry(0x2800, 0x2AFF, ForceWakeDomain::RENDER), |
| Entry(0x3000, 0x3FFF, ForceWakeDomain::RENDER), |
| Entry(0x5200, 0x52FF, ForceWakeDomain::RENDER), |
| Entry(0x5300, 0x53FF, ForceWakeDomain::RENDER), |
| Entry(0x5500, 0x55FF, ForceWakeDomain::RENDER), |
| Entry(0x6000, 0x6FFF, ForceWakeDomain::RENDER), |
| Entry(0x7000, 0x7FFF, ForceWakeDomain::RENDER), |
| Entry(0x8140, 0x814F, ForceWakeDomain::RENDER), |
| Entry(0x8150, 0x815F, ForceWakeDomain::RENDER), |
| Entry(0x8300, 0x84FF, ForceWakeDomain::RENDER), |
| Entry(0x94D0, 0x951F, ForceWakeDomain::RENDER), |
| Entry(0x9520, 0x955F, ForceWakeDomain::RENDER), |
| Entry(0xB000, 0xB0FF, ForceWakeDomain::RENDER), |
| Entry(0xB100, 0xB3FF, ForceWakeDomain::RENDER), |
| Entry(0xD800, 0xD8FF, ForceWakeDomain::RENDER), |
| Entry(0xDC00, 0xDDFF, ForceWakeDomain::RENDER), |
| Entry(0xDE80, 0xDEFF, ForceWakeDomain::RENDER), |
| Entry(0xDF00, 0xDFFF, ForceWakeDomain::RENDER), |
| Entry(0xE000, 0xE0FF, ForceWakeDomain::RENDER), |
| Entry(0xE100, 0xE1FF, ForceWakeDomain::RENDER), |
| Entry(0xE200, 0xE3FF, ForceWakeDomain::RENDER), |
| Entry(0xE400, 0xE7FF, ForceWakeDomain::RENDER), |
| Entry(0xE800, 0xE8FF, ForceWakeDomain::RENDER), |
| Entry(0x14800, 0x14FFF, ForceWakeDomain::RENDER), |
| Entry(0x16E00, 0x16FFF, ForceWakeDomain::RENDER), |
| Entry(0x17000, 0x17FFF, ForceWakeDomain::RENDER), |
| Entry(0x18000, 0x19FFF, ForceWakeDomain::RENDER), |
| Entry(0x1A000, 0x1BFFF, ForceWakeDomain::RENDER), |
| Entry(0x20000, 0x20FFF, ForceWakeDomain::GEN12_VDBOX0), |
| // Entry(0x21000, 0x21FFF, ForceWakeDomain::GEN12_VDBOX2), |
| Entry(0x24A00, 0x24A7F, ForceWakeDomain::RENDER), |
| Entry(0x25600, 0x2567F, ForceWakeDomain::GEN12_VDBOX0), |
| // Entry(0x25680, 0x256FF, ForceWakeDomain::GEN12_VDBOX2), |
| Entry(0x25A00, 0x25A7F, ForceWakeDomain::GEN12_VDBOX0), |
| // Entry(0x25A80, 0x25AFF, ForceWakeDomain::GEN12_VDBOX2), |
| Entry(0x1C0000, 0x1C07FF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C0800, 0x1C0FFF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C1000, 0x1C1FFF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C2000, 0x1C27FF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C2800, 0x1C2AFF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C2B00, 0x1C2BFF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C2D00, 0x1C2DFF, ForceWakeDomain::GEN12_VDBOX0), |
| Entry(0x1C3F00, 0x1C3FFF, ForceWakeDomain::GEN12_VDBOX0), |
| // Entry(0x1C8000, 0x1C9FFF, ForceWakeDomain::GEN12_VEBOX0), |
| // Entry(0x1CA000, 0x1CA0FF, ForceWakeDomain::GEN12_VEBOX0), |
| // Entry(0x1CBF00, 0x1CBFFF, ForceWakeDomain::GEN12_VEBOX0), |
| Entry(0x1CC000, 0x1CCFFF, ForceWakeDomain::GEN12_VDBOX0), |
| // Entry(0x1D0000, 0x1D07FF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D0800, 0x1D0FFF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D1000, 0x1D1FFF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D2000, 0x1D27FF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D2800, 0x1D2AFF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D2B00, 0x1D2BFF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D2D00, 0x1D2DFF, ForceWakeDomain::GEN12_VDBOX2), |
| // Entry(0x1D3F00, 0x1D3FFF, ForceWakeDomain::GEN12_VDBOX2), |
| }; |
| // clang-format on |