Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/io/mem.rs
29266 views
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`.
31
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
/// ```
77
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
87
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
/// ```
135
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.
141
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.
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`].
189
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
200
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> {
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`].
257
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> {
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
275
fn deref(&self) -> &Self::Target {
276
// SAFETY: Safe as by the invariant of `IoMem`.
277
unsafe { Io::from_raw(&self.io) }
278
}
279
}
280
281