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