`IoCapable<T>` provides both `io_read` and `io_write`, so a backend that
supports accesses of type `T` supports them in both directions, and every
(non-copy) `Io` method that reads or writes a value requires both. There
is no way to express a backend, or a view, that can only be read or only
be written.

Thus, replace `IoCapable<T>` with an `IoReadable<T>` trait holding
`io_read` and an `IoWritable<T>` trait holding `io_write`, and implement
both for all existing backends. The non-copy `Io` methods that read a
value now require `IoReadable` and those that write one require
`IoWritable`. `update` and `try_update` read and then write, so they
require both.

The copy methods use `IoCopyable` and are not changed here.

No functional change intended. This prepares for read-only and write-only
views, added in a following patch.

Signed-off-by: Daniel Almeida <[email protected]>
---
 rust/kernel/dma.rs    |  12 ++++--
 rust/kernel/io.rs     | 101 +++++++++++++++++++++++++++++---------------------
 rust/kernel/pci/io.rs |  10 +++--
 3 files changed, 75 insertions(+), 48 deletions(-)

diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 4ce914b7d1da..7216a78d38c9 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -17,8 +17,9 @@
     io::{
         IoBackend,
         IoBase,
-        IoCapable,
         IoCopyable,
+        IoReadable,
+        IoWritable,
         SysMem,
         SysMemBackend, //
     },
@@ -1180,15 +1181,20 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     }
 }
 
-impl<T> IoCapable<T> for CoherentIoBackend
+impl<T> IoReadable<T> for CoherentIoBackend
 where
-    SysMemBackend: IoCapable<T>,
+    SysMemBackend: IoReadable<T>,
 {
     #[inline]
     fn io_read<'a>(view: Self::View<'a, T>) -> T {
         SysMemBackend::io_read(view.cpu_addr)
     }
+}
 
+impl<T> IoWritable<T> for CoherentIoBackend
+where
+    SysMemBackend: IoWritable<T>,
+{
     #[inline]
     fn io_write<'a>(view: Self::View<'a, T>, value: T) {
         SysMemBackend::io_write(view.cpu_addr, value)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index de8ef8e2aec4..fd5dd5f6bda4 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -247,9 +247,9 @@ fn io_view_as_repr<'a, IO: Io<'a, Target = T>, T: AsRepr>(
 /// backends (e.g. MMIO, PCI config space, etc.).
 ///
 /// The base trait only defines the projection operations; which I/O methods 
are available depends
-/// on which [`IoCapable<T>`] traits are implemented for the type. For 
example, for MMIO regions,
-/// all widths (u8, u16, u32, and u64 on 64-bit systems) are typically 
supported. For PCI
-/// configuration space, u8, u16, and u32 are supported but u64 is not.
+/// on which [`IoReadable<T>`] and [`IoWritable<T>`] traits are implemented 
for the type. For
+/// example, for MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit 
systems) are typically
+/// supported. For PCI configuration space, u8, u16, and u32 are supported but 
u64 is not.
 ///
 /// This trait is separate from the `Io` trait as multiple different I/O types 
may share the same
 /// operation.
@@ -276,18 +276,24 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     ) -> Self::View<'a, U>;
 }
 
-/// Trait indicating that an I/O backend supports operations of a certain type 
and providing an
-/// implementation for these operations.
+/// Trait indicating that an I/O backend supports reads of a certain type and 
providing an
+/// implementation for these reads.
 ///
 /// Different I/O backends can implement this trait to expose only the 
operations they support.
 ///
-/// For example, a PCI configuration space may implement `IoCapable<u8>`, 
`IoCapable<u16>`,
-/// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 
64-bit
+/// For example, a PCI configuration space may implement `IoReadable<u8>`, 
`IoReadable<u16>`,
+/// and `IoReadable<u32>`, but not `IoReadable<u64>`, while an MMIO region on 
a 64-bit
 /// system might implement all four.
-pub trait IoCapable<T>: IoBackend {
+pub trait IoReadable<T>: IoBackend {
     /// Performs an I/O read of type `T` at `view` and returns the result.
     fn io_read<'a>(view: Self::View<'a, T>) -> T;
+}
 
+/// Trait indicating that an I/O backend supports writes of a certain type and 
providing an
+/// implementation for these writes.
+///
+/// Like [`IoReadable`], it is implemented for each type the backend supports.
+pub trait IoWritable<T>: IoBackend {
     /// Performs an I/O write of `value` at `view`.
     fn io_write<'a>(view: Self::View<'a, T>, value: T);
 }
@@ -548,7 +554,7 @@ fn try_cast<U>(self) -> Result<<Self::Backend as 
IoBackend>::View<'a, U>>
     fn read_val(self) -> Self::Target
     where
         Self::Target: AsReprMut,
-        Self::Backend: IoCapable<<Self::Target as AsRepr>::Repr>,
+        Self::Backend: IoReadable<<Self::Target as AsRepr>::Repr>,
     {
         Self::Target::from_repr(Self::Backend::io_read(io_view_as_repr(self)))
     }
@@ -570,7 +576,7 @@ fn read_val(self) -> Self::Target
     fn write_val(self, value: Self::Target)
     where
         Self::Target: AsRepr,
-        Self::Backend: IoCapable<<Self::Target as AsRepr>::Repr>,
+        Self::Backend: IoWritable<<Self::Target as AsRepr>::Repr>,
     {
         Self::Backend::io_write(io_view_as_repr(self), 
Self::Target::into_repr(value))
     }
@@ -695,7 +701,7 @@ fn copy_to_slice(self, data: &mut [u8])
     fn try_read8(self, offset: usize) -> Result<u8>
     where
         usize: IoLoc<Self::Target, u8>,
-        Self::Backend: IoCapable<u8>,
+        Self::Backend: IoReadable<u8>,
     {
         self.try_read(offset)
     }
@@ -705,7 +711,7 @@ fn try_read8(self, offset: usize) -> Result<u8>
     fn try_read16(self, offset: usize) -> Result<u16>
     where
         usize: IoLoc<Self::Target, u16>,
-        Self::Backend: IoCapable<u16>,
+        Self::Backend: IoReadable<u16>,
     {
         self.try_read(offset)
     }
@@ -715,7 +721,7 @@ fn try_read16(self, offset: usize) -> Result<u16>
     fn try_read32(self, offset: usize) -> Result<u32>
     where
         usize: IoLoc<Self::Target, u32>,
-        Self::Backend: IoCapable<u32>,
+        Self::Backend: IoReadable<u32>,
     {
         self.try_read(offset)
     }
@@ -725,7 +731,7 @@ fn try_read32(self, offset: usize) -> Result<u32>
     fn try_read64(self, offset: usize) -> Result<u64>
     where
         usize: IoLoc<Self::Target, u64>,
-        Self::Backend: IoCapable<u64>,
+        Self::Backend: IoReadable<u64>,
     {
         self.try_read(offset)
     }
@@ -735,7 +741,7 @@ fn try_read64(self, offset: usize) -> Result<u64>
     fn try_write8(self, value: u8, offset: usize) -> Result
     where
         usize: IoLoc<Self::Target, u8>,
-        Self::Backend: IoCapable<u8>,
+        Self::Backend: IoWritable<u8>,
     {
         self.try_write(offset, value)
     }
@@ -745,7 +751,7 @@ fn try_write8(self, value: u8, offset: usize) -> Result
     fn try_write16(self, value: u16, offset: usize) -> Result
     where
         usize: IoLoc<Self::Target, u16>,
-        Self::Backend: IoCapable<u16>,
+        Self::Backend: IoWritable<u16>,
     {
         self.try_write(offset, value)
     }
@@ -755,7 +761,7 @@ fn try_write16(self, value: u16, offset: usize) -> Result
     fn try_write32(self, value: u32, offset: usize) -> Result
     where
         usize: IoLoc<Self::Target, u32>,
-        Self::Backend: IoCapable<u32>,
+        Self::Backend: IoWritable<u32>,
     {
         self.try_write(offset, value)
     }
@@ -765,7 +771,7 @@ fn try_write32(self, value: u32, offset: usize) -> Result
     fn try_write64(self, value: u64, offset: usize) -> Result
     where
         usize: IoLoc<Self::Target, u64>,
-        Self::Backend: IoCapable<u64>,
+        Self::Backend: IoWritable<u64>,
     {
         self.try_write(offset, value)
     }
@@ -777,7 +783,7 @@ fn try_write64(self, value: u64, offset: usize) -> Result
     fn read8(self, offset: usize) -> u8
     where
         usize: IoLoc<Self::Target, u8>,
-        Self::Backend: IoCapable<u8>,
+        Self::Backend: IoReadable<u8>,
     {
         self.read(offset)
     }
@@ -789,7 +795,7 @@ fn read8(self, offset: usize) -> u8
     fn read16(self, offset: usize) -> u16
     where
         usize: IoLoc<Self::Target, u16>,
-        Self::Backend: IoCapable<u16>,
+        Self::Backend: IoReadable<u16>,
     {
         self.read(offset)
     }
@@ -801,7 +807,7 @@ fn read16(self, offset: usize) -> u16
     fn read32(self, offset: usize) -> u32
     where
         usize: IoLoc<Self::Target, u32>,
-        Self::Backend: IoCapable<u32>,
+        Self::Backend: IoReadable<u32>,
     {
         self.read(offset)
     }
@@ -813,7 +819,7 @@ fn read32(self, offset: usize) -> u32
     fn read64(self, offset: usize) -> u64
     where
         usize: IoLoc<Self::Target, u64>,
-        Self::Backend: IoCapable<u64>,
+        Self::Backend: IoReadable<u64>,
     {
         self.read(offset)
     }
@@ -825,7 +831,7 @@ fn read64(self, offset: usize) -> u64
     fn write8(self, value: u8, offset: usize)
     where
         usize: IoLoc<Self::Target, u8>,
-        Self::Backend: IoCapable<u8>,
+        Self::Backend: IoWritable<u8>,
     {
         self.write(offset, value)
     }
@@ -837,7 +843,7 @@ fn write8(self, value: u8, offset: usize)
     fn write16(self, value: u16, offset: usize)
     where
         usize: IoLoc<Self::Target, u16>,
-        Self::Backend: IoCapable<u16>,
+        Self::Backend: IoWritable<u16>,
     {
         self.write(offset, value)
     }
@@ -849,7 +855,7 @@ fn write16(self, value: u16, offset: usize)
     fn write32(self, value: u32, offset: usize)
     where
         usize: IoLoc<Self::Target, u32>,
-        Self::Backend: IoCapable<u32>,
+        Self::Backend: IoWritable<u32>,
     {
         self.write(offset, value)
     }
@@ -861,7 +867,7 @@ fn write32(self, value: u32, offset: usize)
     fn write64(self, value: u64, offset: usize)
     where
         usize: IoLoc<Self::Target, u64>,
-        Self::Backend: IoCapable<u64>,
+        Self::Backend: IoWritable<u64>,
     {
         self.write(offset, value)
     }
@@ -894,7 +900,7 @@ fn try_read<T, L>(self, location: L) -> Result<T>
     where
         T: AsReprMut,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoReadable<<T as AsRepr>::Repr>,
     {
         Ok(io_read!(self, try: location))
     }
@@ -927,7 +933,7 @@ fn try_write<T, L>(self, location: L, value: T) -> Result
     where
         T: AsRepr,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoWritable<<T as AsRepr>::Repr>,
     {
         io_write!(self, try: location, value);
         Ok(())
@@ -973,7 +979,7 @@ fn try_write_reg<T, L, V>(self, value: V) -> Result
         T: AsRepr,
         L: IoLoc<Self::Target, T>,
         V: LocatedRegister<Self::Target, Location = L, Value = T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoWritable<<T as AsRepr>::Repr>,
     {
         let (location, value) = value.into_io_op();
 
@@ -1007,7 +1013,7 @@ fn try_update<T, L, F>(self, location: L, f: F) -> Result
     where
         T: AsReprMut,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoReadable<<T as AsRepr>::Repr> + IoWritable<<T as 
AsRepr>::Repr>,
         F: FnOnce(T) -> T,
     {
         let view = io_project!(self, try: location);
@@ -1041,7 +1047,7 @@ fn read<T, L>(self, location: L) -> T
     where
         T: AsReprMut,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoReadable<<T as AsRepr>::Repr>,
     {
         io_read!(self, build: location)
     }
@@ -1072,7 +1078,7 @@ fn write<T, L>(self, location: L, value: T)
     where
         T: AsRepr,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoWritable<<T as AsRepr>::Repr>,
     {
         io_write!(self, build: location, value);
     }
@@ -1116,7 +1122,7 @@ fn write_reg<T, L, V>(self, value: V)
         T: AsRepr,
         L: IoLoc<Self::Target, T>,
         V: LocatedRegister<Self::Target, Location = L, Value = T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoWritable<<T as AsRepr>::Repr>,
     {
         let (location, value) = value.into_io_op();
 
@@ -1150,7 +1156,7 @@ fn update<T, L, F>(self, location: L, f: F)
     where
         T: AsReprMut,
         L: IoLoc<Self::Target, T>,
-        Self::Backend: IoCapable<<T as AsRepr>::Repr>,
+        Self::Backend: IoReadable<<T as AsRepr>::Repr> + IoWritable<<T as 
AsRepr>::Repr>,
         F: FnOnce(T) -> T,
     {
         let view = io_project!(self, build: location);
@@ -1237,17 +1243,20 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     }
 }
 
-/// Implements [`IoCapable`] on `$backend` for `$ty` using `$read_fn` and 
`$write_fn`.
+/// Implements [`IoReadable`] and [`IoWritable`] on `$backend` for `$ty` using 
`$read_fn` and
+/// `$write_fn`.
 macro_rules! impl_mmio_io_capable {
     ($backend: ident, $ty:ty, $read_fn:ident, $write_fn:ident) => {
-        impl IoCapable<$ty> for $backend {
+        impl IoReadable<$ty> for $backend {
             #[inline]
             fn io_read(view: <$backend as IoBackend>::View<'_, $ty>) -> $ty {
                 // SAFETY: `$backend::as_ptr(view)` is a valid pointer for 
MMIO operations for both
                 // `MmioBackend` and `RelaxedMmioBackend`.
                 unsafe { 
bindings::$read_fn($backend::as_ptr(view).cast_const().cast()) }
             }
+        }
 
+        impl IoWritable<$ty> for $backend {
             #[inline]
             fn io_write(view: <$backend as IoBackend>::View<'_, $ty>, value: 
$ty) {
                 // SAFETY: `$backend::as_ptr(view)` is a valid pointer for 
MMIO operations for both
@@ -1396,11 +1405,11 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     }
 }
 
-/// Implements [`IoCapable`] on `SysMemBackend` for `$ty` using 
`read_volatile` and
-/// `write_volatile`.
+/// Implements [`IoReadable`] and [`IoWritable`] on `SysMemBackend` for `$ty` 
using
+/// `read_volatile` and `write_volatile`.
 macro_rules! impl_sysmem_io_capable {
     ($ty:ty) => {
-        impl IoCapable<$ty> for SysMemBackend {
+        impl IoReadable<$ty> for SysMemBackend {
             #[inline]
             fn io_read(view: SysMem<'_, $ty>) -> $ty {
                 // SAFETY:
@@ -1411,7 +1420,9 @@ fn io_read(view: SysMem<'_, $ty>) -> $ty {
                 // - The macro is only used on primitives so all bit patterns 
are valid.
                 unsafe { view.ptr.read_volatile() }
             }
+        }
 
+        impl IoWritable<$ty> for SysMemBackend {
             #[inline]
             fn io_write(view: SysMem<'_, $ty>, value: $ty) {
                 // SAFETY:
@@ -1601,10 +1612,10 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     }
 }
 
-impl<T> IoCapable<T> for IoSysMapBackend
+impl<T> IoReadable<T> for IoSysMapBackend
 where
-    MmioBackend: IoCapable<T>,
-    SysMemBackend: IoCapable<T>,
+    MmioBackend: IoReadable<T>,
+    SysMemBackend: IoReadable<T>,
 {
     #[inline]
     fn io_read(view: Self::View<'_, T>) -> T {
@@ -1613,7 +1624,13 @@ fn io_read(view: Self::View<'_, T>) -> T {
             IoSysMap::Sys(r) => SysMemBackend::io_read(r),
         }
     }
+}
 
+impl<T> IoWritable<T> for IoSysMapBackend
+where
+    MmioBackend: IoWritable<T>,
+    SysMemBackend: IoWritable<T>,
+{
     #[inline]
     fn io_write<'a>(view: Self::View<'a, T>, value: T) {
         match view {
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index 953e16735c6e..426e914e15c2 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -10,7 +10,8 @@
     io::{
         IoBackend,
         IoBase,
-        IoCapable,
+        IoReadable,
+        IoWritable,
         Mmio,
         MmioBackend,
         MmioRaw,
@@ -111,10 +112,11 @@ unsafe fn project_view<'a, T: ?Sized + KnownSize, U: 
?Sized + KnownSize>(
     }
 }
 
-/// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn` and 
`$write_fn`.
+/// Implements [`IoReadable`] and [`IoWritable`] on [`ConfigSpace`] for `$ty` 
using `$read_fn`
+/// and `$write_fn`.
 macro_rules! impl_config_space_io_capable {
     ($ty:ty, $read_fn:ident, $write_fn:ident) => {
-        impl IoCapable<$ty> for ConfigSpaceBackend {
+        impl IoReadable<$ty> for ConfigSpaceBackend {
             fn io_read(view: ConfigSpace<'_, $ty>) -> $ty {
                 // CAST: The offset is cast to `i32` because the C functions 
expect a 32-bit
                 // signed offset parameter. PCI configuration space size is at 
most 4096 bytes,
@@ -128,7 +130,9 @@ fn io_read(view: ConfigSpace<'_, $ty>) -> $ty {
                 let _ = unsafe { bindings::$read_fn(view.pdev.as_raw(), addr, 
&mut val) };
                 val
             }
+        }
 
+        impl IoWritable<$ty> for ConfigSpaceBackend {
             fn io_write(view: ConfigSpace<'_, $ty>, value: $ty) {
                 // CAST: The offset is cast to `i32` because the C functions 
expect a 32-bit
                 // signed offset parameter. PCI configuration space size is at 
most 4096 bytes,

-- 
2.56.0

Reply via email to