There will be multiple functions that will store into XArray. It's not ideal to duplicate this check in all of them. Moving it into the constructor function will remove the need for duplication. Signed-off-by: Onur Özkan --- rust/kernel/xarray.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index a49d6db28845..90e27cd5197e 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -87,6 +87,12 @@ pub enum AllocKind { impl XArray { /// Creates a new initializer for this type. pub fn new(kind: AllocKind) -> impl PinInit { + // Ensure pointers stored in XArray are suitably aligned. + build_assert!( + T::FOREIGN_ALIGN >= 4, + "pointers stored in XArray must be 4-byte aligned" + ); + let flags = match kind { AllocKind::Alloc => bindings::XA_FLAGS_ALLOC, AllocKind::Alloc1 => bindings::XA_FLAGS_ALLOC1, @@ -230,10 +236,6 @@ pub fn store( value: T, gfp: alloc::Flags, ) -> Result, StoreError> { - build_assert!( - T::FOREIGN_ALIGN >= 4, - "pointers stored in XArray must be 4-byte aligned" - ); let new = value.into_foreign(); let old = { -- 2.51.0 Implements `alloc` function to `XArray` that wraps `xa_alloc` safely, which will be used to generate the auxiliary device IDs. Resolves a task from the nova/core task list under the "XArray bindings [XARR]" section in "Documentation/gpu/nova/core/todo.rst" file. Signed-off-by: Onur Özkan --- rust/kernel/xarray.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 90e27cd5197e..0711ccf99fb4 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -10,7 +10,7 @@ ffi::c_void, types::{ForeignOwnable, NotThreadSafe, Opaque}, }; -use core::{iter, marker::PhantomData, pin::Pin, ptr::NonNull}; +use core::{iter, marker::PhantomData, ops::Range, pin::Pin, ptr::NonNull}; use pin_init::{pin_data, pin_init, pinned_drop, PinInit}; /// An array which efficiently maps sparse integer indices to owned objects. @@ -268,6 +268,45 @@ pub fn store( Ok(unsafe { T::try_from_foreign(old) }) } } + + /// Allocates an empty slot within the given `limit` and stores `value` there. + /// + /// May drop the lock if needed to allocate memory, and then reacquire it afterwards. + /// + /// On success, returns the allocated index. + /// + /// On failure, returns the element which was attempted to be stored. + pub fn alloc( + &mut self, + limit: Range, + value: T, + gfp: alloc::Flags, + ) -> Result> { + let new = value.into_foreign(); + let mut id: u32 = 0; + + let limit = bindings::xa_limit { + min: limit.start, + max: limit.end, + }; + + // SAFETY: + // - `self.xa.xa` is valid by the type invariant. + // - `new` came from `T::into_foreign`. + let ret = + unsafe { bindings::__xa_alloc(self.xa.xa.get(), &mut id, new, limit, gfp.as_raw()) }; + + if ret < 0 { + // SAFETY: `__xa_alloc` doesn't take ownership on error. + let value = unsafe { T::from_foreign(new) }; + return Err(StoreError { + value, + error: Error::from_errno(ret), + }); + } + + Ok(id) + } } // SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T` is `Send`. -- 2.51.0 Implements `alloc_cyclic` function to `XArray` that wraps `xa_alloc_cyclic` safely, which will be used to generate the auxiliary device IDs. Resolves a task from the nova/core task list under the "XArray bindings [XARR]" section in "Documentation/gpu/nova/core/todo.rst" file. Signed-off-by: Onur Özkan --- rust/kernel/xarray.rs | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 0711ccf99fb4..8ac7210afd6b 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -307,6 +307,56 @@ pub fn alloc( Ok(id) } + + /// Allocates an empty slot within the given `limit`, storing `value` and cycling from `*next`. + /// + /// May drop the lock if needed to allocate memory, and then reacquire it afterwards. + /// + /// On success, returns the allocated index and the next pointer respectively. + /// + /// On failure, returns the element which was attempted to be stored. + pub fn alloc_cyclic( + &mut self, + limit: Range, + mut next: u32, + value: T, + gfp: alloc::Flags, + ) -> Result<(u32, u32), StoreError> { + let new = value.into_foreign(); + + let limit = bindings::xa_limit { + min: limit.start, + max: limit.end, + }; + + // `__xa_alloc_cyclic` overwrites this. + let mut id: u32 = 0; + + // SAFETY: + // - `self.xa.xa` is valid by the type invariant. + // - `new` came from `T::into_foreign`. + let ret = unsafe { + bindings::__xa_alloc_cyclic( + self.xa.xa.get(), + &mut id, + new, + limit, + &mut next, + gfp.as_raw(), + ) + }; + + if ret < 0 { + // SAFETY: `__xa_alloc_cyclic` doesn't take ownership on error. + let value = unsafe { T::from_foreign(new) }; + return Err(StoreError { + value, + error: Error::from_errno(ret), + }); + } + + Ok((id, next)) + } } // SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T` is `Send`. -- 2.51.0 The task is completed in this series. Signed-off-by: Onur Özkan --- Documentation/gpu/nova/core/todo.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Documentation/gpu/nova/core/todo.rst b/Documentation/gpu/nova/core/todo.rst index 0972cb905f7a..de70a857fcfd 100644 --- a/Documentation/gpu/nova/core/todo.rst +++ b/Documentation/gpu/nova/core/todo.rst @@ -210,14 +210,6 @@ capability, MSI API abstractions. | Complexity: Beginner -XArray bindings [XARR] ----------------------- - -We need bindings for `xa_alloc`/`xa_alloc_cyclic` in order to generate the -auxiliary device IDs. - -| Complexity: Intermediate - Debugfs abstractions -------------------- -- 2.51.0