1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::prelude::*; 4 use kernel::types::ARef; 5 use kernel::{dev_warn, device}; 6 7 use crate::dma::DmaObject; 8 use crate::driver::Bar0; 9 use crate::gpu::Chipset; 10 11 mod hal; 12 13 /// Type holding the sysmem flush memory page, a page of memory to be written into the 14 /// `NV_PFB_NISO_FLUSH_SYSMEM_ADDR*` registers and used to maintain memory coherency. 15 /// 16 /// Users are responsible for manually calling [`Self::unregister`] before dropping this object, 17 /// otherwise the GPU might still use it even after it has been freed. 18 pub(crate) struct SysmemFlush { 19 /// Chipset we are operating on. 20 chipset: Chipset, 21 device: ARef<device::Device>, 22 /// Keep the page alive as long as we need it. 23 page: DmaObject, 24 } 25 26 impl SysmemFlush { 27 /// Allocate a memory page and register it as the sysmem flush page. 28 pub(crate) fn register( 29 dev: &device::Device<device::Bound>, 30 bar: &Bar0, 31 chipset: Chipset, 32 ) -> Result<Self> { 33 let page = DmaObject::new(dev, kernel::page::PAGE_SIZE)?; 34 35 hal::fb_hal(chipset).write_sysmem_flush_page(bar, page.dma_handle())?; 36 37 Ok(Self { 38 chipset, 39 device: dev.into(), 40 page, 41 }) 42 } 43 44 /// Unregister the managed sysmem flush page. 45 /// 46 /// In order to gracefully tear down the GPU, users must make sure to call this method before 47 /// dropping the object. 48 pub(crate) fn unregister(&self, bar: &Bar0) { 49 let hal = hal::fb_hal(self.chipset); 50 51 if hal.read_sysmem_flush_page(bar) == self.page.dma_handle() { 52 let _ = hal.write_sysmem_flush_page(bar, 0).inspect_err(|e| { 53 dev_warn!( 54 &self.device, 55 "failed to unregister sysmem flush page: {:?}", 56 e 57 ) 58 }); 59 } else { 60 // Another page has been registered after us for some reason - warn as this is a bug. 61 dev_warn!( 62 &self.device, 63 "attempt to unregister a sysmem flush page that is not active\n" 64 ); 65 } 66 } 67 } 68