diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index e622bf3beab42d..e49c2170601298 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -76,6 +76,7 @@ pub mod task; pub mod workqueue; pub mod linked_list; +#[cfg(CONFIG_MLX4_EN)] pub mod mlx4; mod raw_list; pub mod rbtree; diff --git a/rust/kernel/mlx4.rs b/rust/kernel/mlx4.rs index a4fd26a37b4dbd..7f53e0e9e670bc 100644 --- a/rust/kernel/mlx4.rs +++ b/rust/kernel/mlx4.rs @@ -1,42 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Infiniband mlx4 devices. +//! + use alloc::boxed::Box; -use cm::CmWorkQueue; use core::pin::Pin; -use core::{cell::UnsafeCell, marker, ptr}; +use core::{marker, ptr}; use macros::vtable; -use mcg::McgWorkQueue; -use qp::QpWorkQueue; -use crate::error::{code::*, Error, Result}; +use crate::bindings; +use crate::error::{code::*, Result}; use crate::str::CStr; use crate::workqueue::{BoxedQueue, Queue}; -use crate::{bindings, pr_info}; -mod cm; -mod mcg; -mod qp; - -/// Soft RDMA transport registration. +/// Infiband mlx4 device registration. /// pub struct Registration { registered: bool, + #[allow(dead_code)] name: &'static CStr, - wq: Mlx4WorkQueue, cm_wq: CmWorkQueue, qp_wq: QpWorkQueue, mcg_wq: McgWorkQueue, phantom: marker::PhantomData, - //rxe_link_ops: bindings::rdma_link_ops, - //再包一层 - //_pin: PhantomPinned, - - // /// Context initialised on construction and made available to all file instances on - // /// [`file::Operations::open`]. - //open_data: MaybeUninit, } impl Registration { + /// Creates a new [`Registration`] but does not register it yet. + /// + /// It is allowed to move. pub fn new(name: &'static CStr) -> Self { + // INVARIANT: `registered` is `false` Self { registered: false, name, @@ -45,18 +40,29 @@ impl Registration { qp_wq: QpWorkQueue::new(), mcg_wq: McgWorkQueue::new(), phantom: marker::PhantomData, - //rxe_link_ops:bindings::rdma_link_ops::default(), } } + /// Registers a infiband mlx4 device. + /// + /// Returns a pinned heap-allocated representation of the registration. pub fn new_pinned(name: &'static CStr) -> Result>> { let mut r = Pin::from(Box::try_new(Self::new(name))?); r.as_mut().register()?; Ok(r) } + // Registers a infiband mlx4 device with the rest of the kernel. + /// + /// It must be pinned because the memory block that represents the registration is + /// self-referential. pub fn register(self: Pin<&mut Self>) -> Result { + // SAFETY: We must ensure that we never move out of `this`. let this = unsafe { self.get_unchecked_mut() }; + if this.registered { + // Already registered. + return Err(EINVAL); + } match this.wq.init() { Ok(()) => {} @@ -90,8 +96,7 @@ impl Registration { } } - // interface用vtable替换掉 - + // SAFETY: The adapter is compatible with the mlx4 register unsafe { bindings::mlx4_register_interface(Mlx4OperationTable::::build()); } @@ -102,9 +107,9 @@ impl Registration { } impl Drop for Registration { + /// Removes the registration from the kernel if it has completed successfully before. fn drop(&mut self) { if self.registered { - //unsafe{bindings::mlx4_unregister_interface();} self.mcg_wq.clean(); self.cm_wq.clean(); self.qp_wq.clean(); @@ -113,9 +118,15 @@ impl Drop for Registration { } } +/// Build kernel's `struct mlx4_interface` type with mlx4 device operation. pub struct Mlx4OperationTable(marker::PhantomData); impl Mlx4OperationTable { + /// Builds an instance of [`struct mlx4_interface`]. + /// + /// # Safety + /// + /// The caller must ensure that the adapter is compatible with the way the device is registered. pub fn build() -> *mut bindings::mlx4_interface { return &mut bindings::mlx4_interface { add: Some(Self::add_callback), @@ -134,58 +145,39 @@ impl Mlx4OperationTable { }; } - unsafe extern "C" fn add_callback(dev: *mut bindings::mlx4_dev) -> *mut core::ffi::c_void { + unsafe extern "C" fn add_callback(_dev: *mut bindings::mlx4_dev) -> *mut core::ffi::c_void { + let _ = T::add(); return ptr::null_mut(); } unsafe extern "C" fn remove_callback( - dev: *mut bindings::mlx4_dev, - context: *mut core::ffi::c_void, + _dev: *mut bindings::mlx4_dev, + _context: *mut core::ffi::c_void, ) { + let _ = T::remove(); } unsafe extern "C" fn event_callback( - dev: *mut bindings::mlx4_dev, - context: *mut core::ffi::c_void, - event: bindings::mlx4_dev_event, - param: core::ffi::c_ulong, + _dev: *mut bindings::mlx4_dev, + _context: *mut core::ffi::c_void, + _event: bindings::mlx4_dev_event, + _param: core::ffi::c_ulong, ) { + let _ = T::event(); } - - // unsafe extern "C" fn get_dev_callback( - // dev: *mut mlx4_dev, - // context: *mut core::ffi::c_void, - // port: u8_, - // ) -> *mut core::ffi::c_void { - // } - - // unsafe extern "C" fn activate_callback( - // dev: *mut mlx4_dev, - // context: *mut core::ffi::c_void - // ) { - // } - - // MLX4FUNC:bindings::mlx4_interface=bindings::mlx4_interface { - // add:Some(Self::add_callback), - // remove:Some(Self::remove_callback), - // event:Some(Self::event_callback), - // get_dev:None, - // activate:None, - // list:bindings::list_head{next:ptr::null_mut(),prev:ptr::null_mut()}, - // // MLX4_PROT_IB_IPV6 - // protocol:0, - // // MLX4_INTFF_BONDING - // flags:1, - // }; } +/// Corresponds to the kernel's `struct mlx4_interface`. +/// +/// You implement this trait whenever you would create a `struct mlx4_interface`. #[vtable] pub trait Mlx4Operation { - fn add(); - fn remove(); - fn event(); - // fn get_dev(); - // fn activate(); + /// Add a new mlx4 ib device. + fn add() -> Result; + /// Remove mlx4 ib device. + fn remove() -> Result; + /// Respond to specific mlx4 ib device event + fn event() -> Result; } pub(crate) struct Mlx4WorkQueue { @@ -213,3 +205,84 @@ impl Mlx4WorkQueue { } } } + +pub(crate) struct CmWorkQueue { + cm_wq: Option, +} + +impl CmWorkQueue { + pub(crate) fn new() -> Self { + Self { cm_wq: None } + } + + pub(crate) fn init(&mut self) -> Result { + let cm_wq_tmp = Queue::try_new(format_args!("mlx4_ib_cm"), 0, 0); + self.cm_wq = match cm_wq_tmp { + Ok(cm_wq) => Some(cm_wq), + Err(e) => return Err(e), + }; + + Ok(()) + } + + pub(crate) fn clean(&mut self) { + if self.cm_wq.is_some() { + drop(self.cm_wq.take().unwrap()); + } + } +} + +pub(crate) struct McgWorkQueue { + clean_wq: Option, +} + +impl McgWorkQueue { + pub(crate) fn new() -> Self { + Self { clean_wq: None } + } + + pub(crate) fn init(&mut self) -> Result { + let clean_wq_tmp = Queue::try_new(format_args!("mlx4_ib_mcg"), 655369, 1); + self.clean_wq = match clean_wq_tmp { + Ok(clean_wq) => Some(clean_wq), + Err(e) => return Err(e), + }; + + Ok(()) + } + + pub(crate) fn clean(&mut self) { + if self.clean_wq.is_some() { + drop(self.clean_wq.take().unwrap()); + } + } +} + +pub(crate) struct QpWorkQueue { + mlx4_ib_qp_event_wq: Option, +} + +impl QpWorkQueue { + pub(crate) fn new() -> Self { + Self { + mlx4_ib_qp_event_wq: None, + } + } + + pub(crate) fn init(&mut self) -> Result { + let mlx4_ib_qp_event_wq_tmp = + Queue::try_new(format_args!("mlx4_ib_qp_event_wq"), 655361, 1); + self.mlx4_ib_qp_event_wq = match mlx4_ib_qp_event_wq_tmp { + Ok(mlx4_ib_qp_event_wq) => Some(mlx4_ib_qp_event_wq), + Err(e) => return Err(e), + }; + + Ok(()) + } + + pub(crate) fn clean(&mut self) { + if self.mlx4_ib_qp_event_wq.is_some() { + drop(self.mlx4_ib_qp_event_wq.take().unwrap()); + } + } +} diff --git a/rust/kernel/mlx4/cm.rs b/rust/kernel/mlx4/cm.rs deleted file mode 100644 index 72d90356f3face..00000000000000 --- a/rust/kernel/mlx4/cm.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::error::{code::*, Error, Result}; -use crate::workqueue::{BoxedQueue, Queue}; -use core::ptr; - -pub(crate) struct CmWorkQueue { - cm_wq: Option, -} - -impl CmWorkQueue { - pub(crate) fn new() -> Self { - Self { cm_wq: None } - } - - pub(crate) fn init(&mut self) -> Result { - let cm_wq_tmp = Queue::try_new(format_args!("mlx4_ib_cm"), 0, 0); - self.cm_wq = match cm_wq_tmp { - Ok(cm_wq) => Some(cm_wq), - Err(e) => return Err(e), - }; - - Ok(()) - } - - pub(crate) fn clean(&mut self) { - if self.cm_wq.is_some() { - drop(self.cm_wq.take().unwrap()); - } - } -} diff --git a/rust/kernel/mlx4/mcg.rs b/rust/kernel/mlx4/mcg.rs deleted file mode 100644 index d3e0bfbe2f9c23..00000000000000 --- a/rust/kernel/mlx4/mcg.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::error::{code::*, Error, Result}; -use crate::workqueue::{BoxedQueue, Queue}; -use core::ptr; - -pub(crate) struct McgWorkQueue { - clean_wq: Option, -} - -impl McgWorkQueue { - pub(crate) fn new() -> Self { - Self { clean_wq: None } - } - - pub(crate) fn init(&mut self) -> Result { - let clean_wq_tmp = Queue::try_new(format_args!("mlx4_ib_mcg"), 655369, 1); - self.clean_wq = match clean_wq_tmp { - Ok(clean_wq) => Some(clean_wq), - Err(e) => return Err(e), - }; - - Ok(()) - } - - pub(crate) fn clean(&mut self) { - if self.clean_wq.is_some() { - drop(self.clean_wq.take().unwrap()); - } - } -} diff --git a/rust/kernel/mlx4/qp.rs b/rust/kernel/mlx4/qp.rs deleted file mode 100644 index bbcb4b30b54854..00000000000000 --- a/rust/kernel/mlx4/qp.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::error::{code::*, Error, Result}; -use crate::workqueue::{BoxedQueue, Queue}; -use core::ptr; - -pub(crate) struct QpWorkQueue { - mlx4_ib_qp_event_wq: Option, -} - -impl QpWorkQueue { - pub(crate) fn new() -> Self { - Self { - mlx4_ib_qp_event_wq: None, - } - } - - pub(crate) fn init(&mut self) -> Result { - let mlx4_ib_qp_event_wq_tmp = - Queue::try_new(format_args!("mlx4_ib_qp_event_wq"), 655361, 1); - self.mlx4_ib_qp_event_wq = match mlx4_ib_qp_event_wq_tmp { - Ok(mlx4_ib_qp_event_wq) => Some(mlx4_ib_qp_event_wq), - Err(e) => return Err(e), - }; - - Ok(()) - } - - pub(crate) fn clean(&mut self) { - if self.mlx4_ib_qp_event_wq.is_some() { - drop(self.mlx4_ib_qp_event_wq.take().unwrap()); - } - } -} diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 74ccb85797b363..fa289af097b1a7 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -408,6 +408,9 @@ pub struct BoxedQueue { ptr: NonNull, } +// SAFETY: Kernel workqueues are usable from any thread. +unsafe impl Sync for BoxedQueue {} + impl BoxedQueue { /// Creates a new instance of [`BoxedQueue`]. ///