{"id":2229249,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2229249/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pwm/patch/20260427221155.2144848-15-dakr@kernel.org/","project":{"id":38,"url":"http://patchwork.ozlabs.org/api/1.1/projects/38/?format=json","name":"Linux PWM development","link_name":"linux-pwm","list_id":"linux-pwm.vger.kernel.org","list_email":"linux-pwm@vger.kernel.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260427221155.2144848-15-dakr@kernel.org>","date":"2026-04-27T22:11:12","name":"[14/24] rust: auxiliary: generalize Registration over ForLt","commit_ref":null,"pull_url":null,"state":"handled-elsewhere","archived":false,"hash":"463ad0ccddd16ac08efd67bbe088ae793641f29c","submitter":{"id":89037,"url":"http://patchwork.ozlabs.org/api/1.1/people/89037/?format=json","name":"Danilo Krummrich","email":"dakr@kernel.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-pwm/patch/20260427221155.2144848-15-dakr@kernel.org/mbox/","series":[{"id":501734,"url":"http://patchwork.ozlabs.org/api/1.1/series/501734/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pwm/list/?series=501734","date":"2026-04-27T22:10:58","name":"rust: device: Higher-Ranked Lifetime Types for device drivers","version":1,"mbox":"http://patchwork.ozlabs.org/series/501734/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2229249/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2229249/checks/","tags":{},"headers":{"Return-Path":"\n <linux-pwm+bounces-8717-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pwm@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=Xz60eMTw;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-pwm+bounces-8717-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=\"Xz60eMTw\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=10.30.226.201"],"Received":["from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4J2K6T5Dz1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 08:21:45 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 4715A3145E54\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 27 Apr 2026 22:14:00 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id EC3743AE701;\n\tMon, 27 Apr 2026 22:13:36 +0000 (UTC)","from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org\n [10.30.226.201])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id C6E2C3AD500;\n\tMon, 27 Apr 2026 22:13:36 +0000 (UTC)","by smtp.kernel.org (Postfix) with ESMTPSA id 9A275C19425;\n\tMon, 27 Apr 2026 22:13:30 +0000 (UTC)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777328016; cv=none;\n b=VCbYSoTOJGEwuqqANoeIw0alBiwH+EY/FM6INS3nzTgeFqBeMGD/Jb7nnbKk1sxTdja5M1EufcfNK6uW1UK6xLsD3ePP6c1BrcSC8LJDVXoZa4+mZgehGuvdG1WSSqRzzXzTFDd/MQMeWIKvHaswM/opsw1/Gud1IMF8R9+1jgU=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777328016; c=relaxed/simple;\n\tbh=fYpYyJUHzZkxcr62qUd+Bupt8j3iNvgRc3q30X3mPgE=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=nEoI+xuUqmTcNdvNCh/DR4Yl6qGRdRvvDMCkaKpEOEN8otawxZM41ei2QLytmy5z9IN+RbZbh0TmSw1/UIqBic3Ne3RliwtIRDaDMWG72ZXj5HsGvS0LS2Ygp2v1o40h8vAum2vEr9UcRfCs3SjVTZc9jF6Ja+WlurBSUVXlOHg=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org\n header.b=Xz60eMTw; arc=none smtp.client-ip=10.30.226.201","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1777328016;\n\tbh=fYpYyJUHzZkxcr62qUd+Bupt8j3iNvgRc3q30X3mPgE=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=Xz60eMTwi9F9Xopxl23ANXhzlrKa8KRUQ74F6VU5w+e8bzuAWSzV5TwPtI0vVpdav\n\t V3F6rNYgZ87FgkTdG0ZCLT0rzlpai178fhUXc9FeTjkhIpZOa9k/1MtAqVZ+cL8ky0\n\t PIAiAggVBi2102ji8oWmXmKIj56HEl6ijBWEDkjvdKhZzEvuLtnJZKAKUCR6vensXk\n\t 7nDSyEnfLyAwj0zG0I8VO5agWq88jJinRVQaDy7h9yi7Pxy6sEmEGdK35gWU5HJqIX\n\t r2DZ79/MVnwxsN8vWJL4PzB/iP9I4VClh+K22BlZk9QTAtPjcqhp7vCzk23Vl51EaX\n\t EocGnyooTDO0Q==","From":"Danilo Krummrich <dakr@kernel.org>","To":"gregkh@linuxfoundation.org,\n\trafael@kernel.org,\n\tacourbot@nvidia.com,\n\taliceryhl@google.com,\n\tdavid.m.ertman@intel.com,\n\tira.weiny@intel.com,\n\tleon@kernel.org,\n\tviresh.kumar@linaro.org,\n\tm.wilczynski@samsung.com,\n\tukleinek@kernel.org,\n\tbhelgaas@google.com,\n\tkwilczynski@kernel.org,\n\tabdiel.janulgue@gmail.com,\n\trobin.murphy@arm.com,\n\tmarkus.probst@posteo.de,\n\tojeda@kernel.org,\n\tboqun@kernel.org,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tlossin@kernel.org,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu","Cc":"driver-core@lists.linux.dev,\n\tlinux-kernel@vger.kernel.org,\n\tnova-gpu@lists.linux.dev,\n\tdri-devel@lists.freedesktop.org,\n\tlinux-pm@vger.kernel.org,\n\tlinux-pwm@vger.kernel.org,\n\tlinux-pci@vger.kernel.org,\n\trust-for-linux@vger.kernel.org,\n\tDanilo Krummrich <dakr@kernel.org>","Subject":"[PATCH 14/24] rust: auxiliary: generalize Registration over ForLt","Date":"Tue, 28 Apr 2026 00:11:12 +0200","Message-ID":"<20260427221155.2144848-15-dakr@kernel.org>","X-Mailer":"git-send-email 2.54.0","In-Reply-To":"<20260427221155.2144848-1-dakr@kernel.org>","References":"<20260427221155.2144848-1-dakr@kernel.org>","Precedence":"bulk","X-Mailing-List":"linux-pwm@vger.kernel.org","List-Id":"<linux-pwm.vger.kernel.org>","List-Subscribe":"<mailto:linux-pwm+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pwm+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"Generalize Registration<T> to Registration<F: ForLt> and\nDevice::registration_data<F: ForLt>() to return Pin<&F::Of<'_>>.\n\nThe stored 'static lifetime is shortened to the borrow lifetime of &self\nvia ForLt::cast_ref; ForLt's covariance guarantee makes this sound.\n\nSigned-off-by: Danilo Krummrich <dakr@kernel.org>\n---\n drivers/gpu/nova-core/driver.rs       |  4 +-\n rust/kernel/auxiliary.rs              | 80 ++++++++++++++++++---------\n samples/rust/rust_driver_auxiliary.rs |  7 ++-\n 3 files changed, 61 insertions(+), 30 deletions(-)","diff":"diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs\nindex 815489dd92d0..2a17fc99d9b6 100644\n--- a/drivers/gpu/nova-core/driver.rs\n+++ b/drivers/gpu/nova-core/driver.rs\n@@ -21,6 +21,7 @@\n         },\n         Arc,\n     },\n+    types::ForLt,\n };\n \n use crate::gpu::Gpu;\n@@ -32,7 +33,8 @@\n pub(crate) struct NovaCore {\n     #[pin]\n     pub(crate) gpu: Gpu,\n-    _reg: Devres<auxiliary::Registration<()>>,\n+    #[allow(clippy::type_complexity)]\n+    _reg: Devres<auxiliary::Registration<ForLt!(())>>,\n }\n \n const BAR0_SIZE: usize = SZ_16M;\ndiff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs\nindex f593a21a16be..e27de4be4d87 100644\n--- a/rust/kernel/auxiliary.rs\n+++ b/rust/kernel/auxiliary.rs\n@@ -287,12 +287,19 @@ pub fn parent(&self) -> &device::Device<device::Bound> {\n \n     /// Returns a pinned reference to the registration data set by the registering (parent) driver.\n     ///\n-    /// Returns [`EINVAL`] if `T` does not match the type used by the parent driver when calling\n+    /// `F` is the [`ForLt`](trait@ForLt) encoding of the data type. The returned\n+    /// reference has its lifetime shortened from `'static` to `&self`'s borrow lifetime via\n+    /// [`ForLt::cast_ref`].\n+    ///\n+    /// Returns [`EINVAL`] if `F` does not match the type used by the parent driver when calling\n     /// [`Registration::new()`].\n     ///\n     /// Returns [`ENOENT`] if no registration data has been set, e.g. when the device was\n     /// registered by a C driver.\n-    pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {\n+    pub fn registration_data<F: ForLt>(&self) -> Result<Pin<&F::Of<'_>>>\n+    where\n+        F::Of<'static>: 'static,\n+    {\n         // SAFETY: By the type invariant, `self.as_raw()` is a valid `struct auxiliary_device`.\n         let ptr = unsafe { (*self.as_raw()).registration_data_rust };\n         if ptr.is_null() {\n@@ -305,18 +312,23 @@ pub fn registration_data<T: 'static>(&self) -> Result<Pin<&T>> {\n \n         // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `Registration::new()`;\n         // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, so reading a `TypeId`\n-        // at the start of the allocation is valid regardless of `T`.\n+        // at the start of the allocation is valid regardless of `F`.\n         let type_id = unsafe { ptr.cast::<TypeId>().read() };\n-        if type_id != TypeId::of::<T>() {\n+        if type_id != TypeId::of::<F::Of<'static>>() {\n             return Err(EINVAL);\n         }\n \n-        // SAFETY: The `TypeId` check above confirms that the stored type is `T`; `ptr` remains\n-        // valid until `Registration::drop()` calls `from_foreign()`.\n-        let wrapper = unsafe { Pin::<KBox<RegistrationData<T>>>::borrow(ptr) };\n+        // SAFETY: The `TypeId` check above confirms that the stored type matches\n+        // `F::Of<'static>`; `ptr` remains valid until `Registration::drop()` calls\n+        // `from_foreign()`.\n+        let wrapper = unsafe { Pin::<KBox<RegistrationData<F::Of<'static>>>>::borrow(ptr) };\n \n         // SAFETY: `data` is a structurally pinned field of `RegistrationData`.\n-        Ok(unsafe { wrapper.map_unchecked(|w| &w.data) })\n+        let pinned: Pin<&F::Of<'static>> = unsafe { wrapper.map_unchecked(|w| &w.data) };\n+\n+        // SAFETY: ForLt guarantees covariance, making it sound to shorten 'static to &self's\n+        // lifetime via cast_ref.\n+        Ok(unsafe { Pin::new_unchecked(F::cast_ref(pinned.get_ref())) })\n     }\n }\n \n@@ -405,43 +417,54 @@ struct RegistrationData<T> {\n /// This type represents the registration of a [`struct auxiliary_device`]. When its parent device\n /// is unbound, the corresponding auxiliary device will be unregistered from the system.\n ///\n-/// The type parameter `T` is the type of the registration data owned by the registering (parent)\n-/// driver. It can be accessed by the auxiliary driver through\n-/// [`Device::registration_data()`].\n+/// The type parameter `F` is a [`ForLt`](trait@ForLt) encoding of the registration\n+/// data type. For non-lifetime-parameterized types, use [`ForLt!(T)`](macro@ForLt).\n+/// The data can be accessed by the auxiliary driver through [`Device::registration_data()`].\n ///\n /// # Invariants\n ///\n /// `self.adev` always holds a valid pointer to an initialized and registered\n /// [`struct auxiliary_device`], and `registration_data` points to a valid\n-/// `Pin<KBox<RegistrationData<T>>>`.\n-pub struct Registration<T: 'static> {\n+/// `Pin<KBox<RegistrationData<F::Of<'static>>>>`.\n+pub struct Registration<F: ForLt>\n+where\n+    F::Of<'static>: 'static,\n+{\n     adev: NonNull<bindings::auxiliary_device>,\n-    _data: PhantomData<T>,\n+    _data: PhantomData<F>,\n }\n \n-impl<T: Send + 'static> Registration<T> {\n+impl<F: ForLt> Registration<F>\n+where\n+    F::Of<'static>: Send + 'static,\n+{\n     /// Create and register a new auxiliary device with the given registration data.\n     ///\n     /// The `data` is owned by the registration and can be accessed through the auxiliary device\n     /// via [`Device::registration_data()`].\n-    pub fn new<E>(\n-        parent: &device::Device<device::Bound>,\n+    pub fn new<'a, E>(\n+        parent: &'a device::Device<device::Bound>,\n         name: &CStr,\n         id: u32,\n         modname: &CStr,\n-        data: impl PinInit<T, E>,\n+        data: impl PinInit<F::Of<'a>, E>,\n     ) -> Result<Devres<Self>>\n     where\n         Error: From<E>,\n     {\n         let data = KBox::pin_init::<Error>(\n             try_pin_init!(RegistrationData {\n-                type_id: TypeId::of::<T>(),\n+                type_id: TypeId::of::<F::Of<'static>>(),\n                 data <- data,\n             }),\n             GFP_KERNEL,\n         )?;\n \n+        // SAFETY: Lifetimes are erased and do not affect layout, so RegistrationData<F::Of<'a>>\n+        // and RegistrationData<F::Of<'static>> have identical representation.\n+        let data: Pin<KBox<RegistrationData<F::Of<'static>>>> =\n+            unsafe { core::mem::transmute(data) };\n+\n         let boxed = KBox::new(Opaque::<bindings::auxiliary_device>::zeroed(), GFP_KERNEL)?;\n         let adev = boxed.get();\n \n@@ -470,9 +493,11 @@ pub fn new<E>(\n         let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) };\n         if ret != 0 {\n             // SAFETY: `registration_data` was set above via `into_foreign()`.\n-            let _ = unsafe {\n-                Pin::<KBox<RegistrationData<T>>>::from_foreign((*adev).registration_data_rust)\n-            };\n+            drop(unsafe {\n+                Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(\n+                    (*adev).registration_data_rust,\n+                )\n+            });\n \n             // SAFETY: `adev` is guaranteed to be a valid pointer to a\n             // `struct auxiliary_device`, which has been initialized.\n@@ -494,7 +519,10 @@ pub fn new<E>(\n     }\n }\n \n-impl<T: 'static> Drop for Registration<T> {\n+impl<F: ForLt> Drop for Registration<F>\n+where\n+    F::Of<'static>: 'static,\n+{\n     fn drop(&mut self) {\n         // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` is a valid registered\n         // `struct auxiliary_device`.\n@@ -502,7 +530,7 @@ fn drop(&mut self) {\n \n         // SAFETY: `registration_data` was set in `new()` via `into_foreign()`.\n         drop(unsafe {\n-            Pin::<KBox<RegistrationData<T>>>::from_foreign(\n+            Pin::<KBox<RegistrationData<F::Of<'static>>>>::from_foreign(\n                 (*self.adev.as_ptr()).registration_data_rust,\n             )\n         });\n@@ -516,7 +544,7 @@ fn drop(&mut self) {\n }\n \n // SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread.\n-unsafe impl<T: Send> Send for Registration<T> {}\n+unsafe impl<F: ForLt> Send for Registration<F> where F::Of<'static>: Send {}\n \n // SAFETY: `Registration` does not expose any methods or fields that need synchronization.\n-unsafe impl<T: Send> Sync for Registration<T> {}\n+unsafe impl<F: ForLt> Sync for Registration<F> where F::Of<'static>: Send {}\ndiff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs\nindex d35963ac7fa4..4ad619c5731e 100644\n--- a/samples/rust/rust_driver_auxiliary.rs\n+++ b/samples/rust/rust_driver_auxiliary.rs\n@@ -55,9 +55,10 @@ struct Data {\n     index: u32,\n }\n \n+#[allow(clippy::type_complexity)]\n struct ParentDriver {\n-    _reg0: Devres<auxiliary::Registration<Data>>,\n-    _reg1: Devres<auxiliary::Registration<Data>>,\n+    _reg0: Devres<auxiliary::Registration<ForLt!(Data)>>,\n+    _reg1: Devres<auxiliary::Registration<ForLt!(Data)>>,\n }\n \n kernel::pci_device_table!(\n@@ -100,7 +101,7 @@ fn connect(adev: &auxiliary::Device<Bound>) -> Result {\n         let dev = adev.parent();\n         let pdev: &pci::Device<Bound> = dev.try_into()?;\n \n-        let data = adev.registration_data::<Data>()?;\n+        let data = adev.registration_data::<ForLt!(Data)>()?;\n \n         dev_info!(\n             dev,\n","prefixes":["14/24"]}