From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4855346BF; Fri, 20 Mar 2026 19:46:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036005; cv=none; b=T2WW5M88QfCNj11+1ARNJCXm4TYgyJsHYZrG4PQOLg9LHbM1ZU9XLcEVJ56dnAqdOaor/NklZAKHhCNgF1S7oQWMaxgFcgLYoCEkC8bQcMH55+zH2g2YHpD93sa29E2yi9Rc1rfFKuWueBWw+Yi3O9W3awPLRz9wdMl+XNTu+fA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036005; c=relaxed/simple; bh=7IrYb1jT8W1MG5tVtcLS6oRPxPvMpufx+jp6IJ+X/uo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ng9fX2gTWrza7+Hz0t6Xs/n4tZ+I76Hu/9UYFkd0k/EfdxEezEGepd2Ty+gmRkeRUWAPh4W+t9T3NRGc48IODQvX1F3TrJsSTUJX3P9B3DQCcIg+qVmcaP8bTiMb4sYpZWv+LZeTXYIulkaeHRlWhbB/e87fYAm2Ph3bebG2Z2Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=q6EXzaEG; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="q6EXzaEG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FE0FC19425; Fri, 20 Mar 2026 19:46:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036004; bh=7IrYb1jT8W1MG5tVtcLS6oRPxPvMpufx+jp6IJ+X/uo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q6EXzaEGhZjv5DtTK1D3QHVldQRYQNWz9Rq628sTPVJt8UpsaCgTgBKhADgkBzW1n OcZu8qW0YYDRUvK0i02i+JkAOL8r+MoCtvTAq0FZLlRQfU8Q2X+sZZCgIBikO6PbH8 mvLQ1Gmki+l0q2kgqLYU0izL9e0vM9GYVGoTESsSEGC/6mn2hQcKHXG4E5I/p+cMAO BhM4OWvMrJKkjT7i6U/nbAKzfHbBMnlTqPILazfhB0rFM5BCQtEGqBUmBxmXv1FEle Ibfg1gM7ENyU56D79wpCYY28Csho/rhpbVVyZEe5Je8WDSU3mQPpO9GQkTW5ncaQub J3/HM0rFVwLxQ== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 1/8] rust: dma: use "kernel vertical" style for imports Date: Fri, 20 Mar 2026 20:45:36 +0100 Message-ID: <20260320194626.36263-2-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Convert all imports to use "kernel vertical" style. With this, subsequent patches neither introduce unrelated changes nor leave an inconsistent import pattern. While at it, drop unnecessary imports covered by prelude::*. Link: https://docs.kernel.org/rust/coding-guidelines.html#imports Reviewed-by: Gary Guo Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Andreas Hindborg --- rust/kernel/dma.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index a396f8435739..2eea7e2f8f04 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -5,12 +5,20 @@ //! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-ma= pping.h) =20 use crate::{ - bindings, build_assert, device, - device::{Bound, Core}, - error::{to_result, Result}, + bindings, + build_assert, + device::{ + self, + Bound, + Core, // + }, + error::to_result, prelude::*, sync::aref::ARef, - transmute::{AsBytes, FromBytes}, + transmute::{ + AsBytes, + FromBytes, // + }, // }; use core::ptr::NonNull; =20 --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0E7F46BF; Fri, 20 Mar 2026 19:46:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036009; cv=none; b=U0DfDsrnIo/EgSztxHJozVPGBSguqZ+kqFPyy465M4GKP2C3XzHmnSzKPQieD05WXOAL3un4HI29KUS6RZ8OndfnxNFwdHbof2PpdXwNuwkCC5k4O4Bx80Zld5iiG/yNsi/pjRcQAPHct4VNi5KUfkFap9Uh0lEJz8d/W61O1QA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036009; c=relaxed/simple; bh=MbNR7sflXJCHbsd8e0KJm3tLAjkzfia8gexI+aafWdc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ogo9xV9XaRzvzYVfbvm8xHS5+RBqL5C23yhs/5Sa8mhB2pusJxhMT2hHBNoQzBfH9UN8SQcbEakifoVjKi9AuI/JEea9byhD2hJHfebILtLCXhA/tx7SXFisgBKKmPRIl16GFe8pFjEV3vWHQxXoHP6GcSKggZ0BvCT8gVfZQlw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iZe0sYQB; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iZe0sYQB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 584DDC4CEF7; Fri, 20 Mar 2026 19:46:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036009; bh=MbNR7sflXJCHbsd8e0KJm3tLAjkzfia8gexI+aafWdc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iZe0sYQBd5ZgmIajwKpCA3R3e+itTtaRskWmA6PA+QwKW6Rk2Nbc1tJ0fx9+QIIlD awX5zdII2taDMB0iWlRwjLgdT872YzWld/rCOEuwZjJYImeM6hZsYJwfmvvagYWiMA VtO5mZ4TM8yn6wUWNo0KPYeuDWTgdN4GI2WNOvxKreNMgEWyjgZxMnF1nGXYH7iArf h2lcyGwoNsNMxNMrej5OBhQL8wsqdIuPG2WGPRdtAs6+CMxEB1ZBG3SqhjH28WhPYd pKOQWwmxOC5nxMm6535ZA06a41tOnVGGjh2ChnLWeFJvO486zuFdtRDq+Ca4XiUS0N XXqRwXqpxpGmQ== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 2/8] rust: dma: add generalized container for types other than slices Date: Fri, 20 Mar 2026 20:45:37 +0100 Message-ID: <20260320194626.36263-3-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gary Guo Currently, `CoherentAllocation` is concecptually a DMA coherent container of a slice of `[T]` of runtime-checked length. Generalize it by creating `dma::Coherent` which can hold any value of `T`. `Coherent::alloc_with_attrs` is implemented but not yet exposed, as I believe we should not expose the way to obtain an uninitialized coherent region. `Coherent<[T]>` provides a `len` method instead of the previous `count()` method to be consistent with methods on slices. The existing type is re-defined as a type alias of `Coherent<[T]>` to ease transition. Methods in use are not yet removed. Signed-off-by: Gary Guo Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot --- rust/kernel/device.rs | 4 +- rust/kernel/dma.rs | 361 ++++++++++++++++++++++++++---------------- 2 files changed, 226 insertions(+), 139 deletions(-) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 94e0548e7687..379058eca2ed 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -575,7 +575,7 @@ pub trait DeviceContext: private::Sealed {} /// The bound context indicates that for the entire duration of the lifeti= me of a [`Device`] /// reference, the [`Device`] is guaranteed to be bound to a driver. /// -/// Some APIs, such as [`dma::CoherentAllocation`] or [`Devres`] rely on t= he [`Device`] to be bound, +/// Some APIs, such as [`dma::Coherent`] or [`Devres`] rely on the [`Devic= e`] to be bound, /// which can be proven with the [`Bound`] device context. /// /// Any abstraction that can guarantee a scope where the corresponding bus= device is bound, should @@ -584,7 +584,7 @@ pub trait DeviceContext: private::Sealed {} /// /// [`Devres`]: kernel::devres::Devres /// [`Devres::access`]: kernel::devres::Devres::access -/// [`dma::CoherentAllocation`]: kernel::dma::CoherentAllocation +/// [`dma::Coherent`]: kernel::dma::Coherent pub struct Bound; =20 mod private { diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 2eea7e2f8f04..ff3e147f1a23 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -6,7 +6,6 @@ =20 use crate::{ bindings, - build_assert, device::{ self, Bound, @@ -14,6 +13,7 @@ }, error::to_result, prelude::*, + ptr::KnownSize, sync::aref::ARef, transmute::{ AsBytes, @@ -357,18 +357,17 @@ fn from(direction: DataDirection) -> Self { /// This is an abstraction around the `dma_alloc_coherent` API which is us= ed to allocate and map /// large coherent DMA regions. /// -/// A [`CoherentAllocation`] instance contains a pointer to the allocated = region (in the +/// A [`Coherent`] instance contains a pointer to the allocated region (in= the /// processor's virtual address space) and the device address which can be= given to the device -/// as the DMA address base of the region. The region is released once [`C= oherentAllocation`] +/// as the DMA address base of the region. The region is released once [`C= oherent`] /// is dropped. /// /// # Invariants /// -/// - For the lifetime of an instance of [`CoherentAllocation`], the `cpu_= addr` is a valid pointer +/// - For the lifetime of an instance of [`Coherent`], the `cpu_addr` is a= valid pointer /// to an allocated region of coherent memory and `dma_handle` is the DM= A address base of the /// region. -/// - The size in bytes of the allocation is equal to `size_of:: * coun= t`. -/// - `size_of:: * count` fits into a `usize`. +/// - The size in bytes of the allocation is equal to size information via= pointer. // TODO // // DMA allocations potentially carry device resources (e.g.IOMMU mappings)= , hence for soundness @@ -379,124 +378,260 @@ fn from(direction: DataDirection) -> Self { // allocation from surviving device unbind; it would require RCU read side= critical sections to // access the memory, which may require subsequent unnecessary copies. // -// Hence, find a way to revoke the device resources of a `CoherentAllocati= on`, but not the -// entire `CoherentAllocation` including the allocated memory itself. -pub struct CoherentAllocation { +// Hence, find a way to revoke the device resources of a `Coherent`, but n= ot the +// entire `Coherent` including the allocated memory itself. +pub struct Coherent { dev: ARef, dma_handle: DmaAddress, - count: usize, cpu_addr: NonNull, dma_attrs: Attrs, } =20 -impl CoherentAllocation { - /// Allocates a region of `size_of:: * count` of coherent memory. +impl Coherent { + /// Returns the size in bytes of this allocation. + #[inline] + pub fn size(&self) -> usize { + T::size(self.cpu_addr.as_ptr()) + } + + /// Returns the raw pointer to the allocated region in the CPU's virtu= al address space. + #[inline] + pub fn as_ptr(&self) -> *const T { + self.cpu_addr.as_ptr() + } + + /// Returns the raw pointer to the allocated region in the CPU's virtu= al address space as + /// a mutable pointer. + #[inline] + pub fn as_mut_ptr(&self) -> *mut T { + self.cpu_addr.as_ptr() + } + + /// Returns a DMA handle which may be given to the device as the DMA a= ddress base of + /// the region. + #[inline] + pub fn dma_handle(&self) -> DmaAddress { + self.dma_handle + } + + /// Returns a reference to the data in the region. /// - /// # Examples + /// # Safety /// - /// ``` - /// # use kernel::device::{Bound, Device}; - /// use kernel::dma::{attrs::*, CoherentAllocation}; + /// * Callers must ensure that the device does not read/write to/from = memory while the returned + /// slice is live. + /// * Callers must ensure that this call does not race with a write to= the same region while + /// the returned slice is live. + #[inline] + pub unsafe fn as_ref(&self) -> &T { + // SAFETY: per safety requirement. + unsafe { &*self.as_ptr() } + } + + /// Returns a mutable reference to the data in the region. /// - /// # fn test(dev: &Device) -> Result { - /// let c: CoherentAllocation =3D - /// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_N= O_WARN)?; - /// # Ok::<(), Error>(()) } - /// ``` - pub fn alloc_attrs( + /// # Safety + /// + /// * Callers must ensure that the device does not read/write to/from = memory while the returned + /// slice is live. + /// * Callers must ensure that this call does not race with a read or = write to the same region + /// while the returned slice is live. + #[expect(clippy::mut_from_ref, reason =3D "unsafe to use API")] + #[inline] + pub unsafe fn as_mut(&self) -> &mut T { + // SAFETY: per safety requirement. + unsafe { &mut *self.as_mut_ptr() } + } + + /// Reads the value of `field` and ensures that its type is [`FromByte= s`]. + /// + /// # Safety + /// + /// This must be called from the [`dma_read`] macro which ensures that= the `field` pointer is + /// validated beforehand. + /// + /// Public but hidden since it should only be used from [`dma_read`] m= acro. + #[doc(hidden)] + pub unsafe fn field_read(&self, field: *const F) -> F { + // SAFETY: + // - By the safety requirements field is valid. + // - Using read_volatile() here is not sound as per the usual rule= s, the usage here is + // a special exception with the following notes in place. When dea= ling with a potential + // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that + // read on a valid memory is not UB. Currently read_volatile() is = used for this, and the + // rationale behind is that it should generate the same code as RE= AD_ONCE() which the + // kernel already relies on to avoid UB on data races. Note that t= he usage of + // read_volatile() is limited to this particular case, it cannot b= e used to prevent + // the UB caused by racing between two kernel functions nor do the= y provide atomicity. + unsafe { field.read_volatile() } + } + + /// Writes a value to `field` and ensures that its type is [`AsBytes`]. + /// + /// # Safety + /// + /// This must be called from the [`dma_write`] macro which ensures tha= t the `field` pointer is + /// validated beforehand. + /// + /// Public but hidden since it should only be used from [`dma_write`] = macro. + #[doc(hidden)] + pub unsafe fn field_write(&self, field: *mut F, val: F) { + // SAFETY: + // - By the safety requirements field is valid. + // - Using write_volatile() here is not sound as per the usual rul= es, the usage here is + // a special exception with the following notes in place. When dea= ling with a potential + // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that + // write on a valid memory is not UB. Currently write_volatile() i= s used for this, and the + // rationale behind is that it should generate the same code as WR= ITE_ONCE() which the + // kernel already relies on to avoid UB on data races. Note that t= he usage of + // write_volatile() is limited to this particular case, it cannot = be used to prevent + // the UB caused by racing between two kernel functions nor do the= y provide atomicity. + unsafe { field.write_volatile(val) } + } +} + +impl Coherent { + /// Allocates a region of `T` of coherent memory. + #[expect(unused)] + fn alloc_with_attrs( dev: &device::Device, - count: usize, gfp_flags: kernel::alloc::Flags, dma_attrs: Attrs, - ) -> Result> { - build_assert!( - core::mem::size_of::() > 0, - "It doesn't make sense for the allocated type to be a ZST" - ); + ) -> Result { + const { + assert!( + core::mem::size_of::() > 0, + "It doesn't make sense for the allocated type to be a ZST" + ); + } =20 - let size =3D count - .checked_mul(core::mem::size_of::()) - .ok_or(EOVERFLOW)?; let mut dma_handle =3D 0; // SAFETY: Device pointer is guaranteed as valid by the type invar= iant on `Device`. let addr =3D unsafe { bindings::dma_alloc_attrs( dev.as_raw(), - size, + core::mem::size_of::(), &mut dma_handle, gfp_flags.as_raw(), dma_attrs.as_raw(), ) }; - let addr =3D NonNull::new(addr).ok_or(ENOMEM)?; + let cpu_addr =3D NonNull::new(addr.cast()).ok_or(ENOMEM)?; // INVARIANT: - // - We just successfully allocated a coherent region which is acc= essible for - // `count` elements, hence the cpu address is valid. We also hol= d a refcounted reference - // to the device. - // - The allocated `size` is equal to `size_of:: * count`. - // - The allocated `size` fits into a `usize`. + // - We just successfully allocated a coherent region which is ade= quately sized for `T`, + // hence the cpu address is valid. + // - We also hold a refcounted reference to the device. Ok(Self { dev: dev.into(), dma_handle, - count, - cpu_addr: addr.cast(), + cpu_addr, dma_attrs, }) } =20 - /// Performs the same functionality as [`CoherentAllocation::alloc_att= rs`], except the - /// `dma_attrs` is 0 by default. - pub fn alloc_coherent( + /// Allocates a region of `[T; len]` of coherent memory. + fn alloc_slice_with_attrs( dev: &device::Device, - count: usize, + len: usize, gfp_flags: kernel::alloc::Flags, - ) -> Result> { - CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0)) + dma_attrs: Attrs, + ) -> Result> { + const { + assert!( + core::mem::size_of::() > 0, + "It doesn't make sense for the allocated type to be a ZST" + ); + } + + // `dma_alloc_attrs` cannot handle zero-length allocation, bail ea= rly. + if len =3D=3D 0 { + Err(EINVAL)?; + } + + let size =3D core::mem::size_of::().checked_mul(len).ok_or(ENOM= EM)?; + let mut dma_handle =3D 0; + // SAFETY: Device pointer is guaranteed as valid by the type invar= iant on `Device`. + let addr =3D unsafe { + bindings::dma_alloc_attrs( + dev.as_raw(), + size, + &mut dma_handle, + gfp_flags.as_raw(), + dma_attrs.as_raw(), + ) + }; + let cpu_addr =3D NonNull::slice_from_raw_parts(NonNull::new(addr.c= ast()).ok_or(ENOMEM)?, len); + // INVARIANT: + // - We just successfully allocated a coherent region which is ade= quately sized for + // `[T; len]`, hence the cpu address is valid. + // - We also hold a refcounted reference to the device. + Ok(Coherent { + dev: dev.into(), + dma_handle, + cpu_addr, + dma_attrs, + }) } +} =20 +impl Coherent<[T]> { /// Returns the number of elements `T` in this allocation. /// /// Note that this is not the size of the allocation in bytes, which i= s provided by /// [`Self::size`]. - pub fn count(&self) -> usize { - self.count + #[inline] + #[expect(clippy::len_without_is_empty, reason =3D "Coherent slice is n= ever empty")] + pub fn len(&self) -> usize { + self.cpu_addr.len() } +} =20 - /// Returns the size in bytes of this allocation. - pub fn size(&self) -> usize { - // INVARIANT: The type invariant of `Self` guarantees that `size_o= f:: * count` fits into - // a `usize`. - self.count * core::mem::size_of::() - } +// Type alias for compatibility. +#[doc(hidden)] +pub type CoherentAllocation =3D Coherent<[T]>; =20 - /// Returns the raw pointer to the allocated region in the CPU's virtu= al address space. - #[inline] - pub fn as_ptr(&self) -> *const [T] { - core::ptr::slice_from_raw_parts(self.cpu_addr.as_ptr(), self.count) +impl CoherentAllocation { + /// Allocates a region of `size_of:: * count` of coherent memory. + /// + /// # Examples + /// + /// ``` + /// # use kernel::device::{Bound, Device}; + /// use kernel::dma::{attrs::*, CoherentAllocation}; + /// + /// # fn test(dev: &Device) -> Result { + /// let c: CoherentAllocation =3D + /// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_N= O_WARN)?; + /// # Ok::<(), Error>(()) } + /// ``` + pub fn alloc_attrs( + dev: &device::Device, + count: usize, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + ) -> Result> { + Coherent::alloc_slice_with_attrs(dev, count, gfp_flags, dma_attrs) } =20 - /// Returns the raw pointer to the allocated region in the CPU's virtu= al 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.c= ount) + /// Performs the same functionality as [`CoherentAllocation::alloc_att= rs`], except the + /// `dma_attrs` is 0 by default. + pub fn alloc_coherent( + dev: &device::Device, + count: usize, + gfp_flags: kernel::alloc::Flags, + ) -> Result> { + CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0)) } =20 /// Returns the base address to the allocated region in the CPU's virt= ual address space. pub fn start_ptr(&self) -> *const T { - self.cpu_addr.as_ptr() + self.as_ptr().cast() } =20 /// Returns the base address to the allocated region in the CPU's virt= ual address space as /// a mutable pointer. pub fn start_ptr_mut(&mut self) -> *mut T { - self.cpu_addr.as_ptr() - } - - /// Returns a DMA handle which may be given to the device as the DMA a= ddress base of - /// the region. - pub fn dma_handle(&self) -> DmaAddress { - self.dma_handle + self.as_mut_ptr().cast() } =20 /// Returns a DMA handle starting at `offset` (in units of `T`) which = may be given to the @@ -504,11 +639,9 @@ pub fn dma_handle(&self) -> DmaAddress { /// /// Returns `EINVAL` if `offset` is not within the bounds of the alloc= ation. pub fn dma_handle_with_offset(&self, offset: usize) -> Result { - if offset >=3D self.count { + if offset >=3D self.len() { Err(EINVAL) } else { - // INVARIANT: The type invariant of `Self` guarantees that `si= ze_of:: * count` fits - // into a `usize`, and `offset` is inferior to `count`. Ok(self.dma_handle + (offset * core::mem::size_of::()) as D= maAddress) } } @@ -516,7 +649,7 @@ pub fn dma_handle_with_offset(&self, offset: usize) -> = Result { /// Common helper to validate a range applied from the allocated regio= n in the CPU's virtual /// address space. fn validate_range(&self, offset: usize, count: usize) -> Result { - if offset.checked_add(count).ok_or(EOVERFLOW)? > self.count { + if offset.checked_add(count).ok_or(EOVERFLOW)? > self.len() { return Err(EINVAL); } Ok(()) @@ -601,66 +734,20 @@ pub unsafe fn write(&mut self, src: &[T], offset: usi= ze) -> Result { }; Ok(()) } - - /// Reads the value of `field` and ensures that its type is [`FromByte= s`]. - /// - /// # Safety - /// - /// This must be called from the [`dma_read`] macro which ensures that= the `field` pointer is - /// validated beforehand. - /// - /// Public but hidden since it should only be used from [`dma_read`] m= acro. - #[doc(hidden)] - pub unsafe fn field_read(&self, field: *const F) -> F { - // SAFETY: - // - By the safety requirements field is valid. - // - Using read_volatile() here is not sound as per the usual rule= s, the usage here is - // a special exception with the following notes in place. When dea= ling with a potential - // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that - // read on a valid memory is not UB. Currently read_volatile() is = used for this, and the - // rationale behind is that it should generate the same code as RE= AD_ONCE() which the - // kernel already relies on to avoid UB on data races. Note that t= he usage of - // read_volatile() is limited to this particular case, it cannot b= e used to prevent - // the UB caused by racing between two kernel functions nor do the= y provide atomicity. - unsafe { field.read_volatile() } - } - - /// Writes a value to `field` and ensures that its type is [`AsBytes`]. - /// - /// # Safety - /// - /// This must be called from the [`dma_write`] macro which ensures tha= t the `field` pointer is - /// validated beforehand. - /// - /// Public but hidden since it should only be used from [`dma_write`] = macro. - #[doc(hidden)] - pub unsafe fn field_write(&self, field: *mut F, val: F) { - // SAFETY: - // - By the safety requirements field is valid. - // - Using write_volatile() here is not sound as per the usual rul= es, the usage here is - // a special exception with the following notes in place. When dea= ling with a potential - // race from a hardware or code outside kernel (e.g. user-space pr= ogram), we need that - // write on a valid memory is not UB. Currently write_volatile() i= s used for this, and the - // rationale behind is that it should generate the same code as WR= ITE_ONCE() which the - // kernel already relies on to avoid UB on data races. Note that t= he usage of - // write_volatile() is limited to this particular case, it cannot = be used to prevent - // the UB caused by racing between two kernel functions nor do the= y provide atomicity. - unsafe { field.write_volatile(val) } - } } =20 /// Note that the device configured to do DMA must be halted before this o= bject is dropped. -impl Drop for CoherentAllocation { +impl Drop for Coherent { fn drop(&mut self) { - let size =3D self.count * core::mem::size_of::(); + let size =3D T::size(self.cpu_addr.as_ptr()); // SAFETY: Device pointer is guaranteed as valid by the type invar= iant on `Device`. // The cpu address, and the dma handle are valid due to the type i= nvariants on - // `CoherentAllocation`. + // `Coherent`. unsafe { bindings::dma_free_attrs( self.dev.as_raw(), size, - self.start_ptr_mut().cast(), + self.cpu_addr.as_ptr().cast(), self.dma_handle, self.dma_attrs.as_raw(), ) @@ -668,20 +755,20 @@ fn drop(&mut self) { } } =20 -// SAFETY: It is safe to send a `CoherentAllocation` to another thread if = `T` +// SAFETY: It is safe to send a `Coherent` to another thread if `T` // can be sent to another thread. -unsafe impl Send for CoherentAllocation = {} +unsafe impl Send for Coherent {} =20 /// 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` i= s an expression evaluating -/// to a [`CoherentAllocation`] and `proj` is a [projection specification]= (kernel::ptr::project!). +/// to a [`Coherent`] and `proj` is a [projection specification](kernel::p= tr::project!). /// /// # Examples /// /// ``` /// use kernel::device::Device; -/// use kernel::dma::{attrs::*, CoherentAllocation}; +/// use kernel::dma::{attrs::*, Coherent}; /// /// struct MyStruct { field: u32, } /// @@ -690,7 +777,7 @@ unsafe impl Send for Coh= erentAllocation {} /// // SAFETY: Instances of `MyStruct` have no uninitialized portions. /// unsafe impl kernel::transmute::AsBytes for MyStruct{}; /// -/// # fn test(alloc: &kernel::dma::CoherentAllocation) -> Result= { +/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { /// let whole =3D kernel::dma_read!(alloc, [2]?); /// let field =3D kernel::dma_read!(alloc, [1]?.field); /// # Ok::<(), Error>(()) } @@ -700,17 +787,17 @@ macro_rules! dma_read { ($dma:expr, $($proj:tt)*) =3D> {{ let dma =3D &$dma; let ptr =3D $crate::ptr::project!( - $crate::dma::CoherentAllocation::as_ptr(dma), $($proj)* + $crate::dma::Coherent::as_ptr(dma), $($proj)* ); // SAFETY: The pointer created by the projection is within the DMA= region. - unsafe { $crate::dma::CoherentAllocation::field_read(dma, ptr) } + unsafe { $crate::dma::Coherent::field_read(dma, ptr) } }}; } =20 /// 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 +/// evaluating to a [`Coherent`], `proj` is a /// [projection specification](kernel::ptr::project!), and `val` is the va= lue to be written to the /// projected location. /// @@ -718,7 +805,7 @@ macro_rules! dma_read { /// /// ``` /// use kernel::device::Device; -/// use kernel::dma::{attrs::*, CoherentAllocation}; +/// use kernel::dma::{attrs::*, Coherent}; /// /// struct MyStruct { member: u32, } /// @@ -727,7 +814,7 @@ macro_rules! dma_read { /// // SAFETY: Instances of `MyStruct` have no uninitialized portions. /// unsafe impl kernel::transmute::AsBytes for MyStruct{}; /// -/// # fn test(alloc: &kernel::dma::CoherentAllocation) -> Result= { +/// # fn test(alloc: &kernel::dma::Coherent<[MyStruct]>) -> Result { /// kernel::dma_write!(alloc, [2]?.member, 0xf); /// kernel::dma_write!(alloc, [1]?, MyStruct { member: 0xf }); /// # Ok::<(), Error>(()) } @@ -737,11 +824,11 @@ macro_rules! dma_write { (@parse [$dma:expr] [$($proj:tt)*] [, $val:expr]) =3D> {{ let dma =3D &$dma; let ptr =3D $crate::ptr::project!( - mut $crate::dma::CoherentAllocation::as_mut_ptr(dma), $($proj)* + mut $crate::dma::Coherent::as_mut_ptr(dma), $($proj)* ); let val =3D $val; // SAFETY: The pointer created by the projection is within the DMA= region. - unsafe { $crate::dma::CoherentAllocation::field_write(dma, ptr, va= l) } + unsafe { $crate::dma::Coherent::field_write(dma, ptr, val) } }}; (@parse [$dma:expr] [$($proj:tt)*] [.$field:tt $($rest:tt)*]) =3D> { $crate::dma_write!(@parse [$dma] [$($proj)* .$field] [$($rest)*]) --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1DADC303A07; Fri, 20 Mar 2026 19:46:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036014; cv=none; b=OvAqSNWpl93O3uLwQ837fCoG1AbxVnxCz/6fKCHHb4+SqE3glXTXleOKYaND5GuG/pcA2V2MLTmG6wXIK+I7YxbP2VD+Scs1RUcQ+B+czhwOKv9MG3COAPL8KpO76Xmr52EvpW+57nevju0LnauRPTNDn2tIBl4B+cAX63f+NbA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036014; c=relaxed/simple; bh=+gN5RwGnaQSMZxMY/xHZRgUoqJ9A7H33p/A6H++uu+Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lPRQvVS96xRmWh+yeD93xgUsar9apnScwM3K2TkEnPKfkWbaIGfA1QDSRwnOMsYGofJ6qoHnIlMmwBVP01QLEJ3xTENELoZ4Szo8W3wCNIFl0rJ4Vw588XlPRcK9D5j2KmEbkLcw8jD3MXkCuloVImfAqoaTS05qYasIQsm04y8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m0TQqxrA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="m0TQqxrA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id ED350C2BC9E; Fri, 20 Mar 2026 19:46:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036013; bh=+gN5RwGnaQSMZxMY/xHZRgUoqJ9A7H33p/A6H++uu+Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=m0TQqxrAiJ2ko/8lyY+apyFbcQwBGhgd/kyPlfzTBCNxT3fRY3NRgtj8hol892lJy LAg8spl6UfGZd33v6OKys/zmq7I5FpoYMg/+F36D8FjyQHThzDBu5dy27ZxE8JiUkS u5g4sWr/dUdcXzrA4g/07bTWFoBx7P0fy5j+EljWrKHHpL1VwW0zUNcfrL6DR+OYK0 55yMcISG7hDa23wvIppSGTX4mUI6k8mNSKSJunV7iHc6Fy3pv95n1xjvpIPp1JC70/ CKp0bodrdNpIvydELXoS4eLRNMAc4RjlFbQF80BK8FiWuZRzNJJDWRHzlROU2hhjyz BVodYOfpgdWHQ== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 3/8] rust: dma: add zeroed constructor to `Coherent` Date: Fri, 20 Mar 2026 20:45:38 +0100 Message-ID: <20260320194626.36263-4-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gary Guo These constructors create a coherent container of a single object instead of slice. They are named `zeroed` and `zeroed_with_attrs` to emphasis that they are created initialized zeroed. It is intended that there'll be new constructors that take `PinInit` instead of zeroing. Signed-off-by: Gary Guo Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot --- rust/kernel/dma.rs | 81 ++++++++++++++++++++++++++++++++++++---- samples/rust/rust_dma.rs | 8 ++-- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index ff3e147f1a23..db645b01bdd0 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -47,7 +47,7 @@ pub trait Device: AsRef> { /// # Safety /// /// This method must not be called concurrently with any DMA allocatio= n or mapping primitives, - /// such as [`CoherentAllocation::alloc_attrs`]. + /// such as [`Coherent::zeroed`]. unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result { // SAFETY: // - By the type invariant of `device::Device`, `self.as_ref().as_= raw()` is valid. @@ -64,7 +64,7 @@ unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result { /// # Safety /// /// This method must not be called concurrently with any DMA allocatio= n or mapping primitives, - /// such as [`CoherentAllocation::alloc_attrs`]. + /// such as [`Coherent::zeroed`]. unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result { // SAFETY: // - By the type invariant of `device::Device`, `self.as_ref().as_= raw()` is valid. @@ -83,7 +83,7 @@ unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> = Result { /// # Safety /// /// This method must not be called concurrently with any DMA allocatio= n or mapping primitives, - /// such as [`CoherentAllocation::alloc_attrs`]. + /// such as [`Coherent::zeroed`]. unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result { // SAFETY: // - By the type invariant of `device::Device`, `self.as_ref().as_= raw()` is valid. @@ -102,7 +102,7 @@ unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMas= k) -> Result { /// # Safety /// /// This method must not be called concurrently with any DMA allocatio= n or mapping primitives, - /// such as [`CoherentAllocation::alloc_attrs`]. + /// such as [`Coherent::zeroed`]. unsafe fn dma_set_max_seg_size(&self, size: u32) { // SAFETY: // - By the type invariant of `device::Device`, `self.as_ref().as_= raw()` is valid. @@ -202,12 +202,12 @@ pub const fn value(&self) -> u64 { /// /// ``` /// # use kernel::device::{Bound, Device}; -/// use kernel::dma::{attrs::*, CoherentAllocation}; +/// use kernel::dma::{attrs::*, Coherent}; /// /// # fn test(dev: &Device) -> Result { /// let attribs =3D DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN; -/// let c: CoherentAllocation =3D -/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?; +/// let c: Coherent<[u64]> =3D +/// Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, attribs)?; /// # Ok::<(), Error>(()) } /// ``` #[derive(Clone, Copy, PartialEq)] @@ -492,7 +492,6 @@ pub unsafe fn field_write(&self, field: *mu= t F, val: F) { =20 impl Coherent { /// Allocates a region of `T` of coherent memory. - #[expect(unused)] fn alloc_with_attrs( dev: &device::Device, gfp_flags: kernel::alloc::Flags, @@ -529,6 +528,35 @@ fn alloc_with_attrs( }) } =20 + /// Allocates a region of type `T` of coherent memory. + /// + /// # Examples + /// + /// ``` + /// # use kernel::device::{Bound, Device}; + /// use kernel::dma::{attrs::*, Coherent}; + /// + /// # fn test(dev: &Device) -> Result { + /// let c: Coherent<[u64; 4]> =3D + /// Coherent::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)= ?; + /// # Ok::<(), Error>(()) } + /// ``` + #[inline] + pub fn zeroed_with_attrs( + dev: &device::Device, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + ) -> Result { + Self::alloc_with_attrs(dev, gfp_flags | __GFP_ZERO, dma_attrs) + } + + /// Performs the same functionality as [`Coherent::zeroed_with_attrs`]= , except the + /// `dma_attrs` is 0 by default. + #[inline] + pub fn zeroed(dev: &device::Device, gfp_flags: kernel::alloc::F= lags) -> Result { + Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0)) + } + /// Allocates a region of `[T; len]` of coherent memory. fn alloc_slice_with_attrs( dev: &device::Device, @@ -572,6 +600,43 @@ fn alloc_slice_with_attrs( dma_attrs, }) } + + /// Allocates a zeroed region of type `T` of coherent memory. + /// + /// Unlike `Coherent::<[T; N]>::zeroed_with_attrs`, `Coherent::::ze= roed_slices` support + /// a runtime length. + /// + /// # Examples + /// + /// ``` + /// # use kernel::device::{Bound, Device}; + /// use kernel::dma::{attrs::*, Coherent}; + /// + /// # fn test(dev: &Device) -> Result { + /// let c: Coherent<[u64]> =3D + /// Coherent::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR= _NO_WARN)?; + /// # Ok::<(), Error>(()) } + /// ``` + #[inline] + pub fn zeroed_slice_with_attrs( + dev: &device::Device, + len: usize, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + ) -> Result> { + Coherent::alloc_slice_with_attrs(dev, len, gfp_flags | __GFP_ZERO,= dma_attrs) + } + + /// Performs the same functionality as [`Coherent::zeroed_slice_with_a= ttrs`], except the + /// `dma_attrs` is 0 by default. + #[inline] + pub fn zeroed_slice( + dev: &device::Device, + len: usize, + gfp_flags: kernel::alloc::Flags, + ) -> Result> { + Self::zeroed_slice_with_attrs(dev, len, gfp_flags, Attrs(0)) + } } =20 impl Coherent<[T]> { diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index ce39b5545097..314ef51cd86c 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -6,7 +6,7 @@ =20 use kernel::{ device::Core, - dma::{CoherentAllocation, DataDirection, Device, DmaMask}, + dma::{Coherent, DataDirection, Device, DmaMask}, page, pci, prelude::*, scatterlist::{Owned, SGTable}, @@ -16,7 +16,7 @@ #[pin_data(PinnedDrop)] struct DmaSampleDriver { pdev: ARef, - ca: CoherentAllocation, + ca: Coherent<[MyStruct]>, #[pin] sgt: SGTable>>, } @@ -64,8 +64,8 @@ fn probe(pdev: &pci::Device, _info: &Self::IdInfo) = -> impl PinInit =3D - CoherentAllocation::alloc_coherent(pdev.as_ref(), TEST_VAL= UES.len(), GFP_KERNEL)?; + let ca: Coherent<[MyStruct]> =3D + Coherent::zeroed_slice(pdev.as_ref(), TEST_VALUES.len(), G= FP_KERNEL)?; =20 for (i, value) in TEST_VALUES.into_iter().enumerate() { kernel::dma_write!(ca, [i]?, MyStruct::new(value.0, value.= 1)); --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3FB64303A07; Fri, 20 Mar 2026 19:46:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036018; cv=none; b=FhxSyJLuGRlJgCmHFuG9mfOx0DqdiN0UyPhmm/1Knv1cVTgof/4677phpn+KXB5Uc9lJAYgv4+jaFZqTkDgRez6exmqpXhbS7mVy3DhM0gsuubNgJiuKwok+FZUOrXusUAfoilVw2XcS8pt2mgo0ep+6DcYO+4QlLgYlqn1Zv6U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036018; c=relaxed/simple; bh=bJbrB0VL/Fq7E9V44DRCigpB+wY3S4NcLkRFRufFS7M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JsUpUDhoB0lWsTUAexMZ2KnlOUV0OrJDnvCRgfEm8s3MWfJwwDziOGFJiAbFKpRSZBM0HfqNg/Cr+5I8t48xo3c9tJDhBgmPKRgdXCoZTo+vmPlVY2yTMtOKuR6dtbTg91ScKgbuMXctXSRWEbU22At+GIG5NW9LiRtStUQv9hM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bd8RIXQ9; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bd8RIXQ9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 31C21C19425; Fri, 20 Mar 2026 19:46:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036018; bh=bJbrB0VL/Fq7E9V44DRCigpB+wY3S4NcLkRFRufFS7M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bd8RIXQ9LDhCMlK/CuErA3v3cVa+frbm8fmS4zaPQQNfR0B/7wQYtMLD+cXZ4VB1x jPPdkW3X7KthBuh9+efabxKGtI9bzkGOKZh5GlUVUA1olPdtqkb0+tv9z1PEoA2ltx iLAIAv0XR06pKtI1x76Ft9Uz8PmLnfcrdNKmx64MrgxIxQjdPbEtIczXiED5v8++4V m7l3vXWOVE++zHjPYoWxfLK7+PdX0Ue/ZFPhe4ODntd7+t6vZayBDwLAWGMBcINe6e NB9R0x9e3GsEhPEHhbiCcH0KloJKWuj6P2tscbdOqoDuy2bG5I6DGHdanEGuPSUGUe RMF0EGYCVupNg== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 4/8] rust: dma: introduce dma::CoherentBox for memory initialization Date: Fri, 20 Mar 2026 20:45:39 +0100 Message-ID: <20260320194626.36263-5-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently, dma::Coherent cannot safely provide (mutable) access to its underlying memory because the memory might be concurrently accessed by a DMA device. This makes it difficult to safely initialize the memory before handing it over to the hardware. Introduce dma::CoherentBox, a type that encapsulates a dma::Coherent before its DMA address is exposed to the device. dma::CoherentBox can guarantee exclusive access to the inner dma::Coherent and implement Deref and DerefMut. Once the memory is properly initialized, dma::CoherentBox can be converted into a regular dma::Coherent. Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Andreas Hindborg Reviewed-by: Gary Guo --- rust/kernel/dma.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index db645b01bdd0..cefb54f0424a 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -20,7 +20,13 @@ FromBytes, // }, // }; -use core::ptr::NonNull; +use core::{ + ops::{ + Deref, + DerefMut, // + }, + ptr::NonNull, // +}; =20 /// DMA address type. /// @@ -352,6 +358,152 @@ fn from(direction: DataDirection) -> Self { } } =20 +/// CPU-owned DMA allocation that can be converted into a device-shared [`= Coherent`] object. +/// +/// Unlike [`Coherent`], a [`CoherentBox`] is guaranteed to be fully owned= by the CPU -- its DMA +/// address is not exposed and it cannot be accessed by a device. This mea= ns it can safely be used +/// like a normal boxed allocation (e.g. direct reads, writes, and mutable= slices are all safe). +/// +/// A typical use is to allocate a [`CoherentBox`], populate it with norma= l CPU access, and then +/// convert it into a [`Coherent`] object to share it with the device. +/// +/// # Examples +/// +/// `CoherentBox`: +/// +/// ``` +/// # use kernel::device::{ +/// # Bound, +/// # Device, +/// # }; +/// use kernel::dma::{attrs::*, +/// Coherent, +/// CoherentBox, +/// }; +/// +/// # fn test(dev: &Device) -> Result { +/// let mut dmem: CoherentBox =3D CoherentBox::zeroed(dev, GFP_KERNEL= )?; +/// *dmem =3D 42; +/// let dmem: Coherent =3D dmem.into(); +/// # Ok::<(), Error>(()) } +/// ``` +/// +/// `CoherentBox<[T]>`: +/// +/// +/// ``` +/// # use kernel::device::{ +/// # Bound, +/// # Device, +/// # }; +/// use kernel::dma::{attrs::*, +/// Coherent, +/// CoherentBox, +/// }; +/// +/// # fn test(dev: &Device) -> Result { +/// let mut dmem: CoherentBox<[u64]> =3D CoherentBox::zeroed_slice(dev, 4,= GFP_KERNEL)?; +/// dmem.fill(42); +/// let dmem: Coherent<[u64]> =3D dmem.into(); +/// # Ok::<(), Error>(()) } +/// ``` +pub struct CoherentBox(Cohere= nt); + +impl CoherentBox<[T]> { + /// [`CoherentBox`] variant of [`Coherent::zeroed_slice_with_attrs`]. + #[inline] + pub fn zeroed_slice_with_attrs( + dev: &device::Device, + count: usize, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + ) -> Result { + Coherent::zeroed_slice_with_attrs(dev, count, gfp_flags, dma_attrs= ).map(Self) + } + + /// Same as [CoherentBox::zeroed_slice_with_attrs], but with `dma::Att= rs(0)`. + #[inline] + pub fn zeroed_slice( + dev: &device::Device, + count: usize, + gfp_flags: kernel::alloc::Flags, + ) -> Result { + Self::zeroed_slice_with_attrs(dev, count, gfp_flags, Attrs(0)) + } + + /// Initializes the element at `i` using the given initializer. + /// + /// Returns `EINVAL` if `i` is out of bounds. + pub fn init_at(&mut self, i: usize, init: impl Init) -> Result + where + Error: From, + { + if i >=3D self.0.len() { + return Err(EINVAL); + } + + let ptr =3D &raw mut self[i]; + + // SAFETY: + // - `ptr` is valid, properly aligned, and within this allocation. + // - `T: AsBytes + FromBytes` guarantees all bit patterns are vali= d, so partial writes on + // error cannot leave the element in an invalid state. + // - The DMA address has not been exposed yet, so there is no conc= urrent device access. + unsafe { init.__init(ptr)? }; + + Ok(()) + } +} + +impl CoherentBox { + /// Same as [`CoherentBox::zeroed_slice_with_attrs`], but for a single= element. + #[inline] + pub fn zeroed_with_attrs( + dev: &device::Device, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + ) -> Result { + Coherent::zeroed_with_attrs(dev, gfp_flags, dma_attrs).map(Self) + } + + /// Same as [`CoherentBox::zeroed_slice`], but for a single element. + #[inline] + pub fn zeroed(dev: &device::Device, gfp_flags: kernel::alloc::F= lags) -> Result { + Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0)) + } +} + +impl Deref for CoherentBox= { + type Target =3D T; + + #[inline] + fn deref(&self) -> &Self::Target { + // SAFETY: + // - We have not exposed the DMA address yet, so there can't be an= y concurrent access by a + // device. + // - We have exclusive access to `self.0`. + unsafe { self.0.as_ref() } + } +} + +impl DerefMut for CoherentBox= { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: + // - We have not exposed the DMA address yet, so there can't be an= y concurrent access by a + // device. + // - We have exclusive access to `self.0`. + unsafe { self.0.as_mut() } + } +} + +impl From> for= Coherent { + #[inline] + fn from(value: CoherentBox) -> Self { + value.0 + } +} + /// An abstraction of the `dma_alloc_coherent` API. /// /// This is an abstraction around the `dma_alloc_coherent` API which is us= ed to allocate and map --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9132F353EF2; Fri, 20 Mar 2026 19:47:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036022; cv=none; b=S2OI+ww8qnazbOf7DtZzDrE2hQwC4fq+3Ynn9LPYc2UlZtFosZpjbOCNx3ERkxWzZr5AFWhvJozVP6HkwNp36aIt/b1KLXeRlNrXJx2sqeTf4bsVLaMbbW9239VhHOWFdCZt8ERGMr5A4gbuR7C9OljqRmprGMOs42gHRrLhWlk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036022; c=relaxed/simple; bh=ju9WyBxPqyhdguAHgPK1Hx/Tksq0dRThuffsKQ3jlpE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DR4VBc+cLMu/pefrI54ZTJB3ip3Dn7ejZQtMl/29vPC4UubYCxUAxz6tYN94eTsMHyY4B4MKfS2XTustyp3imkJOe/Fkge4kCdfBQBDAqtnXuc8CmWQXcBlMIGBN1BFaVI7LXmPfu9QeDWLcq55gVPZIyI+hDyjNu5wPqdTODU0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YDSa3Qr6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YDSa3Qr6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 69C74C2BC87; Fri, 20 Mar 2026 19:46:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036022; bh=ju9WyBxPqyhdguAHgPK1Hx/Tksq0dRThuffsKQ3jlpE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YDSa3Qr6JFZRqqZLQfMA9a0TfK0uoNtJcg4U8dI8QYEkz2CP7v7g1K0IFpZj9yLlI dXPS94g4ZCX7jFUhgMeh7cVBfYF8zmqMWmcod2/fWEsugYVFtM6ENu5znrCin3nqbC L5sm9dQ3VQOPiO2UnvKphnuwXH03tB6GpKICe3tPbEBy020QkUKW0fmGc3LqhkNh+z /HPdt35vQTisvSGbtXMO5tWL5zu8frMsB2kmcbqBlM7wH2oACBL/R5DFIu/m0gHtap PU3UhYo/FntqaZcuQZx56wdknXiKMglFIvM4CCYzHvrfKOf+cnp3atWhAwtYkCv+CU MEw+MB2D3beTg== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 5/8] rust: dma: add Coherent:init() and Coherent::init_with_attrs() Date: Fri, 20 Mar 2026 20:45:40 +0100 Message-ID: <20260320194626.36263-6-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Analogous to Coherent::zeroed() and Coherent::zeroed_with_attrs(), add Coherent:init() and Coherent::init_with_attrs() which both take an impl Init argument initializing the DMA coherent memory. Compared to CoherentInit, Coherent::init() is a one-shot constructor that runs an Init closure and immediately exposes the DMA handle, whereas CoherentInit is a multi-stage initializer that provides safe &mut T access by withholding the DMA address until converted to Coherent. Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Andreas Hindborg Reviewed-by: Gary Guo --- rust/kernel/dma.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index cefb54f0424a..6d2bec52806b 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -709,6 +709,44 @@ pub fn zeroed(dev: &device::Device, gfp_flags: = kernel::alloc::Flags) -> R Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0)) } =20 + /// Same as [`Coherent::zeroed_with_attrs`], but instead of a zero-ini= tialization the memory is + /// initialized with `init`. + pub fn init_with_attrs( + dev: &device::Device, + gfp_flags: kernel::alloc::Flags, + dma_attrs: Attrs, + init: impl Init, + ) -> Result + where + Error: From, + { + let dmem =3D Self::alloc_with_attrs(dev, gfp_flags, dma_attrs)?; + let ptr =3D dmem.as_mut_ptr(); + + // SAFETY: + // - `ptr` is valid, properly aligned, and points to exclusively o= wned memory. + // - If `__init` fails, `self` is dropped, which safely frees the = underlying `Coherent`'s + // DMA memory. `T: AsBytes + FromBytes` ensures there are no com= plex `Drop` requirements + // we are bypassing. + unsafe { init.__init(ptr)? }; + + Ok(dmem) + } + + /// Same as [`Coherent::zeroed`], but instead of a zero-initialization= the memory is initialized + /// with `init`. + #[inline] + pub fn init( + dev: &device::Device, + gfp_flags: kernel::alloc::Flags, + init: impl Init, + ) -> Result + where + Error: From, + { + Self::init_with_attrs(dev, gfp_flags, Attrs(0), init) + } + /// Allocates a region of `[T; len]` of coherent memory. fn alloc_slice_with_attrs( dev: &device::Device, --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B26313559F5; Fri, 20 Mar 2026 19:47:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036026; cv=none; b=LqyP8VvaJxjWDQQClflPDUHigCRvWTkjuky4cCsEGnguqITwAFFWATCBtKl+8ptYGl6LubLhm6R1QFmYXo4E9YaZd0Kkc79PR1W9u9PdBUvsTAc9Ep116DNAdZ6ig0X30GIstoN3ZpDPtOQdhcVyDtzau9f4ieUU1QnJGMobrdA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036026; c=relaxed/simple; bh=yc78EFSFizHHU1W4DvyE+4pE9pQQdt0bGIk0ILUuLHM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kVYtbdcjEhWlf3Om/SqOeZnoVKncDht4WRSK7mxkwt4zh+kozF7g2ZfgyH6YEYCyqrkxU/i/S62nXoq2Hnea737lZ45GJnuHk1BswxCUzR6m0JBr35VsrpKS8/F1iRkKFCnic40UZjjo78SmLgIVjF7kyBBHEFpE9xMQPT3V/I0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RS/plEgH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RS/plEgH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A2FD2C4CEF7; Fri, 20 Mar 2026 19:47:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036026; bh=yc78EFSFizHHU1W4DvyE+4pE9pQQdt0bGIk0ILUuLHM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RS/plEgHZ2b/fcU7+m23NjZIXr1vn73AdcNkXaEE+f+jhAlYT1IL4zp/nHw2MjBBp HnkaMiqTht7Xkq6AQdlIPp9RHS7Uj4L6C/Sdu4TWkk7bZS9ITwgsqr9xGc/Wi9vjap vxtzvGt78R1lkvLLbDTn3pXiHjaLG8hb372GoSC4QD3ZO8JexrKvDp7OwJrhEvkZGd /Lavmr27PrELMEQK4K93VkH1JBMVURccwkoJLTVAWAb9X4yA65UWMRFyI+WX8O0EUK DbxOEeMVQ2kYlJCwKsSbwITKGHKVkVxL9iOPB6MvH1mwAzBiZefAXxXlQH9B5VX3AU uy11tKDMk49qA== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 6/8] gpu: nova-core: use Coherent::init to initialize GspFwWprMeta Date: Fri, 20 Mar 2026 20:45:41 +0100 Message-ID: <20260320194626.36263-7-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Convert wpr_meta to use Coherent::init() and simplify the initialization. It also avoids a separate initialization of GspFwWprMeta on the stack. Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo --- drivers/gpu/nova-core/gsp/boot.rs | 7 ++----- drivers/gpu/nova-core/gsp/fw.rs | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/= boot.rs index 5e73bd769dcc..e55210ebb6d1 100644 --- a/drivers/gpu/nova-core/gsp/boot.rs +++ b/drivers/gpu/nova-core/gsp/boot.rs @@ -2,8 +2,7 @@ =20 use kernel::{ device, - dma::CoherentAllocation, - dma_write, + dma::Coherent, io::poll::read_poll_timeout, pci, prelude::*, @@ -164,9 +163,7 @@ pub(crate) fn boot( bar, )?; =20 - let wpr_meta =3D - CoherentAllocation::::alloc_coherent(dev, 1, GFP= _KERNEL | __GFP_ZERO)?; - dma_write!(wpr_meta, [0]?, GspFwWprMeta::new(&gsp_fw, &fb_layout)); + let wpr_meta =3D Coherent::init(dev, GFP_KERNEL, GspFwWprMeta::new= (&gsp_fw, &fb_layout))?; =20 self.cmdq .send_command_no_wait(bar, commands::SetSystemInfo::new(pdev))= ?; diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index a061131b5412..4e3bfc6c4c47 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -204,7 +204,9 @@ pub(crate) fn wpr_heap_size(&self, chipset: Chipset, fb= _size: u64) -> u64 { /// Structure passed to the GSP bootloader, containing the framebuffer lay= out as well as the DMA /// addresses of the GSP bootloader and firmware. #[repr(transparent)] -pub(crate) struct GspFwWprMeta(bindings::GspFwWprMeta); +pub(crate) struct GspFwWprMeta { + inner: bindings::GspFwWprMeta, +} =20 // SAFETY: Padding is explicit and does not contain uninitialized data. unsafe impl AsBytes for GspFwWprMeta {} @@ -217,10 +219,14 @@ unsafe impl FromBytes for GspFwWprMeta {} type GspFwWprMetaBootInfo =3D bindings::GspFwWprMeta__bindgen_ty_1__bindge= n_ty_1; =20 impl GspFwWprMeta { - /// Fill in and return a `GspFwWprMeta` suitable for booting `gsp_firm= ware` using the + /// Returns an initializer for a `GspFwWprMeta` suitable for booting `= gsp_firmware` using the /// `fb_layout` layout. - pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) ->= Self { - Self(bindings::GspFwWprMeta { + pub(crate) fn new<'a>( + gsp_firmware: &'a GspFirmware, + fb_layout: &'a FbLayout, + ) -> impl Init + 'a { + #[allow(non_snake_case)] + let init_inner =3D init!(bindings::GspFwWprMeta { // CAST: we want to store the bits of `GSP_FW_WPR_META_MAGIC` = unmodified. magic: bindings::GSP_FW_WPR_META_MAGIC as u64, revision: u64::from(bindings::GSP_FW_WPR_META_REVISION), @@ -255,7 +261,11 @@ pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layou= t: &FbLayout) -> Self { fbSize: fb_layout.fb.end - fb_layout.fb.start, vgaWorkspaceOffset: fb_layout.vga_workspace.start, vgaWorkspaceSize: fb_layout.vga_workspace.end - fb_layout.vga_= workspace.start, - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(GspFwWprMeta { + inner <- init_inner, }) } } --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0750D26461F; Fri, 20 Mar 2026 19:47:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036031; cv=none; b=QTIhvGoIRCDCUBNWzNOvtKcroFXRLSocp/J2jt1qzcor6GphhFJReyrHOF5u4B7BQXwTucpFtzptw+tXfjTZhOcg9DqkoJcqHuEYegIPGL7zGFa5dnvtUUqZgTMwgaQs7ZZq+BycCtEgUBF3oG4MDJ1v6D0RRvf3bEAIGEaW07k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036031; c=relaxed/simple; bh=H19eCxDOxVLkokvJ6mibpjYwYFYpFnwlymEHSUKk2CM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ec8sZo3fsDu3o2UvBy86p1A71cMSyLVbm2m2+hmqQ5NmZTDCnd38urHfV0se0toig7ubl7Ke2dkxRaWNApHfwwAIrT+ZFx3wRykwqo1fVGh3IolpB+hMwlUNk/gFUuLcyzHOjklgqrXDxcaRO9Pl2q0PKSrsqWSGMladeD2KkH8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XfiuRB0r; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XfiuRB0r" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DB4BBC2BCAF; Fri, 20 Mar 2026 19:47:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036030; bh=H19eCxDOxVLkokvJ6mibpjYwYFYpFnwlymEHSUKk2CM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XfiuRB0rmDmC7dl8VW4ICAzjET0MPrSZ9M/Kxxz/Vbq4Y7R1xbCYg7GFgHNtvkEz9 KCR4fLPOCokYjrVerEKuP/3JWyKGiSWhgZlb7tXTTsFBHpo6+VtyG5kxN8AFU+OHud uYuNpxG/JaG1tLiySY0M89cpXZEIy4OV6vL+LSKp+4T094FwVjeele90B15LxxVd5F aM5ZzulIxzSG4Onk03Mg7iZ6sbj//7bW5HR6S/uUx+nsq8m946rTRcR7M9i3+OcQq5 JBU5qLiGZURTfRxksi7i/V/Ey0q+jKSBqB9hXtjJMNrArV1l8JV6lyQiKcNIgnEjSW cuXY1ut48OF/A== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 7/8] gpu: nova-core: convert Gsp::new() to use CoherentBox Date: Fri, 20 Mar 2026 20:45:42 +0100 Message-ID: <20260320194626.36263-8-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Convert libos (LibosMemoryRegionInitArgument) and rmargs (GspArgumentsPadded) to use CoherentBox / Coherent::init() and simplify the initialization. This also avoids separate initialization on the stack. Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo --- drivers/gpu/nova-core/gsp.rs | 47 +++++++++++-------------- drivers/gpu/nova-core/gsp/fw.rs | 62 +++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 72f173726f87..f0a50bdc4c00 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -5,10 +5,11 @@ use kernel::{ device, dma::{ + Coherent, CoherentAllocation, + CoherentBox, DmaAddress, // }, - dma_write, pci, prelude::*, transmute::AsBytes, // @@ -106,7 +107,7 @@ fn new(dev: &device::Device) -> Result { #[pin_data] pub(crate) struct Gsp { /// Libos arguments. - pub(crate) libos: CoherentAllocation, + pub(crate) libos: Coherent<[LibosMemoryRegionInitArgument]>, /// Init log buffer. loginit: LogBuffer, /// Interrupts log buffer. @@ -117,7 +118,7 @@ pub(crate) struct Gsp { #[pin] pub(crate) cmdq: Cmdq, /// RM arguments. - rmargs: CoherentAllocation, + rmargs: Coherent, } =20 impl Gsp { @@ -126,34 +127,28 @@ pub(crate) fn new(pdev: &pci::Device) = -> impl PinInit= ::alloc_coherent( - dev, - GSP_PAGE_SIZE / size_of::(), - GFP_KERNEL | __GFP_ZERO, - )?, loginit: LogBuffer::new(dev)?, logintr: LogBuffer::new(dev)?, logrm: LogBuffer::new(dev)?, cmdq <- Cmdq::new(dev), - rmargs: CoherentAllocation::::alloc_co= herent( - dev, - 1, - GFP_KERNEL | __GFP_ZERO, - )?, - _: { - // Initialise the logging structures. The OpenRM equiv= alents are in: - // _kgspInitLibosLoggingStructures (allocates memory f= or buffers) - // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs= [] array) - dma_write!( - libos, [0]?, LibosMemoryRegionInitArgument::new("L= OGINIT", &loginit.0) - ); - dma_write!( - libos, [1]?, LibosMemoryRegionInitArgument::new("L= OGINTR", &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)); + rmargs: Coherent::init(dev, GFP_KERNEL, GspArgumentsPadded= ::new(&cmdq))?, + libos: { + let mut libos =3D CoherentBox::zeroed_slice( + dev, + GSP_PAGE_SIZE / size_of::(), + GFP_KERNEL, + )?; + + libos.init_at(0, LibosMemoryRegionInitArgument::new("L= OGINIT", &loginit.0))?; + libos.init_at(1, LibosMemoryRegionInitArgument::new("L= OGINTR", &logintr.0))?; + libos.init_at(2, LibosMemoryRegionInitArgument::new("L= OGRM", &logrm.0))?; + libos.init_at(3, LibosMemoryRegionInitArgument::new("R= MARGS", rmargs))?; + + libos.into() }, })) }) diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index 4e3bfc6c4c47..0d8daf6a80b7 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -9,11 +9,12 @@ use core::ops::Range; =20 use kernel::{ - dma::CoherentAllocation, + dma::Coherent, prelude::*, ptr::{ Alignable, - Alignment, // + Alignment, + KnownSize, // }, sizes::{ SZ_128K, @@ -648,7 +649,9 @@ unsafe impl AsBytes for RunCpuSequencer {} /// The memory allocated for the arguments must remain until the GSP sends= the /// init_done RPC. #[repr(transparent)] -pub(crate) struct LibosMemoryRegionInitArgument(bindings::LibosMemoryRegio= nInitArgument); +pub(crate) struct LibosMemoryRegionInitArgument { + inner: bindings::LibosMemoryRegionInitArgument, +} =20 // SAFETY: Padding is explicit and does not contain uninitialized data. unsafe impl AsBytes for LibosMemoryRegionInitArgument {} @@ -658,10 +661,10 @@ unsafe impl AsBytes for LibosMemoryRegionInitArgument= {} unsafe impl FromBytes for LibosMemoryRegionInitArgument {} =20 impl LibosMemoryRegionInitArgument { - pub(crate) fn new( + pub(crate) fn new<'a, A: AsBytes + FromBytes + KnownSize + ?Sized>( name: &'static str, - obj: &CoherentAllocation, - ) -> Self { + obj: &'a Coherent, + ) -> impl Init + 'a { /// Generates the `ID8` identifier required for some GSP objects. fn id8(name: &str) -> u64 { let mut bytes =3D [0u8; core::mem::size_of::()]; @@ -673,7 +676,8 @@ fn id8(name: &str) -> u64 { u64::from_ne_bytes(bytes) } =20 - Self(bindings::LibosMemoryRegionInitArgument { + #[allow(non_snake_case)] + let init_inner =3D init!(bindings::LibosMemoryRegionInitArgument { id8: id8(name), pa: obj.dma_handle(), size: num::usize_as_u64(obj.size()), @@ -683,7 +687,11 @@ fn id8(name: &str) -> u64 { loc: num::u32_into_u8::< { bindings::LibosMemoryRegionLoc_LIBOS_MEMORY_REGION_LOC_S= YSMEM }, >(), - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(LibosMemoryRegionInitArgument { + inner <- init_inner, }) } } @@ -862,15 +870,23 @@ unsafe impl FromBytes for GspMsgElement {} =20 /// Arguments for GSP startup. #[repr(transparent)] -pub(crate) struct GspArgumentsCached(bindings::GSP_ARGUMENTS_CACHED); +#[derive(Zeroable)] +pub(crate) struct GspArgumentsCached { + inner: bindings::GSP_ARGUMENTS_CACHED, +} =20 impl GspArgumentsCached { /// Creates the arguments for starting the GSP up using `cmdq` as its = command queue. - pub(crate) fn new(cmdq: &Cmdq) -> Self { - Self(bindings::GSP_ARGUMENTS_CACHED { - messageQueueInitArguments: MessageQueueInitArguments::new(cmdq= ).0, + pub(crate) fn new(cmdq: &Cmdq) -> impl Init + '_ { + #[allow(non_snake_case)] + let init_inner =3D init!(bindings::GSP_ARGUMENTS_CACHED { + messageQueueInitArguments <- MessageQueueInitArguments::new(cm= dq), bDmemStack: 1, - ..Default::default() + ..Zeroable::init_zeroed() + }); + + init!(GspArgumentsCached { + inner <- init_inner, }) } } @@ -882,11 +898,21 @@ unsafe impl AsBytes for GspArgumentsCached {} /// must all be a multiple of GSP_PAGE_SIZE in size, so add padding to for= ce it /// to that size. #[repr(C)] +#[derive(Zeroable)] pub(crate) struct GspArgumentsPadded { pub(crate) inner: GspArgumentsCached, _padding: [u8; GSP_PAGE_SIZE - core::mem::size_of::()], } =20 +impl GspArgumentsPadded { + pub(crate) fn new(cmdq: &Cmdq) -> impl Init + '_ { + init!(GspArgumentsPadded { + inner <- GspArgumentsCached::new(cmdq), + ..Zeroable::init_zeroed() + }) + } +} + // SAFETY: Padding is explicit and will not contain uninitialized data. unsafe impl AsBytes for GspArgumentsPadded {} =20 @@ -895,18 +921,18 @@ unsafe impl AsBytes for GspArgumentsPadded {} unsafe impl FromBytes for GspArgumentsPadded {} =20 /// Init arguments for the message queue. -#[repr(transparent)] -struct MessageQueueInitArguments(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS); +type MessageQueueInitArguments =3D bindings::MESSAGE_QUEUE_INIT_ARGUMENTS; =20 impl MessageQueueInitArguments { /// Creates a new init arguments structure for `cmdq`. - fn new(cmdq: &Cmdq) -> Self { - Self(bindings::MESSAGE_QUEUE_INIT_ARGUMENTS { + #[allow(non_snake_case)] + fn new(cmdq: &Cmdq) -> impl Init + '_ { + init!(MessageQueueInitArguments { sharedMemPhysAddr: cmdq.dma_handle(), pageTableEntryCount: num::usize_into_u32::<{ Cmdq::NUM_PTES }>= (), cmdQueueOffset: num::usize_as_u64(Cmdq::CMDQ_OFFSET), statQueueOffset: num::usize_as_u64(Cmdq::STATQ_OFFSET), - ..Default::default() + ..Zeroable::init_zeroed() }) } } --=20 2.53.0 From nobody Sat Apr 4 03:18:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27A5326461F; Fri, 20 Mar 2026 19:47:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036035; cv=none; b=NCW4+FkLkdyD2sTW/8FDBOI8hwiMvQbKmiLgbF1No3zeCBZpZtNsBIQjegOjkUHYmMSK8tDs95JjFxRSdxnVWvwsxmii1FxOG624JcGW6TjOISPcss1gPpzt9AXdJQta4FttNgf+pxlC4wa3KhnOlYf6UMw/cSgFVU3gvB0kLnc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774036035; c=relaxed/simple; bh=kJQ6AOlUSC0Z7dQ3ABfDnQ43PiQSAaKqxuGU0btOtaI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R80fM75T+2Jix96dtVQeuDVRGhTEY3tB+WUn1isSs+nca6nxRXRMv9foRMAfawg5GBVprq747Xa9M7hXIkPXQBV5YNqFqhDVYS1nLkYPLxWJqH/y1qc2xyTHm+T1D31F0+FJcsLF3nqQnsaEHys2aDinKh0TtWHiTEJJAY+NIqY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qgeRGwfO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qgeRGwfO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FF42C2BC87; Fri, 20 Mar 2026 19:47:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774036034; bh=kJQ6AOlUSC0Z7dQ3ABfDnQ43PiQSAaKqxuGU0btOtaI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qgeRGwfOJGZFKbLJ3oAa2We51rBAXugmtmyTIeSEI5kjmIa9op5sB7klGzJ/ubzjI f/sIlAyx+Ku2mY9D2uDzl/5X7imli75QOl4VFS0vdCJHmfZr7rme5lhXs1jtwZHkBr 2lqX8y2NzH9jSXYFUg34CGpHOGZAUQGChOVa3OAKrEKhydVfKxt/X9C3AmZzyocGRT 4+U1cJufxnrnleyXJWgHr9znn+hBGVQkOsYAXNgwqh7NOm7zVjcM/w2jaJZ9gGq3KF WUbxjV5PuqusyjiQe9bksoHsVB9F7zmXtT/0cf1ShtvWYgpIsdYPo/L+TrhMWbEZIW XeIEFWMBqDLRA== From: Danilo Krummrich To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, abdiel.janulgue@gmail.com, daniel.almeida@collabora.com, robin.murphy@arm.com Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 8/8] gpu: nova-core: convert to new dma::Coherent API Date: Fri, 20 Mar 2026 20:45:43 +0100 Message-ID: <20260320194626.36263-9-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320194626.36263-1-dakr@kernel.org> References: <20260320194626.36263-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gary Guo Remove all usages of dma::CoherentAllocation and use the new dma::Coherent type instead. Note that there are still remainders of the old dma::CoherentAllocation API, such as as_slice() and as_slice_mut(). Signed-off-by: Gary Guo Co-developed-by: Danilo Krummrich Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Gary Guo --- drivers/gpu/nova-core/dma.rs | 19 ++++++------- drivers/gpu/nova-core/falcon.rs | 5 ++-- drivers/gpu/nova-core/gsp.rs | 21 ++++++++------ drivers/gpu/nova-core/gsp/cmdq.rs | 21 ++++++-------- drivers/gpu/nova-core/gsp/fw.rs | 46 ++++++++++--------------------- 5 files changed, 47 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/nova-core/dma.rs b/drivers/gpu/nova-core/dma.rs index 7215398969da..3c19d5ffcfe8 100644 --- a/drivers/gpu/nova-core/dma.rs +++ b/drivers/gpu/nova-core/dma.rs @@ -9,13 +9,13 @@ =20 use kernel::{ device, - dma::CoherentAllocation, + dma::Coherent, page::PAGE_SIZE, prelude::*, // }; =20 pub(crate) struct DmaObject { - dma: CoherentAllocation, + dma: Coherent<[u8]>, } =20 impl DmaObject { @@ -24,23 +24,22 @@ pub(crate) fn new(dev: &device::Device, = len: usize) -> Result, data: &[u= 8]) -> Result { - Self::new(dev, data.len()).and_then(|mut dma_obj| { - // SAFETY: We have just allocated the DMA memory, we are the o= nly users and - // we haven't made the device aware of the handle yet. - unsafe { dma_obj.write(data, 0)? } - Ok(dma_obj) - }) + let dma_obj =3D Self::new(dev, data.len())?; + // SAFETY: We have just allocated the DMA memory, we are the only = users and + // we haven't made the device aware of the handle yet. + unsafe { dma_obj.as_mut()[..data.len()].copy_from_slice(data) }; + Ok(dma_obj) } } =20 impl Deref for DmaObject { - type Target =3D CoherentAllocation; + type Target =3D Coherent<[u8]>; =20 fn deref(&self) -> &Self::Target { &self.dma diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon= .rs index 7097a206ec3c..5bf8da8760bf 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -26,8 +26,7 @@ gpu::Chipset, num::{ self, - FromSafeCast, - IntoSafeCast, // + FromSafeCast, // }, regs, regs::macros::RegisterBase, // @@ -653,7 +652,7 @@ fn dma_wr( } FalconMem::Dmem =3D> ( 0, - dma_obj.dma_handle_with_offset(load_offsets.src_start.into= _safe_cast())?, + dma_obj.dma_handle() + DmaAddress::from(load_offsets.src_s= tart), ), }; if dma_start % DmaAddress::from(DMA_LEN) > 0 { diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index f0a50bdc4c00..a045c4189989 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -6,13 +6,15 @@ device, dma::{ Coherent, - CoherentAllocation, CoherentBox, DmaAddress, // }, pci, prelude::*, - transmute::AsBytes, // + transmute::{ + AsBytes, + FromBytes, // + }, // }; =20 pub(crate) mod cmdq; @@ -44,6 +46,9 @@ #[repr(C)] struct PteArray([u64; NUM_ENTRIES]); =20 +/// SAFETY: arrays of `u64` implement `FromBytes` and we are but a wrapper= around one. +unsafe impl FromBytes for PteArray = {} + /// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper a= round one. unsafe impl AsBytes for PteArray {} =20 @@ -71,26 +76,24 @@ fn entry(start: DmaAddress, index: usize) -> Result { /// then pp points to index into the buffer where the next logging entry w= ill /// be written. Therefore, the logging data is valid if: /// 1 <=3D pp < sizeof(buffer)/sizeof(u64) -struct LogBuffer(CoherentAllocation); +struct LogBuffer(Coherent<[u8]>); =20 impl LogBuffer { /// Creates a new `LogBuffer` mapped on `dev`. fn new(dev: &device::Device) -> Result { const NUM_PAGES: usize =3D RM_LOG_BUFFER_NUM_PAGES; =20 - let mut obj =3D Self(CoherentAllocation::::alloc_coherent( + let obj =3D Self(Coherent::::zeroed_slice( dev, NUM_PAGES * GSP_PAGE_SIZE, - GFP_KERNEL | __GFP_ZERO, + GFP_KERNEL, )?); =20 let start_addr =3D obj.0.dma_handle(); =20 // SAFETY: `obj` has just been created and we are its sole user. - let pte_region =3D unsafe { - obj.0 - .as_slice_mut(size_of::(), NUM_PAGES * size_of::= ())? - }; + let pte_region =3D + unsafe { &mut obj.0.as_mut()[size_of::()..][..NUM_PAGES *= size_of::()] }; =20 // Write values one by one to avoid an on-stack instance of `PteAr= ray`. for (i, chunk) in pte_region.chunks_exact_mut(size_of::()).en= umerate() { diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index d36a62ba1c60..f38790601a0f 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -7,7 +7,7 @@ use kernel::{ device, dma::{ - CoherentAllocation, + Coherent, DmaAddress, // }, dma_write, @@ -207,7 +207,7 @@ unsafe impl AsBytes for GspMem {} // that is not a problem because they are not used outside the kernel. unsafe impl FromBytes for GspMem {} =20 -/// Wrapper around [`GspMem`] to share it with the GPU using a [`CoherentA= llocation`]. +/// Wrapper around [`GspMem`] to share it with the GPU using a [`Coherent`= ]. /// /// This provides the low-level functionality to communicate with the GSP,= including allocation of /// queue space to write messages to and management of read/write pointers. @@ -218,7 +218,7 @@ unsafe impl FromBytes for GspMem {} /// pointer and the GSP read pointer. This region is returned by [`Self:= :driver_write_area`]. /// * The driver owns (i.e. can read from) the part of the GSP message que= ue between the CPU read /// pointer and the GSP write pointer. This region is returned by [`Self= ::driver_read_area`]. -struct DmaGspMem(CoherentAllocation); +struct DmaGspMem(Coherent); =20 impl DmaGspMem { /// Allocate a new instance and map it for `dev`. @@ -226,21 +226,20 @@ fn new(dev: &device::Device) -> Result= { const MSGQ_SIZE: u32 =3D num::usize_into_u32::<{ size_of::()= }>(); const RX_HDR_OFF: u32 =3D num::usize_into_u32::<{ mem::offset_of!(= Msgq, rx) }>(); =20 - let gsp_mem =3D - CoherentAllocation::::alloc_coherent(dev, 1, GFP_KERNE= L | __GFP_ZERO)?; + let gsp_mem =3D Coherent::::zeroed(dev, GFP_KERNEL)?; =20 let start =3D gsp_mem.dma_handle(); // Write values one by one to avoid an on-stack instance of `PteAr= ray`. 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, .ptes.0[i], PteArray::<0>::entry(start, i)= ?); } =20 dma_write!( gsp_mem, - [0]?.cpuq.tx, + .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, .cpuq.rx, MsgqRxHeader::new()); =20 Ok(Self(gsp_mem)) } @@ -255,10 +254,9 @@ fn new(dev: &device::Device) -> Result<= Self> { let rx =3D self.gsp_read_ptr() as usize; =20 // SAFETY: - // - The `CoherentAllocation` contains exactly one object. // - We will only access the driver-owned part of the shared memor= y. // - Per the safety statement of the function, no concurrent acces= s will be performed. - let gsp_mem =3D &mut unsafe { self.0.as_slice_mut(0, 1) }.unwrap()= [0]; + let gsp_mem =3D unsafe { &mut *self.0.as_mut() }; // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `< MSGQ_NU= M_PAGES`. let (before_tx, after_tx) =3D gsp_mem.cpuq.msgq.data.split_at_mut(= tx); =20 @@ -309,10 +307,9 @@ fn driver_write_area_size(&self) -> usize { let rx =3D self.cpu_read_ptr() as usize; =20 // SAFETY: - // - The `CoherentAllocation` contains exactly one object. // - We will only access the driver-owned part of the shared memor= y. // - Per the safety statement of the function, no concurrent acces= s will be performed. - let gsp_mem =3D &unsafe { self.0.as_slice(0, 1) }.unwrap()[0]; + let gsp_mem =3D unsafe { &*self.0.as_ptr() }; let data =3D &gsp_mem.gspq.msgq.data; =20 // The area starting at `rx` and ending at `tx - 1` modulo MSGQ_NU= M_PAGES, inclusive, diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index 0d8daf6a80b7..847b5eb215d4 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -40,8 +40,7 @@ }, }; =20 -// TODO: Replace with `IoView` projections once available; the `unwrap()` = calls go away once we -// switch to the new `dma::Coherent` API. +// TODO: Replace with `IoView` projections once available. pub(super) mod gsp_mem { use core::sync::atomic::{ fence, @@ -49,10 +48,9 @@ pub(super) mod gsp_mem { }; =20 use kernel::{ - dma::CoherentAllocation, + dma::Coherent, dma_read, - dma_write, - prelude::*, // + dma_write, // }; =20 use crate::gsp::cmdq::{ @@ -60,49 +58,35 @@ pub(super) mod gsp_mem { MSGQ_NUM_PAGES, // }; =20 - pub(in crate::gsp) fn gsp_write_ptr(qs: &CoherentAllocation) -= > u32 { - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { Ok(dma_read!(qs, [0]?.gspq.tx.0.writePtr) % MS= GQ_NUM_PAGES) }().unwrap() + pub(in crate::gsp) fn gsp_write_ptr(qs: &Coherent) -> u32 { + dma_read!(qs, .gspq.tx.0.writePtr) % MSGQ_NUM_PAGES } =20 - pub(in crate::gsp) fn gsp_read_ptr(qs: &CoherentAllocation) ->= u32 { - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { Ok(dma_read!(qs, [0]?.gspq.rx.0.readPtr) % MSG= Q_NUM_PAGES) }().unwrap() + pub(in crate::gsp) fn gsp_read_ptr(qs: &Coherent) -> u32 { + dma_read!(qs, .gspq.rx.0.readPtr) % MSGQ_NUM_PAGES } =20 - pub(in crate::gsp) fn cpu_read_ptr(qs: &CoherentAllocation) ->= u32 { - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { Ok(dma_read!(qs, [0]?.cpuq.rx.0.readPtr) % MSG= Q_NUM_PAGES) }().unwrap() + pub(in crate::gsp) fn cpu_read_ptr(qs: &Coherent) -> u32 { + dma_read!(qs, .cpuq.rx.0.readPtr) % MSGQ_NUM_PAGES } =20 - pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &CoherentAllocation, count: u32) { + pub(in crate::gsp) fn advance_cpu_read_ptr(qs: &Coherent, coun= t: u32) { let rptr =3D cpu_read_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGES; =20 // Ensure read pointer is properly ordered. fence(Ordering::SeqCst); =20 - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { - dma_write!(qs, [0]?.cpuq.rx.0.readPtr, rptr); - Ok(()) - }() - .unwrap() + dma_write!(qs, .cpuq.rx.0.readPtr, rptr); } =20 - pub(in crate::gsp) fn cpu_write_ptr(qs: &CoherentAllocation) -= > u32 { - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { Ok(dma_read!(qs, [0]?.cpuq.tx.0.writePtr) % MS= GQ_NUM_PAGES) }().unwrap() + pub(in crate::gsp) fn cpu_write_ptr(qs: &Coherent) -> u32 { + dma_read!(qs, .cpuq.tx.0.writePtr) % MSGQ_NUM_PAGES } =20 - pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &CoherentAllocation, count: u32) { + pub(in crate::gsp) fn advance_cpu_write_ptr(qs: &Coherent, cou= nt: u32) { let wptr =3D cpu_write_ptr(qs).wrapping_add(count) % MSGQ_NUM_PAGE= S; =20 - // PANIC: A `dma::CoherentAllocation` always contains at least one= element. - || -> Result { - dma_write!(qs, [0]?.cpuq.tx.0.writePtr, wptr); - Ok(()) - }() - .unwrap(); + dma_write!(qs, .cpuq.tx.0.writePtr, wptr); =20 // Ensure all command data is visible before triggering the GSP re= ad. fence(Ordering::SeqCst); --=20 2.53.0