Subject: linux-next: manual merge of the drm-rust tree with the drm-rust-fixes tree

From: Mark Brown <[email-masked]>
Date: Thu, 12 Mar 2026 14:26:52 +0000

Hi all,

Today's linux-next merge of the drm-rust tree got conflicts in:

  drivers/gpu/nova-core/gsp/cmdq.rs
  drivers/gpu/nova-core/gsp/fw.rs

between commits:

  c7940c8bf215b ("gpu: nova-core: fix stack overflow in GSP memory allocation")
  0073a17b46668 ("gpu: nova-core: gsp: fix UB in DmaGspMem pointer accessors")

from the drm-rust-fixes tree and commit:

  e8f4f9ae86a46 ("gpu: nova-core: gsp: support large RPCs via continuation record")

from the drm-rust tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

diff --cc drivers/gpu/nova-core/gsp/cmdq.rs
index 03a4f35998498,e0b096546d233..0000000000000
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@@ -1,9 -1,14 +1,8 @@@
  // SPDX-License-Identifier: GPL-2.0
  
- use core::{
-     cmp,
-     mem, //
- };
+ mod continuation;
+ 
 -use core::{
 -    mem,
 -    sync::atomic::{
 -        fence,
 -        Ordering, //
 -    }, //
 -};
++use core::mem;
  
  use kernel::{
      device,
@@@ -154,24 -170,21 +165,26 @@@ pub(super) struct Msgq 
  
  /// Structure shared between the driver and the GSP and containing the command and message queues.
  #[repr(C)]
 -struct GspMem {
 +// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
 +pub(super) struct GspMem {
      /// Self-mapping page table entries.
 -    ptes: PteArray<{ GSP_PAGE_SIZE / size_of::<u64>() }>,
 +    ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>,
      /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the
-     /// write and read pointers that the CPU updates.
+     /// write and read pointers that the CPU updates. This means that the read pointer here is an
+     /// index into the GSP queue.
      ///
      /// This member is read-only for the GSP.
 -    cpuq: Msgq,
 +    pub(super) cpuq: Msgq,
      /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the
-     /// write and read pointers that the GSP updates.
+     /// write and read pointers that the GSP updates. This means that the read pointer here is an
+     /// index into the CPU queue.
      ///
      /// This member is read-only for the driver.
 -    gspq: Msgq,
 +    pub(super) gspq: Msgq,
 +}
 +
 +impl GspMem {
 +    const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>();
  }
  
  // SAFETY: These structs don't meet the no-padding requirements of AsBytes but
@@@ -327,27 -359,42 +369,27 @@@ impl DmaGspMem 
      //
      // # Invariants
      //
-     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
+     // - The returned value is within `0..MSGQ_NUM_PAGES`.
      fn gsp_write_ptr(&self) -> u32 {
 -        let gsp_mem = self.0.start_ptr();
 -
 -        // SAFETY:
 -        //  - The 'CoherentAllocation' contains at least one object.
 -        //  - By the invariants of `CoherentAllocation` the pointer is valid.
 -        (unsafe { (*gsp_mem).gspq.tx.write_ptr() } % MSGQ_NUM_PAGES)
 +        super::fw::gsp_mem::gsp_write_ptr(&self.0)
      }
  
      // Returns the index of the memory page the GSP will read the next command from.
      //
      // # Invariants
      //
-     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
+     // - The returned value is within `0..MSGQ_NUM_PAGES`.
      fn gsp_read_ptr(&self) -> u32 {
 -        let gsp_mem = self.0.start_ptr();
 -
 -        // SAFETY:
 -        //  - The 'CoherentAllocation' contains at least one object.
 -        //  - By the invariants of `CoherentAllocation` the pointer is valid.
 -        (unsafe { (*gsp_mem).gspq.rx.read_ptr() } % MSGQ_NUM_PAGES)
 +        super::fw::gsp_mem::gsp_read_ptr(&self.0)
      }
  
      // Returns the index of the memory page the CPU can read the next message from.
      //
      // # Invariants
      //
-     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
+     // - The returned value is within `0..MSGQ_NUM_PAGES`.
      fn cpu_read_ptr(&self) -> u32 {
 -        let gsp_mem = self.0.start_ptr();
 -
 -        // SAFETY:
 -        //  - The ['CoherentAllocation'] contains at least one object.
 -        //  - By the invariants of CoherentAllocation the pointer is valid.
 -        (unsafe { (*gsp_mem).cpuq.rx.read_ptr() } % MSGQ_NUM_PAGES)
 +        super::fw::gsp_mem::cpu_read_ptr(&self.0)
      }
  
      // Informs the GSP that it can send `elem_count` new pages into the message queue.
@@@ -359,9 -416,14 +401,9 @@@
      //
      // # Invariants
      //
-     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
+     // - The returned value is within `0..MSGQ_NUM_PAGES`.
      fn cpu_write_ptr(&self) -> u32 {
 -        let gsp_mem = self.0.start_ptr();
 -
 -        // SAFETY:
 -        //  - The 'CoherentAllocation' contains at least one object.
 -        //  - By the invariants of `CoherentAllocation` the pointer is valid.
 -        (unsafe { (*gsp_mem).cpuq.tx.write_ptr() } % MSGQ_NUM_PAGES)
 +        super::fw::gsp_mem::cpu_write_ptr(&self.0)
      }
  
      // Informs the GSP that it can process `elem_count` new pages from the command queue.
diff --cc drivers/gpu/nova-core/gsp/fw.rs
index 040b30ec3089b,25fca1f6db2c8..0000000000000
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@@ -40,75 -39,10 +39,79 @@@ use crate::
      },
  };
  
 +// TODO: Replace with `IoView` projections once available; the `unwrap()` calls go away once we
 +// switch to the new `dma::Coherent` API.
 +pub(super) mod gsp_mem {
 +    use core::sync::atomic::{
 +        fence,
 +        Ordering, //
 +    };
 +
 +    use kernel::{
 +        dma::CoherentAllocation,
 +        dma_read,
 +        dma_write,
 +        prelude::*, //
 +    };
 +
 +    use crate::gsp::cmdq::{
 +        GspMem,
 +        MSGQ_NUM_PAGES, //
 +    };
 +
 +    pub(in crate::gsp) fn gsp_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
 +    }
 +
 +    pub(in crate::gsp) fn gsp_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result<u32> { Ok(dma_read!(qs, [0]?.gspq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
 +    }
 +
 +    pub(in crate::gsp) fn cpu_read_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES) }().unwrap()
 +    }
 +
 +    pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
 +        let rptr = cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
 +
 +        // Ensure read pointer is properly ordered.
 +        fence(Ordering::SeqCst);
 +
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result {
 +            dma_write!(qs, [0]?.cpuq.rx.0.readPtr, rptr);
 +            Ok(())
 +        }()
 +        .unwrap()
 +    }
 +
 +    pub(in crate::gsp) fn cpu_write_ptr(qs: &CoherentAllocation<GspMem>) -> u32 {
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result<u32> { Ok(dma_read!(qs, [0]?.cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES) }().unwrap()
 +    }
 +
 +    pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &CoherentAllocation<GspMem>, count: u32) {
 +        let wptr = cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES;
 +
 +        // PANIC: A `dma::CoherentAllocation` always contains at least one element.
 +        || -> Result {
 +            dma_write!(qs, [0]?.cpuq.tx.0.writePtr, wptr);
 +            Ok(())
 +        }()
 +        .unwrap();
 +
 +        // Ensure all command data is visible before triggering the GSP read.
 +        fence(Ordering::SeqCst);
 +    }
 +}
 +
+ /// Maximum size of a single GSP message queue element in bytes.
+ pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =
+     num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
+ 
  /// Empty type to group methods related to heap parameters for running the GSP firmware.
  enum GspFwHeapParams {}