1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Generic memory-mapped IO. 4 5 use core::ops::Deref; 6 7 use 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. 27 pub struct IoRequest<'a> { 28 device: &'a Device<Bound>, 29 resource: &'a Resource, 30 } 31 32 impl<'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`. new(device: &'a Device<Bound>, resource: &'a Resource) -> Self39 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 /// ``` iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a85 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 iomap_exclusive_sized<const SIZE: usize>( self, ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a95 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 /// ``` iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a143 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. iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a149 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`]. 159 pub 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 170 impl<const SIZE: usize> ExclusiveIoMem<SIZE> { 171 /// Creates a new `ExclusiveIoMem` instance. ioremap(resource: &Resource) -> Result<Self>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`]. new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a197 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 205 impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { 206 type Target = Io<SIZE>; 207 deref(&self) -> &Self::Target208 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. 222 pub struct IoMem<const SIZE: usize = 0> { 223 io: IoRaw<SIZE>, 224 } 225 226 impl<const SIZE: usize> IoMem<SIZE> { ioremap(resource: &Resource) -> Result<Self>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`]. new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a265 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 273 impl<const SIZE: usize> Drop for IoMem<SIZE> { drop(&mut self)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 280 impl<const SIZE: usize> Deref for IoMem<SIZE> { 281 type Target = Io<SIZE>; 282 deref(&self) -> &Self::Target283 fn deref(&self) -> &Self::Target { 284 // SAFETY: Safe as by the invariant of `IoMem`. 285 unsafe { Io::from_raw(&self.io) } 286 } 287 } 288