16554ad65SAlexandre Courbot // SPDX-License-Identifier: GPL-2.0 26554ad65SAlexandre Courbot 380213934SAlexandre Courbot use core::ops::Range; 480213934SAlexandre Courbot 56554ad65SAlexandre Courbot use kernel::prelude::*; 680213934SAlexandre Courbot use kernel::sizes::*; 76554ad65SAlexandre Courbot use kernel::types::ARef; 86554ad65SAlexandre Courbot use kernel::{dev_warn, device}; 96554ad65SAlexandre Courbot 106554ad65SAlexandre Courbot use crate::dma::DmaObject; 116554ad65SAlexandre Courbot use crate::driver::Bar0; 126554ad65SAlexandre Courbot use crate::gpu::Chipset; 1380213934SAlexandre Courbot use crate::regs; 146554ad65SAlexandre Courbot 156554ad65SAlexandre Courbot mod hal; 166554ad65SAlexandre Courbot 176554ad65SAlexandre Courbot /// Type holding the sysmem flush memory page, a page of memory to be written into the 186554ad65SAlexandre Courbot /// `NV_PFB_NISO_FLUSH_SYSMEM_ADDR*` registers and used to maintain memory coherency. 196554ad65SAlexandre Courbot /// 20*4d3e8913SJoel Fernandes /// A system memory page is required for `sysmembar`, which is a GPU-initiated hardware 21*4d3e8913SJoel Fernandes /// memory-barrier operation that flushes all pending GPU-side memory writes that were done through 22*4d3e8913SJoel Fernandes /// PCIE to system memory. It is required for falcons to be reset as the reset operation involves a 23*4d3e8913SJoel Fernandes /// reset handshake. When the falcon acknowledges a reset, it writes into system memory. To ensure 24*4d3e8913SJoel Fernandes /// this write is visible to the host and prevent driver timeouts, the falcon must perform a 25*4d3e8913SJoel Fernandes /// sysmembar operation to flush its writes. 26*4d3e8913SJoel Fernandes /// 27*4d3e8913SJoel Fernandes /// Because of this, the sysmem flush memory page must be registered as early as possible during 28*4d3e8913SJoel Fernandes /// driver initialization, and before any falcon is reset. 29*4d3e8913SJoel Fernandes /// 306554ad65SAlexandre Courbot /// Users are responsible for manually calling [`Self::unregister`] before dropping this object, 316554ad65SAlexandre Courbot /// otherwise the GPU might still use it even after it has been freed. 326554ad65SAlexandre Courbot pub(crate) struct SysmemFlush { 336554ad65SAlexandre Courbot /// Chipset we are operating on. 346554ad65SAlexandre Courbot chipset: Chipset, 356554ad65SAlexandre Courbot device: ARef<device::Device>, 366554ad65SAlexandre Courbot /// Keep the page alive as long as we need it. 376554ad65SAlexandre Courbot page: DmaObject, 386554ad65SAlexandre Courbot } 396554ad65SAlexandre Courbot 406554ad65SAlexandre Courbot impl SysmemFlush { 416554ad65SAlexandre Courbot /// Allocate a memory page and register it as the sysmem flush page. register( dev: &device::Device<device::Bound>, bar: &Bar0, chipset: Chipset, ) -> Result<Self>426554ad65SAlexandre Courbot pub(crate) fn register( 436554ad65SAlexandre Courbot dev: &device::Device<device::Bound>, 446554ad65SAlexandre Courbot bar: &Bar0, 456554ad65SAlexandre Courbot chipset: Chipset, 466554ad65SAlexandre Courbot ) -> Result<Self> { 476554ad65SAlexandre Courbot let page = DmaObject::new(dev, kernel::page::PAGE_SIZE)?; 486554ad65SAlexandre Courbot 496554ad65SAlexandre Courbot hal::fb_hal(chipset).write_sysmem_flush_page(bar, page.dma_handle())?; 506554ad65SAlexandre Courbot 516554ad65SAlexandre Courbot Ok(Self { 526554ad65SAlexandre Courbot chipset, 536554ad65SAlexandre Courbot device: dev.into(), 546554ad65SAlexandre Courbot page, 556554ad65SAlexandre Courbot }) 566554ad65SAlexandre Courbot } 576554ad65SAlexandre Courbot 586554ad65SAlexandre Courbot /// Unregister the managed sysmem flush page. 596554ad65SAlexandre Courbot /// 606554ad65SAlexandre Courbot /// In order to gracefully tear down the GPU, users must make sure to call this method before 616554ad65SAlexandre Courbot /// dropping the object. unregister(&self, bar: &Bar0)626554ad65SAlexandre Courbot pub(crate) fn unregister(&self, bar: &Bar0) { 636554ad65SAlexandre Courbot let hal = hal::fb_hal(self.chipset); 646554ad65SAlexandre Courbot 656554ad65SAlexandre Courbot if hal.read_sysmem_flush_page(bar) == self.page.dma_handle() { 666554ad65SAlexandre Courbot let _ = hal.write_sysmem_flush_page(bar, 0).inspect_err(|e| { 676554ad65SAlexandre Courbot dev_warn!( 686554ad65SAlexandre Courbot &self.device, 696554ad65SAlexandre Courbot "failed to unregister sysmem flush page: {:?}", 706554ad65SAlexandre Courbot e 716554ad65SAlexandre Courbot ) 726554ad65SAlexandre Courbot }); 736554ad65SAlexandre Courbot } else { 746554ad65SAlexandre Courbot // Another page has been registered after us for some reason - warn as this is a bug. 756554ad65SAlexandre Courbot dev_warn!( 766554ad65SAlexandre Courbot &self.device, 776554ad65SAlexandre Courbot "attempt to unregister a sysmem flush page that is not active\n" 786554ad65SAlexandre Courbot ); 796554ad65SAlexandre Courbot } 806554ad65SAlexandre Courbot } 816554ad65SAlexandre Courbot } 8280213934SAlexandre Courbot 8380213934SAlexandre Courbot /// Layout of the GPU framebuffer memory. 8480213934SAlexandre Courbot /// 8580213934SAlexandre Courbot /// Contains ranges of GPU memory reserved for a given purpose during the GSP boot process. 8680213934SAlexandre Courbot #[derive(Debug)] 8780213934SAlexandre Courbot #[expect(dead_code)] 8880213934SAlexandre Courbot pub(crate) struct FbLayout { 8980213934SAlexandre Courbot pub(crate) fb: Range<u64>, 9080213934SAlexandre Courbot pub(crate) vga_workspace: Range<u64>, 9180213934SAlexandre Courbot pub(crate) frts: Range<u64>, 9280213934SAlexandre Courbot } 9380213934SAlexandre Courbot 9480213934SAlexandre Courbot impl FbLayout { 9580213934SAlexandre Courbot /// Computes the FB layout. new(chipset: Chipset, bar: &Bar0) -> Result<Self>9680213934SAlexandre Courbot pub(crate) fn new(chipset: Chipset, bar: &Bar0) -> Result<Self> { 9780213934SAlexandre Courbot let hal = hal::fb_hal(chipset); 9880213934SAlexandre Courbot 9980213934SAlexandre Courbot let fb = { 10080213934SAlexandre Courbot let fb_size = hal.vidmem_size(bar); 10180213934SAlexandre Courbot 10280213934SAlexandre Courbot 0..fb_size 10380213934SAlexandre Courbot }; 10480213934SAlexandre Courbot 10580213934SAlexandre Courbot let vga_workspace = { 10680213934SAlexandre Courbot let vga_base = { 10780213934SAlexandre Courbot const NV_PRAMIN_SIZE: u64 = SZ_1M as u64; 10880213934SAlexandre Courbot let base = fb.end - NV_PRAMIN_SIZE; 10980213934SAlexandre Courbot 11080213934SAlexandre Courbot if hal.supports_display(bar) { 11180213934SAlexandre Courbot match regs::NV_PDISP_VGA_WORKSPACE_BASE::read(bar).vga_workspace_addr() { 11280213934SAlexandre Courbot Some(addr) => { 11380213934SAlexandre Courbot if addr < base { 11480213934SAlexandre Courbot const VBIOS_WORKSPACE_SIZE: u64 = SZ_128K as u64; 11580213934SAlexandre Courbot 11680213934SAlexandre Courbot // Point workspace address to end of framebuffer. 11780213934SAlexandre Courbot fb.end - VBIOS_WORKSPACE_SIZE 11880213934SAlexandre Courbot } else { 11980213934SAlexandre Courbot addr 12080213934SAlexandre Courbot } 12180213934SAlexandre Courbot } 12280213934SAlexandre Courbot None => base, 12380213934SAlexandre Courbot } 12480213934SAlexandre Courbot } else { 12580213934SAlexandre Courbot base 12680213934SAlexandre Courbot } 12780213934SAlexandre Courbot }; 12880213934SAlexandre Courbot 12980213934SAlexandre Courbot vga_base..fb.end 13080213934SAlexandre Courbot }; 13180213934SAlexandre Courbot 13280213934SAlexandre Courbot let frts = { 13380213934SAlexandre Courbot const FRTS_DOWN_ALIGN: u64 = SZ_128K as u64; 13480213934SAlexandre Courbot const FRTS_SIZE: u64 = SZ_1M as u64; 1353606620bSAlexandre Courbot // TODO[NUMM]: replace with `align_down` once it lands. 13680213934SAlexandre Courbot let frts_base = (vga_workspace.start & !(FRTS_DOWN_ALIGN - 1)) - FRTS_SIZE; 13780213934SAlexandre Courbot 13880213934SAlexandre Courbot frts_base..frts_base + FRTS_SIZE 13980213934SAlexandre Courbot }; 14080213934SAlexandre Courbot 14180213934SAlexandre Courbot Ok(Self { 14280213934SAlexandre Courbot fb, 14380213934SAlexandre Courbot vga_workspace, 14480213934SAlexandre Courbot frts, 14580213934SAlexandre Courbot }) 14680213934SAlexandre Courbot } 14780213934SAlexandre Courbot } 148