Commit 121d87b2 authored by Zhi Wang's avatar Zhi Wang Committed by Danilo Krummrich
Browse files

rust: io: separate generic I/O helpers from MMIO implementation



The previous Io<SIZE> type combined both the generic I/O access helpers
and MMIO implementation details in a single struct. This coupling prevented
reusing the I/O helpers for other backends, such as PCI configuration
space.

Establish a clean separation between the I/O interface and concrete
backends by separating generic I/O helpers from MMIO implementation.

Introduce a new trait hierarchy to handle different access capabilities:

- IoCapable<T>: A marker trait indicating that a backend supports I/O
  operations of a certain type (u8, u16, u32, or u64).

- Io trait: Defines fallible (try_read8, try_write8, etc.) and infallibile
  (read8, write8, etc.) I/O methods with runtime bounds checking and
  compile-time bounds checking.

- IoKnownSize trait: The marker trait for types support infallible I/O
  methods.

Move the MMIO-specific logic into a dedicated Mmio<SIZE> type that
implements the Io traits. Rename IoRaw to MmioRaw and update consumers to
use the new types.

Cc: Alexandre Courbot <acourbot@nvidia.com>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Bjorn Helgaas <helgaas@kernel.org>
Cc: Gary Guo <gary@garyguo.net>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Signed-off-by: default avatarZhi Wang <zhiw@nvidia.com>
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Reviewed-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Reviewed-by: default avatarGary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260121202212.4438-3-zhiw@nvidia.com


[ Add #[expect(unused)] to define_{read,write}!(). - Danilo ]
Signed-off-by: default avatarDanilo Krummrich <dakr@kernel.org>
parent 7043698a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
use kernel::device::Bound;
use kernel::device::Device;
use kernel::devres::Devres;
use kernel::io::Io;
use kernel::prelude::*;

use crate::driver::IoMem;
+4 −1
Original line number Diff line number Diff line
@@ -12,7 +12,10 @@

use kernel::{
    device,
    io::poll::read_poll_timeout,
    io::{
        poll::read_poll_timeout,
        Io, //
    },
    prelude::*,
    time::{
        delay::fsleep,
+54 −36
Original line number Diff line number Diff line
@@ -369,16 +369,18 @@ impl $name {

            /// Read the register from its address in `io`.
            #[inline(always)]
            pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
            pub(crate) fn read<T, I>(io: &T) -> Self where
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                Self(io.read32($offset))
            }

            /// Write the value contained in `self` to the register address in `io`.
            #[inline(always)]
            pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
            pub(crate) fn write<T, I>(self, io: &T) where
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                io.write32(self.0, $offset)
            }
@@ -386,11 +388,12 @@ pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where
            /// Read the register from its address in `io` and run `f` on its value to obtain a new
            /// value to write back.
            #[inline(always)]
            pub(crate) fn update<const SIZE: usize, T, F>(
            pub(crate) fn update<T, I, F>(
                io: &T,
                f: F,
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
                let reg = f(Self::read(io));
@@ -408,12 +411,13 @@ impl $name {
            /// Read the register from `io`, using the base address provided by `base` and adding
            /// the register's offset to it.
            #[inline(always)]
            pub(crate) fn read<const SIZE: usize, T, B>(
            pub(crate) fn read<T, I, B>(
                io: &T,
                #[allow(unused_variables)]
                base: &B,
            ) -> Self where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                const OFFSET: usize = $name::OFFSET;
@@ -428,13 +432,14 @@ pub(crate) fn read<const SIZE: usize, T, B>(
            /// Write the value contained in `self` to `io`, using the base address provided by
            /// `base` and adding the register's offset to it.
            #[inline(always)]
            pub(crate) fn write<const SIZE: usize, T, B>(
            pub(crate) fn write<T, I, B>(
                self,
                io: &T,
                #[allow(unused_variables)]
                base: &B,
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                const OFFSET: usize = $name::OFFSET;
@@ -449,12 +454,13 @@ pub(crate) fn write<const SIZE: usize, T, B>(
            /// the register's offset to it, then run `f` on its value to obtain a new value to
            /// write back.
            #[inline(always)]
            pub(crate) fn update<const SIZE: usize, T, B, F>(
            pub(crate) fn update<T, I, B, F>(
                io: &T,
                base: &B,
                f: F,
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
@@ -474,11 +480,12 @@ impl $name {

            /// Read the array register at index `idx` from its address in `io`.
            #[inline(always)]
            pub(crate) fn read<const SIZE: usize, T>(
            pub(crate) fn read<T, I>(
                io: &T,
                idx: usize,
            ) -> Self where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                build_assert!(idx < Self::SIZE);

@@ -490,12 +497,13 @@ pub(crate) fn read<const SIZE: usize, T>(

            /// Write the value contained in `self` to the array register with index `idx` in `io`.
            #[inline(always)]
            pub(crate) fn write<const SIZE: usize, T>(
            pub(crate) fn write<T, I>(
                self,
                io: &T,
                idx: usize
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                build_assert!(idx < Self::SIZE);

@@ -507,12 +515,13 @@ pub(crate) fn write<const SIZE: usize, T>(
            /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a
            /// new value to write back.
            #[inline(always)]
            pub(crate) fn update<const SIZE: usize, T, F>(
            pub(crate) fn update<T, I, F>(
                io: &T,
                idx: usize,
                f: F,
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
                let reg = f(Self::read(io, idx));
@@ -524,11 +533,12 @@ pub(crate) fn update<const SIZE: usize, T, F>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_read<const SIZE: usize, T>(
            pub(crate) fn try_read<T, I>(
                io: &T,
                idx: usize,
            ) -> ::kernel::error::Result<Self> where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                if idx < Self::SIZE {
                    Ok(Self::read(io, idx))
@@ -542,12 +552,13 @@ pub(crate) fn try_read<const SIZE: usize, T>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_write<const SIZE: usize, T>(
            pub(crate) fn try_write<T, I>(
                self,
                io: &T,
                idx: usize,
            ) -> ::kernel::error::Result where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
            {
                if idx < Self::SIZE {
                    Ok(self.write(io, idx))
@@ -562,12 +573,13 @@ pub(crate) fn try_write<const SIZE: usize, T>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_update<const SIZE: usize, T, F>(
            pub(crate) fn try_update<T, I, F>(
                io: &T,
                idx: usize,
                f: F,
            ) -> ::kernel::error::Result where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
                if idx < Self::SIZE {
@@ -593,13 +605,14 @@ impl $name {
            /// Read the array register at index `idx` from `io`, using the base address provided
            /// by `base` and adding the register's offset to it.
            #[inline(always)]
            pub(crate) fn read<const SIZE: usize, T, B>(
            pub(crate) fn read<T, I, B>(
                io: &T,
                #[allow(unused_variables)]
                base: &B,
                idx: usize,
            ) -> Self where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                build_assert!(idx < Self::SIZE);
@@ -614,14 +627,15 @@ pub(crate) fn read<const SIZE: usize, T, B>(
            /// Write the value contained in `self` to `io`, using the base address provided by
            /// `base` and adding the offset of array register `idx` to it.
            #[inline(always)]
            pub(crate) fn write<const SIZE: usize, T, B>(
            pub(crate) fn write<T, I, B>(
                self,
                io: &T,
                #[allow(unused_variables)]
                base: &B,
                idx: usize
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                build_assert!(idx < Self::SIZE);
@@ -636,13 +650,14 @@ pub(crate) fn write<const SIZE: usize, T, B>(
            /// by `base` and adding the register's offset to it, then run `f` on its value to
            /// obtain a new value to write back.
            #[inline(always)]
            pub(crate) fn update<const SIZE: usize, T, B, F>(
            pub(crate) fn update<T, I, B, F>(
                io: &T,
                base: &B,
                idx: usize,
                f: F,
            ) where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
@@ -656,12 +671,13 @@ pub(crate) fn update<const SIZE: usize, T, B, F>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_read<const SIZE: usize, T, B>(
            pub(crate) fn try_read<T, I, B>(
                io: &T,
                base: &B,
                idx: usize,
            ) -> ::kernel::error::Result<Self> where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                if idx < Self::SIZE {
@@ -677,13 +693,14 @@ pub(crate) fn try_read<const SIZE: usize, T, B>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_write<const SIZE: usize, T, B>(
            pub(crate) fn try_write<T, I, B>(
                self,
                io: &T,
                base: &B,
                idx: usize,
            ) -> ::kernel::error::Result where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
            {
                if idx < Self::SIZE {
@@ -700,13 +717,14 @@ pub(crate) fn try_write<const SIZE: usize, T, B>(
            /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
            /// access was out-of-bounds.
            #[inline(always)]
            pub(crate) fn try_update<const SIZE: usize, T, B, F>(
            pub(crate) fn try_update<T, I, B, F>(
                io: &T,
                base: &B,
                idx: usize,
                f: F,
            ) -> ::kernel::error::Result where
                T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
                T: ::core::ops::Deref<Target = I>,
                I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>,
                B: crate::regs::macros::RegisterBase<$base>,
                F: ::core::ops::FnOnce(Self) -> Self,
            {
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

use kernel::{
    device,
    io::Io,
    prelude::*,
    ptr::{
        Alignable,
+4 −1
Original line number Diff line number Diff line
@@ -26,7 +26,10 @@
    clk::Clk,
    device::{Bound, Core, Device},
    devres,
    io::mem::IoMem,
    io::{
        mem::IoMem,
        Io, //
    },
    of, platform,
    prelude::*,
    pwm, time,
Loading