xref: /linux/rust/kernel/io.rs (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1ce30d94eSDanilo Krummrich // SPDX-License-Identifier: GPL-2.0
2ce30d94eSDanilo Krummrich 
3ce30d94eSDanilo Krummrich //! Memory-mapped IO.
4ce30d94eSDanilo Krummrich //!
5ce30d94eSDanilo Krummrich //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h)
6ce30d94eSDanilo Krummrich 
7ce30d94eSDanilo Krummrich use crate::error::{code::EINVAL, Result};
8ce30d94eSDanilo Krummrich use crate::{bindings, build_assert};
9ce30d94eSDanilo Krummrich 
10ce30d94eSDanilo Krummrich /// Raw representation of an MMIO region.
11ce30d94eSDanilo Krummrich ///
12ce30d94eSDanilo Krummrich /// By itself, the existence of an instance of this structure does not provide any guarantees that
13ce30d94eSDanilo Krummrich /// the represented MMIO region does exist or is properly mapped.
14ce30d94eSDanilo Krummrich ///
15ce30d94eSDanilo Krummrich /// Instead, the bus specific MMIO implementation must convert this raw representation into an `Io`
16ce30d94eSDanilo Krummrich /// instance providing the actual memory accessors. Only by the conversion into an `Io` structure
17ce30d94eSDanilo Krummrich /// any guarantees are given.
18ce30d94eSDanilo Krummrich pub struct IoRaw<const SIZE: usize = 0> {
19ce30d94eSDanilo Krummrich     addr: usize,
20ce30d94eSDanilo Krummrich     maxsize: usize,
21ce30d94eSDanilo Krummrich }
22ce30d94eSDanilo Krummrich 
23ce30d94eSDanilo Krummrich impl<const SIZE: usize> IoRaw<SIZE> {
24ce30d94eSDanilo Krummrich     /// Returns a new `IoRaw` instance on success, an error otherwise.
25ce30d94eSDanilo Krummrich     pub fn new(addr: usize, maxsize: usize) -> Result<Self> {
26ce30d94eSDanilo Krummrich         if maxsize < SIZE {
27ce30d94eSDanilo Krummrich             return Err(EINVAL);
28ce30d94eSDanilo Krummrich         }
29ce30d94eSDanilo Krummrich 
30ce30d94eSDanilo Krummrich         Ok(Self { addr, maxsize })
31ce30d94eSDanilo Krummrich     }
32ce30d94eSDanilo Krummrich 
33ce30d94eSDanilo Krummrich     /// Returns the base address of the MMIO region.
34ce30d94eSDanilo Krummrich     #[inline]
35ce30d94eSDanilo Krummrich     pub fn addr(&self) -> usize {
36ce30d94eSDanilo Krummrich         self.addr
37ce30d94eSDanilo Krummrich     }
38ce30d94eSDanilo Krummrich 
39ce30d94eSDanilo Krummrich     /// Returns the maximum size of the MMIO region.
40ce30d94eSDanilo Krummrich     #[inline]
41ce30d94eSDanilo Krummrich     pub fn maxsize(&self) -> usize {
42ce30d94eSDanilo Krummrich         self.maxsize
43ce30d94eSDanilo Krummrich     }
44ce30d94eSDanilo Krummrich }
45ce30d94eSDanilo Krummrich 
46ce30d94eSDanilo Krummrich /// IO-mapped memory, starting at the base address @addr and spanning @maxlen bytes.
47ce30d94eSDanilo Krummrich ///
48ce30d94eSDanilo Krummrich /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the
49ce30d94eSDanilo Krummrich /// mapping, performing an additional region request etc.
50ce30d94eSDanilo Krummrich ///
51ce30d94eSDanilo Krummrich /// # Invariant
52ce30d94eSDanilo Krummrich ///
53ce30d94eSDanilo Krummrich /// `addr` is the start and `maxsize` the length of valid I/O mapped memory region of size
54ce30d94eSDanilo Krummrich /// `maxsize`.
55ce30d94eSDanilo Krummrich ///
56ce30d94eSDanilo Krummrich /// # Examples
57ce30d94eSDanilo Krummrich ///
58ce30d94eSDanilo Krummrich /// ```no_run
59ce30d94eSDanilo Krummrich /// # use kernel::{bindings, io::{Io, IoRaw}};
60ce30d94eSDanilo Krummrich /// # use core::ops::Deref;
61ce30d94eSDanilo Krummrich ///
62ce30d94eSDanilo Krummrich /// // See also [`pci::Bar`] for a real example.
63ce30d94eSDanilo Krummrich /// struct IoMem<const SIZE: usize>(IoRaw<SIZE>);
64ce30d94eSDanilo Krummrich ///
65ce30d94eSDanilo Krummrich /// impl<const SIZE: usize> IoMem<SIZE> {
66ce30d94eSDanilo Krummrich ///     /// # Safety
67ce30d94eSDanilo Krummrich ///     ///
68ce30d94eSDanilo Krummrich ///     /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs
69ce30d94eSDanilo Krummrich ///     /// virtual address space.
70ce30d94eSDanilo Krummrich ///     unsafe fn new(paddr: usize) -> Result<Self>{
71ce30d94eSDanilo Krummrich ///         // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
72ce30d94eSDanilo Krummrich ///         // valid for `ioremap`.
73ce30d94eSDanilo Krummrich ///         let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) };
74ce30d94eSDanilo Krummrich ///         if addr.is_null() {
75ce30d94eSDanilo Krummrich ///             return Err(ENOMEM);
76ce30d94eSDanilo Krummrich ///         }
77ce30d94eSDanilo Krummrich ///
78ce30d94eSDanilo Krummrich ///         Ok(IoMem(IoRaw::new(addr as _, SIZE)?))
79ce30d94eSDanilo Krummrich ///     }
80ce30d94eSDanilo Krummrich /// }
81ce30d94eSDanilo Krummrich ///
82ce30d94eSDanilo Krummrich /// impl<const SIZE: usize> Drop for IoMem<SIZE> {
83ce30d94eSDanilo Krummrich ///     fn drop(&mut self) {
84ce30d94eSDanilo Krummrich ///         // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
85ce30d94eSDanilo Krummrich ///         unsafe { bindings::iounmap(self.0.addr() as _); };
86ce30d94eSDanilo Krummrich ///     }
87ce30d94eSDanilo Krummrich /// }
88ce30d94eSDanilo Krummrich ///
89ce30d94eSDanilo Krummrich /// impl<const SIZE: usize> Deref for IoMem<SIZE> {
90ce30d94eSDanilo Krummrich ///    type Target = Io<SIZE>;
91ce30d94eSDanilo Krummrich ///
92ce30d94eSDanilo Krummrich ///    fn deref(&self) -> &Self::Target {
93ce30d94eSDanilo Krummrich ///         // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
94ce30d94eSDanilo Krummrich ///         unsafe { Io::from_raw(&self.0) }
95ce30d94eSDanilo Krummrich ///    }
96ce30d94eSDanilo Krummrich /// }
97ce30d94eSDanilo Krummrich ///
98ce30d94eSDanilo Krummrich ///# fn no_run() -> Result<(), Error> {
99ce30d94eSDanilo Krummrich /// // SAFETY: Invalid usage for example purposes.
100ce30d94eSDanilo Krummrich /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
101*354fd6e8SFiona Behrens /// iomem.write32(0x42, 0x0);
102*354fd6e8SFiona Behrens /// assert!(iomem.try_write32(0x42, 0x0).is_ok());
103*354fd6e8SFiona Behrens /// assert!(iomem.try_write32(0x42, 0x4).is_err());
104ce30d94eSDanilo Krummrich /// # Ok(())
105ce30d94eSDanilo Krummrich /// # }
106ce30d94eSDanilo Krummrich /// ```
107ce30d94eSDanilo Krummrich #[repr(transparent)]
108ce30d94eSDanilo Krummrich pub struct Io<const SIZE: usize = 0>(IoRaw<SIZE>);
109ce30d94eSDanilo Krummrich 
110ce30d94eSDanilo Krummrich macro_rules! define_read {
111*354fd6e8SFiona Behrens     ($(#[$attr:meta])* $name:ident, $try_name:ident, $c_fn:ident -> $type_name:ty) => {
112ce30d94eSDanilo Krummrich         /// Read IO data from a given offset known at compile time.
113ce30d94eSDanilo Krummrich         ///
114ce30d94eSDanilo Krummrich         /// Bound checks are performed on compile time, hence if the offset is not known at compile
115ce30d94eSDanilo Krummrich         /// time, the build will fail.
116ce30d94eSDanilo Krummrich         $(#[$attr])*
117ce30d94eSDanilo Krummrich         #[inline]
118ce30d94eSDanilo Krummrich         pub fn $name(&self, offset: usize) -> $type_name {
119ce30d94eSDanilo Krummrich             let addr = self.io_addr_assert::<$type_name>(offset);
120ce30d94eSDanilo Krummrich 
121ce30d94eSDanilo Krummrich             // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
122*354fd6e8SFiona Behrens             unsafe { bindings::$c_fn(addr as _) }
123ce30d94eSDanilo Krummrich         }
124ce30d94eSDanilo Krummrich 
125ce30d94eSDanilo Krummrich         /// Read IO data from a given offset.
126ce30d94eSDanilo Krummrich         ///
127ce30d94eSDanilo Krummrich         /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is
128ce30d94eSDanilo Krummrich         /// out of bounds.
129ce30d94eSDanilo Krummrich         $(#[$attr])*
130ce30d94eSDanilo Krummrich         pub fn $try_name(&self, offset: usize) -> Result<$type_name> {
131ce30d94eSDanilo Krummrich             let addr = self.io_addr::<$type_name>(offset)?;
132ce30d94eSDanilo Krummrich 
133ce30d94eSDanilo Krummrich             // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
134*354fd6e8SFiona Behrens             Ok(unsafe { bindings::$c_fn(addr as _) })
135ce30d94eSDanilo Krummrich         }
136ce30d94eSDanilo Krummrich     };
137ce30d94eSDanilo Krummrich }
138ce30d94eSDanilo Krummrich 
139ce30d94eSDanilo Krummrich macro_rules! define_write {
140*354fd6e8SFiona Behrens     ($(#[$attr:meta])* $name:ident, $try_name:ident, $c_fn:ident <- $type_name:ty) => {
141ce30d94eSDanilo Krummrich         /// Write IO data from a given offset known at compile time.
142ce30d94eSDanilo Krummrich         ///
143ce30d94eSDanilo Krummrich         /// Bound checks are performed on compile time, hence if the offset is not known at compile
144ce30d94eSDanilo Krummrich         /// time, the build will fail.
145ce30d94eSDanilo Krummrich         $(#[$attr])*
146ce30d94eSDanilo Krummrich         #[inline]
147ce30d94eSDanilo Krummrich         pub fn $name(&self, value: $type_name, offset: usize) {
148ce30d94eSDanilo Krummrich             let addr = self.io_addr_assert::<$type_name>(offset);
149ce30d94eSDanilo Krummrich 
150ce30d94eSDanilo Krummrich             // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
151*354fd6e8SFiona Behrens             unsafe { bindings::$c_fn(value, addr as _, ) }
152ce30d94eSDanilo Krummrich         }
153ce30d94eSDanilo Krummrich 
154ce30d94eSDanilo Krummrich         /// Write IO data from a given offset.
155ce30d94eSDanilo Krummrich         ///
156ce30d94eSDanilo Krummrich         /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is
157ce30d94eSDanilo Krummrich         /// out of bounds.
158ce30d94eSDanilo Krummrich         $(#[$attr])*
159ce30d94eSDanilo Krummrich         pub fn $try_name(&self, value: $type_name, offset: usize) -> Result {
160ce30d94eSDanilo Krummrich             let addr = self.io_addr::<$type_name>(offset)?;
161ce30d94eSDanilo Krummrich 
162ce30d94eSDanilo Krummrich             // SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
163*354fd6e8SFiona Behrens             unsafe { bindings::$c_fn(value, addr as _) }
164ce30d94eSDanilo Krummrich             Ok(())
165ce30d94eSDanilo Krummrich         }
166ce30d94eSDanilo Krummrich     };
167ce30d94eSDanilo Krummrich }
168ce30d94eSDanilo Krummrich 
169ce30d94eSDanilo Krummrich impl<const SIZE: usize> Io<SIZE> {
170ce30d94eSDanilo Krummrich     /// Converts an `IoRaw` into an `Io` instance, providing the accessors to the MMIO mapping.
171ce30d94eSDanilo Krummrich     ///
172ce30d94eSDanilo Krummrich     /// # Safety
173ce30d94eSDanilo Krummrich     ///
174ce30d94eSDanilo Krummrich     /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size
175ce30d94eSDanilo Krummrich     /// `maxsize`.
176ce30d94eSDanilo Krummrich     pub unsafe fn from_raw(raw: &IoRaw<SIZE>) -> &Self {
177ce30d94eSDanilo Krummrich         // SAFETY: `Io` is a transparent wrapper around `IoRaw`.
178ce30d94eSDanilo Krummrich         unsafe { &*core::ptr::from_ref(raw).cast() }
179ce30d94eSDanilo Krummrich     }
180ce30d94eSDanilo Krummrich 
181ce30d94eSDanilo Krummrich     /// Returns the base address of this mapping.
182ce30d94eSDanilo Krummrich     #[inline]
183ce30d94eSDanilo Krummrich     pub fn addr(&self) -> usize {
184ce30d94eSDanilo Krummrich         self.0.addr()
185ce30d94eSDanilo Krummrich     }
186ce30d94eSDanilo Krummrich 
187ce30d94eSDanilo Krummrich     /// Returns the maximum size of this mapping.
188ce30d94eSDanilo Krummrich     #[inline]
189ce30d94eSDanilo Krummrich     pub fn maxsize(&self) -> usize {
190ce30d94eSDanilo Krummrich         self.0.maxsize()
191ce30d94eSDanilo Krummrich     }
192ce30d94eSDanilo Krummrich 
193ce30d94eSDanilo Krummrich     #[inline]
194ce30d94eSDanilo Krummrich     const fn offset_valid<U>(offset: usize, size: usize) -> bool {
195ce30d94eSDanilo Krummrich         let type_size = core::mem::size_of::<U>();
196ce30d94eSDanilo Krummrich         if let Some(end) = offset.checked_add(type_size) {
197ce30d94eSDanilo Krummrich             end <= size && offset % type_size == 0
198ce30d94eSDanilo Krummrich         } else {
199ce30d94eSDanilo Krummrich             false
200ce30d94eSDanilo Krummrich         }
201ce30d94eSDanilo Krummrich     }
202ce30d94eSDanilo Krummrich 
203ce30d94eSDanilo Krummrich     #[inline]
204ce30d94eSDanilo Krummrich     fn io_addr<U>(&self, offset: usize) -> Result<usize> {
205ce30d94eSDanilo Krummrich         if !Self::offset_valid::<U>(offset, self.maxsize()) {
206ce30d94eSDanilo Krummrich             return Err(EINVAL);
207ce30d94eSDanilo Krummrich         }
208ce30d94eSDanilo Krummrich 
209ce30d94eSDanilo Krummrich         // Probably no need to check, since the safety requirements of `Self::new` guarantee that
210ce30d94eSDanilo Krummrich         // this can't overflow.
211ce30d94eSDanilo Krummrich         self.addr().checked_add(offset).ok_or(EINVAL)
212ce30d94eSDanilo Krummrich     }
213ce30d94eSDanilo Krummrich 
214ce30d94eSDanilo Krummrich     #[inline]
215ce30d94eSDanilo Krummrich     fn io_addr_assert<U>(&self, offset: usize) -> usize {
216ce30d94eSDanilo Krummrich         build_assert!(Self::offset_valid::<U>(offset, SIZE));
217ce30d94eSDanilo Krummrich 
218ce30d94eSDanilo Krummrich         self.addr() + offset
219ce30d94eSDanilo Krummrich     }
220ce30d94eSDanilo Krummrich 
221*354fd6e8SFiona Behrens     define_read!(read8, try_read8, readb -> u8);
222*354fd6e8SFiona Behrens     define_read!(read16, try_read16, readw -> u16);
223*354fd6e8SFiona Behrens     define_read!(read32, try_read32, readl -> u32);
224ce30d94eSDanilo Krummrich     define_read!(
225ce30d94eSDanilo Krummrich         #[cfg(CONFIG_64BIT)]
226*354fd6e8SFiona Behrens         read64,
227*354fd6e8SFiona Behrens         try_read64,
228*354fd6e8SFiona Behrens         readq -> u64
229ce30d94eSDanilo Krummrich     );
230ce30d94eSDanilo Krummrich 
231*354fd6e8SFiona Behrens     define_read!(read8_relaxed, try_read8_relaxed, readb_relaxed -> u8);
232*354fd6e8SFiona Behrens     define_read!(read16_relaxed, try_read16_relaxed, readw_relaxed -> u16);
233*354fd6e8SFiona Behrens     define_read!(read32_relaxed, try_read32_relaxed, readl_relaxed -> u32);
234ce30d94eSDanilo Krummrich     define_read!(
235ce30d94eSDanilo Krummrich         #[cfg(CONFIG_64BIT)]
236*354fd6e8SFiona Behrens         read64_relaxed,
237*354fd6e8SFiona Behrens         try_read64_relaxed,
238*354fd6e8SFiona Behrens         readq_relaxed -> u64
239ce30d94eSDanilo Krummrich     );
240ce30d94eSDanilo Krummrich 
241*354fd6e8SFiona Behrens     define_write!(write8, try_write8, writeb <- u8);
242*354fd6e8SFiona Behrens     define_write!(write16, try_write16, writew <- u16);
243*354fd6e8SFiona Behrens     define_write!(write32, try_write32, writel <- u32);
244ce30d94eSDanilo Krummrich     define_write!(
245ce30d94eSDanilo Krummrich         #[cfg(CONFIG_64BIT)]
246*354fd6e8SFiona Behrens         write64,
247*354fd6e8SFiona Behrens         try_write64,
248*354fd6e8SFiona Behrens         writeq <- u64
249ce30d94eSDanilo Krummrich     );
250ce30d94eSDanilo Krummrich 
251*354fd6e8SFiona Behrens     define_write!(write8_relaxed, try_write8_relaxed, writeb_relaxed <- u8);
252*354fd6e8SFiona Behrens     define_write!(write16_relaxed, try_write16_relaxed, writew_relaxed <- u16);
253*354fd6e8SFiona Behrens     define_write!(write32_relaxed, try_write32_relaxed, writel_relaxed <- u32);
254ce30d94eSDanilo Krummrich     define_write!(
255ce30d94eSDanilo Krummrich         #[cfg(CONFIG_64BIT)]
256*354fd6e8SFiona Behrens         write64_relaxed,
257*354fd6e8SFiona Behrens         try_write64_relaxed,
258*354fd6e8SFiona Behrens         writeq_relaxed <- u64
259ce30d94eSDanilo Krummrich     );
260ce30d94eSDanilo Krummrich }
261