+++ /dev/null
-From 95efa20afcc0288cad7a14ea80136a6771b3b65a Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 22 Jan 2026 16:28:46 -0600
-Subject: gpu: nova-core: align LibosMemoryRegionInitArgument size to page size
-
-From: Alexandre Courbot <acourbot@nvidia.com>
-
-[ Upstream commit 58d26d42818c0f8c9b334cc7cf318b43046e675f ]
-
-On Turing and GA100 (i.e. the versions that use Libos v2), GSP-RM insists
-that the 'size' parameter of the LibosMemoryRegionInitArgument struct be
-aligned to 4KB. The logging buffers are already aligned to that size, so
-only the GSP_ARGUMENTS_CACHED struct needs to be adjusted. Make that
-adjustment by adding padding to the end of the struct.
-
-Signed-off-by: Timur Tabi <ttabi@nvidia.com>
-Reviewed-by: Gary Guo <gary@garyguo.net>
-Acked-by: Danilo Krummrich <dakr@kernel.org>
-Link: https://patch.msgid.link/20260122222848.2555890-12-ttabi@nvidia.com
-[acourbot@nvidia.com: GspArgumentsAligned -> GspArgumentsPadded]
-Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
-Stable-dep-of: 4da879a0d3fd ("rust: dma: use pointer projection infra for `dma_{read,write}` macro")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gsp.rs | 8 ++++----
- drivers/gpu/nova-core/gsp/fw.rs | 14 +++++++++++++-
- 2 files changed, 17 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
-index 766fd99053589..174feaca0a6b9 100644
---- a/drivers/gpu/nova-core/gsp.rs
-+++ b/drivers/gpu/nova-core/gsp.rs
-@@ -27,7 +27,7 @@ pub(crate) use fw::{
- use crate::{
- gsp::cmdq::Cmdq,
- gsp::fw::{
-- GspArgumentsCached,
-+ GspArgumentsPadded,
- LibosMemoryRegionInitArgument, //
- },
- num,
-@@ -114,7 +114,7 @@ pub(crate) struct Gsp {
- /// Command queue.
- pub(crate) cmdq: Cmdq,
- /// RM arguments.
-- rmargs: CoherentAllocation<GspArgumentsCached>,
-+ rmargs: CoherentAllocation<GspArgumentsPadded>,
- }
-
- impl Gsp {
-@@ -133,7 +133,7 @@ impl Gsp {
- logintr: LogBuffer::new(dev)?,
- logrm: LogBuffer::new(dev)?,
- cmdq: Cmdq::new(dev)?,
-- rmargs: CoherentAllocation::<GspArgumentsCached>::alloc_coherent(
-+ rmargs: CoherentAllocation::<GspArgumentsPadded>::alloc_coherent(
- dev,
- 1,
- GFP_KERNEL | __GFP_ZERO,
-@@ -149,7 +149,7 @@ impl Gsp {
- libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
- )?;
- dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
-- dma_write!(rmargs[0] = fw::GspArgumentsCached::new(cmdq))?;
-+ dma_write!(rmargs[0].inner = fw::GspArgumentsCached::new(cmdq))?;
- dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?;
- },
- }))
-diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
-index caeb0d251fe5f..83ff91614e36d 100644
---- a/drivers/gpu/nova-core/gsp/fw.rs
-+++ b/drivers/gpu/nova-core/gsp/fw.rs
-@@ -904,9 +904,21 @@ impl GspArgumentsCached {
- // SAFETY: Padding is explicit and will not contain uninitialized data.
- unsafe impl AsBytes for GspArgumentsCached {}
-
-+/// On Turing and GA100, the entries in the `LibosMemoryRegionInitArgument`
-+/// must all be a multiple of GSP_PAGE_SIZE in size, so add padding to force it
-+/// to that size.
-+#[repr(C)]
-+pub(crate) struct GspArgumentsPadded {
-+ pub(crate) inner: GspArgumentsCached,
-+ _padding: [u8; GSP_PAGE_SIZE - core::mem::size_of::<bindings::GSP_ARGUMENTS_CACHED>()],
-+}
-+
-+// SAFETY: Padding is explicit and will not contain uninitialized data.
-+unsafe impl AsBytes for GspArgumentsPadded {}
-+
- // SAFETY: This struct only contains integer types for which all bit patterns
- // are valid.
--unsafe impl FromBytes for GspArgumentsCached {}
-+unsafe impl FromBytes for GspArgumentsPadded {}
-
- /// Init arguments for the message queue.
- #[repr(transparent)]
---
-2.51.0
-
+++ /dev/null
-From ef4e635e9a5f24fa6432649c59af405de10b0692 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 9 Mar 2026 12:34:21 -0400
-Subject: gpu: nova-core: fix stack overflow in GSP memory allocation
-
-From: Tim Kovalenko <tim.kovalenko@proton.me>
-
-[ Upstream commit c7940c8bf215b9dc6211781c77ce80e76982a723 ]
-
-The `Cmdq::new` function was allocating a `PteArray` struct on the stack
-and was causing a stack overflow with 8216 bytes.
-
-Modify the `PteArray` to calculate and write the Page Table Entries
-directly into the coherent DMA buffer one-by-one. This reduces the stack
-usage quite a lot.
-
-Reported-by: Gary Guo <gary@garyguo.net>
-Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/509436-Nova/topic/.60Cmdq.3A.3Anew.60.20uses.20excessive.20stack.20size/near/570375549
-Link: https://lore.kernel.org/rust-for-linux/CANiq72mAQxbRJZDnik3Qmd4phvFwPA01O2jwaaXRh_T+2=L-qA@mail.gmail.com/
-Fixes: f38b4f105cfc ("gpu: nova-core: Create initial Gsp")
-Acked-by: Alexandre Courbot <acourbot@nvidia.com>
-Signed-off-by: Tim Kovalenko <tim.kovalenko@proton.me>
-Link: https://patch.msgid.link/20260309-drm-rust-next-v4-4-4ef485b19a4c@proton.me
-[ * Use PteArray::entry() in LogBuffer::new(),
- * Add TODO comment to use IoView projections once available,
- * Add PTE_ARRAY_SIZE constant to avoid duplication.
-
- - Danilo ]
-Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gsp.rs | 32 ++++++++++++++++---------------
- drivers/gpu/nova-core/gsp/cmdq.rs | 14 ++++++++++++--
- 2 files changed, 29 insertions(+), 17 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
-index 25cd48514c777..c69adaa92bbe7 100644
---- a/drivers/gpu/nova-core/gsp.rs
-+++ b/drivers/gpu/nova-core/gsp.rs
-@@ -47,16 +47,12 @@ struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]);
- unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {}
-
- impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {
-- /// Creates a new page table array mapping `NUM_PAGES` GSP pages starting at address `start`.
-- fn new(start: DmaAddress) -> Result<Self> {
-- let mut ptes = [0u64; NUM_PAGES];
-- for (i, pte) in ptes.iter_mut().enumerate() {
-- *pte = start
-- .checked_add(num::usize_as_u64(i) << GSP_PAGE_SHIFT)
-- .ok_or(EOVERFLOW)?;
-- }
--
-- Ok(Self(ptes))
-+ /// Returns the page table entry for `index`, for a mapping starting at `start`.
-+ // TODO: Replace with `IoView` projection once available.
-+ fn entry(start: DmaAddress, index: usize) -> Result<u64> {
-+ start
-+ .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT)
-+ .ok_or(EOVERFLOW)
- }
- }
-
-@@ -86,16 +82,22 @@ impl LogBuffer {
- NUM_PAGES * GSP_PAGE_SIZE,
- GFP_KERNEL | __GFP_ZERO,
- )?);
-- let ptes = PteArray::<NUM_PAGES>::new(obj.0.dma_handle())?;
-+
-+ let start_addr = obj.0.dma_handle();
-
- // SAFETY: `obj` has just been created and we are its sole user.
-- unsafe {
-- // Copy the self-mapping PTE at the expected location.
-+ let pte_region = unsafe {
- obj.0
-- .as_slice_mut(size_of::<u64>(), size_of_val(&ptes))?
-- .copy_from_slice(ptes.as_bytes())
-+ .as_slice_mut(size_of::<u64>(), NUM_PAGES * size_of::<u64>())?
- };
-
-+ // Write values one by one to avoid an on-stack instance of `PteArray`.
-+ for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() {
-+ let pte_value = PteArray::<0>::entry(start_addr, i)?;
-+
-+ chunk.copy_from_slice(&pte_value.to_ne_bytes());
-+ }
-+
- Ok(obj)
- }
- }
-diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
-index 1cdd1ccfe5702..e94d63f631ceb 100644
---- a/drivers/gpu/nova-core/gsp/cmdq.rs
-+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
-@@ -159,7 +159,7 @@ struct Msgq {
- #[repr(C)]
- 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.
- ///
-@@ -172,6 +172,10 @@ struct GspMem {
- 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
- // that is not a problem because they are not used outside the kernel.
- unsafe impl AsBytes for GspMem {}
-@@ -201,7 +205,13 @@ impl DmaGspMem {
-
- let gsp_mem =
- CoherentAllocation::<GspMem>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
-- dma_write!(gsp_mem, [0]?.ptes, PteArray::new(gsp_mem.dma_handle())?);
-+
-+ let start = gsp_mem.dma_handle();
-+ // Write values one by one to avoid an on-stack instance of `PteArray`.
-+ for i in 0..GspMem::PTE_ARRAY_SIZE {
-+ dma_write!(gsp_mem, [0]?.ptes.0[i], PteArray::<0>::entry(start, i)?);
-+ }
-+
- dma_write!(
- gsp_mem,
- [0]?.cpuq.tx,
---
-2.51.0
-
+++ /dev/null
-From af2e195cfb4960e6070fa7f22a78be22174b6321 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 9 Mar 2026 23:53:24 +0100
-Subject: gpu: nova-core: gsp: fix UB in DmaGspMem pointer accessors
-
-From: Danilo Krummrich <dakr@kernel.org>
-
-[ Upstream commit 0073a17b466684413ac87cf8ff6c19560db44e7a ]
-
-The DmaGspMem pointer accessor methods (gsp_write_ptr, gsp_read_ptr,
-cpu_read_ptr, cpu_write_ptr, advance_cpu_read_ptr,
-advance_cpu_write_ptr) dereference a raw pointer to DMA memory, creating
-an intermediate reference before calling volatile read/write methods.
-
-This is undefined behavior since DMA memory can be concurrently modified
-by the device.
-
-Fix this by moving the implementations into a gsp_mem module in fw.rs
-that uses the dma_read!() / dma_write!() macros, making the original
-methods on DmaGspMem thin forwarding wrappers.
-
-An alternative approach would have been to wrap the shared memory in
-Opaque, but that would have required even more unsafe code.
-
-Since the gsp_mem module lives in fw.rs (to access firmware-specific
-binding field names), GspMem, Msgq and their relevant fields are
-temporarily widened to pub(super). This will be reverted once IoView
-projections are available.
-
-Cc: Gary Guo <gary@garyguo.net>
-Closes: https://lore.kernel.org/nouveau/DGUT14ILG35P.1UMNRKU93JUM1@kernel.org/
-Fixes: 75f6b1de8133 ("gpu: nova-core: gsp: Add GSP command queue bindings and handling")
-Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
-Link: https://patch.msgid.link/20260309225408.27714-1-dakr@kernel.org
-[ Use pub(super) where possible; replace bitwise-and with modulo
- operator analogous to [1]. - Danilo ]
-Link: https://lore.kernel.org/all/20260129-nova-core-cmdq1-v3-1-2ede85493a27@nvidia.com/ [1]
-Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gsp/cmdq.rs | 71 +++++----------------
- drivers/gpu/nova-core/gsp/fw.rs | 101 ++++++++++++++++++++----------
- 2 files changed, 84 insertions(+), 88 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
-index e94d63f631ceb..db53020a495eb 100644
---- a/drivers/gpu/nova-core/gsp/cmdq.rs
-+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
-@@ -2,11 +2,7 @@
-
- use core::{
- cmp,
-- mem,
-- sync::atomic::{
-- fence,
-- Ordering, //
-- }, //
-+ mem, //
- };
-
- use kernel::{
-@@ -146,30 +142,32 @@ static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE);
- #[repr(C)]
- // There is no struct defined for this in the open-gpu-kernel-source headers.
- // Instead it is defined by code in `GspMsgQueuesInit()`.
--struct Msgq {
-+// TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
-+pub(super) struct Msgq {
- /// Header for sending messages, including the write pointer.
-- tx: MsgqTxHeader,
-+ pub(super) tx: MsgqTxHeader,
- /// Header for receiving messages, including the read pointer.
-- rx: MsgqRxHeader,
-+ pub(super) rx: MsgqRxHeader,
- /// The message queue proper.
- msgq: MsgqData,
- }
-
- /// 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<{ 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.
- ///
- /// 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.
- ///
- /// This member is read-only for the driver.
-- gspq: Msgq,
-+ pub(super) gspq: Msgq,
- }
-
- impl GspMem {
-@@ -331,12 +329,7 @@ impl DmaGspMem {
- //
- // - The returned value is between `0` and `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.
-@@ -345,12 +338,7 @@ impl DmaGspMem {
- //
- // - The returned value is between `0` and `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.
-@@ -359,27 +347,12 @@ impl DmaGspMem {
- //
- // - The returned value is between `0` and `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.
- fn advance_cpu_read_ptr(&mut self, elem_count: u32) {
-- let rptr = self.cpu_read_ptr().wrapping_add(elem_count) % MSGQ_NUM_PAGES;
--
-- // Ensure read pointer is properly ordered.
-- fence(Ordering::SeqCst);
--
-- let gsp_mem = self.0.start_ptr_mut();
--
-- // SAFETY:
-- // - The 'CoherentAllocation' contains at least one object.
-- // - By the invariants of `CoherentAllocation` the pointer is valid.
-- unsafe { (*gsp_mem).cpuq.rx.set_read_ptr(rptr) };
-+ super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count)
- }
-
- // Returns the index of the memory page the CPU can write the next command to.
-@@ -388,26 +361,12 @@ impl DmaGspMem {
- //
- // - The returned value is between `0` and `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.
- fn advance_cpu_write_ptr(&mut self, elem_count: u32) {
-- let wptr = self.cpu_write_ptr().wrapping_add(elem_count) & MSGQ_NUM_PAGES;
-- let gsp_mem = self.0.start_ptr_mut();
--
-- // SAFETY:
-- // - The 'CoherentAllocation' contains at least one object.
-- // - By the invariants of `CoherentAllocation` the pointer is valid.
-- unsafe { (*gsp_mem).cpuq.tx.set_write_ptr(wptr) };
--
-- // Ensure all command data is visible before triggering the GSP read.
-- fence(Ordering::SeqCst);
-+ super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count)
- }
- }
-
-diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
-index 83ff91614e36d..040b30ec3089b 100644
---- a/drivers/gpu/nova-core/gsp/fw.rs
-+++ b/drivers/gpu/nova-core/gsp/fw.rs
-@@ -40,6 +40,75 @@ 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);
-+ }
-+}
-+
- /// Empty type to group methods related to heap parameters for running the GSP firmware.
- enum GspFwHeapParams {}
-
-@@ -708,22 +777,6 @@ impl MsgqTxHeader {
- entryOff: num::usize_into_u32::<GSP_PAGE_SIZE>(),
- })
- }
--
-- /// Returns the value of the write pointer for this queue.
-- pub(crate) fn write_ptr(&self) -> u32 {
-- let ptr = core::ptr::from_ref(&self.0.writePtr);
--
-- // SAFETY: `ptr` is a valid pointer to a `u32`.
-- unsafe { ptr.read_volatile() }
-- }
--
-- /// Sets the value of the write pointer for this queue.
-- pub(crate) fn set_write_ptr(&mut self, val: u32) {
-- let ptr = core::ptr::from_mut(&mut self.0.writePtr);
--
-- // SAFETY: `ptr` is a valid pointer to a `u32`.
-- unsafe { ptr.write_volatile(val) }
-- }
- }
-
- // SAFETY: Padding is explicit and does not contain uninitialized data.
-@@ -739,22 +792,6 @@ impl MsgqRxHeader {
- pub(crate) fn new() -> Self {
- Self(Default::default())
- }
--
-- /// Returns the value of the read pointer for this queue.
-- pub(crate) fn read_ptr(&self) -> u32 {
-- let ptr = core::ptr::from_ref(&self.0.readPtr);
--
-- // SAFETY: `ptr` is a valid pointer to a `u32`.
-- unsafe { ptr.read_volatile() }
-- }
--
-- /// Sets the value of the read pointer for this queue.
-- pub(crate) fn set_read_ptr(&mut self, val: u32) {
-- let ptr = core::ptr::from_mut(&mut self.0.readPtr);
--
-- // SAFETY: `ptr` is a valid pointer to a `u32`.
-- unsafe { ptr.write_volatile(val) }
-- }
- }
-
- // SAFETY: Padding is explicit and does not contain uninitialized data.
---
-2.51.0
-
+++ /dev/null
-From 1c6058aaf9de44791f6355774b03c17778aa3b26 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 18 Dec 2025 16:50:50 +0100
-Subject: gpu: nova-core: gsp: get rid of redundant Result in Gsp::new()
-
-From: Danilo Krummrich <dakr@kernel.org>
-
-[ Upstream commit 032a6772d663a26005f4c17be992a716457f095b ]
-
-In Gsp::new(), utilize pin_init_scope() to get rid of the Result in the
-returned
-
- Result<impl PinInit<T, Error>>
-
-which is unnecessarily redundant.
-
-Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
-Link: https://patch.msgid.link/20251218155239.25243-4-dakr@kernel.org
-Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-Stable-dep-of: 4da879a0d3fd ("rust: dma: use pointer projection infra for `dma_{read,write}` macro")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gpu.rs | 2 +-
- drivers/gpu/nova-core/gsp.rs | 78 ++++++++++++++++++------------------
- 2 files changed, 41 insertions(+), 39 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
-index 629c9d2dc994c..50d76092fbdd7 100644
---- a/drivers/gpu/nova-core/gpu.rs
-+++ b/drivers/gpu/nova-core/gpu.rs
-@@ -281,7 +281,7 @@ impl Gpu {
-
- sec2_falcon: Falcon::new(pdev.as_ref(), spec.chipset)?,
-
-- gsp <- Gsp::new(pdev)?,
-+ gsp <- Gsp::new(pdev),
-
- _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon)? },
-
-diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
-index fb6f74797178e..8bc86e1bcac52 100644
---- a/drivers/gpu/nova-core/gsp.rs
-+++ b/drivers/gpu/nova-core/gsp.rs
-@@ -119,43 +119,45 @@ pub(crate) struct Gsp {
-
- impl Gsp {
- // Creates an in-place initializer for a `Gsp` manager for `pdev`.
-- pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> Result<impl PinInit<Self, Error>> {
-- let dev = pdev.as_ref();
-- let libos = CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
-- dev,
-- GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
-- GFP_KERNEL | __GFP_ZERO,
-- )?;
--
-- // Initialise the logging structures. The OpenRM equivalents are in:
-- // _kgspInitLibosLoggingStructures (allocates memory for buffers)
-- // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
-- let loginit = LogBuffer::new(dev)?;
-- dma_write!(libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0))?;
--
-- let logintr = LogBuffer::new(dev)?;
-- dma_write!(libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0))?;
--
-- let logrm = LogBuffer::new(dev)?;
-- dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
--
-- let cmdq = Cmdq::new(dev)?;
--
-- let rmargs = CoherentAllocation::<GspArgumentsCached>::alloc_coherent(
-- dev,
-- 1,
-- GFP_KERNEL | __GFP_ZERO,
-- )?;
-- dma_write!(rmargs[0] = fw::GspArgumentsCached::new(&cmdq))?;
-- dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", &rmargs))?;
--
-- Ok(try_pin_init!(Self {
-- libos,
-- loginit,
-- logintr,
-- logrm,
-- rmargs,
-- cmdq,
-- }))
-+ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ {
-+ pin_init::pin_init_scope(move || {
-+ let dev = pdev.as_ref();
-+ let libos = CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
-+ dev,
-+ GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
-+ GFP_KERNEL | __GFP_ZERO,
-+ )?;
-+
-+ // Initialise the logging structures. The OpenRM equivalents are in:
-+ // _kgspInitLibosLoggingStructures (allocates memory for buffers)
-+ // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
-+ let loginit = LogBuffer::new(dev)?;
-+ dma_write!(libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0))?;
-+
-+ let logintr = LogBuffer::new(dev)?;
-+ dma_write!(libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0))?;
-+
-+ let logrm = LogBuffer::new(dev)?;
-+ dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
-+
-+ let cmdq = Cmdq::new(dev)?;
-+
-+ let rmargs = CoherentAllocation::<GspArgumentsCached>::alloc_coherent(
-+ dev,
-+ 1,
-+ GFP_KERNEL | __GFP_ZERO,
-+ )?;
-+ dma_write!(rmargs[0] = fw::GspArgumentsCached::new(&cmdq))?;
-+ dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", &rmargs))?;
-+
-+ Ok(try_pin_init!(Self {
-+ libos,
-+ loginit,
-+ logintr,
-+ logrm,
-+ rmargs,
-+ cmdq,
-+ }))
-+ })
- }
- }
---
-2.51.0
-
+++ /dev/null
-From 0ebe84e0db1ec49a9d195c200101de823c6c9a14 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 18 Dec 2025 16:50:51 +0100
-Subject: gpu: nova-core: gsp: move appropriate code into pin initializer
-
-From: Danilo Krummrich <dakr@kernel.org>
-
-[ Upstream commit 7acc70476f14661149774ab88d3fe23d83ba4249 ]
-
-Relocate the code that technically fits in the pin initializer into the
-initializer itself.
-
-While, thanks to pin_init_scope(), it is also possible to keep it as is,
-moving appropriate code into the initializer has the advantage that it
-structures the dependencies of fields naturally.
-
-For instance, intermediate data that is only needed for a single field
-goes into the initializer block of this field, making it obvious that it
-is not needed by anything else.
-
-On the other hand, intermediate data that is needed for multiple fields
-to initialize remains above the initializer, naturally indicating that
-it is needed my multiple fields.
-
-Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
-Link: https://patch.msgid.link/20251218155239.25243-5-dakr@kernel.org
-Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-Stable-dep-of: 4da879a0d3fd ("rust: dma: use pointer projection infra for `dma_{read,write}` macro")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gsp.rs | 61 +++++++++++++++++-------------------
- 1 file changed, 28 insertions(+), 33 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
-index 8bc86e1bcac52..766fd99053589 100644
---- a/drivers/gpu/nova-core/gsp.rs
-+++ b/drivers/gpu/nova-core/gsp.rs
-@@ -122,41 +122,36 @@ impl Gsp {
- pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ {
- pin_init::pin_init_scope(move || {
- let dev = pdev.as_ref();
-- let libos = CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
-- dev,
-- GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
-- GFP_KERNEL | __GFP_ZERO,
-- )?;
--
-- // Initialise the logging structures. The OpenRM equivalents are in:
-- // _kgspInitLibosLoggingStructures (allocates memory for buffers)
-- // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
-- let loginit = LogBuffer::new(dev)?;
-- dma_write!(libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0))?;
--
-- let logintr = LogBuffer::new(dev)?;
-- dma_write!(libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0))?;
--
-- let logrm = LogBuffer::new(dev)?;
-- dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
--
-- let cmdq = Cmdq::new(dev)?;
--
-- let rmargs = CoherentAllocation::<GspArgumentsCached>::alloc_coherent(
-- dev,
-- 1,
-- GFP_KERNEL | __GFP_ZERO,
-- )?;
-- dma_write!(rmargs[0] = fw::GspArgumentsCached::new(&cmdq))?;
-- dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", &rmargs))?;
-
- Ok(try_pin_init!(Self {
-- libos,
-- loginit,
-- logintr,
-- logrm,
-- rmargs,
-- cmdq,
-+ libos: CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
-+ dev,
-+ GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
-+ GFP_KERNEL | __GFP_ZERO,
-+ )?,
-+ loginit: LogBuffer::new(dev)?,
-+ logintr: LogBuffer::new(dev)?,
-+ logrm: LogBuffer::new(dev)?,
-+ cmdq: Cmdq::new(dev)?,
-+ rmargs: CoherentAllocation::<GspArgumentsCached>::alloc_coherent(
-+ dev,
-+ 1,
-+ GFP_KERNEL | __GFP_ZERO,
-+ )?,
-+ _: {
-+ // Initialise the logging structures. The OpenRM equivalents are in:
-+ // _kgspInitLibosLoggingStructures (allocates memory for buffers)
-+ // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
-+ dma_write!(
-+ libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
-+ )?;
-+ dma_write!(
-+ libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
-+ )?;
-+ dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
-+ dma_write!(rmargs[0] = fw::GspArgumentsCached::new(cmdq))?;
-+ dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?;
-+ },
- }))
- })
- }
---
-2.51.0
-
+++ /dev/null
-From 26dd613c37a79884da7fd824263d4c93123688c3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 2 Mar 2026 16:42:36 +0000
-Subject: rust: dma: use pointer projection infra for `dma_{read,write}` macro
-
-From: Gary Guo <gary@garyguo.net>
-
-[ Upstream commit 4da879a0d3fd170a70994b73baa554c6913918b5 ]
-
-Current `dma_read!`, `dma_write!` macros also use a custom
-`addr_of!()`-based implementation for projecting pointers, which has
-soundness issue as it relies on absence of `Deref` implementation on types.
-It also has a soundness issue where it does not protect against unaligned
-fields (when `#[repr(packed)]` is used) so it can generate misaligned
-accesses.
-
-This commit migrates them to use the general pointer projection
-infrastructure, which handles these cases correctly.
-
-As part of migration, the macro is updated to have an improved surface
-syntax. The current macro have
-
- dma_read!(a.b.c[d].e.f)
-
-to mean `a.b.c` is a DMA coherent allocation and it should project into it
-with `[d].e.f` and do a read, which is confusing as it makes the indexing
-operator integral to the macro (so it will break if you have an array of
-`CoherentAllocation`, for example).
-
-This also is problematic as we would like to generalize
-`CoherentAllocation` from just slices to arbitrary types.
-
-Make the macro expects `dma_read!(path.to.dma, .path.inside.dma)` as the
-canonical syntax. The index operator is no longer special and is just one
-type of projection (in additional to field projection). Similarly, make
-`dma_write!(path.to.dma, .path.inside.dma, value)` become the canonical
-syntax for writing.
-
-Another issue of the current macro is that it is always fallible. This
-makes sense with existing design of `CoherentAllocation`, but once we
-support fixed size arrays with `CoherentAllocation`, it is desirable to
-have the ability to perform infallible indexing as well, e.g. doing a `[0]`
-index of `[Foo; 2]` is okay and can be checked at build-time, so forcing
-falliblity is non-ideal. To capture this, the macro is changed to use
-`[idx]` as infallible projection and `[idx]?` as fallible index projection
-(those syntax are part of the general projection infra). A benefit of this
-is that while individual indexing operation may fail, the overall
-read/write operation is not fallible.
-
-Fixes: ad2907b4e308 ("rust: add dma coherent allocator abstraction")
-Reviewed-by: Benno Lossin <lossin@kernel.org>
-Signed-off-by: Gary Guo <gary@garyguo.net>
-Link: https://patch.msgid.link/20260302164239.284084-4-gary@kernel.org
-[ Capitalize safety comments; slightly improve wording in doc-comments.
- - Danilo ]
-Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/gpu/nova-core/gsp.rs | 14 ++--
- drivers/gpu/nova-core/gsp/boot.rs | 2 +-
- drivers/gpu/nova-core/gsp/cmdq.rs | 10 ++-
- rust/kernel/dma.rs | 114 +++++++++++++-----------------
- samples/rust/rust_dma.rs | 30 ++++----
- 5 files changed, 81 insertions(+), 89 deletions(-)
-
-diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
-index 174feaca0a6b9..25cd48514c777 100644
---- a/drivers/gpu/nova-core/gsp.rs
-+++ b/drivers/gpu/nova-core/gsp.rs
-@@ -143,14 +143,14 @@ impl Gsp {
- // _kgspInitLibosLoggingStructures (allocates memory for buffers)
- // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
- dma_write!(
-- libos[0] = LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
-- )?;
-+ libos, [0]?, LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
-+ );
- dma_write!(
-- libos[1] = LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
-- )?;
-- dma_write!(libos[2] = LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0))?;
-- dma_write!(rmargs[0].inner = fw::GspArgumentsCached::new(cmdq))?;
-- dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?;
-+ libos, [1]?, LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
-+ );
-+ dma_write!(libos, [2]?, LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0));
-+ dma_write!(rmargs, [0]?.inner, fw::GspArgumentsCached::new(cmdq));
-+ dma_write!(libos, [3]?, LibosMemoryRegionInitArgument::new("RMARGS", rmargs));
- },
- }))
- })
-diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
-index 54937606b5b0a..38b4682ff01be 100644
---- a/drivers/gpu/nova-core/gsp/boot.rs
-+++ b/drivers/gpu/nova-core/gsp/boot.rs
-@@ -160,7 +160,7 @@ impl super::Gsp {
-
- let wpr_meta =
- CoherentAllocation::<GspFwWprMeta>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
-- dma_write!(wpr_meta[0] = GspFwWprMeta::new(&gsp_fw, &fb_layout))?;
-+ dma_write!(wpr_meta, [0]?, GspFwWprMeta::new(&gsp_fw, &fb_layout));
-
- self.cmdq
- .send_command(bar, commands::SetSystemInfo::new(pdev))?;
-diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
-index 3991ccc0c10f1..1cdd1ccfe5702 100644
---- a/drivers/gpu/nova-core/gsp/cmdq.rs
-+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
-@@ -201,9 +201,13 @@ impl DmaGspMem {
-
- let gsp_mem =
- CoherentAllocation::<GspMem>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
-- dma_write!(gsp_mem[0].ptes = PteArray::new(gsp_mem.dma_handle())?)?;
-- dma_write!(gsp_mem[0].cpuq.tx = MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES))?;
-- dma_write!(gsp_mem[0].cpuq.rx = MsgqRxHeader::new())?;
-+ dma_write!(gsp_mem, [0]?.ptes, PteArray::new(gsp_mem.dma_handle())?);
-+ dma_write!(
-+ gsp_mem,
-+ [0]?.cpuq.tx,
-+ MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES)
-+ );
-+ dma_write!(gsp_mem, [0]?.cpuq.rx, MsgqRxHeader::new());
-
- Ok(Self(gsp_mem))
- }
-diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
-index acc65b1e0f245..37e125bb423ad 100644
---- a/rust/kernel/dma.rs
-+++ b/rust/kernel/dma.rs
-@@ -444,6 +444,19 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
- self.count * core::mem::size_of::<T>()
- }
-
-+ /// Returns the raw pointer to the allocated region in the CPU's virtual address space.
-+ #[inline]
-+ pub fn as_ptr(&self) -> *const [T] {
-+ core::ptr::slice_from_raw_parts(self.cpu_addr.as_ptr(), self.count)
-+ }
-+
-+ /// Returns the raw pointer to the allocated region in the CPU's virtual address space as
-+ /// a mutable pointer.
-+ #[inline]
-+ pub fn as_mut_ptr(&self) -> *mut [T] {
-+ core::ptr::slice_from_raw_parts_mut(self.cpu_addr.as_ptr(), self.count)
-+ }
-+
- /// Returns the base address to the allocated region in the CPU's virtual address space.
- pub fn start_ptr(&self) -> *const T {
- self.cpu_addr.as_ptr()
-@@ -564,23 +577,6 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
- Ok(())
- }
-
-- /// Returns a pointer to an element from the region with bounds checking. `offset` is in
-- /// units of `T`, not the number of bytes.
-- ///
-- /// Public but hidden since it should only be used from [`dma_read`] and [`dma_write`] macros.
-- #[doc(hidden)]
-- pub fn item_from_index(&self, offset: usize) -> Result<*mut T> {
-- if offset >= self.count {
-- return Err(EINVAL);
-- }
-- // SAFETY:
-- // - The pointer is valid due to type invariant on `CoherentAllocation`
-- // and we've just checked that the range and index is within bounds.
-- // - `offset` can't overflow since it is smaller than `self.count` and we've checked
-- // that `self.count` won't overflow early in the constructor.
-- Ok(unsafe { self.cpu_addr.as_ptr().add(offset) })
-- }
--
- /// Reads the value of `field` and ensures that its type is [`FromBytes`].
- ///
- /// # Safety
-@@ -653,6 +649,9 @@ unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
-
- /// Reads a field of an item from an allocated region of structs.
- ///
-+/// The syntax is of the form `kernel::dma_read!(dma, proj)` where `dma` is an expression evaluating
-+/// to a [`CoherentAllocation`] and `proj` is a [projection specification](kernel::ptr::project!).
-+///
- /// # Examples
- ///
- /// ```
-@@ -667,36 +666,29 @@ unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
- /// unsafe impl kernel::transmute::AsBytes for MyStruct{};
- ///
- /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
--/// let whole = kernel::dma_read!(alloc[2]);
--/// let field = kernel::dma_read!(alloc[1].field);
-+/// let whole = kernel::dma_read!(alloc, [2]?);
-+/// let field = kernel::dma_read!(alloc, [1]?.field);
- /// # Ok::<(), Error>(()) }
- /// ```
- #[macro_export]
- macro_rules! dma_read {
-- ($dma:expr, $idx: expr, $($field:tt)*) => {{
-- (|| -> ::core::result::Result<_, $crate::error::Error> {
-- let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
-- // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
-- // dereferenced. The compiler also further validates the expression on whether `field`
-- // is a member of `item` when expanded by the macro.
-- unsafe {
-- let ptr_field = ::core::ptr::addr_of!((*item) $($field)*);
-- ::core::result::Result::Ok(
-- $crate::dma::CoherentAllocation::field_read(&$dma, ptr_field)
-- )
-- }
-- })()
-+ ($dma:expr, $($proj:tt)*) => {{
-+ let dma = &$dma;
-+ let ptr = $crate::ptr::project!(
-+ $crate::dma::CoherentAllocation::as_ptr(dma), $($proj)*
-+ );
-+ // SAFETY: The pointer created by the projection is within the DMA region.
-+ unsafe { $crate::dma::CoherentAllocation::field_read(dma, ptr) }
- }};
-- ($dma:ident [ $idx:expr ] $($field:tt)* ) => {
-- $crate::dma_read!($dma, $idx, $($field)*)
-- };
-- ($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {
-- $crate::dma_read!($($dma).*, $idx, $($field)*)
-- };
- }
-
- /// Writes to a field of an item from an allocated region of structs.
- ///
-+/// The syntax is of the form `kernel::dma_write!(dma, proj, val)` where `dma` is an expression
-+/// evaluating to a [`CoherentAllocation`], `proj` is a
-+/// [projection specification](kernel::ptr::project!), and `val` is the value to be written to the
-+/// projected location.
-+///
- /// # Examples
- ///
- /// ```
-@@ -711,37 +703,31 @@ macro_rules! dma_read {
- /// unsafe impl kernel::transmute::AsBytes for MyStruct{};
- ///
- /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
--/// kernel::dma_write!(alloc[2].member = 0xf);
--/// kernel::dma_write!(alloc[1] = MyStruct { member: 0xf });
-+/// kernel::dma_write!(alloc, [2]?.member, 0xf);
-+/// kernel::dma_write!(alloc, [1]?, MyStruct { member: 0xf });
- /// # Ok::<(), Error>(()) }
- /// ```
- #[macro_export]
- macro_rules! dma_write {
-- ($dma:ident [ $idx:expr ] $($field:tt)*) => {{
-- $crate::dma_write!($dma, $idx, $($field)*)
-- }};
-- ($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {{
-- $crate::dma_write!($($dma).*, $idx, $($field)*)
-+ (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) => {{
-+ let dma = &$dma;
-+ let ptr = $crate::ptr::project!(
-+ mut $crate::dma::CoherentAllocation::as_mut_ptr(dma), $($proj)*
-+ );
-+ let val = $val;
-+ // SAFETY: The pointer created by the projection is within the DMA region.
-+ unsafe { $crate::dma::CoherentAllocation::field_write(dma, ptr, val) }
- }};
-- ($dma:expr, $idx: expr, = $val:expr) => {
-- (|| -> ::core::result::Result<_, $crate::error::Error> {
-- let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
-- // SAFETY: `item_from_index` ensures that `item` is always a valid item.
-- unsafe { $crate::dma::CoherentAllocation::field_write(&$dma, item, $val) }
-- ::core::result::Result::Ok(())
-- })()
-+ (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) => {
-+ $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*])
-+ };
-+ (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr]? $($rest:tt)*]) => {
-+ $crate::dma_write!(@parse [$dma] [$($proj)* [$index]?] [$($rest)*])
-+ };
-+ (@parse [$dma:expr] [$($proj:tt)*] [[$index:expr] $($rest:tt)*]) => {
-+ $crate::dma_write!(@parse [$dma] [$($proj)* [$index]] [$($rest)*])
- };
-- ($dma:expr, $idx: expr, $(.$field:ident)* = $val:expr) => {
-- (|| -> ::core::result::Result<_, $crate::error::Error> {
-- let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
-- // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
-- // dereferenced. The compiler also further validates the expression on whether `field`
-- // is a member of `item` when expanded by the macro.
-- unsafe {
-- let ptr_field = ::core::ptr::addr_of_mut!((*item) $(.$field)*);
-- $crate::dma::CoherentAllocation::field_write(&$dma, ptr_field, $val)
-- }
-- ::core::result::Result::Ok(())
-- })()
-+ ($dma:expr, $($rest:tt)*) => {
-+ $crate::dma_write!(@parse [$dma] [] [$($rest)*])
- };
- }
-diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
-index f53bce2a73e3b..bcba1a6e6aaf4 100644
---- a/samples/rust/rust_dma.rs
-+++ b/samples/rust/rust_dma.rs
-@@ -68,7 +68,7 @@ impl pci::Driver for DmaSampleDriver {
- CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VALUES.len(), GFP_KERNEL)?;
-
- for (i, value) in TEST_VALUES.into_iter().enumerate() {
-- kernel::dma_write!(ca[i] = MyStruct::new(value.0, value.1))?;
-+ kernel::dma_write!(ca, [i]?, MyStruct::new(value.0, value.1));
- }
-
- let size = 4 * page::PAGE_SIZE;
-@@ -85,6 +85,20 @@ impl pci::Driver for DmaSampleDriver {
- }
- }
-
-+impl DmaSampleDriver {
-+ fn check_dma(&self) -> Result {
-+ for (i, value) in TEST_VALUES.into_iter().enumerate() {
-+ let val0 = kernel::dma_read!(self.ca, [i]?.h);
-+ let val1 = kernel::dma_read!(self.ca, [i]?.b);
-+
-+ assert_eq!(val0, value.0);
-+ assert_eq!(val1, value.1);
-+ }
-+
-+ Ok(())
-+ }
-+}
-+
- #[pinned_drop]
- impl PinnedDrop for DmaSampleDriver {
- fn drop(self: Pin<&mut Self>) {
-@@ -92,19 +106,7 @@ impl PinnedDrop for DmaSampleDriver {
-
- dev_info!(dev, "Unload DMA test driver.\n");
-
-- for (i, value) in TEST_VALUES.into_iter().enumerate() {
-- let val0 = kernel::dma_read!(self.ca[i].h);
-- let val1 = kernel::dma_read!(self.ca[i].b);
-- assert!(val0.is_ok());
-- assert!(val1.is_ok());
--
-- if let Ok(val0) = val0 {
-- assert_eq!(val0, value.0);
-- }
-- if let Ok(val1) = val1 {
-- assert_eq!(val1, value.1);
-- }
-- }
-+ assert!(self.check_dma().is_ok());
-
- for (i, entry) in self.sgt.iter().enumerate() {
- dev_info!(dev, "Entry[{}]: DMA address: {:#x}", i, entry.dma_address());
---
-2.51.0
-
rxrpc-afs-fix-missing-error-pointer-check-after-rxrp.patch
net-spacemit-fix-error-handling-in-emac_alloc_rx_des.patch
net-spacemit-fix-error-handling-in-emac_tx_mem_map.patch
-gpu-nova-core-gsp-get-rid-of-redundant-result-in-gsp.patch
-gpu-nova-core-gsp-move-appropriate-code-into-pin-ini.patch
-gpu-nova-core-align-libosmemoryregioninitargument-si.patch
-rust-dma-use-pointer-projection-infra-for-dma_-read-.patch
drm-sitronix-st7586-fix-bad-pixel-data-due-to-byte-s.patch
firmware-cs_dsp-fix-fragmentation-regression-in-firm.patch
spi-amlogic-spifc-a4-fix-dma-mapping-error-handling.patch
drivers-net-ice-fix-devlink-parameters-get-without-i.patch
iavf-fix-ptp-use-after-free-during-reset.patch
iavf-fix-incorrect-reset-handling-in-callbacks.patch
-gpu-nova-core-fix-stack-overflow-in-gsp-memory-alloc.patch
accel-amdxdna-fix-runtime-suspend-deadlock-when-ther.patch
asoc-codecs-rt1011-use-component-to-get-the-dapm-con.patch
i40e-fix-src-ip-mask-checks-and-memcpy-argument-name.patch
net-bcmgenet-fix-broken-eee-by-converting-to-phylib-.patch
acpi-osl-fix-__iomem-type-on-return-from-acpi_os_map.patch
asoc-amd-acp3x-rt5682-max9836-add-missing-error-chec.patch
-gpu-nova-core-gsp-fix-ub-in-dmagspmem-pointer-access.patch
asoc-detect-empty-dmi-strings.patch
drm-amdkfd-unreserve-bo-if-queue-update-failed.patch
asoc-amd-acp-mach-common-add-missing-error-check-for.patch