mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	 6f17ab9a63
			
		
	
	
		6f17ab9a63
		
	
	
	
	
		
			
			Alloc
   - Add BorrowedPage type and AsPageIter trait
   - Implement Vmalloc::to_page() and VmallocPageIter
   - Implement AsPageIter for VBox and VVec
 
 DMA & Scatterlist
   - Add dma::DataDirection and type alias for dma_addr_t
   - Abstraction for struct scatterlist and struct sg_table
 
 DRM
   - In the DRM GEM module, simplify overall use of generics, add
     DriverFile type alias and drop Object::SIZE.
 
 Nova (Core)
   - Various register!() macro improvements (paving the way for lifting
     it to common driver infrastructure)
   - Minor VBios fixes and refactoring
   - Minor firmware request refactoring
   - Advance firmware boot stages; process Booter and patch its
     signature, process GSP and GSP bootloader
   - Switch development fimrware version to r570.144
   - Add basic firmware bindings for r570.144
   - Move GSP boot code to its own module
   - Clean up and take advantage of pin-init features to store most of
     the driver's private data within a single allocation
   - Update ARef import from sync::aref
   - Add website to MAINTAINERS entry
 
 Nova (DRM)
   - Update ARef import from sync::aref
   - Add website to MAINTAINERS entry
 
 Pin-Init
   - Merge pin-init PR from Benno
     - `#[pin_data]` now generates a `*Projection` struct similar to the
       `pin-project` crate.
 
     - Add initializer code blocks to `[try_][pin_]init!` macros: make
       initializer macros accept any number of `_: {/* arbitrary code
       */},` & make them run the code at that point.
 
     - Make the `[try_][pin_]init!` macros expose initialized fields via
       a `let` binding as `&mut T` or `Pin<&mut T>` for later fields.
 
 Rust
   - Various methods for AsBytes and FromBytes traits
 
 Tyr
   - Initial Rust driver skeleton for ARM Mali GPUs.
     - It can power up the GPU, query for GPU metatdata through MMIO and
       provide the metadata to userspace via DRM device IOCTL (struct
       drm_panthor_dev_query).
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQS2q/xV6QjXAdC7k+1FlHeO1qrKLgUCaMlv1gAKCRBFlHeO1qrK
 Lu8uAQDTJvYuAvSh9MyeSWhOl6H+7u4CpRb3FeatQsApnn7mRQD9Ft1RJyB7keRm
 vDUsGZi4P9f5BDwXOLq6aRRzuxWIvQc=
 =fvs6
 -----END PGP SIGNATURE-----
Merge tag 'drm-rust-next-2025-09-16' of https://gitlab.freedesktop.org/drm/rust/kernel into drm-next
DRM Rust changes for v6.18
Alloc
  - Add BorrowedPage type and AsPageIter trait
  - Implement Vmalloc::to_page() and VmallocPageIter
  - Implement AsPageIter for VBox and VVec
DMA & Scatterlist
  - Add dma::DataDirection and type alias for dma_addr_t
  - Abstraction for struct scatterlist and struct sg_table
DRM
  - In the DRM GEM module, simplify overall use of generics, add
    DriverFile type alias and drop Object::SIZE.
Nova (Core)
  - Various register!() macro improvements (paving the way for lifting
    it to common driver infrastructure)
  - Minor VBios fixes and refactoring
  - Minor firmware request refactoring
  - Advance firmware boot stages; process Booter and patch its
    signature, process GSP and GSP bootloader
  - Switch development fimrware version to r570.144
  - Add basic firmware bindings for r570.144
  - Move GSP boot code to its own module
  - Clean up and take advantage of pin-init features to store most of
    the driver's private data within a single allocation
  - Update ARef import from sync::aref
  - Add website to MAINTAINERS entry
Nova (DRM)
  - Update ARef import from sync::aref
  - Add website to MAINTAINERS entry
Pin-Init
  - Merge pin-init PR from Benno
    - `#[pin_data]` now generates a `*Projection` struct similar to the
      `pin-project` crate.
    - Add initializer code blocks to `[try_][pin_]init!` macros: make
      initializer macros accept any number of `_: {/* arbitrary code
      */},` & make them run the code at that point.
    - Make the `[try_][pin_]init!` macros expose initialized fields via
      a `let` binding as `&mut T` or `Pin<&mut T>` for later fields.
Rust
  - Various methods for AsBytes and FromBytes traits
Tyr
  - Initial Rust driver skeleton for ARM Mali GPUs.
    - It can power up the GPU, query for GPU metatdata through MMIO and
      provide the metadata to userspace via DRM device IOCTL (struct
      drm_panthor_dev_query).
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: "Danilo Krummrich" <dakr@kernel.org>
Link: https://lore.kernel.org/r/DCUC4SY6SRBD.1ZLHAIQZOC6KG@kernel.org
		
	
			
		
			
				
	
	
		
			247 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| 
 | |
| //! Allocator support.
 | |
| //!
 | |
| //! Documentation for the kernel's memory allocators can found in the "Memory Allocation Guide"
 | |
| //! linked below. For instance, this includes the concept of "get free page" (GFP) flags and the
 | |
| //! typical application of the different kernel allocators.
 | |
| //!
 | |
| //! Reference: <https://docs.kernel.org/core-api/memory-allocation.html>
 | |
| 
 | |
| use super::Flags;
 | |
| use core::alloc::Layout;
 | |
| use core::ptr;
 | |
| use core::ptr::NonNull;
 | |
| 
 | |
| use crate::alloc::{AllocError, Allocator};
 | |
| use crate::bindings;
 | |
| use crate::page;
 | |
| use crate::pr_warn;
 | |
| 
 | |
| mod iter;
 | |
| pub use self::iter::VmallocPageIter;
 | |
| 
 | |
| /// The contiguous kernel allocator.
 | |
| ///
 | |
| /// `Kmalloc` is typically used for physically contiguous allocations up to page size, but also
 | |
| /// supports larger allocations up to `bindings::KMALLOC_MAX_SIZE`, which is hardware specific.
 | |
| ///
 | |
| /// For more details see [self].
 | |
| pub struct Kmalloc;
 | |
| 
 | |
| /// The virtually contiguous kernel allocator.
 | |
| ///
 | |
| /// `Vmalloc` allocates pages from the page level allocator and maps them into the contiguous kernel
 | |
| /// virtual space. It is typically used for large allocations. The memory allocated with this
 | |
| /// allocator is not physically contiguous.
 | |
| ///
 | |
| /// For more details see [self].
 | |
| pub struct Vmalloc;
 | |
| 
 | |
| /// The kvmalloc kernel allocator.
 | |
| ///
 | |
| /// `KVmalloc` attempts to allocate memory with `Kmalloc` first, but falls back to `Vmalloc` upon
 | |
| /// failure. This allocator is typically used when the size for the requested allocation is not
 | |
| /// known and may exceed the capabilities of `Kmalloc`.
 | |
| ///
 | |
| /// For more details see [self].
 | |
| pub struct KVmalloc;
 | |
| 
 | |
| /// # Invariants
 | |
| ///
 | |
| /// One of the following: `krealloc`, `vrealloc`, `kvrealloc`.
 | |
| struct ReallocFunc(
 | |
|     unsafe extern "C" fn(*const crate::ffi::c_void, usize, u32) -> *mut crate::ffi::c_void,
 | |
| );
 | |
| 
 | |
| impl ReallocFunc {
 | |
|     // INVARIANT: `krealloc` satisfies the type invariants.
 | |
|     const KREALLOC: Self = Self(bindings::krealloc);
 | |
| 
 | |
|     // INVARIANT: `vrealloc` satisfies the type invariants.
 | |
|     const VREALLOC: Self = Self(bindings::vrealloc);
 | |
| 
 | |
|     // INVARIANT: `kvrealloc` satisfies the type invariants.
 | |
|     const KVREALLOC: Self = Self(bindings::kvrealloc);
 | |
| 
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// This method has the same safety requirements as [`Allocator::realloc`].
 | |
|     ///
 | |
|     /// # Guarantees
 | |
|     ///
 | |
|     /// This method has the same guarantees as `Allocator::realloc`. Additionally
 | |
|     /// - it accepts any pointer to a valid memory allocation allocated by this function.
 | |
|     /// - memory allocated by this function remains valid until it is passed to this function.
 | |
|     #[inline]
 | |
|     unsafe fn call(
 | |
|         &self,
 | |
|         ptr: Option<NonNull<u8>>,
 | |
|         layout: Layout,
 | |
|         old_layout: Layout,
 | |
|         flags: Flags,
 | |
|     ) -> Result<NonNull<[u8]>, AllocError> {
 | |
|         let size = layout.size();
 | |
|         let ptr = match ptr {
 | |
|             Some(ptr) => {
 | |
|                 if old_layout.size() == 0 {
 | |
|                     ptr::null()
 | |
|                 } else {
 | |
|                     ptr.as_ptr()
 | |
|                 }
 | |
|             }
 | |
|             None => ptr::null(),
 | |
|         };
 | |
| 
 | |
|         // SAFETY:
 | |
|         // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc` and thus only requires that
 | |
|         //   `ptr` is NULL or valid.
 | |
|         // - `ptr` is either NULL or valid by the safety requirements of this function.
 | |
|         //
 | |
|         // GUARANTEE:
 | |
|         // - `self.0` is one of `krealloc`, `vrealloc`, `kvrealloc`.
 | |
|         // - Those functions provide the guarantees of this function.
 | |
|         let raw_ptr = unsafe {
 | |
|             // If `size == 0` and `ptr != NULL` the memory behind the pointer is freed.
 | |
|             self.0(ptr.cast(), size, flags.0).cast()
 | |
|         };
 | |
| 
 | |
|         let ptr = if size == 0 {
 | |
|             crate::alloc::dangling_from_layout(layout)
 | |
|         } else {
 | |
|             NonNull::new(raw_ptr).ok_or(AllocError)?
 | |
|         };
 | |
| 
 | |
|         Ok(NonNull::slice_from_raw_parts(ptr, size))
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Kmalloc {
 | |
|     /// Returns a [`Layout`] that makes [`Kmalloc`] fulfill the requested size and alignment of
 | |
|     /// `layout`.
 | |
|     pub fn aligned_layout(layout: Layout) -> Layout {
 | |
|         // Note that `layout.size()` (after padding) is guaranteed to be a multiple of
 | |
|         // `layout.align()` which together with the slab guarantees means that `Kmalloc` will return
 | |
|         // a properly aligned object (see comments in `kmalloc()` for more information).
 | |
|         layout.pad_to_align()
 | |
|     }
 | |
| }
 | |
| 
 | |
| // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
 | |
| // - memory remains valid until it is explicitly freed,
 | |
| // - passing a pointer to a valid memory allocation is OK,
 | |
| // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
 | |
| unsafe impl Allocator for Kmalloc {
 | |
|     #[inline]
 | |
|     unsafe fn realloc(
 | |
|         ptr: Option<NonNull<u8>>,
 | |
|         layout: Layout,
 | |
|         old_layout: Layout,
 | |
|         flags: Flags,
 | |
|     ) -> Result<NonNull<[u8]>, AllocError> {
 | |
|         let layout = Kmalloc::aligned_layout(layout);
 | |
| 
 | |
|         // SAFETY: `ReallocFunc::call` has the same safety requirements as `Allocator::realloc`.
 | |
|         unsafe { ReallocFunc::KREALLOC.call(ptr, layout, old_layout, flags) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Vmalloc {
 | |
|     /// Convert a pointer to a [`Vmalloc`] allocation to a [`page::BorrowedPage`].
 | |
|     ///
 | |
|     /// # Examples
 | |
|     ///
 | |
|     /// ```
 | |
|     /// # use core::ptr::{NonNull, from_mut};
 | |
|     /// # use kernel::{page, prelude::*};
 | |
|     /// use kernel::alloc::allocator::Vmalloc;
 | |
|     ///
 | |
|     /// let mut vbox = VBox::<[u8; page::PAGE_SIZE]>::new_uninit(GFP_KERNEL)?;
 | |
|     ///
 | |
|     /// {
 | |
|     ///     // SAFETY: By the type invariant of `Box` the inner pointer of `vbox` is non-null.
 | |
|     ///     let ptr = unsafe { NonNull::new_unchecked(from_mut(&mut *vbox)) };
 | |
|     ///
 | |
|     ///     // SAFETY:
 | |
|     ///     // `ptr` is a valid pointer to a `Vmalloc` allocation.
 | |
|     ///     // `ptr` is valid for the entire lifetime of `page`.
 | |
|     ///     let page = unsafe { Vmalloc::to_page(ptr.cast()) };
 | |
|     ///
 | |
|     ///     // SAFETY: There is no concurrent read or write to the same page.
 | |
|     ///     unsafe { page.fill_zero_raw(0, page::PAGE_SIZE)? };
 | |
|     /// }
 | |
|     /// # Ok::<(), Error>(())
 | |
|     /// ```
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// - `ptr` must be a valid pointer to a [`Vmalloc`] allocation.
 | |
|     /// - `ptr` must remain valid for the entire duration of `'a`.
 | |
|     pub unsafe fn to_page<'a>(ptr: NonNull<u8>) -> page::BorrowedPage<'a> {
 | |
|         // SAFETY: `ptr` is a valid pointer to `Vmalloc` memory.
 | |
|         let page = unsafe { bindings::vmalloc_to_page(ptr.as_ptr().cast()) };
 | |
| 
 | |
|         // SAFETY: `vmalloc_to_page` returns a valid pointer to a `struct page` for a valid pointer
 | |
|         // to `Vmalloc` memory.
 | |
|         let page = unsafe { NonNull::new_unchecked(page) };
 | |
| 
 | |
|         // SAFETY:
 | |
|         // - `page` is a valid pointer to a `struct page`, given that by the safety requirements of
 | |
|         //   this function `ptr` is a valid pointer to a `Vmalloc` allocation.
 | |
|         // - By the safety requirements of this function `ptr` is valid for the entire lifetime of
 | |
|         //   `'a`.
 | |
|         unsafe { page::BorrowedPage::from_raw(page) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
 | |
| // - memory remains valid until it is explicitly freed,
 | |
| // - passing a pointer to a valid memory allocation is OK,
 | |
| // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
 | |
| unsafe impl Allocator for Vmalloc {
 | |
|     #[inline]
 | |
|     unsafe fn realloc(
 | |
|         ptr: Option<NonNull<u8>>,
 | |
|         layout: Layout,
 | |
|         old_layout: Layout,
 | |
|         flags: Flags,
 | |
|     ) -> Result<NonNull<[u8]>, AllocError> {
 | |
|         // TODO: Support alignments larger than PAGE_SIZE.
 | |
|         if layout.align() > bindings::PAGE_SIZE {
 | |
|             pr_warn!("Vmalloc does not support alignments larger than PAGE_SIZE yet.\n");
 | |
|             return Err(AllocError);
 | |
|         }
 | |
| 
 | |
|         // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
 | |
|         // allocated with this `Allocator`.
 | |
|         unsafe { ReallocFunc::VREALLOC.call(ptr, layout, old_layout, flags) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // SAFETY: `realloc` delegates to `ReallocFunc::call`, which guarantees that
 | |
| // - memory remains valid until it is explicitly freed,
 | |
| // - passing a pointer to a valid memory allocation is OK,
 | |
| // - `realloc` satisfies the guarantees, since `ReallocFunc::call` has the same.
 | |
| unsafe impl Allocator for KVmalloc {
 | |
|     #[inline]
 | |
|     unsafe fn realloc(
 | |
|         ptr: Option<NonNull<u8>>,
 | |
|         layout: Layout,
 | |
|         old_layout: Layout,
 | |
|         flags: Flags,
 | |
|     ) -> Result<NonNull<[u8]>, AllocError> {
 | |
|         // `KVmalloc` may use the `Kmalloc` backend, hence we have to enforce a `Kmalloc`
 | |
|         // compatible layout.
 | |
|         let layout = Kmalloc::aligned_layout(layout);
 | |
| 
 | |
|         // TODO: Support alignments larger than PAGE_SIZE.
 | |
|         if layout.align() > bindings::PAGE_SIZE {
 | |
|             pr_warn!("KVmalloc does not support alignments larger than PAGE_SIZE yet.\n");
 | |
|             return Err(AllocError);
 | |
|         }
 | |
| 
 | |
|         // SAFETY: If not `None`, `ptr` is guaranteed to point to valid memory, which was previously
 | |
|         // allocated with this `Allocator`.
 | |
|         unsafe { ReallocFunc::KVREALLOC.call(ptr, layout, old_layout, flags) }
 | |
|     }
 | |
| }
 |