xref: /linux/rust/kernel/io/mem.rs (revision 644672e93a1aa6bfc3ebc102cbf9b8efad16e786)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Generic memory-mapped IO.
4 
5 use core::ops::Deref;
6 
7 use crate::{
8     device::{
9         Bound,
10         Device, //
11     },
12     devres::Devres,
13     io::{
14         self,
15         resource::{
16             Region,
17             Resource, //
18         },
19         Io,
20         IoRaw, //
21     },
22     prelude::*,
23 };
24 
25 /// An IO request for a specific device and resource.
26 pub struct IoRequest<'a> {
27     device: &'a Device<Bound>,
28     resource: &'a Resource,
29 }
30 
31 impl<'a> IoRequest<'a> {
32     /// Creates a new [`IoRequest`] instance.
33     ///
34     /// # Safety
35     ///
36     /// Callers must ensure that `resource` is valid for `device` during the
37     /// lifetime `'a`.
38     pub(crate) unsafe fn new(device: &'a Device<Bound>, resource: &'a Resource) -> Self {
39         IoRequest { device, resource }
40     }
41 
42     /// Maps an [`IoRequest`] where the size is known at compile time.
43     ///
44     /// This uses the [`ioremap()`] C API.
45     ///
46     /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
47     ///
48     /// # Examples
49     ///
50     /// The following example uses a [`kernel::platform::Device`] for
51     /// illustration purposes.
52     ///
53     /// ```no_run
54     /// use kernel::{
55     ///     bindings,
56     ///     device::Core,
57     ///     of,
58     ///     platform,
59     /// };
60     /// struct SampleDriver;
61     ///
62     /// impl platform::Driver for SampleDriver {
63     ///    # type IdInfo = ();
64     ///
65     ///    fn probe(
66     ///       pdev: &platform::Device<Core>,
67     ///       info: Option<&Self::IdInfo>,
68     ///    ) -> impl PinInit<Self, Error> {
69     ///       let offset = 0; // Some offset.
70     ///
71     ///       // If the size is known at compile time, use [`Self::iomap_sized`].
72     ///       //
73     ///       // No runtime checks will apply when reading and writing.
74     ///       let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
75     ///       let iomem = request.iomap_sized::<42>();
76     ///       let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
77     ///
78     ///       let io = iomem.access(pdev.as_ref())?;
79     ///
80     ///       // Read and write a 32-bit value at `offset`.
81     ///       let data = io.read32_relaxed(offset);
82     ///
83     ///       io.write32_relaxed(data, offset);
84     ///
85     ///       # Ok(SampleDriver)
86     ///     }
87     /// }
88     /// ```
89     pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a {
90         IoMem::new(self)
91     }
92 
93     /// Same as [`Self::iomap_sized`] but with exclusive access to the
94     /// underlying region.
95     ///
96     /// This uses the [`ioremap()`] C API.
97     ///
98     /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
99     pub fn iomap_exclusive_sized<const SIZE: usize>(
100         self,
101     ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a {
102         ExclusiveIoMem::new(self)
103     }
104 
105     /// Maps an [`IoRequest`] where the size is not known at compile time,
106     ///
107     /// This uses the [`ioremap()`] C API.
108     ///
109     /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device
110     ///
111     /// # Examples
112     ///
113     /// The following example uses a [`kernel::platform::Device`] for
114     /// illustration purposes.
115     ///
116     /// ```no_run
117     /// use kernel::{
118     ///     bindings,
119     ///     device::Core,
120     ///     of,
121     ///     platform,
122     /// };
123     /// struct SampleDriver;
124     ///
125     /// impl platform::Driver for SampleDriver {
126     ///    # type IdInfo = ();
127     ///
128     ///    fn probe(
129     ///       pdev: &platform::Device<Core>,
130     ///       info: Option<&Self::IdInfo>,
131     ///    ) -> impl PinInit<Self, Error> {
132     ///       let offset = 0; // Some offset.
133     ///
134     ///       // Unlike [`Self::iomap_sized`], here the size of the memory region
135     ///       // is not known at compile time, so only the `try_read*` and `try_write*`
136     ///       // family of functions should be used, leading to runtime checks on every
137     ///       // access.
138     ///       let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
139     ///       let iomem = request.iomap();
140     ///       let iomem = KBox::pin_init(iomem, GFP_KERNEL)?;
141     ///
142     ///       let io = iomem.access(pdev.as_ref())?;
143     ///
144     ///       let data = io.try_read32_relaxed(offset)?;
145     ///
146     ///       io.try_write32_relaxed(data, offset)?;
147     ///
148     ///       # Ok(SampleDriver)
149     ///     }
150     /// }
151     /// ```
152     pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a {
153         Self::iomap_sized::<0>(self)
154     }
155 
156     /// Same as [`Self::iomap`] but with exclusive access to the underlying
157     /// region.
158     pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a {
159         Self::iomap_exclusive_sized::<0>(self)
160     }
161 }
162 
163 /// An exclusive memory-mapped IO region.
164 ///
165 /// # Invariants
166 ///
167 /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`].
168 pub struct ExclusiveIoMem<const SIZE: usize> {
169     /// The underlying `IoMem` instance.
170     iomem: IoMem<SIZE>,
171 
172     /// The region abstraction. This represents exclusive access to the
173     /// range represented by the underlying `iomem`.
174     ///
175     /// This field is needed for ownership of the region.
176     _region: Region,
177 }
178 
179 impl<const SIZE: usize> ExclusiveIoMem<SIZE> {
180     /// Creates a new `ExclusiveIoMem` instance.
181     fn ioremap(resource: &Resource) -> Result<Self> {
182         let start = resource.start();
183         let size = resource.size();
184         let name = resource.name().unwrap_or_default();
185 
186         let region = resource
187             .request_region(
188                 start,
189                 size,
190                 name.to_cstring()?,
191                 io::resource::Flags::IORESOURCE_MEM,
192             )
193             .ok_or(EBUSY)?;
194 
195         let iomem = IoMem::ioremap(resource)?;
196 
197         let iomem = ExclusiveIoMem {
198             iomem,
199             _region: region,
200         };
201 
202         Ok(iomem)
203     }
204 
205     /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`].
206     pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
207         let dev = io_request.device;
208         let res = io_request.resource;
209 
210         Devres::new(dev, Self::ioremap(res))
211     }
212 }
213 
214 impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {
215     type Target = Io<SIZE>;
216 
217     fn deref(&self) -> &Self::Target {
218         &self.iomem
219     }
220 }
221 
222 /// A generic memory-mapped IO region.
223 ///
224 /// Accesses to the underlying region is checked either at compile time, if the
225 /// region's size is known at that point, or at runtime otherwise.
226 ///
227 /// # Invariants
228 ///
229 /// [`IoMem`] always holds an [`IoRaw`] instance that holds a valid pointer to the
230 /// start of the I/O memory mapped region.
231 pub struct IoMem<const SIZE: usize = 0> {
232     io: IoRaw<SIZE>,
233 }
234 
235 impl<const SIZE: usize> IoMem<SIZE> {
236     fn ioremap(resource: &Resource) -> Result<Self> {
237         // Note: Some ioremap() implementations use types that depend on the CPU
238         // word width rather than the bus address width.
239         //
240         // TODO: Properly address this in the C code to avoid this `try_into`.
241         let size = resource.size().try_into()?;
242         if size == 0 {
243             return Err(EINVAL);
244         }
245 
246         let res_start = resource.start();
247 
248         let addr = if resource
249             .flags()
250             .contains(io::resource::Flags::IORESOURCE_MEM_NONPOSTED)
251         {
252             // SAFETY:
253             // - `res_start` and `size` are read from a presumably valid `struct resource`.
254             // - `size` is known not to be zero at this point.
255             unsafe { bindings::ioremap_np(res_start, size) }
256         } else {
257             // SAFETY:
258             // - `res_start` and `size` are read from a presumably valid `struct resource`.
259             // - `size` is known not to be zero at this point.
260             unsafe { bindings::ioremap(res_start, size) }
261         };
262 
263         if addr.is_null() {
264             return Err(ENOMEM);
265         }
266 
267         let io = IoRaw::new(addr as usize, size)?;
268         let io = IoMem { io };
269 
270         Ok(io)
271     }
272 
273     /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`].
274     pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a {
275         let dev = io_request.device;
276         let res = io_request.resource;
277 
278         Devres::new(dev, Self::ioremap(res))
279     }
280 }
281 
282 impl<const SIZE: usize> Drop for IoMem<SIZE> {
283     fn drop(&mut self) {
284         // SAFETY: Safe as by the invariant of `Io`.
285         unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }
286     }
287 }
288 
289 impl<const SIZE: usize> Deref for IoMem<SIZE> {
290     type Target = Io<SIZE>;
291 
292     fn deref(&self) -> &Self::Target {
293         // SAFETY: Safe as by the invariant of `IoMem`.
294         unsafe { Io::from_raw(&self.io) }
295     }
296 }
297