A page of system memory is reserved so sysmembar can perform a read on it if a system write occurred since the last flush. Do this early as it can be required to e.g. reset the GPU falcons.
Signed-off-by: Alexandre Courbot <acour...@nvidia.com> --- drivers/gpu/nova-core/gpu.rs | 45 +++++++++++++++++++++++++++++++++++++++++-- drivers/gpu/nova-core/regs.rs | 10 ++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index a9fcf74717791dc7e23678869bf84f61e51873e2..c338da69ecbc2200f1ef3061a4d62971b021e3eb 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -3,6 +3,7 @@ use kernel::{device, devres::Devres, error::code::*, pci, prelude::*}; use crate::devinit; +use crate::dma::DmaObject; use crate::driver::Bar0; use crate::firmware::Firmware; use crate::regs; @@ -158,12 +159,32 @@ fn new(bar: &Bar0) -> Result<Spec> { } /// Structure holding the resources required to operate the GPU. -#[pin_data] +#[pin_data(PinnedDrop)] pub(crate) struct Gpu { spec: Spec, /// MMIO mapping of PCI BAR 0 bar: Devres<Bar0>, fw: Firmware, + // System memory page required for flushing all pending GPU-side memory writes done through + // PCIE into system memory. + sysmem_flush: DmaObject, +} + +#[pinned_drop] +impl PinnedDrop for Gpu { + fn drop(self: Pin<&mut Self>) { + // Unregister the sysmem flush page before we release it. + let _ = self.bar.try_access_with(|b| { + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() + .set_adr_39_08(0) + .write(b); + if self.spec.chipset >= Chipset::GA102 { + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default() + .set_adr_63_40(0) + .write(b); + } + }); + } } impl Gpu { @@ -187,10 +208,30 @@ pub(crate) fn new( devinit::wait_gfw_boot_completion(bar) .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; + // System memory page required for sysmembar to properly flush into system memory. + let sysmem_flush = { + let page = DmaObject::new(pdev.as_ref(), kernel::bindings::PAGE_SIZE)?; + + // Register the sysmem flush page. + let handle = page.dma_handle(); + + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() + .set_adr_39_08((handle >> 8) as u32) + .write(bar); + if spec.chipset >= Chipset::GA102 { + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default() + .set_adr_63_40((handle >> 40) as u32) + .write(bar); + } + + page + }; + Ok(pin_init!(Self { spec, bar: devres_bar, - fw + fw, + sysmem_flush, })) } } diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index 401d885539cee03cbe732102f5e2233785a7b284..218cb6441eb0e5c6e5b52eabba006163eec0c8b4 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -39,6 +39,16 @@ pub(crate) fn chipset(self) -> Result<Chipset, Error> { } } +/* PFB */ + +register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 { + 31:0 adr_39_08 as u32; +}); + +register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 { + 23:0 adr_63_40 as u32; +}); + /* PGC6 */ register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128 { -- 2.49.0