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`. new(device: &'a Device<Bound>, resource: &'a Resource) -> Self31 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 /// ``` iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a77 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 iomap_exclusive_sized<const SIZE: usize>( self, ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a87 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 /// ``` iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a135 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. iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a141 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. ioremap(resource: &Resource) -> Result<Self>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`]. new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a189 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 deref(&self) -> &Self::Target200 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> { ioremap(resource: &Resource) -> Result<Self>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`]. new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a257 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> { drop(&mut self)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 deref(&self) -> &Self::Target275 fn deref(&self) -> &Self::Target { 276 // SAFETY: Safe as by the invariant of `IoMem`. 277 unsafe { Io::from_raw(&self.io) } 278 } 279 } 280