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