All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Eliot Courtney" <ecourtney@nvidia.com>
To: "Alexandre Courbot" <acourbot@nvidia.com>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>
Cc: "John Hubbard" <jhubbard@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	"Timur Tabi" <ttabi@nvidia.com>,
	"Eliot Courtney" <ecourtney@nvidia.com>,
	"Zhi Wang" <zhiw@nvidia.com>, <nova-gpu@lists.linux.dev>,
	<rust-for-linux@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 10/12] gpu: nova-core: falcon: allow DMA transfers to read from a framebuffer address
Date: Mon, 09 Nov 2026 16:23:29 +0900	[thread overview]
Message-ID: <DMQI0G2K6Z3B.1YEH6D2ZILRBI@nvidia.com> (raw)
In-Reply-To: <20261107-r000-fw-v2-10-fb37cc5b20cd@nvidia.com>

On Sat Nov 7, 2026 at 6:48 PM JST, Alexandre Courbot wrote:
> The r000 boot protocol has a load-and-execute event in which GSP-RM asks
> the driver to load a Heavy-Secured binary from framebuffer memory into
> the GSP falcon's memory by DMA in order to run it.
>
> Nova-core's falcon DMA loading method currently only supports loading
> from a DMA object that the driver has allocated, so there is no way to
> copy an image from framebuffer memory that an event supplied.
>
> Address this by making the source of a falcon DMA transfer an enum,
> which can be either a DMA object, or a GPU framebuffer address.
>
> The framebuffer address source has no user yet, but will be used by the
> r000 boot protocol.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  drivers/gpu/nova-core/falcon.rs | 65 ++++++++++++++++++++++++++---------------
>  1 file changed, 42 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
> index 00da664887fc..b63265abd263 100644
> --- a/drivers/gpu/nova-core/falcon.rs
> +++ b/drivers/gpu/nova-core/falcon.rs
> @@ -140,6 +140,15 @@ pub(crate) enum FalconMem {
>      Dmem { tag: bool },
>  }
>  
> +/// Where a falcon DMA transfer reads from.
> +pub(crate) enum FalconDmaSource<'a> {
> +    /// A DMA object in system memory.
> +    Sysmem(&'a Coherent<'a, [u8]>),
> +    /// GPU framebuffer memory at physical address `base`.
> +    #[expect(dead_code)]
> +    Framebuffer { base: u64 },
> +}
> +
>  bounded_enum! {
>      /// Defines the Framebuffer Interface (FBIF) aperture type.
>      /// This determines the memory type for external memory access during a DMA transfer, which is
> @@ -544,13 +553,10 @@ pub(crate) fn with_fbif_transcfg<R>(
>          Ok(result)
>      }
>  
> -    /// Perform a DMA write according to `load_offsets` from `dma_obj` into the falcon's
> -    /// `target_mem`.
> -    ///
> -    /// `sec` is set if the loaded firmware is expected to run in secure mode.
> +    /// Perform a DMA write according to `load_offsets` from `src` into the falcon's `target_mem`.
>      fn dma_wr(
>          &self,
> -        dma_obj: &Coherent<'_, [u8]>,
> +        src: FalconDmaSource<'_>,
>          target_mem: FalconMem,
>          load_offsets: FalconDmaLoadTarget,
>      ) -> Result {
> @@ -563,23 +569,32 @@ fn dma_wr(
>          // For IMEM and tagged DMEM, we want to use the start offset as a virtual address tag for
>          // each page, since addresses in the firmware (and the boot vector) are virtual.
>          //
> -        // For untagged DMEM, the start offset is folded into the DMA base.
> -        let (fb_offset, base_offset) = match target_mem {
> -            FalconMem::ImemSecure | FalconMem::ImemNonSecure | FalconMem::Dmem { tag: true } => {
> -                (load_offsets.src_start, 0)
> +        // For untagged DMEM in a DMA object, the start offset is folded into the DMA base. For a
> +        // framebuffer address, the DMA engine adds the start offset to the address.
> +        let (fb_offset, dma_base) = match src {
> +            FalconDmaSource::Sysmem(dma_obj) => {
> +                let (fb_offset, base_offset) = match target_mem {
> +                    FalconMem::ImemSecure
> +                    | FalconMem::ImemNonSecure
> +                    | FalconMem::Dmem { tag: true } => (load_offsets.src_start, 0),
> +                    FalconMem::Dmem { tag: false } => {
> +                        (0, usize::from_safe_cast(load_offsets.src_start))
> +                    }
> +                };
> +
> +                // Upper limit of transfer is `(num_transfers * DMA_LEN) + load_offsets.src_start`.
> +                let dma_end = num_transfers
> +                    .checked_mul(DMA_LEN)
> +                    .and_then(|size| size.checked_add(load_offsets.src_start))
> +                    .map(usize::from_safe_cast)
> +                    .ok_or(EOVERFLOW)?;
> +
> +                (
> +                    fb_offset,
> +                    io_project!(dma_obj, [try: base_offset..dma_end]).dma_address(),
> +                )
>              }
> -            FalconMem::Dmem { tag: false } => (0, usize::from_safe_cast(load_offsets.src_start)),
> -        };
> -
> -        let dma_base = {
> -            // Upper limit of transfer is `(num_transfers * DMA_LEN) + load_offsets.src_start`.
> -            let dma_end = num_transfers
> -                .checked_mul(DMA_LEN)
> -                .and_then(|size| size.checked_add(load_offsets.src_start))
> -                .map(usize::from_safe_cast)
> -                .ok_or(EOVERFLOW)?;
> -
> -            io_project!(dma_obj, [try: base_offset..dma_end]).dma_address()
> +            FalconDmaSource::Framebuffer { base } => (load_offsets.src_start, base),
>          };

I think this code is simplifiable. The `Sysmem` branch computes some offsets
based on `target_mem`. But I don't see why this has to be specific to that
branch. What we could do (and what openrm does afaict) is just split that out,
for example:

```
let (fb_offset, base_offset) = match target_mem {
    FalconMem::ImemSecure | FalconMem::ImemNonSecure | FalconMem::Dmem { tag: true } => {
        (load_offsets.src_start, 0)
    }
    FalconMem::Dmem { tag: false } => (0, usize::from_safe_cast(load_offsets.src_start)),
};

let dma_base = match src {
    FalconDmaSource::Sysmem(dma_obj) => {
        let dma_end = num_transfers
            .checked_mul(DMA_LEN)
            .and_then(|size| size.checked_add(load_offsets.src_start))
            .map(usize::from_safe_cast)
            .ok_or(EOVERFLOW)?;

        io_project!(dma_obj, [try: base_offset..dma_end]).dma_address()
    }
    FalconDmaSource::Framebuffer { base } => base
        .checked_add(u64::from_safe_cast(base_offset))
        .ok_or(EOVERFLOW)?,
};
```

Alternatively I think the following is simpler where you just always pass the
base of the DMA region and use the offset param
(NV_PFALCON_FALCON_DMATRFFBOFFS), but it's not what openrm does. That is,
tag==false case it doesn't matter (?) how the offset is split between
`fb_offset` and `base_offset` is so might as well make it match the other cases:

```
let dma_base = match src {
    FalconDmaSource::Sysmem(dma_obj) => {
        let dma_end = num_transfers
            .checked_mul(DMA_LEN)
            .and_then(|size| size.checked_add(load_offsets.src_start))
            .map(usize::from_safe_cast)
            .ok_or(EOVERFLOW)?;

        io_project!(dma_obj, [try: 0..dma_end]).dma_address()
    }
    FalconDmaSource::Framebuffer { base } => base,
};
let dma_offset = load_offsets.src_start;
```

  reply	other threads:[~2026-11-09  7:23 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07  9:47 [PATCH v2 00/12] gpu: nova-core: generic bootloader and falcon DMA changes for r000 Alexandre Courbot
2026-11-07  9:47 ` [PATCH v2 01/12] gpu: nova-core: separate the generic falcon bootloader from FWSEC Alexandre Courbot
2026-11-07  9:47 ` [PATCH v2 02/12] gpu: nova-core: falcon: widen the IMEM PIO offset to 24 bits Alexandre Courbot
2026-11-09  4:32   ` Eliot Courtney
2026-11-07  9:47 ` [PATCH v2 03/12] gpu: nova-core: place the generic bootloader at the top of IMEM Alexandre Courbot
2026-11-09  4:53   ` Eliot Courtney
2026-11-10 10:14     ` Alexandre Courbot
2026-11-07  9:48 ` [PATCH v2 04/12] gpu: nova-core: move the bootloader DMEM descriptor out of FWSEC Alexandre Courbot
2026-11-07  9:48 ` [PATCH v2 05/12] gpu: nova-core: run the generic bootloader from its own type Alexandre Courbot
2026-11-09  4:59   ` Eliot Courtney
2026-11-07  9:48 ` [PATCH v2 06/12] rust: io: register: implement Copy and Clone for RegisterArrayLoc Alexandre Courbot
2026-11-07  9:55   ` sashiko-bot
2026-11-07 13:05   ` Danilo Krummrich
2026-11-09  5:00   ` Eliot Courtney
2026-11-09 11:58   ` Gary Guo
2026-11-07  9:48 ` [PATCH v2 07/12] gpu: nova-core: falcon: introduce and use with_fbif_transcfg Alexandre Courbot
2026-11-09  5:36   ` Eliot Courtney
2026-11-07  9:48 ` [PATCH v2 08/12] gpu: nova-core: falcon: rename the local variables of dma_wr() Alexandre Courbot
2026-11-09  5:39   ` Eliot Courtney
2026-11-07  9:48 ` [PATCH v2 09/12] gpu: nova-core: falcon: allow DMEM DMA transfers to request tagging Alexandre Courbot
2026-11-09  5:47   ` Eliot Courtney
2026-11-07  9:48 ` [PATCH v2 10/12] gpu: nova-core: falcon: allow DMA transfers to read from a framebuffer address Alexandre Courbot
2026-11-09  7:23   ` Eliot Courtney [this message]
2026-11-10 10:16     ` Alexandre Courbot
2026-11-07  9:48 ` [PATCH v2 11/12] gpu: nova-core: falcon: check the per-block DMA offsets for overflow Alexandre Courbot
2026-11-07  9:48 ` [PATCH v2 12/12] gpu: nova-core: falcon: program the FBIF_TRANSCFG register in dma_wr Alexandre Courbot
2026-11-09  7:24   ` Eliot Courtney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DMQI0G2K6Z3B.1YEH6D2ZILRBI@nvidia.com \
    --to=ecourtney@nvidia.com \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=jhubbard@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=simona@ffwll.ch \
    --cc=ttabi@nvidia.com \
    --cc=zhiw@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.