Skip to main content

rdmaxcel_sys/
lib.rs

1/*
2 * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9// sections of code adapted from https://github.com/jonhoo/rust-ibverbs
10// Copyright (c) 2016 Jon Gjengset under MIT License (MIT)
11
12mod inner {
13    #![allow(non_upper_case_globals)]
14    #![allow(non_camel_case_types)]
15    #![allow(non_snake_case)]
16    #![allow(unused_attributes)]
17    #[cfg(not(cargo))]
18    use crate::ibv_wc_flags;
19    #[cfg(not(cargo))]
20    use crate::ibv_wc_opcode;
21    #[cfg(not(cargo))]
22    use crate::ibv_wc_status;
23    #[cfg(cargo)]
24    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
25
26    // ROCm/HIP compatibility layer
27    //
28    // In ROCm builds, bindgen generates HIP types and constants instead of CUDA equivalents.
29    // These type aliases and const aliases allow Rust code to use CUDA names consistently
30    // across both CUDA and ROCm backends, avoiding the need for conditional compilation
31    // throughout the codebase.
32    #[cfg(use_rocm)]
33    pub use self::rocm_compat::*;
34
35    #[cfg(use_rocm)]
36    mod rocm_compat {
37        use super::*;
38
39        // Basic types
40        pub type CUdevice = hipDevice_t;
41        pub type CUdeviceptr = hipDeviceptr_t;
42        pub type CUcontext = hipCtx_t;
43
44        // Memory management types
45        pub type CUmemGenericAllocationHandle = hipMemGenericAllocationHandle_t;
46        pub type CUmemAllocationProp = hipMemAllocationProp;
47        pub type CUmemAccessDesc = hipMemAccessDesc;
48
49        // Error codes
50        pub type CUresult = hipError_t;
51        pub const CUDA_SUCCESS: hipError_t = hipSuccess;
52        pub const CUDA_ERROR_NOT_INITIALIZED: hipError_t = hipErrorNotInitialized;
53
54        // Pointer attributes
55        pub const CU_POINTER_ATTRIBUTE_MEMORY_TYPE: hipPointer_attribute =
56            HIP_POINTER_ATTRIBUTE_MEMORY_TYPE;
57        pub const CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL: hipPointer_attribute =
58            HIP_POINTER_ATTRIBUTE_DEVICE_ORDINAL;
59        pub const CU_POINTER_ATTRIBUTE_CONTEXT: hipPointer_attribute =
60            HIP_POINTER_ATTRIBUTE_CONTEXT;
61
62        // Device attributes
63        pub type CUdevice_attribute = hipDeviceAttribute_t;
64        pub const CU_DEVICE_ATTRIBUTE_PCI_BUS_ID: hipDeviceAttribute_t = hipDeviceAttributePciBusId;
65        pub const CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID: hipDeviceAttribute_t =
66            hipDeviceAttributePciDeviceId;
67        pub const CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID: hipDeviceAttribute_t =
68            hipDeviceAttributePciDomainId;
69
70        // Memory types
71        pub const CU_MEMORYTYPE_DEVICE: u32 = 2; // hipMemoryTypeDevice = 2
72
73        // Memory handle types
74        pub const CU_MEM_RANGE_HANDLE_TYPE_DMA_BUF_FD: hipMemRangeHandleType =
75            hipMemRangeHandleTypeDmaBufFd;
76        pub const CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR: hipMemAllocationHandleType =
77            hipMemHandleTypePosixFileDescriptor;
78
79        // Memory allocation flags
80        pub const CU_MEM_ALLOCATION_TYPE_PINNED: hipMemAllocationType = hipMemAllocationTypePinned;
81        pub const CU_MEM_LOCATION_TYPE_DEVICE: hipMemLocationType = hipMemLocationTypeDevice;
82        pub const CU_MEM_ALLOC_GRANULARITY_MINIMUM: hipMemAllocationGranularity_flags =
83            hipMemAllocationGranularityMinimum;
84        pub const CU_MEM_ACCESS_FLAGS_PROT_READWRITE: hipMemAccessFlags =
85            hipMemAccessFlagsProtReadWrite;
86    }
87
88    #[repr(C, packed(1))]
89    #[derive(Debug, Default, Clone, Copy)]
90    pub struct mlx5_wqe_ctrl_seg {
91        pub opmod_idx_opcode: u32,
92        pub qpn_ds: u32,
93        pub signature: u8,
94        pub dci_stream_channel_id: u16,
95        pub fm_ce_se: u8,
96        pub imm: u32,
97    }
98
99    #[repr(C)]
100    #[derive(Debug, Copy, Clone)]
101    pub struct ibv_wc {
102        wr_id: u64,
103        status: ibv_wc_status::Type,
104        opcode: ibv_wc_opcode::Type,
105        vendor_err: u32,
106        byte_len: u32,
107
108        /// Immediate data OR the local RKey that was invalidated depending on `wc_flags`.
109        /// See `man ibv_poll_cq` for details.
110        pub imm_data: u32,
111        /// Local QP number of completed WR.
112        ///
113        /// Relevant for Receive Work Completions that are associated with an SRQ.
114        pub qp_num: u32,
115        /// Source QP number (remote QP number) of completed WR.
116        ///
117        /// Relevant for Receive Work Completions of a UD QP.
118        pub src_qp: u32,
119        /// Flags of the Work Completion. It is either 0 or the bitwise OR of one or more of the
120        /// following flags:
121        ///
122        ///  - `IBV_WC_GRH`: Indicator that GRH is present for a Receive Work Completions of a UD QP.
123        ///    If this bit is set, the first 40 bytes of the buffered that were referred to in the
124        ///    Receive request will contain the GRH of the incoming message. If this bit is cleared,
125        ///    the content of those first 40 bytes is undefined
126        ///  - `IBV_WC_WITH_IMM`: Indicator that imm_data is valid. Relevant for Receive Work
127        ///    Completions
128        pub wc_flags: ibv_wc_flags,
129        /// P_Key index (valid only for GSI QPs).
130        pub pkey_index: u16,
131        /// Source LID (the base LID that this message was sent from).
132        ///
133        /// Relevant for Receive Work Completions of a UD QP.
134        pub slid: u16,
135        /// Service Level (the SL LID that this message was sent with).
136        ///
137        /// Relevant for Receive Work Completions of a UD QP.
138        pub sl: u8,
139        /// Destination LID path bits.
140        ///
141        /// Relevant for Receive Work Completions of a UD QP (not applicable for multicast messages).
142        pub dlid_path_bits: u8,
143    }
144
145    #[allow(clippy::len_without_is_empty)]
146    impl ibv_wc {
147        /// Returns the 64 bit value that was associated with the corresponding Work Request.
148        pub fn wr_id(&self) -> u64 {
149            self.wr_id
150        }
151
152        /// Returns the number of bytes transferred.
153        ///
154        /// Relevant if the Receive Queue for incoming Send or RDMA Write with immediate operations.
155        /// This value doesn't include the length of the immediate data, if such exists. Relevant in
156        /// the Send Queue for RDMA Read and Atomic operations.
157        ///
158        /// For the Receive Queue of a UD QP that is not associated with an SRQ or for an SRQ that is
159        /// associated with a UD QP this value equals to the payload of the message plus the 40 bytes
160        /// reserved for the GRH. The number of bytes transferred is the payload of the message plus
161        /// the 40 bytes reserved for the GRH, whether or not the GRH is present
162        pub fn len(&self) -> usize {
163            self.byte_len as usize
164        }
165
166        /// Check if this work requested completed successfully.
167        ///
168        /// A successful work completion (`IBV_WC_SUCCESS`) means that the corresponding Work Request
169        /// (and all of the unsignaled Work Requests that were posted previous to it) ended, and the
170        /// memory buffers that this Work Request refers to are ready to be (re)used.
171        pub fn is_valid(&self) -> bool {
172            self.status == ibv_wc_status::IBV_WC_SUCCESS
173        }
174
175        /// Returns the work completion status and vendor error syndrome (`vendor_err`) if the work
176        /// request did not completed successfully.
177        ///
178        /// Possible statuses include:
179        ///
180        ///  - `IBV_WC_LOC_LEN_ERR`: Local Length Error: this happens if a Work Request that was posted
181        ///    in a local Send Queue contains a message that is greater than the maximum message size
182        ///    that is supported by the RDMA device port that should send the message or an Atomic
183        ///    operation which its size is different than 8 bytes was sent. This also may happen if a
184        ///    Work Request that was posted in a local Receive Queue isn't big enough for holding the
185        ///    incoming message or if the incoming message size if greater the maximum message size
186        ///    supported by the RDMA device port that received the message.
187        ///  - `IBV_WC_LOC_QP_OP_ERR`: Local QP Operation Error: an internal QP consistency error was
188        ///    detected while processing this Work Request: this happens if a Work Request that was
189        ///    posted in a local Send Queue of a UD QP contains an Address Handle that is associated
190        ///    with a Protection Domain to a QP which is associated with a different Protection Domain
191        ///    or an opcode which isn't supported by the transport type of the QP isn't supported (for
192        ///    example:
193        ///    RDMA Write over a UD QP).
194        ///  - `IBV_WC_LOC_EEC_OP_ERR`: Local EE Context Operation Error: an internal EE Context
195        ///    consistency error was detected while processing this Work Request (unused, since its
196        ///    relevant only to RD QPs or EE Context, which aren’t supported).
197        ///  - `IBV_WC_LOC_PROT_ERR`: Local Protection Error: the locally posted Work Request’s buffers
198        ///    in the scatter/gather list does not reference a Memory Region that is valid for the
199        ///    requested operation.
200        ///  - `IBV_WC_WR_FLUSH_ERR`: Work Request Flushed Error: A Work Request was in process or
201        ///    outstanding when the QP transitioned into the Error State.
202        ///  - `IBV_WC_MW_BIND_ERR`: Memory Window Binding Error: A failure happened when tried to bind
203        ///    a MW to a MR.
204        ///  - `IBV_WC_BAD_RESP_ERR`: Bad Response Error: an unexpected transport layer opcode was
205        ///    returned by the responder. Relevant for RC QPs.
206        ///  - `IBV_WC_LOC_ACCESS_ERR`: Local Access Error: a protection error occurred on a local data
207        ///    buffer during the processing of a RDMA Write with Immediate operation sent from the
208        ///    remote node. Relevant for RC QPs.
209        ///  - `IBV_WC_REM_INV_REQ_ERR`: Remote Invalid Request Error: The responder detected an
210        ///    invalid message on the channel. Possible causes include the operation is not supported
211        ///    by this receive queue (qp_access_flags in remote QP wasn't configured to support this
212        ///    operation), insufficient buffering to receive a new RDMA or Atomic Operation request, or
213        ///    the length specified in a RDMA request is greater than 2^{31} bytes. Relevant for RC
214        ///    QPs.
215        ///  - `IBV_WC_REM_ACCESS_ERR`: Remote Access Error: a protection error occurred on a remote
216        ///    data buffer to be read by an RDMA Read, written by an RDMA Write or accessed by an
217        ///    atomic operation. This error is reported only on RDMA operations or atomic operations.
218        ///    Relevant for RC QPs.
219        ///  - `IBV_WC_REM_OP_ERR`: Remote Operation Error: the operation could not be completed
220        ///    successfully by the responder. Possible causes include a responder QP related error that
221        ///    prevented the responder from completing the request or a malformed WQE on the Receive
222        ///    Queue. Relevant for RC QPs.
223        ///  - `IBV_WC_RETRY_EXC_ERR`: Transport Retry Counter Exceeded: The local transport timeout
224        ///    retry counter was exceeded while trying to send this message. This means that the remote
225        ///    side didn't send any Ack or Nack. If this happens when sending the first message,
226        ///    usually this mean that the connection attributes are wrong or the remote side isn't in a
227        ///    state that it can respond to messages. If this happens after sending the first message,
228        ///    usually it means that the remote QP isn't available anymore. Relevant for RC QPs.
229        ///  - `IBV_WC_RNR_RETRY_EXC_ERR`: RNR Retry Counter Exceeded: The RNR NAK retry count was
230        ///    exceeded. This usually means that the remote side didn't post any WR to its Receive
231        ///    Queue. Relevant for RC QPs.
232        ///  - `IBV_WC_LOC_RDD_VIOL_ERR`: Local RDD Violation Error: The RDD associated with the QP
233        ///    does not match the RDD associated with the EE Context (unused, since its relevant only
234        ///    to RD QPs or EE Context, which aren't supported).
235        ///  - `IBV_WC_REM_INV_RD_REQ_ERR`: Remote Invalid RD Request: The responder detected an
236        ///    invalid incoming RD message. Causes include a Q_Key or RDD violation (unused, since its
237        ///    relevant only to RD QPs or EE Context, which aren't supported)
238        ///  - `IBV_WC_REM_ABORT_ERR`: Remote Aborted Error: For UD or UC QPs associated with a SRQ,
239        ///    the responder aborted the operation.
240        ///  - `IBV_WC_INV_EECN_ERR`: Invalid EE Context Number: An invalid EE Context number was
241        ///    detected (unused, since its relevant only to RD QPs or EE Context, which aren't
242        ///    supported).
243        ///  - `IBV_WC_INV_EEC_STATE_ERR`: Invalid EE Context State Error: Operation is not legal for
244        ///    the specified EE Context state (unused, since its relevant only to RD QPs or EE Context,
245        ///    which aren't supported).
246        ///  - `IBV_WC_FATAL_ERR`: Fatal Error.
247        ///  - `IBV_WC_RESP_TIMEOUT_ERR`: Response Timeout Error.
248        ///  - `IBV_WC_GENERAL_ERR`: General Error: other error which isn't one of the above errors.
249        pub fn error(&self) -> Option<(ibv_wc_status::Type, u32)> {
250            match self.status {
251                ibv_wc_status::IBV_WC_SUCCESS => None,
252                status => Some((status, self.vendor_err)),
253            }
254        }
255
256        /// Returns the operation that the corresponding Work Request performed.
257        ///
258        /// This value controls the way that data was sent, the direction of the data flow and the
259        /// valid attributes in the Work Completion.
260        pub fn opcode(&self) -> ibv_wc_opcode::Type {
261            self.opcode
262        }
263
264        /// Returns a 32 bits number, in network order, in an SEND or RDMA WRITE opcodes that is being
265        /// sent along with the payload to the remote side and placed in a Receive Work Completion and
266        /// not in a remote memory buffer
267        ///
268        /// Note that IMM is only returned if `IBV_WC_WITH_IMM` is set in `wc_flags`. If this is not
269        /// the case, no immediate value was provided, and `imm_data` should be interpreted
270        /// differently. See `man ibv_poll_cq` for details.
271        pub fn imm_data(&self) -> Option<u32> {
272            if self.is_valid() && ((self.wc_flags & ibv_wc_flags::IBV_WC_WITH_IMM).0 != 0) {
273                Some(self.imm_data)
274            } else {
275                None
276            }
277        }
278    }
279
280    impl Default for ibv_wc {
281        fn default() -> Self {
282            ibv_wc {
283                wr_id: 0,
284                status: ibv_wc_status::IBV_WC_GENERAL_ERR,
285                opcode: ibv_wc_opcode::IBV_WC_LOCAL_INV,
286                vendor_err: 0,
287                byte_len: 0,
288                imm_data: 0,
289                qp_num: 0,
290                src_qp: 0,
291                wc_flags: ibv_wc_flags(0),
292                pkey_index: 0,
293                slid: 0,
294                sl: 0,
295                dlid_path_bits: 0,
296            }
297        }
298    }
299}
300
301pub use inner::*;
302
303// Segment scanner callback type - type alias for the bindgen-generated type
304pub type RdmaxcelSegmentScannerFn = rdmaxcel_segment_scanner_fn;
305
306// Additional extern "C" declarations for functions that are also auto-generated by bindgen.
307// These provide a place for doc comments and explicit signatures.
308unsafe extern "C" {
309    pub fn rdmaxcel_error_string(error_code: std::os::raw::c_int) -> *const std::os::raw::c_char;
310
311    /// Get PCI address from a CUDA/HIP device pointer
312    ///
313    /// In CUDA builds, cuda_ptr is CUdeviceptr (u64).
314    /// In ROCm builds, cuda_ptr is CUdeviceptr (aliased to hipDeviceptr_t = void*).
315    pub fn get_cuda_pci_address_from_ptr(
316        cuda_ptr: CUdeviceptr,
317        pci_addr_out: *mut std::os::raw::c_char,
318        pci_addr_size: usize,
319    ) -> std::os::raw::c_int;
320
321    /// Debug: Print comprehensive device attributes
322    pub fn rdmaxcel_print_device_info(context: *mut ibv_context);
323
324    // EFA functions
325
326    /// Check if the device is an EFA device (via efadv_query_device)
327    pub fn rdmaxcel_is_efa_dev(ctx: *mut ibv_context) -> std::os::raw::c_int;
328
329    /// EFA connect: INIT->RTR->RTS + AH creation, stored directly in qp struct
330    pub fn rdmaxcel_efa_connect(
331        qp: *mut rdmaxcel_qp_t,
332        port_num: u8,
333        pkey_index: u16,
334        qkey: u32,
335        psn: u32,
336        gid_index: u8,
337        remote_gid: *const u8,
338        remote_qpn: u32,
339    ) -> std::os::raw::c_int;
340
341    /// EFA post operation with ibv_post_recv fallback
342    /// op_type: 0 = write, 1 = read, 2 = recv, 3 = write_with_imm
343    pub fn rdmaxcel_qp_post_op(
344        qp: *mut rdmaxcel_qp_t,
345        local_addr: *mut std::ffi::c_void,
346        lkey: u32,
347        length: usize,
348        remote_addr: *mut std::ffi::c_void,
349        rkey: u32,
350        wr_id: u64,
351        signaled: std::os::raw::c_int,
352        op_type: std::os::raw::c_int,
353    ) -> std::os::raw::c_int;
354}