1*d6b92ffaSHans Petter Selasky /* 2*d6b92ffaSHans Petter Selasky * Copyright (c) 2012 Mellanox Technologies, Inc. All rights reserved. 3*d6b92ffaSHans Petter Selasky * 4*d6b92ffaSHans Petter Selasky * This software is available to you under a choice of one of two 5*d6b92ffaSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU 6*d6b92ffaSHans Petter Selasky * General Public License (GPL) Version 2, available from the file 7*d6b92ffaSHans Petter Selasky * COPYING in the main directory of this source tree, or the 8*d6b92ffaSHans Petter Selasky * OpenIB.org BSD license below: 9*d6b92ffaSHans Petter Selasky * 10*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or 11*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following 12*d6b92ffaSHans Petter Selasky * conditions are met: 13*d6b92ffaSHans Petter Selasky * 14*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above 15*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following 16*d6b92ffaSHans Petter Selasky * disclaimer. 17*d6b92ffaSHans Petter Selasky * 18*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above 19*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following 20*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials 21*d6b92ffaSHans Petter Selasky * provided with the distribution. 22*d6b92ffaSHans Petter Selasky * 23*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30*d6b92ffaSHans Petter Selasky * SOFTWARE. 31*d6b92ffaSHans Petter Selasky */ 32*d6b92ffaSHans Petter Selasky 33*d6b92ffaSHans Petter Selasky #include <config.h> 34*d6b92ffaSHans Petter Selasky 35*d6b92ffaSHans Petter Selasky #include <stdlib.h> 36*d6b92ffaSHans Petter Selasky #include <pthread.h> 37*d6b92ffaSHans Petter Selasky #include <string.h> 38*d6b92ffaSHans Petter Selasky #include <errno.h> 39*d6b92ffaSHans Petter Selasky #include <stdio.h> 40*d6b92ffaSHans Petter Selasky 41*d6b92ffaSHans Petter Selasky #include "mlx5.h" 42*d6b92ffaSHans Petter Selasky #include "doorbell.h" 43*d6b92ffaSHans Petter Selasky #include "wqe.h" 44*d6b92ffaSHans Petter Selasky 45*d6b92ffaSHans Petter Selasky #define MLX5_ATOMIC_SIZE 8 46*d6b92ffaSHans Petter Selasky 47*d6b92ffaSHans Petter Selasky static const uint32_t mlx5_ib_opcode[] = { 48*d6b92ffaSHans Petter Selasky [IBV_WR_SEND] = MLX5_OPCODE_SEND, 49*d6b92ffaSHans Petter Selasky [IBV_WR_SEND_WITH_INV] = MLX5_OPCODE_SEND_INVAL, 50*d6b92ffaSHans Petter Selasky [IBV_WR_SEND_WITH_IMM] = MLX5_OPCODE_SEND_IMM, 51*d6b92ffaSHans Petter Selasky [IBV_WR_RDMA_WRITE] = MLX5_OPCODE_RDMA_WRITE, 52*d6b92ffaSHans Petter Selasky [IBV_WR_RDMA_WRITE_WITH_IMM] = MLX5_OPCODE_RDMA_WRITE_IMM, 53*d6b92ffaSHans Petter Selasky [IBV_WR_RDMA_READ] = MLX5_OPCODE_RDMA_READ, 54*d6b92ffaSHans Petter Selasky [IBV_WR_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_CS, 55*d6b92ffaSHans Petter Selasky [IBV_WR_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_FA, 56*d6b92ffaSHans Petter Selasky [IBV_WR_BIND_MW] = MLX5_OPCODE_UMR, 57*d6b92ffaSHans Petter Selasky [IBV_WR_LOCAL_INV] = MLX5_OPCODE_UMR, 58*d6b92ffaSHans Petter Selasky [IBV_WR_TSO] = MLX5_OPCODE_TSO, 59*d6b92ffaSHans Petter Selasky }; 60*d6b92ffaSHans Petter Selasky 61*d6b92ffaSHans Petter Selasky static void *get_recv_wqe(struct mlx5_qp *qp, int n) 62*d6b92ffaSHans Petter Selasky { 63*d6b92ffaSHans Petter Selasky return qp->buf.buf + qp->rq.offset + (n << qp->rq.wqe_shift); 64*d6b92ffaSHans Petter Selasky } 65*d6b92ffaSHans Petter Selasky 66*d6b92ffaSHans Petter Selasky static void *get_wq_recv_wqe(struct mlx5_rwq *rwq, int n) 67*d6b92ffaSHans Petter Selasky { 68*d6b92ffaSHans Petter Selasky return rwq->pbuff + (n << rwq->rq.wqe_shift); 69*d6b92ffaSHans Petter Selasky } 70*d6b92ffaSHans Petter Selasky 71*d6b92ffaSHans Petter Selasky static int copy_to_scat(struct mlx5_wqe_data_seg *scat, void *buf, int *size, 72*d6b92ffaSHans Petter Selasky int max) 73*d6b92ffaSHans Petter Selasky { 74*d6b92ffaSHans Petter Selasky int copy; 75*d6b92ffaSHans Petter Selasky int i; 76*d6b92ffaSHans Petter Selasky 77*d6b92ffaSHans Petter Selasky if (unlikely(!(*size))) 78*d6b92ffaSHans Petter Selasky return IBV_WC_SUCCESS; 79*d6b92ffaSHans Petter Selasky 80*d6b92ffaSHans Petter Selasky for (i = 0; i < max; ++i) { 81*d6b92ffaSHans Petter Selasky copy = min_t(long, *size, be32toh(scat->byte_count)); 82*d6b92ffaSHans Petter Selasky memcpy((void *)(unsigned long)be64toh(scat->addr), buf, copy); 83*d6b92ffaSHans Petter Selasky *size -= copy; 84*d6b92ffaSHans Petter Selasky if (*size == 0) 85*d6b92ffaSHans Petter Selasky return IBV_WC_SUCCESS; 86*d6b92ffaSHans Petter Selasky 87*d6b92ffaSHans Petter Selasky buf += copy; 88*d6b92ffaSHans Petter Selasky ++scat; 89*d6b92ffaSHans Petter Selasky } 90*d6b92ffaSHans Petter Selasky return IBV_WC_LOC_LEN_ERR; 91*d6b92ffaSHans Petter Selasky } 92*d6b92ffaSHans Petter Selasky 93*d6b92ffaSHans Petter Selasky int mlx5_copy_to_recv_wqe(struct mlx5_qp *qp, int idx, void *buf, int size) 94*d6b92ffaSHans Petter Selasky { 95*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *scat; 96*d6b92ffaSHans Petter Selasky int max = 1 << (qp->rq.wqe_shift - 4); 97*d6b92ffaSHans Petter Selasky 98*d6b92ffaSHans Petter Selasky scat = get_recv_wqe(qp, idx); 99*d6b92ffaSHans Petter Selasky if (unlikely(qp->wq_sig)) 100*d6b92ffaSHans Petter Selasky ++scat; 101*d6b92ffaSHans Petter Selasky 102*d6b92ffaSHans Petter Selasky return copy_to_scat(scat, buf, &size, max); 103*d6b92ffaSHans Petter Selasky } 104*d6b92ffaSHans Petter Selasky 105*d6b92ffaSHans Petter Selasky int mlx5_copy_to_send_wqe(struct mlx5_qp *qp, int idx, void *buf, int size) 106*d6b92ffaSHans Petter Selasky { 107*d6b92ffaSHans Petter Selasky struct mlx5_wqe_ctrl_seg *ctrl; 108*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *scat; 109*d6b92ffaSHans Petter Selasky void *p; 110*d6b92ffaSHans Petter Selasky int max; 111*d6b92ffaSHans Petter Selasky 112*d6b92ffaSHans Petter Selasky idx &= (qp->sq.wqe_cnt - 1); 113*d6b92ffaSHans Petter Selasky ctrl = mlx5_get_send_wqe(qp, idx); 114*d6b92ffaSHans Petter Selasky if (qp->ibv_qp->qp_type != IBV_QPT_RC) { 115*d6b92ffaSHans Petter Selasky fprintf(stderr, "scatter to CQE is supported only for RC QPs\n"); 116*d6b92ffaSHans Petter Selasky return IBV_WC_GENERAL_ERR; 117*d6b92ffaSHans Petter Selasky } 118*d6b92ffaSHans Petter Selasky p = ctrl + 1; 119*d6b92ffaSHans Petter Selasky 120*d6b92ffaSHans Petter Selasky switch (be32toh(ctrl->opmod_idx_opcode) & 0xff) { 121*d6b92ffaSHans Petter Selasky case MLX5_OPCODE_RDMA_READ: 122*d6b92ffaSHans Petter Selasky p = p + sizeof(struct mlx5_wqe_raddr_seg); 123*d6b92ffaSHans Petter Selasky break; 124*d6b92ffaSHans Petter Selasky 125*d6b92ffaSHans Petter Selasky case MLX5_OPCODE_ATOMIC_CS: 126*d6b92ffaSHans Petter Selasky case MLX5_OPCODE_ATOMIC_FA: 127*d6b92ffaSHans Petter Selasky p = p + sizeof(struct mlx5_wqe_raddr_seg) + 128*d6b92ffaSHans Petter Selasky sizeof(struct mlx5_wqe_atomic_seg); 129*d6b92ffaSHans Petter Selasky break; 130*d6b92ffaSHans Petter Selasky 131*d6b92ffaSHans Petter Selasky default: 132*d6b92ffaSHans Petter Selasky fprintf(stderr, "scatter to CQE for opcode %d\n", 133*d6b92ffaSHans Petter Selasky be32toh(ctrl->opmod_idx_opcode) & 0xff); 134*d6b92ffaSHans Petter Selasky return IBV_WC_REM_INV_REQ_ERR; 135*d6b92ffaSHans Petter Selasky } 136*d6b92ffaSHans Petter Selasky 137*d6b92ffaSHans Petter Selasky scat = p; 138*d6b92ffaSHans Petter Selasky max = (be32toh(ctrl->qpn_ds) & 0x3F) - (((void *)scat - (void *)ctrl) >> 4); 139*d6b92ffaSHans Petter Selasky if (unlikely((void *)(scat + max) > qp->sq.qend)) { 140*d6b92ffaSHans Petter Selasky int tmp = ((void *)qp->sq.qend - (void *)scat) >> 4; 141*d6b92ffaSHans Petter Selasky int orig_size = size; 142*d6b92ffaSHans Petter Selasky 143*d6b92ffaSHans Petter Selasky if (copy_to_scat(scat, buf, &size, tmp) == IBV_WC_SUCCESS) 144*d6b92ffaSHans Petter Selasky return IBV_WC_SUCCESS; 145*d6b92ffaSHans Petter Selasky max = max - tmp; 146*d6b92ffaSHans Petter Selasky buf += orig_size - size; 147*d6b92ffaSHans Petter Selasky scat = mlx5_get_send_wqe(qp, 0); 148*d6b92ffaSHans Petter Selasky } 149*d6b92ffaSHans Petter Selasky 150*d6b92ffaSHans Petter Selasky return copy_to_scat(scat, buf, &size, max); 151*d6b92ffaSHans Petter Selasky } 152*d6b92ffaSHans Petter Selasky 153*d6b92ffaSHans Petter Selasky void *mlx5_get_send_wqe(struct mlx5_qp *qp, int n) 154*d6b92ffaSHans Petter Selasky { 155*d6b92ffaSHans Petter Selasky return qp->sq_start + (n << MLX5_SEND_WQE_SHIFT); 156*d6b92ffaSHans Petter Selasky } 157*d6b92ffaSHans Petter Selasky 158*d6b92ffaSHans Petter Selasky void mlx5_init_rwq_indices(struct mlx5_rwq *rwq) 159*d6b92ffaSHans Petter Selasky { 160*d6b92ffaSHans Petter Selasky rwq->rq.head = 0; 161*d6b92ffaSHans Petter Selasky rwq->rq.tail = 0; 162*d6b92ffaSHans Petter Selasky } 163*d6b92ffaSHans Petter Selasky 164*d6b92ffaSHans Petter Selasky void mlx5_init_qp_indices(struct mlx5_qp *qp) 165*d6b92ffaSHans Petter Selasky { 166*d6b92ffaSHans Petter Selasky qp->sq.head = 0; 167*d6b92ffaSHans Petter Selasky qp->sq.tail = 0; 168*d6b92ffaSHans Petter Selasky qp->rq.head = 0; 169*d6b92ffaSHans Petter Selasky qp->rq.tail = 0; 170*d6b92ffaSHans Petter Selasky qp->sq.cur_post = 0; 171*d6b92ffaSHans Petter Selasky } 172*d6b92ffaSHans Petter Selasky 173*d6b92ffaSHans Petter Selasky static int mlx5_wq_overflow(struct mlx5_wq *wq, int nreq, struct mlx5_cq *cq) 174*d6b92ffaSHans Petter Selasky { 175*d6b92ffaSHans Petter Selasky unsigned cur; 176*d6b92ffaSHans Petter Selasky 177*d6b92ffaSHans Petter Selasky cur = wq->head - wq->tail; 178*d6b92ffaSHans Petter Selasky if (cur + nreq < wq->max_post) 179*d6b92ffaSHans Petter Selasky return 0; 180*d6b92ffaSHans Petter Selasky 181*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&cq->lock); 182*d6b92ffaSHans Petter Selasky cur = wq->head - wq->tail; 183*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&cq->lock); 184*d6b92ffaSHans Petter Selasky 185*d6b92ffaSHans Petter Selasky return cur + nreq >= wq->max_post; 186*d6b92ffaSHans Petter Selasky } 187*d6b92ffaSHans Petter Selasky 188*d6b92ffaSHans Petter Selasky static inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg, 189*d6b92ffaSHans Petter Selasky uint64_t remote_addr, uint32_t rkey) 190*d6b92ffaSHans Petter Selasky { 191*d6b92ffaSHans Petter Selasky rseg->raddr = htobe64(remote_addr); 192*d6b92ffaSHans Petter Selasky rseg->rkey = htobe32(rkey); 193*d6b92ffaSHans Petter Selasky rseg->reserved = 0; 194*d6b92ffaSHans Petter Selasky } 195*d6b92ffaSHans Petter Selasky 196*d6b92ffaSHans Petter Selasky static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg, 197*d6b92ffaSHans Petter Selasky enum ibv_wr_opcode opcode, 198*d6b92ffaSHans Petter Selasky uint64_t swap, 199*d6b92ffaSHans Petter Selasky uint64_t compare_add) 200*d6b92ffaSHans Petter Selasky { 201*d6b92ffaSHans Petter Selasky if (opcode == IBV_WR_ATOMIC_CMP_AND_SWP) { 202*d6b92ffaSHans Petter Selasky aseg->swap_add = htobe64(swap); 203*d6b92ffaSHans Petter Selasky aseg->compare = htobe64(compare_add); 204*d6b92ffaSHans Petter Selasky } else { 205*d6b92ffaSHans Petter Selasky aseg->swap_add = htobe64(compare_add); 206*d6b92ffaSHans Petter Selasky } 207*d6b92ffaSHans Petter Selasky } 208*d6b92ffaSHans Petter Selasky 209*d6b92ffaSHans Petter Selasky static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg, 210*d6b92ffaSHans Petter Selasky struct ibv_send_wr *wr) 211*d6b92ffaSHans Petter Selasky { 212*d6b92ffaSHans Petter Selasky memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof dseg->av); 213*d6b92ffaSHans Petter Selasky dseg->av.dqp_dct = htobe32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV); 214*d6b92ffaSHans Petter Selasky dseg->av.key.qkey.qkey = htobe32(wr->wr.ud.remote_qkey); 215*d6b92ffaSHans Petter Selasky } 216*d6b92ffaSHans Petter Selasky 217*d6b92ffaSHans Petter Selasky static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ibv_sge *sg, 218*d6b92ffaSHans Petter Selasky int offset) 219*d6b92ffaSHans Petter Selasky { 220*d6b92ffaSHans Petter Selasky dseg->byte_count = htobe32(sg->length - offset); 221*d6b92ffaSHans Petter Selasky dseg->lkey = htobe32(sg->lkey); 222*d6b92ffaSHans Petter Selasky dseg->addr = htobe64(sg->addr + offset); 223*d6b92ffaSHans Petter Selasky } 224*d6b92ffaSHans Petter Selasky 225*d6b92ffaSHans Petter Selasky static void set_data_ptr_seg_atomic(struct mlx5_wqe_data_seg *dseg, 226*d6b92ffaSHans Petter Selasky struct ibv_sge *sg) 227*d6b92ffaSHans Petter Selasky { 228*d6b92ffaSHans Petter Selasky dseg->byte_count = htobe32(MLX5_ATOMIC_SIZE); 229*d6b92ffaSHans Petter Selasky dseg->lkey = htobe32(sg->lkey); 230*d6b92ffaSHans Petter Selasky dseg->addr = htobe64(sg->addr); 231*d6b92ffaSHans Petter Selasky } 232*d6b92ffaSHans Petter Selasky 233*d6b92ffaSHans Petter Selasky /* 234*d6b92ffaSHans Petter Selasky * Avoid using memcpy() to copy to BlueFlame page, since memcpy() 235*d6b92ffaSHans Petter Selasky * implementations may use move-string-buffer assembler instructions, 236*d6b92ffaSHans Petter Selasky * which do not guarantee order of copying. 237*d6b92ffaSHans Petter Selasky */ 238*d6b92ffaSHans Petter Selasky static void mlx5_bf_copy(unsigned long long *dst, unsigned long long *src, 239*d6b92ffaSHans Petter Selasky unsigned bytecnt, struct mlx5_qp *qp) 240*d6b92ffaSHans Petter Selasky { 241*d6b92ffaSHans Petter Selasky while (bytecnt > 0) { 242*d6b92ffaSHans Petter Selasky *dst++ = *src++; 243*d6b92ffaSHans Petter Selasky *dst++ = *src++; 244*d6b92ffaSHans Petter Selasky *dst++ = *src++; 245*d6b92ffaSHans Petter Selasky *dst++ = *src++; 246*d6b92ffaSHans Petter Selasky *dst++ = *src++; 247*d6b92ffaSHans Petter Selasky *dst++ = *src++; 248*d6b92ffaSHans Petter Selasky *dst++ = *src++; 249*d6b92ffaSHans Petter Selasky *dst++ = *src++; 250*d6b92ffaSHans Petter Selasky bytecnt -= 8 * sizeof(unsigned long long); 251*d6b92ffaSHans Petter Selasky if (unlikely(src == qp->sq.qend)) 252*d6b92ffaSHans Petter Selasky src = qp->sq_start; 253*d6b92ffaSHans Petter Selasky } 254*d6b92ffaSHans Petter Selasky } 255*d6b92ffaSHans Petter Selasky 256*d6b92ffaSHans Petter Selasky static uint32_t send_ieth(struct ibv_send_wr *wr) 257*d6b92ffaSHans Petter Selasky { 258*d6b92ffaSHans Petter Selasky switch (wr->opcode) { 259*d6b92ffaSHans Petter Selasky case IBV_WR_SEND_WITH_IMM: 260*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_WRITE_WITH_IMM: 261*d6b92ffaSHans Petter Selasky return wr->imm_data; 262*d6b92ffaSHans Petter Selasky case IBV_WR_SEND_WITH_INV: 263*d6b92ffaSHans Petter Selasky return htobe32(wr->imm_data); 264*d6b92ffaSHans Petter Selasky default: 265*d6b92ffaSHans Petter Selasky return 0; 266*d6b92ffaSHans Petter Selasky } 267*d6b92ffaSHans Petter Selasky } 268*d6b92ffaSHans Petter Selasky 269*d6b92ffaSHans Petter Selasky static int set_data_inl_seg(struct mlx5_qp *qp, struct ibv_send_wr *wr, 270*d6b92ffaSHans Petter Selasky void *wqe, int *sz, 271*d6b92ffaSHans Petter Selasky struct mlx5_sg_copy_ptr *sg_copy_ptr) 272*d6b92ffaSHans Petter Selasky { 273*d6b92ffaSHans Petter Selasky struct mlx5_wqe_inline_seg *seg; 274*d6b92ffaSHans Petter Selasky void *addr; 275*d6b92ffaSHans Petter Selasky int len; 276*d6b92ffaSHans Petter Selasky int i; 277*d6b92ffaSHans Petter Selasky int inl = 0; 278*d6b92ffaSHans Petter Selasky void *qend = qp->sq.qend; 279*d6b92ffaSHans Petter Selasky int copy; 280*d6b92ffaSHans Petter Selasky int offset = sg_copy_ptr->offset; 281*d6b92ffaSHans Petter Selasky 282*d6b92ffaSHans Petter Selasky seg = wqe; 283*d6b92ffaSHans Petter Selasky wqe += sizeof *seg; 284*d6b92ffaSHans Petter Selasky for (i = sg_copy_ptr->index; i < wr->num_sge; ++i) { 285*d6b92ffaSHans Petter Selasky addr = (void *) (unsigned long)(wr->sg_list[i].addr + offset); 286*d6b92ffaSHans Petter Selasky len = wr->sg_list[i].length - offset; 287*d6b92ffaSHans Petter Selasky inl += len; 288*d6b92ffaSHans Petter Selasky offset = 0; 289*d6b92ffaSHans Petter Selasky 290*d6b92ffaSHans Petter Selasky if (unlikely(inl > qp->max_inline_data)) 291*d6b92ffaSHans Petter Selasky return ENOMEM; 292*d6b92ffaSHans Petter Selasky 293*d6b92ffaSHans Petter Selasky if (unlikely(wqe + len > qend)) { 294*d6b92ffaSHans Petter Selasky copy = qend - wqe; 295*d6b92ffaSHans Petter Selasky memcpy(wqe, addr, copy); 296*d6b92ffaSHans Petter Selasky addr += copy; 297*d6b92ffaSHans Petter Selasky len -= copy; 298*d6b92ffaSHans Petter Selasky wqe = mlx5_get_send_wqe(qp, 0); 299*d6b92ffaSHans Petter Selasky } 300*d6b92ffaSHans Petter Selasky memcpy(wqe, addr, len); 301*d6b92ffaSHans Petter Selasky wqe += len; 302*d6b92ffaSHans Petter Selasky } 303*d6b92ffaSHans Petter Selasky 304*d6b92ffaSHans Petter Selasky if (likely(inl)) { 305*d6b92ffaSHans Petter Selasky seg->byte_count = htobe32(inl | MLX5_INLINE_SEG); 306*d6b92ffaSHans Petter Selasky *sz = align(inl + sizeof seg->byte_count, 16) / 16; 307*d6b92ffaSHans Petter Selasky } else 308*d6b92ffaSHans Petter Selasky *sz = 0; 309*d6b92ffaSHans Petter Selasky 310*d6b92ffaSHans Petter Selasky return 0; 311*d6b92ffaSHans Petter Selasky } 312*d6b92ffaSHans Petter Selasky 313*d6b92ffaSHans Petter Selasky static uint8_t wq_sig(struct mlx5_wqe_ctrl_seg *ctrl) 314*d6b92ffaSHans Petter Selasky { 315*d6b92ffaSHans Petter Selasky return calc_sig(ctrl, be32toh(ctrl->qpn_ds)); 316*d6b92ffaSHans Petter Selasky } 317*d6b92ffaSHans Petter Selasky 318*d6b92ffaSHans Petter Selasky #ifdef MLX5_DEBUG 319*d6b92ffaSHans Petter Selasky static void dump_wqe(FILE *fp, int idx, int size_16, struct mlx5_qp *qp) 320*d6b92ffaSHans Petter Selasky { 321*d6b92ffaSHans Petter Selasky uint32_t *p = NULL; 322*d6b92ffaSHans Petter Selasky int i, j; 323*d6b92ffaSHans Petter Selasky int tidx = idx; 324*d6b92ffaSHans Petter Selasky 325*d6b92ffaSHans Petter Selasky fprintf(fp, "dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx)); 326*d6b92ffaSHans Petter Selasky for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) { 327*d6b92ffaSHans Petter Selasky if ((i & 0xf) == 0) { 328*d6b92ffaSHans Petter Selasky void *buf = mlx5_get_send_wqe(qp, tidx); 329*d6b92ffaSHans Petter Selasky tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1); 330*d6b92ffaSHans Petter Selasky p = buf; 331*d6b92ffaSHans Petter Selasky j = 0; 332*d6b92ffaSHans Petter Selasky } 333*d6b92ffaSHans Petter Selasky fprintf(fp, "%08x %08x %08x %08x\n", be32toh(p[j]), be32toh(p[j + 1]), 334*d6b92ffaSHans Petter Selasky be32toh(p[j + 2]), be32toh(p[j + 3])); 335*d6b92ffaSHans Petter Selasky } 336*d6b92ffaSHans Petter Selasky } 337*d6b92ffaSHans Petter Selasky #endif /* MLX5_DEBUG */ 338*d6b92ffaSHans Petter Selasky 339*d6b92ffaSHans Petter Selasky 340*d6b92ffaSHans Petter Selasky void *mlx5_get_atomic_laddr(struct mlx5_qp *qp, uint16_t idx, int *byte_count) 341*d6b92ffaSHans Petter Selasky { 342*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *dpseg; 343*d6b92ffaSHans Petter Selasky void *addr; 344*d6b92ffaSHans Petter Selasky 345*d6b92ffaSHans Petter Selasky dpseg = mlx5_get_send_wqe(qp, idx) + sizeof(struct mlx5_wqe_ctrl_seg) + 346*d6b92ffaSHans Petter Selasky sizeof(struct mlx5_wqe_raddr_seg) + 347*d6b92ffaSHans Petter Selasky sizeof(struct mlx5_wqe_atomic_seg); 348*d6b92ffaSHans Petter Selasky addr = (void *)(unsigned long)be64toh(dpseg->addr); 349*d6b92ffaSHans Petter Selasky 350*d6b92ffaSHans Petter Selasky /* 351*d6b92ffaSHans Petter Selasky * Currently byte count is always 8 bytes. Fix this when 352*d6b92ffaSHans Petter Selasky * we support variable size of atomics 353*d6b92ffaSHans Petter Selasky */ 354*d6b92ffaSHans Petter Selasky *byte_count = 8; 355*d6b92ffaSHans Petter Selasky return addr; 356*d6b92ffaSHans Petter Selasky } 357*d6b92ffaSHans Petter Selasky 358*d6b92ffaSHans Petter Selasky static inline int copy_eth_inline_headers(struct ibv_qp *ibqp, 359*d6b92ffaSHans Petter Selasky struct ibv_send_wr *wr, 360*d6b92ffaSHans Petter Selasky struct mlx5_wqe_eth_seg *eseg, 361*d6b92ffaSHans Petter Selasky struct mlx5_sg_copy_ptr *sg_copy_ptr) 362*d6b92ffaSHans Petter Selasky { 363*d6b92ffaSHans Petter Selasky uint32_t inl_hdr_size = MLX5_ETH_L2_INLINE_HEADER_SIZE; 364*d6b92ffaSHans Petter Selasky int inl_hdr_copy_size = 0; 365*d6b92ffaSHans Petter Selasky int j = 0; 366*d6b92ffaSHans Petter Selasky FILE *fp = to_mctx(ibqp->context)->dbg_fp; 367*d6b92ffaSHans Petter Selasky 368*d6b92ffaSHans Petter Selasky if (unlikely(wr->num_sge < 1)) { 369*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "illegal num_sge: %d, minimum is 1\n", 370*d6b92ffaSHans Petter Selasky wr->num_sge); 371*d6b92ffaSHans Petter Selasky return EINVAL; 372*d6b92ffaSHans Petter Selasky } 373*d6b92ffaSHans Petter Selasky 374*d6b92ffaSHans Petter Selasky if (likely(wr->sg_list[0].length >= MLX5_ETH_L2_INLINE_HEADER_SIZE)) { 375*d6b92ffaSHans Petter Selasky inl_hdr_copy_size = MLX5_ETH_L2_INLINE_HEADER_SIZE; 376*d6b92ffaSHans Petter Selasky memcpy(eseg->inline_hdr_start, 377*d6b92ffaSHans Petter Selasky (void *)(uintptr_t)wr->sg_list[0].addr, 378*d6b92ffaSHans Petter Selasky inl_hdr_copy_size); 379*d6b92ffaSHans Petter Selasky } else { 380*d6b92ffaSHans Petter Selasky for (j = 0; j < wr->num_sge && inl_hdr_size > 0; ++j) { 381*d6b92ffaSHans Petter Selasky inl_hdr_copy_size = min(wr->sg_list[j].length, 382*d6b92ffaSHans Petter Selasky inl_hdr_size); 383*d6b92ffaSHans Petter Selasky memcpy(eseg->inline_hdr_start + 384*d6b92ffaSHans Petter Selasky (MLX5_ETH_L2_INLINE_HEADER_SIZE - inl_hdr_size), 385*d6b92ffaSHans Petter Selasky (void *)(uintptr_t)wr->sg_list[j].addr, 386*d6b92ffaSHans Petter Selasky inl_hdr_copy_size); 387*d6b92ffaSHans Petter Selasky inl_hdr_size -= inl_hdr_copy_size; 388*d6b92ffaSHans Petter Selasky } 389*d6b92ffaSHans Petter Selasky if (unlikely(inl_hdr_size)) { 390*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "Ethernet headers < 16 bytes\n"); 391*d6b92ffaSHans Petter Selasky return EINVAL; 392*d6b92ffaSHans Petter Selasky } 393*d6b92ffaSHans Petter Selasky --j; 394*d6b92ffaSHans Petter Selasky } 395*d6b92ffaSHans Petter Selasky 396*d6b92ffaSHans Petter Selasky 397*d6b92ffaSHans Petter Selasky eseg->inline_hdr_sz = htobe16(MLX5_ETH_L2_INLINE_HEADER_SIZE); 398*d6b92ffaSHans Petter Selasky 399*d6b92ffaSHans Petter Selasky /* If we copied all the sge into the inline-headers, then we need to 400*d6b92ffaSHans Petter Selasky * start copying from the next sge into the data-segment. 401*d6b92ffaSHans Petter Selasky */ 402*d6b92ffaSHans Petter Selasky if (unlikely(wr->sg_list[j].length == inl_hdr_copy_size)) { 403*d6b92ffaSHans Petter Selasky ++j; 404*d6b92ffaSHans Petter Selasky inl_hdr_copy_size = 0; 405*d6b92ffaSHans Petter Selasky } 406*d6b92ffaSHans Petter Selasky 407*d6b92ffaSHans Petter Selasky sg_copy_ptr->index = j; 408*d6b92ffaSHans Petter Selasky sg_copy_ptr->offset = inl_hdr_copy_size; 409*d6b92ffaSHans Petter Selasky 410*d6b92ffaSHans Petter Selasky return 0; 411*d6b92ffaSHans Petter Selasky } 412*d6b92ffaSHans Petter Selasky 413*d6b92ffaSHans Petter Selasky #undef ALIGN 414*d6b92ffaSHans Petter Selasky #define ALIGN(x, log_a) ((((x) + (1 << (log_a)) - 1)) & ~((1 << (log_a)) - 1)) 415*d6b92ffaSHans Petter Selasky 416*d6b92ffaSHans Petter Selasky static inline uint16_t get_klm_octo(int nentries) 417*d6b92ffaSHans Petter Selasky { 418*d6b92ffaSHans Petter Selasky return htobe16(ALIGN(nentries, 3) / 2); 419*d6b92ffaSHans Petter Selasky } 420*d6b92ffaSHans Petter Selasky 421*d6b92ffaSHans Petter Selasky static void set_umr_data_seg(struct mlx5_qp *qp, enum ibv_mw_type type, 422*d6b92ffaSHans Petter Selasky int32_t rkey, struct ibv_mw_bind_info *bind_info, 423*d6b92ffaSHans Petter Selasky uint32_t qpn, void **seg, int *size) 424*d6b92ffaSHans Petter Selasky { 425*d6b92ffaSHans Petter Selasky union { 426*d6b92ffaSHans Petter Selasky struct mlx5_wqe_umr_klm_seg klm; 427*d6b92ffaSHans Petter Selasky uint8_t reserved[64]; 428*d6b92ffaSHans Petter Selasky } *data = *seg; 429*d6b92ffaSHans Petter Selasky 430*d6b92ffaSHans Petter Selasky data->klm.byte_count = htobe32(bind_info->length); 431*d6b92ffaSHans Petter Selasky data->klm.mkey = htobe32(bind_info->mr->lkey); 432*d6b92ffaSHans Petter Selasky data->klm.address = htobe64(bind_info->addr); 433*d6b92ffaSHans Petter Selasky 434*d6b92ffaSHans Petter Selasky memset(&data->klm + 1, 0, sizeof(data->reserved) - 435*d6b92ffaSHans Petter Selasky sizeof(data->klm)); 436*d6b92ffaSHans Petter Selasky 437*d6b92ffaSHans Petter Selasky *seg += sizeof(*data); 438*d6b92ffaSHans Petter Selasky *size += (sizeof(*data) / 16); 439*d6b92ffaSHans Petter Selasky } 440*d6b92ffaSHans Petter Selasky 441*d6b92ffaSHans Petter Selasky static void set_umr_mkey_seg(struct mlx5_qp *qp, enum ibv_mw_type type, 442*d6b92ffaSHans Petter Selasky int32_t rkey, struct ibv_mw_bind_info *bind_info, 443*d6b92ffaSHans Petter Selasky uint32_t qpn, void **seg, int *size) 444*d6b92ffaSHans Petter Selasky { 445*d6b92ffaSHans Petter Selasky struct mlx5_wqe_mkey_context_seg *mkey = *seg; 446*d6b92ffaSHans Petter Selasky 447*d6b92ffaSHans Petter Selasky mkey->qpn_mkey = htobe32((rkey & 0xFF) | 448*d6b92ffaSHans Petter Selasky ((type == IBV_MW_TYPE_1 || !bind_info->length) ? 449*d6b92ffaSHans Petter Selasky 0xFFFFFF00 : qpn << 8)); 450*d6b92ffaSHans Petter Selasky if (bind_info->length) { 451*d6b92ffaSHans Petter Selasky /* Local read is set in kernel */ 452*d6b92ffaSHans Petter Selasky mkey->access_flags = 0; 453*d6b92ffaSHans Petter Selasky mkey->free = 0; 454*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_LOCAL_WRITE) 455*d6b92ffaSHans Petter Selasky mkey->access_flags |= 456*d6b92ffaSHans Petter Selasky MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_LOCAL_WRITE; 457*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_WRITE) 458*d6b92ffaSHans Petter Selasky mkey->access_flags |= 459*d6b92ffaSHans Petter Selasky MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_REMOTE_WRITE; 460*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_READ) 461*d6b92ffaSHans Petter Selasky mkey->access_flags |= 462*d6b92ffaSHans Petter Selasky MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_REMOTE_READ; 463*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_ATOMIC) 464*d6b92ffaSHans Petter Selasky mkey->access_flags |= 465*d6b92ffaSHans Petter Selasky MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_ATOMIC; 466*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_ZERO_BASED) 467*d6b92ffaSHans Petter Selasky mkey->start_addr = 0; 468*d6b92ffaSHans Petter Selasky else 469*d6b92ffaSHans Petter Selasky mkey->start_addr = htobe64(bind_info->addr); 470*d6b92ffaSHans Petter Selasky mkey->len = htobe64(bind_info->length); 471*d6b92ffaSHans Petter Selasky } else { 472*d6b92ffaSHans Petter Selasky mkey->free = MLX5_WQE_MKEY_CONTEXT_FREE; 473*d6b92ffaSHans Petter Selasky } 474*d6b92ffaSHans Petter Selasky 475*d6b92ffaSHans Petter Selasky *seg += sizeof(struct mlx5_wqe_mkey_context_seg); 476*d6b92ffaSHans Petter Selasky *size += (sizeof(struct mlx5_wqe_mkey_context_seg) / 16); 477*d6b92ffaSHans Petter Selasky } 478*d6b92ffaSHans Petter Selasky 479*d6b92ffaSHans Petter Selasky static inline void set_umr_control_seg(struct mlx5_qp *qp, enum ibv_mw_type type, 480*d6b92ffaSHans Petter Selasky int32_t rkey, struct ibv_mw_bind_info *bind_info, 481*d6b92ffaSHans Petter Selasky uint32_t qpn, void **seg, int *size) 482*d6b92ffaSHans Petter Selasky { 483*d6b92ffaSHans Petter Selasky struct mlx5_wqe_umr_ctrl_seg *ctrl = *seg; 484*d6b92ffaSHans Petter Selasky 485*d6b92ffaSHans Petter Selasky ctrl->flags = MLX5_WQE_UMR_CTRL_FLAG_TRNSLATION_OFFSET | 486*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_FLAG_INLINE; 487*d6b92ffaSHans Petter Selasky ctrl->mkey_mask = htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_FREE | 488*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_MKEY); 489*d6b92ffaSHans Petter Selasky ctrl->translation_offset = 0; 490*d6b92ffaSHans Petter Selasky memset(ctrl->rsvd0, 0, sizeof(ctrl->rsvd0)); 491*d6b92ffaSHans Petter Selasky memset(ctrl->rsvd1, 0, sizeof(ctrl->rsvd1)); 492*d6b92ffaSHans Petter Selasky 493*d6b92ffaSHans Petter Selasky if (type == IBV_MW_TYPE_2) 494*d6b92ffaSHans Petter Selasky ctrl->mkey_mask |= htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_QPN); 495*d6b92ffaSHans Petter Selasky 496*d6b92ffaSHans Petter Selasky if (bind_info->length) { 497*d6b92ffaSHans Petter Selasky ctrl->klm_octowords = get_klm_octo(1); 498*d6b92ffaSHans Petter Selasky if (type == IBV_MW_TYPE_2) 499*d6b92ffaSHans Petter Selasky ctrl->flags |= MLX5_WQE_UMR_CTRL_FLAG_CHECK_FREE; 500*d6b92ffaSHans Petter Selasky ctrl->mkey_mask |= htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_LEN | 501*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_START_ADDR | 502*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_LOCAL_WRITE | 503*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_REMOTE_READ | 504*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_REMOTE_WRITE | 505*d6b92ffaSHans Petter Selasky MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_ATOMIC); 506*d6b92ffaSHans Petter Selasky } else { 507*d6b92ffaSHans Petter Selasky ctrl->klm_octowords = get_klm_octo(0); 508*d6b92ffaSHans Petter Selasky if (type == IBV_MW_TYPE_2) 509*d6b92ffaSHans Petter Selasky ctrl->flags |= MLX5_WQE_UMR_CTRL_FLAG_CHECK_QPN; 510*d6b92ffaSHans Petter Selasky } 511*d6b92ffaSHans Petter Selasky 512*d6b92ffaSHans Petter Selasky *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); 513*d6b92ffaSHans Petter Selasky *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; 514*d6b92ffaSHans Petter Selasky } 515*d6b92ffaSHans Petter Selasky 516*d6b92ffaSHans Petter Selasky static inline int set_bind_wr(struct mlx5_qp *qp, enum ibv_mw_type type, 517*d6b92ffaSHans Petter Selasky int32_t rkey, struct ibv_mw_bind_info *bind_info, 518*d6b92ffaSHans Petter Selasky uint32_t qpn, void **seg, int *size) 519*d6b92ffaSHans Petter Selasky { 520*d6b92ffaSHans Petter Selasky void *qend = qp->sq.qend; 521*d6b92ffaSHans Petter Selasky 522*d6b92ffaSHans Petter Selasky #ifdef MW_DEBUG 523*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & 524*d6b92ffaSHans Petter Selasky ~(IBV_ACCESS_REMOTE_ATOMIC | IBV_ACCESS_REMOTE_READ | 525*d6b92ffaSHans Petter Selasky IBV_ACCESS_REMOTE_WRITE)) 526*d6b92ffaSHans Petter Selasky return EINVAL; 527*d6b92ffaSHans Petter Selasky 528*d6b92ffaSHans Petter Selasky if (bind_info->mr && 529*d6b92ffaSHans Petter Selasky (bind_info->mr->addr > (void *)bind_info->addr || 530*d6b92ffaSHans Petter Selasky bind_info->mr->addr + bind_info->mr->length < 531*d6b92ffaSHans Petter Selasky (void *)bind_info->addr + bind_info->length || 532*d6b92ffaSHans Petter Selasky !(to_mmr(bind_info->mr)->alloc_flags & IBV_ACCESS_MW_BIND) || 533*d6b92ffaSHans Petter Selasky (bind_info->mw_access_flags & 534*d6b92ffaSHans Petter Selasky (IBV_ACCESS_REMOTE_ATOMIC | IBV_ACCESS_REMOTE_WRITE) && 535*d6b92ffaSHans Petter Selasky !(to_mmr(bind_info->mr)->alloc_flags & IBV_ACCESS_LOCAL_WRITE)))) 536*d6b92ffaSHans Petter Selasky return EINVAL; 537*d6b92ffaSHans Petter Selasky 538*d6b92ffaSHans Petter Selasky #endif 539*d6b92ffaSHans Petter Selasky 540*d6b92ffaSHans Petter Selasky /* check that len > 2GB because KLM support only 2GB */ 541*d6b92ffaSHans Petter Selasky if (bind_info->length > 1UL << 31) 542*d6b92ffaSHans Petter Selasky return EOPNOTSUPP; 543*d6b92ffaSHans Petter Selasky 544*d6b92ffaSHans Petter Selasky set_umr_control_seg(qp, type, rkey, bind_info, qpn, seg, size); 545*d6b92ffaSHans Petter Selasky if (unlikely((*seg == qend))) 546*d6b92ffaSHans Petter Selasky *seg = mlx5_get_send_wqe(qp, 0); 547*d6b92ffaSHans Petter Selasky 548*d6b92ffaSHans Petter Selasky set_umr_mkey_seg(qp, type, rkey, bind_info, qpn, seg, size); 549*d6b92ffaSHans Petter Selasky if (!bind_info->length) 550*d6b92ffaSHans Petter Selasky return 0; 551*d6b92ffaSHans Petter Selasky 552*d6b92ffaSHans Petter Selasky if (unlikely((seg == qend))) 553*d6b92ffaSHans Petter Selasky *seg = mlx5_get_send_wqe(qp, 0); 554*d6b92ffaSHans Petter Selasky 555*d6b92ffaSHans Petter Selasky set_umr_data_seg(qp, type, rkey, bind_info, qpn, seg, size); 556*d6b92ffaSHans Petter Selasky return 0; 557*d6b92ffaSHans Petter Selasky } 558*d6b92ffaSHans Petter Selasky 559*d6b92ffaSHans Petter Selasky /* Copy tso header to eth segment with considering padding and WQE 560*d6b92ffaSHans Petter Selasky * wrap around in WQ buffer. 561*d6b92ffaSHans Petter Selasky */ 562*d6b92ffaSHans Petter Selasky static inline int set_tso_eth_seg(void **seg, struct ibv_send_wr *wr, 563*d6b92ffaSHans Petter Selasky void *qend, struct mlx5_qp *qp, int *size) 564*d6b92ffaSHans Petter Selasky { 565*d6b92ffaSHans Petter Selasky struct mlx5_wqe_eth_seg *eseg = *seg; 566*d6b92ffaSHans Petter Selasky int size_of_inl_hdr_start = sizeof(eseg->inline_hdr_start); 567*d6b92ffaSHans Petter Selasky uint64_t left, left_len, copy_sz; 568*d6b92ffaSHans Petter Selasky void *pdata = wr->tso.hdr; 569*d6b92ffaSHans Petter Selasky FILE *fp = to_mctx(qp->ibv_qp->context)->dbg_fp; 570*d6b92ffaSHans Petter Selasky 571*d6b92ffaSHans Petter Selasky if (unlikely(wr->tso.hdr_sz < MLX5_ETH_L2_MIN_HEADER_SIZE || 572*d6b92ffaSHans Petter Selasky wr->tso.hdr_sz > qp->max_tso_header)) { 573*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, 574*d6b92ffaSHans Petter Selasky "TSO header size should be at least %d and at most %d\n", 575*d6b92ffaSHans Petter Selasky MLX5_ETH_L2_MIN_HEADER_SIZE, 576*d6b92ffaSHans Petter Selasky qp->max_tso_header); 577*d6b92ffaSHans Petter Selasky return EINVAL; 578*d6b92ffaSHans Petter Selasky } 579*d6b92ffaSHans Petter Selasky 580*d6b92ffaSHans Petter Selasky left = wr->tso.hdr_sz; 581*d6b92ffaSHans Petter Selasky eseg->mss = htobe16(wr->tso.mss); 582*d6b92ffaSHans Petter Selasky eseg->inline_hdr_sz = htobe16(wr->tso.hdr_sz); 583*d6b92ffaSHans Petter Selasky 584*d6b92ffaSHans Petter Selasky /* Check if there is space till the end of queue, if yes, 585*d6b92ffaSHans Petter Selasky * copy all in one shot, otherwise copy till the end of queue, 586*d6b92ffaSHans Petter Selasky * rollback and then copy the left 587*d6b92ffaSHans Petter Selasky */ 588*d6b92ffaSHans Petter Selasky left_len = qend - (void *)eseg->inline_hdr_start; 589*d6b92ffaSHans Petter Selasky copy_sz = min(left_len, left); 590*d6b92ffaSHans Petter Selasky 591*d6b92ffaSHans Petter Selasky memcpy(eseg->inline_hdr_start, pdata, copy_sz); 592*d6b92ffaSHans Petter Selasky 593*d6b92ffaSHans Petter Selasky /* The -1 is because there are already 16 bytes included in 594*d6b92ffaSHans Petter Selasky * eseg->inline_hdr[16] 595*d6b92ffaSHans Petter Selasky */ 596*d6b92ffaSHans Petter Selasky *seg += align(copy_sz - size_of_inl_hdr_start, 16) - 16; 597*d6b92ffaSHans Petter Selasky *size += align(copy_sz - size_of_inl_hdr_start, 16) / 16 - 1; 598*d6b92ffaSHans Petter Selasky 599*d6b92ffaSHans Petter Selasky /* The last wqe in the queue */ 600*d6b92ffaSHans Petter Selasky if (unlikely(copy_sz < left)) { 601*d6b92ffaSHans Petter Selasky *seg = mlx5_get_send_wqe(qp, 0); 602*d6b92ffaSHans Petter Selasky left -= copy_sz; 603*d6b92ffaSHans Petter Selasky pdata += copy_sz; 604*d6b92ffaSHans Petter Selasky memcpy(*seg, pdata, left); 605*d6b92ffaSHans Petter Selasky *seg += align(left, 16); 606*d6b92ffaSHans Petter Selasky *size += align(left, 16) / 16; 607*d6b92ffaSHans Petter Selasky } 608*d6b92ffaSHans Petter Selasky 609*d6b92ffaSHans Petter Selasky return 0; 610*d6b92ffaSHans Petter Selasky } 611*d6b92ffaSHans Petter Selasky 612*d6b92ffaSHans Petter Selasky static inline int _mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, 613*d6b92ffaSHans Petter Selasky struct ibv_send_wr **bad_wr) 614*d6b92ffaSHans Petter Selasky { 615*d6b92ffaSHans Petter Selasky struct mlx5_context *ctx; 616*d6b92ffaSHans Petter Selasky struct mlx5_qp *qp = to_mqp(ibqp); 617*d6b92ffaSHans Petter Selasky void *seg; 618*d6b92ffaSHans Petter Selasky struct mlx5_wqe_eth_seg *eseg; 619*d6b92ffaSHans Petter Selasky struct mlx5_wqe_ctrl_seg *ctrl = NULL; 620*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *dpseg; 621*d6b92ffaSHans Petter Selasky struct mlx5_sg_copy_ptr sg_copy_ptr = {.index = 0, .offset = 0}; 622*d6b92ffaSHans Petter Selasky int nreq; 623*d6b92ffaSHans Petter Selasky int inl = 0; 624*d6b92ffaSHans Petter Selasky int err = 0; 625*d6b92ffaSHans Petter Selasky int size = 0; 626*d6b92ffaSHans Petter Selasky int i; 627*d6b92ffaSHans Petter Selasky unsigned idx; 628*d6b92ffaSHans Petter Selasky uint8_t opmod = 0; 629*d6b92ffaSHans Petter Selasky struct mlx5_bf *bf = qp->bf; 630*d6b92ffaSHans Petter Selasky void *qend = qp->sq.qend; 631*d6b92ffaSHans Petter Selasky uint32_t mlx5_opcode; 632*d6b92ffaSHans Petter Selasky struct mlx5_wqe_xrc_seg *xrc; 633*d6b92ffaSHans Petter Selasky uint8_t fence; 634*d6b92ffaSHans Petter Selasky uint8_t next_fence; 635*d6b92ffaSHans Petter Selasky uint32_t max_tso = 0; 636*d6b92ffaSHans Petter Selasky FILE *fp = to_mctx(ibqp->context)->dbg_fp; /* The compiler ignores in non-debug mode */ 637*d6b92ffaSHans Petter Selasky 638*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&qp->sq.lock); 639*d6b92ffaSHans Petter Selasky 640*d6b92ffaSHans Petter Selasky next_fence = qp->fm_cache; 641*d6b92ffaSHans Petter Selasky 642*d6b92ffaSHans Petter Selasky for (nreq = 0; wr; ++nreq, wr = wr->next) { 643*d6b92ffaSHans Petter Selasky if (unlikely(wr->opcode < 0 || 644*d6b92ffaSHans Petter Selasky wr->opcode >= sizeof mlx5_ib_opcode / sizeof mlx5_ib_opcode[0])) { 645*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "bad opcode %d\n", wr->opcode); 646*d6b92ffaSHans Petter Selasky err = EINVAL; 647*d6b92ffaSHans Petter Selasky *bad_wr = wr; 648*d6b92ffaSHans Petter Selasky goto out; 649*d6b92ffaSHans Petter Selasky } 650*d6b92ffaSHans Petter Selasky 651*d6b92ffaSHans Petter Selasky if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, 652*d6b92ffaSHans Petter Selasky to_mcq(qp->ibv_qp->send_cq)))) { 653*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "work queue overflow\n"); 654*d6b92ffaSHans Petter Selasky err = ENOMEM; 655*d6b92ffaSHans Petter Selasky *bad_wr = wr; 656*d6b92ffaSHans Petter Selasky goto out; 657*d6b92ffaSHans Petter Selasky } 658*d6b92ffaSHans Petter Selasky 659*d6b92ffaSHans Petter Selasky if (unlikely(wr->num_sge > qp->sq.max_gs)) { 660*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "max gs exceeded %d (max = %d)\n", 661*d6b92ffaSHans Petter Selasky wr->num_sge, qp->sq.max_gs); 662*d6b92ffaSHans Petter Selasky err = ENOMEM; 663*d6b92ffaSHans Petter Selasky *bad_wr = wr; 664*d6b92ffaSHans Petter Selasky goto out; 665*d6b92ffaSHans Petter Selasky } 666*d6b92ffaSHans Petter Selasky 667*d6b92ffaSHans Petter Selasky if (wr->send_flags & IBV_SEND_FENCE) 668*d6b92ffaSHans Petter Selasky fence = MLX5_WQE_CTRL_FENCE; 669*d6b92ffaSHans Petter Selasky else 670*d6b92ffaSHans Petter Selasky fence = next_fence; 671*d6b92ffaSHans Petter Selasky next_fence = 0; 672*d6b92ffaSHans Petter Selasky idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); 673*d6b92ffaSHans Petter Selasky ctrl = seg = mlx5_get_send_wqe(qp, idx); 674*d6b92ffaSHans Petter Selasky *(uint32_t *)(seg + 8) = 0; 675*d6b92ffaSHans Petter Selasky ctrl->imm = send_ieth(wr); 676*d6b92ffaSHans Petter Selasky ctrl->fm_ce_se = qp->sq_signal_bits | fence | 677*d6b92ffaSHans Petter Selasky (wr->send_flags & IBV_SEND_SIGNALED ? 678*d6b92ffaSHans Petter Selasky MLX5_WQE_CTRL_CQ_UPDATE : 0) | 679*d6b92ffaSHans Petter Selasky (wr->send_flags & IBV_SEND_SOLICITED ? 680*d6b92ffaSHans Petter Selasky MLX5_WQE_CTRL_SOLICITED : 0); 681*d6b92ffaSHans Petter Selasky 682*d6b92ffaSHans Petter Selasky seg += sizeof *ctrl; 683*d6b92ffaSHans Petter Selasky size = sizeof *ctrl / 16; 684*d6b92ffaSHans Petter Selasky 685*d6b92ffaSHans Petter Selasky switch (ibqp->qp_type) { 686*d6b92ffaSHans Petter Selasky case IBV_QPT_XRC_SEND: 687*d6b92ffaSHans Petter Selasky if (unlikely(wr->opcode != IBV_WR_BIND_MW && 688*d6b92ffaSHans Petter Selasky wr->opcode != IBV_WR_LOCAL_INV)) { 689*d6b92ffaSHans Petter Selasky xrc = seg; 690*d6b92ffaSHans Petter Selasky xrc->xrc_srqn = htobe32(wr->qp_type.xrc.remote_srqn); 691*d6b92ffaSHans Petter Selasky seg += sizeof(*xrc); 692*d6b92ffaSHans Petter Selasky size += sizeof(*xrc) / 16; 693*d6b92ffaSHans Petter Selasky } 694*d6b92ffaSHans Petter Selasky /* fall through */ 695*d6b92ffaSHans Petter Selasky case IBV_QPT_RC: 696*d6b92ffaSHans Petter Selasky switch (wr->opcode) { 697*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_READ: 698*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_WRITE: 699*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_WRITE_WITH_IMM: 700*d6b92ffaSHans Petter Selasky set_raddr_seg(seg, wr->wr.rdma.remote_addr, 701*d6b92ffaSHans Petter Selasky wr->wr.rdma.rkey); 702*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_raddr_seg); 703*d6b92ffaSHans Petter Selasky size += sizeof(struct mlx5_wqe_raddr_seg) / 16; 704*d6b92ffaSHans Petter Selasky break; 705*d6b92ffaSHans Petter Selasky 706*d6b92ffaSHans Petter Selasky case IBV_WR_ATOMIC_CMP_AND_SWP: 707*d6b92ffaSHans Petter Selasky case IBV_WR_ATOMIC_FETCH_AND_ADD: 708*d6b92ffaSHans Petter Selasky if (unlikely(!qp->atomics_enabled)) { 709*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, "atomic operations are not supported\n"); 710*d6b92ffaSHans Petter Selasky err = ENOSYS; 711*d6b92ffaSHans Petter Selasky *bad_wr = wr; 712*d6b92ffaSHans Petter Selasky goto out; 713*d6b92ffaSHans Petter Selasky } 714*d6b92ffaSHans Petter Selasky set_raddr_seg(seg, wr->wr.atomic.remote_addr, 715*d6b92ffaSHans Petter Selasky wr->wr.atomic.rkey); 716*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_raddr_seg); 717*d6b92ffaSHans Petter Selasky 718*d6b92ffaSHans Petter Selasky set_atomic_seg(seg, wr->opcode, 719*d6b92ffaSHans Petter Selasky wr->wr.atomic.swap, 720*d6b92ffaSHans Petter Selasky wr->wr.atomic.compare_add); 721*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_atomic_seg); 722*d6b92ffaSHans Petter Selasky 723*d6b92ffaSHans Petter Selasky size += (sizeof(struct mlx5_wqe_raddr_seg) + 724*d6b92ffaSHans Petter Selasky sizeof(struct mlx5_wqe_atomic_seg)) / 16; 725*d6b92ffaSHans Petter Selasky break; 726*d6b92ffaSHans Petter Selasky 727*d6b92ffaSHans Petter Selasky case IBV_WR_BIND_MW: 728*d6b92ffaSHans Petter Selasky next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE; 729*d6b92ffaSHans Petter Selasky ctrl->imm = htobe32(wr->bind_mw.mw->rkey); 730*d6b92ffaSHans Petter Selasky err = set_bind_wr(qp, wr->bind_mw.mw->type, 731*d6b92ffaSHans Petter Selasky wr->bind_mw.rkey, 732*d6b92ffaSHans Petter Selasky &wr->bind_mw.bind_info, 733*d6b92ffaSHans Petter Selasky ibqp->qp_num, &seg, &size); 734*d6b92ffaSHans Petter Selasky if (err) { 735*d6b92ffaSHans Petter Selasky *bad_wr = wr; 736*d6b92ffaSHans Petter Selasky goto out; 737*d6b92ffaSHans Petter Selasky } 738*d6b92ffaSHans Petter Selasky 739*d6b92ffaSHans Petter Selasky qp->sq.wr_data[idx] = IBV_WC_BIND_MW; 740*d6b92ffaSHans Petter Selasky break; 741*d6b92ffaSHans Petter Selasky case IBV_WR_LOCAL_INV: { 742*d6b92ffaSHans Petter Selasky struct ibv_mw_bind_info bind_info = {}; 743*d6b92ffaSHans Petter Selasky 744*d6b92ffaSHans Petter Selasky next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE; 745*d6b92ffaSHans Petter Selasky ctrl->imm = htobe32(wr->imm_data); 746*d6b92ffaSHans Petter Selasky err = set_bind_wr(qp, IBV_MW_TYPE_2, 0, 747*d6b92ffaSHans Petter Selasky &bind_info, ibqp->qp_num, 748*d6b92ffaSHans Petter Selasky &seg, &size); 749*d6b92ffaSHans Petter Selasky if (err) { 750*d6b92ffaSHans Petter Selasky *bad_wr = wr; 751*d6b92ffaSHans Petter Selasky goto out; 752*d6b92ffaSHans Petter Selasky } 753*d6b92ffaSHans Petter Selasky 754*d6b92ffaSHans Petter Selasky qp->sq.wr_data[idx] = IBV_WC_LOCAL_INV; 755*d6b92ffaSHans Petter Selasky break; 756*d6b92ffaSHans Petter Selasky } 757*d6b92ffaSHans Petter Selasky 758*d6b92ffaSHans Petter Selasky default: 759*d6b92ffaSHans Petter Selasky break; 760*d6b92ffaSHans Petter Selasky } 761*d6b92ffaSHans Petter Selasky break; 762*d6b92ffaSHans Petter Selasky 763*d6b92ffaSHans Petter Selasky case IBV_QPT_UC: 764*d6b92ffaSHans Petter Selasky switch (wr->opcode) { 765*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_WRITE: 766*d6b92ffaSHans Petter Selasky case IBV_WR_RDMA_WRITE_WITH_IMM: 767*d6b92ffaSHans Petter Selasky set_raddr_seg(seg, wr->wr.rdma.remote_addr, 768*d6b92ffaSHans Petter Selasky wr->wr.rdma.rkey); 769*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_raddr_seg); 770*d6b92ffaSHans Petter Selasky size += sizeof(struct mlx5_wqe_raddr_seg) / 16; 771*d6b92ffaSHans Petter Selasky break; 772*d6b92ffaSHans Petter Selasky case IBV_WR_BIND_MW: 773*d6b92ffaSHans Petter Selasky next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE; 774*d6b92ffaSHans Petter Selasky ctrl->imm = htobe32(wr->bind_mw.mw->rkey); 775*d6b92ffaSHans Petter Selasky err = set_bind_wr(qp, wr->bind_mw.mw->type, 776*d6b92ffaSHans Petter Selasky wr->bind_mw.rkey, 777*d6b92ffaSHans Petter Selasky &wr->bind_mw.bind_info, 778*d6b92ffaSHans Petter Selasky ibqp->qp_num, &seg, &size); 779*d6b92ffaSHans Petter Selasky if (err) { 780*d6b92ffaSHans Petter Selasky *bad_wr = wr; 781*d6b92ffaSHans Petter Selasky goto out; 782*d6b92ffaSHans Petter Selasky } 783*d6b92ffaSHans Petter Selasky 784*d6b92ffaSHans Petter Selasky qp->sq.wr_data[idx] = IBV_WC_BIND_MW; 785*d6b92ffaSHans Petter Selasky break; 786*d6b92ffaSHans Petter Selasky case IBV_WR_LOCAL_INV: { 787*d6b92ffaSHans Petter Selasky struct ibv_mw_bind_info bind_info = {}; 788*d6b92ffaSHans Petter Selasky 789*d6b92ffaSHans Petter Selasky next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE; 790*d6b92ffaSHans Petter Selasky ctrl->imm = htobe32(wr->imm_data); 791*d6b92ffaSHans Petter Selasky err = set_bind_wr(qp, IBV_MW_TYPE_2, 0, 792*d6b92ffaSHans Petter Selasky &bind_info, ibqp->qp_num, 793*d6b92ffaSHans Petter Selasky &seg, &size); 794*d6b92ffaSHans Petter Selasky if (err) { 795*d6b92ffaSHans Petter Selasky *bad_wr = wr; 796*d6b92ffaSHans Petter Selasky goto out; 797*d6b92ffaSHans Petter Selasky } 798*d6b92ffaSHans Petter Selasky 799*d6b92ffaSHans Petter Selasky qp->sq.wr_data[idx] = IBV_WC_LOCAL_INV; 800*d6b92ffaSHans Petter Selasky break; 801*d6b92ffaSHans Petter Selasky } 802*d6b92ffaSHans Petter Selasky 803*d6b92ffaSHans Petter Selasky default: 804*d6b92ffaSHans Petter Selasky break; 805*d6b92ffaSHans Petter Selasky } 806*d6b92ffaSHans Petter Selasky break; 807*d6b92ffaSHans Petter Selasky 808*d6b92ffaSHans Petter Selasky case IBV_QPT_UD: 809*d6b92ffaSHans Petter Selasky set_datagram_seg(seg, wr); 810*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_datagram_seg); 811*d6b92ffaSHans Petter Selasky size += sizeof(struct mlx5_wqe_datagram_seg) / 16; 812*d6b92ffaSHans Petter Selasky if (unlikely((seg == qend))) 813*d6b92ffaSHans Petter Selasky seg = mlx5_get_send_wqe(qp, 0); 814*d6b92ffaSHans Petter Selasky break; 815*d6b92ffaSHans Petter Selasky 816*d6b92ffaSHans Petter Selasky case IBV_QPT_RAW_PACKET: 817*d6b92ffaSHans Petter Selasky memset(seg, 0, sizeof(struct mlx5_wqe_eth_seg)); 818*d6b92ffaSHans Petter Selasky eseg = seg; 819*d6b92ffaSHans Petter Selasky 820*d6b92ffaSHans Petter Selasky if (wr->send_flags & IBV_SEND_IP_CSUM) { 821*d6b92ffaSHans Petter Selasky if (!(qp->qp_cap_cache & MLX5_CSUM_SUPPORT_RAW_OVER_ETH)) { 822*d6b92ffaSHans Petter Selasky err = EINVAL; 823*d6b92ffaSHans Petter Selasky *bad_wr = wr; 824*d6b92ffaSHans Petter Selasky goto out; 825*d6b92ffaSHans Petter Selasky } 826*d6b92ffaSHans Petter Selasky 827*d6b92ffaSHans Petter Selasky eseg->cs_flags |= MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 828*d6b92ffaSHans Petter Selasky } 829*d6b92ffaSHans Petter Selasky 830*d6b92ffaSHans Petter Selasky if (wr->opcode == IBV_WR_TSO) { 831*d6b92ffaSHans Petter Selasky max_tso = qp->max_tso; 832*d6b92ffaSHans Petter Selasky err = set_tso_eth_seg(&seg, wr, qend, qp, &size); 833*d6b92ffaSHans Petter Selasky if (unlikely(err)) { 834*d6b92ffaSHans Petter Selasky *bad_wr = wr; 835*d6b92ffaSHans Petter Selasky goto out; 836*d6b92ffaSHans Petter Selasky } 837*d6b92ffaSHans Petter Selasky } else { 838*d6b92ffaSHans Petter Selasky err = copy_eth_inline_headers(ibqp, wr, seg, &sg_copy_ptr); 839*d6b92ffaSHans Petter Selasky if (unlikely(err)) { 840*d6b92ffaSHans Petter Selasky *bad_wr = wr; 841*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, 842*d6b92ffaSHans Petter Selasky "copy_eth_inline_headers failed, err: %d\n", 843*d6b92ffaSHans Petter Selasky err); 844*d6b92ffaSHans Petter Selasky goto out; 845*d6b92ffaSHans Petter Selasky } 846*d6b92ffaSHans Petter Selasky } 847*d6b92ffaSHans Petter Selasky 848*d6b92ffaSHans Petter Selasky seg += sizeof(struct mlx5_wqe_eth_seg); 849*d6b92ffaSHans Petter Selasky size += sizeof(struct mlx5_wqe_eth_seg) / 16; 850*d6b92ffaSHans Petter Selasky break; 851*d6b92ffaSHans Petter Selasky 852*d6b92ffaSHans Petter Selasky default: 853*d6b92ffaSHans Petter Selasky break; 854*d6b92ffaSHans Petter Selasky } 855*d6b92ffaSHans Petter Selasky 856*d6b92ffaSHans Petter Selasky if (wr->send_flags & IBV_SEND_INLINE && wr->num_sge) { 857*d6b92ffaSHans Petter Selasky int sz = 0; 858*d6b92ffaSHans Petter Selasky 859*d6b92ffaSHans Petter Selasky err = set_data_inl_seg(qp, wr, seg, &sz, &sg_copy_ptr); 860*d6b92ffaSHans Petter Selasky if (unlikely(err)) { 861*d6b92ffaSHans Petter Selasky *bad_wr = wr; 862*d6b92ffaSHans Petter Selasky mlx5_dbg(fp, MLX5_DBG_QP_SEND, 863*d6b92ffaSHans Petter Selasky "inline layout failed, err %d\n", err); 864*d6b92ffaSHans Petter Selasky goto out; 865*d6b92ffaSHans Petter Selasky } 866*d6b92ffaSHans Petter Selasky inl = 1; 867*d6b92ffaSHans Petter Selasky size += sz; 868*d6b92ffaSHans Petter Selasky } else { 869*d6b92ffaSHans Petter Selasky dpseg = seg; 870*d6b92ffaSHans Petter Selasky for (i = sg_copy_ptr.index; i < wr->num_sge; ++i) { 871*d6b92ffaSHans Petter Selasky if (unlikely(dpseg == qend)) { 872*d6b92ffaSHans Petter Selasky seg = mlx5_get_send_wqe(qp, 0); 873*d6b92ffaSHans Petter Selasky dpseg = seg; 874*d6b92ffaSHans Petter Selasky } 875*d6b92ffaSHans Petter Selasky if (likely(wr->sg_list[i].length)) { 876*d6b92ffaSHans Petter Selasky if (unlikely(wr->opcode == 877*d6b92ffaSHans Petter Selasky IBV_WR_ATOMIC_CMP_AND_SWP || 878*d6b92ffaSHans Petter Selasky wr->opcode == 879*d6b92ffaSHans Petter Selasky IBV_WR_ATOMIC_FETCH_AND_ADD)) 880*d6b92ffaSHans Petter Selasky set_data_ptr_seg_atomic(dpseg, wr->sg_list + i); 881*d6b92ffaSHans Petter Selasky else { 882*d6b92ffaSHans Petter Selasky if (unlikely(wr->opcode == IBV_WR_TSO)) { 883*d6b92ffaSHans Petter Selasky if (max_tso < wr->sg_list[i].length) { 884*d6b92ffaSHans Petter Selasky err = EINVAL; 885*d6b92ffaSHans Petter Selasky *bad_wr = wr; 886*d6b92ffaSHans Petter Selasky goto out; 887*d6b92ffaSHans Petter Selasky } 888*d6b92ffaSHans Petter Selasky max_tso -= wr->sg_list[i].length; 889*d6b92ffaSHans Petter Selasky } 890*d6b92ffaSHans Petter Selasky set_data_ptr_seg(dpseg, wr->sg_list + i, 891*d6b92ffaSHans Petter Selasky sg_copy_ptr.offset); 892*d6b92ffaSHans Petter Selasky } 893*d6b92ffaSHans Petter Selasky sg_copy_ptr.offset = 0; 894*d6b92ffaSHans Petter Selasky ++dpseg; 895*d6b92ffaSHans Petter Selasky size += sizeof(struct mlx5_wqe_data_seg) / 16; 896*d6b92ffaSHans Petter Selasky } 897*d6b92ffaSHans Petter Selasky } 898*d6b92ffaSHans Petter Selasky } 899*d6b92ffaSHans Petter Selasky 900*d6b92ffaSHans Petter Selasky mlx5_opcode = mlx5_ib_opcode[wr->opcode]; 901*d6b92ffaSHans Petter Selasky ctrl->opmod_idx_opcode = htobe32(((qp->sq.cur_post & 0xffff) << 8) | 902*d6b92ffaSHans Petter Selasky mlx5_opcode | 903*d6b92ffaSHans Petter Selasky (opmod << 24)); 904*d6b92ffaSHans Petter Selasky ctrl->qpn_ds = htobe32(size | (ibqp->qp_num << 8)); 905*d6b92ffaSHans Petter Selasky 906*d6b92ffaSHans Petter Selasky if (unlikely(qp->wq_sig)) 907*d6b92ffaSHans Petter Selasky ctrl->signature = wq_sig(ctrl); 908*d6b92ffaSHans Petter Selasky 909*d6b92ffaSHans Petter Selasky qp->sq.wrid[idx] = wr->wr_id; 910*d6b92ffaSHans Petter Selasky qp->sq.wqe_head[idx] = qp->sq.head + nreq; 911*d6b92ffaSHans Petter Selasky qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); 912*d6b92ffaSHans Petter Selasky 913*d6b92ffaSHans Petter Selasky #ifdef MLX5_DEBUG 914*d6b92ffaSHans Petter Selasky if (mlx5_debug_mask & MLX5_DBG_QP_SEND) 915*d6b92ffaSHans Petter Selasky dump_wqe(to_mctx(ibqp->context)->dbg_fp, idx, size, qp); 916*d6b92ffaSHans Petter Selasky #endif 917*d6b92ffaSHans Petter Selasky } 918*d6b92ffaSHans Petter Selasky 919*d6b92ffaSHans Petter Selasky out: 920*d6b92ffaSHans Petter Selasky if (likely(nreq)) { 921*d6b92ffaSHans Petter Selasky qp->sq.head += nreq; 922*d6b92ffaSHans Petter Selasky qp->fm_cache = next_fence; 923*d6b92ffaSHans Petter Selasky 924*d6b92ffaSHans Petter Selasky /* 925*d6b92ffaSHans Petter Selasky * Make sure that descriptors are written before 926*d6b92ffaSHans Petter Selasky * updating doorbell record and ringing the doorbell 927*d6b92ffaSHans Petter Selasky */ 928*d6b92ffaSHans Petter Selasky udma_to_device_barrier(); 929*d6b92ffaSHans Petter Selasky qp->db[MLX5_SND_DBR] = htobe32(qp->sq.cur_post & 0xffff); 930*d6b92ffaSHans Petter Selasky 931*d6b92ffaSHans Petter Selasky /* Make sure that the doorbell write happens before the memcpy 932*d6b92ffaSHans Petter Selasky * to WC memory below */ 933*d6b92ffaSHans Petter Selasky ctx = to_mctx(ibqp->context); 934*d6b92ffaSHans Petter Selasky if (bf->need_lock) 935*d6b92ffaSHans Petter Selasky mmio_wc_spinlock(&bf->lock.lock); 936*d6b92ffaSHans Petter Selasky else 937*d6b92ffaSHans Petter Selasky mmio_wc_start(); 938*d6b92ffaSHans Petter Selasky 939*d6b92ffaSHans Petter Selasky if (!ctx->shut_up_bf && nreq == 1 && bf->uuarn && 940*d6b92ffaSHans Petter Selasky (inl || ctx->prefer_bf) && size > 1 && 941*d6b92ffaSHans Petter Selasky size <= bf->buf_size / 16) 942*d6b92ffaSHans Petter Selasky mlx5_bf_copy(bf->reg + bf->offset, (unsigned long long *)ctrl, 943*d6b92ffaSHans Petter Selasky align(size * 16, 64), qp); 944*d6b92ffaSHans Petter Selasky else 945*d6b92ffaSHans Petter Selasky mlx5_write64((__be32 *)ctrl, bf->reg + bf->offset, 946*d6b92ffaSHans Petter Selasky &ctx->lock32); 947*d6b92ffaSHans Petter Selasky 948*d6b92ffaSHans Petter Selasky /* 949*d6b92ffaSHans Petter Selasky * use mmio_flush_writes() to ensure write combining buffers are flushed out 950*d6b92ffaSHans Petter Selasky * of the running CPU. This must be carried inside the spinlock. 951*d6b92ffaSHans Petter Selasky * Otherwise, there is a potential race. In the race, CPU A 952*d6b92ffaSHans Petter Selasky * writes doorbell 1, which is waiting in the WC buffer. CPU B 953*d6b92ffaSHans Petter Selasky * writes doorbell 2, and it's write is flushed earlier. Since 954*d6b92ffaSHans Petter Selasky * the mmio_flush_writes is CPU local, this will result in the HCA seeing 955*d6b92ffaSHans Petter Selasky * doorbell 2, followed by doorbell 1. 956*d6b92ffaSHans Petter Selasky * Flush before toggling bf_offset to be latency oriented. 957*d6b92ffaSHans Petter Selasky */ 958*d6b92ffaSHans Petter Selasky mmio_flush_writes(); 959*d6b92ffaSHans Petter Selasky bf->offset ^= bf->buf_size; 960*d6b92ffaSHans Petter Selasky if (bf->need_lock) 961*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&bf->lock); 962*d6b92ffaSHans Petter Selasky } 963*d6b92ffaSHans Petter Selasky 964*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&qp->sq.lock); 965*d6b92ffaSHans Petter Selasky 966*d6b92ffaSHans Petter Selasky return err; 967*d6b92ffaSHans Petter Selasky } 968*d6b92ffaSHans Petter Selasky 969*d6b92ffaSHans Petter Selasky int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, 970*d6b92ffaSHans Petter Selasky struct ibv_send_wr **bad_wr) 971*d6b92ffaSHans Petter Selasky { 972*d6b92ffaSHans Petter Selasky #ifdef MW_DEBUG 973*d6b92ffaSHans Petter Selasky if (wr->opcode == IBV_WR_BIND_MW) { 974*d6b92ffaSHans Petter Selasky if (wr->bind_mw.mw->type == IBV_MW_TYPE_1) 975*d6b92ffaSHans Petter Selasky return EINVAL; 976*d6b92ffaSHans Petter Selasky 977*d6b92ffaSHans Petter Selasky if (!wr->bind_mw.bind_info.mr || 978*d6b92ffaSHans Petter Selasky !wr->bind_mw.bind_info.addr || 979*d6b92ffaSHans Petter Selasky !wr->bind_mw.bind_info.length) 980*d6b92ffaSHans Petter Selasky return EINVAL; 981*d6b92ffaSHans Petter Selasky 982*d6b92ffaSHans Petter Selasky if (wr->bind_mw.bind_info.mr->pd != wr->bind_mw.mw->pd) 983*d6b92ffaSHans Petter Selasky return EINVAL; 984*d6b92ffaSHans Petter Selasky } 985*d6b92ffaSHans Petter Selasky #endif 986*d6b92ffaSHans Petter Selasky 987*d6b92ffaSHans Petter Selasky return _mlx5_post_send(ibqp, wr, bad_wr); 988*d6b92ffaSHans Petter Selasky } 989*d6b92ffaSHans Petter Selasky 990*d6b92ffaSHans Petter Selasky int mlx5_bind_mw(struct ibv_qp *qp, struct ibv_mw *mw, 991*d6b92ffaSHans Petter Selasky struct ibv_mw_bind *mw_bind) 992*d6b92ffaSHans Petter Selasky { 993*d6b92ffaSHans Petter Selasky struct ibv_mw_bind_info *bind_info = &mw_bind->bind_info; 994*d6b92ffaSHans Petter Selasky struct ibv_send_wr wr = {}; 995*d6b92ffaSHans Petter Selasky struct ibv_send_wr *bad_wr = NULL; 996*d6b92ffaSHans Petter Selasky int ret; 997*d6b92ffaSHans Petter Selasky 998*d6b92ffaSHans Petter Selasky if (!bind_info->mr && (bind_info->addr || bind_info->length)) { 999*d6b92ffaSHans Petter Selasky errno = EINVAL; 1000*d6b92ffaSHans Petter Selasky return errno; 1001*d6b92ffaSHans Petter Selasky } 1002*d6b92ffaSHans Petter Selasky 1003*d6b92ffaSHans Petter Selasky if (bind_info->mw_access_flags & IBV_ACCESS_ZERO_BASED) { 1004*d6b92ffaSHans Petter Selasky errno = EINVAL; 1005*d6b92ffaSHans Petter Selasky return errno; 1006*d6b92ffaSHans Petter Selasky } 1007*d6b92ffaSHans Petter Selasky 1008*d6b92ffaSHans Petter Selasky if (bind_info->mr) { 1009*d6b92ffaSHans Petter Selasky if (to_mmr(bind_info->mr)->alloc_flags & IBV_ACCESS_ZERO_BASED) { 1010*d6b92ffaSHans Petter Selasky errno = EINVAL; 1011*d6b92ffaSHans Petter Selasky return errno; 1012*d6b92ffaSHans Petter Selasky } 1013*d6b92ffaSHans Petter Selasky 1014*d6b92ffaSHans Petter Selasky if (mw->pd != bind_info->mr->pd) { 1015*d6b92ffaSHans Petter Selasky errno = EPERM; 1016*d6b92ffaSHans Petter Selasky return errno; 1017*d6b92ffaSHans Petter Selasky } 1018*d6b92ffaSHans Petter Selasky } 1019*d6b92ffaSHans Petter Selasky 1020*d6b92ffaSHans Petter Selasky wr.opcode = IBV_WR_BIND_MW; 1021*d6b92ffaSHans Petter Selasky wr.next = NULL; 1022*d6b92ffaSHans Petter Selasky wr.wr_id = mw_bind->wr_id; 1023*d6b92ffaSHans Petter Selasky wr.send_flags = mw_bind->send_flags; 1024*d6b92ffaSHans Petter Selasky wr.bind_mw.bind_info = mw_bind->bind_info; 1025*d6b92ffaSHans Petter Selasky wr.bind_mw.mw = mw; 1026*d6b92ffaSHans Petter Selasky wr.bind_mw.rkey = ibv_inc_rkey(mw->rkey); 1027*d6b92ffaSHans Petter Selasky 1028*d6b92ffaSHans Petter Selasky ret = _mlx5_post_send(qp, &wr, &bad_wr); 1029*d6b92ffaSHans Petter Selasky if (ret) 1030*d6b92ffaSHans Petter Selasky return ret; 1031*d6b92ffaSHans Petter Selasky 1032*d6b92ffaSHans Petter Selasky mw->rkey = wr.bind_mw.rkey; 1033*d6b92ffaSHans Petter Selasky 1034*d6b92ffaSHans Petter Selasky return 0; 1035*d6b92ffaSHans Petter Selasky } 1036*d6b92ffaSHans Petter Selasky 1037*d6b92ffaSHans Petter Selasky static void set_sig_seg(struct mlx5_qp *qp, struct mlx5_rwqe_sig *sig, 1038*d6b92ffaSHans Petter Selasky int size, uint16_t idx) 1039*d6b92ffaSHans Petter Selasky { 1040*d6b92ffaSHans Petter Selasky uint8_t sign; 1041*d6b92ffaSHans Petter Selasky uint32_t qpn = qp->ibv_qp->qp_num; 1042*d6b92ffaSHans Petter Selasky 1043*d6b92ffaSHans Petter Selasky sign = calc_sig(sig, size); 1044*d6b92ffaSHans Petter Selasky sign ^= calc_sig(&qpn, 4); 1045*d6b92ffaSHans Petter Selasky sign ^= calc_sig(&idx, 2); 1046*d6b92ffaSHans Petter Selasky sig->signature = sign; 1047*d6b92ffaSHans Petter Selasky } 1048*d6b92ffaSHans Petter Selasky 1049*d6b92ffaSHans Petter Selasky static void set_wq_sig_seg(struct mlx5_rwq *rwq, struct mlx5_rwqe_sig *sig, 1050*d6b92ffaSHans Petter Selasky int size, uint16_t idx) 1051*d6b92ffaSHans Petter Selasky { 1052*d6b92ffaSHans Petter Selasky uint8_t sign; 1053*d6b92ffaSHans Petter Selasky uint32_t qpn = rwq->wq.wq_num; 1054*d6b92ffaSHans Petter Selasky 1055*d6b92ffaSHans Petter Selasky sign = calc_sig(sig, size); 1056*d6b92ffaSHans Petter Selasky sign ^= calc_sig(&qpn, 4); 1057*d6b92ffaSHans Petter Selasky sign ^= calc_sig(&idx, 2); 1058*d6b92ffaSHans Petter Selasky sig->signature = sign; 1059*d6b92ffaSHans Petter Selasky } 1060*d6b92ffaSHans Petter Selasky 1061*d6b92ffaSHans Petter Selasky int mlx5_post_wq_recv(struct ibv_wq *ibwq, struct ibv_recv_wr *wr, 1062*d6b92ffaSHans Petter Selasky struct ibv_recv_wr **bad_wr) 1063*d6b92ffaSHans Petter Selasky { 1064*d6b92ffaSHans Petter Selasky struct mlx5_rwq *rwq = to_mrwq(ibwq); 1065*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *scat; 1066*d6b92ffaSHans Petter Selasky int err = 0; 1067*d6b92ffaSHans Petter Selasky int nreq; 1068*d6b92ffaSHans Petter Selasky int ind; 1069*d6b92ffaSHans Petter Selasky int i, j; 1070*d6b92ffaSHans Petter Selasky struct mlx5_rwqe_sig *sig; 1071*d6b92ffaSHans Petter Selasky 1072*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&rwq->rq.lock); 1073*d6b92ffaSHans Petter Selasky 1074*d6b92ffaSHans Petter Selasky ind = rwq->rq.head & (rwq->rq.wqe_cnt - 1); 1075*d6b92ffaSHans Petter Selasky 1076*d6b92ffaSHans Petter Selasky for (nreq = 0; wr; ++nreq, wr = wr->next) { 1077*d6b92ffaSHans Petter Selasky if (unlikely(mlx5_wq_overflow(&rwq->rq, nreq, 1078*d6b92ffaSHans Petter Selasky to_mcq(rwq->wq.cq)))) { 1079*d6b92ffaSHans Petter Selasky err = ENOMEM; 1080*d6b92ffaSHans Petter Selasky *bad_wr = wr; 1081*d6b92ffaSHans Petter Selasky goto out; 1082*d6b92ffaSHans Petter Selasky } 1083*d6b92ffaSHans Petter Selasky 1084*d6b92ffaSHans Petter Selasky if (unlikely(wr->num_sge > rwq->rq.max_gs)) { 1085*d6b92ffaSHans Petter Selasky err = EINVAL; 1086*d6b92ffaSHans Petter Selasky *bad_wr = wr; 1087*d6b92ffaSHans Petter Selasky goto out; 1088*d6b92ffaSHans Petter Selasky } 1089*d6b92ffaSHans Petter Selasky 1090*d6b92ffaSHans Petter Selasky scat = get_wq_recv_wqe(rwq, ind); 1091*d6b92ffaSHans Petter Selasky sig = (struct mlx5_rwqe_sig *)scat; 1092*d6b92ffaSHans Petter Selasky if (unlikely(rwq->wq_sig)) { 1093*d6b92ffaSHans Petter Selasky memset(sig, 0, 1 << rwq->rq.wqe_shift); 1094*d6b92ffaSHans Petter Selasky ++scat; 1095*d6b92ffaSHans Petter Selasky } 1096*d6b92ffaSHans Petter Selasky 1097*d6b92ffaSHans Petter Selasky for (i = 0, j = 0; i < wr->num_sge; ++i) { 1098*d6b92ffaSHans Petter Selasky if (unlikely(!wr->sg_list[i].length)) 1099*d6b92ffaSHans Petter Selasky continue; 1100*d6b92ffaSHans Petter Selasky set_data_ptr_seg(scat + j++, wr->sg_list + i, 0); 1101*d6b92ffaSHans Petter Selasky } 1102*d6b92ffaSHans Petter Selasky 1103*d6b92ffaSHans Petter Selasky if (j < rwq->rq.max_gs) { 1104*d6b92ffaSHans Petter Selasky scat[j].byte_count = 0; 1105*d6b92ffaSHans Petter Selasky scat[j].lkey = htobe32(MLX5_INVALID_LKEY); 1106*d6b92ffaSHans Petter Selasky scat[j].addr = 0; 1107*d6b92ffaSHans Petter Selasky } 1108*d6b92ffaSHans Petter Selasky 1109*d6b92ffaSHans Petter Selasky if (unlikely(rwq->wq_sig)) 1110*d6b92ffaSHans Petter Selasky set_wq_sig_seg(rwq, sig, (wr->num_sge + 1) << 4, 1111*d6b92ffaSHans Petter Selasky rwq->rq.head & 0xffff); 1112*d6b92ffaSHans Petter Selasky 1113*d6b92ffaSHans Petter Selasky rwq->rq.wrid[ind] = wr->wr_id; 1114*d6b92ffaSHans Petter Selasky 1115*d6b92ffaSHans Petter Selasky ind = (ind + 1) & (rwq->rq.wqe_cnt - 1); 1116*d6b92ffaSHans Petter Selasky } 1117*d6b92ffaSHans Petter Selasky 1118*d6b92ffaSHans Petter Selasky out: 1119*d6b92ffaSHans Petter Selasky if (likely(nreq)) { 1120*d6b92ffaSHans Petter Selasky rwq->rq.head += nreq; 1121*d6b92ffaSHans Petter Selasky /* 1122*d6b92ffaSHans Petter Selasky * Make sure that descriptors are written before 1123*d6b92ffaSHans Petter Selasky * doorbell record. 1124*d6b92ffaSHans Petter Selasky */ 1125*d6b92ffaSHans Petter Selasky udma_to_device_barrier(); 1126*d6b92ffaSHans Petter Selasky *(rwq->recv_db) = htobe32(rwq->rq.head & 0xffff); 1127*d6b92ffaSHans Petter Selasky } 1128*d6b92ffaSHans Petter Selasky 1129*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&rwq->rq.lock); 1130*d6b92ffaSHans Petter Selasky 1131*d6b92ffaSHans Petter Selasky return err; 1132*d6b92ffaSHans Petter Selasky } 1133*d6b92ffaSHans Petter Selasky 1134*d6b92ffaSHans Petter Selasky int mlx5_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, 1135*d6b92ffaSHans Petter Selasky struct ibv_recv_wr **bad_wr) 1136*d6b92ffaSHans Petter Selasky { 1137*d6b92ffaSHans Petter Selasky struct mlx5_qp *qp = to_mqp(ibqp); 1138*d6b92ffaSHans Petter Selasky struct mlx5_wqe_data_seg *scat; 1139*d6b92ffaSHans Petter Selasky int err = 0; 1140*d6b92ffaSHans Petter Selasky int nreq; 1141*d6b92ffaSHans Petter Selasky int ind; 1142*d6b92ffaSHans Petter Selasky int i, j; 1143*d6b92ffaSHans Petter Selasky struct mlx5_rwqe_sig *sig; 1144*d6b92ffaSHans Petter Selasky 1145*d6b92ffaSHans Petter Selasky mlx5_spin_lock(&qp->rq.lock); 1146*d6b92ffaSHans Petter Selasky 1147*d6b92ffaSHans Petter Selasky ind = qp->rq.head & (qp->rq.wqe_cnt - 1); 1148*d6b92ffaSHans Petter Selasky 1149*d6b92ffaSHans Petter Selasky for (nreq = 0; wr; ++nreq, wr = wr->next) { 1150*d6b92ffaSHans Petter Selasky if (unlikely(mlx5_wq_overflow(&qp->rq, nreq, 1151*d6b92ffaSHans Petter Selasky to_mcq(qp->ibv_qp->recv_cq)))) { 1152*d6b92ffaSHans Petter Selasky err = ENOMEM; 1153*d6b92ffaSHans Petter Selasky *bad_wr = wr; 1154*d6b92ffaSHans Petter Selasky goto out; 1155*d6b92ffaSHans Petter Selasky } 1156*d6b92ffaSHans Petter Selasky 1157*d6b92ffaSHans Petter Selasky if (unlikely(wr->num_sge > qp->rq.max_gs)) { 1158*d6b92ffaSHans Petter Selasky err = EINVAL; 1159*d6b92ffaSHans Petter Selasky *bad_wr = wr; 1160*d6b92ffaSHans Petter Selasky goto out; 1161*d6b92ffaSHans Petter Selasky } 1162*d6b92ffaSHans Petter Selasky 1163*d6b92ffaSHans Petter Selasky scat = get_recv_wqe(qp, ind); 1164*d6b92ffaSHans Petter Selasky sig = (struct mlx5_rwqe_sig *)scat; 1165*d6b92ffaSHans Petter Selasky if (unlikely(qp->wq_sig)) { 1166*d6b92ffaSHans Petter Selasky memset(sig, 0, 1 << qp->rq.wqe_shift); 1167*d6b92ffaSHans Petter Selasky ++scat; 1168*d6b92ffaSHans Petter Selasky } 1169*d6b92ffaSHans Petter Selasky 1170*d6b92ffaSHans Petter Selasky for (i = 0, j = 0; i < wr->num_sge; ++i) { 1171*d6b92ffaSHans Petter Selasky if (unlikely(!wr->sg_list[i].length)) 1172*d6b92ffaSHans Petter Selasky continue; 1173*d6b92ffaSHans Petter Selasky set_data_ptr_seg(scat + j++, wr->sg_list + i, 0); 1174*d6b92ffaSHans Petter Selasky } 1175*d6b92ffaSHans Petter Selasky 1176*d6b92ffaSHans Petter Selasky if (j < qp->rq.max_gs) { 1177*d6b92ffaSHans Petter Selasky scat[j].byte_count = 0; 1178*d6b92ffaSHans Petter Selasky scat[j].lkey = htobe32(MLX5_INVALID_LKEY); 1179*d6b92ffaSHans Petter Selasky scat[j].addr = 0; 1180*d6b92ffaSHans Petter Selasky } 1181*d6b92ffaSHans Petter Selasky 1182*d6b92ffaSHans Petter Selasky if (unlikely(qp->wq_sig)) 1183*d6b92ffaSHans Petter Selasky set_sig_seg(qp, sig, (wr->num_sge + 1) << 4, 1184*d6b92ffaSHans Petter Selasky qp->rq.head & 0xffff); 1185*d6b92ffaSHans Petter Selasky 1186*d6b92ffaSHans Petter Selasky qp->rq.wrid[ind] = wr->wr_id; 1187*d6b92ffaSHans Petter Selasky 1188*d6b92ffaSHans Petter Selasky ind = (ind + 1) & (qp->rq.wqe_cnt - 1); 1189*d6b92ffaSHans Petter Selasky } 1190*d6b92ffaSHans Petter Selasky 1191*d6b92ffaSHans Petter Selasky out: 1192*d6b92ffaSHans Petter Selasky if (likely(nreq)) { 1193*d6b92ffaSHans Petter Selasky qp->rq.head += nreq; 1194*d6b92ffaSHans Petter Selasky 1195*d6b92ffaSHans Petter Selasky /* 1196*d6b92ffaSHans Petter Selasky * Make sure that descriptors are written before 1197*d6b92ffaSHans Petter Selasky * doorbell record. 1198*d6b92ffaSHans Petter Selasky */ 1199*d6b92ffaSHans Petter Selasky udma_to_device_barrier(); 1200*d6b92ffaSHans Petter Selasky 1201*d6b92ffaSHans Petter Selasky /* 1202*d6b92ffaSHans Petter Selasky * For Raw Packet QP, avoid updating the doorbell record 1203*d6b92ffaSHans Petter Selasky * as long as the QP isn't in RTR state, to avoid receiving 1204*d6b92ffaSHans Petter Selasky * packets in illegal states. 1205*d6b92ffaSHans Petter Selasky * This is only for Raw Packet QPs since they are represented 1206*d6b92ffaSHans Petter Selasky * differently in the hardware. 1207*d6b92ffaSHans Petter Selasky */ 1208*d6b92ffaSHans Petter Selasky if (likely(!(ibqp->qp_type == IBV_QPT_RAW_PACKET && 1209*d6b92ffaSHans Petter Selasky ibqp->state < IBV_QPS_RTR))) 1210*d6b92ffaSHans Petter Selasky qp->db[MLX5_RCV_DBR] = htobe32(qp->rq.head & 0xffff); 1211*d6b92ffaSHans Petter Selasky } 1212*d6b92ffaSHans Petter Selasky 1213*d6b92ffaSHans Petter Selasky mlx5_spin_unlock(&qp->rq.lock); 1214*d6b92ffaSHans Petter Selasky 1215*d6b92ffaSHans Petter Selasky return err; 1216*d6b92ffaSHans Petter Selasky } 1217*d6b92ffaSHans Petter Selasky 1218*d6b92ffaSHans Petter Selasky int mlx5_use_huge(const char *key) 1219*d6b92ffaSHans Petter Selasky { 1220*d6b92ffaSHans Petter Selasky char *e; 1221*d6b92ffaSHans Petter Selasky e = getenv(key); 1222*d6b92ffaSHans Petter Selasky if (e && !strcmp(e, "y")) 1223*d6b92ffaSHans Petter Selasky return 1; 1224*d6b92ffaSHans Petter Selasky 1225*d6b92ffaSHans Petter Selasky return 0; 1226*d6b92ffaSHans Petter Selasky } 1227*d6b92ffaSHans Petter Selasky 1228*d6b92ffaSHans Petter Selasky struct mlx5_qp *mlx5_find_qp(struct mlx5_context *ctx, uint32_t qpn) 1229*d6b92ffaSHans Petter Selasky { 1230*d6b92ffaSHans Petter Selasky int tind = qpn >> MLX5_QP_TABLE_SHIFT; 1231*d6b92ffaSHans Petter Selasky 1232*d6b92ffaSHans Petter Selasky if (ctx->qp_table[tind].refcnt) 1233*d6b92ffaSHans Petter Selasky return ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK]; 1234*d6b92ffaSHans Petter Selasky else 1235*d6b92ffaSHans Petter Selasky return NULL; 1236*d6b92ffaSHans Petter Selasky } 1237*d6b92ffaSHans Petter Selasky 1238*d6b92ffaSHans Petter Selasky int mlx5_store_qp(struct mlx5_context *ctx, uint32_t qpn, struct mlx5_qp *qp) 1239*d6b92ffaSHans Petter Selasky { 1240*d6b92ffaSHans Petter Selasky int tind = qpn >> MLX5_QP_TABLE_SHIFT; 1241*d6b92ffaSHans Petter Selasky 1242*d6b92ffaSHans Petter Selasky if (!ctx->qp_table[tind].refcnt) { 1243*d6b92ffaSHans Petter Selasky ctx->qp_table[tind].table = calloc(MLX5_QP_TABLE_MASK + 1, 1244*d6b92ffaSHans Petter Selasky sizeof(struct mlx5_qp *)); 1245*d6b92ffaSHans Petter Selasky if (!ctx->qp_table[tind].table) 1246*d6b92ffaSHans Petter Selasky return -1; 1247*d6b92ffaSHans Petter Selasky } 1248*d6b92ffaSHans Petter Selasky 1249*d6b92ffaSHans Petter Selasky ++ctx->qp_table[tind].refcnt; 1250*d6b92ffaSHans Petter Selasky ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK] = qp; 1251*d6b92ffaSHans Petter Selasky return 0; 1252*d6b92ffaSHans Petter Selasky } 1253*d6b92ffaSHans Petter Selasky 1254*d6b92ffaSHans Petter Selasky void mlx5_clear_qp(struct mlx5_context *ctx, uint32_t qpn) 1255*d6b92ffaSHans Petter Selasky { 1256*d6b92ffaSHans Petter Selasky int tind = qpn >> MLX5_QP_TABLE_SHIFT; 1257*d6b92ffaSHans Petter Selasky 1258*d6b92ffaSHans Petter Selasky if (!--ctx->qp_table[tind].refcnt) 1259*d6b92ffaSHans Petter Selasky free(ctx->qp_table[tind].table); 1260*d6b92ffaSHans Petter Selasky else 1261*d6b92ffaSHans Petter Selasky ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK] = NULL; 1262*d6b92ffaSHans Petter Selasky } 1263