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