xref: /linux/rust/kernel/io.rs (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Memory-mapped IO.
4 //!
5 //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h)
6 
7 use crate::{
8     bindings,
9     prelude::*, //
10 };
11 
12 #[cfg(CONFIG_HAS_IOMEM)]
13 pub mod mem;
14 pub mod poll;
15 pub mod register;
16 pub mod resource;
17 
18 pub use crate::register;
19 pub use resource::Resource;
20 
21 use register::LocatedRegister;
22 
23 /// Physical address type.
24 ///
25 /// This is a type alias to either `u32` or `u64` depending on the config option
26 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
27 pub type PhysAddr = bindings::phys_addr_t;
28 
29 /// Resource Size type.
30 ///
31 /// This is a type alias to either `u32` or `u64` depending on the config option
32 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures.
33 pub type ResourceSize = bindings::resource_size_t;
34 
35 /// Raw representation of an MMIO region.
36 ///
37 /// By itself, the existence of an instance of this structure does not provide any guarantees that
38 /// the represented MMIO region does exist or is properly mapped.
39 ///
40 /// Instead, the bus specific MMIO implementation must convert this raw representation into an
41 /// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio`
42 /// structure any guarantees are given.
43 pub struct MmioRaw<const SIZE: usize = 0> {
44     addr: usize,
45     maxsize: usize,
46 }
47 
48 impl<const SIZE: usize> MmioRaw<SIZE> {
49     /// Returns a new `MmioRaw` instance on success, an error otherwise.
50     pub fn new(addr: usize, maxsize: usize) -> Result<Self> {
51         if maxsize < SIZE {
52             return Err(EINVAL);
53         }
54 
55         Ok(Self { addr, maxsize })
56     }
57 
58     /// Returns the base address of the MMIO region.
59     #[inline]
60     pub fn addr(&self) -> usize {
61         self.addr
62     }
63 
64     /// Returns the maximum size of the MMIO region.
65     #[inline]
66     pub fn maxsize(&self) -> usize {
67         self.maxsize
68     }
69 }
70 
71 /// IO-mapped memory region.
72 ///
73 /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the
74 /// mapping, performing an additional region request etc.
75 ///
76 /// # Invariant
77 ///
78 /// `addr` is the start and `maxsize` the length of valid I/O mapped memory region of size
79 /// `maxsize`.
80 ///
81 /// # Examples
82 ///
83 /// ```no_run
84 /// # #![cfg(CONFIG_HAS_IOMEM)]
85 /// use kernel::{
86 ///     bindings,
87 ///     ffi::c_void,
88 ///     io::{
89 ///         Io,
90 ///         IoKnownSize,
91 ///         Mmio,
92 ///         MmioRaw,
93 ///         PhysAddr,
94 ///     },
95 /// };
96 /// use core::ops::Deref;
97 ///
98 /// // See also `pci::Bar` for a real example.
99 /// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>);
100 ///
101 /// impl<const SIZE: usize> IoMem<SIZE> {
102 ///     /// # Safety
103 ///     ///
104 ///     /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs
105 ///     /// virtual address space.
106 ///     unsafe fn new(paddr: usize) -> Result<Self>{
107 ///         // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
108 ///         // valid for `ioremap`.
109 ///         let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) };
110 ///         if addr.is_null() {
111 ///             return Err(ENOMEM);
112 ///         }
113 ///
114 ///         Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?))
115 ///     }
116 /// }
117 ///
118 /// impl<const SIZE: usize> Drop for IoMem<SIZE> {
119 ///     fn drop(&mut self) {
120 ///         // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
121 ///         unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
122 ///     }
123 /// }
124 ///
125 /// impl<const SIZE: usize> Deref for IoMem<SIZE> {
126 ///    type Target = Mmio<SIZE>;
127 ///
128 ///    fn deref(&self) -> &Self::Target {
129 ///         // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
130 ///         unsafe { Mmio::from_raw(&self.0) }
131 ///    }
132 /// }
133 ///
134 ///# fn no_run() -> Result<(), Error> {
135 /// // SAFETY: Invalid usage for example purposes.
136 /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
137 /// iomem.write32(0x42, 0x0);
138 /// assert!(iomem.try_write32(0x42, 0x0).is_ok());
139 /// assert!(iomem.try_write32(0x42, 0x4).is_err());
140 /// # Ok(())
141 /// # }
142 /// ```
143 #[repr(transparent)]
144 pub struct Mmio<const SIZE: usize = 0>(MmioRaw<SIZE>);
145 
146 /// Checks whether an access of type `U` at the given `offset`
147 /// is valid within this region.
148 #[inline]
149 const fn offset_valid<U>(offset: usize, size: usize) -> bool {
150     let type_size = core::mem::size_of::<U>();
151     if let Some(end) = offset.checked_add(type_size) {
152         end <= size && offset % type_size == 0
153     } else {
154         false
155     }
156 }
157 
158 /// Trait indicating that an I/O backend supports operations of a certain type and providing an
159 /// implementation for these operations.
160 ///
161 /// Different I/O backends can implement this trait to expose only the operations they support.
162 ///
163 /// For example, a PCI configuration space may implement `IoCapable<u8>`, `IoCapable<u16>`,
164 /// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 64-bit
165 /// system might implement all four.
166 pub trait IoCapable<T> {
167     /// Performs an I/O read of type `T` at `address` and returns the result.
168     ///
169     /// # Safety
170     ///
171     /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`.
172     unsafe fn io_read(&self, address: usize) -> T;
173 
174     /// Performs an I/O write of `value` at `address`.
175     ///
176     /// # Safety
177     ///
178     /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`.
179     unsafe fn io_write(&self, value: T, address: usize);
180 }
181 
182 /// Describes a given I/O location: its offset, width, and type to convert the raw value from and
183 /// into.
184 ///
185 /// This trait is the key abstraction allowing [`Io::read`], [`Io::write`], and [`Io::update`] (and
186 /// their fallible [`try_read`](Io::try_read), [`try_write`](Io::try_write) and
187 /// [`try_update`](Io::try_update) counterparts) to work uniformly with both raw [`usize`] offsets
188 /// (for primitive types like [`u32`]) and typed ones (like those generated by the [`register!`]
189 /// macro).
190 ///
191 /// An `IoLoc<T>` carries three pieces of information:
192 ///
193 /// - The offset to access (returned by [`IoLoc::offset`]),
194 /// - The width of the access (determined by [`IoLoc::IoType`]),
195 /// - The type `T` in which the raw data is returned or provided.
196 ///
197 /// `T` and `IoLoc::IoType` may differ: for instance, a typed register has `T` = the register type
198 /// with its bitfields, and `IoType` = its backing primitive (e.g. `u32`).
199 pub trait IoLoc<T> {
200     /// Size ([`u8`], [`u16`], etc) of the I/O performed on the returned [`offset`](IoLoc::offset).
201     type IoType: Into<T> + From<T>;
202 
203     /// Consumes `self` and returns the offset of this location.
204     fn offset(self) -> usize;
205 }
206 
207 /// Implements [`IoLoc<$ty>`] for [`usize`], allowing [`usize`] to be used as a parameter of
208 /// [`Io::read`] and [`Io::write`].
209 macro_rules! impl_usize_ioloc {
210     ($($ty:ty),*) => {
211         $(
212             impl IoLoc<$ty> for usize {
213                 type IoType = $ty;
214 
215                 #[inline(always)]
216                 fn offset(self) -> usize {
217                     self
218                 }
219             }
220         )*
221     }
222 }
223 
224 // Provide the ability to read any primitive type from a [`usize`].
225 impl_usize_ioloc!(u8, u16, u32, u64);
226 
227 /// Types implementing this trait (e.g. MMIO BARs or PCI config regions)
228 /// can perform I/O operations on regions of memory.
229 ///
230 /// This is an abstract representation to be implemented by arbitrary I/O
231 /// backends (e.g. MMIO, PCI config space, etc.).
232 ///
233 /// The [`Io`] trait provides:
234 /// - Base address and size information
235 /// - Helper methods for offset validation and address calculation
236 /// - Fallible (runtime checked) accessors for different data widths
237 ///
238 /// Which I/O methods are available depends on which [`IoCapable<T>`] traits
239 /// are implemented for the type.
240 ///
241 /// # Examples
242 ///
243 /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems) are typically
244 /// supported. For PCI configuration space, u8, u16, and u32 are supported but u64 is not.
245 pub trait Io {
246     /// Returns the base address of this mapping.
247     fn addr(&self) -> usize;
248 
249     /// Returns the maximum size of this mapping.
250     fn maxsize(&self) -> usize;
251 
252     /// Returns the absolute I/O address for a given `offset`,
253     /// performing runtime bound checks.
254     #[inline]
255     fn io_addr<U>(&self, offset: usize) -> Result<usize> {
256         if !offset_valid::<U>(offset, self.maxsize()) {
257             return Err(EINVAL);
258         }
259 
260         // Probably no need to check, since the safety requirements of `Self::new` guarantee that
261         // this can't overflow.
262         self.addr().checked_add(offset).ok_or(EINVAL)
263     }
264 
265     /// Fallible 8-bit read with runtime bounds check.
266     #[inline(always)]
267     fn try_read8(&self, offset: usize) -> Result<u8>
268     where
269         Self: IoCapable<u8>,
270     {
271         self.try_read(offset)
272     }
273 
274     /// Fallible 16-bit read with runtime bounds check.
275     #[inline(always)]
276     fn try_read16(&self, offset: usize) -> Result<u16>
277     where
278         Self: IoCapable<u16>,
279     {
280         self.try_read(offset)
281     }
282 
283     /// Fallible 32-bit read with runtime bounds check.
284     #[inline(always)]
285     fn try_read32(&self, offset: usize) -> Result<u32>
286     where
287         Self: IoCapable<u32>,
288     {
289         self.try_read(offset)
290     }
291 
292     /// Fallible 64-bit read with runtime bounds check.
293     #[inline(always)]
294     fn try_read64(&self, offset: usize) -> Result<u64>
295     where
296         Self: IoCapable<u64>,
297     {
298         self.try_read(offset)
299     }
300 
301     /// Fallible 8-bit write with runtime bounds check.
302     #[inline(always)]
303     fn try_write8(&self, value: u8, offset: usize) -> Result
304     where
305         Self: IoCapable<u8>,
306     {
307         self.try_write(offset, value)
308     }
309 
310     /// Fallible 16-bit write with runtime bounds check.
311     #[inline(always)]
312     fn try_write16(&self, value: u16, offset: usize) -> Result
313     where
314         Self: IoCapable<u16>,
315     {
316         self.try_write(offset, value)
317     }
318 
319     /// Fallible 32-bit write with runtime bounds check.
320     #[inline(always)]
321     fn try_write32(&self, value: u32, offset: usize) -> Result
322     where
323         Self: IoCapable<u32>,
324     {
325         self.try_write(offset, value)
326     }
327 
328     /// Fallible 64-bit write with runtime bounds check.
329     #[inline(always)]
330     fn try_write64(&self, value: u64, offset: usize) -> Result
331     where
332         Self: IoCapable<u64>,
333     {
334         self.try_write(offset, value)
335     }
336 
337     /// Infallible 8-bit read with compile-time bounds check.
338     #[inline(always)]
339     fn read8(&self, offset: usize) -> u8
340     where
341         Self: IoKnownSize + IoCapable<u8>,
342     {
343         self.read(offset)
344     }
345 
346     /// Infallible 16-bit read with compile-time bounds check.
347     #[inline(always)]
348     fn read16(&self, offset: usize) -> u16
349     where
350         Self: IoKnownSize + IoCapable<u16>,
351     {
352         self.read(offset)
353     }
354 
355     /// Infallible 32-bit read with compile-time bounds check.
356     #[inline(always)]
357     fn read32(&self, offset: usize) -> u32
358     where
359         Self: IoKnownSize + IoCapable<u32>,
360     {
361         self.read(offset)
362     }
363 
364     /// Infallible 64-bit read with compile-time bounds check.
365     #[inline(always)]
366     fn read64(&self, offset: usize) -> u64
367     where
368         Self: IoKnownSize + IoCapable<u64>,
369     {
370         self.read(offset)
371     }
372 
373     /// Infallible 8-bit write with compile-time bounds check.
374     #[inline(always)]
375     fn write8(&self, value: u8, offset: usize)
376     where
377         Self: IoKnownSize + IoCapable<u8>,
378     {
379         self.write(offset, value)
380     }
381 
382     /// Infallible 16-bit write with compile-time bounds check.
383     #[inline(always)]
384     fn write16(&self, value: u16, offset: usize)
385     where
386         Self: IoKnownSize + IoCapable<u16>,
387     {
388         self.write(offset, value)
389     }
390 
391     /// Infallible 32-bit write with compile-time bounds check.
392     #[inline(always)]
393     fn write32(&self, value: u32, offset: usize)
394     where
395         Self: IoKnownSize + IoCapable<u32>,
396     {
397         self.write(offset, value)
398     }
399 
400     /// Infallible 64-bit write with compile-time bounds check.
401     #[inline(always)]
402     fn write64(&self, value: u64, offset: usize)
403     where
404         Self: IoKnownSize + IoCapable<u64>,
405     {
406         self.write(offset, value)
407     }
408 
409     /// Generic fallible read with runtime bounds check.
410     ///
411     /// # Examples
412     ///
413     /// Read a primitive type from an I/O address:
414     ///
415     /// ```no_run
416     /// use kernel::io::{
417     ///     Io,
418     ///     Mmio,
419     /// };
420     ///
421     /// fn do_reads(io: &Mmio) -> Result {
422     ///     // 32-bit read from address `0x10`.
423     ///     let v: u32 = io.try_read(0x10)?;
424     ///
425     ///     // 8-bit read from address `0xfff`.
426     ///     let v: u8 = io.try_read(0xfff)?;
427     ///
428     ///     Ok(())
429     /// }
430     /// ```
431     #[inline(always)]
432     fn try_read<T, L>(&self, location: L) -> Result<T>
433     where
434         L: IoLoc<T>,
435         Self: IoCapable<L::IoType>,
436     {
437         let address = self.io_addr::<L::IoType>(location.offset())?;
438 
439         // SAFETY: `address` has been validated by `io_addr`.
440         Ok(unsafe { self.io_read(address) }.into())
441     }
442 
443     /// Generic fallible write with runtime bounds check.
444     ///
445     /// # Examples
446     ///
447     /// Write a primitive type to an I/O address:
448     ///
449     /// ```no_run
450     /// use kernel::io::{
451     ///     Io,
452     ///     Mmio,
453     /// };
454     ///
455     /// fn do_writes(io: &Mmio) -> Result {
456     ///     // 32-bit write of value `1` at address `0x10`.
457     ///     io.try_write(0x10, 1u32)?;
458     ///
459     ///     // 8-bit write of value `0xff` at address `0xfff`.
460     ///     io.try_write(0xfff, 0xffu8)?;
461     ///
462     ///     Ok(())
463     /// }
464     /// ```
465     #[inline(always)]
466     fn try_write<T, L>(&self, location: L, value: T) -> Result
467     where
468         L: IoLoc<T>,
469         Self: IoCapable<L::IoType>,
470     {
471         let address = self.io_addr::<L::IoType>(location.offset())?;
472         let io_value = value.into();
473 
474         // SAFETY: `address` has been validated by `io_addr`.
475         unsafe { self.io_write(io_value, address) }
476 
477         Ok(())
478     }
479 
480     /// Generic fallible write of a fully-located register value.
481     ///
482     /// # Examples
483     ///
484     /// Tuples carrying a location and a value can be used with this method:
485     ///
486     /// ```no_run
487     /// use kernel::io::{
488     ///     register,
489     ///     Io,
490     ///     Mmio,
491     /// };
492     ///
493     /// register! {
494     ///     VERSION(u32) @ 0x100 {
495     ///         15:8 major;
496     ///         7:0  minor;
497     ///     }
498     /// }
499     ///
500     /// impl VERSION {
501     ///     fn new(major: u8, minor: u8) -> Self {
502     ///         VERSION::zeroed().with_major(major).with_minor(minor)
503     ///     }
504     /// }
505     ///
506     /// fn do_write_reg(io: &Mmio) -> Result {
507     ///
508     ///     io.try_write_reg(VERSION::new(1, 0))
509     /// }
510     /// ```
511     #[inline(always)]
512     fn try_write_reg<T, L, V>(&self, value: V) -> Result
513     where
514         L: IoLoc<T>,
515         V: LocatedRegister<Location = L, Value = T>,
516         Self: IoCapable<L::IoType>,
517     {
518         let (location, value) = value.into_io_op();
519 
520         self.try_write(location, value)
521     }
522 
523     /// Generic fallible update with runtime bounds check.
524     ///
525     /// Note: this does not perform any synchronization. The caller is responsible for ensuring
526     /// exclusive access if required.
527     ///
528     /// # Examples
529     ///
530     /// Read the u32 value at address `0x10`, increment it, and store the updated value back:
531     ///
532     /// ```no_run
533     /// use kernel::io::{
534     ///     Io,
535     ///     Mmio,
536     /// };
537     ///
538     /// fn do_update(io: &Mmio<0x1000>) -> Result {
539     ///     io.try_update(0x10, |v: u32| {
540     ///         v + 1
541     ///     })
542     /// }
543     /// ```
544     #[inline(always)]
545     fn try_update<T, L, F>(&self, location: L, f: F) -> Result
546     where
547         L: IoLoc<T>,
548         Self: IoCapable<L::IoType>,
549         F: FnOnce(T) -> T,
550     {
551         let address = self.io_addr::<L::IoType>(location.offset())?;
552 
553         // SAFETY: `address` has been validated by `io_addr`.
554         let value: T = unsafe { self.io_read(address) }.into();
555         let io_value = f(value).into();
556 
557         // SAFETY: `address` has been validated by `io_addr`.
558         unsafe { self.io_write(io_value, address) }
559 
560         Ok(())
561     }
562 
563     /// Generic infallible read with compile-time bounds check.
564     ///
565     /// # Examples
566     ///
567     /// Read a primitive type from an I/O address:
568     ///
569     /// ```no_run
570     /// use kernel::io::{
571     ///     Io,
572     ///     Mmio,
573     /// };
574     ///
575     /// fn do_reads(io: &Mmio<0x1000>) {
576     ///     // 32-bit read from address `0x10`.
577     ///     let v: u32 = io.read(0x10);
578     ///
579     ///     // 8-bit read from the top of the I/O space.
580     ///     let v: u8 = io.read(0xfff);
581     /// }
582     /// ```
583     #[inline(always)]
584     fn read<T, L>(&self, location: L) -> T
585     where
586         L: IoLoc<T>,
587         Self: IoKnownSize + IoCapable<L::IoType>,
588     {
589         let address = self.io_addr_assert::<L::IoType>(location.offset());
590 
591         // SAFETY: `address` has been validated by `io_addr_assert`.
592         unsafe { self.io_read(address) }.into()
593     }
594 
595     /// Generic infallible write with compile-time bounds check.
596     ///
597     /// # Examples
598     ///
599     /// Write a primitive type to an I/O address:
600     ///
601     /// ```no_run
602     /// use kernel::io::{
603     ///     Io,
604     ///     Mmio,
605     /// };
606     ///
607     /// fn do_writes(io: &Mmio<0x1000>) {
608     ///     // 32-bit write of value `1` at address `0x10`.
609     ///     io.write(0x10, 1u32);
610     ///
611     ///     // 8-bit write of value `0xff` at the top of the I/O space.
612     ///     io.write(0xfff, 0xffu8);
613     /// }
614     /// ```
615     #[inline(always)]
616     fn write<T, L>(&self, location: L, value: T)
617     where
618         L: IoLoc<T>,
619         Self: IoKnownSize + IoCapable<L::IoType>,
620     {
621         let address = self.io_addr_assert::<L::IoType>(location.offset());
622         let io_value = value.into();
623 
624         // SAFETY: `address` has been validated by `io_addr_assert`.
625         unsafe { self.io_write(io_value, address) }
626     }
627 
628     /// Generic infallible write of a fully-located register value.
629     ///
630     /// # Examples
631     ///
632     /// Tuples carrying a location and a value can be used with this method:
633     ///
634     /// ```no_run
635     /// use kernel::io::{
636     ///     register,
637     ///     Io,
638     ///     Mmio,
639     /// };
640     ///
641     /// register! {
642     ///     VERSION(u32) @ 0x100 {
643     ///         15:8 major;
644     ///         7:0  minor;
645     ///     }
646     /// }
647     ///
648     /// impl VERSION {
649     ///     fn new(major: u8, minor: u8) -> Self {
650     ///         VERSION::zeroed().with_major(major).with_minor(minor)
651     ///     }
652     /// }
653     ///
654     /// fn do_write_reg(io: &Mmio<0x1000>) {
655     ///     io.write_reg(VERSION::new(1, 0));
656     /// }
657     /// ```
658     #[inline(always)]
659     fn write_reg<T, L, V>(&self, value: V)
660     where
661         L: IoLoc<T>,
662         V: LocatedRegister<Location = L, Value = T>,
663         Self: IoKnownSize + IoCapable<L::IoType>,
664     {
665         let (location, value) = value.into_io_op();
666 
667         self.write(location, value)
668     }
669 
670     /// Generic infallible update with compile-time bounds check.
671     ///
672     /// Note: this does not perform any synchronization. The caller is responsible for ensuring
673     /// exclusive access if required.
674     ///
675     /// # Examples
676     ///
677     /// Read the u32 value at address `0x10`, increment it, and store the updated value back:
678     ///
679     /// ```no_run
680     /// use kernel::io::{
681     ///     Io,
682     ///     Mmio,
683     /// };
684     ///
685     /// fn do_update(io: &Mmio<0x1000>) {
686     ///     io.update(0x10, |v: u32| {
687     ///         v + 1
688     ///     })
689     /// }
690     /// ```
691     #[inline(always)]
692     fn update<T, L, F>(&self, location: L, f: F)
693     where
694         L: IoLoc<T>,
695         Self: IoKnownSize + IoCapable<L::IoType> + Sized,
696         F: FnOnce(T) -> T,
697     {
698         let address = self.io_addr_assert::<L::IoType>(location.offset());
699 
700         // SAFETY: `address` has been validated by `io_addr_assert`.
701         let value: T = unsafe { self.io_read(address) }.into();
702         let io_value = f(value).into();
703 
704         // SAFETY: `address` has been validated by `io_addr_assert`.
705         unsafe { self.io_write(io_value, address) }
706     }
707 }
708 
709 /// Trait for types with a known size at compile time.
710 ///
711 /// This trait is implemented by I/O backends that have a compile-time known size,
712 /// enabling the use of infallible I/O accessors with compile-time bounds checking.
713 ///
714 /// Types implementing this trait can use the infallible methods in [`Io`] trait
715 /// (e.g., `read8`, `write32`), which require `Self: IoKnownSize` bound.
716 pub trait IoKnownSize: Io {
717     /// Minimum usable size of this region.
718     const MIN_SIZE: usize;
719 
720     /// Returns the absolute I/O address for a given `offset`,
721     /// performing compile-time bound checks.
722     // Always inline to optimize out error path of `build_assert`.
723     #[inline(always)]
724     fn io_addr_assert<U>(&self, offset: usize) -> usize {
725         build_assert!(offset_valid::<U>(offset, Self::MIN_SIZE));
726 
727         self.addr() + offset
728     }
729 }
730 
731 /// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$write_fn`.
732 macro_rules! impl_mmio_io_capable {
733     ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:ident) => {
734         $(#[$attr])*
735         impl<const SIZE: usize> IoCapable<$ty> for $mmio<SIZE> {
736             unsafe fn io_read(&self, address: usize) -> $ty {
737                 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations.
738                 unsafe { bindings::$read_fn(address as *const c_void) }
739             }
740 
741             unsafe fn io_write(&self, value: $ty, address: usize) {
742                 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations.
743                 unsafe { bindings::$write_fn(value, address as *mut c_void) }
744             }
745         }
746     };
747 }
748 
749 // MMIO regions support 8, 16, and 32-bit accesses.
750 impl_mmio_io_capable!(Mmio, u8, readb, writeb);
751 impl_mmio_io_capable!(Mmio, u16, readw, writew);
752 impl_mmio_io_capable!(Mmio, u32, readl, writel);
753 // MMIO regions on 64-bit systems also support 64-bit accesses.
754 impl_mmio_io_capable!(
755     Mmio,
756     #[cfg(CONFIG_64BIT)]
757     u64,
758     readq,
759     writeq
760 );
761 
762 impl<const SIZE: usize> Io for Mmio<SIZE> {
763     /// Returns the base address of this mapping.
764     #[inline]
765     fn addr(&self) -> usize {
766         self.0.addr()
767     }
768 
769     /// Returns the maximum size of this mapping.
770     #[inline]
771     fn maxsize(&self) -> usize {
772         self.0.maxsize()
773     }
774 }
775 
776 impl<const SIZE: usize> IoKnownSize for Mmio<SIZE> {
777     const MIN_SIZE: usize = SIZE;
778 }
779 
780 impl<const SIZE: usize> Mmio<SIZE> {
781     /// Converts an `MmioRaw` into an `Mmio` instance, providing the accessors to the MMIO mapping.
782     ///
783     /// # Safety
784     ///
785     /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size
786     /// `maxsize`.
787     pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self {
788         // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`.
789         unsafe { &*core::ptr::from_ref(raw).cast() }
790     }
791 }
792 
793 /// [`Mmio`] wrapper using relaxed accessors.
794 ///
795 /// This type provides an implementation of [`Io`] that uses relaxed I/O MMIO operands instead of
796 /// the regular ones.
797 ///
798 /// See [`Mmio::relaxed`] for a usage example.
799 #[repr(transparent)]
800 pub struct RelaxedMmio<const SIZE: usize = 0>(Mmio<SIZE>);
801 
802 impl<const SIZE: usize> Io for RelaxedMmio<SIZE> {
803     #[inline]
804     fn addr(&self) -> usize {
805         self.0.addr()
806     }
807 
808     #[inline]
809     fn maxsize(&self) -> usize {
810         self.0.maxsize()
811     }
812 }
813 
814 impl<const SIZE: usize> IoKnownSize for RelaxedMmio<SIZE> {
815     const MIN_SIZE: usize = SIZE;
816 }
817 
818 impl<const SIZE: usize> Mmio<SIZE> {
819     /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O operations.
820     ///
821     /// Relaxed accessors do not provide ordering guarantees with respect to DMA or memory accesses
822     /// and can be used when such ordering is not required.
823     ///
824     /// # Examples
825     ///
826     /// ```no_run
827     /// use kernel::io::{
828     ///     Io,
829     ///     Mmio,
830     ///     RelaxedMmio,
831     /// };
832     ///
833     /// fn do_io(io: &Mmio<0x100>) {
834     ///     // The access is performed using `readl_relaxed` instead of `readl`.
835     ///     let v = io.relaxed().read32(0x10);
836     /// }
837     ///
838     /// ```
839     pub fn relaxed(&self) -> &RelaxedMmio<SIZE> {
840         // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `Mmio`, so `Mmio<SIZE>` and
841         // `RelaxedMmio<SIZE>` have identical layout.
842         unsafe { core::mem::transmute(self) }
843     }
844 }
845 
846 // MMIO regions support 8, 16, and 32-bit accesses.
847 impl_mmio_io_capable!(RelaxedMmio, u8, readb_relaxed, writeb_relaxed);
848 impl_mmio_io_capable!(RelaxedMmio, u16, readw_relaxed, writew_relaxed);
849 impl_mmio_io_capable!(RelaxedMmio, u32, readl_relaxed, writel_relaxed);
850 // MMIO regions on 64-bit systems also support 64-bit accesses.
851 impl_mmio_io_capable!(
852     RelaxedMmio,
853     #[cfg(CONFIG_64BIT)]
854     u64,
855     readq_relaxed,
856     writeq_relaxed
857 );
858