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