From nobody Thu Apr 9 17:57:47 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 2DE334DB564; Tue, 3 Mar 2026 16:23:25 +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=1772555006; cv=none; b=bJ9QEjYteUCD/Z72M5QQ5YOqKOnUXqqZm5TF7JINTfIo1kBQr9s3hYxZAkGKdfktbqeZWXAG2N7H7qMEgrbDTEbs1ZwZ17BasDLU+1bG9qP9yCraUC+wW/Jd4QBYGxcukCC9c7Yj08uoTu7KDT/Ep3UcJlG+2l43Q4X6VP9Yyv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555006; c=relaxed/simple; bh=sZeYMfqAjnE/ZOhGVSDNSGhEbY9o/U7Qeic9UXsETko=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=if37tKuP/wqiHCt/UKysWBwkzUBcpZNXhV6s0nd0CwOJoUHBlpm4U02uM06AAR4aqZhDeVLeVjZm0ntCQYsHrOXuYibVceFUlNFFdi5t25DgGf8osL5J4IKZKRnIhbDonu0DtkchuhmGQoJR2/46TcfuLrQTHxYBC2gD2hBa+ZQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jW+Ib2ZV; 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="jW+Ib2ZV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 01522C19422; Tue, 3 Mar 2026 16:23:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555005; bh=sZeYMfqAjnE/ZOhGVSDNSGhEbY9o/U7Qeic9UXsETko=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jW+Ib2ZVBR7gmR5KmTVPaQtcqQagtSa3fj+JrPcYu7+ZunDCTA3gDKPbR3z/hBu00 zOBMyBq7puRrTBszGHwAsNBk5w9kq7LGlIn+zgxCpDz2FzxwmGVYiHnmKaOongRTma rhKobipEX3CX5HAyNCCPqLrU6FeZxQ3ws2H1KUh5fsXyyeMdz96JtOkwMNAlQouemQ GLhrvl3pUf5kowisjzDzceQE1fis2lt3WLTA8LnYdDg8TmSpzI3NShub1Qdpvf8bE+ mj9xDZ6eFwbNkyMLkhzzBM93/pkdZ+WwZAAUreKp8tg5UIfHLI6AQnogG87KOsn+rx L5lk9HZ5yteEQ== 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 1/8] rust: dma: use "kernel vertical" style for imports Date: Tue, 3 Mar 2026 17:22:52 +0100 Message-ID: <20260303162314.94363-2-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 Signed-off-by: Danilo Krummrich Reviewed-by: Gary Guo --- 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 cd2957b5f260..54512278085e 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 Thu Apr 9 17:57:47 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 768B64DB547; Tue, 3 Mar 2026 16:23:30 +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=1772555010; cv=none; b=p+9xjoFugqxk37TEIo6u02Y1JyyraeRdiNpr3AUkiZ9h5aut+qgAQXC1H//Jbzi4eInMwBYzk4zNchxsUzIWhR13t2DfMnEy+7dax/wIZswHRLQWYoYEcVoCOgqWvoddP8f3s2JQqZQ+Lo1FmsOU7XNGzHC+CC8tjuffypnbAMw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555010; c=relaxed/simple; bh=+TCDKXUKD/DuQo8wyguxxZ7g4OqdWwlSrUMCf5ftORg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OFLN/EYTTlI08TGUc7ZgUeKw7gVmco4TesoahbR5vCBUjJsSgwTWpW9ftWjex1+Jy+hIPLALZ9jBMxOldrffEBBHn4rz5U3/egsrmVJCpRr3cKBxP3av1M5RsyJRzEMP02StwDrsD8Ab82XElAVcZlbFPxOy39esULTaOhybKwk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dCLmffoW; 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="dCLmffoW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2E36BC116C6; Tue, 3 Mar 2026 16:23:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555009; bh=+TCDKXUKD/DuQo8wyguxxZ7g4OqdWwlSrUMCf5ftORg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dCLmffoWpI/L7Wgjs6hmjTG1WqUvGp3qIdPRD9fN1CBx6bvNVHB8PfBuude3YFgyz OR7eYyITDJlW0si54rtPaDtZ5GnvuvEpJJJmgqTvS/aE/jKK9pUIEBY6juXBFcNBEE CU3wYN6FeqlFJBjYrZGuGw/D57f80LmjID8w/Wn3+2NvdjDiqxDUSqJyIwOK3uP0uw lyW7ITHl6adhhTzDCECIEG33sC7XYnyhqqhU2kgcBFGWa2nuPVC9CQp74PnHgH0DnG gonnHWoiEFUkh7Wuym3EKq0HDwNZmB/Zncnzzo58v/jTxkI9AJoEDXL1Ez9aupAhz9 ikyEtrOnY0QXg== 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 2/8] rust: dma: add generalized container for types other than slices Date: Tue, 3 Mar 2026 17:22:53 +0100 Message-ID: <20260303162314.94363-3-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- 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 54512278085e..3a692ac76ba2 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 C= oherent {} =20 /// Reads a field of an item from an allocated region of structs. /// /// The syntax is of form `kernel::dma_read!(dma, proj)` where `dma` is an= expression to an -/// [`CoherentAllocation`] and `proj` is a [projection specification](kern= el::ptr::project!). +/// [`Coherent`] and `proj` is a [projection specification](kernel::ptr::p= roject!). /// /// # 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: pointer created by projection is within 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 form `kernel::dma_write!(dma, proj, val)` where `dma`= is an expression to an -/// [`CoherentAllocation`] and `proj` is a [projection specification](kern= el::ptr::project!), +/// [`Coherent`] and `proj` is a [projection specification](kernel::ptr::p= roject!), /// and `val` is the value 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: pointer created by projection is within 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 Thu Apr 9 17:57:47 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 791E54D8DA6; Tue, 3 Mar 2026 16:23:34 +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=1772555014; cv=none; b=mYfkJaEuhbzKvmL840uw0SKh1Zg1q+bPUNkjWlzLiKT2qQ4xZCbefYrEwnPxLGSHRZm3vZZuK7rVIrC0uTnE3Q07yD0i6e0ZaKF28h3lGrAfv2lNXE5OicMpuj1MKOlHFBiQc3/2o6ptTmcygvEOIVPi2Tjzx5l5EEwUZwoQeBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555014; c=relaxed/simple; bh=2KpsdZwDEoGsFZo4mcehIAvYG9ASAGAxsst8MTspzNM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hCPoxZ6Y9WTuLuE7FSE4zfeyqYjltYeiOvIUtacJfCxM0skXLjQI4+oHd7pOMXRX8GZ3uFT64I/AW0jiwq4rSY6sDU7dn/nCNuIlJrPGs7cCoTGfGuWKnd/Q2bFTtBfUDzPu2k2WT/yfUlsIWNs5t3uP6MfzHqKALeH7f/HfkYE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CINpFcQG; 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="CINpFcQG" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 51E9FC19425; Tue, 3 Mar 2026 16:23:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555014; bh=2KpsdZwDEoGsFZo4mcehIAvYG9ASAGAxsst8MTspzNM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CINpFcQGYvbR4YvZESh+564qUW9h1Drprf79ZT8AiYiKKCLinSv3zb9hMtDAicQ2v sFwHmTkwr7S6S+1v729+qDlKvJsaobdCNbFbVjqHF5dLK4kEuWIQiZNpT9myRHpwbu sulikvPjA7VlcMZwjqIDOdcbaammLmbO+RG0OTJjlGRzJsfA8bjLBKqugjzL26M363 nZCryzqnQQBG5YhZ/94KNoJ5Md3SGF3vr6GLPnuIG1SkOGWEtaDA3infQH9PAMjW1k Zoukdz/1mCYfEiUIiU+HJZ1zz7F7uTVOr+V7NfXkOR7VFcZK/cnTA7Cj/n58Q5gL3D USgcqQskKmQtA== 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 3/8] rust: dma: add zeroed constructor to `Coherent` Date: Tue, 3 Mar 2026 17:22:54 +0100 Message-ID: <20260303162314.94363-4-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 Signed-off-by: Danilo Krummrich Reviewed-by: Alexandre Courbot Reviewed-by: Alice Ryhl --- rust/kernel/dma.rs | 77 +++++++++++++++++++++++++++++++++++----- samples/rust/rust_dma.rs | 8 ++--- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 3a692ac76ba2..291fdea3b52b 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,33 @@ 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>(()) } + /// ``` + 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. + 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 +598,41 @@ 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= ored_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>(()) } + /// ``` + 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. + 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 Thu Apr 9 17:57:47 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 B60CB48A2C1; Tue, 3 Mar 2026 16:23:38 +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=1772555018; cv=none; b=oTgHBNkqhhx+7bFHCiPrMxVElAQqK3Z7RHWkpxxzHVKgXOa20T1BdH7LO9qm4Aby2QFgbfT+0zAKSrtsSIy0jXe5BPJkzzkoP3mc+Y4xiO3LwxqoYdEL7EMG1uop+CIJ4pSwaIkU5gozmFmBxB/OU+BzkHh5vZpYVRxpER6pAs4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555018; c=relaxed/simple; bh=lvS+2efafKwewwHd7ONO5y6+Y49CgHw8VIi3bRKXV+s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AYNRbg4AAZwbvrRfpN027D2SMo0lAX9YaN0yEtqEzb/gBCxM4hgkbPtK8yUfATWhDZMHw5xrer4EBR0nBGqchDclCgESxf/qiU4dsSqGd2Q8fOvdtaerOZPXROwROHwFgx7KDnhd+K1HzJKTChM1kpWGMiD07LqCfB1wPAMAc7g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pJgBC+lu; 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="pJgBC+lu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7715CC2BCB0; Tue, 3 Mar 2026 16:23:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555018; bh=lvS+2efafKwewwHd7ONO5y6+Y49CgHw8VIi3bRKXV+s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pJgBC+luK2vnGf5VECQogdIin5ejUVwJ/MBgNwPKigPRYTo/X/75Uvpvtl1UqQyl7 RbTf4I7YXeQzkGZSuMMi78LymclByTCU/nZCfaFzxJ3PjPARKunoJjZUIpRLe2KBhD 0kFdsmbFWb2lB/vgFeBoJPn9gAJLrdmfZTnYToaYTzHAynJXDe4dKlQVT46ytElXSm CSnqQ/AHK1LQzsN4CM3fCW3iI+0Dl4grK40RbexUN5CeBKI3ypdKx8jdxNY+x03fEm JE8W+fRcAnDYouuuGTOWAOeQleLw2OGwaK/NVpTLWuyjU2jN/+g7NBnlqHtpldZ09j 2f8W8c8jXw6YA== 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 4/8] rust: dma: introduce dma::CoherentInit for memory initialization Date: Tue, 3 Mar 2026 17:22:55 +0100 Message-ID: <20260303162314.94363-5-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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::CoherentInit, a type that encapsulates a dma::Coherent before its DMA address is exposed to the device. dma::CoherentInit can guarantee exclusive access to the inner dma::Coherent and implement Deref and DerefMut. Once the memory is properly initialized, dma::CoherentInit can be converted into a regular dma::Coherent. Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- rust/kernel/dma.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 291fdea3b52b..79dd8717ac47 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,151 @@ fn from(direction: DataDirection) -> Self { } } =20 +/// Initializer type for [`Coherent`]. +/// +/// A [`Coherent`] object can't provide access to its memory as (mutable) = slice safely, since it +/// can't fulfill the requirements for creating a slice. For instance, it = is not valid to have a +/// (mutable) slice to of the memory of a [`Coherent`] while the memory mi= ght be accessed by a +/// device. +/// +/// In contrast, this initializer type is able to fulfill the requirements= to safely obtain a +/// (mutable) slice, as it neither provides access to the DMA address of t= he embedded [`Coherent`], +/// nor can it be used with the DMA projection accessors. +/// +/// Once initialized, this type can be converted to a regular [`Coherent`]= object. +/// +/// # Examples +/// +/// `CoherentInit`: +/// +/// ``` +/// # use kernel::device::{ +/// # Bound, +/// # Device, +/// # }; +/// use kernel::dma::{attrs::*, +/// Coherent, +/// CoherentInit, +/// }; +/// +/// # fn test(dev: &Device) -> Result { +/// let mut dmem: CoherentInit =3D +/// CoherentInit::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)= ?; +/// *dmem =3D 42; +/// let dmem: Coherent =3D dmem.into(); +/// # Ok::<(), Error>(()) } +/// ``` +/// +/// `CoherentInit<[T]>`: +/// +/// +/// ``` +/// # use kernel::device::{ +/// # Bound, +/// # Device, +/// # }; +/// use kernel::dma::{attrs::*, +/// Coherent, +/// CoherentInit, +/// }; +/// +/// # fn test(dev: &Device) -> Result { +/// let mut dmem: CoherentInit<[u64]> =3D +/// CoherentInit::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR= _NO_WARN)?; +/// dmem.fill(42); +/// let dmem: Coherent<[u64]> =3D dmem.into(); +/// # Ok::<(), Error>(()) } +/// ``` +pub struct CoherentInit(Coher= ent); + +impl CoherentInit<[T]> { + /// Initializer variant of [`Coherent::zeroed_slice_with_attrs`]. + 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 [CoherentInit::zeroed_slice_with_attrs], but with `dma::At= trs(0)`. + 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 core::ptr::from_mut(&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 CoherentInit { + /// Same as [`CoherentInit::zeroed_slice_with_attrs`], but for a singl= e element. + 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 [`CoherentInit::zeroed_slice`], but for a single element. + 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 CoherentInit { + type Target =3D T; + + 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 CoherentIni= t { + 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> fo= r Coherent { + fn from(value: CoherentInit) -> 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 Thu Apr 9 17:57:47 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 E79774DC55F; Tue, 3 Mar 2026 16:23:42 +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=1772555023; cv=none; b=d7aUHIUq5WDHaSi8/sI11+t0OPz8zwSXWS4QWYn5N/8TgjS+AHAjdkayy5lX77qPQgsoR7MOuco1xW4u3VC9jKVvGCF3YV7oZJ14O+Wpp9eHN5on6puP4a4KVWCLeGJLqueyk591F0MFpFE4cynW7J1XFQBpqbfiaRlGVtHA1cE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555023; c=relaxed/simple; bh=+liU4pQNiYF4RC3Z3F4oQnCGR+HREs2Sq3MMzyTGAOA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XdfoUEjFUBAeBm/Pzyjfq0mqsMd/6o45tSCrJS/hCmNVXPUxsDsSkH2m/hs+ZYLQl/Q1g7/CIaX7rNYNP+BjDMRLdvOjc0tdmIlon+9to9HkVMMbsoDzQe95kwprdgcjWYSMk9VJ3hiSNsE9c7++k5k20m3hd/Ym5YpSzvGGsA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Bmk0Z2oM; 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="Bmk0Z2oM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AADDDC116C6; Tue, 3 Mar 2026 16:23:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555022; bh=+liU4pQNiYF4RC3Z3F4oQnCGR+HREs2Sq3MMzyTGAOA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Bmk0Z2oMWzuq509fyO1v/aQOfoxTxOlzclkhD5GNbCyhMh2yu7FChr7EvI1YQFM37 Fx5Mp4iZ2DPDaE+dXPD5pHJ4jClMOez0HOTmtreERsarMbW/eVna6KcaUiexSp+Hjv Jze0+p30dGCWoZXalXq1WaWwbtypMGwe5IPDaZSyirikkHoc6dx9Ee5JXE/8vTK4i0 DxBMAxlOHejyxts5d7/HXVI62feIhiQC6h//7SBUWvWUiNsr8Nb0sCvAVxXew1tuLK 4/c/3cEZ20EAZCdl4DInvPgBRsrOAjU0ohTE3xerRQKGN5oVMVR4FxemYsjIxAhnwn AcNgedmkzliPg== 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 5/8] rust: dma: add Coherent:init() and Coherent::init_with_attrs() Date: Tue, 3 Mar 2026 17:22:56 +0100 Message-ID: <20260303162314.94363-6-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 --- rust/kernel/dma.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 79dd8717ac47..d77c1b6cb0c4 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -706,6 +706,43 @@ 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`. + 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 Thu Apr 9 17:57:47 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 DA7904DC55A; Tue, 3 Mar 2026 16:23:46 +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=1772555027; cv=none; b=i7obHoGYTzix7HlrCGAODrv6BWhydZ/Mn9WfiSh8W1SZJBSQgD85o/VXiOOcFBprS0OWYR6IjNhwr4EZo3mhpFTnrkwIRpetlMLPIeV7+atzY2zjZg5E1vJFgJU/s5dlYePjYhC9ej+xwezlf7GiqXeBYdFVSI07ookmm3Otyj8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555027; c=relaxed/simple; bh=RRwlxYxwMBwbZCAUZL3IuCb0Hwkrc8JPcDDRIvn48Qw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fmKZ85ioqy4lacDMVX3GBQdZBmapUiNGIhxF0Dvm3cxTmrHA8rf2FYJmpQxTU3b91C9+LaUTvlBZNdnSapLWrk824eHMAXDSibiMwzDQk+XqqZbQeF0Hg863n+8m8WJdqJUlRfEUaEPewti7CBVSuWmc3LM2C24KjTwjg8eqOdo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AXJ+vRwp; 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="AXJ+vRwp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D77E6C19425; Tue, 3 Mar 2026 16:23:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555026; bh=RRwlxYxwMBwbZCAUZL3IuCb0Hwkrc8JPcDDRIvn48Qw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AXJ+vRwpD+EC7R58rTnSZ/QZYMKFuXqSXO3N90797MlZ9vYi3KprMBIs8w+G2RZD+ 2kN6PvgKj34HKMHJhIzKXtVaeylMgeF56kentZ9Z9C09Yg1O53lPcZYOVNxXr7gbi3 jINaPy0/1NcOm7jOt3Vh9vaMj3FWtgqTBZAhcgwyeOhi4Gbp5fRzxoJxG9C5pvGwSo YXJSBpUDyzqSVWqFcWC8DvlGuWgBZTMkHljj0xCicQYs1BuGQTdLtBWf5gJCRyn+im et4kuO34LXSpgiC2zi5PxvGiBDFsNw0H8/iNP6nKFYClKVa7pE27bJ9H2LB68qKy1s ELA3SlfZZ+GNg== 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 6/8] gpu: nova-core: use Coherent::init to initialize GspFwWprMeta Date: Tue, 3 Mar 2026 17:22:57 +0100 Message-ID: <20260303162314.94363-7-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 --- 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 7f46fa5e9b50..1a4d9ee4f256 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::*, @@ -155,9 +154,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(bar, commands::SetSystemInfo::new(pdev))?; diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw= .rs index f1797e1f0d9d..751d5447214d 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -131,7 +131,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 {} @@ -144,10 +146,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), @@ -182,7 +188,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 Thu Apr 9 17:57:47 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 35C964E3760; Tue, 3 Mar 2026 16:23:50 +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=1772555031; cv=none; b=rkcgihMykRXhs6QaOJUH7/6WxwT8HTphqxKrZ0LmRIXoTKz/65q6J8uGMwaXyk5QOvzzwkZVuRoQCZkQPcd01F63Xdi1XyS6kZ1/Qo1aqessKxDlX52CTr+qynYYl0rkU5iKDVv/6j86QKRo8/kPbv4PaAv8Ss0Hh/kptT88ZGw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555031; c=relaxed/simple; bh=sjmFT1BethSxXRjKz3v5DqaLtJGPmc3qrxzO8Mx+Gkw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UcAPDLEA3OoBwi4Q65Pq2K/XUlnZ9ab0g3o3ZnDUutY+/eLdYLjqGHWszGPTw0rRAU0TaetSRKHVVwRg6ZyzgoBZRiJgzLKl+XaDYf1yDr4Z/8uqhtMVDoy2MgVYLWYohKrT1ReHVzPkQew/wr5dEBKNGOCr5DjqNDdotCQtg4Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OX5R1rGj; 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="OX5R1rGj" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 008EFC116C6; Tue, 3 Mar 2026 16:23:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555030; bh=sjmFT1BethSxXRjKz3v5DqaLtJGPmc3qrxzO8Mx+Gkw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OX5R1rGjIVQhugnA4adMhjT3v0fvbmh5Ql4V7W1aD96do/gGSRTvf7hSI/y0Srdzw 6A1tCRsdvNvuUZw0la6UdZmaqrmcmnTRVOMJU3Fg+2HJp44h32EewzaZTP1wCYN6Ha aAR/yruJVRY0lwWK4+WbgPzASf47E7gb3G828E5wFe0WXAanp4iKoxeR2SpYlri/fn 6hpn6sCE/hAiSNXpPYEqn0lnZLl9j6/blsAExJkq514JlFJH6fW//dRFkWTM0WvzBX +d3/aoazHoLtr7akyPzYQA89yB2XjSeN/CzllLEvE7QZhsU3EeTywPlxmupTBfL1gI yd0UPSFPce9NQ== 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 7/8] gpu: nova-core: convert Gsp::new() to use CoherentInit Date: Tue, 3 Mar 2026 17:22:58 +0100 Message-ID: <20260303162314.94363-8-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 CoherentInit / Coherent::init() and simplify the initialization. This also avoids separate initialization on the stack. Signed-off-by: Danilo Krummrich --- 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 25cd48514c77..cb7f6b4dc0f8 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, + CoherentInit, DmaAddress, // }, - dma_write, pci, prelude::*, transmute::AsBytes, // @@ -104,7 +105,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. @@ -114,7 +115,7 @@ pub(crate) struct Gsp { /// Command queue. pub(crate) cmdq: Cmdq, /// RM arguments. - rmargs: CoherentAllocation, + rmargs: Coherent, } =20 impl Gsp { @@ -123,34 +124,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 CoherentInit::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 751d5447214d..59cb03a9b238 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, @@ -568,7 +569,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 {} @@ -578,10 +581,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::()]; @@ -593,7 +596,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()), @@ -603,7 +607,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, }) } } @@ -814,15 +822,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, }) } } @@ -834,11 +850,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 @@ -847,18 +873,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 Thu Apr 9 17:57:47 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 6BA9C4DB547; Tue, 3 Mar 2026 16:23:55 +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=1772555035; cv=none; b=rCGpQ4UvVUMnXX7XjzyWD07UUPi/5GayjMEQnN3t7YFc7ZgNHpAyWCtmz/u6suWM6ygfVlvfB7aiPgDfZzf99O2SxGVl7/vcM3Hs+Rqz94ak3FrR73OYqhfk0W7dxJyxvgvebCquD7f5Q4HqKlL88iyl3nK952AYoa9q6CJtF1A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772555035; c=relaxed/simple; bh=MMf/7ThUQxA41boroXlWwAOlZa0iETTF8GP7vXiZQ5s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oTSkR6wMUhRWRYlTMEO339II3WMVuAxnML2f6CAQGjJ/8LiY+kxQ35HYbsdlGmIi9U+a4hlKqohipVxaOsSm6cePYLvQMEwaSnv/HC7rUOuJviKdcrRGpIw8fpbhX+H0Jg9MTBCj2YujJYVwpMWV0UF6bCYGQML7EuvGNTPJeKA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iHDe3w0f; 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="iHDe3w0f" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2EB26C2BCB0; Tue, 3 Mar 2026 16:23:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1772555034; bh=MMf/7ThUQxA41boroXlWwAOlZa0iETTF8GP7vXiZQ5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iHDe3w0fwWuVhmuVJ9Wg7lfQiQ0XouM+RpO8ExbNmGccdaGyRHSpKxdJ0BLh22ipQ f3TmGLG4ehurQSe0ckEmsJXCPXG7lriFnLsuxX8VAgYZXZADsNgJE6064YHGdFF9IW 1FQe5epZr7vZhjH+rU+rfpzaGPGZWRgwtTZpHWiuqu3piHaeVjIHyurJokSPrZqDyT 4UcD8W2W9gJrlMik7Dov8F4aMXkE5zjs8z8K96b+F7JgupF3S50G9wwcVs95iIKc4C fDm5fDIQ9/GQoy50X0Vcambsxwzgm/hhbLiLxLC+DYJqPMD7lmr+eZeXUKBkB2We2S NajhB+FMH2zlQ== 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 8/8] gpu: nova-core: convert to new dma::Coherent API Date: Tue, 3 Mar 2026 17:22:59 +0100 Message-ID: <20260303162314.94363-9-dakr@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260303162314.94363-1-dakr@kernel.org> References: <20260303162314.94363-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 Signed-off-by: Danilo Krummrich --- drivers/gpu/nova-core/dma.rs | 19 +++++------ drivers/gpu/nova-core/falcon.rs | 7 ++-- drivers/gpu/nova-core/firmware.rs | 10 ++---- drivers/gpu/nova-core/gsp.rs | 18 ++++++---- drivers/gpu/nova-core/gsp/cmdq.rs | 55 ++++++++++++------------------- 5 files changed, 46 insertions(+), 63 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 37bfee1d0949..39f5df568ddb 100644 --- a/drivers/gpu/nova-core/falcon.rs +++ b/drivers/gpu/nova-core/falcon.rs @@ -25,10 +25,7 @@ driver::Bar0, falcon::hal::LoadMethod, gpu::Chipset, - num::{ - FromSafeCast, - IntoSafeCast, // - }, + num::FromSafeCast, regs, regs::macros::RegisterBase, // }; @@ -434,7 +431,7 @@ fn dma_wr>( } FalconMem::Dmem =3D> ( 0, - fw.dma_handle_with_offset(load_offsets.src_start.into_safe= _cast())?, + fw.dma_handle() + DmaAddress::from(load_offsets.src_start), ), }; if dma_start % DmaAddress::from(DMA_LEN) > 0 { diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firm= ware.rs index 815e8000bf81..efb20ef34f31 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -310,7 +310,7 @@ trait FirmwareSignature: AsRef<[u8]>= {} impl FirmwareDmaObject { /// Patches the firmware at offset `sig_base_img` with `signature`. fn patch_signature>( - mut self, + self, signature: &S, sig_base_img: usize, ) -> Result> { @@ -320,12 +320,8 @@ fn patch_signature>( } =20 // SAFETY: We are the only user of this object, so there cannot be= any race. - let dst =3D unsafe { self.0.start_ptr_mut().add(sig_base_img) }; - - // SAFETY: `signature` and `dst` are valid, properly aligned, and = do not overlap. - unsafe { - core::ptr::copy_nonoverlapping(signature_bytes.as_ptr(), dst, = signature_bytes.len()) - }; + let dst =3D unsafe { self.0.as_mut() }; + dst[sig_base_img..][..signature_bytes.len()].copy_from_slice(signa= ture_bytes); =20 Ok(FirmwareDmaObject(self.0, PhantomData)) } diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index cb7f6b4dc0f8..fcb3020acf8d 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -6,13 +6,15 @@ device, dma::{ Coherent, - CoherentAllocation, CoherentInit, 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 @@ -75,25 +80,24 @@ fn new(start: DmaAddress) -> 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, )?); let ptes =3D PteArray::::new(obj.0.dma_handle())?; =20 // SAFETY: `obj` has just been created and we are its sole user. unsafe { // Copy the self-mapping PTE at the expected location. - obj.0 - .as_slice_mut(size_of::(), size_of_val(&ptes))? + obj.0.as_mut()[size_of::()..][..size_of_val(&ptes)] .copy_from_slice(ptes.as_bytes()) }; =20 diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/= cmdq.rs index 0056bfbf0a44..05c5f70dd4a9 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -11,7 +11,7 @@ use kernel::{ device, dma::{ - CoherentAllocation, + Coherent, DmaAddress, // }, dma_write, @@ -181,7 +181,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. @@ -192,7 +192,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`. @@ -200,15 +200,10 @@ 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)?; - 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()); + let gsp_mem =3D Coherent::::zeroed(dev, GFP_KERNEL)?; + dma_write!(gsp_mem, .ptes, PteArray::new(gsp_mem.dma_handle())?); + dma_write!(gsp_mem, .cpuq.tx, MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_= OFF, MSGQ_NUM_PAGES)); + dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new()); =20 Ok(Self(gsp_mem)) } @@ -223,10 +218,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_ptr() }; // 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 @@ -264,10 +258,9 @@ fn new(dev: &device::Device) -> Result<= Self> { 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, @@ -334,11 +327,10 @@ fn allocate_command(&mut self, size: usize) -> Result= > { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_write_ptr(&self) -> u32 { - let gsp_mem =3D self.0.start_ptr(); + let gsp_mem =3D self.0.as_ptr(); =20 // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is val= id. + // - By the invariants of `Coherent` the pointer is valid. (unsafe { (*gsp_mem).gspq.tx.write_ptr() } % MSGQ_NUM_PAGES) } =20 @@ -348,11 +340,10 @@ fn gsp_write_ptr(&self) -> u32 { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn gsp_read_ptr(&self) -> u32 { - let gsp_mem =3D self.0.start_ptr(); + let gsp_mem =3D self.0.as_ptr(); =20 // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is val= id. + // - By the invariants of `Coherent` the pointer is valid. (unsafe { (*gsp_mem).gspq.rx.read_ptr() } % MSGQ_NUM_PAGES) } =20 @@ -362,11 +353,10 @@ fn gsp_read_ptr(&self) -> u32 { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_read_ptr(&self) -> u32 { - let gsp_mem =3D self.0.start_ptr(); + let gsp_mem =3D self.0.as_ptr(); =20 // SAFETY: - // - The ['CoherentAllocation'] contains at least one object. - // - By the invariants of CoherentAllocation the pointer is valid. + // - By the invariants of `Coherent` the pointer is valid. (unsafe { (*gsp_mem).cpuq.rx.read_ptr() } % MSGQ_NUM_PAGES) } =20 @@ -377,11 +367,10 @@ fn advance_cpu_read_ptr(&mut self, elem_count: u32) { // Ensure read pointer is properly ordered. fence(Ordering::SeqCst); =20 - let gsp_mem =3D self.0.start_ptr_mut(); + let gsp_mem =3D self.0.as_mut_ptr(); =20 // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is val= id. + // - By the invariants of `Coherent` the pointer is valid. unsafe { (*gsp_mem).cpuq.rx.set_read_ptr(rptr) }; } =20 @@ -391,22 +380,20 @@ fn advance_cpu_read_ptr(&mut self, elem_count: u32) { // // - The returned value is within `0..MSGQ_NUM_PAGES`. fn cpu_write_ptr(&self) -> u32 { - let gsp_mem =3D self.0.start_ptr(); + let gsp_mem =3D self.0.as_ptr(); =20 // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is val= id. + // - By the invariants of `Coherent` the pointer is valid. (unsafe { (*gsp_mem).cpuq.tx.write_ptr() } % MSGQ_NUM_PAGES) } =20 // 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 =3D self.cpu_write_ptr().wrapping_add(elem_count) % MSGQ_= NUM_PAGES; - let gsp_mem =3D self.0.start_ptr_mut(); + let gsp_mem =3D self.0.as_mut_ptr(); =20 // SAFETY: - // - The 'CoherentAllocation' contains at least one object. - // - By the invariants of `CoherentAllocation` the pointer is val= id. + // - By the invariants of `Coherent` the pointer is valid. unsafe { (*gsp_mem).cpuq.tx.set_write_ptr(wptr) }; =20 // Ensure all command data is visible before triggering the GSP re= ad. --=20 2.53.0