From nobody Sat Jun 13 15:12:53 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 4533E31715C; Wed, 6 May 2026 21:51:29 +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=1778104289; cv=none; b=cfFWd7xWgoKkbsUVsL3H278u3VIQWV6KmEA2k5s5jG7uwzYAC/XCZvGOTWT69iRPvzSIW+KkLZMt/f+yyWPzXWGaNK0zKKkF78zz16WHHNb+7QxPQK25hs1e71gSOP0EDt1wTCEa7P9gWfcyOtKHa0py/CejabPPoIwEl0GMVPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104289; c=relaxed/simple; bh=KszMW7j0arPfCne/rylxes/QioHMAvioxwStyBryJ9U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Gz0Sy7ANNvaPm15gFrsFmRcRv2ZA7CkziPXqzGD5/hEch7Qfv9WJUvobrM2OH+0YyzFJbv4N2orWoH8o2aPpkADxOTcuii6oh0Tsxzx4H+Nms9m9bgqnMsDqUE9qRBnCovKmUFrAejLLbjbswBTQIkcK2Se2/CNe8x/73+KxZwY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=o4y35u9e; 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="o4y35u9e" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9B006C2BCB2; Wed, 6 May 2026 21:51:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104288; bh=KszMW7j0arPfCne/rylxes/QioHMAvioxwStyBryJ9U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o4y35u9eE358d7mgQ1JSLN1Xw9FGVJvi+MFsDXKTR5yEL0zcaeyXlVDdaDyB/0H9w TmYLm2fTqz2ZihNoFX9gVVCl4C8pJKphkNjdkPGFJWISUbfpfoOM6F0P9aJgpTanrF /yzeD8ZUisJbZYM9F6cw1xRtVlryxaH+I1pP/6FTUsfhLSwJYuyI8WI2FQj6R8XGhA B+D/cnJyQ0iXOHimMav6Aa7nsLoUJjs2NMWpMYAKHjbV37cH6ur4emuoJ11ukiLHgK rsY2qGzoDadblH2RsI0F3PuP9ymW7PRaiqfMDm0REQwJFzSpYF7Qpfcr4CCyaQ1lQu StVDgSLsQY4vw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 01/25] rust: driver core: drop drvdata before devres release Date: Wed, 6 May 2026 23:50:37 +0200 Message-ID: <20260506215113.851360-2-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Move the post_unbind_rust callback before devres_release_all() in device_unbind_cleanup(). With drvdata() removed, the driver's bus device private data is only accessible by the owning driver itself. It is hence safe to drop the driver's bus device private data before devres actions are released. This reordering is the key enabler for Higher-Ranked Lifetime Types (HRT) in Rust device drivers -- it allows driver structs to hold direct references to devres-managed resources, because the bus device private data (and with it all such references) is guaranteed to be dropped while the underlying devres resources are still alive. Without this change, devres resources would be freed first, leaving the driver's bus device private data with dangling references during its destructor. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/base/dd.c | 2 +- include/linux/device/driver.h | 4 ++-- rust/kernel/driver.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 5799a60fd058..be59d2e13a15 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -593,9 +593,9 @@ static DEVICE_ATTR_RW(state_synced); =20 static void device_unbind_cleanup(struct device *dev) { - devres_release_all(dev); if (dev->driver->p_cb.post_unbind_rust) dev->driver->p_cb.post_unbind_rust(dev); + devres_release_all(dev); arch_teardown_dma_ops(dev); kfree(dev->dma_range_map); dev->dma_range_map =3D NULL; diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index bbc67ec513ed..38e9a4679447 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -123,8 +123,8 @@ struct device_driver { struct driver_private *p; struct { /* - * Called after remove() and after all devres entries have been - * processed. This is a Rust only callback. + * Called after remove() but before devres entries are released. + * This is a Rust only callback. */ void (*post_unbind_rust)(struct device *dev); } p_cb; diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 93e5dd6ae371..bb53035a1017 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -189,8 +189,8 @@ extern "C" fn post_unbind_callback(dev: *mut bindings::= device) { // INVARIANT: `dev` is valid for the duration of the `post_unbind_= callback()`. let dev =3D unsafe { &*dev.cast::>() }; =20 - // `remove()` and all devres callbacks have been completed at this= point, hence drop the - // driver's device private data. + // `remove()` has been completed at this point; devres resources a= re still valid and will + // be released after the driver's bus device private data is dropp= ed. // // SAFETY: By the safety requirements of the `Driver` trait, `T::D= riverData` is the // driver's device private data type. --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 82CFE239085; Wed, 6 May 2026 21:51:35 +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=1778104295; cv=none; b=gzV3EoIbaswUHwhUNzRFAfc2UMAqLgCg9hcgCU/UX0E6PYXIV/HNEFS0dLxmLKbJitTTeOk6/deClEnwE22iSj19xGXW+huuh0hC2D3kvbCvRt+of6DWUSDY/KLVak+xScqUD7HWM1eDtM1iZhyZCppawwq9rzt893AmgT0nIiQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104295; c=relaxed/simple; bh=fI7CwTbB84GwLVWKCzG5zYfxgKsLcuvRyv0WzVH9QV8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LoUZ+KNYy8ij5OT+ohq6JZM0L/VaheKyQGd54C1TF6e6AkIsbxsICy74dXiXp9elW9Qg/UHixaPdMvz/kt2ZcuiiX1WpC8uz6Zn7SgP4kSesYrmD0eHa/8RZT4cAxcND5RcZQhh/9j+RgOiusiKsrWJ+Xoa4zfy96GcM+6DYZRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TnL92aUQ; 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="TnL92aUQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 530D4C2BCC4; Wed, 6 May 2026 21:51:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104295; bh=fI7CwTbB84GwLVWKCzG5zYfxgKsLcuvRyv0WzVH9QV8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TnL92aUQwSrBdEOF3K7nXMIDzArS3BUzdbQssR6a1vx8nS7LkcasmIKUGhc550zUk df+5rSDgZkdHWBX1WNoNPaesQdoFIGH512W/zldc6rOh/y93OMvA6BRIl22d7mj89D Ydh89Y6hSgMp2tBaErjhPRqvo0Gc1JopZL+DJqoDWSjxMjnHyb8usacwhAXsAYGNQL /T+p9sGBBZCokTxEVX2JF3zG3C1ydxEWxY9pTuH0MsyvHtCY1CEzgfa8h+iwGoN9cN r2DztTJIYacHakSgaOrS19mv6LPwZoHryniwCuX6EHSJqqssqBNydbYcZnVguNoW1H 8278iKpzwY/kw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org Subject: [PATCH v2 02/25] rust: types: add `ForLt` trait for higher-ranked lifetime support Date: Wed, 6 May 2026 23:50:38 +0200 Message-ID: <20260506215113.851360-3-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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 There are a few cases, e.g. when dealing with data referencing each other, one might want to write code that are generic over lifetimes. For example, if you want take a function that takes `&'a Foo` and gives `Bar<'a>`, you can write: f: impl for<'a> FnOnce(&'a Foo) -> Bar<'a>, However, it becomes tricky when you want that function to not have a fixed `Bar`, but have it be generic again. In this case, one needs something that is generic over types that are themselves generic over lifetimes. `ForLt` provides such support. It provides a trait `ForLt` which describes a type generic over lifetime. One may use `ForLt::Of<'a>` to get an instance of a type for a specific lifetime. For the case of cross referencing, one would almost always want the lifetime to be covariant. Therefore this is also made a requirement for the `ForLt` trait, so functions with `ForLt` trait bound can assume covariance. A macro `ForLt!()` is provided to be able to obtain a type that implements `ForLt`. For example, `ForLt!(for<'a> Bar<'a>)` would yield a type that `::Of<'a>` is `Bar<'a>`. This also works with lifetime elision, e.g. `ForLt!(Bar<'_>)` or for types without lifetime at all, e.g. `ForLt!(u32)`. The API design draws inspiration from the higher-kinded-types [1] crate, however different design decision has been taken (e.g. covariance requirement) and the implementation is independent. License headers use "Apache-2.0 OR MIT" because I anticipate this to be used in pin-init crate too which is licensed as such. Link: https://docs.rs/higher-kinded-types/ [1] Signed-off-by: Gary Guo Tested-by: Dirk Behme --- rust/Makefile | 1 + rust/kernel/types.rs | 4 + rust/kernel/types/for_lt.rs | 117 +++++++++++++++++ rust/macros/for_lt.rs | 242 ++++++++++++++++++++++++++++++++++++ rust/macros/lib.rs | 12 ++ 5 files changed, 376 insertions(+) create mode 100644 rust/kernel/types/for_lt.rs create mode 100644 rust/macros/for_lt.rs diff --git a/rust/Makefile b/rust/Makefile index b361bfedfdf0..c5a9a3339416 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -110,6 +110,7 @@ syn-cfgs :=3D \ feature=3D"parsing" \ feature=3D"printing" \ feature=3D"proc-macro" \ + feature=3D"visit" \ feature=3D"visit-mut" =20 syn-flags :=3D \ diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 4329d3c2c2e5..3119401dcb9f 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -11,6 +11,10 @@ }; use pin_init::{PinInit, Wrapper, Zeroable}; =20 +#[doc(hidden)] +pub mod for_lt; +pub use for_lt::ForLt; + /// Used to transfer ownership to and from foreign (non-Rust) languages. /// /// Ownership is transferred from Rust to a foreign language by calling [`= Self::into_foreign`] and diff --git a/rust/kernel/types/for_lt.rs b/rust/kernel/types/for_lt.rs new file mode 100644 index 000000000000..22b4518a115b --- /dev/null +++ b/rust/kernel/types/for_lt.rs @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Provide implementation and test of the `ForLt` trait and macro. +//! +//! This module is hidden and user should just use `ForLt!` directly. + +use core::marker::PhantomData; + +/// Representation of types generic over a lifetime. +/// +/// The type must be covariant over the generic lifetime, i.e. the lifetim= e parameter +/// can be soundly shorterned. +/// +/// The lifetime involved must be covariant. +/// +/// # Macro +/// +/// It is not recommended to implement this trait directly. `ForLt!` macro= is provided to obtain a +/// type that implements this trait. +/// +/// The full syntax is +/// ``` +/// # use kernel::types::ForLt; +/// # fn expect_lt() {} +/// # struct TypeThatUse<'a>(&'a ()); +/// # expect_lt::< +/// ForLt!(for<'a> TypeThatUse<'a>) +/// # >(); +/// ``` +/// which gives a type so that ` TypeThatUse<'a>) as ForLt>= ::Of<'b>` +/// is `TypeThatUse<'b>`. +/// +/// You may also use a short-hand syntax which works similar to lifetime e= lision. +/// The macro also accepts types that does not involved lifetime at all. +/// ``` +/// # use kernel::types::ForLt; +/// # fn expect_lt() {} +/// # struct TypeThatUse<'a>(&'a ()); +/// # expect_lt::< +/// ForLt!(TypeThatUse<'_>) // Equivalent to `ForLt!(for<'a> TypeThatUse<'= a>)` +/// # >(); +/// # expect_lt::< +/// ForLt!(&u32) // Equivalent to `ForLt!(for<'a> &'a u32)` +/// # >(); +/// # expect_lt::< +/// ForLt!(u32) // Equivalent to `ForLt!(for<'a> u32)` +/// # >(); +/// ``` +/// +/// The macro will attempt to prove that the type is indeed covariant over= the lifetime supplied. +/// When it cannot be syntactically proven, it will emit checks to ask the= Rust compiler to prove +/// it. +/// ```ignore,compile_fail +/// # use kernel::types::ForLt; +/// # fn expect_lt() {} +/// # expect_lt::< +/// ForLt!(fn(&u32)) // Contravariant, will fail compilation. +/// # >(); +/// ``` +/// +/// There is a limitation if the type refer to generic parameters; if the = macro cannot prove the +/// covariance syntactically, the emitted checks will fail the compilation= as it needs to refer to +/// the generic parameter but is in a separate item. +/// ``` +/// # use kernel::types::ForLt; +/// fn expect_lt() {} +/// # #[allow(clippy::unnecessary_safety_comment, reason =3D "false positi= ve")] +/// fn generic_fn() { +/// // Syntactically proven by the macro +/// expect_lt::(); +/// // Syntactically proven by the macro +/// expect_lt::)>(); +/// // Cannot be syntactically proven, need to check covariance of `KB= ox` +/// // expect_lt::)>(); +/// } +/// ``` +/// +/// # Safety +/// +/// `Self::Of<'a>` must be covariant over the lifetime `'a`. +pub unsafe trait ForLt { + /// The type parameterized by the lifetime. + type Of<'a>: 'a; + + /// Cast a reference to a shorter lifetime. + #[inline(always)] + fn cast_ref<'r, 'short: 'r, 'long: 'short>(long: &'r Self::Of<'long>) = -> &'r Self::Of<'short> { + // SAFETY: This is sound as this trait guarantees covariance. + unsafe { core::mem::transmute(long) } + } +} +pub use macros::ForLt; + +/// This is intended to be an "unsafe-to-refer-to" type. +/// +/// Must only be used by the `ForLt!` macro. +/// +/// `T` is the magic `dyn for<'a> WithLt<'a, TypeThatUse<'a>>` generated b= y macro. +/// +/// `WF` is a type that the macro can use to assert some specific type is = well-formed. +/// +/// `N` is to provide the macro a place to emit arbitrary items, in case i= t needs to prove +/// additional properties. +#[doc(hidden)] +pub struct UnsafeForLtImpl(PhantomData<(WF,= T)>); + +// This is a helper trait for implementation `ForLt` to be able to use HRT= B. +#[doc(hidden)] +pub trait WithLt<'a> { + type Of: 'a; +} + +// SAFETY: In `ForLt!` macro, a covariance proof is generated when naming = `UnsafeForLtImpl` +// and it will fail to evaluate if the type is not covariant. +unsafe impl WithLt<'a>, WF> ForLt for UnsafeForLtImpl<= T, WF, 0> { + type Of<'a> =3D >::Of; +} diff --git a/rust/macros/for_lt.rs b/rust/macros/for_lt.rs new file mode 100644 index 000000000000..df2027789713 --- /dev/null +++ b/rust/macros/for_lt.rs @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::{ + Span, + TokenStream, // +}; +use quote::{ + format_ident, + quote, // +}; +use syn::{ + parse::{ + Parse, + ParseStream, // + }, + visit::Visit, + visit_mut::VisitMut, + Lifetime, + Result, + Token, + Type, // +}; + +pub(crate) enum HigherRankedType { + Explicit { + _for_token: Token![for], + _lt_token: Token![<], + lifetime: Lifetime, + _gt_token: Token![>], + ty: Type, + }, + Implicit { + ty: Type, + }, +} + +impl Parse for HigherRankedType { + fn parse(input: ParseStream<'_>) -> Result { + if input.peek(Token![for]) { + Ok(Self::Explicit { + _for_token: input.parse()?, + _lt_token: input.parse()?, + lifetime: input.parse()?, + _gt_token: input.parse()?, + ty: input.parse()?, + }) + } else { + Ok(Self::Implicit { ty: input.parse()? }) + } + } +} + +trait TypeExt { + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type; + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type; + fn has_lifetime(&self, lt: &Lifetime) -> bool; +} + +impl TypeExt for Type { + fn expand_elided_lifetime(&self, explicit_lt: &Lifetime) -> Type { + struct ElidedLifetimeExpander<'a>(&'a Lifetime); + + impl VisitMut for ElidedLifetimeExpander<'_> { + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { + // Expand explicit `'_` + if lifetime.ident =3D=3D "_" { + *lifetime =3D self.0.clone(); + } + } + + fn visit_type_reference_mut(&mut self, reference: &mut syn::Ty= peReference) { + syn::visit_mut::visit_type_reference_mut(self, reference); + + if reference.lifetime.is_none() { + reference.lifetime =3D Some(self.0.clone()); + } + } + } + + let mut ret =3D self.clone(); + ElidedLifetimeExpander(explicit_lt).visit_type_mut(&mut ret); + ret + } + + fn replace_lifetime(&self, src: &Lifetime, dst: &Lifetime) -> Type { + struct LifetimeReplacer<'a>(&'a Lifetime, &'a Lifetime); + + impl VisitMut for LifetimeReplacer<'_> { + fn visit_lifetime_mut(&mut self, lifetime: &mut Lifetime) { + if lifetime.ident =3D=3D self.0.ident { + *lifetime =3D self.1.clone(); + } + } + } + + let mut ret =3D self.clone(); + LifetimeReplacer(src, dst).visit_type_mut(&mut ret); + ret + } + + fn has_lifetime(&self, lt: &Lifetime) -> bool { + struct HasLifetime<'a>(&'a Lifetime, bool); + + impl Visit<'_> for HasLifetime<'_> { + fn visit_lifetime(&mut self, lifetime: &Lifetime) { + if lifetime.ident =3D=3D self.0.ident { + self.1 =3D true; + } + } + } + + let mut visitor =3D HasLifetime(lt, false); + visitor.visit_type(self); + visitor.1 + } +} + +struct Prover<'a>(&'a Lifetime, Vec<&'a Type>); + +impl<'a> Prover<'a> { + /// Prove that `ty` is covariant over `'lt`. + /// + /// This also needs to prove that it'll be wellformed for any instance= of `'lt`. + /// It can be assumed that `ty` will be wellformed if `'lt` is substit= uted to `'static`. + fn prove(&mut self, ty: &'a Type) { + match ty { + Type::Paren(ty) =3D> self.prove(&ty.elem), + Type::Group(ty) =3D> self.prove(&ty.elem), + + // No lifetime involved + Type::Never(_) =3D> {} + + // `[T; N]` and `[T]` is covariant over `T`. + Type::Array(ty) =3D> self.prove(&ty.elem), + Type::Slice(ty) =3D> self.prove(&ty.elem), + + Type::Tuple(ty) =3D> { + for elem in &ty.elems { + self.prove(elem); + } + } + + // `*const T` is covariant over `T` + Type::Ptr(ty) if ty.const_token.is_some() =3D> self.prove(&ty.= elem), + + // `&T` is covariant over `T` and lifetime. + // + // Note that if we encounter `&'other_lt T`, then we still nee= d to make sure the type + // is wellformed if `T` involves `&'lt`, so we defer to the co= mpiler. + // + // This is to block cases like `ForLt!(for<'a> &'static &'a u3= 2)`, as the presence of + // the type implies `'a: 'static` but this is unsound. + Type::Reference(ty) + if ty.mutability.is_none() && ty.lifetime.as_ref() =3D=3D = Some(self.0) =3D> + { + self.prove(&ty.elem) + } + + // `&[mut] T` is covariant over lifetime. + // In case we have `&[mut] NoLifetime`, we don't need to do ad= ditional checks. + Type::Reference(ty) if !ty.elem.has_lifetime(self.0) =3D> (), + + // No mention of lifetime at all, no need to perform compiler = check. + ty if !ty.has_lifetime(self.0) =3D> (), + + // Otherwise, we need to emit checks so that compiler can dete= rmine if the types are + // actually covariant. + ty =3D> self.1.push(ty), + } + } +} + +pub(crate) fn for_lt(input: HigherRankedType) -> TokenStream { + let (ty, lifetime) =3D match input { + HigherRankedType::Explicit { lifetime, ty, .. } =3D> (ty, lifetime= ), + HigherRankedType::Implicit { ty } =3D> { + // If there's no explicit `for<'a>` binder, inject a synthetic= `'__elided` lifetime + // and expand elided sites. + let lifetime =3D Lifetime { + apostrophe: Span::mixed_site(), + ident: format_ident!("__elided", span =3D Span::mixed_site= ()), + }; + (ty.expand_elided_lifetime(&lifetime), lifetime) + } + }; + + let mut prover =3D Prover(&lifetime, Vec::new()); + prover.prove(&ty); + + let mut proof =3D Vec::new(); + + // Emit proofs for every type that requires additional compiler help i= n proving covariance. + for (idx, required_proof) in prover.1.into_iter().enumerate() { + // Insert a proof that the type is well-formed. + // + // This is intended to workaround a Rust compiler soundness bug re= lated to HRTB. + // https://github.com/rust-lang/rust/issues/152489 + // + // This needs to be a struct instead of fn to avoid the implied WF= bounds. + let wf_proof_name =3D format_ident!("ProveWf{idx}"); + proof.push(quote!( + struct #wf_proof_name<#lifetime>( + ::core::marker::PhantomData<&#lifetime ()>, #required_proof + ); + )); + + // Insert a proof that the type is covariant. + let cov_proof_name =3D format_ident!("prove_covariant_{idx}"); + proof.push(quote!( + fn #cov_proof_name<'__short, '__long: '__short>( + long: #wf_proof_name<'__long> + ) -> #wf_proof_name<'__short> { + long + } + )); + } + + // Make sure that the type is wellformed when substituting lifetime wi= th `'static`. + // + // Currently the Rust compiler doesn't check this, see the above Prove= Wf documentation. + // + // We prefer to use this way of proving WF-ness as it can work when ge= nerics are involved. + let ty_static =3D ty.replace_lifetime( + &lifetime, + &Lifetime { + apostrophe: Span::mixed_site(), + ident: format_ident!("static"), + }, + ); + + quote!( + ::kernel::types::for_lt::UnsafeForLtImpl::< + dyn for<#lifetime> ::kernel::types::for_lt::WithLt<#lifetime, = Of =3D #ty>, + #ty_static, + { + #(#proof)* + + 0 + } + > + ) +} diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 2cfd59e0f9e7..e5f6f8318112 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -17,6 +17,7 @@ mod concat_idents; mod export; mod fmt; +mod for_lt; mod helpers; mod kunit; mod module; @@ -489,3 +490,14 @@ pub fn kunit_tests(attr: TokenStream, input: TokenStre= am) -> TokenStream { .unwrap_or_else(|e| e.into_compile_error()) .into() } + +/// Obtain a type that implements `ForLt` for the given higher-ranked type. +/// +/// Please refer to the documentation of [`ForLt`] trait. +/// +/// [`ForLt`]: trait.ForLt.html +#[proc_macro] +#[allow(non_snake_case)] // The macro shares the name with the trait. +pub fn ForLt(input: TokenStream) -> TokenStream { + for_lt::for_lt(parse_macro_input!(input)).into() +} --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 3AF4E31715C; Wed, 6 May 2026 21:51: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=1778104302; cv=none; b=X3fI4FuOcSI5JaL14srEzTzlud1is8Xnk909KEbcBPY7l9eyIZtLdwozJLWvilVnPMYZRSoG5ymuG6SnKP4YwDPU/o06bJlmbWrxOcDPYrxuuaLsjm7HBBpRlgzYa5jc0yyBcGbqxHCx63mlsgD92HQOJUTSgm3oZudD26+lDUQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104302; c=relaxed/simple; bh=FzCtsvvJktcwIZ1wUZhKLVgQ/60zQdzBFPdyJsVc0P4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=do4Y8x7gJQZN1vCbK5b0tmTEgn/gSnHqQ11ALq4OzZVoJI9Q6BPREzZCbtdgTQ10505Zboru5V+p9DDJJ3Nw3eEqquk2ozCXX42G17dbjUadXUI0jLPNdSrq7LzyGlX4glVbmq68H4GRbQRd2mNCYLGAkp3+A86pxl3D0bOaakA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WuAPpZL7; 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="WuAPpZL7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D4D9FC2BCC4; Wed, 6 May 2026 21:51:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104302; bh=FzCtsvvJktcwIZ1wUZhKLVgQ/60zQdzBFPdyJsVc0P4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WuAPpZL7RMrPTI990v7VfJ1Z6y+Tz2GFskBvnJPeEs/T1IsTAGy7BbpsS8iE7y4ln YVvhh302ow/ck+EAWzvUzrijue4EPqDJUgEkeJFW4iVndoTvnX+6Qmv7FzS7NHFpA4 A5mwVMROnLBpMnX5Hb0aKGd8aFb+h+SvUOo9bnQh3pxAmJMp/3u4F7PdH0G12EO94/ jKq9LfVrFK5A5AFTqKScYCMldkc/HP8gEPop0etXaEyPsoObF+v2+vvCs5JSwSyFys mMCWOLd3MUX5kmTlh2n1dzXqgI/H/Oria+jim9BAh9bu7jYHAdeWzU1/YC3a8JAYIY aJTgUobK/Ql1w== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 03/25] rust: device: generalize drvdata methods over ForLt Date: Wed, 6 May 2026 23:50:39 +0200 Message-ID: <20260506215113.851360-4-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Generalize set_drvdata(), drvdata_obtain() and drvdata_borrow() to take F: ForLt, enabling Higher-Ranked Lifetime Types (HRT) for device private data. The data is initialized as F::Of<'bound> and stored as F::Of<'static>; ForLt guarantees covariance, making it sound to shorten the stored 'static lifetime to the borrow lifetime of &self. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/auxiliary.rs | 7 ++-- rust/kernel/device.rs | 75 ++++++++++++++++++++++++++++------------ rust/kernel/driver.rs | 15 +++++--- rust/kernel/i2c.rs | 13 ++++--- rust/kernel/pci.rs | 11 +++--- rust/kernel/platform.rs | 11 +++--- rust/kernel/usb.rs | 11 +++--- 7 files changed, 96 insertions(+), 47 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 19aec94aa95b..37690fa14891 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -20,6 +20,7 @@ }, prelude::*, types::{ + ForLt, ForeignOwnable, Opaque, // }, @@ -46,7 +47,7 @@ // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType =3D bindings::auxiliary_driver; - type DriverData =3D T; + type DriverData =3D ForLt!(T); const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 @@ -97,7 +98,7 @@ extern "C" fn probe_callback( from_result(|| { let data =3D T::probe(adev, info); =20 - adev.as_ref().set_drvdata(data)?; + adev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -112,7 +113,7 @@ extern "C" fn remove_callback(adev: *mut bindings::auxi= liary_device) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { adev.as_ref().drvdata_borrow::() }; + let data =3D unsafe { adev.as_ref().drvdata_borrow::() = }; =20 T::unbind(adev, data); } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index fd50399aadea..cee61638b08c 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -10,6 +10,7 @@ prelude::*, sync::aref::ARef, types::{ + ForLt, ForeignOwnable, Opaque, // }, // @@ -202,23 +203,42 @@ pub unsafe fn as_bound(&self) -> &Device { } =20 impl Device { - /// Store a pointer to the bound driver's private data. - pub fn set_drvdata(&self, data: impl PinInit) ->= Result { + /// Store the bound driver's private data. + /// + /// `F` is the [`ForLt`] encoding of the data type. For types without = a lifetime parameter, + /// use [`ForLt!(T)`](macro@ForLt). For lifetime-parameterized types, = the data is + /// initialized as `F::Of<'bound>` and stored as `F::Of<'static>`; lif= etimes are + /// erased and do not affect layout, while [`ForLt`] guarantees covari= ance for safe + /// lifetime shortening. + /// + /// [`ForLt`]: trait@ForLt + pub fn set_drvdata<'bound, F: ForLt>( + &self, + data: impl PinInit, Error>, + ) -> Result { let data =3D KBox::pin_init(data, GFP_KERNEL)?; =20 + // SAFETY: Lifetimes are erased and do not affect layout, so Of<'b= ound> and Of<'static> have + // identical representation. The raw pointer is type-erased throug= h c_void anyway. + let ptr =3D KBox::into_raw(unsafe { Pin::into_inner_unchecked(data= ) }); + // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. - unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreig= n().cast()) }; + unsafe { bindings::dev_set_drvdata(self.as_raw(), ptr.cast()) }; =20 Ok(()) } =20 /// Take ownership of the private data stored in this [`Device`]. /// + /// `F` is the [`ForLt`] encoding of the data type. The returned [`KBo= x`] has its lifetime + /// tied to `&self`, ensuring it is dropped before the device goes awa= y. + /// /// # Safety /// - /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by - /// [`Device::set_drvdata`]. - pub(crate) unsafe fn drvdata_obtain(&self) -> Option>> { + /// - `F` must match the [`ForLt`] type previously stored by [`Device:= :set_drvdata`]. + /// + /// [`ForLt`]: trait@ForLt + pub(crate) unsafe fn drvdata_obtain(&self) -> Option>>> { // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. let ptr =3D unsafe { bindings::dev_get_drvdata(self.as_raw()) }; =20 @@ -230,24 +250,31 @@ pub(crate) unsafe fn drvdata_obtain(&self= ) -> Option>> { } =20 // SAFETY: - // - If `ptr` is not NULL, it comes from a previous call to `into_= foreign()`. - // - `dev_get_drvdata()` guarantees to return the same pointer giv= en to `dev_set_drvdata()` - // in `into_foreign()`. - Some(unsafe { Pin::>::from_foreign(ptr.cast()) }) + // - If `ptr` is not NULL, it was stored by a previous call to `se= t_drvdata()`, which + // stores a pointer via `KBox::into_raw()`. + // - Lifetimes are erased and do not affect layout, so reconstruct= ing as `F::Of<'_>` + // (tied to `&self`) is sound. + // - `dev_get_drvdata()` guarantees to return the same pointer giv= en to + // `dev_set_drvdata()`. + Some(unsafe { Pin::new_unchecked(KBox::from_raw(ptr.cast())) }) } =20 /// Borrow the driver's private data bound to this [`Device`]. /// + /// `F` is the [`ForLt`] encoding of the data type. The returned refer= ence has its lifetime + /// shortened from `'static` to `&self`'s borrow lifetime via [`ForLt:= :cast_ref`]. + /// /// # Safety /// /// - Must only be called after a preceding call to [`Device::set_drvd= ata`] and before the /// device is fully unbound. - /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by - /// [`Device::set_drvdata`]. - pub unsafe fn drvdata_borrow(&self) -> Pin<&T> { + /// - `F` must match the [`ForLt`] type previously stored by [`Device:= :set_drvdata`]. + /// + /// [`ForLt`]: trait@ForLt + pub unsafe fn drvdata_borrow(&self) -> Pin<&F::Of<'_>> { // SAFETY: `drvdata_unchecked()` has the exact same safety require= ments as the ones // required by this method. - unsafe { self.drvdata_unchecked() } + unsafe { self.drvdata_unchecked::() } } } =20 @@ -258,18 +285,22 @@ impl Device { /// /// - Must only be called after a preceding call to [`Device::set_drvd= ata`] and before /// the device is fully unbound. - /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by - /// [`Device::set_drvdata`]. - unsafe fn drvdata_unchecked(&self) -> Pin<&T> { + /// - `F` must match the [`ForLt`] type previously stored by [`Device:= :set_drvdata`]. + unsafe fn drvdata_unchecked(&self) -> Pin<&F::Of<'_>> { // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. let ptr =3D unsafe { bindings::dev_get_drvdata(self.as_raw()) }; =20 // SAFETY: - // - By the safety requirements of this function, `ptr` comes from= a previous call to - // `into_foreign()`. - // - `dev_get_drvdata()` guarantees to return the same pointer giv= en to `dev_set_drvdata()` - // in `into_foreign()`. - unsafe { Pin::>::borrow(ptr.cast()) } + // - By the safety requirements of this function, `ptr` was stored= by a previous call to + // `set_drvdata()` via `KBox::into_raw()`. + // - `dev_get_drvdata()` guarantees to return the same pointer giv= en to + // `dev_set_drvdata()`. + let pinned: Pin<&F::Of<'static>> =3D + unsafe { Pin::>>::borrow(ptr.cast()) }; + + // SAFETY: The data was pinned when stored; `cast_ref` only shorte= ns + // the lifetime, so the pinning guarantee is preserved. + unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) } } } =20 diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index bb53035a1017..2ab3c0050117 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -99,7 +99,10 @@ device, of, prelude::*, - types::Opaque, + types::{ + ForLt, + Opaque, // + }, ThisModule, // }; =20 @@ -112,14 +115,16 @@ /// /// Implementors must guarantee that: /// - `DriverType` is `repr(C)`, -/// - `DriverData` is the type of the driver's device private data. +/// - `DriverData` is the [`ForLt`] encoding of the driver's device privat= e data type. /// - `DriverType` embeds a valid `struct device_driver` at byte offset `D= EVICE_DRIVER_OFFSET`. +/// +/// [`ForLt`]: trait@ForLt pub unsafe trait DriverLayout { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; =20 - /// The type of the driver's device private data. - type DriverData; + /// The [`ForLt`](trait@ForLt) encoding of the driver's device private= data type. + type DriverData: ForLt; =20 /// Byte offset of the embedded `struct device_driver` within `DriverT= ype`. /// @@ -193,7 +198,7 @@ extern "C" fn post_unbind_callback(dev: *mut bindings::= device) { // be released after the driver's bus device private data is dropp= ed. // // SAFETY: By the safety requirements of the `Driver` trait, `T::D= riverData` is the - // driver's device private data type. + // ForLt encoding of the driver's device private data type. drop(unsafe { dev.drvdata_obtain::() }); } =20 diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 7b908f0c5a58..cde3dd7a6cc7 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -20,7 +20,10 @@ ARef, AlwaysRefCounted, // }, - types::Opaque, // + types::{ + ForLt, + Opaque, // + }, // }; =20 use core::{ @@ -98,7 +101,7 @@ macro_rules! i2c_device_table { // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType =3D bindings::i2c_driver; - type DriverData =3D T; + type DriverData =3D ForLt!(T); const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 @@ -165,7 +168,7 @@ extern "C" fn probe_callback(idev: *mut bindings::i2c_c= lient) -> kernel::ffi::c_ from_result(|| { let data =3D T::probe(idev, info); =20 - idev.as_ref().set_drvdata(data)?; + idev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -177,7 +180,7 @@ extern "C" fn remove_callback(idev: *mut bindings::i2c_= client) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_dr= vdata()` has been called // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; + let data =3D unsafe { idev.as_ref().drvdata_borrow::() = }; =20 T::unbind(idev, data); } @@ -189,7 +192,7 @@ extern "C" fn shutdown_callback(idev: *mut bindings::i2= c_client) { // SAFETY: `shutdown_callback` is only ever called after a success= ful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; + let data =3D unsafe { idev.as_ref().drvdata_borrow::() = }; =20 T::shutdown(idev, data); } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index af74ddff6114..fe5148f41d8b 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -19,7 +19,10 @@ }, prelude::*, str::CStr, - types::Opaque, + types::{ + ForLt, + Opaque, // + }, ThisModule, // }; use core::{ @@ -64,7 +67,7 @@ // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType =3D bindings::pci_driver; - type DriverData =3D T; + type DriverData =3D ForLt!(T); const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 @@ -115,7 +118,7 @@ extern "C" fn probe_callback( from_result(|| { let data =3D T::probe(pdev, info); =20 - pdev.as_ref().set_drvdata(data)?; + pdev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -130,7 +133,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_= dev) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() = }; =20 T::unbind(pdev, data); } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 8917d4ee499f..7ff69e3eea90 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -27,7 +27,10 @@ }, of, prelude::*, - types::Opaque, + types::{ + ForLt, + Opaque, // + }, ThisModule, // }; =20 @@ -50,7 +53,7 @@ // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType =3D bindings::platform_driver; - type DriverData =3D T; + type DriverData =3D ForLt!(T); const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 @@ -103,7 +106,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platf= orm_device) -> kernel::ff from_result(|| { let data =3D T::probe(pdev, info); =20 - pdev.as_ref().set_drvdata(data)?; + pdev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -118,7 +121,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::plat= form_device) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() = }; =20 T::unbind(pdev, data); } diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 9c17a672cd27..9b9d3ae41087 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -19,7 +19,10 @@ }, prelude::*, sync::aref::AlwaysRefCounted, - types::Opaque, + types::{ + ForLt, + Opaque, // + }, ThisModule, // }; use core::{ @@ -41,7 +44,7 @@ // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType =3D bindings::usb_driver; - type DriverData =3D T; + type DriverData =3D ForLt!(T); const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 @@ -93,7 +96,7 @@ extern "C" fn probe_callback( let data =3D T::probe(intf, id, info); =20 let dev: &device::Device =3D intf.as_ref= (); - dev.set_drvdata(data)?; + dev.set_drvdata::(data)?; Ok(0) }) } @@ -110,7 +113,7 @@ extern "C" fn disconnect_callback(intf: *mut bindings::= usb_interface) { // SAFETY: `disconnect_callback` is only ever called after a succe= ssful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { dev.drvdata_borrow::() }; + let data =3D unsafe { dev.drvdata_borrow::() }; =20 T::disconnect(intf, data); } --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 8A1A431715C; Wed, 6 May 2026 21:51:48 +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=1778104309; cv=none; b=gTBgcqzcAkmqXVOV+Lt9RfEiQvsCJpKTqUKllGHt6227ERqwDyy4i4bxuFpAEsfu72e7K0lskbI1DoPxkPl/NmO4n4p0xTdhWzWB+Lrx8svCmnnbpGIYG5lvrykIB9u5JQK6wtaJQSpf4nisIJb27JRSQcRMEThFGaEvNT2BXEA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104309; c=relaxed/simple; bh=CVDhFuv85MahzpR44TGGEknLyGLiFPiboA4gD9I6zS8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GI+4zdnobPW7RKEeBFJEcSz38H4WPTxzrrvw/pPnlspPuRApAXSB/58kx6wtY/9a6flUGWcFG27S3sStN9fehjKQhDa5dR0l/HyygOTeNzpPecyfrfgLc8SRUVugI+Hfhk8vlEetyQ5WQiSx4USNX3MAkUadPsg6LlXvb53ChXI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lC59G5IQ; 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="lC59G5IQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8D540C2BCFD; Wed, 6 May 2026 21:51:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104308; bh=CVDhFuv85MahzpR44TGGEknLyGLiFPiboA4gD9I6zS8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lC59G5IQUtnI0r9rKzsfpRnjxCA4QoqhhAHTrZbDMn9NJB9otwvq6J28fuVy6FlTU pUOiPOtnFhFKeBu/0gmzCdBItP7k1DS2aTfMjfZ6HahvH38FqCuIJEjhpY0aKLdo5W nuJp+Lwns+zU1zs6qG6ppV6fPcalY8WI7V2ms+7A3s4TuJgatnoHrZZXQsU6V0maG0 T4pZA3VnsL5SQq6QiH88UL/h+nENC/ZLRzODlM6leQUjLvSN8J7eNu1Of1gptHDsc4 1iHZoWTm21Aa11dFgB9t5X20T8TOz1GP+Z72WWwTA6x9aQ/EwKACq2bl9D9RbIzktD fwmf1H9LDyAtg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 04/25] rust: driver: make Adapter trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:40 +0200 Message-ID: <20260506215113.851360-5-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Parameterize the Adapter trait with a lifetime, changing the id_info(), of_id_info() and acpi_id_info() methods to take &'bound Device and return &'bound Self::IdInfo instead of &'static. This is needed for the ForLt conversion of bus driver traits. Once Driver becomes lifetime-parameterized, its IdInfo associated type may depend on the lifetime parameter. With Adapter<'bound>, the impl can set IdInfo =3D as Driver<'bound>>::IdInfo and the lifetime flows through naturally, avoiding the need for transmute. For the current non-lifetime-parameterized Driver trait, this is a no-op type relaxation; IdInfo is 'static and &'static coerces to &'bound. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/driver.rs | 16 ++++++++++------ rust/kernel/i2c.rs | 10 +++++----- rust/kernel/platform.rs | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 2ab3c0050117..e462535f545d 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -96,7 +96,11 @@ =20 use crate::{ acpi, - device, + device::{ + self, + Bound, + Device, // + }, of, prelude::*, types::{ @@ -192,7 +196,7 @@ extern "C" fn post_unbind_callback(dev: *mut bindings::= device) { // a `struct device`. // // INVARIANT: `dev` is valid for the duration of the `post_unbind_= callback()`. - let dev =3D unsafe { &*dev.cast::>() }; + let dev =3D unsafe { &*dev.cast::>() = }; =20 // `remove()` has been completed at this point; devres resources a= re still valid and will // be released after the driver's bus device private data is dropp= ed. @@ -309,7 +313,7 @@ unsafe fn acpi_of_match_device( /// of a device and a driver. /// /// It provides bus independent functions for device / driver interactions. -pub trait Adapter { +pub trait Adapter<'bound> { /// The type holding driver private data about each device id supporte= d by the driver. type IdInfo: 'static; =20 @@ -319,7 +323,7 @@ pub trait Adapter { /// Returns the driver's private data from the matching entry in the [= `acpi::IdTable`], if any. /// /// If this returns `None`, it means there is no match with an entry i= n the [`acpi::IdTable`]. - fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo>= { + fn acpi_id_info(dev: &'bound Device) -> Option<&'bound Self::Id= Info> { #[cfg(not(CONFIG_ACPI))] { let _ =3D dev; @@ -353,7 +357,7 @@ fn acpi_id_info(dev: &device::Device) -> Option<&'stati= c Self::IdInfo> { /// Returns the driver's private data from the matching entry in the [= `of::IdTable`], if any. /// /// If this returns `None`, it means there is no match with an entry i= n the [`of::IdTable`]. - fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { + fn of_id_info(dev: &'bound Device) -> Option<&'bound Self::IdIn= fo> { let table =3D Self::of_id_table()?; =20 #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))] @@ -417,7 +421,7 @@ fn of_id_info(dev: &device::Device) -> Option<&'static = Self::IdInfo> { /// /// If this returns `None`, it means that there is no match in any of = the ID tables directly /// associated with a [`device::Device`]. - fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> { + fn id_info(dev: &'bound Device) -> Option<&'bound Self::IdInfo>= { let id =3D Self::acpi_id_info(dev); if id.is_some() { return id; diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index cde3dd7a6cc7..208c73aa3ce3 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -162,8 +162,8 @@ extern "C" fn probe_callback(idev: *mut bindings::i2c_c= lient) -> kernel::ffi::c_ // INVARIANT: `idev` is valid for the duration of `probe_callback(= )`. let idev =3D unsafe { &*idev.cast::>() }; =20 - let info =3D - Self::i2c_id_info(idev).or_else(|| ::= id_info(idev.as_ref())); + let info =3D Self::i2c_id_info(idev) + .or_else(|| >::id_info(idev.as_ref= ())); =20 from_result(|| { let data =3D T::probe(idev, info); @@ -198,14 +198,14 @@ extern "C" fn shutdown_callback(idev: *mut bindings::= i2c_client) { } =20 /// The [`i2c::IdTable`] of the corresponding driver. - fn i2c_id_table() -> Option::IdInfo>= > { + fn i2c_id_table() -> Option>= ::IdInfo>> { T::I2C_ID_TABLE } =20 /// Returns the driver's private data from the matching entry in the [= `i2c::IdTable`], if any. /// /// If this returns `None`, it means there is no match with an entry i= n the [`i2c::IdTable`]. - fn i2c_id_info(dev: &I2cClient) -> Option<&'static ::IdInfo> { + fn i2c_id_info(dev: &I2cClient) -> Option<&'static >::IdInfo> { let table =3D Self::i2c_id_table()?; =20 // SAFETY: @@ -225,7 +225,7 @@ fn i2c_id_info(dev: &I2cClient) -> Option<&'static ::Id } } =20 -impl driver::Adapter for Adapter { +impl<'bound, T: Driver + 'static> driver::Adapter<'bound> for Adapter { type IdInfo =3D T::IdInfo; =20 fn of_id_table() -> Option> { diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 7ff69e3eea90..506731a648c2 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -101,7 +101,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platf= orm_device) -> kernel::ff // // INVARIANT: `pdev` is valid for the duration of `probe_callback(= )`. let pdev =3D unsafe { &*pdev.cast::>(= ) }; - let info =3D ::id_info(pdev.as_ref()); + let info =3D >::id_info(pdev.as_ref()); =20 from_result(|| { let data =3D T::probe(pdev, info); @@ -127,7 +127,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::plat= form_device) { } } =20 -impl driver::Adapter for Adapter { +impl<'bound, T: Driver + 'static> driver::Adapter<'bound> for Adapter { type IdInfo =3D T::IdInfo; =20 fn of_id_table() -> Option> { --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 E03C63B3C13; Wed, 6 May 2026 21:51: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=1778104316; cv=none; b=fh/3DlWMFir0MYMZHub11J98WaNs1xgHdXv3/RAqVlJLyiFBHUjZSQS0c3KlpiHQMwdlUa8v1qfI1OCbF7iv5LMcHzCKZlxsKVNtCZqxZU7AEoiDZnjKIwvks2bUwpVPmvb/v4cqvpit4JZsz6un2z/GZ81MKe/mYd2ANQKM3Gs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104316; c=relaxed/simple; bh=OBpeRj6FSTcG0AEEiVV2B733gMqON0DFwTtw26epeTs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZLL2Ff3Fv9YbJ2wQo1YmfERjqnfodnwTWiVc7BiDAToN+KAN1kDO3XPtRiDJJZsDfCL/QKqi+WmCzzrlmrSlxcbMI705HnuaEoN4urWXFEgLzsGgjZ5C7O33QWgcePpOmE7kcPyo9oXfG7Xq9hx2dv2lJYxrixd7T2eBNcTR3KE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NsPl84A+; 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="NsPl84A+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48BD3C2BCB0; Wed, 6 May 2026 21:51:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104315; bh=OBpeRj6FSTcG0AEEiVV2B733gMqON0DFwTtw26epeTs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NsPl84A+sPG+5pSao2NU0zfqqTmAskgxFwvco5wPX8g1hdsrAIhdIZFydxZvzbmXp PPR/X1+L5kw+P3BUTYfTQTRdeEsGV7thr/LDuOvuuZtBhKdLXWUea5JE+sUBzM8fKW 2oLOFbwA6aXmjbwvP826WGjsTx1xCW6RyVGqa3gIUJI7pKQkGhiApGu7eRWm8JfGdz P7VxvjUPlZqISuuIP+AL/4diFomVLO+Kgw2z4QKIq7sw1HTuwQtbfBzvwEKOu5ix7n nZZf8ccb3hLa9fVEXXUPZTWR4EBspkD49TbXMTlwqau3SCEQxl1GSxLQZZY1zM/5z5 tNu6QgCmlqRPA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 05/25] rust: pci: implement Sync for Device Date: Wed, 6 May 2026 23:50:41 +0200 Message-ID: <20260506215113.851360-6-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Implement Sync for Device in addition to Device. The underlying struct pci_dev is the same; Bound is a zero-sized type-state marker that does not affect thread safety. This is needed for pci::Bar to hold &'bound Device (required for Bar::into_devres()) while remaining Send. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/pci.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index fe5148f41d8b..6f82f2e6c74f 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -526,3 +526,7 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all methods of `De= vice` // (i.e. `Device) are thread safe. unsafe impl Sync for Device {} + +// SAFETY: Same as `Device` -- the underlying `struct pci_dev` is = the same; +// `Bound` is a zero-sized type-state marker that does not affect thread s= afety. +unsafe impl Sync for Device {} --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 77A283B47C1; Wed, 6 May 2026 21:52: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=1778104322; cv=none; b=F28bhgMT4/h7w99WUafezYVaieCi9/pxPkzY4tcDbogoaIVEDiyRi6Hid9P5mBl7HVKt8+gGLCkQWOBJV9nnAu0D14Natuo9fpwB67BUN2F7IefYqcFfBsAWAqlMx+rwCDg+kjoE64XKTEOQV54J26AKygUQ7cvEdtxnCeavb0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104322; c=relaxed/simple; bh=QpY7OeVzdag9i3s1zOXGyUJCcDhM97iVsWF8/eXysoQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PFXkbG9XZr7f8G8rSVpon74NLwb8Pm3iaLdUV54cR20XFhvI7G/y2wzkT+lruVV6pNfzh19daHzpxkqaUQei21Q8rfI26XgqkGeqQ6CUDEuD2eP0CdciZhlq0lqV8jR2scVRUZCkhcxZzsOiuV+KMgoyvzFxhv/OA90pwWjkkLs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QzKG5z+l; 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="QzKG5z+l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 073C9C2BCB2; Wed, 6 May 2026 21:51:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104322; bh=QpY7OeVzdag9i3s1zOXGyUJCcDhM97iVsWF8/eXysoQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QzKG5z+l99CxfwRBalOq5RgpE7Kw8jLaOSMQ4Wnr150LD7wUyxnH7TaDhUPmckLRH cayED4QHWEkfYgPB3MPt3uOtPlSTAoF9KuPByKpr34thsdjPAZJ9F8J7S1yfkJ/YwD rDfSaSaoV5M6I1JodfESH8b1njNPE515MU9y8+kboGEcOrTTErBn0eA66NN1ZI3xlP M3C89VzSYUVwc1NMH+RSxor1SQFZBww8uWMNFQPgTntbxw5s/uO8UbV2BuEOGZt0Ta ZE8t4MvpK2Snzp6e5k9cJhxZqN2c6Ue8lijOkcCHIvm4NODpmTn/eAiPJqJa4K/Re2 vKIn3jrgQ7oyw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 06/25] rust: platform: implement Sync for Device Date: Wed, 6 May 2026 23:50:42 +0200 Message-ID: <20260506215113.851360-7-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Device uses the same underlying struct platform_device as Device; Bound is a zero-sized type-state marker that does not affect thread safety. This is needed for drivers to store &'bound platform::Device in their HRT private data while remaining Send. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/platform.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 506731a648c2..aec26307ae68 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -564,3 +564,7 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all methods of `De= vice` // (i.e. `Device) are thread safe. unsafe impl Sync for Device {} + +// SAFETY: Same as `Device` -- the underlying `struct platform_dev= ice` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread s= afety. +unsafe impl Sync for Device {} --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 64BF03B3C00; Wed, 6 May 2026 21:52:09 +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=1778104329; cv=none; b=WwtY4JPtVl2yY30XjEQOstnzfWsjYm3//tlvWjPMKaUXGZmn13p5wUpmwVH6k/1mkPExjCFqBlPaZrVmX4vU4BFvbtdTwdzcHA3DM0mfFJMO/6z7yHzZGwznaBzu52nPVG6pAZcyVDIp12Fc+0vWTaiaUuCZjN1sTRsJhpRQJTU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104329; c=relaxed/simple; bh=65oXQ5dRDyn6R/I5J2GVV5AhZXrpJwtI039sm97wFnA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tEdDRIQB6rJhp9wn1FgLkqNqr4tMoPBd/ETPhjhC9jVBcom2mf9zwJAQThwBi0Mzp15aOvIQ+wVCJX3ayL4gE+ADqpf2uEb+xNQyLUKUFkHoMixnyeUL2RzHrXfP6TvsP4obE/DTDuv8CTQQwe3ebCg6ddUweGtrnCSYU7y79GY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=alPIjzJn; 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="alPIjzJn" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B44E5C2BCB0; Wed, 6 May 2026 21:52:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104329; bh=65oXQ5dRDyn6R/I5J2GVV5AhZXrpJwtI039sm97wFnA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=alPIjzJnnLxZxj29Xga2dbUcgu56hG9l4FCeYpl8Ai4wUAhOFarKeAjgmmClxyFr+ VtoV7qhGLx0FZdixxfQjyJws6nXYDi+fIEPBypTPna7ivMpUAjNKHyd3ryIbuGI0ET 0WJml/BikgrO3E7NqldEv28tWSQKAQomjP4Yfth2KBv0FGujgh+fcmV47AKCKF1xIK 5283l6TDvLMZ1vumA8RIZl4jzPA93uK4t5Zo7ENV3dkU62VuMNJAHjNXSl+11ET5ZQ kINuExF25ZhakSKXNQTNNXnZtowYciFPTe3//hjD1w73IN54i8JT8v84ooqtN9ss4D B7HGlJPOQeJvQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 07/25] rust: auxiliary: implement Sync for Device Date: Wed, 6 May 2026 23:50:43 +0200 Message-ID: <20260506215113.851360-8-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Device uses the same underlying struct auxiliary_device as Device; Bound is a zero-sized type-state marker that does not affect thread safety. This is needed for drivers to store &'bound auxiliary::Device in their HRT private data while remaining Send. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/auxiliary.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 37690fa14891..e193ba5b7167 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -366,6 +366,10 @@ unsafe impl Send for Device {} // (i.e. `Device) are thread safe. unsafe impl Sync for Device {} =20 +// SAFETY: Same as `Device` -- the underlying `struct auxiliary_de= vice` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread s= afety. +unsafe impl Sync for Device {} + /// Wrapper that stores a [`TypeId`] alongside the registration data for r= untime type checking. #[repr(C)] #[pin_data] --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 1637D3B3C00; Wed, 6 May 2026 21:52: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=1778104336; cv=none; b=MsGspQAXR0S8BU7J2jBRbI9fpL7RFUXcBdRItJSB/Ci7ps9T9exN2HYNpEPFgWUdtJW3sXH90c6qpZ4JPn6IA1jDHE5WTHeuNdBMwJvomeC9YtgR2Xy9iWrczYNhIFM1j35XeGApVjtRPazGuPtwu7JhNP1qtdqAeSub5ae69po= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104336; c=relaxed/simple; bh=CJzXzWucM829+MDBDBZxsfVoUlMH9RIMYpxWLe+dI5Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OpzoPWyhQ1f3sIOX7wbrGKsF78B6w+Bs4hBPeuGCWcPM+sUkE8lMFiUttpQFGZi7r+z48SXZHrUgYU8MLJLaKvIWF/mDyfPwB3zClaCEGam4ESuasSRbXaGKaerPECCCDgYuSoK5n9kKjMQiUkXGvw9zISkPDsx+CaHwuqnXxu0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gqiWVNkr; 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="gqiWVNkr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6F378C2BCB2; Wed, 6 May 2026 21:52:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104335; bh=CJzXzWucM829+MDBDBZxsfVoUlMH9RIMYpxWLe+dI5Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gqiWVNkrOAoUEQgxyKxXgOhRxSopfd85M2KuZiGUg3Q9+CBan75GNvs50HVzvOT/2 QyUOlNTGtIV7uCejdqwiTzlDr8pe4WmFWjdkJdfstXxPIQCZs31DpJYiuNOCO0ZU+o D+mxt5xuFZc6VV7kzDwV7C0FPzGBoqJz/4zX91UXjgL9AinumpyM+GljwaZ1To6Acr Kg+UklkEy6NjaBYwVCYK3o+dOAIUDi1MeboX+ama+VPAzdxGvMzgl6c/IDTWGHMEtD LyCuPWtyucJb96lH/hMXT6YjMflOSTyafjXudZtyitRHVl01VLNA6139XR4sAOA+ve n/DB5C2AVPBKA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 08/25] rust: usb: implement Sync for Device Date: Wed, 6 May 2026 23:50:44 +0200 Message-ID: <20260506215113.851360-9-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Device uses the same underlying struct usb_device as Device; Bound is a zero-sized type-state marker that does not affect thread safety. This is needed for drivers to store &'bound usb::Device in their HRT private data while remaining Send. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/usb.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 9b9d3ae41087..442e456fd2d3 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -467,6 +467,10 @@ unsafe impl Send for Device {} // allow any mutation through a shared reference. unsafe impl Sync for Device {} =20 +// SAFETY: Same as `Device` -- the underlying `struct usb_device` = is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread s= afety. +unsafe impl Sync for Device {} + /// Declares a kernel module that exposes a single USB driver. /// /// # Examples --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 C7FDB3B47DF; Wed, 6 May 2026 21:52:22 +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=1778104342; cv=none; b=SdSKbMBrlI8raeSTQtaFGFL2MP3cePfcZ8okjI15RAlFCcy5WcnJEf+7Hs65FGot3MUe7dEHNrE33xMH/oYRGf9jQn1YQ73mA7S+Cd/FXX0vkaz/Pon+QlLuGQtYpTjYPtj789Ledw8fnZMf+lg8sYR0CPvNI3RkYDold91CqzU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104342; c=relaxed/simple; bh=hUk/06OQ65XIhi8xFZ1jZmeWHhNf8K96MP/3Shol3Ps=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VssihG86EQrnt8dmyDSnHSXclpZR7tPljMDQ80/4T2/TvRfXqAqvJCP6H1K4DdDfBKEByKW/PfROkY/B5ntGAF5EKuYr7dytO/7XUYohzRdfwVMpo1SB/OPLJIZC8xL+KFH38MEhlulwjjNrSwLjA/Efb+jxD8nkGa5B1p9ZCmM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mZ9aLErk; 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="mZ9aLErk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 27F25C2BCB0; Wed, 6 May 2026 21:52:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104342; bh=hUk/06OQ65XIhi8xFZ1jZmeWHhNf8K96MP/3Shol3Ps=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mZ9aLErk/O67CVVusinDvzXa1zZ5Sq+jvu/KVH4Rk7wBUsOzZrUHRywvjFM77FVbC B9HnyoZUNJ6seAgoqMFl/CX3/wHHPzhML+1d21x26xlbFULJ3Y03JM3BZCDXoWCcdg m5DTmSTVAG0YPC/wy6XNBPONWu2vPkwjI8Wyt4v+Rx8vNNgqkxO8d4rD8X/ABVTYD1 Gcul3KKNU84kySZx3AaquiOf/tvaOmS17Tn1gu7z4Ug3ZCPE67Nm+nkk8stuX+0PNx XWim4gydo+hn1jDezUf3CkiWQsPG+EqsliZJt9Y+LMxAudTkN8C8KcSaDTAyBxuP5/ J8W4a+SXhik8A== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 09/25] rust: device: implement Sync for Device Date: Wed, 6 May 2026 23:50:45 +0200 Message-ID: <20260506215113.851360-10-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" The underlying `struct device` is the same for all device contexts; `Bound` is a zero-sized type-state marker that does not affect thread safety. Implement `Sync` for `Device` with the same safety argument as the existing `Device` implementation. This is needed for types that hold `&'bound Device`, such as `io::mem::IoMem`, to be `Send`. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/device.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index cee61638b08c..fbbb297cf2a9 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -498,6 +498,10 @@ unsafe impl Send for Device {} // synchronization in `struct device`. unsafe impl Sync for Device {} =20 +// SAFETY: Same as `Device` -- the underlying `struct device` is t= he same; `Bound` is a +// zero-sized type-state marker that does not affect thread safety. +unsafe impl Sync for Device {} + /// Marker trait for the context or scope of a bus specific device. /// /// [`DeviceContext`] is a marker trait for types representing the context= of a bus specific --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 4C5A23B3C19; Wed, 6 May 2026 21:52:29 +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=1778104349; cv=none; b=Bu/AQGEBYLU552AROig+5Eds8FJ0W5JAondUUXn7i/5pyNTD75r8N55rtoPnXyOrFsQ58Gnvo1WagbKOvcsh8pFtlzOsjmRqrTmGf/MdAbSMDJAa3B+/q60w2uDRJ9uJfpEyyROP/ON6exJCAVIkR0l9ubkjO+Ikqtw1zsoxa6Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104349; c=relaxed/simple; bh=ig5DV0Sc4uVWVdLoZr3ZmpFzcTtS822JAW+IY4+QRxw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UvZW9hRVuh/gNLdtsxQ8nV6CVKAm30WgiD5IJ7+1cap9Ql6N4aGn1H4bpZ/ik2rBLepoy35yMkns61nYoxCq8W/0u4f0P0FUcz3lEwSNV1F31cbjLqUn0KxgM6vVCvr5XdjKBj2XfGURab8rXul39DrSf3W/2iDcIhHuaKnQCOM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=q/kTinFp; 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="q/kTinFp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D7111C2BCC4; Wed, 6 May 2026 21:52:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104349; bh=ig5DV0Sc4uVWVdLoZr3ZmpFzcTtS822JAW+IY4+QRxw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q/kTinFpYiLdcgsk9g/ipcufmJ28uyG5/TtU456pVzuI2LTwykr3G+FevCNrd3vOg nkBXwjxjoLzHEwAuusi7/YSalnUrIx4Rq71ix5vF7xCm3dq0c6+3YLfdAbLMP7xpCL ikGPvnUdEztaO99lvtasnh63Z9QSNUjy/NV+2BANeL8hzrSiDcNckXU0bPf1AGj6Pr l9XQmxZEij7lLji3u2dqmAdhO/P6bh5JWewcwZ1Lt+vXepe1Ksa5svXoKyTGGI/vm4 T9enMIfsFlQjK6JXfXZRKLat0C6GNgvwmZRPCthfTB5hNm96JW1vVc5WCy/pqs81sy BDPMHSa0cOAIA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 10/25] rust: pci: make Driver trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:46 +0200 Message-ID: <20260506215113.851360-11-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Make pci::Driver take a lifetime parameter 'bound that ties device resources to the binding scope. Internally, Adapter becomes Adapter with a HRTB bound for<'bound> F::Of<'bound>: Driver<'bound>; module_pci_driver! wraps the driver type in ForLt!() so drivers don't have to. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/driver.rs | 9 ++- drivers/gpu/nova-core/nova_core.rs | 4 +- rust/kernel/pci.rs | 80 +++++++++++++++++++-------- samples/rust/rust_dma.rs | 9 ++- samples/rust/rust_driver_auxiliary.rs | 13 +++-- samples/rust/rust_driver_pci.rs | 11 ++-- 6 files changed, 87 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 8fe484d357f6..d0ccfbc8d0ea 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -50,7 +50,7 @@ pub(crate) struct NovaCore { kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - ::IdInfo, + >::IdInfo, [ // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. ( @@ -72,11 +72,14 @@ pub(crate) struct NovaCore { ] ); =20 -impl pci::Driver for NovaCore { +impl<'bound> pci::Driver<'bound> for NovaCore { type IdInfo =3D (); const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinIn= it { + fn probe( + pdev: &'bound pci::Device, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); =20 diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 04a1fa6b25f8..49c093a0cb42 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -7,6 +7,7 @@ driver::Registration, pci, prelude::*, + types::ForLt, InPlaceModule, // }; =20 @@ -46,8 +47,9 @@ fn drop(&mut self) { struct NovaCoreModule { // Fields are dropped in declaration order, so `_driver` is dropped fi= rst, // then `_debugfs_guard` clears `DEBUGFS_ROOT`. + #[allow(clippy::type_complexity)] #[pin] - _driver: Registration>, + _driver: Registration>, _debugfs_guard: DebugfsRootGuard, } =20 diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 6f82f2e6c74f..1335857cae94 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -58,22 +58,35 @@ }; =20 /// An adapter for the registration of PCI drivers. -pub struct Adapter(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver= 's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_pci_driver!` generates +/// this automatically via `ForLt!()`. +pub struct Adapter(PhantomData); =20 // SAFETY: // - `bindings::pci_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored type of the driver's device private da= ta. // - `struct pci_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. -unsafe impl driver::DriverLayout for Adapter { +unsafe impl driver::DriverLayout for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType =3D bindings::pci_driver; - type DriverData =3D ForLt!(T); + type DriverData =3D F; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl driver::RegistrationOps for Adapter { +unsafe impl driver::RegistrationOps for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( pdrv: &Opaque, name: &'static CStr, @@ -84,7 +97,7 @@ unsafe fn register( (*pdrv.get()).name =3D name.as_char_ptr(); (*pdrv.get()).probe =3D Some(Self::probe_callback); (*pdrv.get()).remove =3D Some(Self::remove_callback); - (*pdrv.get()).id_table =3D T::ID_TABLE.as_ptr(); + (*pdrv.get()).id_table =3D as Driver<'static>>= ::ID_TABLE.as_ptr(); } =20 // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. @@ -99,7 +112,11 @@ unsafe fn unregister(pdrv: &Opaque) { } } =20 -impl Adapter { +impl Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback( pdev: *mut bindings::pci_dev, id: *const bindings::pci_device_id, @@ -113,12 +130,12 @@ extern "C" fn probe_callback( // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `stru= ct pci_device_id` and // does not add additional invariants, so it's safe to transmute. let id =3D unsafe { &*id.cast::() }; - let info =3D T::ID_TABLE.info(id.index()); =20 from_result(|| { - let data =3D T::probe(pdev, info); + let info =3D as Driver<'_>>::ID_TABLE.info(id.index= ()); + let data =3D as Driver<'_>>::probe(pdev, info); =20 - pdev.as_ref().set_drvdata::(data)?; + pdev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -131,16 +148,18 @@ extern "C" fn remove_callback(pdev: *mut bindings::pc= i_dev) { let pdev =3D unsafe { &*pdev.cast::>(= ) }; =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called - // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_borrow::() = }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; =20 - T::unbind(pdev, data); + as Driver<'_>>::unbind(pdev, data); } } =20 /// Declares a kernel module that exposes a single PCI driver. /// +/// The `type` field accepts a driver type, optionally with a lifetime pla= ceholder `'_` for +/// lifetime-parameterized drivers. The macro wraps it in [`ForLt!`] autom= atically. +/// /// # Examples /// ///```ignore @@ -152,10 +171,16 @@ extern "C" fn remove_callback(pdev: *mut bindings::pc= i_dev) { /// license: "GPL v2", /// } ///``` +/// +/// [`ForLt!`]: macro@ForLt +/// [`ForLt`]: trait@ForLt #[macro_export] macro_rules! module_pci_driver { -($($f:tt)*) =3D> { - $crate::module_driver!(, $crate::pci::Adapter, { $($f)* }); +(type: $type:ty, $($rest:tt)*) =3D> { + $crate::module_driver!(, $crate::pci::Adapter, { + type: $crate::types::ForLt!($type), + $($rest)* + }); }; } =20 @@ -261,6 +286,9 @@ macro_rules! pci_device_table { =20 /// The PCI driver trait. /// +/// Drivers implement this trait with a lifetime parameter `'bound` that t= ies +/// device resources to the device scope. +/// /// # Examples /// ///``` @@ -271,7 +299,7 @@ macro_rules! pci_device_table { /// kernel::pci_device_table!( /// PCI_TABLE, /// MODULE_PCI_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// ( /// pci::DeviceId::from_id(pci::Vendor::REDHAT, bindings::PCI_= ANY_ID as u32), @@ -280,21 +308,22 @@ macro_rules! pci_device_table { /// ] /// ); /// -/// impl pci::Driver for MyDriver { +/// impl<'bound> pci::Driver<'bound> for MyDriver { /// type IdInfo =3D (); /// const ID_TABLE: pci::IdTable =3D &PCI_TABLE; /// /// fn probe( -/// _pdev: &pci::Device, -/// _id_info: &Self::IdInfo, -/// ) -> impl PinInit { +/// _pdev: &'bound pci::Device, +/// _id_info: &'bound Self::IdInfo, +/// ) -> impl PinInit + 'bound { /// Err(ENODEV) /// } /// } ///``` +/// /// Drivers must implement this trait in order to get a PCI driver registe= red. Please refer to the /// `Adapter` documentation for an example. -pub trait Driver: Send { +pub trait Driver<'bound>: Send { /// The type holding information about each device id supported by the= driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -310,7 +339,10 @@ pub trait Driver: Send { /// /// Called when a new pci device is added or discovered. Implementers = should /// attempt to initialize the device here. - fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl P= inInit; + fn probe( + dev: &'bound Device, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound; =20 /// PCI driver unbind. /// @@ -322,7 +354,7 @@ pub trait Driver: Send { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + fn unbind(dev: &'bound Device, this: Pin<&'bound Self>) { let _ =3D (dev, this); } } diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs index 129bb4b39c04..e8b3e2e799f3 100644 --- a/samples/rust/rust_dma.rs +++ b/samples/rust/rust_dma.rs @@ -52,15 +52,18 @@ unsafe impl kernel::transmute::FromBytes for MyStruct {} kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - ::IdInfo, + >::IdInfo, [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] ); =20 -impl pci::Driver for DmaSampleDriver { +impl<'bound> pci::Driver<'bound> for DmaSampleDriver { type IdInfo =3D (); const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinIn= it { + fn probe( + pdev: &'bound pci::Device, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { dev_info!(pdev, "Probe DMA test driver.\n"); =20 diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driv= er_auxiliary.rs index 319ef734c02b..a1b42d30580e 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -14,6 +14,7 @@ driver, pci, prelude::*, + types::ForLt, InPlaceModule, // }; =20 @@ -59,16 +60,19 @@ struct ParentDriver { kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - ::IdInfo, + >::IdInfo, [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())] ); =20 -impl pci::Driver for ParentDriver { +impl<'bound> pci::Driver<'bound> for ParentDriver { type IdInfo =3D (); =20 const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 - fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinIn= it { + fn probe( + pdev: &'bound pci::Device, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { Ok(Self { _reg0: auxiliary::Registration::new( pdev.as_ref(), @@ -116,7 +120,8 @@ fn connect(adev: &auxiliary::Device) -> Result { #[pin_data] struct SampleModule { #[pin] - _pci_driver: driver::Registration>, + #[allow(clippy::type_complexity)] + _pci_driver: driver::Registration>, #[pin] _aux_driver: driver::Registration>, } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index 47d3e84fab63..794311691d1e 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -77,7 +77,7 @@ struct SampleDriver { kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - ::IdInfo, + >::IdInfo, [( pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), TestIndex::NO_EVENTFD @@ -138,12 +138,15 @@ fn config_space(pdev: &pci::Device) { } } =20 -impl pci::Driver for SampleDriver { +impl<'bound> pci::Driver<'bound> for SampleDriver { type IdInfo =3D TestIndex; =20 const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 - fn probe(pdev: &pci::Device, info: &Self::IdInfo) -> impl PinIni= t { + fn probe( + pdev: &'bound pci::Device, + info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { let vendor =3D pdev.vendor_id(); dev_dbg!( @@ -174,7 +177,7 @@ fn probe(pdev: &pci::Device, info: &Self::IdInfo)= -> impl PinInit, this: Pin<&Self>) { + fn unbind(pdev: &'bound pci::Device, this: Pin<&'bound Self>) { if let Ok(bar) =3D this.bar.access(pdev.as_ref()) { // Reset pci-testdev by writing a new test index. bar.write_reg(regs::TEST::zeroed().with_index(this.index)); --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 EB0053B3C08; Wed, 6 May 2026 21:52:35 +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=1778104356; cv=none; b=Qx+FsIRRSKWGfN2cpminAi/ETJjQRQajwf6DBgiQiHUkqqIwT4hxbitjL7frmDmr6he19l+qa/VdsjJNHyJA1hPTUTaCmRMSSMuKID693w5/aUcCVVarPucWLR9/Pd2Xf2KAnf5SWreyxqCKxcwZ1pErMayZKaZzix2AHfYQGL0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104356; c=relaxed/simple; bh=m18eL326a7UxUeaBlXTJIluWa9nCNdGX1vUvh9wtta0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZJSEsVD5HC2hDChjFrk7Wdk6uyc9snKEaUVDfXVF+HuOuUgdYJfQr0wBplsH3zCTWbl0Ww1Vx2OeDqGYYP8/HXFe6e6mGD8xQoAHRbsMFwqH10ei6Gdl5dYlWQO/ZCG9kTbqsljbeDyqURAnIAJDSh5O39QWSjmB70M4bq6P7m4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gC5RhkgC; 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="gC5RhkgC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8F895C2BCC4; Wed, 6 May 2026 21:52:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104355; bh=m18eL326a7UxUeaBlXTJIluWa9nCNdGX1vUvh9wtta0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gC5RhkgCZ4uSciap4Gdmes8vQkh6xOPhU3t/32U8eLWQV0RGuOamnXUIktg8PowjD Q5oqLDR5MoYtPGb6p5PjE+QQ9Xf1BT2se5I6G5X3cebQ3XJO5E6xqWGaN+DpVnY5PZ b8hIMezDszOO51yDROv1JwrY5jkEsuXNxIWBun/22m2CmbBRhNpU5UuMABVvRXb9x2 ggAbH+zey0RsUnuB04/VeO7nch0UcmmkztzlhLqksJRBhAwT2LfbQb8pXR8k3SWJlG lLOPIU9LA0e0cUQpi4muYxy4pEP9LGw5JgxDmn/in9FV9Dt13coh+PFIqidriBGxpp fWcAtJKX2rybA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 11/25] rust: platform: make Driver trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:47 +0200 Message-ID: <20260506215113.851360-12-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Make platform::Driver take a lifetime parameter 'bound that ties device resources to the binding scope. Internally, Adapter becomes Adapter with a bound for<'bound> F::Of<'bound>: Driver<'bound>; module_platform_driver! wraps the driver type in ForLt!() so drivers don't have to. Acked-by: Uwe Kleine-K=C3=B6nig Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/cpufreq/rcpufreq_dt.rs | 10 +-- drivers/gpu/drm/tyr/driver.rs | 10 +-- drivers/pwm/pwm_th1520.rs | 10 +-- rust/kernel/cpufreq.rs | 8 +-- rust/kernel/driver.rs | 9 ++- rust/kernel/io/mem.rs | 16 ++--- rust/kernel/platform.rs | 93 ++++++++++++++++++---------- samples/rust/rust_debugfs.rs | 10 +-- samples/rust/rust_driver_platform.rs | 12 ++-- samples/rust/rust_i2c_client.rs | 12 ++-- samples/rust/rust_soc.rs | 12 ++-- 11 files changed, 117 insertions(+), 85 deletions(-) diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs index f17bf64c22e2..f0ad2d115cf3 100644 --- a/drivers/cpufreq/rcpufreq_dt.rs +++ b/drivers/cpufreq/rcpufreq_dt.rs @@ -195,18 +195,18 @@ fn register_em(policy: &mut cpufreq::Policy) { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"operating-points-v2"), ())] ); =20 -impl platform::Driver for CPUFreqDTDriver { +impl<'bound> platform::Driver<'bound> for CPUFreqDTDriver { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); =20 fn probe( - pdev: &platform::Device, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { cpufreq::Registration::::new_foreign_owned(pdev.a= s_ref())?; Ok(Self {}) } diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 279710b36a10..96d83605e4b9 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -82,21 +82,21 @@ fn issue_soft_reset(dev: &Device, iomem: &Devres= ) -> Result { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [ (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) ] ); =20 -impl platform::Driver for TyrPlatformDriverData { +impl<'bound> platform::Driver<'bound> for TyrPlatformDriverData { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); =20 fn probe( - pdev: &platform::Device, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let core_clk =3D Clk::get(pdev.as_ref(), Some(c"core"))?; let stacks_clk =3D OptionalClk::get(pdev.as_ref(), Some(c"stacks")= )?; let coregroup_clk =3D OptionalClk::get(pdev.as_ref(), Some(c"coreg= roup"))?; diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index ddd44a5ce497..a7831b4ebe00 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -310,18 +310,18 @@ fn drop(self: Pin<&mut Self>) { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"thead,th1520-pwm"), ())] ); =20 -impl platform::Driver for Th1520PwmPlatformDriver { +impl<'bound> platform::Driver<'bound> for Th1520PwmPlatformDriver { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); =20 fn probe( - pdev: &platform::Device, - _id_info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev =3D pdev.as_ref(); let request =3D pdev.io_request_by_index(0).ok_or(ENODEV)?; =20 diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index d8d26870bea2..ac59cdfd633c 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -886,14 +886,14 @@ fn register_em(_policy: &mut Policy) { /// } /// } /// -/// impl platform::Driver for SampleDriver { +/// impl<'a> platform::Driver<'a> for SampleDriver { /// type IdInfo =3D (); /// const OF_ID_TABLE: Option> =3D None; /// /// fn probe( -/// pdev: &platform::Device, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// pdev: &'a platform::Device, +/// _id_info: Option<&'a Self::IdInfo>, +/// ) -> impl PinInit + 'a { /// cpufreq::Registration::::new_foreign_owned(pdev.= as_ref())?; /// Ok(Self {}) /// } diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index e462535f545d..7c5148772697 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -13,7 +13,7 @@ //! The main driver interface is defined by a bus specific driver trait. F= or instance: //! //! ```ignore -//! pub trait Driver: Send { +//! pub trait Driver<'bound>: Send { //! /// The type holding information about each device ID supported by= the driver. //! type IdInfo: 'static; //! @@ -24,10 +24,13 @@ //! const ACPI_ID_TABLE: Option> =3D None; //! //! /// Driver probe. -//! fn probe(dev: &Device, id_info: &Self::IdInfo) -> im= pl PinInit; +//! fn probe( +//! dev: &'bound Device, +//! id_info: &'bound Self::IdInfo, +//! ) -> impl PinInit + 'bound; //! //! /// Driver unbind (optional). -//! fn unbind(dev: &Device, this: Pin<&Self>) { +//! fn unbind(dev: &'bound Device, this: Pin<&'bound Sel= f>) { //! let _ =3D (dev, this); //! } //! } diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index 7dc78d547f7a..fd5292df5870 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -60,13 +60,13 @@ pub(crate) unsafe fn new(device: &'a Device, res= ource: &'a Resource) -> S /// }; /// struct SampleDriver; /// - /// impl platform::Driver for SampleDriver { + /// impl<'bound> platform::Driver<'bound> for SampleDriver { /// # type IdInfo =3D (); /// /// fn probe( - /// pdev: &platform::Device, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit { + /// pdev: &'bound platform::Device, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit + 'bound { /// let offset =3D 0; // Some offset. /// /// // If the size is known at compile time, use [`Self::iomap_s= ized`]. @@ -124,13 +124,13 @@ pub fn iomap_exclusive_sized( /// }; /// struct SampleDriver; /// - /// impl platform::Driver for SampleDriver { + /// impl<'bound> platform::Driver<'bound> for SampleDriver { /// # type IdInfo =3D (); /// /// fn probe( - /// pdev: &platform::Device, - /// info: Option<&Self::IdInfo>, - /// ) -> impl PinInit { + /// pdev: &'bound platform::Device, + /// info: Option<&'bound Self::IdInfo>, + /// ) -> impl PinInit + 'bound { /// let offset =3D 0; // Some offset. /// /// // Unlike [`Self::iomap_sized`], here the size of the memory= region diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index aec26307ae68..9959364429b5 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -44,33 +44,46 @@ }; =20 /// An adapter for the registration of platform drivers. -pub struct Adapter(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver= 's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_platform_driver!` +/// generates this automatically via `ForLt!()`. +pub struct Adapter(PhantomData); =20 // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored type of the driver's device private da= ta. // - `struct platform_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. -unsafe impl driver::DriverLayout for Adapter { +unsafe impl driver::DriverLayout for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType =3D bindings::platform_driver; - type DriverData =3D ForLt!(T); + type DriverData =3D F; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl driver::RegistrationOps for Adapter { +unsafe impl driver::RegistrationOps for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( pdrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { - let of_table =3D match T::OF_ID_TABLE { + let of_table =3D match as Driver<'static>>::OF_ID_= TABLE { Some(table) =3D> table.as_ptr(), None =3D> core::ptr::null(), }; =20 - let acpi_table =3D match T::ACPI_ID_TABLE { + let acpi_table =3D match as Driver<'static>>::ACPI= _ID_TABLE { Some(table) =3D> table.as_ptr(), None =3D> core::ptr::null(), }; @@ -94,19 +107,23 @@ unsafe fn unregister(pdrv: &Opaque) { } } =20 -impl Adapter { +impl Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> = kernel::ffi::c_int { // SAFETY: The platform bus only ever calls the probe callback wit= h a valid pointer to a // `struct platform_device`. // // INVARIANT: `pdev` is valid for the duration of `probe_callback(= )`. let pdev =3D unsafe { &*pdev.cast::>(= ) }; - let info =3D >::id_info(pdev.as_ref()); =20 from_result(|| { - let data =3D T::probe(pdev, info); + let info =3D >::id_info(pdev.as_re= f()); + let data =3D as Driver<'_>>::probe(pdev, info); =20 - pdev.as_ref().set_drvdata::(data)?; + pdev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -119,28 +136,34 @@ extern "C" fn remove_callback(pdev: *mut bindings::pl= atform_device) { let pdev =3D unsafe { &*pdev.cast::>(= ) }; =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called - // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_borrow::() = }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; =20 - T::unbind(pdev, data); + as Driver<'_>>::unbind(pdev, data); } } =20 -impl<'bound, T: Driver + 'static> driver::Adapter<'bound> for Adapter { - type IdInfo =3D T::IdInfo; +impl<'bound, F> driver::Adapter<'bound> for Adapter +where + F: ForLt + 'static, + for<'b> F::Of<'b>: Driver<'b>, +{ + type IdInfo =3D as Driver<'bound>>::IdInfo; =20 fn of_id_table() -> Option> { - T::OF_ID_TABLE + as Driver<'bound>>::OF_ID_TABLE } =20 fn acpi_id_table() -> Option> { - T::ACPI_ID_TABLE + as Driver<'bound>>::ACPI_ID_TABLE } } =20 /// Declares a kernel module that exposes a single platform driver. /// +/// The `type` field accepts a driver type, optionally with a lifetime pla= ceholder `'_` for +/// lifetime-parameterized drivers. The macro wraps it in [`ForLt!`] autom= atically. +/// /// # Examples /// /// ```ignore @@ -152,10 +175,16 @@ fn acpi_id_table() -> Option> { /// license: "GPL v2", /// } /// ``` +/// +/// [`ForLt!`]: macro@ForLt +/// [`ForLt`]: trait@ForLt #[macro_export] macro_rules! module_platform_driver { - ($($f:tt)*) =3D> { - $crate::module_driver!(, $crate::platform::Adapter, { $($f)*= }); + (type: $type:ty, $($rest:tt)*) =3D> { + $crate::module_driver!(, $crate::platform::Adapter, { + type: $crate::types::ForLt!($type), + $($rest)* + }); }; } =20 @@ -178,7 +207,7 @@ macro_rules! module_platform_driver { /// kernel::of_device_table!( /// OF_TABLE, /// MODULE_OF_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (of::DeviceId::new(c"test,device"), ()) /// ] @@ -187,26 +216,26 @@ macro_rules! module_platform_driver { /// kernel::acpi_device_table!( /// ACPI_TABLE, /// MODULE_ACPI_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (acpi::DeviceId::new(c"LNUXBEEF"), ()) /// ] /// ); /// -/// impl platform::Driver for MyDriver { +/// impl<'bound> platform::Driver<'bound> for MyDriver { /// type IdInfo =3D (); /// const OF_ID_TABLE: Option> =3D Some(&OF_= TABLE); /// const ACPI_ID_TABLE: Option> =3D Some(= &ACPI_TABLE); /// /// fn probe( -/// _pdev: &platform::Device, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// _pdev: &'bound platform::Device, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit + 'bound { /// Err(ENODEV) /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver<'bound>: Send { /// The type holding driver private data about each device id supporte= d by the driver. // TODO: Use associated_type_defaults once stabilized: // @@ -226,9 +255,9 @@ pub trait Driver: Send { /// Called when a new platform device is added or discovered. /// Implementers should attempt to initialize the device here. fn probe( - dev: &Device, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + dev: &'bound Device, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound; =20 /// Platform driver unbind. /// @@ -240,7 +269,7 @@ fn probe( /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + fn unbind(dev: &'bound Device, this: Pin<&'bound Self>) { let _ =3D (dev, this); } } diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 0963efe19f93..ca73c0ef4a79 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -111,19 +111,19 @@ fn from_str(s: &str) -> Result { kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - ::IdInfo, + >::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); =20 -impl platform::Driver for RustDebugFs { +impl<'bound> platform::Driver<'bound> for RustDebugFs { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D None; const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); =20 fn probe( - pdev: &platform::Device, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { RustDebugFs::new(pdev).pin_chain(|this| { this.counter.store(91, Relaxed); { diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_drive= r_platform.rs index f2229d176fb9..5b7037eb4b3f 100644 --- a/samples/rust/rust_driver_platform.rs +++ b/samples/rust/rust_driver_platform.rs @@ -88,26 +88,26 @@ struct SampleDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"test,rust-device"), Info(42))] ); =20 kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - ::IdInfo, + >::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), Info(0))] ); =20 -impl platform::Driver for SampleDriver { +impl<'bound> platform::Driver<'bound> for SampleDriver { type IdInfo =3D Info; const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); =20 fn probe( - pdev: &platform::Device, - info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev =3D pdev.as_ref(); =20 dev_dbg!(dev, "Probe Rust Platform driver sample.\n"); diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client= .rs index 8d2c12e535b0..e21595a4376e 100644 --- a/samples/rust/rust_i2c_client.rs +++ b/samples/rust/rust_i2c_client.rs @@ -88,14 +88,14 @@ struct SampleDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"test,rust-device"), ())] ); =20 kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - ::IdInfo, + >::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); =20 @@ -104,15 +104,15 @@ struct SampleDriver { const BOARD_INFO: i2c::I2cBoardInfo =3D i2c::I2cBoardInfo::new(c"rust_driver_i2c", SAMPLE_I2C_CLIENT_ADDR); =20 -impl platform::Driver for SampleDriver { +impl<'bound> platform::Driver<'bound> for SampleDriver { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); =20 fn probe( - pdev: &platform::Device, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { dev_info!( pdev.as_ref(), "Probe Rust I2C Client registration sample.\n" diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs index 8079c1c48416..356d093bc8dd 100644 --- a/samples/rust/rust_soc.rs +++ b/samples/rust/rust_soc.rs @@ -24,26 +24,26 @@ struct SampleSocDriver { kernel::of_device_table!( OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"test,rust-device"), ())] ); =20 kernel::acpi_device_table!( ACPI_TABLE, MODULE_ACPI_TABLE, - ::IdInfo, + >::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), ())] ); =20 -impl platform::Driver for SampleSocDriver { +impl<'bound> platform::Driver<'bound> for SampleSocDriver { type IdInfo =3D (); const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); =20 fn probe( - pdev: &platform::Device, - _info: Option<&Self::IdInfo>, - ) -> impl PinInit { + pdev: &'bound platform::Device, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { dev_dbg!(pdev, "Probe Rust SoC driver sample.\n"); =20 let pdev =3D pdev.into(); --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 A513E3B3C08; Wed, 6 May 2026 21:52: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=1778104362; cv=none; b=cllXCz4FdTPGq2YywzXHKR+BW9b20AVsZbtR241cjxs3eQPGXX6AlgtgEo0/En2L0CSaX2CrsDyBf2uvvNm2xjcR4jYYjywUiUlCaUwAO+VBCGxLrW7OTvbQTcZTcsHrqazl5um9sAZDGYeHqm8QIZfTiaa4rVKViiZ7bXPJEhw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104362; c=relaxed/simple; bh=MLfMM778T9pvISlajrqiOEZI+9A8Be7jGUlckLgNLCI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oPLMfiLOEJJlQ8MvvRMsGOUIo8KjSFPCs5xGsk836VsCvs+W3JEd5E9N3+I/L73uqsw5FDxz3ySdgojIcfkIasBxiTDAV7uu5n0wXuuAypgBaob9a/qWdRbkZfyXiB78c+5iqBQv+kL7FJaLoyUN7njfvRCwAYce2ex8CS485Pg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Vo1IzwE5; 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="Vo1IzwE5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48158C2BCC4; Wed, 6 May 2026 21:52:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104362; bh=MLfMM778T9pvISlajrqiOEZI+9A8Be7jGUlckLgNLCI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Vo1IzwE5/2GxiHxXpRlyCshyU6iNZnsYPIJM+gjuJ3uViELs5QB0bQcjIfaHX2eXz MWO6wowOyfU9nyHXw3XLeM3NODttIhANCADb7nD+29NZpeyIT0IPKhID6ip0zI87CE his2UON8NDTeyrU2MPOTMDKtTnlA+80MN9zgFkYS/j3Wm+j6bRNUvDmpCU6plV74hy GQpjVwi6m2pIr5KTtiVrBZ2aoKQMxd7jbEHsb229AfP56LJmA+V31Z5jfTzneDBo4b wKC48Iq3v7gghLFiapaZSRke/pU3yW8WiHrEMDOas62+aXeXyao5XwZJhqzBn+uf5w Y+FwafEMtfOhQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 12/25] rust: auxiliary: make Driver trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:48 +0200 Message-ID: <20260506215113.851360-13-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Make auxiliary::Driver take a lifetime parameter 'bound that ties device resources to the binding scope. Internally, Adapter becomes Adapter with a bound for<'bound> F::Of<'bound>: Driver<'bound>; module_auxiliary_driver! wraps the driver type in ForLt!() so drivers don't have to. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/drm/nova/driver.rs | 9 ++-- rust/kernel/auxiliary.rs | 60 ++++++++++++++++++--------- samples/rust/rust_driver_auxiliary.rs | 12 ++++-- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs index b1af0a099551..8e28ccad0575 100644 --- a/drivers/gpu/drm/nova/driver.rs +++ b/drivers/gpu/drm/nova/driver.rs @@ -42,18 +42,21 @@ pub(crate) struct NovaData { kernel::auxiliary_device_table!( AUX_TABLE, MODULE_AUX_TABLE, - ::IdInfo, + >::IdInfo, [( auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME), () )] ); =20 -impl auxiliary::Driver for NovaDriver { +impl<'bound> auxiliary::Driver<'bound> for NovaDriver { type IdInfo =3D (); const ID_TABLE: auxiliary::IdTable =3D &AUX_TABLE; =20 - fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl= PinInit { + fn probe( + adev: &'bound auxiliary::Device, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { let data =3D try_pin_init!(NovaData { adev: adev.into() }); =20 let drm =3D drm::Device::::new(adev.as_ref(), data)?; diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index e193ba5b7167..d2785a841380 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -38,22 +38,35 @@ }; =20 /// An adapter for the registration of auxiliary drivers. -pub struct Adapter(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver= 's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_auxiliary_driver!` +/// generates this automatically via `ForLt!()`. +pub struct Adapter(PhantomData); =20 // SAFETY: // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored type of the driver's device private da= ta. // - `struct auxiliary_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. -unsafe impl driver::DriverLayout for Adapter { +unsafe impl driver::DriverLayout for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType =3D bindings::auxiliary_driver; - type DriverData =3D ForLt!(T); + type DriverData =3D F; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl driver::RegistrationOps for Adapter { +unsafe impl driver::RegistrationOps for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( adrv: &Opaque, name: &'static CStr, @@ -64,7 +77,7 @@ unsafe fn register( (*adrv.get()).name =3D name.as_char_ptr(); (*adrv.get()).probe =3D Some(Self::probe_callback); (*adrv.get()).remove =3D Some(Self::remove_callback); - (*adrv.get()).id_table =3D T::ID_TABLE.as_ptr(); + (*adrv.get()).id_table =3D as Driver<'static>>= ::ID_TABLE.as_ptr(); } =20 // SAFETY: `adrv` is guaranteed to be a valid `DriverType`. @@ -79,7 +92,11 @@ unsafe fn unregister(adrv: &Opaque) { } } =20 -impl Adapter { +impl Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback( adev: *mut bindings::auxiliary_device, id: *const bindings::auxiliary_device_id, @@ -93,12 +110,12 @@ extern "C" fn probe_callback( // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `stru= ct auxiliary_device_id` // and does not add additional invariants, so it's safe to transmu= te. let id =3D unsafe { &*id.cast::() }; - let info =3D T::ID_TABLE.info(id.index()); =20 from_result(|| { - let data =3D T::probe(adev, info); + let info =3D as Driver<'_>>::ID_TABLE.info(id.index= ()); + let data =3D as Driver<'_>>::probe(adev, info); =20 - adev.as_ref().set_drvdata::(data)?; + adev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -111,19 +128,21 @@ extern "C" fn remove_callback(adev: *mut bindings::au= xiliary_device) { let adev =3D unsafe { &*adev.cast::>(= ) }; =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called - // and stored a `Pin>`. - let data =3D unsafe { adev.as_ref().drvdata_borrow::() = }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { adev.as_ref().drvdata_borrow::() }; =20 - T::unbind(adev, data); + as Driver<'_>>::unbind(adev, data); } } =20 /// Declares a kernel module that exposes a single auxiliary driver. #[macro_export] macro_rules! module_auxiliary_driver { - ($($f:tt)*) =3D> { - $crate::module_driver!(, $crate::auxiliary::Adapter, { $($f)= * }); + (type: $type:ty, $($rest:tt)*) =3D> { + $crate::module_driver!(, $crate::auxiliary::Adapter, { + type: $crate::types::ForLt!($type), + $($rest)* + }); }; } =20 @@ -195,7 +214,7 @@ macro_rules! auxiliary_device_table { /// The auxiliary driver trait. /// /// Drivers must implement this trait in order to get an auxiliary driver = registered. -pub trait Driver { +pub trait Driver<'bound>: Send { /// The type holding information about each device id supported by the= driver. /// /// TODO: Use associated_type_defaults once stabilized: @@ -209,7 +228,10 @@ pub trait Driver { /// Auxiliary driver probe. /// /// Called when an auxiliary device is matches a corresponding driver. - fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl P= inInit; + fn probe( + dev: &'bound Device, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound; =20 /// Auxiliary driver unbind. /// @@ -221,7 +243,7 @@ pub trait Driver { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. - fn unbind(dev: &Device, this: Pin<&Self>) { + fn unbind(dev: &'bound Device, this: Pin<&'bound Self>) { let _ =3D (dev, this); } } diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driv= er_auxiliary.rs index a1b42d30580e..6baeb1dde5da 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -26,16 +26,19 @@ kernel::auxiliary_device_table!( AUX_TABLE, MODULE_AUX_TABLE, - ::IdInfo, + >::IdInfo, [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())] ); =20 -impl auxiliary::Driver for AuxiliaryDriver { +impl<'bound> auxiliary::Driver<'bound> for AuxiliaryDriver { type IdInfo =3D (); =20 const ID_TABLE: auxiliary::IdTable =3D &AUX_TABLE; =20 - fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> impl= PinInit { + fn probe( + adev: &'bound auxiliary::Device, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { dev_info!( adev, "Probing auxiliary driver for auxiliary device with id=3D{}\n", @@ -123,7 +126,8 @@ struct SampleModule { #[allow(clippy::type_complexity)] _pci_driver: driver::Registration>, #[pin] - _aux_driver: driver::Registration>, + #[allow(clippy::type_complexity)] + _aux_driver: driver::Registration>, } =20 impl InPlaceModule for SampleModule { --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 9D6173B3C13; Wed, 6 May 2026 21:52: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=1778104369; cv=none; b=WJ+AeuN9M85cpk1Tzex496795iKTzgz9jqIF1iDE4B5r7MOm+uG0V57I6pNHNlz6JSxLcA94YUuC0/195r80OGFtJX9+YpIGDVKCcRSj86wj/XLHvEO5mgXqP6USdHcnAw3mWaF7DjIzmIqdcZpXTL1hx0vdOb1heukJwrhrlzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104369; c=relaxed/simple; bh=/QsI18VRrkWM/0er0Ht6IXGPiMe3T+8m/tPEwZGU5xU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hrP1pJ0iSOE94u2Md/kMkGtqOADZeFEjGpt2xBKXYc0UQbjkIhbjzKOswPSy8C363iWG78vpUG9SeTY2bqVf5h4mBQR08VQ/utp85pxQvBxlhMX0gveYQMtHyFol8oPcNrkZmWFmBYtPKI/vxm8/zBw1HuN49uRfwyERuvL8qCc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=WPSEuIOI; 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="WPSEuIOI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 02114C2BCC9; Wed, 6 May 2026 21:52:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104369; bh=/QsI18VRrkWM/0er0Ht6IXGPiMe3T+8m/tPEwZGU5xU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WPSEuIOIw5Yoi9UWFFIZ8cjMb6orSavyW4gfg3wKuUCRAGMGsmFoaXb3fTZAzW+jt 3lsol0H2mVDhm2Eu4TX214XN01cx4ec4PrmqKA/RinxBUibjudM3Y0T9i+n3kjWWLt mmR897JQkVb/hf3b33Ykuuf0NBUnfWko3v88bten+kfMjb1JjPgq39Kd73xPhQAfXs oHNTWxKJ7f3c2JkSthm9iW6H1nExAKzEfg6lvhr6U/g5CNBbq9Cx1dBF2vds2q3dVD qSfvaApH80HYC3QwZ4QjlkOEOXhu09g1OKTr/aCY2muXEDvPfHVrGixG1hUBEZlFlV u5AkHb5FrFfBw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 13/25] rust: auxiliary: generalize Registration over ForLt Date: Wed, 6 May 2026 23:50:49 +0200 Message-ID: <20260506215113.851360-14-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Generalize Registration to Registration and Device::registration_data() to return Pin<&F::Of<'_>>. The stored 'static lifetime is shortened to the borrow lifetime of &self via ForLt::cast_ref; ForLt's covariance guarantee makes this sound. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/driver.rs | 4 +- rust/kernel/auxiliary.rs | 67 +++++++++++++++++---------- samples/rust/rust_driver_auxiliary.rs | 7 +-- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index d0ccfbc8d0ea..ed154cd93fa8 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -21,6 +21,7 @@ }, Arc, }, + types::ForLt, }; =20 use crate::gpu::Gpu; @@ -32,7 +33,8 @@ pub(crate) struct NovaCore { #[pin] pub(crate) gpu: Gpu, - _reg: Devres>, + #[allow(clippy::type_complexity)] + _reg: Devres>, } =20 const BAR0_SIZE: usize =3D SZ_16M; diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index d2785a841380..cbfb32298fde 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -288,12 +288,16 @@ pub fn parent(&self) -> &device::Device { =20 /// Returns a pinned reference to the registration data set by the reg= istering (parent) driver. /// - /// Returns [`EINVAL`] if `T` does not match the type used by the pare= nt driver when calling + /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The r= eturned + /// reference has its lifetime shortened from `'static` to `&self`'s b= orrow lifetime via + /// [`ForLt::cast_ref`]. + /// + /// Returns [`EINVAL`] if `F` does not match the type used by the pare= nt driver when calling /// [`Registration::new()`]. /// /// Returns [`ENOENT`] if no registration data has been set, e.g. when= the device was /// registered by a C driver. - pub fn registration_data(&self) -> Result> { + pub fn registration_data(&self) -> Result>> { // SAFETY: By the type invariant, `self.as_raw()` is a valid `stru= ct auxiliary_device`. let ptr =3D unsafe { (*self.as_raw()).registration_data_rust }; if ptr.is_null() { @@ -306,18 +310,23 @@ pub fn registration_data(&self) -> Result= > { =20 // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `= Registration::new()`; // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, = so reading a `TypeId` - // at the start of the allocation is valid regardless of `T`. + // at the start of the allocation is valid regardless of `F`. let type_id =3D unsafe { ptr.cast::().read() }; - if type_id !=3D TypeId::of::() { + if type_id !=3D TypeId::of::>() { return Err(EINVAL); } =20 - // SAFETY: The `TypeId` check above confirms that the stored type = is `T`; `ptr` remains - // valid until `Registration::drop()` calls `from_foreign()`. - let wrapper =3D unsafe { Pin::>>::borrow(= ptr) }; + // SAFETY: The `TypeId` check above confirms that the stored type = matches + // `F::Of<'static>`; `ptr` remains valid until `Registration::drop= ()` calls + // `from_foreign()`. + let wrapper =3D unsafe { Pin::>>>::borrow(ptr) }; =20 // SAFETY: `data` is a structurally pinned field of `RegistrationD= ata`. - Ok(unsafe { wrapper.map_unchecked(|w| &w.data) }) + let pinned: Pin<&F::Of<'static>> =3D unsafe { wrapper.map_unchecke= d(|w| &w.data) }; + + // SAFETY: The data was pinned when stored; `cast_ref` only shorte= ns + // the lifetime, so the pinning guarantee is preserved. + Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) }) } } =20 @@ -406,43 +415,51 @@ struct RegistrationData { /// This type represents the registration of a [`struct auxiliary_device`]= . When its parent device /// is unbound, the corresponding auxiliary device will be unregistered fr= om the system. /// -/// The type parameter `T` is the type of the registration data owned by t= he registering (parent) -/// driver. It can be accessed by the auxiliary driver through -/// [`Device::registration_data()`]. +/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the reg= istration +/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](mac= ro@ForLt). +/// The data can be accessed by the auxiliary driver through [`Device::reg= istration_data()`]. /// /// # Invariants /// /// `self.adev` always holds a valid pointer to an initialized and registe= red /// [`struct auxiliary_device`] whose `registration_data_rust` field point= s to a -/// valid `Pin>>`. -pub struct Registration { +/// valid `Pin>>>`. +pub struct Registration { adev: NonNull, - _data: PhantomData, + _data: PhantomData, } =20 -impl Registration { +impl Registration +where + for<'a> F::Of<'a>: Send, +{ /// Create and register a new auxiliary device with the given registra= tion data. /// /// The `data` is owned by the registration and can be accessed throug= h the auxiliary device /// via [`Device::registration_data()`]. - pub fn new( - parent: &device::Device, + pub fn new<'bound, E>( + parent: &'bound device::Device, name: &CStr, id: u32, modname: &CStr, - data: impl PinInit, + data: impl PinInit, E>, ) -> Result> where Error: From, { let data =3D KBox::pin_init::( try_pin_init!(RegistrationData { - type_id: TypeId::of::(), + type_id: TypeId::of::>(), data <- data, }), GFP_KERNEL, )?; =20 + // SAFETY: Lifetimes are erased and do not affect layout, so Regis= trationData> + // and RegistrationData> have identical representat= ion. + let data: Pin>>> =3D + unsafe { core::mem::transmute(data) }; + let boxed: KBox> =3D KBox::zero= ed(GFP_KERNEL)?; let adev =3D boxed.get(); =20 @@ -472,7 +489,9 @@ pub fn new( if ret !=3D 0 { // SAFETY: `registration_data` was set above via `into_foreign= ()`. drop(unsafe { - Pin::>>::from_foreign((*adev).reg= istration_data_rust) + Pin::>>>::from_foreig= n( + (*adev).registration_data_rust, + ) }); =20 // SAFETY: `adev` is guaranteed to be a valid pointer to a @@ -495,7 +514,7 @@ pub fn new( } } =20 -impl Drop for Registration { +impl Drop for Registration { fn drop(&mut self) { // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` i= s a valid registered // `struct auxiliary_device`. @@ -503,7 +522,7 @@ fn drop(&mut self) { =20 // SAFETY: `registration_data` was set in `new()` via `into_foreig= n()`. drop(unsafe { - Pin::>>::from_foreign( + Pin::>>>::from_foreign( (*self.adev.as_ptr()).registration_data_rust, ) }); @@ -517,7 +536,7 @@ fn drop(&mut self) { } =20 // SAFETY: A `Registration` of a `struct auxiliary_device` can be released= from any thread. -unsafe impl Send for Registration {} +unsafe impl Send for Registration where for<'a> F::Of<'a>: Se= nd {} =20 // SAFETY: `Registration` does not expose any methods or fields that need = synchronization. -unsafe impl Sync for Registration {} +unsafe impl Sync for Registration where for<'a> F::Of<'a>: Se= nd {} diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driv= er_auxiliary.rs index 6baeb1dde5da..de44ba901967 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -55,9 +55,10 @@ struct Data { index: u32, } =20 +#[allow(clippy::type_complexity)] struct ParentDriver { - _reg0: Devres>, - _reg1: Devres>, + _reg0: Devres>, + _reg1: Devres>, } =20 kernel::pci_device_table!( @@ -100,7 +101,7 @@ fn connect(adev: &auxiliary::Device) -> Result { let dev =3D adev.parent(); let pdev: &pci::Device =3D dev.try_into()?; =20 - let data =3D adev.registration_data::()?; + let data =3D adev.registration_data::()?; =20 dev_info!( dev, --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 170553B47E6; Wed, 6 May 2026 21:52:56 +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=1778104376; cv=none; b=pjJ9CpbK1kZcU5EQxba0zbmIaG8MmyPtQ5AR7X7lowGe4cFphyvo8wKzMB/HUM9CqTZmMeLWQEWwpe7FuTd1x9aRrY4pJ2K/RDv0ObRO5Nt9ttAaw6pSAVrODMjiqv19YMJMo9VOvzendT/oiNa1v/efKKM/sR4LJ1d6Hh5G3Nk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104376; c=relaxed/simple; bh=B41qhnlWkuJRcEF+9/CBmB57mbW1o1f5mPWmr/KvZ70=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nOsfJz/ySz8G0fHxfFpebZBdwq74S5sPDwlQPZKK0RF4G4Rnx/vEJr1+k1ytoPhWyNClOKx7pRziG/bj2OnCgVtn1jqugoK5nY8LMB/yBVzYYbjvC//kwD/jM3WiDmowMPIIOQcvR1eF1U91R0tKQAJLcGKf9KmBC2SJedGwpjc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bkqig5py; 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="bkqig5py" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AFCD3C2BCB0; Wed, 6 May 2026 21:52:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104376; bh=B41qhnlWkuJRcEF+9/CBmB57mbW1o1f5mPWmr/KvZ70=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bkqig5pyQxtuaOepYFe1QL+l62PRar/O4TMqB/FY0i5jpOQ+iEKmnJ5xa7UZcZvzb MG7m/A6tvszZR8PzmaaCl0aq+g4Q/pjbqZRs7TLphD8jsuZAOgwrKxy8Gx+us694Ay sS6FJljHKJjzTXJQzwKU4NXdXz8FlcLWC72HzgPZNHL2VNL+52mbVUcCO84MmM3zUR XkQCK1wdyqO8o+HYrD+3cuOYeMSeZwlP1zvLuw0oSnzFTNf5FHGf5XEH2Sm4SJ6Neb fEHjIUVuHp60RdeRKAaJSR2cjPaKSuGgyJtJ/b3LEpqHbTuhT8Bd2nKpSxn6Qwbn1x wZz+IZpjVd8ow== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 14/25] samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration data Date: Wed, 6 May 2026 23:50:50 +0200 Message-ID: <20260506215113.851360-15-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Make the Data struct lifetime-parameterized, storing a reference to the parent pci::Device. This demonstrates that registration data can hold device resources tied to the parent driver's lifetime. In connect(), retrieve the parent PCI device from the registration data rather than casting through adev.parent(). Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- samples/rust/rust_driver_auxiliary.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driv= er_auxiliary.rs index de44ba901967..da445c4cc910 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -51,14 +51,15 @@ fn probe( } } =20 -struct Data { +struct Data<'bound> { index: u32, + parent: &'bound pci::Device, } =20 #[allow(clippy::type_complexity)] struct ParentDriver { - _reg0: Devres>, - _reg1: Devres>, + _reg0: Devres)>>, + _reg1: Devres)>>, } =20 kernel::pci_device_table!( @@ -83,14 +84,20 @@ fn probe( AUXILIARY_NAME, 0, MODULE_NAME, - Data { index: 0 }, + Data { + index: 0, + parent: pdev, + }, )?, _reg1: auxiliary::Registration::new( pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME, - Data { index: 1 }, + Data { + index: 1, + parent: pdev, + }, )?, }) } @@ -98,13 +105,11 @@ fn probe( =20 impl ParentDriver { fn connect(adev: &auxiliary::Device) -> Result { - let dev =3D adev.parent(); - let pdev: &pci::Device =3D dev.try_into()?; - - let data =3D adev.registration_data::()?; + let data =3D adev.registration_data::)>()?; + let pdev =3D data.parent; =20 dev_info!( - dev, + pdev, "Connect auxiliary {} with parent: VendorID=3D{}, DeviceID=3D{= :#x}\n", adev.id(), pdev.vendor_id(), @@ -112,7 +117,7 @@ fn connect(adev: &auxiliary::Device) -> Result { ); =20 dev_info!( - dev, + pdev, "Connected to auxiliary device with index {}.\n", data.index ); --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 384D23B47C1; Wed, 6 May 2026 21:53: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=1778104383; cv=none; b=uJhbQ+Jd6ZVMqniCjtAP6HpL57Hf4BeqAM3LSeN6AuFwqNPYy6oq8FVlBBtyvt2016XMwBQrJuXDbTZUh+lnUJ6hy3tkyGKMCWRKN1n1mdvZI9cT297KYmKGUCBsqaA6mJBoKCEHafYhhkmerdB/e2nvIGHXyOteOVdQY8bBwJU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104383; c=relaxed/simple; bh=8mVevI3VU2GFyXMCNKv15BqIJsRsEGfi7AurMq0Pxr0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gcWgGLfD08JsYVb/nOrEWsOAzLHfeGlU2Qtxs1gOPvzMSH5f5TH41UFNXEbWHngKpajxrdYc7djKGPpOtJMb+XZAKEvDTIpxvYFZmnA5wVFI92ZNMCe4pwLABFjwqqUbEZHXEAawhV+ZZo9FMsy/twwEJcaVmjNfLjGLBh4D4X8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g+oqCDre; 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="g+oqCDre" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67E64C2BCB2; Wed, 6 May 2026 21:52:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104382; bh=8mVevI3VU2GFyXMCNKv15BqIJsRsEGfi7AurMq0Pxr0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g+oqCDre+Cu2aiESBf7dxd8srf/hKwnBhb8x/s/wEh8NP8dZ4BaRC0dG8IbCwCMDq J/P/UVCB24zOMRTxxxmksShZo2ON84qYUecSU280qKanEf2PJKgjk3ptEKeXfRRLq3 lUaPsx2eJRT1QV125gLGiDeE28LE8HtTJ2db1++FRenLULLG4yicOXppqBi2rPGoNA dOj0NewM4+XhAu07xDKtfvZvVUQ0ZqlsBDEjw5iY2jOxv8uUvsABpQNbtLClwcQau0 iilhtyKooiFmgF9PSYMi9j2vt2V2o+7TsljfmAjDytkXXVK72Alh7gDv+LCndxUSXx LgnFMEvTLrpXQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 15/25] rust: usb: make Driver trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:51 +0200 Message-ID: <20260506215113.851360-16-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Make usb::Driver take a lifetime parameter 'bound that ties device resources to the binding scope. Internally, Adapter becomes Adapter with a bound for<'bound> F::Of<'bound>: Driver<'bound>; module_usb_driver! wraps the driver type in ForLt!() so drivers don't have to. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/usb.rs | 85 ++++++++++++++++++++------------- samples/rust/rust_driver_usb.rs | 14 +++--- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 442e456fd2d3..450be2b7c542 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -35,22 +35,35 @@ }; =20 /// An adapter for the registration of USB drivers. -pub struct Adapter(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver= 's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_usb_driver!` generates +/// this automatically via `ForLt!()`. +pub struct Adapter(PhantomData); =20 // SAFETY: // - `bindings::usb_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored type of the driver's device private da= ta. // - `struct usb_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. -unsafe impl driver::DriverLayout for Adapter { +unsafe impl driver::DriverLayout for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType =3D bindings::usb_driver; - type DriverData =3D ForLt!(T); + type DriverData =3D F; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl driver::RegistrationOps for Adapter { +unsafe impl driver::RegistrationOps for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( udrv: &Opaque, name: &'static CStr, @@ -61,7 +74,7 @@ unsafe fn register( (*udrv.get()).name =3D name.as_char_ptr(); (*udrv.get()).probe =3D Some(Self::probe_callback); (*udrv.get()).disconnect =3D Some(Self::disconnect_callback); - (*udrv.get()).id_table =3D T::ID_TABLE.as_ptr(); + (*udrv.get()).id_table =3D as Driver<'static>>= ::ID_TABLE.as_ptr(); } =20 // SAFETY: `udrv` is guaranteed to be a valid `DriverType`. @@ -76,7 +89,11 @@ unsafe fn unregister(udrv: &Opaque) { } } =20 -impl Adapter { +impl Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback( intf: *mut bindings::usb_interface, id: *const bindings::usb_device_id, @@ -87,16 +104,16 @@ extern "C" fn probe_callback( // INVARIANT: `intf` is valid for the duration of `probe_callback(= )`. let intf =3D unsafe { &*intf.cast::>() }; =20 - from_result(|| { - // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `= struct usb_device_id` and - // does not add additional invariants, so it's safe to transmu= te. - let id =3D unsafe { &*id.cast::() }; + // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `stru= ct usb_device_id` and + // does not add additional invariants, so it's safe to transmute. + let id =3D unsafe { &*id.cast::() }; =20 - let info =3D T::ID_TABLE.info(id.index()); - let data =3D T::probe(intf, id, info); + from_result(|| { + let info =3D as Driver<'_>>::ID_TABLE.info(id.index= ()); + let data =3D as Driver<'_>>::probe(intf, id, info); =20 let dev: &device::Device =3D intf.as_ref= (); - dev.set_drvdata::(data)?; + dev.set_drvdata::(data)?; Ok(0) }) } @@ -111,11 +128,10 @@ extern "C" fn disconnect_callback(intf: *mut bindings= ::usb_interface) { let dev: &device::Device =3D intf.as_ref(); =20 // SAFETY: `disconnect_callback` is only ever called after a succe= ssful call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called - // and stored a `Pin>`. - let data =3D unsafe { dev.drvdata_borrow::() }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { dev.drvdata_borrow::() }; =20 - T::disconnect(intf, data); + as Driver<'_>>::disconnect(intf, data); } } =20 @@ -281,29 +297,29 @@ macro_rules! usb_device_table { /// kernel::usb_device_table!( /// USB_TABLE, /// MODULE_USB_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (usb::DeviceId::from_id(0x1234, 0x5678), ()), /// (usb::DeviceId::from_id(0xabcd, 0xef01), ()), /// ] /// ); /// -/// impl usb::Driver for MyDriver { +/// impl<'bound> usb::Driver<'bound> for MyDriver { /// type IdInfo =3D (); /// const ID_TABLE: usb::IdTable =3D &USB_TABLE; /// /// fn probe( -/// _interface: &usb::Interface, -/// _id: &usb::DeviceId, -/// _info: &Self::IdInfo, -/// ) -> impl PinInit { +/// _interface: &'bound usb::Interface, +/// _id: &'bound usb::DeviceId, +/// _info: &'bound Self::IdInfo, +/// ) -> impl PinInit + 'bound { /// Err(ENODEV) /// } /// -/// fn disconnect(_interface: &usb::Interface, _data: Pin<&Self>= ) {} +/// fn disconnect(_interface: &'bound usb::Interface, _data: Pin= <&'bound Self>) {} /// } ///``` -pub trait Driver { +pub trait Driver<'bound> { /// The type holding information about each one of the device ids supp= orted by the driver. type IdInfo: 'static; =20 @@ -315,15 +331,15 @@ pub trait Driver { /// Called when a new USB interface is bound to this driver. /// Implementers should attempt to initialize the interface here. fn probe( - interface: &Interface, - id: &DeviceId, - id_info: &Self::IdInfo, - ) -> impl PinInit; + interface: &'bound Interface, + id: &'bound DeviceId, + id_info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound; =20 /// USB driver disconnect. /// /// Called when the USB interface is about to be unbound from this dri= ver. - fn disconnect(interface: &Interface, data: Pin<&Self>); + fn disconnect(interface: &'bound Interface, data: Pin<&'= bound Self>); } =20 /// A USB interface. @@ -486,7 +502,10 @@ unsafe impl Sync for Device {} /// ``` #[macro_export] macro_rules! module_usb_driver { - ($($f:tt)*) =3D> { - $crate::module_driver!(, $crate::usb::Adapter, { $($f)* }); + (type: $type:ty, $($rest:tt)*) =3D> { + $crate::module_driver!(, $crate::usb::Adapter, { + type: $crate::types::ForLt!($type), + $($rest)* + }); } } diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb= .rs index ab72e99e1274..271aaf415795 100644 --- a/samples/rust/rust_driver_usb.rs +++ b/samples/rust/rust_driver_usb.rs @@ -20,26 +20,26 @@ struct SampleDriver { kernel::usb_device_table!( USB_TABLE, MODULE_USB_TABLE, - ::IdInfo, + >::IdInfo, [(usb::DeviceId::from_id(0x1234, 0x5678), ()),] ); =20 -impl usb::Driver for SampleDriver { +impl<'bound> usb::Driver<'bound> for SampleDriver { type IdInfo =3D (); const ID_TABLE: usb::IdTable =3D &USB_TABLE; =20 fn probe( - intf: &usb::Interface, - _id: &usb::DeviceId, - _info: &Self::IdInfo, - ) -> impl PinInit { + intf: &'bound usb::Interface, + _id: &'bound usb::DeviceId, + _info: &'bound Self::IdInfo, + ) -> impl PinInit + 'bound { let dev: &device::Device =3D intf.as_ref(); dev_info!(dev, "Rust USB driver sample probed\n"); =20 Ok(Self { _intf: intf.into() }) } =20 - fn disconnect(intf: &usb::Interface, _data: Pin<&Self>) { + fn disconnect(intf: &'bound usb::Interface, _data: Pin<&'bound S= elf>) { let dev: &device::Device =3D intf.as_ref(); dev_info!(dev, "Rust USB driver sample disconnected\n"); } --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 BD4DD364052; Wed, 6 May 2026 21:53:09 +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=1778104389; cv=none; b=OWb2l9LV+wUNkMRC+DpXf80Mg0zckAo5oKMudxXjOjrQr5WUf0dKrH4M0u9XcNzaZI5vMyRkBM+N4UkVGryVW2xH7U2hk7YNzv1bmRNQyWMofdopSlbAsADNAeUiXDC+CYWDbzegIYIIcrnGWDHuSqtP16UipagxPEwlnrTkpg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104389; c=relaxed/simple; bh=2Eca7fHkT4mXNq9mfuLx9YKSfzIqR9YZSmP1nxSgjdA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mjBHawDZZXAl9khGWcPIJ+zoJff6yUo6+nMzMwxlnUiCXTqk21F55wyVo0wb8GYXphWITMpfA1S7fIAofGzub/+WDeGqB0PcO9MZ3LKNFlyTfpj3eswyGCLcH2JWe0r+zzXpvOXCMpdx7ZBDWLqFiMSOzZXfl61hb3e4+tyqH6s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=c/U0zFjp; 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="c/U0zFjp" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 462D1C2BCB0; Wed, 6 May 2026 21:53:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104389; bh=2Eca7fHkT4mXNq9mfuLx9YKSfzIqR9YZSmP1nxSgjdA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=c/U0zFjpQuVvANkGXt+f7jg269KYBiY/xfHKHTIewM7mkDjGNYR3IHIr4rK4JcYi8 zVWWsBoXPmH6Lm+sam+HZXdXYsv9bDX1c7dMP95A7/WZJn/MtzR40bHlvRnRM32pZZ yQFLWMlEp246a65CHpumtLy9U5mtImpj/BfrwCRueOWsnjzJgcS2agZp7ZgaWriWGx gb6Szlz7fl/zK9cwm9BqM6vs6xlSg1AcyFgXtfH8UAVp/mbcEktj+opfrbP9AlUM5k oKMVXXlywUGXhD9EhWb5qOYqGiAz+XuCl4j59eTU+PdUyfkWz1phKDyIRxou/UJCe/ qeyj4Hw8Xo3HQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 16/25] rust: i2c: make Driver trait lifetime-parameterized Date: Wed, 6 May 2026 23:50:52 +0200 Message-ID: <20260506215113.851360-17-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Make i2c::Driver take a lifetime parameter 'bound that ties device resources to the binding scope. Internally, Adapter becomes Adapter with a bound for<'bound> F::Of<'bound>: Driver<'bound>; module_i2c_driver! wraps the driver type in ForLt!() so drivers don't have to. Acked-by: Igor Korotin Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/i2c.rs | 119 +++++++++++++++++++------------- samples/rust/rust_driver_i2c.rs | 18 ++--- 2 files changed, 81 insertions(+), 56 deletions(-) diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 208c73aa3ce3..2216b49604b2 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -92,43 +92,58 @@ macro_rules! i2c_device_table { } =20 /// An adapter for the registration of I2C drivers. -pub struct Adapter(T); +/// +/// `F` is a [`ForLt`](trait@ForLt) type that maps lifetimes to the driver= 's device +/// private data type, i.e. `F::Of<'bound>` is the driver struct +/// parameterized by `'bound`. The macro `module_i2c_driver!` generates +/// this automatically via `ForLt!()`. +pub struct Adapter(PhantomData); =20 // SAFETY: // - `bindings::i2c_driver` is a C type declared as `repr(C)`. -// - `T` is the type of the driver's device private data. +// - `F::Of<'static>` is the stored type of the driver's device private da= ta. // - `struct i2c_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. -unsafe impl driver::DriverLayout for Adapter { +unsafe impl driver::DriverLayout for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ type DriverType =3D bindings::i2c_driver; - type DriverData =3D ForLt!(T); + type DriverData =3D F; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. -unsafe impl driver::RegistrationOps for Adapter { +unsafe impl driver::RegistrationOps for Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ unsafe fn register( idrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { build_assert!( - T::ACPI_ID_TABLE.is_some() || T::OF_ID_TABLE.is_some() || T::I= 2C_ID_TABLE.is_some(), + as Driver<'static>>::ACPI_ID_TABLE.is_some() + || as Driver<'static>>::OF_ID_TABLE.is_som= e() + || as Driver<'static>>::I2C_ID_TABLE.is_so= me(), "At least one of ACPI/OF/Legacy tables must be present when re= gistering an i2c driver" ); =20 - let i2c_table =3D match T::I2C_ID_TABLE { + let i2c_table =3D match as Driver<'static>>::I2C_I= D_TABLE { Some(table) =3D> table.as_ptr(), None =3D> core::ptr::null(), }; =20 - let of_table =3D match T::OF_ID_TABLE { + let of_table =3D match as Driver<'static>>::OF_ID_= TABLE { Some(table) =3D> table.as_ptr(), None =3D> core::ptr::null(), }; =20 - let acpi_table =3D match T::ACPI_ID_TABLE { + let acpi_table =3D match as Driver<'static>>::ACPI= _ID_TABLE { Some(table) =3D> table.as_ptr(), None =3D> core::ptr::null(), }; @@ -154,7 +169,11 @@ unsafe fn unregister(idrv: &Opaque) { } } =20 -impl Adapter { +impl Adapter +where + F: ForLt + 'static, + for<'bound> F::Of<'bound>: Driver<'bound>, +{ extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kerne= l::ffi::c_int { // SAFETY: The I2C bus only ever calls the probe callback with a v= alid pointer to a // `struct i2c_client`. @@ -162,13 +181,12 @@ extern "C" fn probe_callback(idev: *mut bindings::i2c= _client) -> kernel::ffi::c_ // INVARIANT: `idev` is valid for the duration of `probe_callback(= )`. let idev =3D unsafe { &*idev.cast::>() }; =20 - let info =3D Self::i2c_id_info(idev) - .or_else(|| >::id_info(idev.as_ref= ())); - from_result(|| { - let data =3D T::probe(idev, info); + let info =3D Self::i2c_id_info(idev) + .or_else(|| >::id_info(idev.as= _ref())); + let data =3D as Driver<'_>>::probe(idev, info); =20 - idev.as_ref().set_drvdata::(data)?; + idev.as_ref().set_drvdata::(data)?; Ok(0) }) } @@ -178,11 +196,10 @@ extern "C" fn remove_callback(idev: *mut bindings::i2= c_client) { let idev =3D unsafe { &*idev.cast::>() }; =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to - // `probe_callback`, hence it's guaranteed that `I2cClient::set_dr= vdata()` has been called - // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_borrow::() = }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; =20 - T::unbind(idev, data); + as Driver<'_>>::unbind(idev, data); } =20 extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { @@ -190,23 +207,24 @@ extern "C" fn shutdown_callback(idev: *mut bindings::= i2c_client) { let idev =3D unsafe { &*idev.cast::>() }; =20 // SAFETY: `shutdown_callback` is only ever called after a success= ful call to - // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called - // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_borrow::() = }; + // `probe_callback`, hence it's guaranteed that drvdata has been s= et. + let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; =20 - T::shutdown(idev, data); + as Driver<'_>>::shutdown(idev, data); } =20 /// The [`i2c::IdTable`] of the corresponding driver. - fn i2c_id_table() -> Option>= ::IdInfo>> { - T::I2C_ID_TABLE + fn i2c_id_table<'bound>() -> Option as Driver<'= bound>>::IdInfo>> { + as Driver<'bound>>::I2C_ID_TABLE } =20 /// Returns the driver's private data from the matching entry in the [= `i2c::IdTable`], if any. /// /// If this returns `None`, it means there is no match with an entry i= n the [`i2c::IdTable`]. - fn i2c_id_info(dev: &I2cClient) -> Option<&'static >::IdInfo> { - let table =3D Self::i2c_id_table()?; + fn i2c_id_info<'bound>( + dev: &I2cClient, + ) -> Option<&'bound as Driver<'bound>>::IdInfo> { + let table =3D Self::i2c_id_table::<'bound>()?; =20 // SAFETY: // - `table` has static lifetime, hence it's valid for reads @@ -225,15 +243,19 @@ fn i2c_id_info(dev: &I2cClient) -> Option<&'static driver::Adapter<'bound> for Adapter { - type IdInfo =3D T::IdInfo; +impl<'bound, F> driver::Adapter<'bound> for Adapter +where + F: ForLt + 'static, + F::Of<'bound>: Driver<'bound>, +{ + type IdInfo =3D as Driver<'bound>>::IdInfo; =20 fn of_id_table() -> Option> { - T::OF_ID_TABLE + as Driver<'bound>>::OF_ID_TABLE } =20 fn acpi_id_table() -> Option> { - T::ACPI_ID_TABLE + as Driver<'bound>>::ACPI_ID_TABLE } } =20 @@ -252,8 +274,11 @@ fn acpi_id_table() -> Option> { /// ``` #[macro_export] macro_rules! module_i2c_driver { - ($($f:tt)*) =3D> { - $crate::module_driver!(, $crate::i2c::Adapter, { $($f)* }); + (type: $type:ty, $($rest:tt)*) =3D> { + $crate::module_driver!(, $crate::i2c::Adapter, { + type: $crate::types::ForLt!($type), + $($rest)* + }); }; } =20 @@ -271,7 +296,7 @@ macro_rules! module_i2c_driver { /// kernel::acpi_device_table!( /// ACPI_TABLE, /// MODULE_ACPI_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (acpi::DeviceId::new(c"LNUXBEEF"), ()) /// ] @@ -280,7 +305,7 @@ macro_rules! module_i2c_driver { /// kernel::i2c_device_table!( /// I2C_TABLE, /// MODULE_I2C_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (i2c::DeviceId::new(c"rust_driver_i2c"), ()) /// ] @@ -289,30 +314,30 @@ macro_rules! module_i2c_driver { /// kernel::of_device_table!( /// OF_TABLE, /// MODULE_OF_TABLE, -/// ::IdInfo, +/// >::IdInfo, /// [ /// (of::DeviceId::new(c"test,device"), ()) /// ] /// ); /// -/// impl i2c::Driver for MyDriver { +/// impl<'bound> i2c::Driver<'bound> for MyDriver { /// type IdInfo =3D (); /// const I2C_ID_TABLE: Option> =3D Some(&I= 2C_TABLE); /// const OF_ID_TABLE: Option> =3D Some(&OF_= TABLE); /// const ACPI_ID_TABLE: Option> =3D Some(= &ACPI_TABLE); /// /// fn probe( -/// _idev: &i2c::I2cClient, -/// _id_info: Option<&Self::IdInfo>, -/// ) -> impl PinInit { +/// _idev: &'bound i2c::I2cClient, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit + 'bound { /// Err(ENODEV) /// } /// -/// fn shutdown(_idev: &i2c::I2cClient, this: Pin<&Self>) { +/// fn shutdown(_idev: &'bound i2c::I2cClient, _this: Pin<&'boun= d Self>) { /// } /// } ///``` -pub trait Driver: Send { +pub trait Driver<'bound>: Send { /// The type holding information about each device id supported by the= driver. // TODO: Use `associated_type_defaults` once stabilized: // @@ -335,9 +360,9 @@ pub trait Driver: Send { /// Called when a new i2c client is added or discovered. /// Implementers should attempt to initialize the client here. fn probe( - dev: &I2cClient, - id_info: Option<&Self::IdInfo>, - ) -> impl PinInit; + dev: &'bound I2cClient, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound; =20 /// I2C driver shutdown. /// @@ -350,7 +375,7 @@ fn probe( /// This callback is distinct from final resource cleanup, as the driv= er instance remains valid /// after it returns. Any deallocation or teardown of driver-owned res= ources should instead be /// handled in `Self::drop`. - fn shutdown(dev: &I2cClient, this: Pin<&Self>) { + fn shutdown(dev: &'bound I2cClient, this: Pin<&'bound Se= lf>) { let _ =3D (dev, this); } =20 @@ -364,7 +389,7 @@ fn shutdown(dev: &I2cClient, this: Pin<&S= elf>) { /// operations to gracefully tear down the device. /// /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. - fn unbind(dev: &I2cClient, this: Pin<&Self>) { + fn unbind(dev: &'bound I2cClient, this: Pin<&'bound Self= >) { let _ =3D (dev, this); } } diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c= .rs index 6be79f9e9fb5..042a18305817 100644 --- a/samples/rust/rust_driver_i2c.rs +++ b/samples/rust/rust_driver_i2c.rs @@ -15,25 +15,25 @@ kernel::acpi_device_table! { ACPI_TABLE, MODULE_ACPI_TABLE, - ::IdInfo, + >::IdInfo, [(acpi::DeviceId::new(c"LNUXBEEF"), 0)] } =20 kernel::i2c_device_table! { I2C_TABLE, MODULE_I2C_TABLE, - ::IdInfo, + >::IdInfo, [(i2c::DeviceId::new(c"rust_driver_i2c"), 0)] } =20 kernel::of_device_table! { OF_TABLE, MODULE_OF_TABLE, - ::IdInfo, + >::IdInfo, [(of::DeviceId::new(c"test,rust_driver_i2c"), 0)] } =20 -impl i2c::Driver for SampleDriver { +impl<'bound> i2c::Driver<'bound> for SampleDriver { type IdInfo =3D u32; =20 const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); @@ -41,9 +41,9 @@ impl i2c::Driver for SampleDriver { const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); =20 fn probe( - idev: &i2c::I2cClient, - info: Option<&Self::IdInfo>, - ) -> impl PinInit { + idev: &'bound i2c::I2cClient, + info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { let dev =3D idev.as_ref(); =20 dev_info!(dev, "Probe Rust I2C driver sample.\n"); @@ -55,11 +55,11 @@ fn probe( Ok(Self) } =20 - fn shutdown(idev: &i2c::I2cClient, _this: Pin<&Self>) { + fn shutdown(idev: &'bound i2c::I2cClient, _this: Pin<&'bound Sel= f>) { dev_info!(idev.as_ref(), "Shutdown Rust I2C driver sample.\n"); } =20 - fn unbind(idev: &i2c::I2cClient, _this: Pin<&Self>) { + fn unbind(idev: &'bound i2c::I2cClient, _this: Pin<&'bound Self>= ) { dev_info!(idev.as_ref(), "Unbind Rust I2C driver sample.\n"); } } --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 5932A364052; Wed, 6 May 2026 21:53:16 +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=1778104396; cv=none; b=SheBDaqtodw1fWa90EdEBK5muMOU7rLR9F/S+nAGwCs26q5VUiZa9ZKc1T0JHYS72qbTuEOdwxGftp5+yUz7oJ3Q5J/4e6VRvW82GmaGiffKO7DrcrJ+/ggkrSQ+OWsd3TTkpkf/S+57Xb8Er6+T+qt60GDwKU3PJH998ALidBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104396; c=relaxed/simple; bh=heY35TckZke+1W0qxIFdYfwKBHO6XvixKMHPpFriOG0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KC6nSMbVu6PSORVPiMK8zVkGtYmpeXcJYE7/mldNd5nuWCxXsEBKjWMpO52PUfG25hlrar4qh75D01yTq9ANNdfLAL6yms5N3GaoyMiLJAabIHubhNwseHrUV5BnJTz41rFPi1X+JC0HPHb5JFh+8GdJuw97iwqfXD/NzjLgr5Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d8vQCafJ; 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="d8vQCafJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F17D1C2BCB2; Wed, 6 May 2026 21:53:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104396; bh=heY35TckZke+1W0qxIFdYfwKBHO6XvixKMHPpFriOG0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=d8vQCafJGQjKD+nnxawV9t99PpADxI7dQk3LOhS3AVq2hIMg6lBjPSVRWpWpPOO+X uauLiJpqMkFD4kZgApZzNh0aONJd/DEo9Z8Lf02JKZ1dpj/dT5Ame3/P02H1C0jJzx HMXPbj/50HTS7HwOiG4HV44n84PcFvA0Bf9LEz6yPOs7sjyCjOZyH1ULxB2eTYs9kV i3JPZZAZNvhEIqiJLkJNGjgwJavpKvnmzr1/MnKi63WTEi/kJpzElHDfM41uUpySK5 PDYFpqZhzRX9syzM4dK0O5Lg3aIzbpwWYBpj2cPYlBNBwcMO/l7liXSev9/9A+nQ5e FOYtGGyxLBDqw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 17/25] rust: pci: make Bar lifetime-parameterized Date: Wed, 6 May 2026 23:50:53 +0200 Message-ID: <20260506215113.851360-18-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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 pci::Bar to pci::Bar<'bound, SIZE>, storing &'bound Device to tie the BAR mapping lifetime to the device. iomap_region_sized() now returns Result> directly instead of impl PinInit>, Error>. Add Bar::into_devres() to consume the bar and register it as a device-managed resource, returning Devres>. The lifetime is erased to 'static because Devres guarantees the bar does not actually outlive the device -- access is revoked on unbind. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/driver.rs | 7 ++-- rust/kernel/devres.rs | 2 +- rust/kernel/pci/io.rs | 68 +++++++++++++++++---------------- samples/rust/rust_driver_pci.rs | 5 ++- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index ed154cd93fa8..6ee2021ef56e 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -47,7 +47,7 @@ pub(crate) struct NovaCore { // DMA addresses. These systems should be quite rare. const GPU_DMA_BITS: u32 =3D 47; =20 -pub(crate) type Bar0 =3D pci::Bar; +pub(crate) type Bar0 =3D pci::Bar<'static, BAR0_SIZE>; =20 kernel::pci_device_table!( PCI_TABLE, @@ -93,8 +93,9 @@ fn probe( // other threads of execution. unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::())? }; =20 - let bar =3D Arc::pin_init( - pdev.iomap_region_sized::(0, c"nova-core/bar0"), + let bar =3D Arc::new( + pdev.iomap_region_sized::(0, c"nova-core/bar0")? + .into_devres()?, GFP_KERNEL, )?; =20 diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 9e5f93aed20c..ec63317665f4 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -304,7 +304,7 @@ pub fn device(&self) -> &Device { /// pci, // /// }; /// - /// fn from_core(dev: &pci::Device, devres: Devres= >) -> Result { + /// fn from_core(dev: &pci::Device, devres: Devres>) -> Result { /// let bar =3D devres.access(dev.as_ref())?; /// /// let _ =3D bar.read32(0x0); diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index ae78676c927f..5668394a155b 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -14,8 +14,7 @@ Mmio, MmioRaw, // }, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; use core::{ marker::PhantomData, @@ -78,15 +77,15 @@ impl ConfigSpaceKind for Extended { /// The generic parameter `S` indicates the maximum size of the configurat= ion space. /// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`]= for /// 4096-byte PCIe extended configuration space (default). -pub struct ConfigSpace<'a, S: ConfigSpaceKind =3D Extended> { - pub(crate) pdev: &'a Device, +pub struct ConfigSpace<'bound, S: ConfigSpaceKind =3D Extended> { + pub(crate) pdev: &'bound Device, _marker: PhantomData, } =20 /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn`= and `$write_fn`. macro_rules! impl_config_space_io_capable { ($ty:ty, $read_fn:ident, $write_fn:ident) =3D> { - impl<'a, S: ConfigSpaceKind> IoCapable<$ty> for ConfigSpace<'a, S>= { + impl<'bound, S: ConfigSpaceKind> IoCapable<$ty> for ConfigSpace<'b= ound, S> { unsafe fn io_read(&self, address: usize) -> $ty { let mut val: $ty =3D 0; =20 @@ -119,7 +118,7 @@ unsafe fn io_write(&self, value: $ty, address: usize) { impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_= word); impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config= _dword); =20 -impl<'a, S: ConfigSpaceKind> Io for ConfigSpace<'a, S> { +impl<'bound, S: ConfigSpaceKind> Io for ConfigSpace<'bound, S> { /// Returns the base address of the I/O region. It is always 0 for con= figuration space. #[inline] fn addr(&self) -> usize { @@ -133,7 +132,7 @@ fn maxsize(&self) -> usize { } } =20 -impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'a, S> { +impl<'bound, S: ConfigSpaceKind> IoKnownSize for ConfigSpace<'bound, S> { const MIN_SIZE: usize =3D S::SIZE; } =20 @@ -146,14 +145,14 @@ impl<'a, S: ConfigSpaceKind> IoKnownSize for ConfigSp= ace<'a, S> { /// /// `Bar` always holds an `IoRaw` instance that holds a valid pointer to t= he start of the I/O /// memory mapped PCI BAR and its size. -pub struct Bar { - pdev: ARef, +pub struct Bar<'bound, const SIZE: usize =3D 0> { + pdev: &'bound Device, io: MmioRaw, num: i32, } =20 -impl Bar { - pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result { +impl<'bound, const SIZE: usize> Bar<'bound, SIZE> { + pub(super) fn new(pdev: &'bound Device, num: u32, name:= &CStr) -> Result { let len =3D pdev.resource_len(num)?; if len =3D=3D 0 { return Err(ENOMEM); @@ -196,11 +195,7 @@ pub(super) fn new(pdev: &Device, num: u32, name: &CStr= ) -> Result { } }; =20 - Ok(Bar { - pdev: pdev.into(), - io, - num, - }) + Ok(Bar { pdev, io, num }) } =20 /// # Safety @@ -219,11 +214,24 @@ unsafe fn do_release(pdev: &Device, ioptr: usize, num= : i32) { =20 fn release(&self) { // SAFETY: The safety requirements are guaranteed by the type inva= riant of `self.pdev`. - unsafe { Self::do_release(&self.pdev, self.io.addr(), self.num) }; + unsafe { Self::do_release(self.pdev, self.io.addr(), self.num) }; + } + + /// Consume the `Bar` and register it as a device-managed resource. + /// + /// The returned `Devres>` can outlive the original= lifetime `'bound`. Access + /// to the BAR is revoked when the device is unbound. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the `Bar` does not + // actually outlive the device -- access is revoked and the resour= ce is released when the + // device is unbound. + let bar: Bar<'static, SIZE> =3D unsafe { core::mem::transmute(self= ) }; + let pdev =3D bar.pdev; + Devres::new(pdev.as_ref(), bar) } } =20 -impl Bar { +impl Bar<'_> { #[inline] pub(super) fn index_is_valid(index: u32) -> bool { // A `struct pci_dev` owns an array of resources with at most `PCI= _NUM_RESOURCES` entries. @@ -231,13 +239,13 @@ pub(super) fn index_is_valid(index: u32) -> bool { } } =20 -impl Drop for Bar { +impl Drop for Bar<'_, SIZE> { fn drop(&mut self) { self.release(); } } =20 -impl Deref for Bar { +impl Deref for Bar<'_, SIZE> { type Target =3D Mmio; =20 fn deref(&self) -> &Self::Target { @@ -249,20 +257,16 @@ fn deref(&self) -> &Self::Target { impl Device { /// Maps an entire PCI BAR after performing a region-request on it. I/= O operation bound checks /// can be performed on compile time for offsets (plus the requested t= ype size) < SIZE. - pub fn iomap_region_sized<'a, const SIZE: usize>( - &'a self, + pub fn iomap_region_sized<'bound, const SIZE: usize>( + &'bound self, bar: u32, - name: &'a CStr, - ) -> impl PinInit>, Error> + 'a { - Devres::new(self.as_ref(), Bar::::new(self, bar, name)) + name: &CStr, + ) -> Result> { + Bar::new(self, bar, name) } =20 /// Maps an entire PCI BAR after performing a region-request on it. - pub fn iomap_region<'a>( - &'a self, - bar: u32, - name: &'a CStr, - ) -> impl PinInit, Error> + 'a { + pub fn iomap_region<'bound>(&'bound self, bar: u32, name: &CStr) -> Re= sult> { self.iomap_region_sized::<0>(bar, name) } =20 @@ -282,7 +286,7 @@ pub fn cfg_size(&self) -> ConfigSpaceSize { } =20 /// Return an initialized normal (256-byte) config space object. - pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, Normal> { + pub fn config_space<'bound>(&'bound self) -> ConfigSpace<'bound, Norma= l> { ConfigSpace { pdev: self, _marker: PhantomData, @@ -290,7 +294,7 @@ pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, No= rmal> { } =20 /// Return an initialized extended (4096-byte) config space object. - pub fn config_space_extended<'a>(&'a self) -> Result> { + pub fn config_space_extended<'bound>(&'bound self) -> Result> { if self.cfg_size() !=3D ConfigSpaceSize::Extended { return Err(EINVAL); } diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index 794311691d1e..bbcb816456e0 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -45,7 +45,7 @@ mod regs { pub(super) const END: usize =3D 0x10; } =20 -type Bar0 =3D pci::Bar<{ regs::END }>; +type Bar0 =3D pci::Bar<'static, { regs::END }>; =20 #[derive(Copy, Clone, Debug)] struct TestIndex(u8); @@ -160,7 +160,8 @@ fn probe( pdev.set_master(); =20 Ok(try_pin_init!(Self { - bar <- pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_= driver_pci"), + bar: pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_dr= iver_pci")? + .into_devres()?, index: *info, _: { let bar =3D bar.access(pdev.as_ref())?; --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 1E1FD3B47F1; Wed, 6 May 2026 21:53:23 +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=1778104403; cv=none; b=mPnTkg3b0VmWH6yY1GMMlD01P5KeKIXUw4ixactvAOhTy9w4NbWmdE6+sQqomqafSKb+Qu+de/X9QvuIBglp01WHN6GwGvFUuYBrhq1AMKCBQUlK2VsmROiY9Bd0e1xqTfdq/wj3ivG+eTq/Zbd4t95/OalRBU/KMGGvZZNCjE0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104403; c=relaxed/simple; bh=qKv1bN6NFqhDPUVV2w2mU26ZHoUM5hP8VQLgogXE4sc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=fQLa7lUdmpZ4z3/fPZIRK0+4mITbFXLKPEB5cM5KQw4kHmAKiLhHuu2ewkhEaJnogym5fi8pxdQkyZ+Zy2G/dTey1jB5HxrsGKuaV6DLXh3yWlHdiPxBXvL3ZW5nI59aYai2yMGODPTH3giFSRfVKXGK7/ShPBRjQhaqF4C1Ehg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tx1m0cua; 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="tx1m0cua" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA3B9C2BCB2; Wed, 6 May 2026 21:53:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104403; bh=qKv1bN6NFqhDPUVV2w2mU26ZHoUM5hP8VQLgogXE4sc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tx1m0cuaaursPkcJv7cgw0iDjIfcpsLTHSyCvUtQteNtqM7YWr2DkQTwF73B8YQ9c FlF/h0RefD6oKqkkJf8CBBxy1twk55EpmD/8NXejAcpbfAma/aiefFVj943mO3RDFS FxxY4IzHaOsejMBKK3vxD18N/jLkRP7X3WcMldVtHcELHt2BzVtRmbzHWQs5tZ0tNe LeUwlB30CDd5EOEjr3jcXBi/Em6GmgArWaUaYuSqk1iaILBlhrFcfvi2oHAXuYojB6 ykcnXQ+bvYyj68YMx29GWRXxQI7PW4gPs0AmFABqR3/gBKBROEwLBISiuHAR3fThsb dnoSFUCYP5Dow== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 18/25] rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized Date: Wed, 6 May 2026 23:50:54 +0200 Message-ID: <20260506215113.851360-19-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add a lifetime parameter to IoMem<'bound, SIZE> and ExclusiveIoMem<'bound, SIZE>, storing a &'bound Device reference to tie the mapping to the device's lifetime. This mirrors the pci::Bar<'bound, SIZE> design and enables drivers to hold I/O memory mappings directly in their HRT private data, tied to the device lifetime. IoRequest::iomap_* methods now return the mapping directly instead of wrapping it in Devres. Callers that need device-managed revocation can call the new into_devres() method. Acked-by: Uwe Kleine-K=C3=B6nig Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/drm/tyr/driver.rs | 4 +- drivers/pwm/pwm_th1520.rs | 4 +- rust/kernel/io/mem.rs | 115 +++++++++++++++++----------------- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 96d83605e4b9..295a627de2b2 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -37,7 +37,7 @@ regs, // }; =20 -pub(crate) type IoMem =3D kernel::io::mem::IoMem; +pub(crate) type IoMem =3D kernel::io::mem::IoMem<'static, SZ_2M>; =20 pub(crate) struct TyrDrmDriver; =20 @@ -109,7 +109,7 @@ fn probe( let sram_regulator =3D Regulator::::get(pdev.a= s_ref(), c"sram")?; =20 let request =3D pdev.io_request_by_index(0).ok_or(ENODEV)?; - let iomem =3D Arc::pin_init(request.iomap_sized::(), GFP_KE= RNEL)?; + let iomem =3D Arc::new(request.iomap_sized::()?.into_devres= ()?, GFP_KERNEL)?; =20 issue_soft_reset(pdev.as_ref(), &iomem)?; gpu::l2_power_on(pdev.as_ref(), &iomem)?; diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs index a7831b4ebe00..3deb39d8e0fc 100644 --- a/drivers/pwm/pwm_th1520.rs +++ b/drivers/pwm/pwm_th1520.rs @@ -92,7 +92,7 @@ struct Th1520WfHw { #[pin_data(PinnedDrop)] struct Th1520PwmDriverData { #[pin] - iomem: devres::Devres>, + iomem: devres::Devres>, clk: Clk, } =20 @@ -351,7 +351,7 @@ fn probe( dev, TH1520_MAX_PWM_NUM, try_pin_init!(Th1520PwmDriverData { - iomem <- request.iomap_sized::(), + iomem <- request.iomap_sized::()?.int= o_devres(), clk <- clk, }), )?; diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs index fd5292df5870..a4cb12ee70d3 100644 --- a/rust/kernel/io/mem.rs +++ b/rust/kernel/io/mem.rs @@ -23,19 +23,19 @@ }; =20 /// An IO request for a specific device and resource. -pub struct IoRequest<'a> { - device: &'a Device, - resource: &'a Resource, +pub struct IoRequest<'bound> { + device: &'bound Device, + resource: &'bound Resource, } =20 -impl<'a> IoRequest<'a> { +impl<'bound> IoRequest<'bound> { /// Creates a new [`IoRequest`] instance. /// /// # Safety /// /// Callers must ensure that `resource` is valid for `device` during t= he - /// lifetime `'a`. - pub(crate) unsafe fn new(device: &'a Device, resource: &'a Reso= urce) -> Self { + /// lifetime `'bound`. + pub(crate) unsafe fn new(device: &'bound Device, resource: &'bo= und Resource) -> Self { IoRequest { device, resource } } =20 @@ -73,22 +73,19 @@ pub(crate) unsafe fn new(device: &'a Device, res= ource: &'a Resource) -> S /// // /// // No runtime checks will apply when reading and writing. /// let request =3D pdev.io_request_by_index(0).ok_or(ENODEV)?; - /// let iomem =3D request.iomap_sized::<42>(); - /// let iomem =3D KBox::pin_init(iomem, GFP_KERNEL)?; - /// - /// let io =3D iomem.access(pdev.as_ref())?; + /// let iomem =3D request.iomap_sized::<42>()?; /// /// // Read and write a 32-bit value at `offset`. - /// let data =3D io.read32(offset); + /// let data =3D iomem.read32(offset); /// - /// io.write32(data, offset); + /// iomem.write32(data, offset); /// /// # Ok(SampleDriver) /// } /// } /// ``` - pub fn iomap_sized(self) -> impl PinInit>, Error> + 'a { - IoMem::new(self) + pub fn iomap_sized(self) -> Result> { + IoMem::ioremap(self.device, self.resource) } =20 /// Same as [`Self::iomap_sized`] but with exclusive access to the @@ -97,10 +94,8 @@ pub fn iomap_sized(self) -> impl PinI= nit>, /// This uses the [`ioremap()`] C API. /// /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#g= etting-access-to-the-device - pub fn iomap_exclusive_sized( - self, - ) -> impl PinInit>, Error> + 'a { - ExclusiveIoMem::new(self) + pub fn iomap_exclusive_sized(self) -> Result> { + ExclusiveIoMem::ioremap(self.device, self.resource) } =20 /// Maps an [`IoRequest`] where the size is not known at compile time, @@ -138,27 +133,24 @@ pub fn iomap_exclusive_sized( /// // family of functions should be used, leading to runtime ch= ecks on every /// // access. /// let request =3D pdev.io_request_by_index(0).ok_or(ENODEV)?; - /// let iomem =3D request.iomap(); - /// let iomem =3D KBox::pin_init(iomem, GFP_KERNEL)?; - /// - /// let io =3D iomem.access(pdev.as_ref())?; + /// let iomem =3D request.iomap()?; /// - /// let data =3D io.try_read32(offset)?; + /// let data =3D iomem.try_read32(offset)?; /// - /// io.try_write32(data, offset)?; + /// iomem.try_write32(data, offset)?; /// /// # Ok(SampleDriver) /// } /// } /// ``` - pub fn iomap(self) -> impl PinInit>, Error> + 'a { - Self::iomap_sized::<0>(self) + pub fn iomap(self) -> Result> { + self.iomap_sized::<0>() } =20 /// Same as [`Self::iomap`] but with exclusive access to the underlying /// region. - pub fn iomap_exclusive(self) -> impl PinInit>= , Error> + 'a { - Self::iomap_exclusive_sized::<0>(self) + pub fn iomap_exclusive(self) -> Result> { + self.iomap_exclusive_sized::<0>() } } =20 @@ -167,9 +159,9 @@ pub fn iomap_exclusive(self) -> impl PinInit>, Error> + /// # Invariants /// /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. -pub struct ExclusiveIoMem { +pub struct ExclusiveIoMem<'bound, const SIZE: usize> { /// The underlying `IoMem` instance. - iomem: IoMem, + iomem: IoMem<'bound, SIZE>, =20 /// The region abstraction. This represents exclusive access to the /// range represented by the underlying `iomem`. @@ -178,9 +170,9 @@ pub struct ExclusiveIoMem { _region: Region, } =20 -impl ExclusiveIoMem { +impl<'bound, const SIZE: usize> ExclusiveIoMem<'bound, SIZE> { /// Creates a new `ExclusiveIoMem` instance. - fn ioremap(resource: &Resource) -> Result { + fn ioremap(dev: &'bound Device, resource: &Resource) -> Result<= Self> { let start =3D resource.start(); let size =3D resource.size(); let name =3D resource.name().unwrap_or_default(); @@ -194,26 +186,29 @@ fn ioremap(resource: &Resource) -> Result { ) .ok_or(EBUSY)?; =20 - let iomem =3D IoMem::ioremap(resource)?; + let iomem =3D IoMem::ioremap(dev, resource)?; =20 - let iomem =3D ExclusiveIoMem { + Ok(ExclusiveIoMem { iomem, _region: region, - }; - - Ok(iomem) + }) } =20 - /// Creates a new `ExclusiveIoMem` instance from a previously acquired= [`IoRequest`]. - pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit= , Error> + 'a { - let dev =3D io_request.device; - let res =3D io_request.resource; - - Devres::new(dev, Self::ioremap(res)) + /// Consume the `ExclusiveIoMem` and register it as a device-managed r= esource. + /// + /// The returned `Devres>` can outlive t= he original lifetime + /// `'bound`. Access to the I/O memory is revoked when the device is u= nbound. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the + // `ExclusiveIoMem` does not actually outlive the device -- access= is revoked and the + // resource is released when the device is unbound. + let iomem: ExclusiveIoMem<'static, SIZE> =3D unsafe { core::mem::t= ransmute(self) }; + let dev =3D iomem.iomem.dev; + Devres::new(dev, iomem) } } =20 -impl Deref for ExclusiveIoMem { +impl Deref for ExclusiveIoMem<'_, SIZE> { type Target =3D Mmio; =20 fn deref(&self) -> &Self::Target { @@ -230,12 +225,13 @@ fn deref(&self) -> &Self::Target { /// /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid poin= ter to the /// start of the I/O memory mapped region. -pub struct IoMem { +pub struct IoMem<'bound, const SIZE: usize =3D 0> { + dev: &'bound Device, io: MmioRaw, } =20 -impl IoMem { - fn ioremap(resource: &Resource) -> Result { +impl<'bound, const SIZE: usize> IoMem<'bound, SIZE> { + fn ioremap(dev: &'bound Device, resource: &Resource) -> Result<= Self> { // Note: Some ioremap() implementations use types that depend on t= he CPU // word width rather than the bus address width. // @@ -267,28 +263,33 @@ fn ioremap(resource: &Resource) -> Result { } =20 let io =3D MmioRaw::new(addr as usize, size)?; - let io =3D IoMem { io }; =20 - Ok(io) + Ok(IoMem { dev, io }) } =20 - /// Creates a new `IoMem` instance from a previously acquired [`IoRequ= est`]. - pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit= , Error> + 'a { - let dev =3D io_request.device; - let res =3D io_request.resource; - - Devres::new(dev, Self::ioremap(res)) + /// Consume the `IoMem` and register it as a device-managed resource. + /// + /// The returned `Devres>` can outlive the origin= al + /// lifetime `'bound`. Access to the I/O memory is revoked when the de= vice + /// is unbound. + pub fn into_devres(self) -> Result>> { + // SAFETY: Casting to `'static` is sound because `Devres` guarante= es the `IoMem` does not + // actually outlive the device -- access is revoked and the resour= ce is released when the + // device is unbound. + let iomem: IoMem<'static, SIZE> =3D unsafe { core::mem::transmute(= self) }; + let dev =3D iomem.dev; + Devres::new(dev, iomem) } } =20 -impl Drop for IoMem { +impl Drop for IoMem<'_, SIZE> { fn drop(&mut self) { // SAFETY: Safe as by the invariant of `Io`. unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } } } =20 -impl Deref for IoMem { +impl Deref for IoMem<'_, SIZE> { type Target =3D Mmio; =20 fn deref(&self) -> &Self::Target { --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 11AAB3B47F1; Wed, 6 May 2026 21:53:29 +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=1778104410; cv=none; b=taDG0Hvthb1p4+HX0YNtAVLUV8eCw+CAR4hr9whFzg8RNb4W9cJfThQYpwkCwRoKzDfBu8+UVFVKSOogoWmoWBgf5P95+q6/y3HHGcpXsoEca9G/Cm7N8syNgocjvZYdw/JXxLHUUqhfHQw9z+z5fHuSdgqZohZbAefvMrxQyrQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104410; c=relaxed/simple; bh=eNzpTvhmzibrNZ7+pOvewsfEGIExrdgY3tVgUF7aVt8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a0ZMaPZbR/AVJteWclKBbpirQeLO8YygIN/K+hNuvtH1j5hYiYonNSRFTo3aT77pcfP4p8XvQJKYu4agYbb2NzA6Rv7btujH4O6JhC7rcEBkb0mawQvh4sUW+8brGymiuDbLLLKtUvPMhshwd+guXKtmr8vK8FCTzqAHhx9h9zs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jNmvh8hJ; 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="jNmvh8hJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 651ECC2BCF5; Wed, 6 May 2026 21:53:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104409; bh=eNzpTvhmzibrNZ7+pOvewsfEGIExrdgY3tVgUF7aVt8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jNmvh8hJd5VlZAfnTNiW15wW4oU4VlOju5HNc1H30/6+ngs78wFHVCXuvg0uftl3Q tWv9P70WoJ4VPB4OPRe0KOjdk3mkzHbLkYnsF+ML3cpz7T79ZMQVl/3oYHPJ9sYh/c //mrsPGVehfUfqB7Z4eAejw1IvzY0nkA84AeHj0gSk46PdtaycobJUoBq9B8jSNOhN ainGZY8s0C9ZcVOm95b0SDMchtikZMoGrM4w3i9WFPnlSjFf9gOJdKd3AzjO3B81wp G6GFUXQSBlICG4nPULdgnvtBFTurNO3YrpTtyf5PvolaLZeDyuRVR9zw9j313quem3 Nq87CLxxFtp2A== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 19/25] samples: rust: rust_driver_pci: use HRT lifetime for Bar Date: Wed, 6 May 2026 23:50:55 +0200 Message-ID: <20260506215113.851360-20-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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 the sample driver to SampleDriver<'bound>, taking advantage of the lifetime-parameterized Driver trait. The driver struct holds &'bound pci::Device directly instead of ARef, and pci::Bar<'bound> directly instead of Devres. This removes PinnedDrop, pin_init_scope, and runtime revocation checks on BAR access. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- samples/rust/rust_driver_pci.rs | 89 +++++++++++++++------------------ 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci= .rs index bbcb816456e0..a7b7e580685c 100644 --- a/samples/rust/rust_driver_pci.rs +++ b/samples/rust/rust_driver_pci.rs @@ -9,7 +9,6 @@ Bound, Core, // }, - devres::Devres, io::{ register, register::Array, @@ -17,8 +16,7 @@ }, num::Bounded, pci, - prelude::*, - sync::aref::ARef, // + prelude::*, // }; =20 mod regs { @@ -45,7 +43,7 @@ mod regs { pub(super) const END: usize =3D 0x10; } =20 -type Bar0 =3D pci::Bar<'static, { regs::END }>; +type Bar0<'bound> =3D pci::Bar<'bound, { regs::END }>; =20 #[derive(Copy, Clone, Debug)] struct TestIndex(u8); @@ -66,26 +64,24 @@ impl TestIndex { const NO_EVENTFD: Self =3D Self(0); } =20 -#[pin_data(PinnedDrop)] -struct SampleDriver { - pdev: ARef, - #[pin] - bar: Devres, +struct SampleDriver<'bound> { + pdev: &'bound pci::Device, + bar: Bar0<'bound>, index: TestIndex, } =20 kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - >::IdInfo, + as pci::Driver<'_>>::IdInfo, [( pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), TestIndex::NO_EVENTFD )] ); =20 -impl SampleDriver { - fn testdev(index: &TestIndex, bar: &Bar0) -> Result { +impl SampleDriver<'_> { + fn testdev(index: &TestIndex, bar: &Bar0<'_>) -> Result { // Select the test. bar.write_reg(regs::TEST::zeroed().with_index(*index)); =20 @@ -138,7 +134,7 @@ fn config_space(pdev: &pci::Device) { } } =20 -impl<'bound> pci::Driver<'bound> for SampleDriver { +impl<'bound> pci::Driver<'bound> for SampleDriver<'bound> { type IdInfo =3D TestIndex; =20 const ID_TABLE: pci::IdTable =3D &PCI_TABLE; @@ -147,54 +143,47 @@ fn probe( pdev: &'bound pci::Device, info: &'bound Self::IdInfo, ) -> impl PinInit + 'bound { - pin_init::pin_init_scope(move || { - let vendor =3D pdev.vendor_id(); - dev_dbg!( - pdev, - "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", - vendor, - pdev.device_id() - ); - - pdev.enable_device_mem()?; - pdev.set_master(); - - Ok(try_pin_init!(Self { - bar: pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_dr= iver_pci")? - .into_devres()?, - index: *info, - _: { - let bar =3D bar.access(pdev.as_ref())?; - - dev_info!( - pdev, - "pci-testdev data-match count: {}\n", - Self::testdev(info, bar)? - ); - Self::config_space(pdev); - }, - pdev: pdev.into(), - })) + let vendor =3D pdev.vendor_id(); + dev_dbg!( + pdev, + "Probe Rust PCI driver sample (PCI ID: {}, 0x{:x}).\n", + vendor, + pdev.device_id() + ); + + pdev.enable_device_mem()?; + pdev.set_master(); + + let bar =3D pdev.iomap_region_sized::<{ regs::END }>(0, c"rust_dri= ver_pci")?; + + dev_info!( + pdev, + "pci-testdev data-match count: {}\n", + Self::testdev(info, &bar)? + ); + Self::config_space(pdev); + + Ok(Self { + pdev, + bar, + index: *info, }) } =20 - fn unbind(pdev: &'bound pci::Device, this: Pin<&'bound Self>) { - if let Ok(bar) =3D this.bar.access(pdev.as_ref()) { - // Reset pci-testdev by writing a new test index. - bar.write_reg(regs::TEST::zeroed().with_index(this.index)); - } + fn unbind(_pdev: &'bound pci::Device, this: Pin<&'bound Self>) { + this.bar + .write_reg(regs::TEST::zeroed().with_index(this.index)); } } =20 -#[pinned_drop] -impl PinnedDrop for SampleDriver { - fn drop(self: Pin<&mut Self>) { +impl Drop for SampleDriver<'_> { + fn drop(&mut self) { dev_dbg!(self.pdev, "Remove Rust PCI driver sample.\n"); } } =20 kernel::module_pci_driver! { - type: SampleDriver, + type: SampleDriver<'_>, name: "rust_driver_pci", authors: ["Danilo Krummrich"], description: "Rust PCI driver", --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 C3AD43B47F1; Wed, 6 May 2026 21:53:36 +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=1778104416; cv=none; b=ChTZFURM2JIlRCO1pV5/DSkHUVOknvShRsKNE8L5mGLpbgOn/22Pki3giBWUC4CjVsnBuo8JIQJuA1ksUc9rxR3oxIHPtmF54UfD85YL7R3N9JxpAUdAwCAwOi69GsYlogwRlIcmtlPGQo3YhxVQmsQ1VtdUk9NiWSMvel6Cwp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104416; c=relaxed/simple; bh=2HGyxkck0VbZoE2/KRDlqTHdsM1TmFjEbVBOzJ/9bgs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iNgB2xyEyHRLQASsHL/mK9UDAU7mg9/AGmXsWja31NUp0c/Vmo1ResyrQt4WXHwT9INNcfOOJP8VKVjtUW4THKWGAR+g8Nzjh5GqcDrGQlnLcOv/D9WUzQUN/ebXAjEOf7UF5U3ol+3ukYqZEooU+WsgSk3dAnICqbEjdeo376s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ax4Q4Fn7; 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="ax4Q4Fn7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 22299C2BCB0; Wed, 6 May 2026 21:53:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104416; bh=2HGyxkck0VbZoE2/KRDlqTHdsM1TmFjEbVBOzJ/9bgs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ax4Q4Fn7rRavxAuSd0FPz42OlWdpAnnXo3Ds1KKx1FynV2Dggd0U5mq68CPqw3dvP c5OMEGA+qr0VYKU3a2Z/jXc6MIjOEHr1qY3N4cG/MMFCAHSKyKKCYNGPC/3HJjNhxD DQDgDIvm1oxPh2nNyYRDH+hDGXz9nHF4w7uSjbZicgcJrgxOE9z8nEiXnlib5zAj/W njQk73gu1AxaH3GgwuzOj32DV0dadGjIscd5z+QSaW6kJLA8gdlyZbMxa/9dM3vgu3 qFK8htCrBA8MhXh+JyMteO21sz/lEgCyzmsb9V9CN997dmBp/A6k9hg1aK/sFg2odP mXo4iu5Qm4FAw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 20/25] rust: driver-core: rename 'a lifetime to 'bound Date: Wed, 6 May 2026 23:50:56 +0200 Message-ID: <20260506215113.851360-21-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Rename the generic lifetime parameter from 'a to 'bound in pci, platform, i2c and devres. This makes it explicit that the lifetime represents the device binding scope, consistent with the convention established by the HRT series. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- rust/kernel/devres.rs | 14 +++++++++----- rust/kernel/i2c.rs | 6 +++--- rust/kernel/pci/irq.rs | 38 +++++++++++++++++++------------------- rust/kernel/platform.rs | 18 +++++++++--------- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index ec63317665f4..58efe80474bd 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -280,10 +280,11 @@ pub fn device(&self) -> &Device { &self.dev } =20 - /// Obtain `&'a T`, bypassing the [`Revocable`]. + /// Obtain `&'bound T`, bypassing the [`Revocable`]. /// - /// This method allows to directly obtain a `&'a T`, bypassing the [`R= evocable`], by presenting - /// a `&'a Device` of the same [`Device`] this [`Devres`] insta= nce has been created with. + /// This method allows to directly obtain a `&'bound T`, bypassing the + /// [`Revocable`], by presenting a `&'bound Device` of the same + /// [`Device`] this [`Devres`] instance has been created with. /// /// # Errors /// @@ -316,7 +317,7 @@ pub fn device(&self) -> &Device { /// Ok(()) /// } /// ``` - pub fn access<'a>(&'a self, dev: &'a Device) -> Result<&'a T> { + pub fn access<'bound>(&'bound self, dev: &'bound Device) -> Res= ult<&'bound T> { if self.dev.as_raw() !=3D dev.as_raw() { return Err(EINVAL); } @@ -338,7 +339,10 @@ pub fn try_access_with R>(&self, f= : F) -> Option { } =20 /// [`Devres`] accessor for [`Revocable::try_access_with_guard`]. - pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> O= ption<&'a T> { + pub fn try_access_with_guard<'bound>( + &'bound self, + guard: &'bound rcu::Guard, + ) -> Option<&'bound T> { self.data().try_access_with_guard(guard) } } diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 2216b49604b2..5a601cba7dc0 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -584,11 +584,11 @@ unsafe impl Sync for I2cClient {} =20 impl Registration { /// The C `i2c_new_client_device` function wrapper for manual I2C clie= nt creation. - pub fn new<'a>( + pub fn new<'bound>( i2c_adapter: &I2cAdapter, i2c_board_info: &I2cBoardInfo, - parent_dev: &'a device::Device, - ) -> impl PinInit, Error> + 'a { + parent_dev: &'bound device::Device, + ) -> impl PinInit, Error> + 'bound { Devres::new(parent_dev, Self::try_new(i2c_adapter, i2c_board_info)) } =20 diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs index d9230e105541..92207fd46403 100644 --- a/rust/kernel/pci/irq.rs +++ b/rust/kernel/pci/irq.rs @@ -76,19 +76,19 @@ const fn as_raw(self) -> u32 { /// This type ties an IRQ vector to the device it was allocated for, /// ensuring the vector is only used with the correct device. #[derive(Clone, Copy)] -pub struct IrqVector<'a> { - dev: &'a Device, +pub struct IrqVector<'bound> { + dev: &'bound Device, index: u32, } =20 -impl<'a> IrqVector<'a> { +impl<'bound> IrqVector<'bound> { /// Creates a new [`IrqVector`] for the given device and index. /// /// # Safety /// /// - `index` must be a valid IRQ vector index for `dev`. /// - `dev` must point to a [`Device`] that has successfully allocated= IRQ vectors. - unsafe fn new(dev: &'a Device, index: u32) -> Self { + unsafe fn new(dev: &'bound Device, index: u32) -> Self { Self { dev, index } } =20 @@ -98,10 +98,10 @@ fn index(&self) -> u32 { } } =20 -impl<'a> TryInto> for IrqVector<'a> { +impl<'bound> TryInto> for IrqVector<'bound> { type Error =3D Error; =20 - fn try_into(self) -> Result> { + fn try_into(self) -> Result> { // SAFETY: `self.as_raw` returns a valid pointer to a `struct pci_= dev`. let irq =3D unsafe { bindings::pci_irq_vector(self.dev.as_raw(), s= elf.index()) }; if irq < 0 { @@ -129,12 +129,12 @@ impl IrqVectorRegistration { /// /// Allocates IRQ vectors and registers them with devres for automatic= cleanup. /// Returns a range of valid IRQ vectors. - fn register<'a>( - dev: &'a Device, + fn register<'bound>( + dev: &'bound Device, min_vecs: u32, max_vecs: u32, irq_types: IrqTypes, - ) -> Result>> { + ) -> Result>> { // SAFETY: // - `dev.as_raw()` is guaranteed to be a valid pointer to a `stru= ct pci_dev` // by the type invariant of `Device`. @@ -173,13 +173,13 @@ fn drop(&mut self) { =20 impl Device { /// Returns a [`kernel::irq::Registration`] for the given IRQ vector. - pub fn request_irq<'a, T: crate::irq::Handler + 'static>( - &'a self, - vector: IrqVector<'a>, + pub fn request_irq<'bound, T: crate::irq::Handler + 'static>( + &'bound self, + vector: IrqVector<'bound>, flags: irq::Flags, name: &'static CStr, - handler: impl PinInit + 'a, - ) -> impl PinInit, Error> + 'a { + handler: impl PinInit + 'bound, + ) -> impl PinInit, Error> + 'bound { pin_init::pin_init_scope(move || { let request =3D vector.try_into()?; =20 @@ -188,13 +188,13 @@ pub fn request_irq<'a, T: crate::irq::Handler + 'stat= ic>( } =20 /// Returns a [`kernel::irq::ThreadedRegistration`] for the given IRQ = vector. - pub fn request_threaded_irq<'a, T: crate::irq::ThreadedHandler + 'stat= ic>( - &'a self, - vector: IrqVector<'a>, + pub fn request_threaded_irq<'bound, T: crate::irq::ThreadedHandler + '= static>( + &'bound self, + vector: IrqVector<'bound>, flags: irq::Flags, name: &'static CStr, - handler: impl PinInit + 'a, - ) -> impl PinInit, Error> + 'a { + handler: impl PinInit + 'bound, + ) -> impl PinInit, Error> + 'bound { pin_init::pin_init_scope(move || { let request =3D vector.try_into()?; =20 diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 9959364429b5..f59f22283c53 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -365,13 +365,13 @@ macro_rules! define_irq_accessor_by_index { $handler_trait:ident ) =3D> { $(#[$meta])* - pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( - &'a self, + pub fn $fn_name<'bound, T: irq::$handler_trait + 'static>( + &'bound self, flags: irq::Flags, index: u32, name: &'static CStr, - handler: impl PinInit + 'a, - ) -> impl PinInit, Error> + 'a { + handler: impl PinInit + 'bound, + ) -> impl PinInit, Error> + 'bound { pin_init::pin_init_scope(move || { let request =3D self.$request_fn(index)?; =20 @@ -394,13 +394,13 @@ macro_rules! define_irq_accessor_by_name { $handler_trait:ident ) =3D> { $(#[$meta])* - pub fn $fn_name<'a, T: irq::$handler_trait + 'static>( - &'a self, + pub fn $fn_name<'bound, T: irq::$handler_trait + 'static>( + &'bound self, flags: irq::Flags, - irq_name: &'a CStr, + irq_name: &'bound CStr, name: &'static CStr, - handler: impl PinInit + 'a, - ) -> impl PinInit, Error> + 'a { + handler: impl PinInit + 'bound, + ) -> impl PinInit, Error> + 'bound { pin_init::pin_init_scope(move || { let request =3D self.$request_fn(irq_name)?; =20 --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 7702B3B4E81; Wed, 6 May 2026 21:53:43 +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=1778104423; cv=none; b=rxN+N7TgPH9P40ZN4INv438SWyoQNt6CAFlpBChT/+ma2RFJWG5pBaiZa9Da8yFmfbDooNoig/WAmqlz9Lh8a0PiFLnkeua3JEpidNQYD1mQuNzsAj+EastjLqBYos3BO6GPEmd6sDVHY/A5LGK7kAUymcNSnlqEk7b5uoAnUTs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104423; c=relaxed/simple; bh=rJ9Zf42krWnw6GFHxY+YcEyrmhC+ZgJmklrrd85+jss=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dTte6Cgp7MR2CK30cYbUszyH6MdwSF060SHDqCiWFfyXriuijFY3Dg3Bna/bpuA3EOo+3rPivNSC/iMHl8SBuXUFtUzMLmm+AxLjwc16lBqGKMRd5nxEByw77NNYHqkKiwxQpDAdBxB3ADDo7ULIW3rEzIllP+r+CxhbtO8S4sg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pCcSNroA; 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="pCcSNroA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CCFD0C2BCB2; Wed, 6 May 2026 21:53:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104423; bh=rJ9Zf42krWnw6GFHxY+YcEyrmhC+ZgJmklrrd85+jss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pCcSNroALL1xSHMZYPlVdmtM878HCCVaqIiIa7SXFqPg3QO8LXrVN0UIeXAACWsb2 3eZa+yTNX5aqqXWSbA/6P8FV2bbn9g9MPjQhrKmL7DBHKW9BK/AVe2kLp8vkm/sBas jXoCs+rS7WXRP2Or5zhlmF8oJVqLGs/y9+v9r6k5VXXrCtVIZsW+F7JS7TlV1mbFfu f4/bUiiAoJOGLFJISzHdLjFhO7uHF7WTGBL1PCHd15845vENxADZ6nK9SyEnqY+qd+ rFc5unDGBecf5nsvc3ANSVIJBrB2Y+eq4aFRH1YqllDyWbrwrMz0TWxWfJkVS/lWL4 UA965uYpRp9wQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 21/25] gpu: nova-core: rename 'a lifetime to 'bound Date: Wed, 6 May 2026 23:50:57 +0200 Message-ID: <20260506215113.851360-22-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Rename the generic lifetime parameter from 'a to 'bound in nova-core. This makes it explicit that the lifetime represents the device binding scope, consistent with the convention established by the HRT series. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/firmware/gsp.rs | 8 ++++---- drivers/gpu/nova-core/gpu.rs | 8 ++++---- drivers/gpu/nova-core/gsp/commands.rs | 10 +++++----- drivers/gpu/nova-core/gsp/fw/commands.rs | 4 +++- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/= firmware/gsp.rs index 2fcc255c3bc8..9dbd88c55f7e 100644 --- a/drivers/gpu/nova-core/firmware/gsp.rs +++ b/drivers/gpu/nova-core/firmware/gsp.rs @@ -65,11 +65,11 @@ pub(crate) struct GspFirmware { impl GspFirmware { /// Loads the GSP firmware binaries, map them into `dev`'s address-spa= ce, and creates the page /// tables expected by the GSP bootloader to load it. - pub(crate) fn new<'a>( - dev: &'a device::Device, + pub(crate) fn new<'bound>( + dev: &'bound device::Device, chipset: Chipset, - ver: &'a str, - ) -> impl PinInit + 'a { + ver: &'bound str, + ) -> impl PinInit + 'bound { pin_init::pin_init_scope(move || { let firmware =3D super::request_firmware(dev, chipset, "gsp", = ver)?; =20 diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 0f6fe9a1b955..9288b30fe4c3 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -241,11 +241,11 @@ pub(crate) struct Gpu { } =20 impl Gpu { - pub(crate) fn new<'a>( - pdev: &'a pci::Device, + pub(crate) fn new<'bound>( + pdev: &'bound pci::Device, devres_bar: Arc>, - bar: &'a Bar0, - ) -> impl PinInit + 'a { + bar: &'bound Bar0, + ) -> impl PinInit + 'bound { try_pin_init!(Self { spec: Spec::new(pdev.as_ref(), bar).inspect(|spec| { dev_info!(pdev,"NVIDIA ({})\n", spec); diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/= gsp/commands.rs index c89c7b57a751..0da5b92f4b27 100644 --- a/drivers/gpu/nova-core/gsp/commands.rs +++ b/drivers/gpu/nova-core/gsp/commands.rs @@ -35,18 +35,18 @@ }; =20 /// The `GspSetSystemInfo` command. -pub(crate) struct SetSystemInfo<'a> { - pdev: &'a pci::Device, +pub(crate) struct SetSystemInfo<'bound> { + pdev: &'bound pci::Device, } =20 -impl<'a> SetSystemInfo<'a> { +impl<'bound> SetSystemInfo<'bound> { /// Creates a new `GspSetSystemInfo` command using the parameters of `= pdev`. - pub(crate) fn new(pdev: &'a pci::Device) -> Self { + pub(crate) fn new(pdev: &'bound pci::Device) -> Self { Self { pdev } } } =20 -impl<'a> CommandToGsp for SetSystemInfo<'a> { +impl<'bound> CommandToGsp for SetSystemInfo<'bound> { const FUNCTION: MsgFunction =3D MsgFunction::GspSetSystemInfo; type Command =3D GspSetSystemInfo; type Reply =3D NoReply; diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs b/drivers/gpu/nova-co= re/gsp/fw/commands.rs index db46276430be..d3ef7ecdd73e 100644 --- a/drivers/gpu/nova-core/gsp/fw/commands.rs +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs @@ -24,7 +24,9 @@ pub(crate) struct GspSetSystemInfo { impl GspSetSystemInfo { /// Returns an in-place initializer for the `GspSetSystemInfo` command. #[allow(non_snake_case)] - pub(crate) fn init<'a>(dev: &'a pci::Device) -> impl In= it + 'a { + pub(crate) fn init<'bound>( + dev: &'bound pci::Device, + ) -> impl Init + 'bound { type InnerGspSystemInfo =3D bindings::GspSystemInfo; let init_inner =3D try_init!(InnerGspSystemInfo { gpuPhysAddr: dev.resource_start(0)?, --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 1C5CE3B3C1D; Wed, 6 May 2026 21:53: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=1778104430; cv=none; b=H9nsMlScHJOIpAt+fQZAuVJYyyet9kcSjuHpIHVDwO3OwIOr98M+Ohqc7/BXPHvMpYNGgT0xkheMIgZZkzEHLZpTawMvT5xRChf/827321JxMn7XtnVbGnvpZLgxIDmSG6WwI1ZrZm3SaKfUj5BnhrGCGTZbR1nvCanDYVA0/wI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104430; c=relaxed/simple; bh=g2KiL/CMPCnweI4E7xuxmAbnHThqGiuaJZ5Xgj96eoQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CiQeUpYngl1awoA7nw0+XaPFNjW7vRVZ0noULs9gf++7srvnUZ1FE18Fex3a3xTDdplJmv3W6AdTD8BYaU1XW1AZwjsWUqiqvPirc3CoQZRqmqP7vDt2mAe148a/HrUmDU0FurXc9MfuMpmqeBOeHVZ3+szu3q/2gCqU3VhYokI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ccn5zjyH; 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="ccn5zjyH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 83CFFC2BCB0; Wed, 6 May 2026 21:53:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104429; bh=g2KiL/CMPCnweI4E7xuxmAbnHThqGiuaJZ5Xgj96eoQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ccn5zjyHSwiiC5I5sDThi8TB9aiUc88iMMoHEE04BAyedJ0wJ8vo7wBJILTfOkTaW hbq566Ll9IWHtbvBmjHyQ2EM1s57FqAs9pt5KjrPi4AOqKyXyS4Ezswrem+ye+NoUw AC35F9Qigy6HZiOXGpu9zP1vR6FNK0P9MaQ+73wjk9mTONmK28JKU6awmhBZvbM7h5 HBxJ/CbCJuy7fiL7BKBIxcYKdaLPz3ekhmKy9AC7TfuBYWjtqDNpLTqkkUNfFpItjZ Ez55jCG215SEPaCplJ6GerZ1A6e05do4aai6jt9Xt0qJQZ6XQc+FjSIyCkDucsPv80 afq4HWEkZo80w== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 22/25] gpu: nova-core: use HRT lifetime for Bar Date: Wed, 6 May 2026 23:50:58 +0200 Message-ID: <20260506215113.851360-23-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Take advantage of the lifetime-parameterized pci::Bar<'bound> to hold the BAR mapping directly in NovaCore<'bound>, and pass a borrowed reference to Gpu<'bound>. This eliminates the Arc> indirection, removes runtime revocation checks for BAR access, and simplifies Gpu::unbind(). Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/driver.rs | 40 ++++++++++++++---------------- drivers/gpu/nova-core/gpu.rs | 27 ++++++++------------ drivers/gpu/nova-core/nova_core.rs | 2 +- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 6ee2021ef56e..11b632ae3789 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -14,12 +14,9 @@ }, prelude::*, sizes::SZ_16M, - sync::{ - atomic::{ - Atomic, - Relaxed, // - }, - Arc, + sync::atomic::{ + Atomic, + Relaxed, // }, types::ForLt, }; @@ -30,9 +27,10 @@ static AUXILIARY_ID_COUNTER: Atomic =3D Atomic::new(0); =20 #[pin_data] -pub(crate) struct NovaCore { +pub(crate) struct NovaCore<'bound> { #[pin] - pub(crate) gpu: Gpu, + pub(crate) gpu: Gpu<'bound>, + bar: pci::Bar<'bound, BAR0_SIZE>, #[allow(clippy::type_complexity)] _reg: Devres>, } @@ -47,12 +45,12 @@ pub(crate) struct NovaCore { // DMA addresses. These systems should be quite rare. const GPU_DMA_BITS: u32 =3D 47; =20 -pub(crate) type Bar0 =3D pci::Bar<'static, BAR0_SIZE>; +pub(crate) type Bar0 =3D kernel::io::Mmio; =20 kernel::pci_device_table!( PCI_TABLE, MODULE_PCI_TABLE, - >::IdInfo, + as pci::Driver<'_>>::IdInfo, [ // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. ( @@ -74,7 +72,7 @@ pub(crate) struct NovaCore { ] ); =20 -impl<'bound> pci::Driver<'bound> for NovaCore { +impl<'bound> pci::Driver<'bound> for NovaCore<'bound> { type IdInfo =3D (); const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 @@ -93,14 +91,14 @@ fn probe( // other threads of execution. unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::())? }; =20 - let bar =3D Arc::new( - pdev.iomap_region_sized::(0, c"nova-core/bar0")? - .into_devres()?, - GFP_KERNEL, - )?; - - Ok(try_pin_init!(Self { - gpu <- Gpu::new(pdev, bar.clone(), bar.access(pdev.as_ref(= ))?), + Ok(try_pin_init!(NovaCore { + bar: pdev.iomap_region_sized::(0, c"nova-core/b= ar0")?, + // TODO: Use `&bar` self-referential pin-init syntax once = available. + // + // SAFETY: `bar` is initialized before this expression is = evaluated + // (`try_pin_init!()` initializes fields in declaration or= der), lives at a pinned + // stable address, and is dropped after `gpu` (struct fiel= d drop order). + gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) = }), _reg: auxiliary::Registration::new( pdev.as_ref(), c"nova-drm", @@ -114,7 +112,7 @@ fn probe( }) } =20 - fn unbind(pdev: &pci::Device, this: Pin<&Self>) { - this.gpu.unbind(pdev.as_ref()); + fn unbind(_pdev: &'bound pci::Device, this: Pin<&'bound Self>) { + this.gpu.unbind(); } } diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 9288b30fe4c3..03295fa6fb32 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -2,13 +2,11 @@ =20 use kernel::{ device, - devres::Devres, fmt, io::Io, num::Bounded, pci, - prelude::*, - sync::Arc, // + prelude::*, // }; =20 use crate::{ @@ -224,10 +222,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Res= ult { =20 /// Structure holding the resources required to operate the GPU. #[pin_data] -pub(crate) struct Gpu { +pub(crate) struct Gpu<'bound> { spec: Spec, - /// MMIO mapping of PCI BAR 0 - bar: Arc>, + /// MMIO mapping of PCI BAR 0. + bar: &'bound Bar0, /// System memory page required for flushing all pending GPU-side memo= ry writes done through /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-= barrier operation). sysmem_flush: SysmemFlush, @@ -240,10 +238,9 @@ pub(crate) struct Gpu { gsp: Gsp, } =20 -impl Gpu { - pub(crate) fn new<'bound>( +impl<'bound> Gpu<'bound> { + pub(crate) fn new( pdev: &'bound pci::Device, - devres_bar: Arc>, bar: &'bound Bar0, ) -> impl PinInit + 'bound { try_pin_init!(Self { @@ -257,6 +254,8 @@ pub(crate) fn new<'bound>( .inspect_err(|_| dev_err!(pdev, "GFW boot did not comp= lete\n"))?; }, =20 + bar, + sysmem_flush: SysmemFlush::register(pdev.as_ref(), bar, spec.c= hipset)?, =20 gsp_falcon: Falcon::new( @@ -270,19 +269,13 @@ pub(crate) fn new<'bound>( gsp <- Gsp::new(pdev), =20 _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon= )? }, - - bar: devres_bar, }) } =20 /// Called when the corresponding [`Device`](device::Device) is unboun= d. /// /// Note: This method must only be called from `Driver::unbind`. - pub(crate) fn unbind(&self, dev: &device::Device) { - kernel::warn_on!(self - .bar - .access(dev) - .inspect(|bar| self.sysmem_flush.unregister(bar)) - .is_err()); + pub(crate) fn unbind(&self) { + self.sysmem_flush.unregister(self.bar); } } diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nov= a_core.rs index 49c093a0cb42..ed5eb39c8201 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -49,7 +49,7 @@ struct NovaCoreModule { // then `_debugfs_guard` clears `DEBUGFS_ROOT`. #[allow(clippy::type_complexity)] #[pin] - _driver: Registration>, + _driver: Registration)>>, _debugfs_guard: DebugfsRootGuard, } =20 --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 C5FCD3B47E5; Wed, 6 May 2026 21:53:56 +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=1778104436; cv=none; b=ruYq3cNyZRGkatP9IWzSzuM9HfyqNAlQpSmRr9+suC+QHF7kvGA41ko1irO6WMWl2p+jlvDsfvmKBVEi3ly+TuRtoGfXCP2S+IKfC54qN59b5JZ+8Y6GD7vSyG+oSErWqXUbZTyj2qA3iHUdOlegyVHjKlc/VdGw2LAfylzN+yo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104436; c=relaxed/simple; bh=JemW6+hXTNe2roNUmuhyi6dJSHZ2hsaM41xXJeGWXFU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aTcl3g57sL/3jrlbH0j/PvhHOfeIuCXWJV94WqMMoUcRT7QrHbFN3gq1p94xEhd3NNgJwoxaB7gZPHYT2DAoczocBaClpXjJT+0EBqxZOCtfZ1jfBV7vix44OdKIExoGpBtAdSktoirzyBQFqqXjqHqasM977flLi5CYhm+s0hI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Q19nEG2C; 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="Q19nEG2C" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3CF14C2BCB2; Wed, 6 May 2026 21:53:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104436; bh=JemW6+hXTNe2roNUmuhyi6dJSHZ2hsaM41xXJeGWXFU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q19nEG2Cgkh58jimLzg/BPtuOxYrcF8uDCvMbepj/dLeF2Yc1z6Po0VIQkEVyPkWo 7d1XtbLnjtlqYvK9jfsa7B1spr5VkcFuhckDh3aee+PNec23wrfXE7GDmh4fSyFbYF zFwfb21iBqVr1snKbrX6nLrZxUHyJ6kDdUYdqriWUz4p3l2NC4JqvKBD8ZMHWirMOq rzIMP3LOE18QfcE4MNtN1xvL9E8gt3wUKBnbVub7H2bLJqIS+sBUYV1Fg3UJNxARHM 5aIuRnE3UoHFzR4dxHrqskYtTI5F5JN5qgfQljOyHYqy5wGptNJcjdmhfemtSqSGMv sW8vByLQupKlA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich , Eliot Courtney Subject: [PATCH v2 23/25] gpu: nova-core: unregister sysmem flush page from Drop Date: Wed, 6 May 2026 23:50:59 +0200 Message-ID: <20260506215113.851360-24-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Now that SysmemFlush can borrow the Bar via HRT lifetime, store a &'bound Bar0 reference and implement Drop to automatically unregister the sysmem flush page. This removes the need for manual unregister() calls and the Gpu::unbind() method. Reported-by: Eliot Courtney Closes: https://lore.kernel.org/all/20260409-fix-systemflush-v1-1-a1d6c968f= 17c@nvidia.com/ Fixes: 6554ad65b589 ("gpu: nova-core: register sysmem flush page") Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/driver.rs | 4 ---- drivers/gpu/nova-core/fb.rs | 22 ++++++++++------------ drivers/gpu/nova-core/gpu.rs | 9 +-------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 11b632ae3789..31d2a8dadb7b 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -111,8 +111,4 @@ fn probe( })) }) } - - fn unbind(_pdev: &'bound pci::Device, this: Pin<&'bound Self>) { - this.gpu.unbind(); - } } diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index bdd5eed760e1..a707fbfe3ced 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -46,21 +46,20 @@ /// Because of this, the sysmem flush memory page must be registered as ea= rly as possible during /// driver initialization, and before any falcon is reset. /// -/// Users are responsible for manually calling [`Self::unregister`] before= dropping this object, -/// otherwise the GPU might still use it even after it has been freed. -pub(crate) struct SysmemFlush { +pub(crate) struct SysmemFlush<'bound> { /// Chipset we are operating on. chipset: Chipset, device: ARef, + bar: &'bound Bar0, /// Keep the page alive as long as we need it. page: CoherentHandle, } =20 -impl SysmemFlush { +impl<'bound> SysmemFlush<'bound> { /// Allocate a memory page and register it as the sysmem flush page. pub(crate) fn register( dev: &device::Device, - bar: &Bar0, + bar: &'bound Bar0, chipset: Chipset, ) -> Result { let page =3D CoherentHandle::alloc(dev, kernel::page::PAGE_SIZE, G= FP_KERNEL)?; @@ -70,19 +69,18 @@ pub(crate) fn register( Ok(Self { chipset, device: dev.into(), + bar, page, }) } +} =20 - /// Unregister the managed sysmem flush page. - /// - /// In order to gracefully tear down the GPU, users must make sure to = call this method before - /// dropping the object. - pub(crate) fn unregister(&self, bar: &Bar0) { +impl Drop for SysmemFlush<'_> { + fn drop(&mut self) { let hal =3D hal::fb_hal(self.chipset); =20 - if hal.read_sysmem_flush_page(bar) =3D=3D self.page.dma_handle() { - let _ =3D hal.write_sysmem_flush_page(bar, 0).inspect_err(|e| { + if hal.read_sysmem_flush_page(self.bar) =3D=3D self.page.dma_handl= e() { + let _ =3D hal.write_sysmem_flush_page(self.bar, 0).inspect_err= (|e| { dev_warn!( &self.device, "failed to unregister sysmem flush page: {:?}\n", diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 03295fa6fb32..c17d068b35eb 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -228,7 +228,7 @@ pub(crate) struct Gpu<'bound> { bar: &'bound Bar0, /// System memory page required for flushing all pending GPU-side memo= ry writes done through /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-= barrier operation). - sysmem_flush: SysmemFlush, + sysmem_flush: SysmemFlush<'bound>, /// GSP falcon instance, used for GSP boot up and cleanup. gsp_falcon: Falcon, /// SEC2 falcon instance, used for GSP boot up and cleanup. @@ -271,11 +271,4 @@ pub(crate) fn new( _: { gsp.boot(pdev, bar, spec.chipset, gsp_falcon, sec2_falcon= )? }, }) } - - /// Called when the corresponding [`Device`](device::Device) is unboun= d. - /// - /// Note: This method must only be called from `Driver::unbind`. - pub(crate) fn unbind(&self) { - self.sysmem_flush.unregister(self.bar); - } } --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 E53FE3B47D6; Wed, 6 May 2026 21:54:03 +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=1778104444; cv=none; b=oQrJiM7CllIFfuz2JVMsJzpviHMbnBNBYEcfuO9OueYiwYymgGtqvXyJJbjoRzrQABShVD1rcANtzlFybCkyOlL+J92dcpIaFTIf1UjV4R6YRy5mFTruKaqLI33e4FRrmnZyhAM8yAmJj8uEtxXIjn6qmEbXlTSXKn9h4tUqbiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104444; c=relaxed/simple; bh=ehe2nY6HcH6JtRvtBxvkGvdAIzSzQ7wCS3Ek50X1INE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ElsiCnp0hrqnSvjsMvIVXmoMfqFi9P6O/TuuX/0YyZXB+brwI8rGnmCFIoFNq4GnLoNXKyO9Nz+OTj4F9DQt/9LxSAQc3/Qn2ZAxXhW8xTeXu48BFe0ziECnJvZkHn1+qUPqO6IqPbnppL6ogLHWno6oyivvZpGwIgHUX64A/o4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=c7xsYTEE; 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="c7xsYTEE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 212AAC2BCB0; Wed, 6 May 2026 21:53:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104443; bh=ehe2nY6HcH6JtRvtBxvkGvdAIzSzQ7wCS3Ek50X1INE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=c7xsYTEE7d1id01Jb752U8+IgHd50N19/BGVX0reUOcFzLeDHNo4ZO/YSkUZLsKji FjsIaU9q1pgzRMnxSFWO2kJRh9gcjJwqjDVzzNTB0oc2vFQnM9de07nvlwNX5fNyIF 5lMqoCwIgxJyjJest+36C1lDqa/0kbPY/cberHsa3UyI/jt62WNnLrEFvlU6y4evN4 mHQoqUbmOw7Kgf5tYGCmgSnSvyJlWJTPMqwQLxwFwKj8dPW6xx71WuRrOnQEzJSerU GbVjmmYJXgXQbJEeHz0RRtUYsRb9dFC27IWnElrIewo19aHlpNzfGi6rNpuoY71cyZ FB7pSrAGDZG8w== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 24/25] gpu: nova-core: replace ARef with &'bound Device in SysmemFlush Date: Wed, 6 May 2026 23:51:00 +0200 Message-ID: <20260506215113.851360-25-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Now that SysmemFlush is lifetime-parameterized, the ARef is unnecessary -- a plain &'bound Device reference suffices. Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/nova-core/fb.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/nova-core/fb.rs b/drivers/gpu/nova-core/fb.rs index a707fbfe3ced..e22dec12ae7e 100644 --- a/drivers/gpu/nova-core/fb.rs +++ b/drivers/gpu/nova-core/fb.rs @@ -15,8 +15,7 @@ Alignable, Alignment, // }, - sizes::*, - sync::aref::ARef, // + sizes::*, // }; =20 use crate::{ @@ -49,7 +48,7 @@ pub(crate) struct SysmemFlush<'bound> { /// Chipset we are operating on. chipset: Chipset, - device: ARef, + device: &'bound device::Device, bar: &'bound Bar0, /// Keep the page alive as long as we need it. page: CoherentHandle, @@ -58,7 +57,7 @@ pub(crate) struct SysmemFlush<'bound> { impl<'bound> SysmemFlush<'bound> { /// Allocate a memory page and register it as the sysmem flush page. pub(crate) fn register( - dev: &device::Device, + dev: &'bound device::Device, bar: &'bound Bar0, chipset: Chipset, ) -> Result { @@ -68,7 +67,7 @@ pub(crate) fn register( =20 Ok(Self { chipset, - device: dev.into(), + device: dev, bar, page, }) --=20 2.54.0 From nobody Sat Jun 13 15:12:53 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 9789F3B4EAD; Wed, 6 May 2026 21:54: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=1778104450; cv=none; b=VWKp1XCccwGNa4F0cNm8+V6QhoW+SEr2/ORZl48lJxFPjXpjZpGnfrWAff4ShVnYufWBR5y5Pa+EDWyUdHkukpxl/A5qVmvcASgFEYxaOvgQJRxHQQ5Sy6iA9JinHC8vNggGOBYbWAFVZ0neHynyvO97JwdyLMX6/1S88Y75Jnc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778104450; c=relaxed/simple; bh=VG30qVsb6RRcXgQELJg9Ca7p/xOe3vGfkPeGGTG4/LY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AKp2ZvnFC9rWEBSxFvUjJ4UEwhFp4Bc2qR5y/mWCywwAerCmiFRn4dtCwrYfj5jbm0uOO4T0z9wlge7gxn0uLWJXb0L5k08I7qHWzQSToNMzm1ZcJWxP9NClGR6mtRDjJN+3KsirymMQ9bfr7XCOODoSw1/O2scUl6HMZ639tmI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=CvVRRka0; 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="CvVRRka0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 026B0C2BCB2; Wed, 6 May 2026 21:54:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1778104450; bh=VG30qVsb6RRcXgQELJg9Ca7p/xOe3vGfkPeGGTG4/LY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CvVRRka0UdUyjqUuewxIjDCozRr885C1yZbQ+nXEiERgeUq1lsuxNFGejbsaYbLJH 4LxLI/7Cdsp1MpFN38v72WYXJfYCo1ChgNVnLfvqg7CvEQDsHMJ2eV9lsMyMyIYaUx h2mAzjKKXKk7qMZ977jmCpLjn8VzWwhbgVeA9FH+HUDrAO7s/rD5ieU4EwxY5OfnGY s8rthYTks/vHKDvqyOuaX1BmJJ6fp1fHLwqHQDVzJt8XKSdaF4EXwDIAiuxPbdzJi4 1fx1z1SILndIPvYx+KeUpOR+ITHFzFxq37YOQHk+SeC87j/bDWMW7t0tuBZav3kjVg Nm9CXtW4ZkspA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, viresh.kumar@linaro.org, m.wilczynski@samsung.com, ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, abdiel.janulgue@gmail.com, robin.murphy@arm.com, markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev, daniel.almeida@collabora.com Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org, linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 25/25] gpu: drm: tyr: use HRT lifetime for IoMem Date: Wed, 6 May 2026 23:51:01 +0200 Message-ID: <20260506215113.851360-26-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260506215113.851360-1-dakr@kernel.org> References: <20260506215113.851360-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" Take advantage of the lifetime-parameterized IoMem<'bound> to use the memory mapping directly during probe, eliminating the Arc> indirection. Since the IoMem is only used during probe, this also simplifies Register::read/write to be infallible -- the Devres access check is no longer needed, so reads return u32 directly and writes return (). Signed-off-by: Danilo Krummrich Tested-by: Dirk Behme --- drivers/gpu/drm/tyr/driver.rs | 14 ++++---- drivers/gpu/drm/tyr/gpu.rs | 62 +++++++++++++++++------------------ drivers/gpu/drm/tyr/regs.rs | 21 +++--------- 3 files changed, 41 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 295a627de2b2..e6c84a1433d2 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -10,7 +10,6 @@ Core, Device, // }, - devres::Devres, drm, drm::ioctl, io::poll, @@ -23,7 +22,6 @@ sizes::SZ_2M, sync::{ aref::ARef, - Arc, Mutex, // }, time, // @@ -37,7 +35,7 @@ regs, // }; =20 -pub(crate) type IoMem =3D kernel::io::mem::IoMem<'static, SZ_2M>; +pub(crate) type IoMem =3D kernel::io::Mmio; =20 pub(crate) struct TyrDrmDriver; =20 @@ -65,11 +63,11 @@ pub(crate) struct TyrDrmDeviceData { pub(crate) gpu_info: GpuInfo, } =20 -fn issue_soft_reset(dev: &Device, iomem: &Devres) -> Result { - regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?; +fn issue_soft_reset(dev: &Device, iomem: &IoMem) -> Result { + regs::GPU_CMD.write(iomem, regs::GPU_CMD_SOFT_RESET); =20 poll::read_poll_timeout( - || regs::GPU_IRQ_RAWSTAT.read(dev, iomem), + || Ok(regs::GPU_IRQ_RAWSTAT.read(iomem)), |status| *status & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED !=3D 0, time::Delta::from_millis(1), time::Delta::from_millis(100), @@ -109,12 +107,12 @@ fn probe( let sram_regulator =3D Regulator::::get(pdev.a= s_ref(), c"sram")?; =20 let request =3D pdev.io_request_by_index(0).ok_or(ENODEV)?; - let iomem =3D Arc::new(request.iomap_sized::()?.into_devres= ()?, GFP_KERNEL)?; + let iomem =3D request.iomap_sized::()?; =20 issue_soft_reset(pdev.as_ref(), &iomem)?; gpu::l2_power_on(pdev.as_ref(), &iomem)?; =20 - let gpu_info =3D GpuInfo::new(pdev.as_ref(), &iomem)?; + let gpu_info =3D GpuInfo::new(&iomem); gpu_info.log(pdev); =20 let platform: ARef =3D pdev.into(); diff --git a/drivers/gpu/drm/tyr/gpu.rs b/drivers/gpu/drm/tyr/gpu.rs index a88775160f98..bb0473c85bf7 100644 --- a/drivers/gpu/drm/tyr/gpu.rs +++ b/drivers/gpu/drm/tyr/gpu.rs @@ -10,7 +10,6 @@ Bound, Device, // }, - devres::Devres, io::poll, platform, prelude::*, @@ -35,37 +34,36 @@ pub(crate) struct GpuInfo(pub(crate) uapi::drm_panthor_gpu_info); =20 impl GpuInfo { - pub(crate) fn new(dev: &Device, iomem: &Devres) -> Resul= t { - let gpu_id =3D regs::GPU_ID.read(dev, iomem)?; - let csf_id =3D regs::GPU_CSF_ID.read(dev, iomem)?; - let gpu_rev =3D regs::GPU_REVID.read(dev, iomem)?; - let core_features =3D regs::GPU_CORE_FEATURES.read(dev, iomem)?; - let l2_features =3D regs::GPU_L2_FEATURES.read(dev, iomem)?; - let tiler_features =3D regs::GPU_TILER_FEATURES.read(dev, iomem)?; - let mem_features =3D regs::GPU_MEM_FEATURES.read(dev, iomem)?; - let mmu_features =3D regs::GPU_MMU_FEATURES.read(dev, iomem)?; - let thread_features =3D regs::GPU_THREAD_FEATURES.read(dev, iomem)= ?; - let max_threads =3D regs::GPU_THREAD_MAX_THREADS.read(dev, iomem)?; - let thread_max_workgroup_size =3D regs::GPU_THREAD_MAX_WORKGROUP_S= IZE.read(dev, iomem)?; - let thread_max_barrier_size =3D regs::GPU_THREAD_MAX_BARRIER_SIZE.= read(dev, iomem)?; - let coherency_features =3D regs::GPU_COHERENCY_FEATURES.read(dev, = iomem)?; - - let texture_features =3D regs::GPU_TEXTURE_FEATURES0.read(dev, iom= em)?; - - let as_present =3D regs::GPU_AS_PRESENT.read(dev, iomem)?; - - let shader_present =3D u64::from(regs::GPU_SHADER_PRESENT_LO.read(= dev, iomem)?); + pub(crate) fn new(iomem: &IoMem) -> Self { + let gpu_id =3D regs::GPU_ID.read(iomem); + let csf_id =3D regs::GPU_CSF_ID.read(iomem); + let gpu_rev =3D regs::GPU_REVID.read(iomem); + let core_features =3D regs::GPU_CORE_FEATURES.read(iomem); + let l2_features =3D regs::GPU_L2_FEATURES.read(iomem); + let tiler_features =3D regs::GPU_TILER_FEATURES.read(iomem); + let mem_features =3D regs::GPU_MEM_FEATURES.read(iomem); + let mmu_features =3D regs::GPU_MMU_FEATURES.read(iomem); + let thread_features =3D regs::GPU_THREAD_FEATURES.read(iomem); + let max_threads =3D regs::GPU_THREAD_MAX_THREADS.read(iomem); + let thread_max_workgroup_size =3D regs::GPU_THREAD_MAX_WORKGROUP_S= IZE.read(iomem); + let thread_max_barrier_size =3D regs::GPU_THREAD_MAX_BARRIER_SIZE.= read(iomem); + let coherency_features =3D regs::GPU_COHERENCY_FEATURES.read(iomem= ); + + let texture_features =3D regs::GPU_TEXTURE_FEATURES0.read(iomem); + + let as_present =3D regs::GPU_AS_PRESENT.read(iomem); + + let shader_present =3D u64::from(regs::GPU_SHADER_PRESENT_LO.read(= iomem)); let shader_present =3D - shader_present | u64::from(regs::GPU_SHADER_PRESENT_HI.read(de= v, iomem)?) << 32; + shader_present | u64::from(regs::GPU_SHADER_PRESENT_HI.read(io= mem)) << 32; =20 - let tiler_present =3D u64::from(regs::GPU_TILER_PRESENT_LO.read(de= v, iomem)?); - let tiler_present =3D - tiler_present | u64::from(regs::GPU_TILER_PRESENT_HI.read(dev,= iomem)?) << 32; + let tiler_present =3D u64::from(regs::GPU_TILER_PRESENT_LO.read(io= mem)); + let tiler_present =3D tiler_present | u64::from(regs::GPU_TILER_PR= ESENT_HI.read(iomem)) << 32; =20 - let l2_present =3D u64::from(regs::GPU_L2_PRESENT_LO.read(dev, iom= em)?); - let l2_present =3D l2_present | u64::from(regs::GPU_L2_PRESENT_HI.= read(dev, iomem)?) << 32; + let l2_present =3D u64::from(regs::GPU_L2_PRESENT_LO.read(iomem)); + let l2_present =3D l2_present | u64::from(regs::GPU_L2_PRESENT_HI.= read(iomem)) << 32; =20 - Ok(Self(uapi::drm_panthor_gpu_info { + Self(uapi::drm_panthor_gpu_info { gpu_id, gpu_rev, csf_id, @@ -88,7 +86,7 @@ pub(crate) fn new(dev: &Device, iomem: &Devres) -> Result { core_features, pad: 0, gpu_features: 0, - })) + }) } =20 pub(crate) fn log(&self, pdev: &platform::Device) { @@ -208,11 +206,11 @@ fn from(value: u32) -> Self { } =20 /// Powers on the l2 block. -pub(crate) fn l2_power_on(dev: &Device, iomem: &Devres) -> R= esult { - regs::L2_PWRON_LO.write(dev, iomem, 1)?; +pub(crate) fn l2_power_on(dev: &Device, iomem: &IoMem) -> Result { + regs::L2_PWRON_LO.write(iomem, 1); =20 poll::read_poll_timeout( - || regs::L2_READY_LO.read(dev, iomem), + || Ok(regs::L2_READY_LO.read(iomem)), |status| *status =3D=3D 1, Delta::from_millis(1), Delta::from_millis(100), diff --git a/drivers/gpu/drm/tyr/regs.rs b/drivers/gpu/drm/tyr/regs.rs index 611870c2e6af..0881b3812afd 100644 --- a/drivers/gpu/drm/tyr/regs.rs +++ b/drivers/gpu/drm/tyr/regs.rs @@ -7,16 +7,7 @@ // does. #![allow(dead_code)] =20 -use kernel::{ - bits::bit_u32, - device::{ - Bound, - Device, // - }, - devres::Devres, - io::Io, - prelude::*, // -}; +use kernel::{bits::bit_u32, io::Io}; =20 use crate::driver::IoMem; =20 @@ -29,15 +20,13 @@ =20 impl Register { #[inline] - pub(crate) fn read(&self, dev: &Device, iomem: &Devres) = -> Result { - let value =3D (*iomem).access(dev)?.read32(OFFSET); - Ok(value) + pub(crate) fn read(&self, iomem: &IoMem) -> u32 { + iomem.read32(OFFSET) } =20 #[inline] - pub(crate) fn write(&self, dev: &Device, iomem: &Devres,= value: u32) -> Result { - (*iomem).access(dev)?.write32(value, OFFSET); - Ok(()) + pub(crate) fn write(&self, iomem: &IoMem, value: u32) { + iomem.write32(value, OFFSET); } } =20 --=20 2.54.0