1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Memory-mapped IO. 4 //! 5 //! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h) 6 7 use crate::{ 8 bindings, 9 prelude::*, // 10 }; 11 12 pub mod mem; 13 pub mod poll; 14 pub mod resource; 15 16 pub use resource::Resource; 17 18 /// Physical address type. 19 /// 20 /// This is a type alias to either `u32` or `u64` depending on the config option 21 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. 22 pub type PhysAddr = bindings::phys_addr_t; 23 24 /// Resource Size type. 25 /// 26 /// This is a type alias to either `u32` or `u64` depending on the config option 27 /// `CONFIG_PHYS_ADDR_T_64BIT`, and it can be a u64 even on 32-bit architectures. 28 pub type ResourceSize = bindings::resource_size_t; 29 30 /// Raw representation of an MMIO region. 31 /// 32 /// By itself, the existence of an instance of this structure does not provide any guarantees that 33 /// the represented MMIO region does exist or is properly mapped. 34 /// 35 /// Instead, the bus specific MMIO implementation must convert this raw representation into an 36 /// `Mmio` instance providing the actual memory accessors. Only by the conversion into an `Mmio` 37 /// structure any guarantees are given. 38 pub struct MmioRaw<const SIZE: usize = 0> { 39 addr: usize, 40 maxsize: usize, 41 } 42 43 impl<const SIZE: usize> MmioRaw<SIZE> { 44 /// Returns a new `MmioRaw` instance on success, an error otherwise. 45 pub fn new(addr: usize, maxsize: usize) -> Result<Self> { 46 if maxsize < SIZE { 47 return Err(EINVAL); 48 } 49 50 Ok(Self { addr, maxsize }) 51 } 52 53 /// Returns the base address of the MMIO region. 54 #[inline] 55 pub fn addr(&self) -> usize { 56 self.addr 57 } 58 59 /// Returns the maximum size of the MMIO region. 60 #[inline] 61 pub fn maxsize(&self) -> usize { 62 self.maxsize 63 } 64 } 65 66 /// IO-mapped memory region. 67 /// 68 /// The creator (usually a subsystem / bus such as PCI) is responsible for creating the 69 /// mapping, performing an additional region request etc. 70 /// 71 /// # Invariant 72 /// 73 /// `addr` is the start and `maxsize` the length of valid I/O mapped memory region of size 74 /// `maxsize`. 75 /// 76 /// # Examples 77 /// 78 /// ```no_run 79 /// use kernel::{ 80 /// bindings, 81 /// ffi::c_void, 82 /// io::{ 83 /// Io, 84 /// IoKnownSize, 85 /// Mmio, 86 /// MmioRaw, 87 /// PhysAddr, 88 /// }, 89 /// }; 90 /// use core::ops::Deref; 91 /// 92 /// // See also `pci::Bar` for a real example. 93 /// struct IoMem<const SIZE: usize>(MmioRaw<SIZE>); 94 /// 95 /// impl<const SIZE: usize> IoMem<SIZE> { 96 /// /// # Safety 97 /// /// 98 /// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs 99 /// /// virtual address space. 100 /// unsafe fn new(paddr: usize) -> Result<Self>{ 101 /// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is 102 /// // valid for `ioremap`. 103 /// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) }; 104 /// if addr.is_null() { 105 /// return Err(ENOMEM); 106 /// } 107 /// 108 /// Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?)) 109 /// } 110 /// } 111 /// 112 /// impl<const SIZE: usize> Drop for IoMem<SIZE> { 113 /// fn drop(&mut self) { 114 /// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`. 115 /// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); }; 116 /// } 117 /// } 118 /// 119 /// impl<const SIZE: usize> Deref for IoMem<SIZE> { 120 /// type Target = Mmio<SIZE>; 121 /// 122 /// fn deref(&self) -> &Self::Target { 123 /// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`. 124 /// unsafe { Mmio::from_raw(&self.0) } 125 /// } 126 /// } 127 /// 128 ///# fn no_run() -> Result<(), Error> { 129 /// // SAFETY: Invalid usage for example purposes. 130 /// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? }; 131 /// iomem.write32(0x42, 0x0); 132 /// assert!(iomem.try_write32(0x42, 0x0).is_ok()); 133 /// assert!(iomem.try_write32(0x42, 0x4).is_err()); 134 /// # Ok(()) 135 /// # } 136 /// ``` 137 #[repr(transparent)] 138 pub struct Mmio<const SIZE: usize = 0>(MmioRaw<SIZE>); 139 140 /// Internal helper macros used to invoke C MMIO read functions. 141 /// 142 /// This macro is intended to be used by higher-level MMIO access macros (io_define_read) and 143 /// provides a unified expansion for infallible vs. fallible read semantics. It emits a direct call 144 /// into the corresponding C helper and performs the required cast to the Rust return type. 145 /// 146 /// # Parameters 147 /// 148 /// * `$c_fn` – The C function performing the MMIO read. 149 /// * `$self` – The I/O backend object. 150 /// * `$ty` – The type of the value to be read. 151 /// * `$addr` – The MMIO address to read. 152 /// 153 /// This macro does not perform any validation; all invariants must be upheld by the higher-level 154 /// abstraction invoking it. 155 macro_rules! call_mmio_read { 156 (infallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => { 157 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 158 unsafe { bindings::$c_fn($addr as *const c_void) as $type } 159 }; 160 161 (fallible, $c_fn:ident, $self:ident, $type:ty, $addr:expr) => {{ 162 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 163 Ok(unsafe { bindings::$c_fn($addr as *const c_void) as $type }) 164 }}; 165 } 166 167 /// Internal helper macros used to invoke C MMIO write functions. 168 /// 169 /// This macro is intended to be used by higher-level MMIO access macros (io_define_write) and 170 /// provides a unified expansion for infallible vs. fallible write semantics. It emits a direct call 171 /// into the corresponding C helper and performs the required cast to the Rust return type. 172 /// 173 /// # Parameters 174 /// 175 /// * `$c_fn` – The C function performing the MMIO write. 176 /// * `$self` – The I/O backend object. 177 /// * `$ty` – The type of the written value. 178 /// * `$addr` – The MMIO address to write. 179 /// * `$value` – The value to write. 180 /// 181 /// This macro does not perform any validation; all invariants must be upheld by the higher-level 182 /// abstraction invoking it. 183 macro_rules! call_mmio_write { 184 (infallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => { 185 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 186 unsafe { bindings::$c_fn($value, $addr as *mut c_void) } 187 }; 188 189 (fallible, $c_fn:ident, $self:ident, $ty:ty, $addr:expr, $value:expr) => {{ 190 // SAFETY: By the type invariant `addr` is a valid address for MMIO operations. 191 unsafe { bindings::$c_fn($value, $addr as *mut c_void) }; 192 Ok(()) 193 }}; 194 } 195 196 /// Generates an accessor method for reading from an I/O backend. 197 /// 198 /// This macro reduces boilerplate by automatically generating either compile-time bounds-checked 199 /// (infallible) or runtime bounds-checked (fallible) read methods. It abstracts the address 200 /// calculation and bounds checking, and delegates the actual I/O read operation to a specified 201 /// helper macro, making it generic over different I/O backends. 202 /// 203 /// # Parameters 204 /// 205 /// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on 206 /// `IoKnownSize` for compile-time checks and returns the value directly. `fallible` performs 207 /// runtime checks against `maxsize()` and returns a `Result<T>`. 208 /// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g., 209 /// `#[cfg(CONFIG_64BIT)]` or inline directives). 210 /// * `$vis:vis` - The visibility of the generated method (e.g., `pub`). 211 /// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `read32`, 212 /// `try_read8`). 213 /// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call 214 /// (e.g., `call_mmio_read`). 215 /// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the 216 /// `$call_macro`. 217 /// * `$type_name:ty` - The Rust type of the value being read (e.g., `u8`, `u32`). 218 macro_rules! io_define_read { 219 (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) -> 220 $type_name:ty) => { 221 /// Read IO data from a given offset known at compile time. 222 /// 223 /// Bound checks are performed on compile time, hence if the offset is not known at compile 224 /// time, the build will fail. 225 $(#[$attr])* 226 // Always inline to optimize out error path of `io_addr_assert`. 227 #[inline(always)] 228 $vis fn $name(&self, offset: usize) -> $type_name { 229 let addr = self.io_addr_assert::<$type_name>(offset); 230 231 // SAFETY: By the type invariant `addr` is a valid address for IO operations. 232 $call_macro!(infallible, $c_fn, self, $type_name, addr) 233 } 234 }; 235 236 (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) -> 237 $type_name:ty) => { 238 /// Read IO data from a given offset. 239 /// 240 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 241 /// out of bounds. 242 $(#[$attr])* 243 $vis fn $try_name(&self, offset: usize) -> Result<$type_name> { 244 let addr = self.io_addr::<$type_name>(offset)?; 245 246 // SAFETY: By the type invariant `addr` is a valid address for IO operations. 247 $call_macro!(fallible, $c_fn, self, $type_name, addr) 248 } 249 }; 250 } 251 252 /// Generates an accessor method for writing to an I/O backend. 253 /// 254 /// This macro reduces boilerplate by automatically generating either compile-time bounds-checked 255 /// (infallible) or runtime bounds-checked (fallible) write methods. It abstracts the address 256 /// calculation and bounds checking, and delegates the actual I/O write operation to a specified 257 /// helper macro, making it generic over different I/O backends. 258 /// 259 /// # Parameters 260 /// 261 /// * `infallible` / `fallible` - Determines the bounds-checking strategy. `infallible` relies on 262 /// `IoKnownSize` for compile-time checks and returns `()`. `fallible` performs runtime checks 263 /// against `maxsize()` and returns a `Result`. 264 /// * `$(#[$attr:meta])*` - Optional attributes to apply to the generated method (e.g., 265 /// `#[cfg(CONFIG_64BIT)]` or inline directives). 266 /// * `$vis:vis` - The visibility of the generated method (e.g., `pub`). 267 /// * `$name:ident` / `$try_name:ident` - The name of the generated method (e.g., `write32`, 268 /// `try_write8`). 269 /// * `$call_macro:ident` - The backend-specific helper macro used to emit the actual I/O call 270 /// (e.g., `call_mmio_write`). 271 /// * `$c_fn:ident` - The backend-specific C function or identifier to be passed into the 272 /// `$call_macro`. 273 /// * `$type_name:ty` - The Rust type of the value being written (e.g., `u8`, `u32`). Note the use 274 /// of `<-` before the type to denote a write operation. 275 macro_rules! io_define_write { 276 (infallible, $(#[$attr:meta])* $vis:vis $name:ident, $call_macro:ident($c_fn:ident) <- 277 $type_name:ty) => { 278 /// Write IO data from a given offset known at compile time. 279 /// 280 /// Bound checks are performed on compile time, hence if the offset is not known at compile 281 /// time, the build will fail. 282 $(#[$attr])* 283 // Always inline to optimize out error path of `io_addr_assert`. 284 #[inline(always)] 285 $vis fn $name(&self, value: $type_name, offset: usize) { 286 let addr = self.io_addr_assert::<$type_name>(offset); 287 288 $call_macro!(infallible, $c_fn, self, $type_name, addr, value); 289 } 290 }; 291 292 (fallible, $(#[$attr:meta])* $vis:vis $try_name:ident, $call_macro:ident($c_fn:ident) <- 293 $type_name:ty) => { 294 /// Write IO data from a given offset. 295 /// 296 /// Bound checks are performed on runtime, it fails if the offset (plus the type size) is 297 /// out of bounds. 298 $(#[$attr])* 299 $vis fn $try_name(&self, value: $type_name, offset: usize) -> Result { 300 let addr = self.io_addr::<$type_name>(offset)?; 301 302 $call_macro!(fallible, $c_fn, self, $type_name, addr, value) 303 } 304 }; 305 } 306 307 /// Checks whether an access of type `U` at the given `offset` 308 /// is valid within this region. 309 #[inline] 310 const fn offset_valid<U>(offset: usize, size: usize) -> bool { 311 let type_size = core::mem::size_of::<U>(); 312 if let Some(end) = offset.checked_add(type_size) { 313 end <= size && offset % type_size == 0 314 } else { 315 false 316 } 317 } 318 319 /// Trait indicating that an I/O backend supports operations of a certain type and providing an 320 /// implementation for these operations. 321 /// 322 /// Different I/O backends can implement this trait to expose only the operations they support. 323 /// 324 /// For example, a PCI configuration space may implement `IoCapable<u8>`, `IoCapable<u16>`, 325 /// and `IoCapable<u32>`, but not `IoCapable<u64>`, while an MMIO region on a 64-bit 326 /// system might implement all four. 327 pub trait IoCapable<T> { 328 /// Performs an I/O read of type `T` at `address` and returns the result. 329 /// 330 /// # Safety 331 /// 332 /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`. 333 unsafe fn io_read(&self, address: usize) -> T; 334 335 /// Performs an I/O write of `value` at `address`. 336 /// 337 /// # Safety 338 /// 339 /// The range `[address..address + size_of::<T>()]` must be within the bounds of `Self`. 340 unsafe fn io_write(&self, value: T, address: usize); 341 } 342 343 /// Types implementing this trait (e.g. MMIO BARs or PCI config regions) 344 /// can perform I/O operations on regions of memory. 345 /// 346 /// This is an abstract representation to be implemented by arbitrary I/O 347 /// backends (e.g. MMIO, PCI config space, etc.). 348 /// 349 /// The [`Io`] trait provides: 350 /// - Base address and size information 351 /// - Helper methods for offset validation and address calculation 352 /// - Fallible (runtime checked) accessors for different data widths 353 /// 354 /// Which I/O methods are available depends on which [`IoCapable<T>`] traits 355 /// are implemented for the type. 356 /// 357 /// # Examples 358 /// 359 /// For MMIO regions, all widths (u8, u16, u32, and u64 on 64-bit systems) are typically 360 /// supported. For PCI configuration space, u8, u16, and u32 are supported but u64 is not. 361 pub trait Io { 362 /// Returns the base address of this mapping. 363 fn addr(&self) -> usize; 364 365 /// Returns the maximum size of this mapping. 366 fn maxsize(&self) -> usize; 367 368 /// Returns the absolute I/O address for a given `offset`, 369 /// performing runtime bound checks. 370 #[inline] 371 fn io_addr<U>(&self, offset: usize) -> Result<usize> { 372 if !offset_valid::<U>(offset, self.maxsize()) { 373 return Err(EINVAL); 374 } 375 376 // Probably no need to check, since the safety requirements of `Self::new` guarantee that 377 // this can't overflow. 378 self.addr().checked_add(offset).ok_or(EINVAL) 379 } 380 381 /// Fallible 8-bit read with runtime bounds check. 382 #[inline(always)] 383 fn try_read8(&self, offset: usize) -> Result<u8> 384 where 385 Self: IoCapable<u8>, 386 { 387 let address = self.io_addr::<u8>(offset)?; 388 389 // SAFETY: `address` has been validated by `io_addr`. 390 Ok(unsafe { self.io_read(address) }) 391 } 392 393 /// Fallible 16-bit read with runtime bounds check. 394 #[inline(always)] 395 fn try_read16(&self, offset: usize) -> Result<u16> 396 where 397 Self: IoCapable<u16>, 398 { 399 let address = self.io_addr::<u16>(offset)?; 400 401 // SAFETY: `address` has been validated by `io_addr`. 402 Ok(unsafe { self.io_read(address) }) 403 } 404 405 /// Fallible 32-bit read with runtime bounds check. 406 #[inline(always)] 407 fn try_read32(&self, offset: usize) -> Result<u32> 408 where 409 Self: IoCapable<u32>, 410 { 411 let address = self.io_addr::<u32>(offset)?; 412 413 // SAFETY: `address` has been validated by `io_addr`. 414 Ok(unsafe { self.io_read(address) }) 415 } 416 417 /// Fallible 64-bit read with runtime bounds check. 418 #[inline(always)] 419 fn try_read64(&self, offset: usize) -> Result<u64> 420 where 421 Self: IoCapable<u64>, 422 { 423 let address = self.io_addr::<u64>(offset)?; 424 425 // SAFETY: `address` has been validated by `io_addr`. 426 Ok(unsafe { self.io_read(address) }) 427 } 428 429 /// Fallible 8-bit write with runtime bounds check. 430 #[inline(always)] 431 fn try_write8(&self, value: u8, offset: usize) -> Result 432 where 433 Self: IoCapable<u8>, 434 { 435 let address = self.io_addr::<u8>(offset)?; 436 437 // SAFETY: `address` has been validated by `io_addr`. 438 unsafe { self.io_write(value, address) }; 439 Ok(()) 440 } 441 442 /// Fallible 16-bit write with runtime bounds check. 443 #[inline(always)] 444 fn try_write16(&self, value: u16, offset: usize) -> Result 445 where 446 Self: IoCapable<u16>, 447 { 448 let address = self.io_addr::<u16>(offset)?; 449 450 // SAFETY: `address` has been validated by `io_addr`. 451 unsafe { self.io_write(value, address) }; 452 Ok(()) 453 } 454 455 /// Fallible 32-bit write with runtime bounds check. 456 #[inline(always)] 457 fn try_write32(&self, value: u32, offset: usize) -> Result 458 where 459 Self: IoCapable<u32>, 460 { 461 let address = self.io_addr::<u32>(offset)?; 462 463 // SAFETY: `address` has been validated by `io_addr`. 464 unsafe { self.io_write(value, address) }; 465 Ok(()) 466 } 467 468 /// Fallible 64-bit write with runtime bounds check. 469 #[inline(always)] 470 fn try_write64(&self, value: u64, offset: usize) -> Result 471 where 472 Self: IoCapable<u64>, 473 { 474 let address = self.io_addr::<u64>(offset)?; 475 476 // SAFETY: `address` has been validated by `io_addr`. 477 unsafe { self.io_write(value, address) }; 478 Ok(()) 479 } 480 481 /// Infallible 8-bit read with compile-time bounds check. 482 #[inline(always)] 483 fn read8(&self, offset: usize) -> u8 484 where 485 Self: IoKnownSize + IoCapable<u8>, 486 { 487 let address = self.io_addr_assert::<u8>(offset); 488 489 // SAFETY: `address` has been validated by `io_addr_assert`. 490 unsafe { self.io_read(address) } 491 } 492 493 /// Infallible 16-bit read with compile-time bounds check. 494 #[inline(always)] 495 fn read16(&self, offset: usize) -> u16 496 where 497 Self: IoKnownSize + IoCapable<u16>, 498 { 499 let address = self.io_addr_assert::<u16>(offset); 500 501 // SAFETY: `address` has been validated by `io_addr_assert`. 502 unsafe { self.io_read(address) } 503 } 504 505 /// Infallible 32-bit read with compile-time bounds check. 506 #[inline(always)] 507 fn read32(&self, offset: usize) -> u32 508 where 509 Self: IoKnownSize + IoCapable<u32>, 510 { 511 let address = self.io_addr_assert::<u32>(offset); 512 513 // SAFETY: `address` has been validated by `io_addr_assert`. 514 unsafe { self.io_read(address) } 515 } 516 517 /// Infallible 64-bit read with compile-time bounds check. 518 #[inline(always)] 519 fn read64(&self, offset: usize) -> u64 520 where 521 Self: IoKnownSize + IoCapable<u64>, 522 { 523 let address = self.io_addr_assert::<u64>(offset); 524 525 // SAFETY: `address` has been validated by `io_addr_assert`. 526 unsafe { self.io_read(address) } 527 } 528 529 /// Infallible 8-bit write with compile-time bounds check. 530 #[inline(always)] 531 fn write8(&self, value: u8, offset: usize) 532 where 533 Self: IoKnownSize + IoCapable<u8>, 534 { 535 let address = self.io_addr_assert::<u8>(offset); 536 537 // SAFETY: `address` has been validated by `io_addr_assert`. 538 unsafe { self.io_write(value, address) } 539 } 540 541 /// Infallible 16-bit write with compile-time bounds check. 542 #[inline(always)] 543 fn write16(&self, value: u16, offset: usize) 544 where 545 Self: IoKnownSize + IoCapable<u16>, 546 { 547 let address = self.io_addr_assert::<u16>(offset); 548 549 // SAFETY: `address` has been validated by `io_addr_assert`. 550 unsafe { self.io_write(value, address) } 551 } 552 553 /// Infallible 32-bit write with compile-time bounds check. 554 #[inline(always)] 555 fn write32(&self, value: u32, offset: usize) 556 where 557 Self: IoKnownSize + IoCapable<u32>, 558 { 559 let address = self.io_addr_assert::<u32>(offset); 560 561 // SAFETY: `address` has been validated by `io_addr_assert`. 562 unsafe { self.io_write(value, address) } 563 } 564 565 /// Infallible 64-bit write with compile-time bounds check. 566 #[inline(always)] 567 fn write64(&self, value: u64, offset: usize) 568 where 569 Self: IoKnownSize + IoCapable<u64>, 570 { 571 let address = self.io_addr_assert::<u64>(offset); 572 573 // SAFETY: `address` has been validated by `io_addr_assert`. 574 unsafe { self.io_write(value, address) } 575 } 576 } 577 578 /// Trait for types with a known size at compile time. 579 /// 580 /// This trait is implemented by I/O backends that have a compile-time known size, 581 /// enabling the use of infallible I/O accessors with compile-time bounds checking. 582 /// 583 /// Types implementing this trait can use the infallible methods in [`Io`] trait 584 /// (e.g., `read8`, `write32`), which require `Self: IoKnownSize` bound. 585 pub trait IoKnownSize: Io { 586 /// Minimum usable size of this region. 587 const MIN_SIZE: usize; 588 589 /// Returns the absolute I/O address for a given `offset`, 590 /// performing compile-time bound checks. 591 // Always inline to optimize out error path of `build_assert`. 592 #[inline(always)] 593 fn io_addr_assert<U>(&self, offset: usize) -> usize { 594 build_assert!(offset_valid::<U>(offset, Self::MIN_SIZE)); 595 596 self.addr() + offset 597 } 598 } 599 600 /// Implements [`IoCapable`] on `$mmio` for `$ty` using `$read_fn` and `$write_fn`. 601 macro_rules! impl_mmio_io_capable { 602 ($mmio:ident, $(#[$attr:meta])* $ty:ty, $read_fn:ident, $write_fn:ident) => { 603 $(#[$attr])* 604 impl<const SIZE: usize> IoCapable<$ty> for $mmio<SIZE> { 605 unsafe fn io_read(&self, address: usize) -> $ty { 606 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations. 607 unsafe { bindings::$read_fn(address as *const c_void) } 608 } 609 610 unsafe fn io_write(&self, value: $ty, address: usize) { 611 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations. 612 unsafe { bindings::$write_fn(value, address as *mut c_void) } 613 } 614 } 615 }; 616 } 617 618 // MMIO regions support 8, 16, and 32-bit accesses. 619 impl_mmio_io_capable!(Mmio, u8, readb, writeb); 620 impl_mmio_io_capable!(Mmio, u16, readw, writew); 621 impl_mmio_io_capable!(Mmio, u32, readl, writel); 622 // MMIO regions on 64-bit systems also support 64-bit accesses. 623 impl_mmio_io_capable!( 624 Mmio, 625 #[cfg(CONFIG_64BIT)] 626 u64, 627 readq, 628 writeq 629 ); 630 631 impl<const SIZE: usize> Io for Mmio<SIZE> { 632 /// Returns the base address of this mapping. 633 #[inline] 634 fn addr(&self) -> usize { 635 self.0.addr() 636 } 637 638 /// Returns the maximum size of this mapping. 639 #[inline] 640 fn maxsize(&self) -> usize { 641 self.0.maxsize() 642 } 643 644 io_define_read!(fallible, try_read8, call_mmio_read(readb) -> u8); 645 io_define_read!(fallible, try_read16, call_mmio_read(readw) -> u16); 646 io_define_read!(fallible, try_read32, call_mmio_read(readl) -> u32); 647 io_define_read!( 648 fallible, 649 #[cfg(CONFIG_64BIT)] 650 try_read64, 651 call_mmio_read(readq) -> u64 652 ); 653 654 io_define_write!(fallible, try_write8, call_mmio_write(writeb) <- u8); 655 io_define_write!(fallible, try_write16, call_mmio_write(writew) <- u16); 656 io_define_write!(fallible, try_write32, call_mmio_write(writel) <- u32); 657 io_define_write!( 658 fallible, 659 #[cfg(CONFIG_64BIT)] 660 try_write64, 661 call_mmio_write(writeq) <- u64 662 ); 663 664 io_define_read!(infallible, read8, call_mmio_read(readb) -> u8); 665 io_define_read!(infallible, read16, call_mmio_read(readw) -> u16); 666 io_define_read!(infallible, read32, call_mmio_read(readl) -> u32); 667 io_define_read!( 668 infallible, 669 #[cfg(CONFIG_64BIT)] 670 read64, 671 call_mmio_read(readq) -> u64 672 ); 673 674 io_define_write!(infallible, write8, call_mmio_write(writeb) <- u8); 675 io_define_write!(infallible, write16, call_mmio_write(writew) <- u16); 676 io_define_write!(infallible, write32, call_mmio_write(writel) <- u32); 677 io_define_write!( 678 infallible, 679 #[cfg(CONFIG_64BIT)] 680 write64, 681 call_mmio_write(writeq) <- u64 682 ); 683 } 684 685 impl<const SIZE: usize> IoKnownSize for Mmio<SIZE> { 686 const MIN_SIZE: usize = SIZE; 687 } 688 689 impl<const SIZE: usize> Mmio<SIZE> { 690 /// Converts an `MmioRaw` into an `Mmio` instance, providing the accessors to the MMIO mapping. 691 /// 692 /// # Safety 693 /// 694 /// Callers must ensure that `addr` is the start of a valid I/O mapped memory region of size 695 /// `maxsize`. 696 pub unsafe fn from_raw(raw: &MmioRaw<SIZE>) -> &Self { 697 // SAFETY: `Mmio` is a transparent wrapper around `MmioRaw`. 698 unsafe { &*core::ptr::from_ref(raw).cast() } 699 } 700 } 701 702 /// [`Mmio`] wrapper using relaxed accessors. 703 /// 704 /// This type provides an implementation of [`Io`] that uses relaxed I/O MMIO operands instead of 705 /// the regular ones. 706 /// 707 /// See [`Mmio::relaxed`] for a usage example. 708 #[repr(transparent)] 709 pub struct RelaxedMmio<const SIZE: usize = 0>(Mmio<SIZE>); 710 711 impl<const SIZE: usize> Io for RelaxedMmio<SIZE> { 712 #[inline] 713 fn addr(&self) -> usize { 714 self.0.addr() 715 } 716 717 #[inline] 718 fn maxsize(&self) -> usize { 719 self.0.maxsize() 720 } 721 } 722 723 impl<const SIZE: usize> IoKnownSize for RelaxedMmio<SIZE> { 724 const MIN_SIZE: usize = SIZE; 725 } 726 727 impl<const SIZE: usize> Mmio<SIZE> { 728 /// Returns a [`RelaxedMmio`] reference that performs relaxed I/O operations. 729 /// 730 /// Relaxed accessors do not provide ordering guarantees with respect to DMA or memory accesses 731 /// and can be used when such ordering is not required. 732 /// 733 /// # Examples 734 /// 735 /// ```no_run 736 /// use kernel::io::{ 737 /// Io, 738 /// Mmio, 739 /// RelaxedMmio, 740 /// }; 741 /// 742 /// fn do_io(io: &Mmio<0x100>) { 743 /// // The access is performed using `readl_relaxed` instead of `readl`. 744 /// let v = io.relaxed().read32(0x10); 745 /// } 746 /// 747 /// ``` 748 pub fn relaxed(&self) -> &RelaxedMmio<SIZE> { 749 // SAFETY: `RelaxedMmio` is `#[repr(transparent)]` over `Mmio`, so `Mmio<SIZE>` and 750 // `RelaxedMmio<SIZE>` have identical layout. 751 unsafe { core::mem::transmute(self) } 752 } 753 } 754 755 // MMIO regions support 8, 16, and 32-bit accesses. 756 impl_mmio_io_capable!(RelaxedMmio, u8, readb_relaxed, writeb_relaxed); 757 impl_mmio_io_capable!(RelaxedMmio, u16, readw_relaxed, writew_relaxed); 758 impl_mmio_io_capable!(RelaxedMmio, u32, readl_relaxed, writel_relaxed); 759 // MMIO regions on 64-bit systems also support 64-bit accesses. 760 impl_mmio_io_capable!( 761 RelaxedMmio, 762 #[cfg(CONFIG_64BIT)] 763 u64, 764 readq_relaxed, 765 writeq_relaxed 766 ); 767