From nobody Sun Feb 8 01:52:42 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 BFEFF1D0B8E for ; Wed, 22 Jan 2025 23:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737590069; cv=none; b=VoRl4hk5t5040G9ZNMWOvHZ/lV+bCx1wcjquBy2/n1mz4vDlQXBas9B/5/7GM0qh2zZsD4XLtwwLXaC6F3fzMsHveT/5N18wT3O52m8KKUn7qnTsptNILo+paspXqvYbODDhIbKdlNsRR6fVjmz8XWBDVu+KpViWGTfR74wEHk8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737590069; c=relaxed/simple; bh=vrMMe0TwCa98LQG10gdjY1GBoqp21ch4jKAdf5KwETg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PIgdwY5bryITSbs1/Zy9HJbdhbmgBjO9GYmskqhrQvs1QnsO8NtzLn0DcHdtSBNdcQDVQyiFlblUDVqtgDxt+woyVyB8x0BK/yJiqSO+lWISqvohONoZMkAoVuY6Y0c1IVhfiYk9XSNJL0lKxlCqYAVOJ01HuYqXA6mkWViXg04= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=IvRwuK5B; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="IvRwuK5B" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737590066; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VKmlxv8pQ8qN6v+5ZFghyPhLccDSs9SACVr9wKUj6jg=; b=IvRwuK5BZSigi6qcE3yU418VjVvri6Pp0O3tCkjH9C5TTB6X1Iw9QoNHSZ4MxIT7HhuCiT hxdMC9ZnLyjcHXcGL3Nfyqm3zZ4vZAX3v6eveOfxOHt6AGgteHWtuOxH2iizxffhu9Qszx r+mP+bTQpUyEHoVMQ4qB/Ib+JN9j/GA= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-17-seYCpLFNMvSf3yza-MtG0Q-1; Wed, 22 Jan 2025 18:54:23 -0500 X-MC-Unique: seYCpLFNMvSf3yza-MtG0Q-1 X-Mimecast-MFC-AGG-ID: seYCpLFNMvSf3yza-MtG0Q Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4ED7A19560B7; Wed, 22 Jan 2025 23:54:20 +0000 (UTC) Received: from chopper.redhat.com (unknown [10.22.88.57]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id ABC2419560AD; Wed, 22 Jan 2025 23:54:17 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Subject: [PATCH 1/2] rust/kernel: Add platform::Device::from_raw() Date: Wed, 22 Jan 2025 18:49:21 -0500 Message-ID: <20250122235340.2145383-2-lyude@redhat.com> In-Reply-To: <20250122235340.2145383-1-lyude@redhat.com> References: <20250122235340.2145383-1-lyude@redhat.com> 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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 Content-Type: text/plain; charset="utf-8" Just a convenience method to convert from a raw struct platform_device pointer into a platform::Device object, which we'll be using in the next commit. Signed-off-by: Lyude Paul --- rust/kernel/platform.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 50e6b04218132..75dc7824eccf4 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -14,7 +14,7 @@ ThisModule, }; =20 -use core::ptr::addr_of_mut; +use core::ptr::{NonNull, addr_of_mut}; =20 /// An adapter for the registration of platform drivers. pub struct Adapter(T); @@ -186,6 +186,21 @@ unsafe fn from_dev(dev: ARef) -> Self { Self(dev) } =20 + /// Convert a raw pointer to a `struct platform_device` into a `Device= `. + /// + /// # Safety + /// + /// * `pdev` must be a valid pointer to a `bindings::platform_device`. + /// * The caller must be guaranteed to hold at least one reference to = `pdev`. + unsafe fn from_raw(pdev: *mut bindings::platform_device) -> Self { + // SAFETY: + // * Our safety contract ensures `pdev` is a valid pointer which w= e hold at least one + // reference to. + // * struct device and `device::Device` have equivalent data layou= ts via the + // `device::Device` type invariants. + Self(unsafe { ARef::from_raw(NonNull::new_unchecked(addr_of_mut!((= *pdev).dev).cast())) }) + } + fn as_raw(&self) -> *mut bindings::platform_device { // SAFETY: By the type invariant `self.0.as_raw` is a pointer to t= he `struct device` // embedded in `struct platform_device`. --=20 2.47.1 From nobody Sun Feb 8 01:52:42 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (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 24ECF1CDA3F for ; Wed, 22 Jan 2025 23:54:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737590074; cv=none; b=KmdWTctXI9R3AwN7M9yR6n2jLqoJ2crY0VT5CxoF0vkhdrUxQdwYbYD9YKrYa24u1AT77Bqula7e2AMs8ejesOR23tsFKSYGT37xyw7y4vSve/+vucupPJX6rvc1u0Y6j9IN1TH6X4o1zrktdXxarcSvFTAU7k5GvMba/jNcJ5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737590074; c=relaxed/simple; bh=k+2WxuFUkJb3ygcg18Fn5sNX0oS0EgYOnFVMYFHzHjY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Z1Uu+eQwf+KwfAdhsBtLH9XDJcNpa4rI60n9Y5Jbqx3wnc37/QaNUIamJ1KmCcjhFMJTILPadvpRvhBOfc+gQKubPjRStC+mYoUj3AXnCcVtJdbOYsWCIINULKx669Xz4431tZKHURqatF9a/UhlITNHg6JAHfCo/cerUlGaZIw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=P/POOwO/; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="P/POOwO/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1737590072; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qn5VPfgtJ4t4Y4+cqcL97GvZXixeJcYoIyEVffAkuws=; b=P/POOwO/s4egwr7g9f2nM5M8JTaVKuGJLN6Yt1vNH5k74qBwdqxsTwD0U9EmvvuIpuwEoX h/zcbCn9Fu4WB+4A+AzPWHqvJiSBbv8n7wPdzrDRp/qNAimiehzBJOSgaW/21v4UhF0H9A UarTazqzJmQBEokZ+ys6jyYhNu9RUZg= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-z2VU-b20N-egqKu72yEhTQ-1; Wed, 22 Jan 2025 18:54:25 -0500 X-MC-Unique: z2VU-b20N-egqKu72yEhTQ-1 X-Mimecast-MFC-AGG-ID: z2VU-b20N-egqKu72yEhTQ Received: from mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.40]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1F3091956080; Wed, 22 Jan 2025 23:54:23 +0000 (UTC) Received: from chopper.redhat.com (unknown [10.22.88.57]) by mx-prod-int-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9107319560AA; Wed, 22 Jan 2025 23:54:20 +0000 (UTC) From: Lyude Paul To: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Ma=C3=ADra=20Canal?= , Greg Kroah-Hartman , "Rafael J. Wysocki" , Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross Subject: [PATCH 2/2] rust/kernel: Add platform::ModuleDevice Date: Wed, 22 Jan 2025 18:49:22 -0500 Message-ID: <20250122235340.2145383-3-lyude@redhat.com> In-Reply-To: <20250122235340.2145383-1-lyude@redhat.com> References: <20250122235340.2145383-1-lyude@redhat.com> 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 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.40 A number of kernel modules work with virtual devices, where being virtual implies that there's no physical device to actually be plugged into the system. Because of that, such modules need to be able to manually instantiate a kernel device themselves - which can then be probed in the same manner as any other kernel device. This adds support for such a usecase by introducing another platform device type, ModuleDevice. This type is interchangeable with normal platform devices, with the one exception being that it controls the lifetime of the registration of the device. Signed-off-by: Lyude Paul Co-authored-by: Ma=C3=ADra Canal --- rust/kernel/platform.rs | 96 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 75dc7824eccf4..b5d38bb182e93 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -13,8 +13,11 @@ types::{ARef, ForeignOwnable, Opaque}, ThisModule, }; - -use core::ptr::{NonNull, addr_of_mut}; +use core::{ + mem::ManuallyDrop, + ops::*, + ptr::{addr_of_mut, NonNull}, +}; =20 /// An adapter for the registration of platform drivers. pub struct Adapter(T); @@ -213,3 +216,92 @@ fn as_ref(&self) -> &device::Device { &self.0 } } + +/// A platform device ID specifier. +/// +/// This type is used for selecting the kind of device ID to use when cons= tructing a new +/// [`ModuleDevice`]. +#[derive(Copy, Clone)] +pub enum ModuleDeviceId { + /// Do not use a device ID with a device. + None, + /// Automatically allocate a device ID for a device. + Auto, + /// Explicitly specify a device ID for a device. + Explicit(i32), +} + +impl ModuleDeviceId { + fn as_raw(self) -> Result { + match self { + ModuleDeviceId::Explicit(id) =3D> { + if matches!( + id, + bindings::PLATFORM_DEVID_NONE | bindings::PLATFORM_DEV= ID_AUTO + ) { + Err(EINVAL) + } else { + Ok(id) + } + } + ModuleDeviceId::None =3D> Ok(bindings::PLATFORM_DEVID_NONE), + ModuleDeviceId::Auto =3D> Ok(bindings::PLATFORM_DEVID_AUTO), + } + } +} + +/// A platform device that was created by a module. +/// +/// This type represents a platform device that was manually created by a = kernel module, typically a +/// virtual device, instead of being discovered by the kernel. It is probe= d upon creation in the +/// same manner as a typical platform device, and the device will not be u= nregistered until this +/// type is dropped. +// We store the Device in a ManuallyDrop container, since we must enforce = that our reference to the +// Device is dropped using platform_device_unregister() +pub struct ModuleDevice(ManuallyDrop); + +impl ModuleDevice { + /// Create and register a new platform device. + /// + /// This creates and registers a new platform device. This is usually = only useful for drivers + /// which create virtual devices, as drivers for real hardware can rel= y on the kernel's probing + /// process. + pub fn new(name: &'static CStr, id: ModuleDeviceId) -> Result { + // SAFETY: + // * ModuleDeviceId::as_raw() always returns a valid device ID + // * Returns NULL on failure, or a valid platform_device pointer o= n success + let pdev_ptr =3D unsafe { bindings::platform_device_alloc(name.as_= char_ptr(), id.as_raw()?) }; + if pdev_ptr.is_null() { + return Err(ENOMEM); + } + + // SAFETY: + // * The previous function is guaranteed to have returned a valid = pointer to a platform_dev, + // or NULL (which we checked for already) + // * The previous function also took a single reference to the pla= tform_dev + let pdev =3D unsafe { Device::from_raw(pdev_ptr) }; + + // SAFETY: We already checked that pdev_ptr is valid above. + to_result(unsafe { bindings::platform_device_add(pdev_ptr) }) + .map(|_| ModuleDevice(ManuallyDrop::new(pdev))) + } +} + +impl Deref for ModuleDevice { + type Target =3D Device; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for ModuleDevice { + fn drop(&mut self) { + // SAFETY: Only one instance of this type can exist for a given pl= atform device, so this is + // safe to call. + unsafe { bindings::platform_device_unregister(self.as_raw()) } + + // No need to manually drop our contents, as platform_device_unreg= ister() dropped the ref + // count that was owned by this type. + } +} --=20 2.47.1