]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rust: pci: impl TryFrom<&Device> for &pci::Device
authorDanilo Krummrich <dakr@kernel.org>
Fri, 21 Mar 2025 21:47:54 +0000 (22:47 +0100)
committerDanilo Krummrich <dakr@kernel.org>
Sat, 19 Apr 2025 08:20:16 +0000 (10:20 +0200)
Implement TryFrom<&device::Device> for &Device.

This allows us to get a &pci::Device from a generic &Device in a safe
way; the conversion fails if the device' bus type does not match with
the PCI bus type.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/r/20250321214826.140946-3-dakr@kernel.org
[ Support device context types, use dev_is_pci() helper. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
rust/helpers/pci.c
rust/kernel/pci.rs

index 8ba22f91145912248069a0c9683500f1a33dea5e..cd0e6bf2cc4d9b37db3a717e7a8422b054f348ec 100644 (file)
@@ -16,3 +16,8 @@ resource_size_t rust_helper_pci_resource_len(struct pci_dev *pdev, int bar)
 {
        return pci_resource_len(pdev, bar);
 }
+
+bool rust_helper_dev_is_pci(const struct device *dev)
+{
+       return dev_is_pci(dev);
+}
index 3664d35b8e796083bff9610dba63fa27f567abd5..38fc8d5ffbf9dba9374cac3cbbaf6d408e34af4c 100644 (file)
@@ -6,7 +6,7 @@
 
 use crate::{
     alloc::flags::*,
-    bindings, device,
+    bindings, container_of, device,
     device_id::RawDeviceId,
     devres::Devres,
     driver,
@@ -455,6 +455,26 @@ impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
     }
 }
 
+impl<Ctx: device::DeviceContext> TryFrom<&device::Device<Ctx>> for &Device<Ctx> {
+    type Error = kernel::error::Error;
+
+    fn try_from(dev: &device::Device<Ctx>) -> Result<Self, Self::Error> {
+        // SAFETY: By the type invariant of `Device`, `dev.as_raw()` is a valid pointer to a
+        // `struct device`.
+        if !unsafe { bindings::dev_is_pci(dev.as_raw()) } {
+            return Err(EINVAL);
+        }
+
+        // SAFETY: We've just verified that the bus type of `dev` equals `bindings::pci_bus_type`,
+        // hence `dev` must be embedded in a valid `struct pci_dev` as guaranteed by the
+        // corresponding C code.
+        let pdev = unsafe { container_of!(dev.as_raw(), bindings::pci_dev, dev) };
+
+        // SAFETY: `pdev` is a valid pointer to a `struct pci_dev`.
+        Ok(unsafe { &*pdev.cast() })
+    }
+}
+
 // SAFETY: A `Device` is always reference-counted and can be released from any thread.
 unsafe impl Send for Device {}