diff mbox series

[v6,13/16] rust: driver: implement `Adapter`

Message ID 20241212163357.35934-14-dakr@kernel.org (mailing list archive)
State Superseded
Headers show
Series Device / Driver PCI / Platform Rust abstractions | expand

Commit Message

Danilo Krummrich Dec. 12, 2024, 4:33 p.m. UTC
In order to not duplicate code in bus specific implementations (e.g.
platform), implement a generic `driver::Adapter` to represent the
connection of matched drivers and devices.

Bus specific `Adapter` implementations can simply implement this trait
to inherit generic functionality, such as matching OF or ACPI device IDs
and ID table entries.

Suggested-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
 rust/bindings/bindings_helper.h |  1 +
 rust/kernel/driver.rs           | 59 ++++++++++++++++++++++++++++++++-
 2 files changed, 59 insertions(+), 1 deletion(-)

Comments

Andreas Hindborg Dec. 19, 2024, 10:53 a.m. UTC | #1
Hi Danilo,

Danilo Krummrich <dakr@kernel.org> writes:

> In order to not duplicate code in bus specific implementations (e.g.
> platform), implement a generic `driver::Adapter` to represent the
> connection of matched drivers and devices.
>
> Bus specific `Adapter` implementations can simply implement this trait
> to inherit generic functionality, such as matching OF or ACPI device IDs
> and ID table entries.
>
> Suggested-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---

I get some warnings when applying this patch:

>   RUSTC L rust/kernel.o
> warning: unused import: `device_id`
>   --> /home/aeh/src/linux-rust/rnvme-v6.13-rc3/rust/kernel/driver.rs:10:13
>    |
> 10 |     device, device_id, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule,
>    |             ^^^^^^^^^
>    |
>    = note: `#[warn(unused_imports)]` on by default
> 
> warning: missing documentation for an associated function
>    --> /home/aeh/src/linux-rust/rnvme-v6.13-rc3/rust/kernel/driver.rs:158:5
>     |
> 158 |     fn of_id_info(_dev: &device::Device) -> Option<&'static Self::IdInfo> {
>     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>     |
>     = note: requested on the command line with `-W missing-docs`
> 
> warning: 2 warnings emitted


Looks like the latter one is from patch 13.


Best regards,
Andreas Hindborg
Danilo Krummrich Dec. 19, 2024, 3:07 p.m. UTC | #2
On Thu, Dec 19, 2024 at 11:53:06AM +0100, Andreas Hindborg wrote:
> 
> Hi Danilo,
> 
> Danilo Krummrich <dakr@kernel.org> writes:
> 
> > In order to not duplicate code in bus specific implementations (e.g.
> > platform), implement a generic `driver::Adapter` to represent the
> > connection of matched drivers and devices.
> >
> > Bus specific `Adapter` implementations can simply implement this trait
> > to inherit generic functionality, such as matching OF or ACPI device IDs
> > and ID table entries.
> >
> > Suggested-by: Rob Herring (Arm) <robh@kernel.org>
> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> > ---
> 
> I get some warnings when applying this patch:

Ah, that's because your're probably having CONFIG_OF=n and some imports are only
used within `of_id_info`.

Gonna fix it for CONFIG_OF=n.

> 
> >   RUSTC L rust/kernel.o
> > warning: unused import: `device_id`
> >   --> /home/aeh/src/linux-rust/rnvme-v6.13-rc3/rust/kernel/driver.rs:10:13
> >    |
> > 10 |     device, device_id, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule,
> >    |             ^^^^^^^^^
> >    |
> >    = note: `#[warn(unused_imports)]` on by default
> > 
> > warning: missing documentation for an associated function
> >    --> /home/aeh/src/linux-rust/rnvme-v6.13-rc3/rust/kernel/driver.rs:158:5
> >     |
> > 158 |     fn of_id_info(_dev: &device::Device) -> Option<&'static Self::IdInfo> {
> >     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> >     |
> >     = note: requested on the command line with `-W missing-docs`
> > 
> > warning: 2 warnings emitted
> 
> 
> Looks like the latter one is from patch 13.
> 
> 
> Best regards,
> Andreas Hindborg
> 
>
diff mbox series

Patch

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 6d7a68e2ecb7..8fe70183a392 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -20,6 +20,7 @@ 
 #include <linux/jump_label.h>
 #include <linux/mdio.h>
 #include <linux/miscdevice.h>
+#include <linux/of_device.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
 #include <linux/pid_namespace.h>
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index c1957ee7bb7e..63dbebbc0829 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -6,7 +6,9 @@ 
 //! register using the [`Registration`] class.
 
 use crate::error::{Error, Result};
-use crate::{init::PinInit, str::CStr, try_pin_init, types::Opaque, ThisModule};
+use crate::{
+    device, device_id, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule,
+};
 use core::pin::Pin;
 use macros::{pin_data, pinned_drop};
 
@@ -115,3 +117,58 @@  fn init(
         }
     }
 }
+
+/// The bus independent adapter to match a drivers and a devices.
+///
+/// This trait should be implemented by the bus specific adapter, which represents the connection
+/// of a device and a driver.
+///
+/// It provides bus independent functions for device / driver interactions.
+pub trait Adapter {
+    /// The type holding driver private data about each device id supported by the driver.
+    type IdInfo: 'static;
+
+    /// The [`of::IdTable`] of the corresponding driver.
+    fn of_id_table() -> Option<of::IdTable<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 in the [`of::IdTable`].
+    #[cfg(CONFIG_OF)]
+    fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
+        let table = Self::of_id_table()?;
+
+        // SAFETY:
+        // - `table` has static lifetime, hence it's valid for read,
+        // - `dev` is guaranteed to be valid while it's alive, and so is `pdev.as_ref().as_raw()`.
+        let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) };
+
+        if raw_id.is_null() {
+            None
+        } else {
+            // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct of_device_id` and
+            // does not add additional invariants, so it's safe to transmute.
+            let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
+
+            Some(table.info(<of::DeviceId as device_id::RawDeviceId>::index(id)))
+        }
+    }
+
+    #[cfg(not(CONFIG_OF))]
+    fn of_id_info(_dev: &device::Device) -> Option<&'static Self::IdInfo> {
+        None
+    }
+
+    /// Returns the driver's private data from the matching entry of any of the ID tables, if any.
+    ///
+    /// 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> {
+        let id = Self::of_id_info(dev);
+        if id.is_some() {
+            return id;
+        }
+
+        None
+    }
+}