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