Skip to content

Commit d520537

Browse files
committed
rust: add infiniband mlx4 device driver basic version
Trying to add infiniband mlx4 device driver, adding the basic interface. Signed-off-by: Allen Xu <[email protected]>
1 parent 5250b38 commit d520537

File tree

7 files changed

+354
-3
lines changed

7 files changed

+354
-3
lines changed

rust/bindings/bindings_helper.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <linux/sysctl.h>
3737
#include <linux/uaccess.h>
3838
#include <linux/uio.h>
39+
#include <linux/mlx4/driver.h>
3940

4041
/* `bindgen` gets confused at certain things. */
4142
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/kernel/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pub mod task;
7676
pub mod workqueue;
7777

7878
pub mod linked_list;
79+
#[cfg(CONFIG_MLX4_EN)]
80+
pub mod mlx4;
7981
mod raw_list;
8082
pub mod rbtree;
8183
pub mod unsafe_list;

rust/kernel/mlx4.rs

+288
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Infiniband mlx4 devices.
4+
//!
5+
6+
use alloc::boxed::Box;
7+
use core::pin::Pin;
8+
use core::{marker, ptr};
9+
use macros::vtable;
10+
11+
use crate::bindings;
12+
use crate::error::{code::*, Result};
13+
use crate::str::CStr;
14+
use crate::workqueue::{BoxedQueue, Queue};
15+
16+
/// Infiband mlx4 device registration.
17+
///
18+
pub struct Registration<T: Mlx4Operation> {
19+
registered: bool,
20+
#[allow(dead_code)]
21+
name: &'static CStr,
22+
wq: Mlx4WorkQueue,
23+
cm_wq: CmWorkQueue,
24+
qp_wq: QpWorkQueue,
25+
mcg_wq: McgWorkQueue,
26+
phantom: marker::PhantomData<T>,
27+
}
28+
29+
impl<T: Mlx4Operation> Registration<T> {
30+
/// Creates a new [`Registration`] but does not register it yet.
31+
///
32+
/// It is allowed to move.
33+
pub fn new(name: &'static CStr) -> Self {
34+
// INVARIANT: `registered` is `false`
35+
Self {
36+
registered: false,
37+
name,
38+
wq: Mlx4WorkQueue::new(),
39+
cm_wq: CmWorkQueue::new(),
40+
qp_wq: QpWorkQueue::new(),
41+
mcg_wq: McgWorkQueue::new(),
42+
phantom: marker::PhantomData,
43+
}
44+
}
45+
46+
/// Registers a infiband mlx4 device.
47+
///
48+
/// Returns a pinned heap-allocated representation of the registration.
49+
pub fn new_pinned(name: &'static CStr) -> Result<Pin<Box<Self>>> {
50+
let mut r = Pin::from(Box::try_new(Self::new(name))?);
51+
r.as_mut().register()?;
52+
Ok(r)
53+
}
54+
55+
// Registers a infiband mlx4 device with the rest of the kernel.
56+
///
57+
/// It must be pinned because the memory block that represents the registration is
58+
/// self-referential.
59+
pub fn register(self: Pin<&mut Self>) -> Result {
60+
// SAFETY: We must ensure that we never move out of `this`.
61+
let this = unsafe { self.get_unchecked_mut() };
62+
if this.registered {
63+
// Already registered.
64+
return Err(EINVAL);
65+
}
66+
67+
match this.wq.init() {
68+
Ok(()) => {}
69+
Err(e) => return Err(e),
70+
}
71+
72+
match this.qp_wq.init() {
73+
Ok(()) => {}
74+
Err(e) => {
75+
this.wq.clean();
76+
return Err(e);
77+
}
78+
}
79+
80+
match this.cm_wq.init() {
81+
Ok(()) => {}
82+
Err(e) => {
83+
this.wq.clean();
84+
this.qp_wq.clean();
85+
return Err(e);
86+
}
87+
}
88+
89+
match this.mcg_wq.init() {
90+
Ok(()) => {}
91+
Err(e) => {
92+
this.wq.clean();
93+
this.cm_wq.clean();
94+
this.qp_wq.clean();
95+
return Err(e);
96+
}
97+
}
98+
99+
// SAFETY: The adapter is compatible with the mlx4 register
100+
unsafe {
101+
bindings::mlx4_register_interface(Mlx4OperationTable::<T>::build());
102+
}
103+
104+
this.registered = true;
105+
Ok(())
106+
}
107+
}
108+
109+
impl<T: Mlx4Operation> Drop for Registration<T> {
110+
/// Removes the registration from the kernel if it has completed successfully before.
111+
fn drop(&mut self) {
112+
if self.registered {
113+
self.mcg_wq.clean();
114+
self.cm_wq.clean();
115+
self.qp_wq.clean();
116+
self.wq.clean();
117+
}
118+
}
119+
}
120+
121+
/// Build kernel's `struct mlx4_interface` type with mlx4 device operation.
122+
pub struct Mlx4OperationTable<T>(marker::PhantomData<T>);
123+
124+
impl<T: Mlx4Operation> Mlx4OperationTable<T> {
125+
/// Builds an instance of [`struct mlx4_interface`].
126+
///
127+
/// # Safety
128+
///
129+
/// The caller must ensure that the adapter is compatible with the way the device is registered.
130+
pub fn build() -> *mut bindings::mlx4_interface {
131+
return &mut bindings::mlx4_interface {
132+
add: Some(Self::add_callback),
133+
remove: Some(Self::remove_callback),
134+
event: Some(Self::event_callback),
135+
get_dev: None,
136+
activate: None,
137+
list: bindings::list_head {
138+
next: ptr::null_mut(),
139+
prev: ptr::null_mut(),
140+
},
141+
// MLX4_PROT_IB_IPV6
142+
protocol: 0,
143+
// MLX4_INTFF_BONDING
144+
flags: 1,
145+
};
146+
}
147+
148+
unsafe extern "C" fn add_callback(_dev: *mut bindings::mlx4_dev) -> *mut core::ffi::c_void {
149+
let _ = T::add();
150+
return ptr::null_mut();
151+
}
152+
153+
unsafe extern "C" fn remove_callback(
154+
_dev: *mut bindings::mlx4_dev,
155+
_context: *mut core::ffi::c_void,
156+
) {
157+
let _ = T::remove();
158+
}
159+
160+
unsafe extern "C" fn event_callback(
161+
_dev: *mut bindings::mlx4_dev,
162+
_context: *mut core::ffi::c_void,
163+
_event: bindings::mlx4_dev_event,
164+
_param: core::ffi::c_ulong,
165+
) {
166+
let _ = T::event();
167+
}
168+
}
169+
170+
/// Corresponds to the kernel's `struct mlx4_interface`.
171+
///
172+
/// You implement this trait whenever you would create a `struct mlx4_interface`.
173+
#[vtable]
174+
pub trait Mlx4Operation {
175+
/// Add a new mlx4 ib device.
176+
fn add() -> Result;
177+
/// Remove mlx4 ib device.
178+
fn remove() -> Result;
179+
/// Respond to specific mlx4 ib device event
180+
fn event() -> Result;
181+
}
182+
183+
pub(crate) struct Mlx4WorkQueue {
184+
wq: Option<BoxedQueue>,
185+
}
186+
187+
impl Mlx4WorkQueue {
188+
pub(crate) fn new() -> Self {
189+
Self { wq: None }
190+
}
191+
192+
pub(crate) fn init(&mut self) -> Result {
193+
let wq_tmp = Queue::try_new(format_args!("mlx4_ib"), 655369, 1);
194+
self.wq = match wq_tmp {
195+
Ok(wq) => Some(wq),
196+
Err(e) => return Err(e),
197+
};
198+
199+
Ok(())
200+
}
201+
202+
pub(crate) fn clean(&mut self) {
203+
if self.wq.is_some() {
204+
drop(self.wq.take().unwrap());
205+
}
206+
}
207+
}
208+
209+
pub(crate) struct CmWorkQueue {
210+
cm_wq: Option<BoxedQueue>,
211+
}
212+
213+
impl CmWorkQueue {
214+
pub(crate) fn new() -> Self {
215+
Self { cm_wq: None }
216+
}
217+
218+
pub(crate) fn init(&mut self) -> Result {
219+
let cm_wq_tmp = Queue::try_new(format_args!("mlx4_ib_cm"), 0, 0);
220+
self.cm_wq = match cm_wq_tmp {
221+
Ok(cm_wq) => Some(cm_wq),
222+
Err(e) => return Err(e),
223+
};
224+
225+
Ok(())
226+
}
227+
228+
pub(crate) fn clean(&mut self) {
229+
if self.cm_wq.is_some() {
230+
drop(self.cm_wq.take().unwrap());
231+
}
232+
}
233+
}
234+
235+
pub(crate) struct McgWorkQueue {
236+
clean_wq: Option<BoxedQueue>,
237+
}
238+
239+
impl McgWorkQueue {
240+
pub(crate) fn new() -> Self {
241+
Self { clean_wq: None }
242+
}
243+
244+
pub(crate) fn init(&mut self) -> Result {
245+
let clean_wq_tmp = Queue::try_new(format_args!("mlx4_ib_mcg"), 655369, 1);
246+
self.clean_wq = match clean_wq_tmp {
247+
Ok(clean_wq) => Some(clean_wq),
248+
Err(e) => return Err(e),
249+
};
250+
251+
Ok(())
252+
}
253+
254+
pub(crate) fn clean(&mut self) {
255+
if self.clean_wq.is_some() {
256+
drop(self.clean_wq.take().unwrap());
257+
}
258+
}
259+
}
260+
261+
pub(crate) struct QpWorkQueue {
262+
mlx4_ib_qp_event_wq: Option<BoxedQueue>,
263+
}
264+
265+
impl QpWorkQueue {
266+
pub(crate) fn new() -> Self {
267+
Self {
268+
mlx4_ib_qp_event_wq: None,
269+
}
270+
}
271+
272+
pub(crate) fn init(&mut self) -> Result {
273+
let mlx4_ib_qp_event_wq_tmp =
274+
Queue::try_new(format_args!("mlx4_ib_qp_event_wq"), 655361, 1);
275+
self.mlx4_ib_qp_event_wq = match mlx4_ib_qp_event_wq_tmp {
276+
Ok(mlx4_ib_qp_event_wq) => Some(mlx4_ib_qp_event_wq),
277+
Err(e) => return Err(e),
278+
};
279+
280+
Ok(())
281+
}
282+
283+
pub(crate) fn clean(&mut self) {
284+
if self.mlx4_ib_qp_event_wq.is_some() {
285+
drop(self.mlx4_ib_qp_event_wq.take().unwrap());
286+
}
287+
}
288+
}

rust/kernel/workqueue.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,14 @@ impl Queue {
209209
///
210210
/// Callers should first consider using one of the existing ones (e.g. [`system`]) before
211211
/// deciding to create a new one.
212-
pub fn try_new(name: fmt::Arguments<'_>) -> Result<BoxedQueue> {
212+
pub fn try_new(name: fmt::Arguments<'_>, flags: u32, max_active: i32) -> Result<BoxedQueue> {
213213
// SAFETY: We use a format string that requires an `fmt::Arguments` pointer as the first
214214
// and only argument.
215215
let ptr = unsafe {
216216
bindings::alloc_workqueue(
217217
c_str!("%pA").as_char_ptr(),
218-
0,
219-
0,
218+
flags,
219+
max_active,
220220
&name as *const _ as *const core::ffi::c_void,
221221
)
222222
};
@@ -408,6 +408,9 @@ pub struct BoxedQueue {
408408
ptr: NonNull<Queue>,
409409
}
410410

411+
// SAFETY: Kernel workqueues are usable from any thread.
412+
unsafe impl Sync for BoxedQueue {}
413+
411414
impl BoxedQueue {
412415
/// Creates a new instance of [`BoxedQueue`].
413416
///

samples/rust/Kconfig

+7
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,11 @@ config SAMPLE_RUST_SELFTESTS
163163

164164
If unsure, say N.
165165

166+
config SAMPLE_RUST_MLX4
167+
tristate "infiniband mlx4"
168+
help
169+
This option builds the infiniband mlx4 driver cases for Rust.
170+
171+
If unsure, say N.
172+
166173
endif # SAMPLES_RUST

samples/rust/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ obj-$(CONFIG_SAMPLE_RUST_NETFILTER) += rust_netfilter.o
1515
obj-$(CONFIG_SAMPLE_RUST_ECHO_SERVER) += rust_echo_server.o
1616
obj-$(CONFIG_SAMPLE_RUST_FS) += rust_fs.o
1717
obj-$(CONFIG_SAMPLE_RUST_SELFTESTS) += rust_selftests.o
18+
obj-$(CONFIG_SAMPLE_RUST_MLX4) += rust_mlx4.o
1819

1920
subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs

0 commit comments

Comments
 (0)