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