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 | 51 +++++++++++++++++++++++++++++++++++++++++-- drivers/gpu/nova-core/regs.rs | 10 +++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index ac246d08141e95927a25cada4ecb7e23156ac6b4..08302967375274fd88bb9b4fef4969e79e82f3b4 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: &Devres<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 _ = with_bar!(&self.bar, |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 { @@ -186,6 +207,32 @@ pub(crate) fn new( devinit::wait_gfw_boot_completion(&bar) .inspect_err(|_| dev_err!(pdev.as_ref(), "GFW boot did not complete"))?; - Ok(pin_init!(Self { spec, bar, fw })) + // 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. + with_bar!(bar, |b| { + let handle = page.dma_handle(); + + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR::default() + .set_adr_39_08((handle >> 8) as u32) + .write(b); + if spec.chipset >= Chipset::GA102 { + regs::NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI::default() + .set_adr_63_40((handle >> 40) as u32) + .write(b); + } + })?; + + page + }; + + Ok(pin_init!(Self { + spec, + bar, + 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