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 Mmio, 20 MmioRaw, // 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 /// io::Io, 58 /// of, 59 /// platform, 60 /// }; 61 /// struct SampleDriver; 62 /// 63 /// impl platform::Driver for SampleDriver { 64 /// # type IdInfo = (); 65 /// # type Data = Self; 66 /// 67 /// fn probe( 68 /// pdev: &platform::Device<Core<'_>>, 69 /// info: Option<&Self::IdInfo>, 70 /// ) -> impl PinInit<Self, Error> { 71 /// let offset = 0; // Some offset. 72 /// 73 /// // If the size is known at compile time, use [`Self::iomap_sized`]. 74 /// // 75 /// // No runtime checks will apply when reading and writing. 76 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 77 /// let iomem = request.iomap_sized::<42>(); 78 /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; 79 /// 80 /// let io = iomem.access(pdev.as_ref())?; 81 /// 82 /// // Read and write a 32-bit value at `offset`. 83 /// let data = io.read32(offset); 84 /// 85 /// io.write32(data, offset); 86 /// 87 /// # Ok(SampleDriver) 88 /// } 89 /// } 90 /// ``` 91 pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a { 92 IoMem::new(self) 93 } 94 95 /// Same as [`Self::iomap_sized`] but with exclusive access to the 96 /// underlying region. 97 /// 98 /// This uses the [`ioremap()`] C API. 99 /// 100 /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device 101 pub fn iomap_exclusive_sized<const SIZE: usize>( 102 self, 103 ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a { 104 ExclusiveIoMem::new(self) 105 } 106 107 /// Maps an [`IoRequest`] where the size is not known at compile time, 108 /// 109 /// This uses the [`ioremap()`] C API. 110 /// 111 /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device 112 /// 113 /// # Examples 114 /// 115 /// The following example uses a [`kernel::platform::Device`] for 116 /// illustration purposes. 117 /// 118 /// ```no_run 119 /// use kernel::{ 120 /// bindings, 121 /// device::Core, 122 /// io::Io, 123 /// of, 124 /// platform, 125 /// }; 126 /// struct SampleDriver; 127 /// 128 /// impl platform::Driver for SampleDriver { 129 /// # type IdInfo = (); 130 /// # type Data = Self; 131 /// 132 /// fn probe( 133 /// pdev: &platform::Device<Core<'_>>, 134 /// info: Option<&Self::IdInfo>, 135 /// ) -> impl PinInit<Self, Error> { 136 /// let offset = 0; // Some offset. 137 /// 138 /// // Unlike [`Self::iomap_sized`], here the size of the memory region 139 /// // is not known at compile time, so only the `try_read*` and `try_write*` 140 /// // family of functions should be used, leading to runtime checks on every 141 /// // access. 142 /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 143 /// let iomem = request.iomap(); 144 /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; 145 /// 146 /// let io = iomem.access(pdev.as_ref())?; 147 /// 148 /// let data = io.try_read32(offset)?; 149 /// 150 /// io.try_write32(data, offset)?; 151 /// 152 /// # Ok(SampleDriver) 153 /// } 154 /// } 155 /// ``` 156 pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a { 157 Self::iomap_sized::<0>(self) 158 } 159 160 /// Same as [`Self::iomap`] but with exclusive access to the underlying 161 /// region. 162 pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a { 163 Self::iomap_exclusive_sized::<0>(self) 164 } 165 } 166 167 /// An exclusive memory-mapped IO region. 168 /// 169 /// # Invariants 170 /// 171 /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. 172 pub struct ExclusiveIoMem<const SIZE: usize> { 173 /// The underlying `IoMem` instance. 174 iomem: IoMem<SIZE>, 175 176 /// The region abstraction. This represents exclusive access to the 177 /// range represented by the underlying `iomem`. 178 /// 179 /// This field is needed for ownership of the region. 180 _region: Region, 181 } 182 183 impl<const SIZE: usize> ExclusiveIoMem<SIZE> { 184 /// Creates a new `ExclusiveIoMem` instance. 185 fn ioremap(resource: &Resource) -> Result<Self> { 186 let start = resource.start(); 187 let size = resource.size(); 188 let name = resource.name().unwrap_or_default(); 189 190 let region = resource 191 .request_region( 192 start, 193 size, 194 name.to_cstring()?, 195 io::resource::Flags::IORESOURCE_MEM, 196 ) 197 .ok_or(EBUSY)?; 198 199 let iomem = IoMem::ioremap(resource)?; 200 201 let iomem = ExclusiveIoMem { 202 iomem, 203 _region: region, 204 }; 205 206 Ok(iomem) 207 } 208 209 /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`]. 210 pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { 211 let dev = io_request.device; 212 let res = io_request.resource; 213 214 Devres::new(dev, Self::ioremap(res)) 215 } 216 } 217 218 impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { 219 type Target = Mmio<SIZE>; 220 221 fn deref(&self) -> &Self::Target { 222 &self.iomem 223 } 224 } 225 226 /// A generic memory-mapped IO region. 227 /// 228 /// Accesses to the underlying region is checked either at compile time, if the 229 /// region's size is known at that point, or at runtime otherwise. 230 /// 231 /// # Invariants 232 /// 233 /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the 234 /// start of the I/O memory mapped region. 235 pub struct IoMem<const SIZE: usize = 0> { 236 io: MmioRaw<SIZE>, 237 } 238 239 impl<const SIZE: usize> IoMem<SIZE> { 240 fn ioremap(resource: &Resource) -> Result<Self> { 241 // Note: Some ioremap() implementations use types that depend on the CPU 242 // word width rather than the bus address width. 243 // 244 // TODO: Properly address this in the C code to avoid this `try_into`. 245 let size = resource.size().try_into()?; 246 if size == 0 { 247 return Err(EINVAL); 248 } 249 250 let res_start = resource.start(); 251 252 let addr = if resource 253 .flags() 254 .contains(io::resource::Flags::IORESOURCE_MEM_NONPOSTED) 255 { 256 // SAFETY: 257 // - `res_start` and `size` are read from a presumably valid `struct resource`. 258 // - `size` is known not to be zero at this point. 259 unsafe { bindings::ioremap_np(res_start, size) } 260 } else { 261 // SAFETY: 262 // - `res_start` and `size` are read from a presumably valid `struct resource`. 263 // - `size` is known not to be zero at this point. 264 unsafe { bindings::ioremap(res_start, size) } 265 }; 266 267 if addr.is_null() { 268 return Err(ENOMEM); 269 } 270 271 let io = MmioRaw::new(addr as usize, size)?; 272 let io = IoMem { io }; 273 274 Ok(io) 275 } 276 277 /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`]. 278 pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { 279 let dev = io_request.device; 280 let res = io_request.resource; 281 282 Devres::new(dev, Self::ioremap(res)) 283 } 284 } 285 286 impl<const SIZE: usize> Drop for IoMem<SIZE> { 287 fn drop(&mut self) { 288 // SAFETY: Safe as by the invariant of `Io`. 289 unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } 290 } 291 } 292 293 impl<const SIZE: usize> Deref for IoMem<SIZE> { 294 type Target = Mmio<SIZE>; 295 296 fn deref(&self) -> &Self::Target { 297 // SAFETY: Safe as by the invariant of `IoMem`. 298 unsafe { Mmio::from_raw(&self.io) } 299 } 300 } 301