xref: /linux/drivers/gpu/nova-core/fb.rs (revision 69f5cd67ce41ba128d3df18137c7a93a1faa84da)
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