@@ -472,6 +472,8 @@ static int mlx5_init_context(struct verbs_device *vdev,
off_t offset;
struct mlx5_device *mdev;
struct verbs_context *v_ctx;
+ struct ibv_device_attr attr;
+ int err;
mdev = to_mdev(&vdev->device);
v_ctx = verbs_get_ctx(ctx);
@@ -585,6 +587,12 @@ static int mlx5_init_context(struct verbs_device *vdev,
verbs_set_ctx_op(v_ctx, get_srq_num, mlx5_get_srq_num);
verbs_set_ctx_op(v_ctx, query_device_ex, mlx5_query_device_ex);
+ err = mlx5_query_device(ctx, &attr);
+ if (err)
+ goto err_free_bf;
+
+ context->atomic_cap = attr.atomic_cap;
+
return 0;
err_free_bf:
@@ -282,6 +282,7 @@ struct mlx5_context {
char hostname[40];
struct mlx5_spinlock hugetlb_lock;
struct list_head hugetlb_list;
+ enum ibv_atomic_cap atomic_cap;
};
struct mlx5_bitmap {
@@ -405,6 +406,7 @@ struct mlx5_qp {
uint32_t *db;
struct mlx5_wq rq;
int wq_sig;
+ int atomics_enabled;
};
struct mlx5_av {
@@ -180,6 +180,20 @@ static inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
rseg->reserved = 0;
}
+static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg,
+ enum ibv_wr_opcode opcode,
+ uint64_t swap,
+ uint64_t compare_add)
+{
+ if (opcode == IBV_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = htonll(swap);
+ aseg->compare = htonll(compare_add);
+ } else {
+ aseg->swap_add = htonll(compare_add);
+ aseg->compare = 0;
+ }
+}
+
static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
struct ibv_send_wr *wr)
{
@@ -336,6 +350,7 @@ int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
void *qend = qp->sq.qend;
uint32_t mlx5_opcode;
struct mlx5_wqe_xrc_seg *xrc;
+ int atom_arg = 0;
#ifdef MLX5_DEBUG
FILE *fp = to_mctx(ibqp->context)->dbg_fp;
#endif
@@ -405,10 +420,25 @@ int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
case IBV_WR_ATOMIC_CMP_AND_SWP:
case IBV_WR_ATOMIC_FETCH_AND_ADD:
- fprintf(stderr, "atomic operations are not supported yet\n");
- err = ENOSYS;
- *bad_wr = wr;
- goto out;
+ if (unlikely(!qp->atomics_enabled)) {
+ mlx5_dbg(fp, MLX5_DBG_QP_SEND, "atomic operations are not supported\n");
+ err = ENOSYS;
+ *bad_wr = wr;
+ goto out;
+ }
+ set_raddr_seg(seg, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
+ seg += sizeof(struct mlx5_wqe_raddr_seg);
+
+ set_atomic_seg(seg, wr->opcode,
+ wr->wr.atomic.swap,
+ wr->wr.atomic.compare_add);
+ seg += sizeof(struct mlx5_wqe_atomic_seg);
+
+ size += (sizeof(struct mlx5_wqe_raddr_seg) +
+ sizeof(struct mlx5_wqe_atomic_seg)) / 16;
+ atom_arg = 8;
+ break;
default:
break;
@@ -462,7 +492,17 @@ int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
dpseg = seg;
}
if (likely(wr->sg_list[i].length)) {
- set_data_ptr_seg(dpseg, wr->sg_list + i);
+ struct ibv_sge sge;
+ struct ibv_sge *psge;
+
+ if (unlikely(atom_arg)) {
+ sge = wr->sg_list[i];
+ sge.length = atom_arg;
+ psge = &sge;
+ } else {
+ psge = wr->sg_list + i;
+ }
+ set_data_ptr_seg(dpseg, psge);
++dpseg;
size += sizeof(struct mlx5_wqe_data_seg) / 16;
}
@@ -1001,6 +1001,8 @@ struct ibv_qp *create_qp(struct ibv_context *context,
qp->db[MLX5_RCV_DBR] = 0;
qp->db[MLX5_SND_DBR] = 0;
+ if (ctx->atomic_cap == IBV_ATOMIC_HCA)
+ qp->atomics_enabled = 1;
pthread_mutex_lock(&ctx->qp_table_mutex);