[PATCH v3 05/16] rust: io: support register projections

Gary Guo <[email protected]>
Newsgroups dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
`IoLoc`s themselves just describe a projection from a region to a concrete
register. Thus, support it in `io_project` macro too. Also, update methods
that operate on `IoLoc` to use I/O projection.

Documentation of `io_project!` is not expanded yet as the example works
better when `register!` type can specify base type. `io_read!` and
`io_write!` gains the ability to operate on registers as corollary of the
capability of `io_project!`. Examples are not added because `read` and
`write` is still preferrably used instead.

Signed-off-by: Gary Guo <[email protected]>
---
 rust/kernel/io.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index 6c087d30a166..ea072c098b13 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -864,8 +864,7 @@ fn try_read<T, L>(self, location: L) -> Result<T>
         L: IoLoc<Self::Target, T>,
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
     {
-        let view = io_view::<Self, T>(self, location.offset())?;
-        Ok(view.read_val())
+        Ok(io_read!(self, try: location))
     }
 
     /// Generic fallible write with runtime bounds check.
@@ -898,8 +897,7 @@ fn try_write<T, L>(self, location: L, value: T) -> Result
         L: IoLoc<Self::Target, T>,
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
     {
-        let view = io_view::<Self, T>(self, location.offset())?;
-        view.write_val(value);
+        io_write!(self, try: location, value);
         Ok(())
     }
 
@@ -978,7 +976,7 @@ fn try_update<T, L, F>(self, location: L, f: F) -> Result
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
         F: FnOnce(T) -> T,
     {
-        let view = io_view::<Self, T>(self, location.offset())?;
+        let view = io_project!(self, try: location);
         view.write_val(f(view.read_val()));
         Ok(())
     }
@@ -1011,8 +1009,7 @@ fn read<T, L>(self, location: L) -> T
         L: IoLoc<Self::Target, T>,
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
     {
-        let view = io_view_assert::<Self, T>(self, location.offset());
-        view.read_val()
+        io_read!(self, build: location)
     }
 
     /// Generic infallible write with compile-time bounds check.
@@ -1043,8 +1040,7 @@ fn write<T, L>(self, location: L, value: T)
         L: IoLoc<Self::Target, T>,
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
     {
-        let view = io_view_assert::<Self, T>(self, location.offset());
-        view.write_val(value)
+        io_write!(self, build: location, value);
     }
 
     /// Generic infallible write of a fully-located register value.
@@ -1121,7 +1117,7 @@ fn update<T, L, F>(self, location: L, f: F)
         Self::Backend: IoCapable<<T as AsRepr>::Repr>,
         F: FnOnce(T) -> T,
     {
-        let view = io_view_assert::<Self, T>(self, location.offset());
+        let view = io_project!(self, build: location);
         view.write_val(f(view.read_val()));
     }
 }
@@ -1666,6 +1662,25 @@ pub unsafe fn project_view<U: ?Sized + KnownSize>(
         // SAFETY: Per safety requirement.
         unsafe { T::Backend::project_view::<T::Target, _>(self.0, ptr) }
     }
+
+    #[inline(always)]
+    pub fn try_project_loc<U, L>(
+        self,
+        location: L,
+    ) -> Result<<T::Backend as IoBackend>::View<'a, U>>
+    where
+        L: IoLoc<T::Target, U>,
+    {
+        io_view::<_, U>(self.0, location.offset())
+    }
+
+    #[inline(always)]
+    pub fn project_loc<U, L>(self, location: L) -> <T::Backend as IoBackend>::View<'a, U>
+    where
+        L: IoLoc<T::Target, U>,
+    {
+        io_view_assert::<_, U>(self.0, location.offset())
+    }
 }
 
 /// Project an I/O type to a subview of it.
@@ -1693,6 +1708,21 @@ pub unsafe fn project_view<U: ?Sized + KnownSize>(
 #[macro_export]
 #[doc(hidden)]
 macro_rules! io_project {
+    // Register projection
+    ($io:expr, try: $ioloc:expr) => {{
+        #[allow(unused)]
+        use $crate::io::IoBase as _;
+        let view = $crate::io::ProjectHelper($io.as_view());
+        view.try_project_loc($ioloc)?
+    }};
+    ($io:expr, build: $ioloc:expr) => {{
+        #[allow(unused)]
+        use $crate::io::IoBase as _;
+        let view = $crate::io::ProjectHelper($io.as_view());
+        view.project_loc($ioloc)
+    }};
+
+    // Field or index projection
     ($io:expr, $($proj:tt)*) => {{
         #[allow(unused)]
         use $crate::io::IoBase as _;
@@ -1763,6 +1793,12 @@ macro_rules! io_write {
     (@parse [$io:expr] [$($proj:tt)*] [[$flavor:ident: $index:expr] $($rest:tt)*]) => {
         $crate::io_write!(@parse [$io] [$($proj)* [$flavor: $index]] [$($rest)*])
     };
+    (@parse [$io:expr] [] [try: $ioloc:expr, $($rest:tt)*]) => {
+        $crate::io_write!(@parse [$io] [try: $ioloc] [, $($rest)*])
+    };
+    (@parse [$io:expr] [] [build: $ioloc:expr, $($rest:tt)*]) => {
+        $crate::io_write!(@parse [$io] [build: $ioloc] [, $($rest)*])
+    };
     ($io:expr, $($rest:tt)*) => {
         $crate::io_write!(@parse [$io] [] [$($rest)*])
     };

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.