kernel/io/mem.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Generic memory-mapped IO.
4
5use core::ops::Deref;
6
7use 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.
27pub struct IoRequest<'a> {
28 device: &'a Device<Bound>,
29 resource: &'a Resource,
30}
31
32impl<'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`.
39 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 /// ```
85 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
95 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 /// ```
143 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.
149 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`].
159pub 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
170impl<const SIZE: usize> ExclusiveIoMem<SIZE> {
171 /// Creates a new `ExclusiveIoMem` instance.
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`].
197 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
205impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> {
206 type Target = Io<SIZE>;
207
208 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.
222pub struct IoMem<const SIZE: usize = 0> {
223 io: IoRaw<SIZE>,
224}
225
226impl<const SIZE: usize> IoMem<SIZE> {
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`].
265 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
273impl<const SIZE: usize> Drop for IoMem<SIZE> {
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
280impl<const SIZE: usize> Deref for IoMem<SIZE> {
281 type Target = Io<SIZE>;
282
283 fn deref(&self) -> &Self::Target {
284 // SAFETY: Safe as by the invariant of `IoMem`.
285 unsafe { Io::from_raw(&self.io) }
286 }
287}