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