diff options
| author | Danilo Krummrich <dakr@kernel.org> | 2026-07-14 00:01:19 +0200 |
|---|---|---|
| committer | Danilo Krummrich <dakr@kernel.org> | 2026-07-14 00:01:38 +0200 |
| commit | 2059254536f4376eeeebee746aa44b4b03db1a5a (patch) | |
| tree | f13154468e8eca9f509ee12f2e07dd1fb1cde2ea /rust/kernel/drm | |
| parent | 6cb3fdc9f5aeb0c5c0f68a28e9370cbe37f555f2 (diff) | |
| parent | 11a4784f902ebf3e674dbaf07dbec9a37aabb5e4 (diff) | |
| download | linux-next-2059254536f4376eeeebee746aa44b4b03db1a5a.tar.gz linux-next-2059254536f4376eeeebee746aa44b4b03db1a5a.zip | |
Merge tag 'rust-io-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core into drm-rust-next
I/O type generalization and projection
This series presents a major rework of I/O types, as a summary:
- Make I/O regions typed. The existing untyped region still exists
with a dynamically sized `Region` type.
- Create I/O view types to represent subregion of a full I/O region mapped.
A projection macro is added to allow safely create such subviews.
- Split I/O traits, make I/O views play a central role, avoid
duplicate monomorphization and less `unsafe` code.
- Add a `SysMem` backend, and make `Coherent` implement `Io`.
- Add copying methods (memcpy_{from,to}io and friends).
This series generalize `Mmio` type from just an untyped region to typed
representations (so `MmioRaw<T>` is `__iomem *T`). This allows us to remove
the `IoKnownSize` trait; the information is sourced from just the pointer
from the `KnownSize` trait instead.
Building on top of that, `Mmio` and `ConfigSpace` have been converted to
typed views of I/O regions rather than just a big chunk of untyped I/O
memory. These changes made it possible to implement `Io` trait for
`Coherent<T>`.
Shared system memory, `SysMem` is also added to the series, given it
similarity in implementation compared to `Coherent`. In fact, the series
use `SysMem` to implement `Coherent`'s I/O methods.
Built on these generalization, this series add `io_project!()`.
`io_project!()` performs a safe way to project a bigger view to a small
subviews, and some Nova code has been converted in this series to
demonstrate cleanups possible with this addition.
New `io_read!()`, `io_write!()` has been added that supersedes
`dma_read!()`, `dma_write!()` macro. Although, they work for primitives
only (to be exact, types that the backend is `IoCapable` of).
One feature that was lost from the old `dma_read!()` and `dma_write!()`
series was the ability to read/write a large structs. However, the
semantics was unclear to begin with, as there was no guarantee about their
atomicity even for structs that were small enough to fit in u32.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/Generic.20I.2FO.20backends/near/571198078
This is a stable tag for other trees to merge.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Diffstat (limited to 'rust/kernel/drm')
| -rw-r--r-- | rust/kernel/drm/gem/shmem.rs | 93 |
1 files changed, 28 insertions, 65 deletions
diff --git a/rust/kernel/drm/gem/shmem.rs b/rust/kernel/drm/gem/shmem.rs index 60dca8871b87..580e0808d6c0 100644 --- a/rust/kernel/drm/gem/shmem.rs +++ b/rust/kernel/drm/gem/shmem.rs @@ -27,9 +27,10 @@ use crate::{ to_result, // }, io::{ - Io, - IoCapable, - IoKnownSize, // + IoBase, + Region, + SysMem, + SysMemBackend, // }, prelude::*, scatterlist, @@ -456,6 +457,27 @@ where } } +impl<'a, D, R, const SIZE: usize> IoBase<'a> for &'a VMap<D, R, SIZE> +where + D: DriverObject, + R: Deref<Target = Object<D>>, +{ + type Backend = SysMemBackend; + type Target = Region<SIZE>; + + #[inline] + fn as_view(self) -> SysMem<'a, Region<SIZE>> { + let ptr = Region::ptr_from_raw_parts_mut(self.addr.cast(), self.owner.size()); + + // SAFETY: Per type invariants of `VMap`: + // - `addr .. addr + owner.size()` is a valid kernel accessible memory region. + // - `addr` is page-aligned, which satisfies `Region`'s 4-byte alignment requirement. + // - The memory remains valid until this `VMap` is dropped; since `self` is `&'a VMap`, + // the borrow prevents the `VMap` from being dropped for the lifetime `'a`. + unsafe { SysMem::new(ptr) } + } +} + impl<D, R, const SIZE: usize> Drop for VMap<D, R, SIZE> where D: DriverObject, @@ -494,66 +516,6 @@ where { } -impl<D, R, const SIZE: usize> Io for VMap<D, R, SIZE> -where - D: DriverObject, - R: Deref<Target = Object<D>>, -{ - #[inline] - fn addr(&self) -> usize { - self.addr as usize - } - - #[inline] - fn maxsize(&self) -> usize { - self.owner.size() - } -} - -impl<D, R, const SIZE: usize> IoKnownSize for VMap<D, R, SIZE> -where - D: DriverObject, - R: Deref<Target = Object<D>>, -{ - const MIN_SIZE: usize = SIZE; -} - -macro_rules! impl_vmap_io_capable { - ($ty:ty) => { - impl<D, R, const SIZE: usize> IoCapable<$ty> for VMap<D, R, SIZE> - where - D: DriverObject, - R: Deref<Target = Object<D>>, - { - #[inline] - unsafe fn io_read(&self, address: usize) -> $ty { - let ptr = address as *mut $ty; - - // SAFETY: The safety contract of `io_read` guarantees that address is a valid - // address within the bounds of `Self` of at least the size of $ty, and is properly - // aligned. - unsafe { ptr::read_volatile(ptr) } - } - - #[inline] - unsafe fn io_write(&self, value: $ty, address: usize) { - let ptr = address as *mut $ty; - - // SAFETY: The safety contract of `io_write` guarantees that address is a valid - // address within the bounds of `Self` of at least the size of $ty, and is properly - // aligned. - unsafe { ptr::write_volatile(ptr, value) } - } - } - }; -} - -impl_vmap_io_capable!(u8); -impl_vmap_io_capable!(u16); -impl_vmap_io_capable!(u32); -#[cfg(CONFIG_64BIT)] -impl_vmap_io_capable!(u64); - /// A reference to a GEM object that is known to have a mapped [`SGTable`]. /// /// This is used by the Rust bindings with [`Devres`] in order to ensure that mappings for SGTables @@ -621,6 +583,7 @@ mod tests { UnregisteredDevice, // }, faux, + io::Io, page::PAGE_SIZE, // }; @@ -699,8 +662,8 @@ mod tests { // Verify the owner matches assert!(ptr::eq(vmap.owner(), obj.deref())); - // Verify the max size matches the actual object size - assert_eq!(vmap.maxsize(), PAGE_SIZE); + // Verify the size matches the actual object size + assert_eq!(vmap.size(), PAGE_SIZE); // Make sure creating a vmap that's too large fails assert!(obj.vmap::<{ PAGE_SIZE + 200 }>().is_err()); |
