* [PATCH v12 0/1] Rust GPU buddy allocator bindings
@ 2026-03-08 18:04 Joel Fernandes
2026-03-08 18:04 ` [PATCH v12 1/1] rust: gpu: Add " Joel Fernandes
` (2 more replies)
0 siblings, 3 replies; 24+ messages in thread
From: Joel Fernandes @ 2026-03-08 18:04 UTC (permalink / raw)
To: linux-kernel
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning,
dri-devel, nouveau, rust-for-linux, Nikola Djukic,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Alex Deucher,
Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost,
Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor,
Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer,
Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang,
Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi,
Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe,
linux-fbdev, Joel Fernandes
This patch adds safe Rust abstractions over the Linux kernel's GPU buddy
allocator for physical memory management. The prerequisite infrastructure
patches (DRM buddy code movement and the uninitialized buddy fix) have been
absorbed into upstream -next, so this is now a standalone patch.
The series along with all dependencies, including clist and nova-core mm
patches, are available at:
git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: nova-mm-current-3-8)
This patch is also here:
https://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git/commit/?id=gpu-buddy-bindings-v12
Change log:
Changes from v11 to v12:
- Rebased on linux-next his is now a standalone single patch as dependencies
are absorbed (but not clist is a prequisite)
- Redesigned allocation API (Alexandre Courbot) for better Rust ergonomics.
- Split single long example into 4 self-contained examples (Alexandre Courbot).
- Several safety and invariant comment changes (Danilo).
- MAINTAINERS changes (Arun, Mathew, Danilo, Dave).
- Fixed `#[cfg(CONFIG_GPU_BUDDY)]` to `#[cfg(CONFIG_GPU_BUDDY = "y")]` (Danilo Krummrich).
- Updated `ffi::clist::CListHead` to `interop::list::CListHead`.
Changes from v10 to v11:
- Dropped "rust: ffi: Convert pub use to pub mod and create ffi module" patch;
the ffi module restructuring will go through a different path.
- Dropped "rust: clist: Add support to interface with C linked lists" patch;
the clist module will be submitted separately.
- Dropped "nova-core: Kconfig: Sort select statements alphabetically" cosmetic
patch.
- Patches 1-3 (DRM buddy movement and fix) are included as reference only;
they are already being pulled into upstream via drm-misc-next.
- Removed clist patches as those can go in independently (Alice).
- Moved the Kconfig GPU_BUDDY selection patch to nova-core mm series to enable
it when it is actually used.
- Various nits to comments, etc.
Changes from v9 to v10:
- Absorbed the DRM buddy code movement patches into this series as patches 1-2.
Dave Airlie reworked these into two parts for better git history.
- Added "gpu: Fix uninitialized buddy for built-in drivers" fix by Koen Koning,
using subsys_initcall instead of module_init to fix NULL pointer dereference
when built-in drivers use the buddy allocator before initialization.
- Added "rust: ffi: Convert pub use to pub mod and create ffi module" to prepare
the ffi module for hosting clist as a sub-module.
- Moved clist from rust/kernel/clist.rs to rust/kernel/ffi/.
- Added "nova-core: Kconfig: Sort select statements alphabetically" (Danilo).
Changes from v8 to v9:
- Updated nova-core Kconfig patch: addressed sorting of Kconfig options.
- Added Daniel Almeida's Reviewed-by tag to clist patch.
- Minor refinements to GPU buddy bindings.
Changes from v7 to v8:
- Added nova-core Kconfig patch to select GPU_BUDDY for VRAM allocation.
- Various changes suggested by Danilo Krummrich, Gary Guo, and Daniel Almeida.
- Added Acked-by: Gary Guo for clist patch.
Changes from v6 to v7:
- Major restructuring: split the large 26-patch v6 RFC series. v7 only contains
the Rust infrastructure patches (clist + GPU buddy bindings), extracted from
the full nova-core MM series. The nova-core MM patches follow separately.
- Rebased on linux-next.
Changes from v5 to v6:
- Rebased on drm-rust-kernel/drm-rust-next.
- Expanded from 6 to 26 patches with full nova-core MM infrastructure including
page table walker, VMM, BAR1 user interface, TLB flush, and GpuMm manager.
Changes from v4 to v5:
- Added PRAMIN aperture support with documentation and self-tests.
- Improved buddy allocator bindings (fewer lines of code).
- Based on drm-rust-next instead of linux-next.
Changes from v3 to v4:
- Combined the clist and DRM buddy series into a single coherent series.
- Added DRM buddy allocator movement from drivers/gpu/drm/ up to drivers/gpu/,
renaming API from drm_buddy to gpu_buddy.
- Added Rust bindings for the GPU buddy allocator.
Changes from v2 to v3:
- Squashed 3 clist patches into one due to inter-dependencies.
- Changed Clist to Clist<'a, T> using const generic offset (Alex Courbot).
- Simplified C helpers to only list_add_tail (Alex Courbot, John Hubbard).
- Added init_list_head() Rust function (Alex Courbot).
- Added FusedIterator, PartialEq/Eq impls.
- Added MAINTAINERS entry (Miguel Ojeda).
Changes from v1 (RFC) to v2:
- Dropped DRM buddy allocator patches; series focuses solely on clist module.
- Dropped sample modules, replaced with doctests.
- Added proper lifetime management similar to scatterlist.
- Split clist into 3 separate patches.
Link to v11: https://lore.kernel.org/all/20260224224005.3232841-1-joelagnelf@nvidia.com/
Joel Fernandes (1):
rust: gpu: Add GPU buddy allocator bindings
MAINTAINERS | 6 +-
rust/bindings/bindings_helper.h | 11 +
rust/helpers/gpu.c | 23 ++
rust/helpers/helpers.c | 1 +
rust/kernel/gpu/buddy.rs | 611 ++++++++++++++++++++++++++++++++
rust/kernel/gpu/mod.rs | 5 +
rust/kernel/lib.rs | 2 +
7 files changed, 658 insertions(+), 1 deletion(-)
create mode 100644 rust/helpers/gpu.c
create mode 100644 rust/kernel/gpu/buddy.rs
create mode 100644 rust/kernel/gpu/mod.rs
--
2.34.1
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH v12 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-08 18:04 [PATCH v12 0/1] Rust GPU buddy allocator bindings Joel Fernandes @ 2026-03-08 18:04 ` Joel Fernandes 2026-03-09 13:53 ` [PATCH v12.1 0/1] Rust " Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 0/2] Rust " Joel Fernandes 2 siblings, 0 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-08 18:04 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Add safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The GPU buddy allocator implements a binary buddy system useful for GPU physical memory allocation. nova-core will use it for physical memory allocation. Christian Koenig mentioned he'd like to step down from reviewer role for GPU buddy so updated accordingly. Arun/Matthew agree on the modified entry. Cc: Nikola Djukic <ndjukic@nvidia.com> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- MAINTAINERS | 6 +- rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu/buddy.rs | 611 ++++++++++++++++++++++++++++++++ rust/kernel/gpu/mod.rs | 5 + rust/kernel/lib.rs | 2 + 7 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu/buddy.rs create mode 100644 rust/kernel/gpu/mod.rs diff --git a/MAINTAINERS b/MAINTAINERS index 4c66f8261ff2..b2600dd05fc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8513,7 +8513,9 @@ T: git https://gitlab.freedesktop.org/drm/rust/kernel.git F: drivers/gpu/drm/nova/ F: drivers/gpu/drm/tyr/ F: drivers/gpu/nova-core/ +F: rust/helpers/gpu.c F: rust/kernel/drm/ +F: rust/kernel/gpu/ DRM DRIVERS FOR ALLWINNER A10 M: Chen-Yu Tsai <wens@kernel.org> @@ -8926,7 +8928,7 @@ F: include/drm/ttm/ GPU BUDDY ALLOCATOR M: Matthew Auld <matthew.auld@intel.com> M: Arun Pravin <arunpravin.paneerselvam@amd.com> -R: Christian Koenig <christian.koenig@amd.com> +R: Joel Fernandes <joelagnelf@nvidia.com> L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git @@ -8935,6 +8937,8 @@ F: drivers/gpu/buddy.c F: drivers/gpu/tests/gpu_buddy_test.c F: include/linux/gpu_buddy.h F: include/drm/drm_buddy.h +F: rust/helpers/gpu.c +F: rust/kernel/gpu/ DRM AUTOMATED TESTING M: Helen Koike <helen.fornazier@gmail.com> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 083cc44aa952..dbb765a9fdbd 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -29,6 +29,7 @@ #include <linux/hrtimer_types.h> #include <linux/acpi.h> +#include <linux/gpu_buddy.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -146,6 +147,16 @@ const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP; const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE; const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE; +#if IS_ENABLED(CONFIG_GPU_BUDDY) +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_RANGE_ALLOCATION = GPU_BUDDY_RANGE_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TOPDOWN_ALLOCATION = GPU_BUDDY_TOPDOWN_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CONTIGUOUS_ALLOCATION = + GPU_BUDDY_CONTIGUOUS_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEAR_ALLOCATION = GPU_BUDDY_CLEAR_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEARED = GPU_BUDDY_CLEARED; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DISABLE; +#endif + #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" diff --git a/rust/helpers/gpu.c b/rust/helpers/gpu.c new file mode 100644 index 000000000000..38b1a4e6bef8 --- /dev/null +++ b/rust/helpers/gpu.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/gpu_buddy.h> + +#ifdef CONFIG_GPU_BUDDY + +__rust_helper u64 rust_helper_gpu_buddy_block_offset(const struct gpu_buddy_block *block) +{ + return gpu_buddy_block_offset(block); +} + +__rust_helper unsigned int rust_helper_gpu_buddy_block_order(struct gpu_buddy_block *block) +{ + return gpu_buddy_block_order(block); +} + +__rust_helper u64 rust_helper_gpu_buddy_block_size(struct gpu_buddy *mm, + struct gpu_buddy_block *block) +{ + return gpu_buddy_block_size(mm, block); +} + +#endif /* CONFIG_GPU_BUDDY */ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 724fcb8240ac..a53929ce52a3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "gpu.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs new file mode 100644 index 000000000000..082dc79ab247 --- /dev/null +++ b/rust/kernel/gpu/buddy.rs @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU buddy allocator bindings. +//! +//! C header: [`include/linux/gpu_buddy.h`](srctree/include/linux/gpu_buddy.h) +//! +//! This module provides Rust abstractions over the Linux kernel's GPU buddy +//! allocator, which implements a binary buddy memory allocator. +//! +//! The buddy allocator manages a contiguous address space and allocates blocks +//! in power-of-two sizes, useful for GPU physical memory management. +//! +//! # Examples +//! +//! Create a buddy allocator and perform a basic range allocation: +//! +//! ``` +//! use kernel::{ +//! gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, +//! prelude::*, +//! ptr::Alignment, +//! sizes::*, // +//! }; +//! +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. +//! let buddy = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_1G as u64, +//! chunk_size: SZ_4K, +//! })?; +//! +//! assert_eq!(buddy.size(), SZ_1G as u64); +//! assert_eq!(buddy.chunk_size(), SZ_4K); +//! let initial_free = buddy.free_memory(); +//! +//! // Allocate 16MB, results in a single 16MB block at offset 0. +//! let allocated = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: 0 }, +//! SZ_16M, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = allocated.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), 0); +//! assert_eq!(block.order(), 12); // 2^12 pages = 16MB +//! assert_eq!(block.size(), SZ_16M); +//! +//! // Dropping the allocation returns the memory to the buddy allocator. +//! drop(allocated); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Top-down allocation allocates from the highest addresses: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: SZ_4K, +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! let topdown = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::TopDown, +//! SZ_16M, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = topdown.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); +//! assert_eq!(block.order(), 12); +//! assert_eq!(block.size(), SZ_16M); +//! +//! // Dropping the allocation returns the memory to the buddy allocator. +//! drop(topdown); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Non-contiguous allocation can fill fragmented memory by returning multiple +//! blocks: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlags, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: SZ_4K, +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! // Create fragmentation by allocating 4MB blocks at [0,4M) and [8M,12M). +//! let frag1 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_4M as u64); +//! +//! let frag2 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_8M as u64); +//! +//! // Allocate 8MB, this returns 2 blocks from the holes. +//! let fragmented = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_16M as u64 }, +//! SZ_8M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let (mut count, mut total) = (0u32, 0usize); +//! for block in fragmented.iter() { +//! assert_eq!(block.size(), SZ_4M); +//! total += block.size(); +//! count += 1; +//! } +//! assert_eq!(total, SZ_8M); +//! assert_eq!(count, 2); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Contiguous allocation fails when only fragmented space is available: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlag, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! // Create a small 16MB buddy allocator with fragmented memory. +//! let small = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_16M as u64, +//! chunk_size: SZ_4K, +//! })?; +//! +//! let _hole1 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! let _hole2 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! // 8MB contiguous should fail, only two non-contiguous 4MB holes exist. +//! let result = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Simple, +//! SZ_8M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlag::Contiguous.into(), +//! ), +//! GFP_KERNEL, +//! ); +//! assert!(result.is_err()); +//! # Ok::<(), Error>(()) +//! ``` + +use crate::{ + bindings, + clist_create, + error::to_result, + interop::list::CListHead, + new_mutex, + prelude::*, + ptr::Alignment, + sync::{ + lock::mutex::MutexGuard, + Arc, + Mutex, // + }, + types::Opaque, // +}; + +/// Allocation mode for the GPU buddy allocator. +/// +/// The mode determines the primary allocation strategy. Modes are mutually +/// exclusive: an allocation is either simple, range-constrained, or top-down. +/// +/// Orthogonal modifier flags (e.g., contiguous, clear) are specified separately +/// via [`GpuBuddyAllocFlags`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum GpuBuddyAllocMode { + /// Simple allocation without constraints. + Simple, + /// Range-based allocation between `start` and `end` addresses. + Range { + /// Start of the allocation range. + start: u64, + /// End of the allocation range. + end: u64, + }, + /// Allocate from top of address space downward. + TopDown, +} + +impl GpuBuddyAllocMode { + // Returns the C flags corresponding to the allocation mode. + fn into_flags(self) -> usize { + match self { + Self::Simple => 0, + Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION as usize, + Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION as usize, + } + } + + // Extracts the range start/end, defaulting to (0, 0) for non-range modes. + fn range(self) -> (u64, u64) { + match self { + Self::Range { start, end } => (start, end), + _ => (0, 0), + } + } +} + +crate::impl_flags!( + /// Modifier flags for GPU buddy allocation. + /// + /// These flags can be combined with any [`GpuBuddyAllocMode`] to control + /// additional allocation behavior. + #[derive(Clone, Copy, Default, PartialEq, Eq)] + pub struct GpuBuddyAllocFlags(u32); + + /// Individual modifier flag for GPU buddy allocation. + #[derive(Clone, Copy, PartialEq, Eq)] + pub enum GpuBuddyAllocFlag { + /// Allocate physically contiguous blocks. + Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32, + + /// Request allocation from cleared (zeroed) memory. + Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32, + + /// Disable trimming of partially used blocks. + TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32, + } +); + +/// Parameters for creating a GPU buddy allocator. +pub struct GpuBuddyParams { + /// Base offset (in bytes) where the managed memory region starts. + /// Allocations will be offset by this value. + pub base_offset: u64, + /// Total physical memory size (in bytes) managed by the allocator. + pub physical_memory_size: u64, + /// Minimum allocation unit / chunk size (in bytes), must be >= 4KB. + pub chunk_size: usize, +} + +/// Inner structure holding the actual buddy allocator. +/// +/// # Synchronization +/// +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). +/// [`GpuBuddyGuard`] ensures that the lock is held for all +/// allocator and free operations, preventing races between concurrent allocations +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains an initialized buddy allocator. +#[pin_data(PinnedDrop)] +struct GpuBuddyInner { + #[pin] + inner: Opaque<bindings::gpu_buddy>, + + // TODO: Replace `Mutex<()>` with `Mutex<Opaque<..>>` once `Mutex::new()` + // accepts `impl PinInit<T>`. + #[pin] + lock: Mutex<()>, + /// Cached creation parameters (do not change after init). + params: GpuBuddyParams, +} + +impl GpuBuddyInner { + /// Create a pin-initializer for the buddy allocator. + fn new(params: GpuBuddyParams) -> impl PinInit<Self, Error> { + let size = params.physical_memory_size; + let chunk_size = params.chunk_size; + + // INVARIANT: `gpu_buddy_init` returns 0 on success, at which point the + // `gpu_buddy` structure is initialized and ready for use with all + // `gpu_buddy_*` APIs. `try_pin_init!` only completes if all fields succeed, + // so the invariant holds when construction finishes. + try_pin_init!(Self { + inner <- Opaque::try_ffi_init(|ptr| { + // SAFETY: `ptr` points to valid uninitialized memory from the pin-init + // infrastructure. `gpu_buddy_init` will initialize the structure. + to_result(unsafe { bindings::gpu_buddy_init(ptr, size, chunk_size as u64) }) + }), + lock <- new_mutex!(()), + params, + }) + } + + /// Lock the mutex and return a guard for accessing the allocator. + fn lock(&self) -> GpuBuddyGuard<'_> { + GpuBuddyGuard { + inner: self, + _guard: self.lock.lock(), + } + } +} + +#[pinned_drop] +impl PinnedDrop for GpuBuddyInner { + fn drop(self: Pin<&mut Self>) { + let guard = self.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + unsafe { + bindings::gpu_buddy_fini(guard.as_raw()); + } + } +} + +// SAFETY: GpuBuddyInner can be sent between threads. +unsafe impl Send for GpuBuddyInner {} + +// SAFETY: `GpuBuddyInner` is `Sync` because `GpuBuddyInner::lock` +// serializes all access to the C allocator, preventing data races. +unsafe impl Sync for GpuBuddyInner {} + +// Guard that proves the lock is held, enabling access to the allocator. +// The `_guard` holds the lock for the duration of this guard's lifetime. +struct GpuBuddyGuard<'a> { + inner: &'a GpuBuddyInner, + _guard: MutexGuard<'a, ()>, +} + +impl GpuBuddyGuard<'_> { + /// Get a raw pointer to the underlying C `gpu_buddy` structure. + fn as_raw(&self) -> *mut bindings::gpu_buddy { + self.inner.inner.get() + } +} + +/// GPU buddy allocator instance. +/// +/// This structure wraps the C `gpu_buddy` allocator using reference counting. +/// The allocator is automatically cleaned up when all references are dropped. +/// +/// Refer to the module-level documentation for usage examples. +pub struct GpuBuddy(Arc<GpuBuddyInner>); + +impl GpuBuddy { + /// Create a new buddy allocator. + /// + /// Creates a buddy allocator that manages a contiguous address space of the given + /// size, with the specified minimum allocation unit (chunk_size must be at least 4KB). + pub fn new(params: GpuBuddyParams) -> Result<Self> { + Ok(Self(Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL)?)) + } + + /// Get the base offset for allocations. + pub fn base_offset(&self) -> u64 { + self.0.params.base_offset + } + + /// Get the chunk size (minimum allocation unit). + pub fn chunk_size(&self) -> usize { + self.0.params.chunk_size + } + + /// Get the total managed size. + pub fn size(&self) -> u64 { + self.0.params.physical_memory_size + } + + /// Get the available (free) memory in bytes. + pub fn free_memory(&self) -> u64 { + let guard = self.0.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized allocator. + // `guard` provides exclusive access. + unsafe { (*guard.as_raw()).avail } + } + + /// Allocate blocks from the buddy allocator. + /// + /// Returns a pin-initializer for [`AllocatedBlocks`]. + /// + /// Takes `&self` instead of `&mut self` because the internal [`Mutex`] provides + /// synchronization - no external `&mut` exclusivity needed. + pub fn alloc_blocks( + &self, + mode: GpuBuddyAllocMode, + size: usize, + min_block_size: Alignment, + flags: GpuBuddyAllocFlags, + ) -> impl PinInit<AllocatedBlocks, Error> { + let buddy_arc = Arc::clone(&self.0); + let (start, end) = mode.range(); + let mode_flags = mode.into_flags(); + let modifier_flags = u32::from(flags) as usize; + + // Create pin-initializer that initializes list and allocates blocks. + try_pin_init!(AllocatedBlocks { + buddy: buddy_arc, + list <- CListHead::new(), + _: { + // Lock while allocating to serialize with concurrent frees. + let guard = buddy.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + to_result(unsafe { + bindings::gpu_buddy_alloc_blocks( + guard.as_raw(), + start, + end, + size as u64, + min_block_size.as_usize() as u64, + list.as_raw(), + mode_flags | modifier_flags, + ) + })? + } + }) + } +} + +/// Allocated blocks from the buddy allocator with automatic cleanup. +/// +/// This structure owns a list of allocated blocks and ensures they are +/// automatically freed when dropped. Use `iter()` to iterate over all +/// allocated blocks. +/// +/// # Invariants +/// +/// - `list` is an initialized, valid list head containing allocated blocks. +#[pin_data(PinnedDrop)] +pub struct AllocatedBlocks { + #[pin] + list: CListHead, + buddy: Arc<GpuBuddyInner>, +} + +impl AllocatedBlocks { + /// Check if the block list is empty. + pub fn is_empty(&self) -> bool { + // An empty list head points to itself. + !self.list.is_linked() + } + + /// Iterate over allocated blocks. + /// + /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`] + /// borrows `self` and is only valid for the duration of that borrow. + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { + // SAFETY: + // - Per the type invariant, `list` is an initialized sentinel `list_head` + // and is not concurrently modified (we hold a `&self` borrow). + // - The list contains `gpu_buddy_block` items linked via + // `__bindgen_anon_1.link`. + // - `Block` is `#[repr(transparent)]` over `gpu_buddy_block`. + let clist = clist_create!(unsafe { + self.list.as_raw(), + Block, + bindings::gpu_buddy_block, + __bindgen_anon_1.link + }); + + clist + .iter() + .map(|this| AllocatedBlock { this, blocks: self }) + } +} + +#[pinned_drop] +impl PinnedDrop for AllocatedBlocks { + fn drop(self: Pin<&mut Self>) { + let guard = self.buddy.lock(); + + // SAFETY: + // - list is valid per the type's invariants. + // - guard provides exclusive access to the allocator. + unsafe { + bindings::gpu_buddy_free_list(guard.as_raw(), self.list.as_raw(), 0); + } + } +} + +/// A GPU buddy block. +/// +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned +/// as references during iteration over [`AllocatedBlocks`]. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`. +#[repr(transparent)] +struct Block(Opaque<bindings::gpu_buddy_block>); + +impl Block { + /// Get a raw pointer to the underlying C block. + fn as_raw(&self) -> *mut bindings::gpu_buddy_block { + self.0.get() + } + + /// Get the block's raw offset in the buddy address space (without base offset). + fn offset(&self) -> u64 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } + } + + /// Get the block order. + fn order(&self) -> u32 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } + } +} + +// SAFETY: `Block` is a wrapper around `gpu_buddy_block` which can be +// sent across threads safely. +unsafe impl Send for Block {} + +// SAFETY: `Block` is only accessed through shared references after +// allocation, and thus safe to access concurrently across threads. +unsafe impl Sync for Block {} + +/// A buddy block paired with its owning [`AllocatedBlocks`] context. +/// +/// Unlike a raw block, which only knows its offset within the buddy address +/// space, an [`AllocatedBlock`] also has access to the allocator's `base_offset` +/// and `chunk_size`, enabling it to compute absolute offsets and byte sizes. +/// +/// Returned by [`AllocatedBlocks::iter()`]. +pub struct AllocatedBlock<'a> { + this: &'a Block, + blocks: &'a AllocatedBlocks, +} + +impl AllocatedBlock<'_> { + /// Get the block's offset in the address space. + /// + /// Returns the absolute offset including the allocator's base offset. + /// This is the actual address to use for accessing the allocated memory. + pub fn offset(&self) -> u64 { + self.blocks.buddy.params.base_offset + self.this.offset() + } + + /// Get the block order (size = chunk_size << order). + pub fn order(&self) -> u32 { + self.this.order() + } + + /// Get the block's size in bytes. + pub fn size(&self) -> usize { + self.blocks.buddy.params.chunk_size << self.this.order() + } +} diff --git a/rust/kernel/gpu/mod.rs b/rust/kernel/gpu/mod.rs new file mode 100644 index 000000000000..8f25e6367edc --- /dev/null +++ b/rust/kernel/gpu/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU subsystem abstractions. + +pub mod buddy; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index bb741f1e0dfd..63e3f656eb6c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -98,6 +98,8 @@ pub mod firmware; pub mod fmt; pub mod fs; +#[cfg(CONFIG_GPU_BUDDY = "y")] +pub mod gpu; #[cfg(CONFIG_I2C = "y")] pub mod i2c; pub mod id_pool; -- 2.34.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH v12.1 0/1] Rust GPU buddy allocator bindings 2026-03-08 18:04 [PATCH v12 0/1] Rust GPU buddy allocator bindings Joel Fernandes 2026-03-08 18:04 ` [PATCH v12 1/1] rust: gpu: Add " Joel Fernandes @ 2026-03-09 13:53 ` Joel Fernandes 2026-03-09 13:53 ` [PATCH v12.1 1/1] rust: gpu: Add " Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 0/2] Rust " Joel Fernandes 2 siblings, 1 reply; 24+ messages in thread From: Joel Fernandes @ 2026-03-09 13:53 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes This patch adds safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The prerequisite infrastructure patches (DRM buddy code movement and the uninitialized buddy fix) have been absorbed into upstream -next, so this is now a standalone patch. The git tree with all patches can be found at: git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: gpu-buddy-bindings-v12.1-20260309) Change log: Changes from v12 to v12.1: - Fixed undeclared type `GpuBuddyFlags` in doc examples: renamed to `GpuBuddyAllocFlags` in all seven doc test examples (found by kernel test robot). Changes from v11 to v12: - Rebased on linux-next; this is now a standalone single patch as dependencies are absorbed (but clist is a prerequisite). - Redesigned allocation API (Alexandre Courbot) for better Rust ergonomics. - Split single long example into 4 self-contained examples (Alexandre Courbot). - Several safety and invariant comment changes (Danilo). - MAINTAINERS changes (Arun, Mathew, Danilo, Dave). - Fixed `#[cfg(CONFIG_GPU_BUDDY)]` to `#[cfg(CONFIG_GPU_BUDDY = "y")]` (Danilo Krummrich). - Updated `ffi::clist::CListHead` to `interop::list::CListHead`. Changes from v10 to v11: - Dropped "rust: ffi: Convert pub use to pub mod and create ffi module" patch; the ffi module restructuring will go through a different path. - Dropped "rust: clist: Add support to interface with C linked lists" patch; the clist module will be submitted separately. - Dropped "nova-core: Kconfig: Sort select statements alphabetically" cosmetic patch. - Patches 1-3 (DRM buddy movement and fix) are included as reference only; they are already being pulled into upstream via drm-misc-next. - Removed clist patches as those can go in independently (Alice). - Moved the Kconfig GPU_BUDDY selection patch to nova-core mm series to enable it when it is actually used. - Various nits to comments, etc. Changes from v9 to v10: - Absorbed the DRM buddy code movement patches into this series as patches 1-2. Dave Airlie reworked these into two parts for better git history. - Added "gpu: Fix uninitialized buddy for built-in drivers" fix by Koen Koning, using subsys_initcall instead of module_init to fix NULL pointer dereference when built-in drivers use the buddy allocator before initialization. - Added "rust: ffi: Convert pub use to pub mod and create ffi module" to prepare the ffi module for hosting clist as a sub-module. - Moved clist from rust/kernel/clist.rs to rust/kernel/ffi/. - Added "nova-core: Kconfig: Sort select statements alphabetically" (Danilo). Changes from v8 to v9: - Updated nova-core Kconfig patch: addressed sorting of Kconfig options. - Added Daniel Almeida's Reviewed-by tag to clist patch. - Minor refinements to GPU buddy bindings. Changes from v7 to v8: - Added nova-core Kconfig patch to select GPU_BUDDY for VRAM allocation. - Various changes suggested by Danilo Krummrich, Gary Guo, and Daniel Almeida. - Added Acked-by: Gary Guo for clist patch. Changes from v6 to v7: - Major restructuring: split the large 26-patch v6 RFC series. v7 only contains the Rust infrastructure patches (clist + GPU buddy bindings), extracted from the full nova-core MM series. The nova-core MM patches follow separately. - Rebased on linux-next. Link to v12: https://lore.kernel.org/all/20260308180407.3988286-1-joelagnelf@nvidia.com/ Link to v11: https://lore.kernel.org/all/20260224224005.3232841-1-joelagnelf@nvidia.com/ Joel Fernandes (1): rust: gpu: Add GPU buddy allocator bindings MAINTAINERS | 6 +- rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu/buddy.rs | 611 ++++++++++++++++++++++++++++++++ rust/kernel/gpu/mod.rs | 5 + rust/kernel/lib.rs | 2 + 7 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu/buddy.rs create mode 100644 rust/kernel/gpu/mod.rs -- 2.34.1 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-09 13:53 ` [PATCH v12.1 0/1] Rust " Joel Fernandes @ 2026-03-09 13:53 ` Joel Fernandes 2026-03-12 17:45 ` Danilo Krummrich 2026-03-16 13:12 ` Alexandre Courbot 0 siblings, 2 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-09 13:53 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Add safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The GPU buddy allocator implements a binary buddy system useful for GPU physical memory allocation. nova-core will use it for physical memory allocation. Christian Koenig mentioned he'd like to step down from reviewer role for GPU buddy so updated accordingly. Arun/Matthew agree on the modified entry. Cc: Nikola Djukic <ndjukic@nvidia.com> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- MAINTAINERS | 6 +- rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu/buddy.rs | 611 ++++++++++++++++++++++++++++++++ rust/kernel/gpu/mod.rs | 5 + rust/kernel/lib.rs | 2 + 7 files changed, 658 insertions(+), 1 deletion(-) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu/buddy.rs create mode 100644 rust/kernel/gpu/mod.rs diff --git a/MAINTAINERS b/MAINTAINERS index 4c66f8261ff2..b2600dd05fc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8513,7 +8513,9 @@ T: git https://gitlab.freedesktop.org/drm/rust/kernel.git F: drivers/gpu/drm/nova/ F: drivers/gpu/drm/tyr/ F: drivers/gpu/nova-core/ +F: rust/helpers/gpu.c F: rust/kernel/drm/ +F: rust/kernel/gpu/ DRM DRIVERS FOR ALLWINNER A10 M: Chen-Yu Tsai <wens@kernel.org> @@ -8926,7 +8928,7 @@ F: include/drm/ttm/ GPU BUDDY ALLOCATOR M: Matthew Auld <matthew.auld@intel.com> M: Arun Pravin <arunpravin.paneerselvam@amd.com> -R: Christian Koenig <christian.koenig@amd.com> +R: Joel Fernandes <joelagnelf@nvidia.com> L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git @@ -8935,6 +8937,8 @@ F: drivers/gpu/buddy.c F: drivers/gpu/tests/gpu_buddy_test.c F: include/linux/gpu_buddy.h F: include/drm/drm_buddy.h +F: rust/helpers/gpu.c +F: rust/kernel/gpu/ DRM AUTOMATED TESTING M: Helen Koike <helen.fornazier@gmail.com> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 083cc44aa952..dbb765a9fdbd 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -29,6 +29,7 @@ #include <linux/hrtimer_types.h> #include <linux/acpi.h> +#include <linux/gpu_buddy.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -146,6 +147,16 @@ const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP; const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE; const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE; +#if IS_ENABLED(CONFIG_GPU_BUDDY) +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_RANGE_ALLOCATION = GPU_BUDDY_RANGE_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TOPDOWN_ALLOCATION = GPU_BUDDY_TOPDOWN_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CONTIGUOUS_ALLOCATION = + GPU_BUDDY_CONTIGUOUS_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEAR_ALLOCATION = GPU_BUDDY_CLEAR_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEARED = GPU_BUDDY_CLEARED; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DISABLE; +#endif + #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" diff --git a/rust/helpers/gpu.c b/rust/helpers/gpu.c new file mode 100644 index 000000000000..38b1a4e6bef8 --- /dev/null +++ b/rust/helpers/gpu.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/gpu_buddy.h> + +#ifdef CONFIG_GPU_BUDDY + +__rust_helper u64 rust_helper_gpu_buddy_block_offset(const struct gpu_buddy_block *block) +{ + return gpu_buddy_block_offset(block); +} + +__rust_helper unsigned int rust_helper_gpu_buddy_block_order(struct gpu_buddy_block *block) +{ + return gpu_buddy_block_order(block); +} + +__rust_helper u64 rust_helper_gpu_buddy_block_size(struct gpu_buddy *mm, + struct gpu_buddy_block *block) +{ + return gpu_buddy_block_size(mm, block); +} + +#endif /* CONFIG_GPU_BUDDY */ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 724fcb8240ac..a53929ce52a3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "gpu.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs new file mode 100644 index 000000000000..9027c9a7778f --- /dev/null +++ b/rust/kernel/gpu/buddy.rs @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU buddy allocator bindings. +//! +//! C header: [`include/linux/gpu_buddy.h`](srctree/include/linux/gpu_buddy.h) +//! +//! This module provides Rust abstractions over the Linux kernel's GPU buddy +//! allocator, which implements a binary buddy memory allocator. +//! +//! The buddy allocator manages a contiguous address space and allocates blocks +//! in power-of-two sizes, useful for GPU physical memory management. +//! +//! # Examples +//! +//! Create a buddy allocator and perform a basic range allocation: +//! +//! ``` +//! use kernel::{ +//! gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, +//! prelude::*, +//! ptr::Alignment, +//! sizes::*, // +//! }; +//! +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. +//! let buddy = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_1G as u64, +//! chunk_size: SZ_4K, +//! })?; +//! +//! assert_eq!(buddy.size(), SZ_1G as u64); +//! assert_eq!(buddy.chunk_size(), SZ_4K); +//! let initial_free = buddy.free_memory(); +//! +//! // Allocate 16MB, results in a single 16MB block at offset 0. +//! let allocated = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: 0 }, +//! SZ_16M, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = allocated.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), 0); +//! assert_eq!(block.order(), 12); // 2^12 pages = 16MB +//! assert_eq!(block.size(), SZ_16M); +//! +//! // Dropping the allocation returns the memory to the buddy allocator. +//! drop(allocated); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Top-down allocation allocates from the highest addresses: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: SZ_4K, +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! let topdown = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::TopDown, +//! SZ_16M, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = topdown.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); +//! assert_eq!(block.order(), 12); +//! assert_eq!(block.size(), SZ_16M); +//! +//! // Dropping the allocation returns the memory to the buddy allocator. +//! drop(topdown); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Non-contiguous allocation can fill fragmented memory by returning multiple +//! blocks: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlags, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: SZ_4K, +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! // Create fragmentation by allocating 4MB blocks at [0,4M) and [8M,12M). +//! let frag1 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_4M as u64); +//! +//! let frag2 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_8M as u64); +//! +//! // Allocate 8MB, this returns 2 blocks from the holes. +//! let fragmented = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_16M as u64 }, +//! SZ_8M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let (mut count, mut total) = (0u32, 0usize); +//! for block in fragmented.iter() { +//! assert_eq!(block.size(), SZ_4M); +//! total += block.size(); +//! count += 1; +//! } +//! assert_eq!(total, SZ_8M); +//! assert_eq!(count, 2); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Contiguous allocation fails when only fragmented space is available: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlag, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! // Create a small 16MB buddy allocator with fragmented memory. +//! let small = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_16M as u64, +//! chunk_size: SZ_4K, +//! })?; +//! +//! let _hole1 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! let _hole2 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! // 8MB contiguous should fail, only two non-contiguous 4MB holes exist. +//! let result = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Simple, +//! SZ_8M, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlag::Contiguous.into(), +//! ), +//! GFP_KERNEL, +//! ); +//! assert!(result.is_err()); +//! # Ok::<(), Error>(()) +//! ``` + +use crate::{ + bindings, + clist_create, + error::to_result, + interop::list::CListHead, + new_mutex, + prelude::*, + ptr::Alignment, + sync::{ + lock::mutex::MutexGuard, + Arc, + Mutex, // + }, + types::Opaque, // +}; + +/// Allocation mode for the GPU buddy allocator. +/// +/// The mode determines the primary allocation strategy. Modes are mutually +/// exclusive: an allocation is either simple, range-constrained, or top-down. +/// +/// Orthogonal modifier flags (e.g., contiguous, clear) are specified separately +/// via [`GpuBuddyAllocFlags`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum GpuBuddyAllocMode { + /// Simple allocation without constraints. + Simple, + /// Range-based allocation between `start` and `end` addresses. + Range { + /// Start of the allocation range. + start: u64, + /// End of the allocation range. + end: u64, + }, + /// Allocate from top of address space downward. + TopDown, +} + +impl GpuBuddyAllocMode { + // Returns the C flags corresponding to the allocation mode. + fn into_flags(self) -> usize { + match self { + Self::Simple => 0, + Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION as usize, + Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION as usize, + } + } + + // Extracts the range start/end, defaulting to (0, 0) for non-range modes. + fn range(self) -> (u64, u64) { + match self { + Self::Range { start, end } => (start, end), + _ => (0, 0), + } + } +} + +crate::impl_flags!( + /// Modifier flags for GPU buddy allocation. + /// + /// These flags can be combined with any [`GpuBuddyAllocMode`] to control + /// additional allocation behavior. + #[derive(Clone, Copy, Default, PartialEq, Eq)] + pub struct GpuBuddyAllocFlags(u32); + + /// Individual modifier flag for GPU buddy allocation. + #[derive(Clone, Copy, PartialEq, Eq)] + pub enum GpuBuddyAllocFlag { + /// Allocate physically contiguous blocks. + Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32, + + /// Request allocation from cleared (zeroed) memory. + Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32, + + /// Disable trimming of partially used blocks. + TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32, + } +); + +/// Parameters for creating a GPU buddy allocator. +pub struct GpuBuddyParams { + /// Base offset (in bytes) where the managed memory region starts. + /// Allocations will be offset by this value. + pub base_offset: u64, + /// Total physical memory size (in bytes) managed by the allocator. + pub physical_memory_size: u64, + /// Minimum allocation unit / chunk size (in bytes), must be >= 4KB. + pub chunk_size: usize, +} + +/// Inner structure holding the actual buddy allocator. +/// +/// # Synchronization +/// +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). +/// [`GpuBuddyGuard`] ensures that the lock is held for all +/// allocator and free operations, preventing races between concurrent allocations +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains an initialized buddy allocator. +#[pin_data(PinnedDrop)] +struct GpuBuddyInner { + #[pin] + inner: Opaque<bindings::gpu_buddy>, + + // TODO: Replace `Mutex<()>` with `Mutex<Opaque<..>>` once `Mutex::new()` + // accepts `impl PinInit<T>`. + #[pin] + lock: Mutex<()>, + /// Cached creation parameters (do not change after init). + params: GpuBuddyParams, +} + +impl GpuBuddyInner { + /// Create a pin-initializer for the buddy allocator. + fn new(params: GpuBuddyParams) -> impl PinInit<Self, Error> { + let size = params.physical_memory_size; + let chunk_size = params.chunk_size; + + // INVARIANT: `gpu_buddy_init` returns 0 on success, at which point the + // `gpu_buddy` structure is initialized and ready for use with all + // `gpu_buddy_*` APIs. `try_pin_init!` only completes if all fields succeed, + // so the invariant holds when construction finishes. + try_pin_init!(Self { + inner <- Opaque::try_ffi_init(|ptr| { + // SAFETY: `ptr` points to valid uninitialized memory from the pin-init + // infrastructure. `gpu_buddy_init` will initialize the structure. + to_result(unsafe { bindings::gpu_buddy_init(ptr, size, chunk_size as u64) }) + }), + lock <- new_mutex!(()), + params, + }) + } + + /// Lock the mutex and return a guard for accessing the allocator. + fn lock(&self) -> GpuBuddyGuard<'_> { + GpuBuddyGuard { + inner: self, + _guard: self.lock.lock(), + } + } +} + +#[pinned_drop] +impl PinnedDrop for GpuBuddyInner { + fn drop(self: Pin<&mut Self>) { + let guard = self.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + unsafe { + bindings::gpu_buddy_fini(guard.as_raw()); + } + } +} + +// SAFETY: GpuBuddyInner can be sent between threads. +unsafe impl Send for GpuBuddyInner {} + +// SAFETY: `GpuBuddyInner` is `Sync` because `GpuBuddyInner::lock` +// serializes all access to the C allocator, preventing data races. +unsafe impl Sync for GpuBuddyInner {} + +// Guard that proves the lock is held, enabling access to the allocator. +// The `_guard` holds the lock for the duration of this guard's lifetime. +struct GpuBuddyGuard<'a> { + inner: &'a GpuBuddyInner, + _guard: MutexGuard<'a, ()>, +} + +impl GpuBuddyGuard<'_> { + /// Get a raw pointer to the underlying C `gpu_buddy` structure. + fn as_raw(&self) -> *mut bindings::gpu_buddy { + self.inner.inner.get() + } +} + +/// GPU buddy allocator instance. +/// +/// This structure wraps the C `gpu_buddy` allocator using reference counting. +/// The allocator is automatically cleaned up when all references are dropped. +/// +/// Refer to the module-level documentation for usage examples. +pub struct GpuBuddy(Arc<GpuBuddyInner>); + +impl GpuBuddy { + /// Create a new buddy allocator. + /// + /// Creates a buddy allocator that manages a contiguous address space of the given + /// size, with the specified minimum allocation unit (chunk_size must be at least 4KB). + pub fn new(params: GpuBuddyParams) -> Result<Self> { + Ok(Self(Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL)?)) + } + + /// Get the base offset for allocations. + pub fn base_offset(&self) -> u64 { + self.0.params.base_offset + } + + /// Get the chunk size (minimum allocation unit). + pub fn chunk_size(&self) -> usize { + self.0.params.chunk_size + } + + /// Get the total managed size. + pub fn size(&self) -> u64 { + self.0.params.physical_memory_size + } + + /// Get the available (free) memory in bytes. + pub fn free_memory(&self) -> u64 { + let guard = self.0.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized allocator. + // `guard` provides exclusive access. + unsafe { (*guard.as_raw()).avail } + } + + /// Allocate blocks from the buddy allocator. + /// + /// Returns a pin-initializer for [`AllocatedBlocks`]. + /// + /// Takes `&self` instead of `&mut self` because the internal [`Mutex`] provides + /// synchronization - no external `&mut` exclusivity needed. + pub fn alloc_blocks( + &self, + mode: GpuBuddyAllocMode, + size: usize, + min_block_size: Alignment, + flags: GpuBuddyAllocFlags, + ) -> impl PinInit<AllocatedBlocks, Error> { + let buddy_arc = Arc::clone(&self.0); + let (start, end) = mode.range(); + let mode_flags = mode.into_flags(); + let modifier_flags = u32::from(flags) as usize; + + // Create pin-initializer that initializes list and allocates blocks. + try_pin_init!(AllocatedBlocks { + buddy: buddy_arc, + list <- CListHead::new(), + _: { + // Lock while allocating to serialize with concurrent frees. + let guard = buddy.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + to_result(unsafe { + bindings::gpu_buddy_alloc_blocks( + guard.as_raw(), + start, + end, + size as u64, + min_block_size.as_usize() as u64, + list.as_raw(), + mode_flags | modifier_flags, + ) + })? + } + }) + } +} + +/// Allocated blocks from the buddy allocator with automatic cleanup. +/// +/// This structure owns a list of allocated blocks and ensures they are +/// automatically freed when dropped. Use `iter()` to iterate over all +/// allocated blocks. +/// +/// # Invariants +/// +/// - `list` is an initialized, valid list head containing allocated blocks. +#[pin_data(PinnedDrop)] +pub struct AllocatedBlocks { + #[pin] + list: CListHead, + buddy: Arc<GpuBuddyInner>, +} + +impl AllocatedBlocks { + /// Check if the block list is empty. + pub fn is_empty(&self) -> bool { + // An empty list head points to itself. + !self.list.is_linked() + } + + /// Iterate over allocated blocks. + /// + /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`] + /// borrows `self` and is only valid for the duration of that borrow. + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { + // SAFETY: + // - Per the type invariant, `list` is an initialized sentinel `list_head` + // and is not concurrently modified (we hold a `&self` borrow). + // - The list contains `gpu_buddy_block` items linked via + // `__bindgen_anon_1.link`. + // - `Block` is `#[repr(transparent)]` over `gpu_buddy_block`. + let clist = clist_create!(unsafe { + self.list.as_raw(), + Block, + bindings::gpu_buddy_block, + __bindgen_anon_1.link + }); + + clist + .iter() + .map(|this| AllocatedBlock { this, blocks: self }) + } +} + +#[pinned_drop] +impl PinnedDrop for AllocatedBlocks { + fn drop(self: Pin<&mut Self>) { + let guard = self.buddy.lock(); + + // SAFETY: + // - list is valid per the type's invariants. + // - guard provides exclusive access to the allocator. + unsafe { + bindings::gpu_buddy_free_list(guard.as_raw(), self.list.as_raw(), 0); + } + } +} + +/// A GPU buddy block. +/// +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned +/// as references during iteration over [`AllocatedBlocks`]. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`. +#[repr(transparent)] +struct Block(Opaque<bindings::gpu_buddy_block>); + +impl Block { + /// Get a raw pointer to the underlying C block. + fn as_raw(&self) -> *mut bindings::gpu_buddy_block { + self.0.get() + } + + /// Get the block's raw offset in the buddy address space (without base offset). + fn offset(&self) -> u64 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } + } + + /// Get the block order. + fn order(&self) -> u32 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } + } +} + +// SAFETY: `Block` is a wrapper around `gpu_buddy_block` which can be +// sent across threads safely. +unsafe impl Send for Block {} + +// SAFETY: `Block` is only accessed through shared references after +// allocation, and thus safe to access concurrently across threads. +unsafe impl Sync for Block {} + +/// A buddy block paired with its owning [`AllocatedBlocks`] context. +/// +/// Unlike a raw block, which only knows its offset within the buddy address +/// space, an [`AllocatedBlock`] also has access to the allocator's `base_offset` +/// and `chunk_size`, enabling it to compute absolute offsets and byte sizes. +/// +/// Returned by [`AllocatedBlocks::iter()`]. +pub struct AllocatedBlock<'a> { + this: &'a Block, + blocks: &'a AllocatedBlocks, +} + +impl AllocatedBlock<'_> { + /// Get the block's offset in the address space. + /// + /// Returns the absolute offset including the allocator's base offset. + /// This is the actual address to use for accessing the allocated memory. + pub fn offset(&self) -> u64 { + self.blocks.buddy.params.base_offset + self.this.offset() + } + + /// Get the block order (size = chunk_size << order). + pub fn order(&self) -> u32 { + self.this.order() + } + + /// Get the block's size in bytes. + pub fn size(&self) -> usize { + self.blocks.buddy.params.chunk_size << self.this.order() + } +} diff --git a/rust/kernel/gpu/mod.rs b/rust/kernel/gpu/mod.rs new file mode 100644 index 000000000000..8f25e6367edc --- /dev/null +++ b/rust/kernel/gpu/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU subsystem abstractions. + +pub mod buddy; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index bb741f1e0dfd..63e3f656eb6c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -98,6 +98,8 @@ pub mod firmware; pub mod fmt; pub mod fs; +#[cfg(CONFIG_GPU_BUDDY = "y")] +pub mod gpu; #[cfg(CONFIG_I2C = "y")] pub mod i2c; pub mod id_pool; -- 2.34.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-09 13:53 ` [PATCH v12.1 1/1] rust: gpu: Add " Joel Fernandes @ 2026-03-12 17:45 ` Danilo Krummrich 2026-03-16 17:29 ` Joel Fernandes 2026-03-16 13:12 ` Alexandre Courbot 1 sibling, 1 reply; 24+ messages in thread From: Danilo Krummrich @ 2026-03-12 17:45 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Mon Mar 9, 2026 at 2:53 PM CET, Joel Fernandes wrote: > Add safe Rust abstractions over the Linux kernel's GPU buddy > allocator for physical memory management. The GPU buddy allocator > implements a binary buddy system useful for GPU physical memory > allocation. nova-core will use it for physical memory allocation. > > Christian Koenig mentioned he'd like to step down from reviewer role for > GPU buddy so updated accordingly. Arun/Matthew agree on the modified entry. > > Cc: Nikola Djukic <ndjukic@nvidia.com> > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> > --- > MAINTAINERS | 6 +- > rust/bindings/bindings_helper.h | 11 + > rust/helpers/gpu.c | 23 ++ > rust/helpers/helpers.c | 1 + > rust/kernel/gpu/buddy.rs | 611 ++++++++++++++++++++++++++++++++ > rust/kernel/gpu/mod.rs | 5 + > rust/kernel/lib.rs | 2 + > 7 files changed, 658 insertions(+), 1 deletion(-) > create mode 100644 rust/helpers/gpu.c > create mode 100644 rust/kernel/gpu/buddy.rs > create mode 100644 rust/kernel/gpu/mod.rs > > diff --git a/MAINTAINERS b/MAINTAINERS > index 4c66f8261ff2..b2600dd05fc2 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8513,7 +8513,9 @@ T: git https://gitlab.freedesktop.org/drm/rust/kernel.git > F: drivers/gpu/drm/nova/ > F: drivers/gpu/drm/tyr/ > F: drivers/gpu/nova-core/ > +F: rust/helpers/gpu.c > F: rust/kernel/drm/ > +F: rust/kernel/gpu/ > > DRM DRIVERS FOR ALLWINNER A10 > M: Chen-Yu Tsai <wens@kernel.org> > @@ -8926,7 +8928,7 @@ F: include/drm/ttm/ > GPU BUDDY ALLOCATOR > M: Matthew Auld <matthew.auld@intel.com> > M: Arun Pravin <arunpravin.paneerselvam@amd.com> > -R: Christian Koenig <christian.koenig@amd.com> This should really be a separate patch as it is unrelated to the addition of the Rust GPU buddy code. > +R: Joel Fernandes <joelagnelf@nvidia.com> > L: dri-devel@lists.freedesktop.org > S: Maintained > T: git https://gitlab.freedesktop.org/drm/misc/kernel.git > @@ -8935,6 +8937,8 @@ F: drivers/gpu/buddy.c > F: drivers/gpu/tests/gpu_buddy_test.c > F: include/linux/gpu_buddy.h > F: include/drm/drm_buddy.h > +F: rust/helpers/gpu.c > +F: rust/kernel/gpu/ ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-12 17:45 ` Danilo Krummrich @ 2026-03-16 17:29 ` Joel Fernandes 0 siblings, 0 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-16 17:29 UTC (permalink / raw) To: Danilo Krummrich Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Thu, 12 Mar 2026, Danilo Krummrich wrote: > -R: Christian Koenig <christian.koenig@amd.com> > > This should really be a separate patch as it is unrelated to the addition of the > Rust GPU buddy code. > > +R: Joel Fernandes <joelagnelf@nvidia.com> Agreed. I'll split the reviewer change into a separate MAINTAINERS patch. The F: path additions will stay in the buddy bindings patch since those directly track the new files being introduced. Thanks for the review! -- Joel Fernandes ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-09 13:53 ` [PATCH v12.1 1/1] rust: gpu: Add " Joel Fernandes 2026-03-12 17:45 ` Danilo Krummrich @ 2026-03-16 13:12 ` Alexandre Courbot 2026-03-16 18:43 ` Joel Fernandes 2026-03-16 18:51 ` John Hubbard 1 sibling, 2 replies; 24+ messages in thread From: Alexandre Courbot @ 2026-03-16 13:12 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: > Add safe Rust abstractions over the Linux kernel's GPU buddy > allocator for physical memory management. The GPU buddy allocator > implements a binary buddy system useful for GPU physical memory > allocation. nova-core will use it for physical memory allocation. > > Christian Koenig mentioned he'd like to step down from reviewer role for > GPU buddy so updated accordingly. Arun/Matthew agree on the modified entry. > > Cc: Nikola Djukic <ndjukic@nvidia.com> > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> This is getting close IMHO. But `make rustdoc` fails on the examples, and there are still clippy warnings - please make sure to address them. A few more comments below. <snip> > diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs > new file mode 100644 > index 000000000000..9027c9a7778f > --- /dev/null > +++ b/rust/kernel/gpu/buddy.rs > @@ -0,0 +1,611 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! GPU buddy allocator bindings. > +//! > +//! C header: [`include/linux/gpu_buddy.h`](srctree/include/linux/gpu_buddy.h) > +//! > +//! This module provides Rust abstractions over the Linux kernel's GPU buddy > +//! allocator, which implements a binary buddy memory allocator. > +//! > +//! The buddy allocator manages a contiguous address space and allocates blocks > +//! in power-of-two sizes, useful for GPU physical memory management. > +//! > +//! # Examples > +//! > +//! Create a buddy allocator and perform a basic range allocation: > +//! > +//! ``` > +//! use kernel::{ > +//! gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, nit: should also use kernel formatting style. > +//! prelude::*, > +//! ptr::Alignment, > +//! sizes::*, // > +//! }; > +//! > +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. > +//! let buddy = GpuBuddy::new(GpuBuddyParams { > +//! base_offset: 0, > +//! physical_memory_size: SZ_1G as u64, > +//! chunk_size: SZ_4K, `chunk_size` is an interesting case. The C API uses a `u64`, but I think we can reasonably consider that we won't ever need chunks larger than 4GB (or can we :O). I'm actually ok with using a `usize` for this one. One of the first things the C code does is throwing an error if it is not a power of 2, so maybe we can even request an `Alignment`? I'm a bit torn as to whether we should use a `u64` to conform with the C API, but doing so would mean we cannot use an `Alignment`... > +//! })?; > +//! > +//! assert_eq!(buddy.size(), SZ_1G as u64); > +//! assert_eq!(buddy.chunk_size(), SZ_4K); > +//! let initial_free = buddy.free_memory(); > +//! > +//! // Allocate 16MB, results in a single 16MB block at offset 0. > +//! let allocated = KBox::pin_init( > +//! buddy.alloc_blocks( > +//! GpuBuddyAllocMode::Range { start: 0, end: 0 }, This zero-sized range looks confusing for the example. I understand the C API allows this, but I don't think we should. Is there a difference with just using `GpuBuddyAllocMode::Simple`? If not, let's switch to that, and reject zero-sized ranges in the same spirit as we don't allow invalid flag combinations. > +//! SZ_16M, > +//! Alignment::new::<SZ_16M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); > +//! > +//! let block = allocated.iter().next().expect("expected one block"); > +//! assert_eq!(block.offset(), 0); > +//! assert_eq!(block.order(), 12); // 2^12 pages = 16MB > +//! assert_eq!(block.size(), SZ_16M); Here we should also check that there is not a second block. > +//! > +//! // Dropping the allocation returns the memory to the buddy allocator. s/memory/range - technically we are not returning physical memory. > +//! drop(allocated); > +//! assert_eq!(buddy.free_memory(), initial_free); > +//! # Ok::<(), Error>(()) > +//! ``` > +//! > +//! Top-down allocation allocates from the highest addresses: > +//! > +//! ``` > +//! # use kernel::{ > +//! # gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, > +//! # prelude::*, > +//! # ptr::Alignment, > +//! # sizes::*, // `make rustdoc` fails to build: error[E0433]: failed to resolve: use of undeclared type `GpuBuddyAllocFlags` --> rust/doctests_kernel_generated.rs:6182:9 | 6182 | GpuBuddyAllocFlags::default(), | ^^^^^^^^^^^^^^^^^^ use of undeclared type `GpuBuddyAllocFlags` | help: an enum with a similar name exists | 6182 - GpuBuddyAllocFlags::default(), 6182 + GpuBuddyAllocFlag::default(), | help: consider importing this struct | 3 + use kernel::gpu::buddy::GpuBuddyAllocFlags; | error[E0433]: failed to resolve: use of undeclared type `GpuBuddyAllocFlags` --> rust/doctests_kernel_generated.rs:6195:9 | 6195 | GpuBuddyAllocFlags::default(), | ^^^^^^^^^^^^^^^^^^ use of undeclared type `GpuBuddyAllocFlags` | help: an enum with a similar name exists | 6195 - GpuBuddyAllocFlags::default(), 6195 + GpuBuddyAllocFlag::default(), | help: consider importing this struct | 3 + use kernel::gpu::buddy::GpuBuddyAllocFlags; > +//! # }; > +//! # let buddy = GpuBuddy::new(GpuBuddyParams { > +//! # base_offset: 0, > +//! # physical_memory_size: SZ_1G as u64, > +//! # chunk_size: SZ_4K, > +//! # })?; > +//! # let initial_free = buddy.free_memory(); > +//! let topdown = KBox::pin_init( > +//! buddy.alloc_blocks( > +//! GpuBuddyAllocMode::TopDown, > +//! SZ_16M, > +//! Alignment::new::<SZ_16M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); > +//! > +//! let block = topdown.iter().next().expect("expected one block"); > +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); > +//! assert_eq!(block.order(), 12); > +//! assert_eq!(block.size(), SZ_16M); > +//! > +//! // Dropping the allocation returns the memory to the buddy allocator. > +//! drop(topdown); > +//! assert_eq!(buddy.free_memory(), initial_free); > +//! # Ok::<(), Error>(()) > +//! ``` > +//! > +//! Non-contiguous allocation can fill fragmented memory by returning multiple > +//! blocks: > +//! > +//! ``` > +//! # use kernel::{ > +//! # gpu::buddy::{ > +//! # GpuBuddy, GpuBuddyAllocFlags, GpuBuddyAllocMode, GpuBuddyParams, > +//! # }, > +//! # prelude::*, > +//! # ptr::Alignment, > +//! # sizes::*, // > +//! # }; > +//! # let buddy = GpuBuddy::new(GpuBuddyParams { > +//! # base_offset: 0, > +//! # physical_memory_size: SZ_1G as u64, > +//! # chunk_size: SZ_4K, > +//! # })?; > +//! # let initial_free = buddy.free_memory(); > +//! // Create fragmentation by allocating 4MB blocks at [0,4M) and [8M,12M). > +//! let frag1 = KBox::pin_init( > +//! buddy.alloc_blocks( > +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, > +//! SZ_4M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! assert_eq!(buddy.free_memory(), initial_free - SZ_4M as u64); > +//! > +//! let frag2 = KBox::pin_init( > +//! buddy.alloc_blocks( > +//! GpuBuddyAllocMode::Range { > +//! start: SZ_8M as u64, > +//! end: (SZ_8M + SZ_4M) as u64, > +//! }, > +//! SZ_4M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! assert_eq!(buddy.free_memory(), initial_free - SZ_8M as u64); > +//! > +//! // Allocate 8MB, this returns 2 blocks from the holes. > +//! let fragmented = KBox::pin_init( > +//! buddy.alloc_blocks( > +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_16M as u64 }, > +//! SZ_8M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); > +//! > +//! let (mut count, mut total) = (0u32, 0usize); > +//! for block in fragmented.iter() { > +//! assert_eq!(block.size(), SZ_4M); > +//! total += block.size(); > +//! count += 1; > +//! } Note that we can avoid mutable variables with this: //! let total_size: usize = fragmented.iter() //! .inspect(|block| assert_eq!(block.size(), SZ_4M)) //! .map(|block| block.size()) //! .sum(); //! assert_eq!(total_size, SZ_8M); //! assert_eq!(fragmented.iter().count(), 2); But your call as to whether this is an improvement. > +//! assert_eq!(total, SZ_8M); > +//! assert_eq!(count, 2); > +//! # Ok::<(), Error>(()) > +//! ``` > +//! > +//! Contiguous allocation fails when only fragmented space is available: > +//! > +//! ``` > +//! # use kernel::{ > +//! # gpu::buddy::{ > +//! # GpuBuddy, GpuBuddyAllocFlag, GpuBuddyAllocMode, GpuBuddyParams, > +//! # }, > +//! # prelude::*, > +//! # ptr::Alignment, > +//! # sizes::*, // > +//! # }; > +//! // Create a small 16MB buddy allocator with fragmented memory. > +//! let small = GpuBuddy::new(GpuBuddyParams { > +//! base_offset: 0, > +//! physical_memory_size: SZ_16M as u64, > +//! chunk_size: SZ_4K, > +//! })?; > +//! > +//! let _hole1 = KBox::pin_init( > +//! small.alloc_blocks( > +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, > +//! SZ_4M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! > +//! let _hole2 = KBox::pin_init( > +//! small.alloc_blocks( > +//! GpuBuddyAllocMode::Range { > +//! start: SZ_8M as u64, > +//! end: (SZ_8M + SZ_4M) as u64, > +//! }, > +//! SZ_4M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlags::default(), > +//! ), > +//! GFP_KERNEL, > +//! )?; > +//! > +//! // 8MB contiguous should fail, only two non-contiguous 4MB holes exist. > +//! let result = KBox::pin_init( > +//! small.alloc_blocks( > +//! GpuBuddyAllocMode::Simple, > +//! SZ_8M, > +//! Alignment::new::<SZ_4M>(), > +//! GpuBuddyAllocFlag::Contiguous.into(), > +//! ), > +//! GFP_KERNEL, > +//! ); > +//! assert!(result.is_err()); > +//! # Ok::<(), Error>(()) > +//! ``` I think these last two examples are great both as documentation and tests - the doc has also become much more readable! > + > +use crate::{ > + bindings, > + clist_create, > + error::to_result, > + interop::list::CListHead, > + new_mutex, > + prelude::*, > + ptr::Alignment, > + sync::{ > + lock::mutex::MutexGuard, > + Arc, > + Mutex, // > + }, > + types::Opaque, // > +}; > + > +/// Allocation mode for the GPU buddy allocator. > +/// > +/// The mode determines the primary allocation strategy. Modes are mutually > +/// exclusive: an allocation is either simple, range-constrained, or top-down. > +/// > +/// Orthogonal modifier flags (e.g., contiguous, clear) are specified separately > +/// via [`GpuBuddyAllocFlags`]. > +#[derive(Copy, Clone, Debug, PartialEq, Eq)] > +pub enum GpuBuddyAllocMode { > + /// Simple allocation without constraints. > + Simple, > + /// Range-based allocation between `start` and `end` addresses. > + Range { > + /// Start of the allocation range. > + start: u64, > + /// End of the allocation range. > + end: u64, > + }, > + /// Allocate from top of address space downward. > + TopDown, > +} > + > +impl GpuBuddyAllocMode { > + // Returns the C flags corresponding to the allocation mode. > + fn into_flags(self) -> usize { > + match self { > + Self::Simple => 0, > + Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION as usize, > + Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION as usize, > + } > + } > + > + // Extracts the range start/end, defaulting to (0, 0) for non-range modes. > + fn range(self) -> (u64, u64) { > + match self { > + Self::Range { start, end } => (start, end), > + _ => (0, 0), > + } > + } > +} > + > +crate::impl_flags!( > + /// Modifier flags for GPU buddy allocation. > + /// > + /// These flags can be combined with any [`GpuBuddyAllocMode`] to control > + /// additional allocation behavior. > + #[derive(Clone, Copy, Default, PartialEq, Eq)] > + pub struct GpuBuddyAllocFlags(u32); > + > + /// Individual modifier flag for GPU buddy allocation. > + #[derive(Clone, Copy, PartialEq, Eq)] > + pub enum GpuBuddyAllocFlag { > + /// Allocate physically contiguous blocks. > + Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32, > + > + /// Request allocation from cleared (zeroed) memory. > + Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32, > + > + /// Disable trimming of partially used blocks. > + TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32, > + } > +); > + > +/// Parameters for creating a GPU buddy allocator. > +pub struct GpuBuddyParams { > + /// Base offset (in bytes) where the managed memory region starts. > + /// Allocations will be offset by this value. > + pub base_offset: u64, > + /// Total physical memory size (in bytes) managed by the allocator. > + pub physical_memory_size: u64, > + /// Minimum allocation unit / chunk size (in bytes), must be >= 4KB. > + pub chunk_size: usize, As I mentioned above, let's consider if we can store this as an `Alignment`. > +} > + > +/// Inner structure holding the actual buddy allocator. > +/// > +/// # Synchronization > +/// > +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). > +/// [`GpuBuddyGuard`] ensures that the lock is held for all > +/// allocator and free operations, preventing races between concurrent allocations > +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped. `GpuBuddyGuard` is now private, so we should avoid mentioning it in the public documentation as it will just confuse users. Users won't care about such implementation details - we can just say that internal locking ensures all operations are properly synchronized. > +/// > +/// # Invariants > +/// > +/// The inner [`Opaque`] contains an initialized buddy allocator. > +#[pin_data(PinnedDrop)] > +struct GpuBuddyInner { > + #[pin] > + inner: Opaque<bindings::gpu_buddy>, > + > + // TODO: Replace `Mutex<()>` with `Mutex<Opaque<..>>` once `Mutex::new()` > + // accepts `impl PinInit<T>`. > + #[pin] > + lock: Mutex<()>, > + /// Cached creation parameters (do not change after init). > + params: GpuBuddyParams, > +} > + > +impl GpuBuddyInner { > + /// Create a pin-initializer for the buddy allocator. > + fn new(params: GpuBuddyParams) -> impl PinInit<Self, Error> { > + let size = params.physical_memory_size; > + let chunk_size = params.chunk_size; > + > + // INVARIANT: `gpu_buddy_init` returns 0 on success, at which point the > + // `gpu_buddy` structure is initialized and ready for use with all > + // `gpu_buddy_*` APIs. `try_pin_init!` only completes if all fields succeed, > + // so the invariant holds when construction finishes. > + try_pin_init!(Self { > + inner <- Opaque::try_ffi_init(|ptr| { > + // SAFETY: `ptr` points to valid uninitialized memory from the pin-init > + // infrastructure. `gpu_buddy_init` will initialize the structure. > + to_result(unsafe { bindings::gpu_buddy_init(ptr, size, chunk_size as u64) }) > + }), > + lock <- new_mutex!(()), > + params, > + }) > + } > + > + /// Lock the mutex and return a guard for accessing the allocator. > + fn lock(&self) -> GpuBuddyGuard<'_> { > + GpuBuddyGuard { > + inner: self, > + _guard: self.lock.lock(), > + } > + } > +} > + > +#[pinned_drop] > +impl PinnedDrop for GpuBuddyInner { > + fn drop(self: Pin<&mut Self>) { > + let guard = self.lock(); > + > + // SAFETY: Per the type invariant, `inner` contains an initialized > + // allocator. `guard` provides exclusive access. > + unsafe { > + bindings::gpu_buddy_fini(guard.as_raw()); > + } > + } > +} > + > +// SAFETY: GpuBuddyInner can be sent between threads. > +unsafe impl Send for GpuBuddyInner {} > + > +// SAFETY: `GpuBuddyInner` is `Sync` because `GpuBuddyInner::lock` > +// serializes all access to the C allocator, preventing data races. > +unsafe impl Sync for GpuBuddyInner {} > + > +// Guard that proves the lock is held, enabling access to the allocator. > +// The `_guard` holds the lock for the duration of this guard's lifetime. > +struct GpuBuddyGuard<'a> { > + inner: &'a GpuBuddyInner, > + _guard: MutexGuard<'a, ()>, > +} > + > +impl GpuBuddyGuard<'_> { > + /// Get a raw pointer to the underlying C `gpu_buddy` structure. > + fn as_raw(&self) -> *mut bindings::gpu_buddy { > + self.inner.inner.get() > + } > +} > + > +/// GPU buddy allocator instance. > +/// > +/// This structure wraps the C `gpu_buddy` allocator using reference counting. > +/// The allocator is automatically cleaned up when all references are dropped. > +/// > +/// Refer to the module-level documentation for usage examples. > +pub struct GpuBuddy(Arc<GpuBuddyInner>); > + > +impl GpuBuddy { > + /// Create a new buddy allocator. > + /// > + /// Creates a buddy allocator that manages a contiguous address space of the given > + /// size, with the specified minimum allocation unit (chunk_size must be at least 4KB). > + pub fn new(params: GpuBuddyParams) -> Result<Self> { > + Ok(Self(Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL)?)) Can be written as: Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL).map(Self) I prefer this form as it avoids the `?` and re-wrapping into `Ok` for something that is already a `Result`. > > + } > + > + /// Get the base offset for allocations. > + pub fn base_offset(&self) -> u64 { > + self.0.params.base_offset > + } > + > + /// Get the chunk size (minimum allocation unit). > + pub fn chunk_size(&self) -> usize { If my suggestion above works this could return an `Alignment`. > + self.0.params.chunk_size > + } > + > + /// Get the total managed size. > + pub fn size(&self) -> u64 { > + self.0.params.physical_memory_size > + } > + > + /// Get the available (free) memory in bytes. > + pub fn free_memory(&self) -> u64 { > + let guard = self.0.lock(); > + > + // SAFETY: Per the type invariant, `inner` contains an initialized allocator. > + // `guard` provides exclusive access. > + unsafe { (*guard.as_raw()).avail } > + } > + > + /// Allocate blocks from the buddy allocator. > + /// > + /// Returns a pin-initializer for [`AllocatedBlocks`]. > + /// > + /// Takes `&self` instead of `&mut self` because the internal [`Mutex`] provides > + /// synchronization - no external `&mut` exclusivity needed. This is another implementation detail - the fact this takes `&self` and is not `unsafe` is already proof that synchronization is taken care of. > + pub fn alloc_blocks( > + &self, > + mode: GpuBuddyAllocMode, > + size: usize, For this parameter I am pretty sure we want to conform to the C API and use a `u64` - there is no benefit in not doing so, and buffers larger than 4GB *are* a reality nowadays, (maybe not for graphics, but this will also be used in compute scenarios). > + min_block_size: Alignment, > + flags: GpuBuddyAllocFlags, > + ) -> impl PinInit<AllocatedBlocks, Error> { > + let buddy_arc = Arc::clone(&self.0); > + let (start, end) = mode.range(); > + let mode_flags = mode.into_flags(); > + let modifier_flags = u32::from(flags) as usize; > + > + // Create pin-initializer that initializes list and allocates blocks. > + try_pin_init!(AllocatedBlocks { > + buddy: buddy_arc, > + list <- CListHead::new(), > + _: { > + // Lock while allocating to serialize with concurrent frees. > + let guard = buddy.lock(); > + > + // SAFETY: Per the type invariant, `inner` contains an initialized > + // allocator. `guard` provides exclusive access. > + to_result(unsafe { > + bindings::gpu_buddy_alloc_blocks( > + guard.as_raw(), > + start, > + end, > + size as u64, > + min_block_size.as_usize() as u64, > + list.as_raw(), > + mode_flags | modifier_flags, > + ) > + })? > + } > + }) > + } > +} > + > +/// Allocated blocks from the buddy allocator with automatic cleanup. > +/// > +/// This structure owns a list of allocated blocks and ensures they are > +/// automatically freed when dropped. Use `iter()` to iterate over all > +/// allocated blocks. > +/// > +/// # Invariants > +/// > +/// - `list` is an initialized, valid list head containing allocated blocks. > +#[pin_data(PinnedDrop)] > +pub struct AllocatedBlocks { > + #[pin] > + list: CListHead, > + buddy: Arc<GpuBuddyInner>, > +} > + > +impl AllocatedBlocks { > + /// Check if the block list is empty. > + pub fn is_empty(&self) -> bool { > + // An empty list head points to itself. > + !self.list.is_linked() > + } > + > + /// Iterate over allocated blocks. > + /// > + /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`] > + /// borrows `self` and is only valid for the duration of that borrow. > + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { > + // SAFETY: > + // - Per the type invariant, `list` is an initialized sentinel `list_head` > + // and is not concurrently modified (we hold a `&self` borrow). > + // - The list contains `gpu_buddy_block` items linked via > + // `__bindgen_anon_1.link`. > + // - `Block` is `#[repr(transparent)]` over `gpu_buddy_block`. > + let clist = clist_create!(unsafe { > + self.list.as_raw(), > + Block, > + bindings::gpu_buddy_block, > + __bindgen_anon_1.link > + }); > + > + clist > + .iter() > + .map(|this| AllocatedBlock { this, blocks: self }) > + } > +} > + > +#[pinned_drop] > +impl PinnedDrop for AllocatedBlocks { > + fn drop(self: Pin<&mut Self>) { > + let guard = self.buddy.lock(); > + > + // SAFETY: > + // - list is valid per the type's invariants. > + // - guard provides exclusive access to the allocator. > + unsafe { > + bindings::gpu_buddy_free_list(guard.as_raw(), self.list.as_raw(), 0); > + } > + } > +} > + > +/// A GPU buddy block. > +/// > +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned > +/// as references during iteration over [`AllocatedBlocks`]. > +/// > +/// # Invariants > +/// > +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`. > +#[repr(transparent)] > +struct Block(Opaque<bindings::gpu_buddy_block>); > + > +impl Block { > + /// Get a raw pointer to the underlying C block. > + fn as_raw(&self) -> *mut bindings::gpu_buddy_block { > + self.0.get() > + } > + > + /// Get the block's raw offset in the buddy address space (without base offset). > + fn offset(&self) -> u64 { > + // SAFETY: `self.as_raw()` is valid per the type's invariants. > + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } > + } > + > + /// Get the block order. > + fn order(&self) -> u32 { > + // SAFETY: `self.as_raw()` is valid per the type's invariants. > + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } > + } Speaking of synchronization - I only had a quick look at the C API, but are we sure these methods can all be called without holding the lock? > +} > + > +// SAFETY: `Block` is a wrapper around `gpu_buddy_block` which can be > +// sent across threads safely. > +unsafe impl Send for Block {} > + > +// SAFETY: `Block` is only accessed through shared references after > +// allocation, and thus safe to access concurrently across threads. > +unsafe impl Sync for Block {} > + > +/// A buddy block paired with its owning [`AllocatedBlocks`] context. > +/// > +/// Unlike a raw block, which only knows its offset within the buddy address > +/// space, an [`AllocatedBlock`] also has access to the allocator's `base_offset` > +/// and `chunk_size`, enabling it to compute absolute offsets and byte sizes. > +/// > +/// Returned by [`AllocatedBlocks::iter()`]. > +pub struct AllocatedBlock<'a> { > + this: &'a Block, > + blocks: &'a AllocatedBlocks, > +} > + > +impl AllocatedBlock<'_> { > + /// Get the block's offset in the address space. > + /// > + /// Returns the absolute offset including the allocator's base offset. > + /// This is the actual address to use for accessing the allocated memory. > + pub fn offset(&self) -> u64 { > + self.blocks.buddy.params.base_offset + self.this.offset() > + } > + > + /// Get the block order (size = chunk_size << order). > + pub fn order(&self) -> u32 { > + self.this.order() > + } > + > + /// Get the block's size in bytes. > + pub fn size(&self) -> usize { > + self.blocks.buddy.params.chunk_size << self.this.order() > + } > +} > diff --git a/rust/kernel/gpu/mod.rs b/rust/kernel/gpu/mod.rs Let's use `gpu.rs` as the file for this module. > new file mode 100644 > index 000000000000..8f25e6367edc > --- /dev/null > +++ b/rust/kernel/gpu/mod.rs > @@ -0,0 +1,5 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! GPU subsystem abstractions. > + > +pub mod buddy; IMHO we should have a `#[cfg(CONFIG_GPU_BUDDY = "y")]` here for defensiveness... > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index bb741f1e0dfd..63e3f656eb6c 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -98,6 +98,8 @@ > pub mod firmware; > pub mod fmt; > pub mod fs; > +#[cfg(CONFIG_GPU_BUDDY = "y")] > +pub mod gpu; ... because in the future I suspect the condition for enabling that module will become broader. I think it's fine to keep it as-is for now though. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 13:12 ` Alexandre Courbot @ 2026-03-16 18:43 ` Joel Fernandes 2026-03-17 0:58 ` Alexandre Courbot 2026-03-16 18:51 ` John Hubbard 1 sibling, 1 reply; 24+ messages in thread From: Joel Fernandes @ 2026-03-16 18:43 UTC (permalink / raw) To: Alexandre Courbot Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev Hi Alex, On Mon Mar 16, 2026 at 10:12 PM JST, Alexandre Courbot wrote: > This is getting close IMHO. But `make rustdoc` fails on the examples, > and there are still clippy warnings - please make sure to address them. Fixed. >> +//! use kernel::{ >> +//! gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, > > nit: should also use kernel formatting style. Fixed. >> +//! ptr::Alignment, >> +//! sizes::*, // >> +//! }; >> +//! >> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. >> +//! let buddy = GpuBuddy::new(GpuBuddyParams { >> +//! base_offset: 0, >> +//! physical_memory_size: SZ_1G as u64, >> +//! chunk_size: SZ_4K, > > `chunk_size` is an interesting case. The C API uses a `u64`, but I think > we can reasonably consider that we won't ever need chunks larger than > 4GB (or can we :O). I'm actually ok with using a `usize` for this one. > > One of the first things the C code does is throwing an error if it is > not a power of 2, so maybe we can even request an `Alignment`? > > I'm a bit torn as to whether we should use a `u64` to conform with the C > API, but doing so would mean we cannot use an `Alignment`... I prefer to keep it simple and use `usize` for now. I cannot imagine chunk_size ever exceeding 4GB, and given our stance on rejecting invalid inputs, this sounds reasonable. Regarding `Alignment`, I still prefer `usize` here since it makes the caller-side simpler and as you noted the C code already does error-checking. Let's revisit if needed once this lands. >> +//! GpuBuddyAllocMode::Range { start: 0, end: 0 }, > > This zero-sized range looks confusing for the example. I understand the > C API allows this, but I don't think we should. Is there a difference > with just using `GpuBuddyAllocMode::Simple`? If not, let's switch to > that, and reject zero-sized ranges in the same spirit as we don't allow > invalid flag combinations. Good point. Switched to use `GpuBuddyAllocMode::Simple` and added validation. >> +//! assert_eq!(block.offset(), 0); >> +//! assert_eq!(block.order(), 12); // 2^12 pages = 16MB >> +//! assert_eq!(block.size(), SZ_16M); > > Here we should also check that there is not a second block. Added. >> +//! // Dropping the allocation returns the memory to the buddy allocator. > > s/memory/range - technically we are not returning physical memory. Fixed. >> +//! let (mut count, mut total) = (0u32, 0usize); >> +//! for block in fragmented.iter() { >> +//! assert_eq!(block.size(), SZ_4M); >> +//! total += block.size(); >> +//! count += 1; >> +//! } > > Note that we can avoid mutable variables with this: > > //! let total_size: usize = fragmented.iter() > //! .inspect(|block| assert_eq!(block.size(), SZ_4M)) > //! .map(|block| block.size()) > //! .sum(); > //! assert_eq!(total_size, SZ_8M); > //! assert_eq!(fragmented.iter().count(), 2); > > But your call as to whether this is an improvement. I feel the current for-loop version is slightly more readable, especially in a doc example aimed at new users, so I'd like to keep it as-is. >> +//! # }; >> +//! # let buddy = GpuBuddy::new(GpuBuddyParams { >> +//! # base_offset: 0, >> +//! # physical_memory_size: SZ_1G as u64, >> +//! # chunk_size: SZ_4K, >> +//! # })?; >> +//! # let initial_free = buddy.free_memory(); > > `make rustdoc` fails to build: > > error[E0433]: failed to resolve: use of undeclared type `GpuBuddyAllocFlags` Fixed. I'll try to run this before submissions henceforth. >> +/// # Synchronization >> +/// >> +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). >> +/// [`GpuBuddyGuard`] ensures that the lock is held for all >> +/// allocator and free operations, preventing races between concurrent allocations >> +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped. > > `GpuBuddyGuard` is now private, so we should avoid mentioning it in the > public documentation as it will just confuse users. > > Users won't care about such implementation details - we can just say > that internal locking ensures all operations are properly synchronized. Done. >> + pub fn new(params: GpuBuddyParams) -> Result<Self> { >> + Ok(Self(Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL)?)) > > Can be written as: > > Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL).map(Self) > > I prefer this form as it avoids the `?` and re-wrapping into `Ok` for > something that is already a `Result`. Done. >> + /// Allocate blocks from the buddy allocator. >> + /// >> + /// Returns a pin-initializer for [`AllocatedBlocks`]. >> + /// >> + /// Takes `&self` instead of `&mut self` because the internal [`Mutex`] provides >> + /// synchronization - no external `&mut` exclusivity needed. > > This is another implementation detail - the fact this takes `&self` and > is not `unsafe` is already proof that synchronization is taken care of. Removed the comment. >> + pub fn alloc_blocks( >> + &self, >> + mode: GpuBuddyAllocMode, >> + size: usize, > > For this parameter I am pretty sure we want to conform to the C API and > use a `u64` - there is no benefit in not doing so, and buffers larger > than 4GB *are* a reality nowadays, (maybe not for graphics, but this > will also be used in compute scenarios). Agreed. Though, note this adds 7 more `as` usages, but I guess there's nothing we can do till the IntoSafe stuff is moved to core rust, I think. >> + fn offset(&self) -> u64 { >> + // SAFETY: `self.as_raw()` is valid per the type's invariants. >> + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } >> + } >> + >> + /// Get the block order. >> + fn order(&self) -> u32 { >> + // SAFETY: `self.as_raw()` is valid per the type's invariants. >> + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } >> + } > > Speaking of synchronization - I only had a quick look at the C API, but > are we sure these methods can all be called without holding the lock? Yes, sure. Locking is only required around alloc/free operations. Additionally, `AllocatedBlock` borrows a reference to `AllocatedBlocks`, so the borrow checker prevents `AllocatedBlocks` from being dropped. >> diff --git a/rust/kernel/gpu/mod.rs b/rust/kernel/gpu/mod.rs > > Let's use `gpu.rs` as the file for this module. Done, renamed and also updated the MAINTAINERS entries. >> +pub mod buddy; > > IMHO we should have a `#[cfg(CONFIG_GPU_BUDDY = "y")]` here for > defensiveness... Added. >> +#[cfg(CONFIG_GPU_BUDDY = "y")] >> +pub mod gpu; > > ... because in the future I suspect the condition for enabling that > module will become broader. I think it's fine to keep it as-is for now > though. Noted, agreed, keeping it as-is for now. Thanks for the thorough review! Will respin and send likely tomorrow or day after. thanks, -- Joel Fernandes ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 18:43 ` Joel Fernandes @ 2026-03-17 0:58 ` Alexandre Courbot 2026-03-17 18:49 ` Joel Fernandes 0 siblings, 1 reply; 24+ messages in thread From: Alexandre Courbot @ 2026-03-17 0:58 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Tue Mar 17, 2026 at 3:43 AM JST, Joel Fernandes wrote: <snip> >>> +//! ptr::Alignment, >>> +//! sizes::*, // >>> +//! }; >>> +//! >>> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. >>> +//! let buddy = GpuBuddy::new(GpuBuddyParams { >>> +//! base_offset: 0, >>> +//! physical_memory_size: SZ_1G as u64, >>> +//! chunk_size: SZ_4K, >> >> `chunk_size` is an interesting case. The C API uses a `u64`, but I think >> we can reasonably consider that we won't ever need chunks larger than >> 4GB (or can we :O). I'm actually ok with using a `usize` for this one. >> >> One of the first things the C code does is throwing an error if it is >> not a power of 2, so maybe we can even request an `Alignment`? >> >> I'm a bit torn as to whether we should use a `u64` to conform with the C >> API, but doing so would mean we cannot use an `Alignment`... > > I prefer to keep it simple and use `usize` for now. I cannot imagine > chunk_size ever exceeding 4GB, and given our stance on rejecting invalid > inputs, this sounds reasonable. Regarding `Alignment`, I still prefer > `usize` here since it makes the caller-side simpler and as you noted the > C code already does error-checking. Let's revisit if needed once this > lands. I would like to insist a bit here re: Alignment. We are not trying to make the caller side simpler - we are trying to make it correct and to turn runtime failures into build-time ones as much as possible. This is a good case for that. The additional burden, if you can call it so, to the caller is just in the initial call to `GpuBuddy::new` - i.e. typically once per driver. The most important API, `alloc_blocks`, will be unaffected - and actually this one already has one `Alignment` as a parameter, for the minimal block size! So if anything it would be illogical not to follow suit on the buddy's `block_size` parameter. <snip> >>> +//! let (mut count, mut total) = (0u32, 0usize); >>> +//! for block in fragmented.iter() { >>> +//! assert_eq!(block.size(), SZ_4M); >>> +//! total += block.size(); >>> +//! count += 1; >>> +//! } >> >> Note that we can avoid mutable variables with this: >> >> //! let total_size: usize = fragmented.iter() >> //! .inspect(|block| assert_eq!(block.size(), SZ_4M)) >> //! .map(|block| block.size()) >> //! .sum(); >> //! assert_eq!(total_size, SZ_8M); >> //! assert_eq!(fragmented.iter().count(), 2); >> >> But your call as to whether this is an improvement. > > I feel the current for-loop version is slightly more readable, > especially in a doc example aimed at new users, so I'd like to keep > it as-is. Sounds good. <snip> >> For this parameter I am pretty sure we want to conform to the C API and >> use a `u64` - there is no benefit in not doing so, and buffers larger >> than 4GB *are* a reality nowadays, (maybe not for graphics, but this >> will also be used in compute scenarios). > > Agreed. Though, note this adds 7 more `as` usages, but I guess there's > nothing we can do till the IntoSafe stuff is moved to core rust, I think. How so? This parameter is just passed to the C function. If you are referring to the examples, then yes that's unfortunate but there are at least two ways where this could be eventually fixed (John's SZ_* rework and the IntoSafe stuff), so we can update these when either lands. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 0:58 ` Alexandre Courbot @ 2026-03-17 18:49 ` Joel Fernandes 0 siblings, 0 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-17 18:49 UTC (permalink / raw) To: Alexandre Courbot Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Tue, Mar 17, 2026 at 09:58:19AM +0900, Alexandre Courbot wrote: > On Tue Mar 17, 2026 at 3:43 AM JST, Joel Fernandes wrote: > <snip> > >>> +//! ptr::Alignment, > >>> +//! sizes::*, // > >>> +//! }; > >>> +//! > >>> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. > >>> +//! let buddy = GpuBuddy::new(GpuBuddyParams { > >>> +//! base_offset: 0, > >>> +//! physical_memory_size: SZ_1G as u64, > >>> +//! chunk_size: SZ_4K, > >> > >> `chunk_size` is an interesting case. The C API uses a `u64`, but I think > >> we can reasonably consider that we won't ever need chunks larger than > >> 4GB (or can we :O). I'm actually ok with using a `usize` for this one. > >> > >> One of the first things the C code does is throwing an error if it is > >> not a power of 2, so maybe we can even request an `Alignment`? > >> > >> I'm a bit torn as to whether we should use a `u64` to conform with the C > >> API, but doing so would mean we cannot use an `Alignment`... > > > > I prefer to keep it simple and use `usize` for now. I cannot imagine > > chunk_size ever exceeding 4GB, and given our stance on rejecting invalid > > inputs, this sounds reasonable. Regarding `Alignment`, I still prefer > > `usize` here since it makes the caller-side simpler and as you noted the > > C code already does error-checking. Let's revisit if needed once this > > lands. > > I would like to insist a bit here re: Alignment. We are not trying to > make the caller side simpler - we are trying to make it correct and to > turn runtime failures into build-time ones as much as possible. This is > a good case for that. > > The additional burden, if you can call it so, to the caller is just in > the initial call to `GpuBuddy::new` - i.e. typically once per driver. > The most important API, `alloc_blocks`, will be unaffected - and > actually this one already has one `Alignment` as a parameter, for the > minimal block size! So if anything it would be illogical not to follow > suit on the buddy's `block_size` parameter. Right, I was on the fence about it, I changed it one place but not the other. After our recent discussion, I will change it all to Alignment considering robustness argument, sounds good :) > > <snip> > >>> +//! let (mut count, mut total) = (0u32, 0usize); > >>> +//! for block in fragmented.iter() { > >>> +//! assert_eq!(block.size(), SZ_4M); > >>> +//! total += block.size(); > >>> +//! count += 1; > >>> +//! } > >> > >> Note that we can avoid mutable variables with this: > >> > >> //! let total_size: usize = fragmented.iter() > >> //! .inspect(|block| assert_eq!(block.size(), SZ_4M)) > >> //! .map(|block| block.size()) > >> //! .sum(); > >> //! assert_eq!(total_size, SZ_8M); > >> //! assert_eq!(fragmented.iter().count(), 2); > >> > >> But your call as to whether this is an improvement. > > > > I feel the current for-loop version is slightly more readable, > > especially in a doc example aimed at new users, so I'd like to keep > > it as-is. > > Sounds good. > > <snip> > >> For this parameter I am pretty sure we want to conform to the C API and > >> use a `u64` - there is no benefit in not doing so, and buffers larger > >> than 4GB *are* a reality nowadays, (maybe not for graphics, but this > >> will also be used in compute scenarios). > > > > Agreed. Though, note this adds 7 more `as` usages, but I guess there's > > nothing we can do till the IntoSafe stuff is moved to core rust, I think. > > How so? This parameter is just passed to the C function. > > If you are referring to the examples, then yes that's unfortunate but > there are at least two ways where this could be eventually fixed (John's > SZ_* rework and the IntoSafe stuff), so we can update these when either > lands. > Yes, referring to the examples. Yes we'll need to adapt it later. For now I'll leave it with the 'as' usage. -- Joel Fernandes ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 13:12 ` Alexandre Courbot 2026-03-16 18:43 ` Joel Fernandes @ 2026-03-16 18:51 ` John Hubbard 2026-03-16 21:00 ` Joel Fernandes 2026-03-17 1:02 ` Alexandre Courbot 1 sibling, 2 replies; 24+ messages in thread From: John Hubbard @ 2026-03-16 18:51 UTC (permalink / raw) To: Alexandre Courbot, Joel Fernandes Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/16/26 6:12 AM, Alexandre Courbot wrote: > On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: ... >> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. >> +//! let buddy = GpuBuddy::new(GpuBuddyParams { >> +//! base_offset: 0, >> +//! physical_memory_size: SZ_1G as u64, >> +//! chunk_size: SZ_4K, > > `chunk_size` is an interesting case. The C API uses a `u64`, but I think > we can reasonably consider that we won't ever need chunks larger than > 4GB (or can we :O). I'm actually ok with using a `usize` for this one. > > One of the first things the C code does is throwing an error if it is > not a power of 2, so maybe we can even request an `Alignment`? > > I'm a bit torn as to whether we should use a `u64` to conform with the C > API, but doing so would mean we cannot use an `Alignment`... Alex, have you seen my Alignment patch [1], for that? It's sitting around with only Miguel having responded, but seems like exactly what you're talking about here. [1] https://lore.kernel.org/20260312031507.216709-3-jhubbard@nvidia.com thanks, -- John Hubbard ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 18:51 ` John Hubbard @ 2026-03-16 21:00 ` Joel Fernandes 2026-03-16 22:08 ` John Hubbard 2026-03-17 1:02 ` Alexandre Courbot 1 sibling, 1 reply; 24+ messages in thread From: Joel Fernandes @ 2026-03-16 21:00 UTC (permalink / raw) To: John Hubbard Cc: Alexandre Courbot, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Andrea Righi, Zhi Wang, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Mon, 16 Mar 2026, John Hubbard wrote: > Alex, have you seen my Alignment patch [1], for that? It's sitting > around with only Miguel having responded, but seems like exactly > what you're talking about here. > > [1] https://lore.kernel.org/20260312031507.216709-3-jhubbard@nvidia.com `Alignment` is already in core Rust for Linux (`rust/kernel/ptr.rs`) and I'm already using it in my nova-core v9 patches. -- Joel Fernandes ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 21:00 ` Joel Fernandes @ 2026-03-16 22:08 ` John Hubbard 0 siblings, 0 replies; 24+ messages in thread From: John Hubbard @ 2026-03-16 22:08 UTC (permalink / raw) To: Joel Fernandes Cc: Alexandre Courbot, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Andrea Righi, Zhi Wang, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/16/26 2:00 PM, Joel Fernandes wrote: > On Mon, 16 Mar 2026, John Hubbard wrote: > >> Alex, have you seen my Alignment patch [1], for that? It's sitting >> around with only Miguel having responded, but seems like exactly >> what you're talking about here. >> >> [1] https://lore.kernel.org/20260312031507.216709-3-jhubbard@nvidia.com > > `Alignment` is already in core Rust for Linux > (`rust/kernel/ptr.rs`) and I'm already using it in my nova-core v9 > patches. > Right, but the patch I linked doesn't introduce Alignment. It adds a new from_u64() constructor to the existing Alignment type. Today the only constructors take usize, so there's no way to go from a u64 DeviceSize constant to an Alignment without a manual cast. Alex wanted to use Alignment for chunk_size but said "doing so would mean we cannot use an Alignment" if the field conforms to the C API's u64. So again, I think that patch is worth looking at. thanks, -- John Hubbard ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-16 18:51 ` John Hubbard 2026-03-16 21:00 ` Joel Fernandes @ 2026-03-17 1:02 ` Alexandre Courbot 2026-03-17 1:10 ` John Hubbard 2026-03-17 18:44 ` Joel Fernandes 1 sibling, 2 replies; 24+ messages in thread From: Alexandre Courbot @ 2026-03-17 1:02 UTC (permalink / raw) To: John Hubbard Cc: Joel Fernandes, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Tue Mar 17, 2026 at 3:51 AM JST, John Hubbard wrote: > On 3/16/26 6:12 AM, Alexandre Courbot wrote: >> On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: > ... >>> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. >>> +//! let buddy = GpuBuddy::new(GpuBuddyParams { >>> +//! base_offset: 0, >>> +//! physical_memory_size: SZ_1G as u64, >>> +//! chunk_size: SZ_4K, >> >> `chunk_size` is an interesting case. The C API uses a `u64`, but I think >> we can reasonably consider that we won't ever need chunks larger than >> 4GB (or can we :O). I'm actually ok with using a `usize` for this one. >> >> One of the first things the C code does is throwing an error if it is >> not a power of 2, so maybe we can even request an `Alignment`? >> >> I'm a bit torn as to whether we should use a `u64` to conform with the C >> API, but doing so would mean we cannot use an `Alignment`... > > Alex, have you seen my Alignment patch [1], for that? It's sitting > around with only Miguel having responded, but seems like exactly > what you're talking about here. Not exactly - this patch provides a shortcut for creating an Alignment from a u64, but it doesn't allow to store alignments larger than 4GB on a 32-bit architecture since the value itself is still stored as a `usize`. But that's really a theoretical worry of mine anyway - nobody will ever work with buffers larger than 4GB on a 32-bit arch to begin with. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 1:02 ` Alexandre Courbot @ 2026-03-17 1:10 ` John Hubbard 2026-03-17 1:58 ` Alexandre Courbot 2026-03-17 18:44 ` Joel Fernandes 1 sibling, 1 reply; 24+ messages in thread From: John Hubbard @ 2026-03-17 1:10 UTC (permalink / raw) To: Alexandre Courbot Cc: Joel Fernandes, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/16/26 6:02 PM, Alexandre Courbot wrote: > On Tue Mar 17, 2026 at 3:51 AM JST, John Hubbard wrote: >> On 3/16/26 6:12 AM, Alexandre Courbot wrote: >>> On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: >> ... >>> I'm a bit torn as to whether we should use a `u64` to conform with the C >>> API, but doing so would mean we cannot use an `Alignment`... >> >> Alex, have you seen my Alignment patch [1], for that? It's sitting >> around with only Miguel having responded, but seems like exactly >> what you're talking about here. > > Not exactly - this patch provides a shortcut for creating an Alignment > from a u64, but it doesn't allow to store alignments larger than 4GB on > a 32-bit architecture since the value itself is still stored as a `usize`. > > But that's really a theoretical worry of mine anyway - nobody will ever > work with buffers larger than 4GB on a 32-bit arch to begin with. Actually, in the CPU world, this claim was made early and often, but turned out to be wildly wrong! That's why we have "high mem" in linux-mm (a constant source of suffering for kernel devs). The 32-bit systems designer do not feel constrained to keep their memory sizes below that which they can directly address. :) thanks, -- John Hubbard ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 1:10 ` John Hubbard @ 2026-03-17 1:58 ` Alexandre Courbot 0 siblings, 0 replies; 24+ messages in thread From: Alexandre Courbot @ 2026-03-17 1:58 UTC (permalink / raw) To: John Hubbard Cc: Joel Fernandes, linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Tue Mar 17, 2026 at 10:10 AM JST, John Hubbard wrote: > On 3/16/26 6:02 PM, Alexandre Courbot wrote: >> On Tue Mar 17, 2026 at 3:51 AM JST, John Hubbard wrote: >>> On 3/16/26 6:12 AM, Alexandre Courbot wrote: >>>> On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: >>> ... >>>> I'm a bit torn as to whether we should use a `u64` to conform with the C >>>> API, but doing so would mean we cannot use an `Alignment`... >>> >>> Alex, have you seen my Alignment patch [1], for that? It's sitting >>> around with only Miguel having responded, but seems like exactly >>> what you're talking about here. >> >> Not exactly - this patch provides a shortcut for creating an Alignment >> from a u64, but it doesn't allow to store alignments larger than 4GB on >> a 32-bit architecture since the value itself is still stored as a `usize`. >> >> But that's really a theoretical worry of mine anyway - nobody will ever >> work with buffers larger than 4GB on a 32-bit arch to begin with. > > Actually, in the CPU world, this claim was made early and often, but > turned out to be wildly wrong! That's why we have "high mem" in > linux-mm (a constant source of suffering for kernel devs). > > The 32-bit systems designer do not feel constrained to keep their > memory sizes below that which they can directly address. :) Yet IIUC PAE still limits a single process to a 4GB address space (and `usize` is still 32-bit anyway), so hopefully we will be spared that pain. :) ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v12.1 1/1] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 1:02 ` Alexandre Courbot 2026-03-17 1:10 ` John Hubbard @ 2026-03-17 18:44 ` Joel Fernandes 1 sibling, 0 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-17 18:44 UTC (permalink / raw) To: Alexandre Courbot, John Hubbard Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, nouveau, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/16/2026 9:02 PM, Alexandre Courbot wrote: > On Tue Mar 17, 2026 at 3:51 AM JST, John Hubbard wrote: >> On 3/16/26 6:12 AM, Alexandre Courbot wrote: >>> On Mon Mar 9, 2026 at 10:53 PM JST, Joel Fernandes wrote: >> ... >>>> +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. >>>> +//! let buddy = GpuBuddy::new(GpuBuddyParams { >>>> +//! base_offset: 0, >>>> +//! physical_memory_size: SZ_1G as u64, >>>> +//! chunk_size: SZ_4K, >>> >>> `chunk_size` is an interesting case. The C API uses a `u64`, but I think >>> we can reasonably consider that we won't ever need chunks larger than >>> 4GB (or can we :O). I'm actually ok with using a `usize` for this one. >>> >>> One of the first things the C code does is throwing an error if it is >>> not a power of 2, so maybe we can even request an `Alignment`? >>> >>> I'm a bit torn as to whether we should use a `u64` to conform with the C >>> API, but doing so would mean we cannot use an `Alignment`... >> >> Alex, have you seen my Alignment patch [1], for that? It's sitting >> around with only Miguel having responded, but seems like exactly >> what you're talking about here. > > Not exactly - this patch provides a shortcut for creating an Alignment > from a u64, but it doesn't allow to store alignments larger than 4GB on > a 32-bit architecture since the value itself is still stored as a `usize`. > > But that's really a theoretical worry of mine anyway - nobody will ever > work with buffers larger than 4GB on a 32-bit arch to begin with. I think we don't have to worry about chunk size ever exceeding 4GB. Such a large minimum size will cause massive fragmentation, essentially defeating the purpose of a buddy allocator and not even for work for any VRAM with < 4GB memory anyway. Per Alex's other email, I will switch this to Alignment to constrain the alignment requirement. I agree now that the robustness of doing so is worth it. thanks, -- Joel Fernandes ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v13 0/2] Rust GPU buddy allocator bindings 2026-03-08 18:04 [PATCH v12 0/1] Rust GPU buddy allocator bindings Joel Fernandes 2026-03-08 18:04 ` [PATCH v12 1/1] rust: gpu: Add " Joel Fernandes 2026-03-09 13:53 ` [PATCH v12.1 0/1] Rust " Joel Fernandes @ 2026-03-17 22:03 ` Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 1/2] rust: gpu: Add " Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer Joel Fernandes 2 siblings, 2 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-17 22:03 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes This patch adds safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The prerequisite infrastructure patches (DRM buddy code movement and the uninitialized buddy fix) have been absorbed into upstream -next, so this is now a standalone patch. The series along with all dependencies, including clist and nova-core mm patches, are available at: git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: buddy-bindings-v13-20260317) Change log: Changes from v12 to v13: - Split MAINTAINERS reviewer update into a separate patch (Danilo). - Adjustments to use the Alignment type chunk size parameters (Alex). - Fixed doctest assertion due to blocks landing on top of range. - Changed chunk_size local vars to Alignment. - Changed block size to u64 from usize. - Renamed rust/kernel/gpu/mod.rs to rust/kernel/gpu.rs. - Several other adjustments (Alex). Changes from v11 to v12: - Rebased on linux-next his is now a standalone single patch as dependencies are absorbed (but not clist is a prequisite) - Redesigned allocation API (Alexandre Courbot) for better Rust ergonomics. - Split single long example into 4 self-contained examples (Alexandre Courbot). - Several safety and invariant comment changes (Danilo). - MAINTAINERS changes (Arun, Mathew, Danilo, Dave). - Fixed `#[cfg(CONFIG_GPU_BUDDY)]` to `#[cfg(CONFIG_GPU_BUDDY = "y")]` (Danilo Krummrich). - Updated `ffi::clist::CListHead` to `interop::list::CListHead`. Changes from v10 to v11: - Dropped "rust: ffi: Convert pub use to pub mod and create ffi module" patch; the ffi module restructuring will go through a different path. - Dropped "rust: clist: Add support to interface with C linked lists" patch; the clist module will be submitted separately. - Dropped "nova-core: Kconfig: Sort select statements alphabetically" cosmetic patch. - Patches 1-3 (DRM buddy movement and fix) are included as reference only; they are already being pulled into upstream via drm-misc-next. - Removed clist patches as those can go in independently (Alice). - Moved the Kconfig GPU_BUDDY selection patch to nova-core mm series to enable it when it is actually used. - Various nits to comments, etc. Changes from v9 to v10: - Absorbed the DRM buddy code movement patches into this series as patches 1-2. Dave Airlie reworked these into two parts for better git history. - Added "gpu: Fix uninitialized buddy for built-in drivers" fix by Koen Koning, using subsys_initcall instead of module_init to fix NULL pointer dereference when built-in drivers use the buddy allocator before initialization. - Added "rust: ffi: Convert pub use to pub mod and create ffi module" to prepare the ffi module for hosting clist as a sub-module. - Moved clist from rust/kernel/clist.rs to rust/kernel/ffi/. - Added "nova-core: Kconfig: Sort select statements alphabetically" (Danilo). Changes from v8 to v9: - Updated nova-core Kconfig patch: addressed sorting of Kconfig options. - Added Daniel Almeida's Reviewed-by tag to clist patch. - Minor refinements to GPU buddy bindings. Changes from v7 to v8: - Added nova-core Kconfig patch to select GPU_BUDDY for VRAM allocation. - Various changes suggested by Danilo Krummrich, Gary Guo, and Daniel Almeida. - Added Acked-by: Gary Guo for clist patch. Changes from v6 to v7: - Major restructuring: split the large 26-patch v6 RFC series. v7 only contains the Rust infrastructure patches (clist + GPU buddy bindings), extracted from the full nova-core MM series. The nova-core MM patches follow separately. - Rebased on linux-next. Changes from v5 to v6: - Rebased on drm-rust-kernel/drm-rust-next. - Expanded from 6 to 26 patches with full nova-core MM infrastructure including page table walker, VMM, BAR1 user interface, TLB flush, and GpuMm manager. Changes from v4 to v5: - Added PRAMIN aperture support with documentation and self-tests. - Improved buddy allocator bindings (fewer lines of code). - Based on drm-rust-next instead of linux-next. Changes from v3 to v4: - Combined the clist and DRM buddy series into a single coherent series. - Added DRM buddy allocator movement from drivers/gpu/drm/ up to drivers/gpu/, renaming API from drm_buddy to gpu_buddy. - Added Rust bindings for the GPU buddy allocator. Changes from v2 to v3: - Squashed 3 clist patches into one due to inter-dependencies. - Changed Clist to Clist<'a, T> using const generic offset (Alex Courbot). - Simplified C helpers to only list_add_tail (Alex Courbot, John Hubbard). - Added init_list_head() Rust function (Alex Courbot). - Added FusedIterator, PartialEq/Eq impls. - Added MAINTAINERS entry (Miguel Ojeda). Changes from v1 (RFC) to v2: - Dropped DRM buddy allocator patches; series focuses solely on clist module. - Dropped sample modules, replaced with doctests. - Added proper lifetime management similar to scatterlist. - Split clist into 3 separate patches. Link to v12: https://lore.kernel.org/all/20260308180407.3988286-1-joelagnelf@nvidia.com/ Link to v11: https://lore.kernel.org/all/20260224224005.3232841-1-joelagnelf@nvidia.com/ Joel Fernandes (2): rust: gpu: Add GPU buddy allocator bindings MAINTAINERS: gpu: buddy: Update reviewer MAINTAINERS | 8 +- rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu.rs | 6 + rust/kernel/gpu/buddy.rs | 623 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 7 files changed, 673 insertions(+), 1 deletion(-) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu.rs create mode 100644 rust/kernel/gpu/buddy.rs -- 2.34.1 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v13 1/2] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 22:03 ` [PATCH v13 0/2] Rust " Joel Fernandes @ 2026-03-17 22:03 ` Joel Fernandes 2026-03-18 18:41 ` Joel Fernandes 2026-03-19 12:49 ` Alexandre Courbot 2026-03-17 22:03 ` [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer Joel Fernandes 1 sibling, 2 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-17 22:03 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Add safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The GPU buddy allocator implements a binary buddy system useful for GPU physical memory allocation. nova-core will use it for physical memory allocation. Cc: Nikola Djukic <ndjukic@nvidia.com> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- MAINTAINERS | 6 + rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu.rs | 6 + rust/kernel/gpu/buddy.rs | 622 ++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 7 files changed, 671 insertions(+) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu.rs create mode 100644 rust/kernel/gpu/buddy.rs diff --git a/MAINTAINERS b/MAINTAINERS index e847099efcc2..cd9505d3be60 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8531,7 +8531,10 @@ T: git https://gitlab.freedesktop.org/drm/rust/kernel.git F: drivers/gpu/drm/nova/ F: drivers/gpu/drm/tyr/ F: drivers/gpu/nova-core/ +F: rust/helpers/gpu.c F: rust/kernel/drm/ +F: rust/kernel/gpu.rs +F: rust/kernel/gpu/ DRM DRIVERS FOR ALLWINNER A10 M: Chen-Yu Tsai <wens@kernel.org> @@ -8952,6 +8955,9 @@ F: drivers/gpu/drm/drm_buddy.c F: drivers/gpu/tests/gpu_buddy_test.c F: include/drm/drm_buddy.h F: include/linux/gpu_buddy.h +F: rust/helpers/gpu.c +F: rust/kernel/gpu.rs +F: rust/kernel/gpu/ DRM AUTOMATED TESTING M: Helen Koike <helen.fornazier@gmail.com> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 083cc44aa952..dbb765a9fdbd 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -29,6 +29,7 @@ #include <linux/hrtimer_types.h> #include <linux/acpi.h> +#include <linux/gpu_buddy.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -146,6 +147,16 @@ const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP; const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE; const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE; +#if IS_ENABLED(CONFIG_GPU_BUDDY) +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_RANGE_ALLOCATION = GPU_BUDDY_RANGE_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TOPDOWN_ALLOCATION = GPU_BUDDY_TOPDOWN_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CONTIGUOUS_ALLOCATION = + GPU_BUDDY_CONTIGUOUS_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEAR_ALLOCATION = GPU_BUDDY_CLEAR_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEARED = GPU_BUDDY_CLEARED; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DISABLE; +#endif + #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" diff --git a/rust/helpers/gpu.c b/rust/helpers/gpu.c new file mode 100644 index 000000000000..38b1a4e6bef8 --- /dev/null +++ b/rust/helpers/gpu.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/gpu_buddy.h> + +#ifdef CONFIG_GPU_BUDDY + +__rust_helper u64 rust_helper_gpu_buddy_block_offset(const struct gpu_buddy_block *block) +{ + return gpu_buddy_block_offset(block); +} + +__rust_helper unsigned int rust_helper_gpu_buddy_block_order(struct gpu_buddy_block *block) +{ + return gpu_buddy_block_order(block); +} + +__rust_helper u64 rust_helper_gpu_buddy_block_size(struct gpu_buddy *mm, + struct gpu_buddy_block *block) +{ + return gpu_buddy_block_size(mm, block); +} + +#endif /* CONFIG_GPU_BUDDY */ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 724fcb8240ac..a53929ce52a3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "gpu.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/kernel/gpu.rs b/rust/kernel/gpu.rs new file mode 100644 index 000000000000..1dc5d0c8c09d --- /dev/null +++ b/rust/kernel/gpu.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU subsystem abstractions. + +#[cfg(CONFIG_GPU_BUDDY = "y")] +pub mod buddy; diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs new file mode 100644 index 000000000000..af99d66832fd --- /dev/null +++ b/rust/kernel/gpu/buddy.rs @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU buddy allocator bindings. +//! +//! C header: [`include/linux/gpu_buddy.h`](srctree/include/linux/gpu_buddy.h) +//! +//! This module provides Rust abstractions over the Linux kernel's GPU buddy +//! allocator, which implements a binary buddy memory allocator. +//! +//! The buddy allocator manages a contiguous address space and allocates blocks +//! in power-of-two sizes, useful for GPU physical memory management. +//! +//! # Examples +//! +//! Create a buddy allocator and perform a basic range allocation: +//! +//! ``` +//! use kernel::{ +//! gpu::buddy::{ +//! GpuBuddy, +//! GpuBuddyAllocFlags, +//! GpuBuddyAllocMode, +//! GpuBuddyParams, // +//! }, +//! prelude::*, +//! ptr::Alignment, +//! sizes::*, // +//! }; +//! +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. +//! let buddy = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_1G as u64, +//! chunk_size: Alignment::new::<SZ_4K>(), +//! })?; +//! +//! assert_eq!(buddy.size(), SZ_1G as u64); +//! assert_eq!(buddy.chunk_size(), Alignment::new::<SZ_4K>()); +//! let initial_free = buddy.free_memory(); +//! +//! // Allocate 16MB. Block lands at the top of the address range. +//! let allocated = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Simple, +//! SZ_16M as u64, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = allocated.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); +//! assert_eq!(block.order(), 12); // 2^12 pages = 16MB +//! assert_eq!(block.size(), SZ_16M as u64); +//! assert_eq!(allocated.iter().count(), 1); +//! +//! // Dropping the allocation returns the range to the buddy allocator. +//! drop(allocated); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Top-down allocation allocates from the highest addresses: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{GpuBuddy, GpuBuddyAllocMode, GpuBuddyAllocFlags, GpuBuddyParams}, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: Alignment::new::<SZ_4K>(), +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! let topdown = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::TopDown, +//! SZ_16M as u64, +//! Alignment::new::<SZ_16M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let block = topdown.iter().next().expect("expected one block"); +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); +//! assert_eq!(block.order(), 12); +//! assert_eq!(block.size(), SZ_16M as u64); +//! +//! // Dropping the allocation returns the range to the buddy allocator. +//! drop(topdown); +//! assert_eq!(buddy.free_memory(), initial_free); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Non-contiguous allocation can fill fragmented memory by returning multiple +//! blocks: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlags, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! # let buddy = GpuBuddy::new(GpuBuddyParams { +//! # base_offset: 0, +//! # physical_memory_size: SZ_1G as u64, +//! # chunk_size: Alignment::new::<SZ_4K>(), +//! # })?; +//! # let initial_free = buddy.free_memory(); +//! // Create fragmentation by allocating 4MB blocks at [0,4M) and [8M,12M). +//! let frag1 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_4M as u64); +//! +//! let frag2 = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_8M as u64); +//! +//! // Allocate 8MB, this returns 2 blocks from the holes. +//! let fragmented = KBox::pin_init( +//! buddy.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_16M as u64 }, +//! SZ_8M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! assert_eq!(buddy.free_memory(), initial_free - SZ_16M as u64); +//! +//! let (mut count, mut total) = (0u32, 0u64); +//! for block in fragmented.iter() { +//! assert_eq!(block.size(), SZ_4M as u64); +//! total += block.size(); +//! count += 1; +//! } +//! assert_eq!(total, SZ_8M as u64); +//! assert_eq!(count, 2); +//! # Ok::<(), Error>(()) +//! ``` +//! +//! Contiguous allocation fails when only fragmented space is available: +//! +//! ``` +//! # use kernel::{ +//! # gpu::buddy::{ +//! # GpuBuddy, GpuBuddyAllocFlag, GpuBuddyAllocFlags, GpuBuddyAllocMode, GpuBuddyParams, +//! # }, +//! # prelude::*, +//! # ptr::Alignment, +//! # sizes::*, // +//! # }; +//! // Create a small 16MB buddy allocator with fragmented memory. +//! let small = GpuBuddy::new(GpuBuddyParams { +//! base_offset: 0, +//! physical_memory_size: SZ_16M as u64, +//! chunk_size: Alignment::new::<SZ_4K>(), +//! })?; +//! +//! let _hole1 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { start: 0, end: SZ_4M as u64 }, +//! SZ_4M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! let _hole2 = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Range { +//! start: SZ_8M as u64, +//! end: (SZ_8M + SZ_4M) as u64, +//! }, +//! SZ_4M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlags::default(), +//! ), +//! GFP_KERNEL, +//! )?; +//! +//! // 8MB contiguous should fail, only two non-contiguous 4MB holes exist. +//! let result = KBox::pin_init( +//! small.alloc_blocks( +//! GpuBuddyAllocMode::Simple, +//! SZ_8M as u64, +//! Alignment::new::<SZ_4M>(), +//! GpuBuddyAllocFlag::Contiguous, +//! ), +//! GFP_KERNEL, +//! ); +//! assert!(result.is_err()); +//! # Ok::<(), Error>(()) +//! ``` + +use crate::{ + bindings, + clist_create, + error::to_result, + interop::list::CListHead, + new_mutex, + prelude::*, + ptr::Alignment, + sync::{ + lock::mutex::MutexGuard, + Arc, + Mutex, // + }, + types::Opaque, // +}; + +/// Allocation mode for the GPU buddy allocator. +/// +/// The mode determines the primary allocation strategy. Modes are mutually +/// exclusive: an allocation is either simple, range-constrained, or top-down. +/// +/// Orthogonal modifier flags (e.g., contiguous, clear) are specified separately +/// via [`GpuBuddyAllocFlags`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum GpuBuddyAllocMode { + /// Simple allocation without constraints. + Simple, + /// Range-based allocation between `start` and `end` addresses. + Range { + /// Start of the allocation range. + start: u64, + /// End of the allocation range. + end: u64, + }, + /// Allocate from top of address space downward. + TopDown, +} + +impl GpuBuddyAllocMode { + // Returns the C flags corresponding to the allocation mode. + fn into_flags(self) -> usize { + match self { + Self::Simple => 0, + Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION, + Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION, + } + } + + // Extracts the range start/end, defaulting to (0, 0) for non-range modes. + fn range(self) -> (u64, u64) { + match self { + Self::Range { start, end } => (start, end), + _ => (0, 0), + } + } +} + +crate::impl_flags!( + /// Modifier flags for GPU buddy allocation. + /// + /// These flags can be combined with any [`GpuBuddyAllocMode`] to control + /// additional allocation behavior. + #[derive(Clone, Copy, Default, PartialEq, Eq)] + pub struct GpuBuddyAllocFlags(u32); + + /// Individual modifier flag for GPU buddy allocation. + #[derive(Clone, Copy, PartialEq, Eq)] + pub enum GpuBuddyAllocFlag { + /// Allocate physically contiguous blocks. + Contiguous = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION as u32, + + /// Request allocation from cleared (zeroed) memory. + Clear = bindings::GPU_BUDDY_CLEAR_ALLOCATION as u32, + + /// Disable trimming of partially used blocks. + TrimDisable = bindings::GPU_BUDDY_TRIM_DISABLE as u32, + } +); + +/// Parameters for creating a GPU buddy allocator. +pub struct GpuBuddyParams { + /// Base offset (in bytes) where the managed memory region starts. + /// Allocations will be offset by this value. + pub base_offset: u64, + /// Total physical memory size (in bytes) managed by the allocator. + pub physical_memory_size: u64, + /// Minimum allocation unit / chunk size, must be >= 4KB. + pub chunk_size: Alignment, +} + +/// Inner structure holding the actual buddy allocator. +/// +/// # Synchronization +/// +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). +/// Internal locking ensures all allocator and free operations are properly +/// synchronized, preventing races between concurrent allocations and the +/// freeing that occurs when [`AllocatedBlocks`] is dropped. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains an initialized buddy allocator. +#[pin_data(PinnedDrop)] +struct GpuBuddyInner { + #[pin] + inner: Opaque<bindings::gpu_buddy>, + + // TODO: Replace `Mutex<()>` with `Mutex<Opaque<..>>` once `Mutex::new()` + // accepts `impl PinInit<T>`. + #[pin] + lock: Mutex<()>, + /// Cached creation parameters (do not change after init). + params: GpuBuddyParams, +} + +impl GpuBuddyInner { + /// Create a pin-initializer for the buddy allocator. + fn new(params: GpuBuddyParams) -> impl PinInit<Self, Error> { + let size = params.physical_memory_size; + let chunk_size = params.chunk_size; + + // INVARIANT: `gpu_buddy_init` returns 0 on success, at which point the + // `gpu_buddy` structure is initialized and ready for use with all + // `gpu_buddy_*` APIs. `try_pin_init!` only completes if all fields succeed, + // so the invariant holds when construction finishes. + try_pin_init!(Self { + inner <- Opaque::try_ffi_init(|ptr| { + // SAFETY: `ptr` points to valid uninitialized memory from the pin-init + // infrastructure. `gpu_buddy_init` will initialize the structure. + to_result(unsafe { bindings::gpu_buddy_init(ptr, size, chunk_size.as_usize() as u64) }) + }), + lock <- new_mutex!(()), + params, + }) + } + + /// Lock the mutex and return a guard for accessing the allocator. + fn lock(&self) -> GpuBuddyGuard<'_> { + GpuBuddyGuard { + inner: self, + _guard: self.lock.lock(), + } + } +} + +#[pinned_drop] +impl PinnedDrop for GpuBuddyInner { + fn drop(self: Pin<&mut Self>) { + let guard = self.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + unsafe { + bindings::gpu_buddy_fini(guard.as_raw()); + } + } +} + +// SAFETY: `GpuBuddyInner` can be sent between threads. +unsafe impl Send for GpuBuddyInner {} + +// SAFETY: `GpuBuddyInner` is `Sync` because `GpuBuddyInner::lock` +// serializes all access to the C allocator, preventing data races. +unsafe impl Sync for GpuBuddyInner {} + +// Guard that proves the lock is held, enabling access to the allocator. +// The `_guard` holds the lock for the duration of this guard's lifetime. +struct GpuBuddyGuard<'a> { + inner: &'a GpuBuddyInner, + _guard: MutexGuard<'a, ()>, +} + +impl GpuBuddyGuard<'_> { + /// Get a raw pointer to the underlying C `gpu_buddy` structure. + fn as_raw(&self) -> *mut bindings::gpu_buddy { + self.inner.inner.get() + } +} + +/// GPU buddy allocator instance. +/// +/// This structure wraps the C `gpu_buddy` allocator using reference counting. +/// The allocator is automatically cleaned up when all references are dropped. +/// +/// Refer to the module-level documentation for usage examples. +pub struct GpuBuddy(Arc<GpuBuddyInner>); + +impl GpuBuddy { + /// Create a new buddy allocator. + /// + /// Creates a buddy allocator that manages a contiguous address space of the given + /// size, with the specified minimum allocation unit (chunk_size must be at least 4KB). + pub fn new(params: GpuBuddyParams) -> Result<Self> { + Arc::pin_init(GpuBuddyInner::new(params), GFP_KERNEL).map(Self) + } + + /// Get the base offset for allocations. + pub fn base_offset(&self) -> u64 { + self.0.params.base_offset + } + + /// Get the chunk size (minimum allocation unit). + pub fn chunk_size(&self) -> Alignment { + self.0.params.chunk_size + } + + /// Get the total managed size. + pub fn size(&self) -> u64 { + self.0.params.physical_memory_size + } + + /// Get the available (free) memory in bytes. + pub fn free_memory(&self) -> u64 { + let guard = self.0.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized allocator. + // `guard` provides exclusive access. + unsafe { (*guard.as_raw()).avail } + } + + /// Allocate blocks from the buddy allocator. + /// + /// Returns a pin-initializer for [`AllocatedBlocks`]. + pub fn alloc_blocks( + &self, + mode: GpuBuddyAllocMode, + size: u64, + min_block_size: Alignment, + flags: impl Into<GpuBuddyAllocFlags>, + ) -> impl PinInit<AllocatedBlocks, Error> { + let buddy_arc = Arc::clone(&self.0); + let (start, end) = mode.range(); + let mode_flags = mode.into_flags(); + let modifier_flags = u32::from(flags.into()) as usize; + + // Create pin-initializer that initializes list and allocates blocks. + try_pin_init!(AllocatedBlocks { + buddy: buddy_arc, + list <- CListHead::new(), + _: { + // Reject zero-sized or inverted ranges. + if let GpuBuddyAllocMode::Range { start, end } = mode { + if end <= start { + Err::<(), Error>(EINVAL)?; + } + } + + // Lock while allocating to serialize with concurrent frees. + let guard = buddy.lock(); + + // SAFETY: Per the type invariant, `inner` contains an initialized + // allocator. `guard` provides exclusive access. + to_result(unsafe { + bindings::gpu_buddy_alloc_blocks( + guard.as_raw(), + start, + end, + size, + min_block_size.as_usize() as u64, + list.as_raw(), + mode_flags | modifier_flags, + ) + })? + } + }) + } +} + +/// Allocated blocks from the buddy allocator with automatic cleanup. +/// +/// This structure owns a list of allocated blocks and ensures they are +/// automatically freed when dropped. Use `iter()` to iterate over all +/// allocated blocks. +/// +/// # Invariants +/// +/// - `list` is an initialized, valid list head containing allocated blocks. +#[pin_data(PinnedDrop)] +pub struct AllocatedBlocks { + #[pin] + list: CListHead, + buddy: Arc<GpuBuddyInner>, +} + +impl AllocatedBlocks { + /// Check if the block list is empty. + pub fn is_empty(&self) -> bool { + // An empty list head points to itself. + !self.list.is_linked() + } + + /// Iterate over allocated blocks. + /// + /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`] + /// borrows `self` and is only valid for the duration of that borrow. + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { + // SAFETY: + // - Per the type invariant, `list` is an initialized sentinel `list_head` + // and is not concurrently modified (we hold a `&self` borrow). + // - The list contains `gpu_buddy_block` items linked via + // `__bindgen_anon_1.link`. + // - `Block` is `#[repr(transparent)]` over `gpu_buddy_block`. + let head = self.list.as_raw(); + let clist = clist_create!(unsafe { + head, + Block, + bindings::gpu_buddy_block, + __bindgen_anon_1.link + }); + + clist + .iter() + .map(|this| AllocatedBlock { this, blocks: self }) + } +} + +#[pinned_drop] +impl PinnedDrop for AllocatedBlocks { + fn drop(self: Pin<&mut Self>) { + let guard = self.buddy.lock(); + + // SAFETY: + // - list is valid per the type's invariants. + // - guard provides exclusive access to the allocator. + unsafe { + bindings::gpu_buddy_free_list(guard.as_raw(), self.list.as_raw(), 0); + } + } +} + +/// A GPU buddy block. +/// +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned +/// as references during iteration over [`AllocatedBlocks`]. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`. +#[repr(transparent)] +struct Block(Opaque<bindings::gpu_buddy_block>); + +impl Block { + /// Get a raw pointer to the underlying C block. + fn as_raw(&self) -> *mut bindings::gpu_buddy_block { + self.0.get() + } + + /// Get the block's raw offset in the buddy address space (without base offset). + fn offset(&self) -> u64 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } + } + + /// Get the block order. + fn order(&self) -> u32 { + // SAFETY: `self.as_raw()` is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } + } +} + +// SAFETY: `Block` is a wrapper around `gpu_buddy_block` which can be +// sent across threads safely. +unsafe impl Send for Block {} + +// SAFETY: `Block` is only accessed through shared references after +// allocation, and thus safe to access concurrently across threads. +unsafe impl Sync for Block {} + +/// A buddy block paired with its owning [`AllocatedBlocks`] context. +/// +/// Unlike a raw block, which only knows its offset within the buddy address +/// space, an [`AllocatedBlock`] also has access to the allocator's `base_offset` +/// and `chunk_size`, enabling it to compute absolute offsets and byte sizes. +/// +/// Returned by [`AllocatedBlocks::iter()`]. +pub struct AllocatedBlock<'a> { + this: &'a Block, + blocks: &'a AllocatedBlocks, +} + +impl AllocatedBlock<'_> { + /// Get the block's offset in the address space. + /// + /// Returns the absolute offset including the allocator's base offset. + /// This is the actual address to use for accessing the allocated memory. + pub fn offset(&self) -> u64 { + self.blocks.buddy.params.base_offset + self.this.offset() + } + + /// Get the block order (size = chunk_size << order). + pub fn order(&self) -> u32 { + self.this.order() + } + + /// Get the block's size in bytes. + pub fn size(&self) -> u64 { + (self.blocks.buddy.params.chunk_size.as_usize() as u64) << self.this.order() + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index bdcf632050ee..2652933e585f 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -102,6 +102,8 @@ pub mod firmware; pub mod fmt; pub mod fs; +#[cfg(CONFIG_GPU_BUDDY = "y")] +pub mod gpu; #[cfg(CONFIG_I2C = "y")] pub mod i2c; pub mod id_pool; -- 2.34.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v13 1/2] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 22:03 ` [PATCH v13 1/2] rust: gpu: Add " Joel Fernandes @ 2026-03-18 18:41 ` Joel Fernandes 2026-03-19 12:49 ` Alexandre Courbot 1 sibling, 0 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-18 18:41 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/17/2026 6:03 PM, Joel Fernandes wrote: > +impl AllocatedBlocks { > + /// Check if the block list is empty. > + pub fn is_empty(&self) -> bool { > + // An empty list head points to itself. > + !self.list.is_linked() > + } > + > + /// Iterate over allocated blocks. > + /// > + /// Returns an iterator yielding [`AllocatedBlock`] values. Each [`AllocatedBlock`] > + /// borrows `self` and is only valid for the duration of that borrow. > + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { > + // SAFETY: > + // - Per the type invariant, `list` is an initialized sentinel `list_head` Sorry that there is a clippy error here, this SAFETY needs to be SAFETY* per: https://lore.kernel.org/all/CANiq72kEnDyUpnWMZmheJytjioeiJUK_C-yQJk77dPid89LExw@mail.gmail.com/ https://lore.kernel.org/all/71b6a115-98f1-4b09-9c04-a99349f51e49@nvidia.com/ here is a fixup: https://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git/commit/?h=nova/mm&id=8ee92de5549324cba602c0e7a491596056f55153 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v13 1/2] rust: gpu: Add GPU buddy allocator bindings 2026-03-17 22:03 ` [PATCH v13 1/2] rust: gpu: Add " Joel Fernandes 2026-03-18 18:41 ` Joel Fernandes @ 2026-03-19 12:49 ` Alexandre Courbot 1 sibling, 0 replies; 24+ messages in thread From: Alexandre Courbot @ 2026-03-19 12:49 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev Hi Joel, On Wed Mar 18, 2026 at 7:03 AM JST, Joel Fernandes wrote: > Add safe Rust abstractions over the Linux kernel's GPU buddy > allocator for physical memory management. The GPU buddy allocator > implements a binary buddy system useful for GPU physical memory > allocation. nova-core will use it for physical memory allocation. > > Cc: Nikola Djukic <ndjukic@nvidia.com> > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> A few things came to mind when re-reading this again. I believe these will be my final comments on this patch though (famous last words). <snip> > +//! # Examples > +//! > +//! Create a buddy allocator and perform a basic range allocation: > +//! > +//! ``` > +//! use kernel::{ > +//! gpu::buddy::{ > +//! GpuBuddy, > +//! GpuBuddyAllocFlags, > +//! GpuBuddyAllocMode, > +//! GpuBuddyParams, // > +//! }, > +//! prelude::*, > +//! ptr::Alignment, > +//! sizes::*, // > +//! }; > +//! > +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. > +//! let buddy = GpuBuddy::new(GpuBuddyParams { > +//! base_offset: 0, > +//! physical_memory_size: SZ_1G as u64, > +//! chunk_size: Alignment::new::<SZ_4K>(), > +//! })?; > +//! > +//! assert_eq!(buddy.size(), SZ_1G as u64); > +//! assert_eq!(buddy.chunk_size(), Alignment::new::<SZ_4K>()); Note that you can also use assert_eq!(buddy.chunk_size().as_usize(), SZ_4K); To avoid the `Alignment` constructor. <snip> > +impl GpuBuddyAllocMode { > + // Returns the C flags corresponding to the allocation mode. > + fn into_flags(self) -> usize { > + match self { > + Self::Simple => 0, > + Self::Range { .. } => bindings::GPU_BUDDY_RANGE_ALLOCATION, > + Self::TopDown => bindings::GPU_BUDDY_TOPDOWN_ALLOCATION, > + } > + } > + > + // Extracts the range start/end, defaulting to (0, 0) for non-range modes. Let's use `(0, 0)` so they are properly formatted (I know it's not a doccomment, but the convention also applies to regular comments). > + fn range(self) -> (u64, u64) { > + match self { > + Self::Range { start, end } => (start, end), > + _ => (0, 0), > + } > + } > +} > + > +crate::impl_flags!( > + /// Modifier flags for GPU buddy allocation. > + /// > + /// These flags can be combined with any [`GpuBuddyAllocMode`] to control > + /// additional allocation behavior. > + #[derive(Clone, Copy, Default, PartialEq, Eq)] > + pub struct GpuBuddyAllocFlags(u32); I've realized a bit late that this should actually be `GpuBuddyAllocFlags(usize)`. The values are defined in the bindings as `usize`, and we convert them to `u32`, only to convert them back into `usize` in `alloc_blocks`. I know it goes against the idea that flags should not have a size dependent on the architecture, but in this case it's just a consequence of the C API not doing it - and in the end we have to conform, so there is no point in resisting. Actually, `GpuBuddyAllocMode::into_flags` already return a `usize`, so we're already halfway there. Just going with the flow and using `usize` removes quite a few `as` in the code. Ideally we would fix the C API and switch back to `u32` in the near future but for now that's the best course of action imho. I've checked whether it worked, and it does - here is a diff for reference: https://github.com/Gnurou/linux/commit/2e1bfc2d8e1f93a76343c7c563b1f4b85a69ab8b <snip> > + /// Get the base offset for allocations. > + pub fn base_offset(&self) -> u64 { > + self.0.params.base_offset > + } > + > + /// Get the chunk size (minimum allocation unit). > + pub fn chunk_size(&self) -> Alignment { > + self.0.params.chunk_size > + } > + > + /// Get the total managed size. > + pub fn size(&self) -> u64 { > + self.0.params.physical_memory_size > + } > + > + /// Get the available (free) memory in bytes. > + pub fn free_memory(&self) -> u64 { This name is a bit confusing as it can be interpreted as this method frees memory, whereas it doesn't free anything, and doesn't even deal with memory (but an address space that may or may not represent memory). In the C `struct gpu_buddy`, the member representing the chunk size is named `chunk_size`, and the total size `size`, making the two methods above this one adopt the same name (by a happy coincidence maybe :)). Let's do the same here - since we are querying `avail`, this method can just be called `avail` to align with the C API. In the same spirit, we should rename `GpuBuddyParams::physical_memory_size` into just `size` because that's the name of the corresponding field in `struct gpu_buddy` and again, we are not limited to managing physical memory with this allocator. > + let guard = self.0.lock(); > + > + // SAFETY: Per the type invariant, `inner` contains an initialized allocator. > + // `guard` provides exclusive access. > + unsafe { (*guard.as_raw()).avail } > + } > + > + /// Allocate blocks from the buddy allocator. > + /// > + /// Returns a pin-initializer for [`AllocatedBlocks`]. > + pub fn alloc_blocks( > + &self, > + mode: GpuBuddyAllocMode, > + size: u64, > + min_block_size: Alignment, > + flags: impl Into<GpuBuddyAllocFlags>, > + ) -> impl PinInit<AllocatedBlocks, Error> { > + let buddy_arc = Arc::clone(&self.0); > + let (start, end) = mode.range(); > + let mode_flags = mode.into_flags(); > + let modifier_flags = u32::from(flags.into()) as usize; > + > + // Create pin-initializer that initializes list and allocates blocks. > + try_pin_init!(AllocatedBlocks { > + buddy: buddy_arc, > + list <- CListHead::new(), > + _: { > + // Reject zero-sized or inverted ranges. > + if let GpuBuddyAllocMode::Range { start, end } = mode { > + if end <= start { > + Err::<(), Error>(EINVAL)?; > + } > + } Ah, indeed we want to disallow decreasing ranges. Actually, why not prevent them from even being expressed by using an actual Rust `Range`? This lets you turn this test into an `is_empty()` and removes 10 LoCs overall. You lose the ability to copy `GpuBuddyAllocMode`, but we don't need it in the first place. Here is a diff showing what it looks like, feel free to pick it: https://github.com/Gnurou/linux/commit/7f9348f6a64d0fbec7ddf99b78ca727a1ac1cd06 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer 2026-03-17 22:03 ` [PATCH v13 0/2] Rust " Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 1/2] rust: gpu: Add " Joel Fernandes @ 2026-03-17 22:03 ` Joel Fernandes 2026-03-18 9:15 ` Matthew Auld 2026-03-18 9:35 ` Christian König 1 sibling, 2 replies; 24+ messages in thread From: Joel Fernandes @ 2026-03-17 22:03 UTC (permalink / raw) To: linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Christian Koenig mentioned he'd like to step down from the reviewer role for the GPU buddy allocator. Joel Fernandes is stepping in as reviewer with agreement from Matthew Auld and Arun Pravin. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index cd9505d3be60..3353cbf98be1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8946,7 +8946,7 @@ F: include/drm/ttm/ GPU BUDDY ALLOCATOR M: Matthew Auld <matthew.auld@intel.com> M: Arun Pravin <arunpravin.paneerselvam@amd.com> -R: Christian Koenig <christian.koenig@amd.com> +R: Joel Fernandes <joelagnelf@nvidia.com> L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git -- 2.34.1 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer 2026-03-17 22:03 ` [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer Joel Fernandes @ 2026-03-18 9:15 ` Matthew Auld 2026-03-18 9:35 ` Christian König 1 sibling, 0 replies; 24+ messages in thread From: Matthew Auld @ 2026-03-18 9:15 UTC (permalink / raw) To: Joel Fernandes, linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 17/03/2026 22:03, Joel Fernandes wrote: > Christian Koenig mentioned he'd like to step down from the reviewer > role for the GPU buddy allocator. Joel Fernandes is stepping in as > reviewer with agreement from Matthew Auld and Arun Pravin. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> Acked-by: Matthew Auld <matthew.auld@intel.com> > --- > MAINTAINERS | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index cd9505d3be60..3353cbf98be1 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8946,7 +8946,7 @@ F: include/drm/ttm/ > GPU BUDDY ALLOCATOR > M: Matthew Auld <matthew.auld@intel.com> > M: Arun Pravin <arunpravin.paneerselvam@amd.com> > -R: Christian Koenig <christian.koenig@amd.com> > +R: Joel Fernandes <joelagnelf@nvidia.com> > L: dri-devel@lists.freedesktop.org > S: Maintained > T: git https://gitlab.freedesktop.org/drm/misc/kernel.git ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer 2026-03-17 22:03 ` [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer Joel Fernandes 2026-03-18 9:15 ` Matthew Auld @ 2026-03-18 9:35 ` Christian König 1 sibling, 0 replies; 24+ messages in thread From: Christian König @ 2026-03-18 9:35 UTC (permalink / raw) To: Joel Fernandes, linux-kernel Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich, Dave Airlie, Daniel Almeida, Koen Koning, dri-devel, rust-for-linux, Nikola Djukic, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alex Gaynor, Boqun Feng, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, alexeyi, Eliot Courtney, joel, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 3/17/26 23:03, Joel Fernandes wrote: > Christian Koenig mentioned he'd like to step down from the reviewer > role for the GPU buddy allocator. Joel Fernandes is stepping in as > reviewer with agreement from Matthew Auld and Arun Pravin. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> Acked-by: Christian König <christian.koenig@amd.com> > --- > MAINTAINERS | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index cd9505d3be60..3353cbf98be1 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8946,7 +8946,7 @@ F: include/drm/ttm/ > GPU BUDDY ALLOCATOR > M: Matthew Auld <matthew.auld@intel.com> > M: Arun Pravin <arunpravin.paneerselvam@amd.com> > -R: Christian Koenig <christian.koenig@amd.com> > +R: Joel Fernandes <joelagnelf@nvidia.com> > L: dri-devel@lists.freedesktop.org > S: Maintained > T: git https://gitlab.freedesktop.org/drm/misc/kernel.git ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2026-03-19 12:49 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-08 18:04 [PATCH v12 0/1] Rust GPU buddy allocator bindings Joel Fernandes 2026-03-08 18:04 ` [PATCH v12 1/1] rust: gpu: Add " Joel Fernandes 2026-03-09 13:53 ` [PATCH v12.1 0/1] Rust " Joel Fernandes 2026-03-09 13:53 ` [PATCH v12.1 1/1] rust: gpu: Add " Joel Fernandes 2026-03-12 17:45 ` Danilo Krummrich 2026-03-16 17:29 ` Joel Fernandes 2026-03-16 13:12 ` Alexandre Courbot 2026-03-16 18:43 ` Joel Fernandes 2026-03-17 0:58 ` Alexandre Courbot 2026-03-17 18:49 ` Joel Fernandes 2026-03-16 18:51 ` John Hubbard 2026-03-16 21:00 ` Joel Fernandes 2026-03-16 22:08 ` John Hubbard 2026-03-17 1:02 ` Alexandre Courbot 2026-03-17 1:10 ` John Hubbard 2026-03-17 1:58 ` Alexandre Courbot 2026-03-17 18:44 ` Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 0/2] Rust " Joel Fernandes 2026-03-17 22:03 ` [PATCH v13 1/2] rust: gpu: Add " Joel Fernandes 2026-03-18 18:41 ` Joel Fernandes 2026-03-19 12:49 ` Alexandre Courbot 2026-03-17 22:03 ` [PATCH v13 2/2] MAINTAINERS: gpu: buddy: Update reviewer Joel Fernandes 2026-03-18 9:15 ` Matthew Auld 2026-03-18 9:35 ` Christian König
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox