162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB 262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2021 Intel Corporation */ 362306a36Sopenharmony_ci#include "osdep.h" 462306a36Sopenharmony_ci#include "defs.h" 562306a36Sopenharmony_ci#include "user.h" 662306a36Sopenharmony_ci#include "irdma.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/** 962306a36Sopenharmony_ci * irdma_set_fragment - set fragment in wqe 1062306a36Sopenharmony_ci * @wqe: wqe for setting fragment 1162306a36Sopenharmony_ci * @offset: offset value 1262306a36Sopenharmony_ci * @sge: sge length and stag 1362306a36Sopenharmony_ci * @valid: The wqe valid 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_cistatic void irdma_set_fragment(__le64 *wqe, u32 offset, struct ib_sge *sge, 1662306a36Sopenharmony_ci u8 valid) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci if (sge) { 1962306a36Sopenharmony_ci set_64bit_val(wqe, offset, 2062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_TO, sge->addr)); 2162306a36Sopenharmony_ci set_64bit_val(wqe, offset + 8, 2262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, valid) | 2362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_LEN, sge->length) | 2462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_STAG, sge->lkey)); 2562306a36Sopenharmony_ci } else { 2662306a36Sopenharmony_ci set_64bit_val(wqe, offset, 0); 2762306a36Sopenharmony_ci set_64bit_val(wqe, offset + 8, 2862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, valid)); 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/** 3362306a36Sopenharmony_ci * irdma_set_fragment_gen_1 - set fragment in wqe 3462306a36Sopenharmony_ci * @wqe: wqe for setting fragment 3562306a36Sopenharmony_ci * @offset: offset value 3662306a36Sopenharmony_ci * @sge: sge length and stag 3762306a36Sopenharmony_ci * @valid: wqe valid flag 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic void irdma_set_fragment_gen_1(__le64 *wqe, u32 offset, 4062306a36Sopenharmony_ci struct ib_sge *sge, u8 valid) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci if (sge) { 4362306a36Sopenharmony_ci set_64bit_val(wqe, offset, 4462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_TO, sge->addr)); 4562306a36Sopenharmony_ci set_64bit_val(wqe, offset + 8, 4662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, sge->length) | 4762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_STAG, sge->lkey)); 4862306a36Sopenharmony_ci } else { 4962306a36Sopenharmony_ci set_64bit_val(wqe, offset, 0); 5062306a36Sopenharmony_ci set_64bit_val(wqe, offset + 8, 0); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/** 5562306a36Sopenharmony_ci * irdma_nop_1 - insert a NOP wqe 5662306a36Sopenharmony_ci * @qp: hw qp ptr 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistatic int irdma_nop_1(struct irdma_qp_uk *qp) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci u64 hdr; 6162306a36Sopenharmony_ci __le64 *wqe; 6262306a36Sopenharmony_ci u32 wqe_idx; 6362306a36Sopenharmony_ci bool signaled = false; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!qp->sq_ring.head) 6662306a36Sopenharmony_ci return -EINVAL; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); 6962306a36Sopenharmony_ci wqe = qp->sq_base[wqe_idx].elem; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci qp->sq_wrtrk_array[wqe_idx].quanta = IRDMA_QP_WQE_MIN_QUANTA; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci set_64bit_val(wqe, 0, 0); 7462306a36Sopenharmony_ci set_64bit_val(wqe, 8, 0); 7562306a36Sopenharmony_ci set_64bit_val(wqe, 16, 0); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_NOP) | 7862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, signaled) | 7962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* make sure WQE is written before valid bit is set */ 8262306a36Sopenharmony_ci dma_wmb(); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * irdma_clr_wqes - clear next 128 sq entries 9162306a36Sopenharmony_ci * @qp: hw qp ptr 9262306a36Sopenharmony_ci * @qp_wqe_idx: wqe_idx 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_civoid irdma_clr_wqes(struct irdma_qp_uk *qp, u32 qp_wqe_idx) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct irdma_qp_quanta *sq; 9762306a36Sopenharmony_ci u32 wqe_idx; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!(qp_wqe_idx & 0x7F)) { 10062306a36Sopenharmony_ci wqe_idx = (qp_wqe_idx + 128) % qp->sq_ring.size; 10162306a36Sopenharmony_ci sq = qp->sq_base + wqe_idx; 10262306a36Sopenharmony_ci if (wqe_idx) 10362306a36Sopenharmony_ci memset(sq, qp->swqe_polarity ? 0 : 0xFF, 10462306a36Sopenharmony_ci 128 * sizeof(*sq)); 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci memset(sq, qp->swqe_polarity ? 0xFF : 0, 10762306a36Sopenharmony_ci 128 * sizeof(*sq)); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/** 11262306a36Sopenharmony_ci * irdma_uk_qp_post_wr - ring doorbell 11362306a36Sopenharmony_ci * @qp: hw qp ptr 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_civoid irdma_uk_qp_post_wr(struct irdma_qp_uk *qp) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci u64 temp; 11862306a36Sopenharmony_ci u32 hw_sq_tail; 11962306a36Sopenharmony_ci u32 sw_sq_head; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* valid bit is written and loads completed before reading shadow */ 12262306a36Sopenharmony_ci mb(); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* read the doorbell shadow area */ 12562306a36Sopenharmony_ci get_64bit_val(qp->shadow_area, 0, &temp); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci hw_sq_tail = (u32)FIELD_GET(IRDMA_QP_DBSA_HW_SQ_TAIL, temp); 12862306a36Sopenharmony_ci sw_sq_head = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); 12962306a36Sopenharmony_ci if (sw_sq_head != qp->initial_ring.head) { 13062306a36Sopenharmony_ci if (sw_sq_head != hw_sq_tail) { 13162306a36Sopenharmony_ci if (sw_sq_head > qp->initial_ring.head) { 13262306a36Sopenharmony_ci if (hw_sq_tail >= qp->initial_ring.head && 13362306a36Sopenharmony_ci hw_sq_tail < sw_sq_head) 13462306a36Sopenharmony_ci writel(qp->qp_id, qp->wqe_alloc_db); 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci if (hw_sq_tail >= qp->initial_ring.head || 13762306a36Sopenharmony_ci hw_sq_tail < sw_sq_head) 13862306a36Sopenharmony_ci writel(qp->qp_id, qp->wqe_alloc_db); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci qp->initial_ring.head = qp->sq_ring.head; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/** 14762306a36Sopenharmony_ci * irdma_qp_get_next_send_wqe - pad with NOP if needed, return where next WR should go 14862306a36Sopenharmony_ci * @qp: hw qp ptr 14962306a36Sopenharmony_ci * @wqe_idx: return wqe index 15062306a36Sopenharmony_ci * @quanta: size of WR in quanta 15162306a36Sopenharmony_ci * @total_size: size of WR in bytes 15262306a36Sopenharmony_ci * @info: info on WR 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci__le64 *irdma_qp_get_next_send_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx, 15562306a36Sopenharmony_ci u16 quanta, u32 total_size, 15662306a36Sopenharmony_ci struct irdma_post_sq_info *info) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci __le64 *wqe; 15962306a36Sopenharmony_ci __le64 *wqe_0 = NULL; 16062306a36Sopenharmony_ci u16 avail_quanta; 16162306a36Sopenharmony_ci u16 i; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci avail_quanta = qp->uk_attrs->max_hw_sq_chunk - 16462306a36Sopenharmony_ci (IRDMA_RING_CURRENT_HEAD(qp->sq_ring) % 16562306a36Sopenharmony_ci qp->uk_attrs->max_hw_sq_chunk); 16662306a36Sopenharmony_ci if (quanta <= avail_quanta) { 16762306a36Sopenharmony_ci /* WR fits in current chunk */ 16862306a36Sopenharmony_ci if (quanta > IRDMA_SQ_RING_FREE_QUANTA(qp->sq_ring)) 16962306a36Sopenharmony_ci return NULL; 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci /* Need to pad with NOP */ 17262306a36Sopenharmony_ci if (quanta + avail_quanta > 17362306a36Sopenharmony_ci IRDMA_SQ_RING_FREE_QUANTA(qp->sq_ring)) 17462306a36Sopenharmony_ci return NULL; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci for (i = 0; i < avail_quanta; i++) { 17762306a36Sopenharmony_ci irdma_nop_1(qp); 17862306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(qp->sq_ring); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci *wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); 18362306a36Sopenharmony_ci if (!*wqe_idx) 18462306a36Sopenharmony_ci qp->swqe_polarity = !qp->swqe_polarity; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->sq_ring, quanta); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci wqe = qp->sq_base[*wqe_idx].elem; 18962306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_1 && quanta == 1 && 19062306a36Sopenharmony_ci (IRDMA_RING_CURRENT_HEAD(qp->sq_ring) & 1)) { 19162306a36Sopenharmony_ci wqe_0 = qp->sq_base[IRDMA_RING_CURRENT_HEAD(qp->sq_ring)].elem; 19262306a36Sopenharmony_ci wqe_0[3] = cpu_to_le64(FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity ? 0 : 1)); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci qp->sq_wrtrk_array[*wqe_idx].wrid = info->wr_id; 19562306a36Sopenharmony_ci qp->sq_wrtrk_array[*wqe_idx].wr_len = total_size; 19662306a36Sopenharmony_ci qp->sq_wrtrk_array[*wqe_idx].quanta = quanta; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return wqe; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * irdma_qp_get_next_recv_wqe - get next qp's rcv wqe 20362306a36Sopenharmony_ci * @qp: hw qp ptr 20462306a36Sopenharmony_ci * @wqe_idx: return wqe index 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci__le64 *irdma_qp_get_next_recv_wqe(struct irdma_qp_uk *qp, u32 *wqe_idx) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci __le64 *wqe; 20962306a36Sopenharmony_ci int ret_code; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (IRDMA_RING_FULL_ERR(qp->rq_ring)) 21262306a36Sopenharmony_ci return NULL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci IRDMA_ATOMIC_RING_MOVE_HEAD(qp->rq_ring, *wqe_idx, ret_code); 21562306a36Sopenharmony_ci if (ret_code) 21662306a36Sopenharmony_ci return NULL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (!*wqe_idx) 21962306a36Sopenharmony_ci qp->rwqe_polarity = !qp->rwqe_polarity; 22062306a36Sopenharmony_ci /* rq_wqe_size_multiplier is no of 32 byte quanta in one rq wqe */ 22162306a36Sopenharmony_ci wqe = qp->rq_base[*wqe_idx * qp->rq_wqe_size_multiplier].elem; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return wqe; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/** 22762306a36Sopenharmony_ci * irdma_uk_rdma_write - rdma write operation 22862306a36Sopenharmony_ci * @qp: hw qp ptr 22962306a36Sopenharmony_ci * @info: post sq information 23062306a36Sopenharmony_ci * @post_sq: flag to post sq 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ciint irdma_uk_rdma_write(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, 23362306a36Sopenharmony_ci bool post_sq) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci u64 hdr; 23662306a36Sopenharmony_ci __le64 *wqe; 23762306a36Sopenharmony_ci struct irdma_rdma_write *op_info; 23862306a36Sopenharmony_ci u32 i, wqe_idx; 23962306a36Sopenharmony_ci u32 total_size = 0, byte_off; 24062306a36Sopenharmony_ci int ret_code; 24162306a36Sopenharmony_ci u32 frag_cnt, addl_frag_cnt; 24262306a36Sopenharmony_ci bool read_fence = false; 24362306a36Sopenharmony_ci u16 quanta; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci op_info = &info->op.rdma_write; 24662306a36Sopenharmony_ci if (op_info->num_lo_sges > qp->max_sq_frag_cnt) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < op_info->num_lo_sges; i++) 25062306a36Sopenharmony_ci total_size += op_info->lo_sg_list[i].length; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci read_fence |= info->read_fence; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (info->imm_data_valid) 25562306a36Sopenharmony_ci frag_cnt = op_info->num_lo_sges + 1; 25662306a36Sopenharmony_ci else 25762306a36Sopenharmony_ci frag_cnt = op_info->num_lo_sges; 25862306a36Sopenharmony_ci addl_frag_cnt = frag_cnt > 1 ? (frag_cnt - 1) : 0; 25962306a36Sopenharmony_ci ret_code = irdma_fragcnt_to_quanta_sq(frag_cnt, &quanta); 26062306a36Sopenharmony_ci if (ret_code) 26162306a36Sopenharmony_ci return ret_code; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size, 26462306a36Sopenharmony_ci info); 26562306a36Sopenharmony_ci if (!wqe) 26662306a36Sopenharmony_ci return -ENOMEM; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci set_64bit_val(wqe, 16, 27162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.addr)); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (info->imm_data_valid) { 27462306a36Sopenharmony_ci set_64bit_val(wqe, 0, 27562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data)); 27662306a36Sopenharmony_ci i = 0; 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, 0, 27962306a36Sopenharmony_ci op_info->lo_sg_list, 28062306a36Sopenharmony_ci qp->swqe_polarity); 28162306a36Sopenharmony_ci i = 1; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci for (byte_off = 32; i < op_info->num_lo_sges; i++) { 28562306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, 28662306a36Sopenharmony_ci &op_info->lo_sg_list[i], 28762306a36Sopenharmony_ci qp->swqe_polarity); 28862306a36Sopenharmony_ci byte_off += 16; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* if not an odd number set valid bit in next fragment */ 29262306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(frag_cnt & 0x01) && 29362306a36Sopenharmony_ci frag_cnt) { 29462306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL, 29562306a36Sopenharmony_ci qp->swqe_polarity); 29662306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_2) 29762306a36Sopenharmony_ci ++addl_frag_cnt; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.lkey) | 30162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) | 30262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid) | 30362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt) | 30462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | 30562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | 30662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | 30762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 30862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (post_sq) 31562306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/** 32162306a36Sopenharmony_ci * irdma_uk_rdma_read - rdma read command 32262306a36Sopenharmony_ci * @qp: hw qp ptr 32362306a36Sopenharmony_ci * @info: post sq information 32462306a36Sopenharmony_ci * @inv_stag: flag for inv_stag 32562306a36Sopenharmony_ci * @post_sq: flag to post sq 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ciint irdma_uk_rdma_read(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, 32862306a36Sopenharmony_ci bool inv_stag, bool post_sq) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct irdma_rdma_read *op_info; 33162306a36Sopenharmony_ci int ret_code; 33262306a36Sopenharmony_ci u32 i, byte_off, total_size = 0; 33362306a36Sopenharmony_ci bool local_fence = false; 33462306a36Sopenharmony_ci u32 addl_frag_cnt; 33562306a36Sopenharmony_ci __le64 *wqe; 33662306a36Sopenharmony_ci u32 wqe_idx; 33762306a36Sopenharmony_ci u16 quanta; 33862306a36Sopenharmony_ci u64 hdr; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci op_info = &info->op.rdma_read; 34162306a36Sopenharmony_ci if (qp->max_sq_frag_cnt < op_info->num_lo_sges) 34262306a36Sopenharmony_ci return -EINVAL; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci for (i = 0; i < op_info->num_lo_sges; i++) 34562306a36Sopenharmony_ci total_size += op_info->lo_sg_list[i].length; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ret_code = irdma_fragcnt_to_quanta_sq(op_info->num_lo_sges, &quanta); 34862306a36Sopenharmony_ci if (ret_code) 34962306a36Sopenharmony_ci return ret_code; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size, 35262306a36Sopenharmony_ci info); 35362306a36Sopenharmony_ci if (!wqe) 35462306a36Sopenharmony_ci return -ENOMEM; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci addl_frag_cnt = op_info->num_lo_sges > 1 ? 35962306a36Sopenharmony_ci (op_info->num_lo_sges - 1) : 0; 36062306a36Sopenharmony_ci local_fence |= info->local_fence; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, 0, op_info->lo_sg_list, 36362306a36Sopenharmony_ci qp->swqe_polarity); 36462306a36Sopenharmony_ci for (i = 1, byte_off = 32; i < op_info->num_lo_sges; ++i) { 36562306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, 36662306a36Sopenharmony_ci &op_info->lo_sg_list[i], 36762306a36Sopenharmony_ci qp->swqe_polarity); 36862306a36Sopenharmony_ci byte_off += 16; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* if not an odd number set valid bit in next fragment */ 37262306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && 37362306a36Sopenharmony_ci !(op_info->num_lo_sges & 0x01) && op_info->num_lo_sges) { 37462306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL, 37562306a36Sopenharmony_ci qp->swqe_polarity); 37662306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_2) 37762306a36Sopenharmony_ci ++addl_frag_cnt; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci set_64bit_val(wqe, 16, 38062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.addr)); 38162306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.lkey) | 38262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) | 38362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | 38462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_OPCODE, 38562306a36Sopenharmony_ci (inv_stag ? IRDMAQP_OP_RDMA_READ_LOC_INV : IRDMAQP_OP_RDMA_READ)) | 38662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) | 38762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) | 38862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 38962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (post_sq) 39662306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/** 40262306a36Sopenharmony_ci * irdma_uk_send - rdma send command 40362306a36Sopenharmony_ci * @qp: hw qp ptr 40462306a36Sopenharmony_ci * @info: post sq information 40562306a36Sopenharmony_ci * @post_sq: flag to post sq 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ciint irdma_uk_send(struct irdma_qp_uk *qp, struct irdma_post_sq_info *info, 40862306a36Sopenharmony_ci bool post_sq) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci __le64 *wqe; 41162306a36Sopenharmony_ci struct irdma_post_send *op_info; 41262306a36Sopenharmony_ci u64 hdr; 41362306a36Sopenharmony_ci u32 i, wqe_idx, total_size = 0, byte_off; 41462306a36Sopenharmony_ci int ret_code; 41562306a36Sopenharmony_ci u32 frag_cnt, addl_frag_cnt; 41662306a36Sopenharmony_ci bool read_fence = false; 41762306a36Sopenharmony_ci u16 quanta; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci op_info = &info->op.send; 42062306a36Sopenharmony_ci if (qp->max_sq_frag_cnt < op_info->num_sges) 42162306a36Sopenharmony_ci return -EINVAL; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci for (i = 0; i < op_info->num_sges; i++) 42462306a36Sopenharmony_ci total_size += op_info->sg_list[i].length; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (info->imm_data_valid) 42762306a36Sopenharmony_ci frag_cnt = op_info->num_sges + 1; 42862306a36Sopenharmony_ci else 42962306a36Sopenharmony_ci frag_cnt = op_info->num_sges; 43062306a36Sopenharmony_ci ret_code = irdma_fragcnt_to_quanta_sq(frag_cnt, &quanta); 43162306a36Sopenharmony_ci if (ret_code) 43262306a36Sopenharmony_ci return ret_code; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size, 43562306a36Sopenharmony_ci info); 43662306a36Sopenharmony_ci if (!wqe) 43762306a36Sopenharmony_ci return -ENOMEM; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci read_fence |= info->read_fence; 44262306a36Sopenharmony_ci addl_frag_cnt = frag_cnt > 1 ? (frag_cnt - 1) : 0; 44362306a36Sopenharmony_ci if (info->imm_data_valid) { 44462306a36Sopenharmony_ci set_64bit_val(wqe, 0, 44562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data)); 44662306a36Sopenharmony_ci i = 0; 44762306a36Sopenharmony_ci } else { 44862306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, 0, 44962306a36Sopenharmony_ci frag_cnt ? op_info->sg_list : NULL, 45062306a36Sopenharmony_ci qp->swqe_polarity); 45162306a36Sopenharmony_ci i = 1; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci for (byte_off = 32; i < op_info->num_sges; i++) { 45562306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, &op_info->sg_list[i], 45662306a36Sopenharmony_ci qp->swqe_polarity); 45762306a36Sopenharmony_ci byte_off += 16; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* if not an odd number set valid bit in next fragment */ 46162306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(frag_cnt & 0x01) && 46262306a36Sopenharmony_ci frag_cnt) { 46362306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL, 46462306a36Sopenharmony_ci qp->swqe_polarity); 46562306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_2) 46662306a36Sopenharmony_ci ++addl_frag_cnt; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci set_64bit_val(wqe, 16, 47062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_DESTQKEY, op_info->qkey) | 47162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_DESTQPN, op_info->dest_qp)); 47262306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, info->stag_to_inv) | 47362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_AHID, op_info->ah_id) | 47462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, 47562306a36Sopenharmony_ci (info->imm_data_valid ? 1 : 0)) | 47662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) | 47762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) | 47862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | 47962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | 48062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | 48162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 48262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_UDPHEADER, info->udp_hdr) | 48362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_L4LEN, info->l4len) | 48462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (post_sq) 49162306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/** 49762306a36Sopenharmony_ci * irdma_set_mw_bind_wqe_gen_1 - set mw bind wqe 49862306a36Sopenharmony_ci * @wqe: wqe for setting fragment 49962306a36Sopenharmony_ci * @op_info: info for setting bind wqe values 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_cistatic void irdma_set_mw_bind_wqe_gen_1(__le64 *wqe, 50262306a36Sopenharmony_ci struct irdma_bind_window *op_info) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci set_64bit_val(wqe, 0, (uintptr_t)op_info->va); 50562306a36Sopenharmony_ci set_64bit_val(wqe, 8, 50662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_PARENTMRSTAG, op_info->mw_stag) | 50762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_MWSTAG, op_info->mr_stag)); 50862306a36Sopenharmony_ci set_64bit_val(wqe, 16, op_info->bind_len); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/** 51262306a36Sopenharmony_ci * irdma_copy_inline_data_gen_1 - Copy inline data to wqe 51362306a36Sopenharmony_ci * @wqe: pointer to wqe 51462306a36Sopenharmony_ci * @sge_list: table of pointers to inline data 51562306a36Sopenharmony_ci * @num_sges: Total inline data length 51662306a36Sopenharmony_ci * @polarity: compatibility parameter 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_cistatic void irdma_copy_inline_data_gen_1(u8 *wqe, struct ib_sge *sge_list, 51962306a36Sopenharmony_ci u32 num_sges, u8 polarity) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci u32 quanta_bytes_remaining = 16; 52262306a36Sopenharmony_ci int i; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci for (i = 0; i < num_sges; i++) { 52562306a36Sopenharmony_ci u8 *cur_sge = (u8 *)(uintptr_t)sge_list[i].addr; 52662306a36Sopenharmony_ci u32 sge_len = sge_list[i].length; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci while (sge_len) { 52962306a36Sopenharmony_ci u32 bytes_copied; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci bytes_copied = min(sge_len, quanta_bytes_remaining); 53262306a36Sopenharmony_ci memcpy(wqe, cur_sge, bytes_copied); 53362306a36Sopenharmony_ci wqe += bytes_copied; 53462306a36Sopenharmony_ci cur_sge += bytes_copied; 53562306a36Sopenharmony_ci quanta_bytes_remaining -= bytes_copied; 53662306a36Sopenharmony_ci sge_len -= bytes_copied; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (!quanta_bytes_remaining) { 53962306a36Sopenharmony_ci /* Remaining inline bytes reside after hdr */ 54062306a36Sopenharmony_ci wqe += 16; 54162306a36Sopenharmony_ci quanta_bytes_remaining = 32; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci/** 54862306a36Sopenharmony_ci * irdma_inline_data_size_to_quanta_gen_1 - based on inline data, quanta 54962306a36Sopenharmony_ci * @data_size: data size for inline 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * Gets the quanta based on inline and immediate data. 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_cistatic inline u16 irdma_inline_data_size_to_quanta_gen_1(u32 data_size) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci return data_size <= 16 ? IRDMA_QP_WQE_MIN_QUANTA : 2; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/** 55962306a36Sopenharmony_ci * irdma_set_mw_bind_wqe - set mw bind in wqe 56062306a36Sopenharmony_ci * @wqe: wqe for setting mw bind 56162306a36Sopenharmony_ci * @op_info: info for setting wqe values 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_cistatic void irdma_set_mw_bind_wqe(__le64 *wqe, 56462306a36Sopenharmony_ci struct irdma_bind_window *op_info) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci set_64bit_val(wqe, 0, (uintptr_t)op_info->va); 56762306a36Sopenharmony_ci set_64bit_val(wqe, 8, 56862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_PARENTMRSTAG, op_info->mr_stag) | 56962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_MWSTAG, op_info->mw_stag)); 57062306a36Sopenharmony_ci set_64bit_val(wqe, 16, op_info->bind_len); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * irdma_copy_inline_data - Copy inline data to wqe 57562306a36Sopenharmony_ci * @wqe: pointer to wqe 57662306a36Sopenharmony_ci * @sge_list: table of pointers to inline data 57762306a36Sopenharmony_ci * @num_sges: number of SGE's 57862306a36Sopenharmony_ci * @polarity: polarity of wqe valid bit 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_cistatic void irdma_copy_inline_data(u8 *wqe, struct ib_sge *sge_list, 58162306a36Sopenharmony_ci u32 num_sges, u8 polarity) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci u8 inline_valid = polarity << IRDMA_INLINE_VALID_S; 58462306a36Sopenharmony_ci u32 quanta_bytes_remaining = 8; 58562306a36Sopenharmony_ci bool first_quanta = true; 58662306a36Sopenharmony_ci int i; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci wqe += 8; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci for (i = 0; i < num_sges; i++) { 59162306a36Sopenharmony_ci u8 *cur_sge = (u8 *)(uintptr_t)sge_list[i].addr; 59262306a36Sopenharmony_ci u32 sge_len = sge_list[i].length; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci while (sge_len) { 59562306a36Sopenharmony_ci u32 bytes_copied; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci bytes_copied = min(sge_len, quanta_bytes_remaining); 59862306a36Sopenharmony_ci memcpy(wqe, cur_sge, bytes_copied); 59962306a36Sopenharmony_ci wqe += bytes_copied; 60062306a36Sopenharmony_ci cur_sge += bytes_copied; 60162306a36Sopenharmony_ci quanta_bytes_remaining -= bytes_copied; 60262306a36Sopenharmony_ci sge_len -= bytes_copied; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!quanta_bytes_remaining) { 60562306a36Sopenharmony_ci quanta_bytes_remaining = 31; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Remaining inline bytes reside after hdr */ 60862306a36Sopenharmony_ci if (first_quanta) { 60962306a36Sopenharmony_ci first_quanta = false; 61062306a36Sopenharmony_ci wqe += 16; 61162306a36Sopenharmony_ci } else { 61262306a36Sopenharmony_ci *wqe = inline_valid; 61362306a36Sopenharmony_ci wqe++; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci if (!first_quanta && quanta_bytes_remaining < 31) 61962306a36Sopenharmony_ci *(wqe + quanta_bytes_remaining) = inline_valid; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/** 62362306a36Sopenharmony_ci * irdma_inline_data_size_to_quanta - based on inline data, quanta 62462306a36Sopenharmony_ci * @data_size: data size for inline 62562306a36Sopenharmony_ci * 62662306a36Sopenharmony_ci * Gets the quanta based on inline and immediate data. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_cistatic u16 irdma_inline_data_size_to_quanta(u32 data_size) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci if (data_size <= 8) 63162306a36Sopenharmony_ci return IRDMA_QP_WQE_MIN_QUANTA; 63262306a36Sopenharmony_ci else if (data_size <= 39) 63362306a36Sopenharmony_ci return 2; 63462306a36Sopenharmony_ci else if (data_size <= 70) 63562306a36Sopenharmony_ci return 3; 63662306a36Sopenharmony_ci else if (data_size <= 101) 63762306a36Sopenharmony_ci return 4; 63862306a36Sopenharmony_ci else if (data_size <= 132) 63962306a36Sopenharmony_ci return 5; 64062306a36Sopenharmony_ci else if (data_size <= 163) 64162306a36Sopenharmony_ci return 6; 64262306a36Sopenharmony_ci else if (data_size <= 194) 64362306a36Sopenharmony_ci return 7; 64462306a36Sopenharmony_ci else 64562306a36Sopenharmony_ci return 8; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/** 64962306a36Sopenharmony_ci * irdma_uk_inline_rdma_write - inline rdma write operation 65062306a36Sopenharmony_ci * @qp: hw qp ptr 65162306a36Sopenharmony_ci * @info: post sq information 65262306a36Sopenharmony_ci * @post_sq: flag to post sq 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ciint irdma_uk_inline_rdma_write(struct irdma_qp_uk *qp, 65562306a36Sopenharmony_ci struct irdma_post_sq_info *info, bool post_sq) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci __le64 *wqe; 65862306a36Sopenharmony_ci struct irdma_rdma_write *op_info; 65962306a36Sopenharmony_ci u64 hdr = 0; 66062306a36Sopenharmony_ci u32 wqe_idx; 66162306a36Sopenharmony_ci bool read_fence = false; 66262306a36Sopenharmony_ci u32 i, total_size = 0; 66362306a36Sopenharmony_ci u16 quanta; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci op_info = &info->op.rdma_write; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (unlikely(qp->max_sq_frag_cnt < op_info->num_lo_sges)) 66862306a36Sopenharmony_ci return -EINVAL; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci for (i = 0; i < op_info->num_lo_sges; i++) 67162306a36Sopenharmony_ci total_size += op_info->lo_sg_list[i].length; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (unlikely(total_size > qp->max_inline_data)) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci quanta = qp->wqe_ops.iw_inline_data_size_to_quanta(total_size); 67762306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size, 67862306a36Sopenharmony_ci info); 67962306a36Sopenharmony_ci if (!wqe) 68062306a36Sopenharmony_ci return -ENOMEM; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci read_fence |= info->read_fence; 68562306a36Sopenharmony_ci set_64bit_val(wqe, 16, 68662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_TO, op_info->rem_addr.addr)); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, op_info->rem_addr.lkey) | 68962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) | 69062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_INLINEDATALEN, total_size) | 69162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_REPORTRTT, info->report_rtt ? 1 : 0) | 69262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) | 69362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, info->imm_data_valid ? 1 : 0) | 69462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | 69562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | 69662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 69762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (info->imm_data_valid) 70062306a36Sopenharmony_ci set_64bit_val(wqe, 0, 70162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data)); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci qp->wqe_ops.iw_copy_inline_data((u8 *)wqe, op_info->lo_sg_list, 70462306a36Sopenharmony_ci op_info->num_lo_sges, 70562306a36Sopenharmony_ci qp->swqe_polarity); 70662306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (post_sq) 71162306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/** 71762306a36Sopenharmony_ci * irdma_uk_inline_send - inline send operation 71862306a36Sopenharmony_ci * @qp: hw qp ptr 71962306a36Sopenharmony_ci * @info: post sq information 72062306a36Sopenharmony_ci * @post_sq: flag to post sq 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ciint irdma_uk_inline_send(struct irdma_qp_uk *qp, 72362306a36Sopenharmony_ci struct irdma_post_sq_info *info, bool post_sq) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci __le64 *wqe; 72662306a36Sopenharmony_ci struct irdma_post_send *op_info; 72762306a36Sopenharmony_ci u64 hdr; 72862306a36Sopenharmony_ci u32 wqe_idx; 72962306a36Sopenharmony_ci bool read_fence = false; 73062306a36Sopenharmony_ci u32 i, total_size = 0; 73162306a36Sopenharmony_ci u16 quanta; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci op_info = &info->op.send; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (unlikely(qp->max_sq_frag_cnt < op_info->num_sges)) 73662306a36Sopenharmony_ci return -EINVAL; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci for (i = 0; i < op_info->num_sges; i++) 73962306a36Sopenharmony_ci total_size += op_info->sg_list[i].length; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (unlikely(total_size > qp->max_inline_data)) 74262306a36Sopenharmony_ci return -EINVAL; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci quanta = qp->wqe_ops.iw_inline_data_size_to_quanta(total_size); 74562306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, quanta, total_size, 74662306a36Sopenharmony_ci info); 74762306a36Sopenharmony_ci if (!wqe) 74862306a36Sopenharmony_ci return -ENOMEM; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci set_64bit_val(wqe, 16, 75362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_DESTQKEY, op_info->qkey) | 75462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_DESTQPN, op_info->dest_qp)); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci read_fence |= info->read_fence; 75762306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_REMSTAG, info->stag_to_inv) | 75862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_AHID, op_info->ah_id) | 75962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_OPCODE, info->op_type) | 76062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_INLINEDATALEN, total_size) | 76162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATAFLAG, 76262306a36Sopenharmony_ci (info->imm_data_valid ? 1 : 0)) | 76362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_REPORTRTT, (info->report_rtt ? 1 : 0)) | 76462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_INLINEDATAFLAG, 1) | 76562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, read_fence) | 76662306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, info->local_fence) | 76762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 76862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_UDPHEADER, info->udp_hdr) | 76962306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_L4LEN, info->l4len) | 77062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (info->imm_data_valid) 77362306a36Sopenharmony_ci set_64bit_val(wqe, 0, 77462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_IMMDATA, info->imm_data)); 77562306a36Sopenharmony_ci qp->wqe_ops.iw_copy_inline_data((u8 *)wqe, op_info->sg_list, 77662306a36Sopenharmony_ci op_info->num_sges, qp->swqe_polarity); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (post_sq) 78362306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return 0; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci/** 78962306a36Sopenharmony_ci * irdma_uk_stag_local_invalidate - stag invalidate operation 79062306a36Sopenharmony_ci * @qp: hw qp ptr 79162306a36Sopenharmony_ci * @info: post sq information 79262306a36Sopenharmony_ci * @post_sq: flag to post sq 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ciint irdma_uk_stag_local_invalidate(struct irdma_qp_uk *qp, 79562306a36Sopenharmony_ci struct irdma_post_sq_info *info, 79662306a36Sopenharmony_ci bool post_sq) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci __le64 *wqe; 79962306a36Sopenharmony_ci struct irdma_inv_local_stag *op_info; 80062306a36Sopenharmony_ci u64 hdr; 80162306a36Sopenharmony_ci u32 wqe_idx; 80262306a36Sopenharmony_ci bool local_fence = false; 80362306a36Sopenharmony_ci struct ib_sge sge = {}; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci op_info = &info->op.inv_local_stag; 80662306a36Sopenharmony_ci local_fence = info->local_fence; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA, 80962306a36Sopenharmony_ci 0, info); 81062306a36Sopenharmony_ci if (!wqe) 81162306a36Sopenharmony_ci return -ENOMEM; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci sge.lkey = op_info->target_stag; 81662306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, 0, &sge, 0); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci set_64bit_val(wqe, 16, 0); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMA_OP_TYPE_INV_STAG) | 82162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_READFENCE, info->read_fence) | 82262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_LOCALFENCE, local_fence) | 82362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, info->signaled) | 82462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (post_sq) 83162306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci return 0; 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci/** 83762306a36Sopenharmony_ci * irdma_uk_post_receive - post receive wqe 83862306a36Sopenharmony_ci * @qp: hw qp ptr 83962306a36Sopenharmony_ci * @info: post rq information 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ciint irdma_uk_post_receive(struct irdma_qp_uk *qp, 84262306a36Sopenharmony_ci struct irdma_post_rq_info *info) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci u32 wqe_idx, i, byte_off; 84562306a36Sopenharmony_ci u32 addl_frag_cnt; 84662306a36Sopenharmony_ci __le64 *wqe; 84762306a36Sopenharmony_ci u64 hdr; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (qp->max_rq_frag_cnt < info->num_sges) 85062306a36Sopenharmony_ci return -EINVAL; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci wqe = irdma_qp_get_next_recv_wqe(qp, &wqe_idx); 85362306a36Sopenharmony_ci if (!wqe) 85462306a36Sopenharmony_ci return -ENOMEM; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci qp->rq_wrid_array[wqe_idx] = info->wr_id; 85762306a36Sopenharmony_ci addl_frag_cnt = info->num_sges > 1 ? (info->num_sges - 1) : 0; 85862306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, 0, info->sg_list, 85962306a36Sopenharmony_ci qp->rwqe_polarity); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci for (i = 1, byte_off = 32; i < info->num_sges; i++) { 86262306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, &info->sg_list[i], 86362306a36Sopenharmony_ci qp->rwqe_polarity); 86462306a36Sopenharmony_ci byte_off += 16; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* if not an odd number set valid bit in next fragment */ 86862306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev >= IRDMA_GEN_2 && !(info->num_sges & 0x01) && 86962306a36Sopenharmony_ci info->num_sges) { 87062306a36Sopenharmony_ci qp->wqe_ops.iw_set_fragment(wqe, byte_off, NULL, 87162306a36Sopenharmony_ci qp->rwqe_polarity); 87262306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_2) 87362306a36Sopenharmony_ci ++addl_frag_cnt; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci set_64bit_val(wqe, 16, 0); 87762306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_ADDFRAGCNT, addl_frag_cnt) | 87862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->rwqe_polarity); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/** 88862306a36Sopenharmony_ci * irdma_uk_cq_resize - reset the cq buffer info 88962306a36Sopenharmony_ci * @cq: cq to resize 89062306a36Sopenharmony_ci * @cq_base: new cq buffer addr 89162306a36Sopenharmony_ci * @cq_size: number of cqes 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_civoid irdma_uk_cq_resize(struct irdma_cq_uk *cq, void *cq_base, int cq_size) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci cq->cq_base = cq_base; 89662306a36Sopenharmony_ci cq->cq_size = cq_size; 89762306a36Sopenharmony_ci IRDMA_RING_INIT(cq->cq_ring, cq->cq_size); 89862306a36Sopenharmony_ci cq->polarity = 1; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci/** 90262306a36Sopenharmony_ci * irdma_uk_cq_set_resized_cnt - record the count of the resized buffers 90362306a36Sopenharmony_ci * @cq: cq to resize 90462306a36Sopenharmony_ci * @cq_cnt: the count of the resized cq buffers 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_civoid irdma_uk_cq_set_resized_cnt(struct irdma_cq_uk *cq, u16 cq_cnt) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci u64 temp_val; 90962306a36Sopenharmony_ci u16 sw_cq_sel; 91062306a36Sopenharmony_ci u8 arm_next_se; 91162306a36Sopenharmony_ci u8 arm_next; 91262306a36Sopenharmony_ci u8 arm_seq_num; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci get_64bit_val(cq->shadow_area, 32, &temp_val); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val); 91762306a36Sopenharmony_ci sw_cq_sel += cq_cnt; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci arm_seq_num = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_SEQ_NUM, temp_val); 92062306a36Sopenharmony_ci arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val); 92162306a36Sopenharmony_ci arm_next = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT, temp_val); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci temp_val = FIELD_PREP(IRDMA_CQ_DBSA_ARM_SEQ_NUM, arm_seq_num) | 92462306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_SW_CQ_SELECT, sw_cq_sel) | 92562306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) | 92662306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, arm_next); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci set_64bit_val(cq->shadow_area, 32, temp_val); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci/** 93262306a36Sopenharmony_ci * irdma_uk_cq_request_notification - cq notification request (door bell) 93362306a36Sopenharmony_ci * @cq: hw cq 93462306a36Sopenharmony_ci * @cq_notify: notification type 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_civoid irdma_uk_cq_request_notification(struct irdma_cq_uk *cq, 93762306a36Sopenharmony_ci enum irdma_cmpl_notify cq_notify) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci u64 temp_val; 94062306a36Sopenharmony_ci u16 sw_cq_sel; 94162306a36Sopenharmony_ci u8 arm_next_se = 0; 94262306a36Sopenharmony_ci u8 arm_next = 0; 94362306a36Sopenharmony_ci u8 arm_seq_num; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci get_64bit_val(cq->shadow_area, 32, &temp_val); 94662306a36Sopenharmony_ci arm_seq_num = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_SEQ_NUM, temp_val); 94762306a36Sopenharmony_ci arm_seq_num++; 94862306a36Sopenharmony_ci sw_cq_sel = (u16)FIELD_GET(IRDMA_CQ_DBSA_SW_CQ_SELECT, temp_val); 94962306a36Sopenharmony_ci arm_next_se = (u8)FIELD_GET(IRDMA_CQ_DBSA_ARM_NEXT_SE, temp_val); 95062306a36Sopenharmony_ci arm_next_se |= 1; 95162306a36Sopenharmony_ci if (cq_notify == IRDMA_CQ_COMPL_EVENT) 95262306a36Sopenharmony_ci arm_next = 1; 95362306a36Sopenharmony_ci temp_val = FIELD_PREP(IRDMA_CQ_DBSA_ARM_SEQ_NUM, arm_seq_num) | 95462306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_SW_CQ_SELECT, sw_cq_sel) | 95562306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT_SE, arm_next_se) | 95662306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQ_DBSA_ARM_NEXT, arm_next); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci set_64bit_val(cq->shadow_area, 32, temp_val); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci writel(cq->cq_id, cq->cqe_alloc_db); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/** 96662306a36Sopenharmony_ci * irdma_uk_cq_poll_cmpl - get cq completion info 96762306a36Sopenharmony_ci * @cq: hw cq 96862306a36Sopenharmony_ci * @info: cq poll information returned 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ciint irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq, 97162306a36Sopenharmony_ci struct irdma_cq_poll_info *info) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci u64 comp_ctx, qword0, qword2, qword3; 97462306a36Sopenharmony_ci __le64 *cqe; 97562306a36Sopenharmony_ci struct irdma_qp_uk *qp; 97662306a36Sopenharmony_ci struct irdma_ring *pring = NULL; 97762306a36Sopenharmony_ci u32 wqe_idx; 97862306a36Sopenharmony_ci int ret_code; 97962306a36Sopenharmony_ci bool move_cq_head = true; 98062306a36Sopenharmony_ci u8 polarity; 98162306a36Sopenharmony_ci bool ext_valid; 98262306a36Sopenharmony_ci __le64 *ext_cqe; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (cq->avoid_mem_cflct) 98562306a36Sopenharmony_ci cqe = IRDMA_GET_CURRENT_EXTENDED_CQ_ELEM(cq); 98662306a36Sopenharmony_ci else 98762306a36Sopenharmony_ci cqe = IRDMA_GET_CURRENT_CQ_ELEM(cq); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci get_64bit_val(cqe, 24, &qword3); 99062306a36Sopenharmony_ci polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3); 99162306a36Sopenharmony_ci if (polarity != cq->polarity) 99262306a36Sopenharmony_ci return -ENOENT; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Ensure CQE contents are read after valid bit is checked */ 99562306a36Sopenharmony_ci dma_rmb(); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci ext_valid = (bool)FIELD_GET(IRDMA_CQ_EXTCQE, qword3); 99862306a36Sopenharmony_ci if (ext_valid) { 99962306a36Sopenharmony_ci u64 qword6, qword7; 100062306a36Sopenharmony_ci u32 peek_head; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (cq->avoid_mem_cflct) { 100362306a36Sopenharmony_ci ext_cqe = (__le64 *)((u8 *)cqe + 32); 100462306a36Sopenharmony_ci get_64bit_val(ext_cqe, 24, &qword7); 100562306a36Sopenharmony_ci polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword7); 100662306a36Sopenharmony_ci } else { 100762306a36Sopenharmony_ci peek_head = (cq->cq_ring.head + 1) % cq->cq_ring.size; 100862306a36Sopenharmony_ci ext_cqe = cq->cq_base[peek_head].buf; 100962306a36Sopenharmony_ci get_64bit_val(ext_cqe, 24, &qword7); 101062306a36Sopenharmony_ci polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword7); 101162306a36Sopenharmony_ci if (!peek_head) 101262306a36Sopenharmony_ci polarity ^= 1; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci if (polarity != cq->polarity) 101562306a36Sopenharmony_ci return -ENOENT; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* Ensure ext CQE contents are read after ext valid bit is checked */ 101862306a36Sopenharmony_ci dma_rmb(); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci info->imm_valid = (bool)FIELD_GET(IRDMA_CQ_IMMVALID, qword7); 102162306a36Sopenharmony_ci if (info->imm_valid) { 102262306a36Sopenharmony_ci u64 qword4; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci get_64bit_val(ext_cqe, 0, &qword4); 102562306a36Sopenharmony_ci info->imm_data = (u32)FIELD_GET(IRDMA_CQ_IMMDATALOW32, qword4); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci info->ud_smac_valid = (bool)FIELD_GET(IRDMA_CQ_UDSMACVALID, qword7); 102862306a36Sopenharmony_ci info->ud_vlan_valid = (bool)FIELD_GET(IRDMA_CQ_UDVLANVALID, qword7); 102962306a36Sopenharmony_ci if (info->ud_smac_valid || info->ud_vlan_valid) { 103062306a36Sopenharmony_ci get_64bit_val(ext_cqe, 16, &qword6); 103162306a36Sopenharmony_ci if (info->ud_vlan_valid) 103262306a36Sopenharmony_ci info->ud_vlan = (u16)FIELD_GET(IRDMA_CQ_UDVLAN, qword6); 103362306a36Sopenharmony_ci if (info->ud_smac_valid) { 103462306a36Sopenharmony_ci info->ud_smac[5] = qword6 & 0xFF; 103562306a36Sopenharmony_ci info->ud_smac[4] = (qword6 >> 8) & 0xFF; 103662306a36Sopenharmony_ci info->ud_smac[3] = (qword6 >> 16) & 0xFF; 103762306a36Sopenharmony_ci info->ud_smac[2] = (qword6 >> 24) & 0xFF; 103862306a36Sopenharmony_ci info->ud_smac[1] = (qword6 >> 32) & 0xFF; 103962306a36Sopenharmony_ci info->ud_smac[0] = (qword6 >> 40) & 0xFF; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci } else { 104362306a36Sopenharmony_ci info->imm_valid = false; 104462306a36Sopenharmony_ci info->ud_smac_valid = false; 104562306a36Sopenharmony_ci info->ud_vlan_valid = false; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci info->q_type = (u8)FIELD_GET(IRDMA_CQ_SQ, qword3); 104962306a36Sopenharmony_ci info->error = (bool)FIELD_GET(IRDMA_CQ_ERROR, qword3); 105062306a36Sopenharmony_ci info->ipv4 = (bool)FIELD_GET(IRDMACQ_IPV4, qword3); 105162306a36Sopenharmony_ci if (info->error) { 105262306a36Sopenharmony_ci info->major_err = FIELD_GET(IRDMA_CQ_MAJERR, qword3); 105362306a36Sopenharmony_ci info->minor_err = FIELD_GET(IRDMA_CQ_MINERR, qword3); 105462306a36Sopenharmony_ci if (info->major_err == IRDMA_FLUSH_MAJOR_ERR) { 105562306a36Sopenharmony_ci info->comp_status = IRDMA_COMPL_STATUS_FLUSHED; 105662306a36Sopenharmony_ci /* Set the min error to standard flush error code for remaining cqes */ 105762306a36Sopenharmony_ci if (info->minor_err != FLUSH_GENERAL_ERR) { 105862306a36Sopenharmony_ci qword3 &= ~IRDMA_CQ_MINERR; 105962306a36Sopenharmony_ci qword3 |= FIELD_PREP(IRDMA_CQ_MINERR, FLUSH_GENERAL_ERR); 106062306a36Sopenharmony_ci set_64bit_val(cqe, 24, qword3); 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci } else { 106362306a36Sopenharmony_ci info->comp_status = IRDMA_COMPL_STATUS_UNKNOWN; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci } else { 106662306a36Sopenharmony_ci info->comp_status = IRDMA_COMPL_STATUS_SUCCESS; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci get_64bit_val(cqe, 0, &qword0); 107062306a36Sopenharmony_ci get_64bit_val(cqe, 16, &qword2); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci info->tcp_seq_num_rtt = (u32)FIELD_GET(IRDMACQ_TCPSEQNUMRTT, qword0); 107362306a36Sopenharmony_ci info->qp_id = (u32)FIELD_GET(IRDMACQ_QPID, qword2); 107462306a36Sopenharmony_ci info->ud_src_qpn = (u32)FIELD_GET(IRDMACQ_UDSRCQPN, qword2); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci get_64bit_val(cqe, 8, &comp_ctx); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci info->solicited_event = (bool)FIELD_GET(IRDMACQ_SOEVENT, qword3); 107962306a36Sopenharmony_ci qp = (struct irdma_qp_uk *)(unsigned long)comp_ctx; 108062306a36Sopenharmony_ci if (!qp || qp->destroy_pending) { 108162306a36Sopenharmony_ci ret_code = -EFAULT; 108262306a36Sopenharmony_ci goto exit; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci wqe_idx = (u32)FIELD_GET(IRDMA_CQ_WQEIDX, qword3); 108562306a36Sopenharmony_ci info->qp_handle = (irdma_qp_handle)(unsigned long)qp; 108662306a36Sopenharmony_ci info->op_type = (u8)FIELD_GET(IRDMACQ_OP, qword3); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (info->q_type == IRDMA_CQE_QTYPE_RQ) { 108962306a36Sopenharmony_ci u32 array_idx; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci array_idx = wqe_idx / qp->rq_wqe_size_multiplier; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (info->comp_status == IRDMA_COMPL_STATUS_FLUSHED || 109462306a36Sopenharmony_ci info->comp_status == IRDMA_COMPL_STATUS_UNKNOWN) { 109562306a36Sopenharmony_ci if (!IRDMA_RING_MORE_WORK(qp->rq_ring)) { 109662306a36Sopenharmony_ci ret_code = -ENOENT; 109762306a36Sopenharmony_ci goto exit; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci info->wr_id = qp->rq_wrid_array[qp->rq_ring.tail]; 110162306a36Sopenharmony_ci array_idx = qp->rq_ring.tail; 110262306a36Sopenharmony_ci } else { 110362306a36Sopenharmony_ci info->wr_id = qp->rq_wrid_array[array_idx]; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci info->bytes_xfered = (u32)FIELD_GET(IRDMACQ_PAYLDLEN, qword0); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (qword3 & IRDMACQ_STAG) { 110962306a36Sopenharmony_ci info->stag_invalid_set = true; 111062306a36Sopenharmony_ci info->inv_stag = (u32)FIELD_GET(IRDMACQ_INVSTAG, qword2); 111162306a36Sopenharmony_ci } else { 111262306a36Sopenharmony_ci info->stag_invalid_set = false; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci IRDMA_RING_SET_TAIL(qp->rq_ring, array_idx + 1); 111562306a36Sopenharmony_ci if (info->comp_status == IRDMA_COMPL_STATUS_FLUSHED) { 111662306a36Sopenharmony_ci qp->rq_flush_seen = true; 111762306a36Sopenharmony_ci if (!IRDMA_RING_MORE_WORK(qp->rq_ring)) 111862306a36Sopenharmony_ci qp->rq_flush_complete = true; 111962306a36Sopenharmony_ci else 112062306a36Sopenharmony_ci move_cq_head = false; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci pring = &qp->rq_ring; 112362306a36Sopenharmony_ci } else { /* q_type is IRDMA_CQE_QTYPE_SQ */ 112462306a36Sopenharmony_ci if (qp->first_sq_wq) { 112562306a36Sopenharmony_ci if (wqe_idx + 1 >= qp->conn_wqes) 112662306a36Sopenharmony_ci qp->first_sq_wq = false; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (wqe_idx < qp->conn_wqes && qp->sq_ring.head == qp->sq_ring.tail) { 112962306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring); 113062306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL(cq->cq_ring); 113162306a36Sopenharmony_ci set_64bit_val(cq->shadow_area, 0, 113262306a36Sopenharmony_ci IRDMA_RING_CURRENT_HEAD(cq->cq_ring)); 113362306a36Sopenharmony_ci memset(info, 0, 113462306a36Sopenharmony_ci sizeof(struct irdma_cq_poll_info)); 113562306a36Sopenharmony_ci return irdma_uk_cq_poll_cmpl(cq, info); 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci if (info->comp_status != IRDMA_COMPL_STATUS_FLUSHED) { 113962306a36Sopenharmony_ci info->wr_id = qp->sq_wrtrk_array[wqe_idx].wrid; 114062306a36Sopenharmony_ci if (!info->comp_status) 114162306a36Sopenharmony_ci info->bytes_xfered = qp->sq_wrtrk_array[wqe_idx].wr_len; 114262306a36Sopenharmony_ci info->op_type = (u8)FIELD_GET(IRDMACQ_OP, qword3); 114362306a36Sopenharmony_ci IRDMA_RING_SET_TAIL(qp->sq_ring, 114462306a36Sopenharmony_ci wqe_idx + qp->sq_wrtrk_array[wqe_idx].quanta); 114562306a36Sopenharmony_ci } else { 114662306a36Sopenharmony_ci if (!IRDMA_RING_MORE_WORK(qp->sq_ring)) { 114762306a36Sopenharmony_ci ret_code = -ENOENT; 114862306a36Sopenharmony_ci goto exit; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci do { 115262306a36Sopenharmony_ci __le64 *sw_wqe; 115362306a36Sopenharmony_ci u64 wqe_qword; 115462306a36Sopenharmony_ci u32 tail; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci tail = qp->sq_ring.tail; 115762306a36Sopenharmony_ci sw_wqe = qp->sq_base[tail].elem; 115862306a36Sopenharmony_ci get_64bit_val(sw_wqe, 24, 115962306a36Sopenharmony_ci &wqe_qword); 116062306a36Sopenharmony_ci info->op_type = (u8)FIELD_GET(IRDMAQPSQ_OPCODE, 116162306a36Sopenharmony_ci wqe_qword); 116262306a36Sopenharmony_ci IRDMA_RING_SET_TAIL(qp->sq_ring, 116362306a36Sopenharmony_ci tail + qp->sq_wrtrk_array[tail].quanta); 116462306a36Sopenharmony_ci if (info->op_type != IRDMAQP_OP_NOP) { 116562306a36Sopenharmony_ci info->wr_id = qp->sq_wrtrk_array[tail].wrid; 116662306a36Sopenharmony_ci info->bytes_xfered = qp->sq_wrtrk_array[tail].wr_len; 116762306a36Sopenharmony_ci break; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci } while (1); 117062306a36Sopenharmony_ci if (info->op_type == IRDMA_OP_TYPE_BIND_MW && 117162306a36Sopenharmony_ci info->minor_err == FLUSH_PROT_ERR) 117262306a36Sopenharmony_ci info->minor_err = FLUSH_MW_BIND_ERR; 117362306a36Sopenharmony_ci qp->sq_flush_seen = true; 117462306a36Sopenharmony_ci if (!IRDMA_RING_MORE_WORK(qp->sq_ring)) 117562306a36Sopenharmony_ci qp->sq_flush_complete = true; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci pring = &qp->sq_ring; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci ret_code = 0; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ciexit: 118362306a36Sopenharmony_ci if (!ret_code && info->comp_status == IRDMA_COMPL_STATUS_FLUSHED) 118462306a36Sopenharmony_ci if (pring && IRDMA_RING_MORE_WORK(*pring)) 118562306a36Sopenharmony_ci move_cq_head = false; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (move_cq_head) { 118862306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring); 118962306a36Sopenharmony_ci if (!IRDMA_RING_CURRENT_HEAD(cq->cq_ring)) 119062306a36Sopenharmony_ci cq->polarity ^= 1; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (ext_valid && !cq->avoid_mem_cflct) { 119362306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(cq->cq_ring); 119462306a36Sopenharmony_ci if (!IRDMA_RING_CURRENT_HEAD(cq->cq_ring)) 119562306a36Sopenharmony_ci cq->polarity ^= 1; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL(cq->cq_ring); 119962306a36Sopenharmony_ci if (!cq->avoid_mem_cflct && ext_valid) 120062306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL(cq->cq_ring); 120162306a36Sopenharmony_ci set_64bit_val(cq->shadow_area, 0, 120262306a36Sopenharmony_ci IRDMA_RING_CURRENT_HEAD(cq->cq_ring)); 120362306a36Sopenharmony_ci } else { 120462306a36Sopenharmony_ci qword3 &= ~IRDMA_CQ_WQEIDX; 120562306a36Sopenharmony_ci qword3 |= FIELD_PREP(IRDMA_CQ_WQEIDX, pring->tail); 120662306a36Sopenharmony_ci set_64bit_val(cqe, 24, qword3); 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return ret_code; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci/** 121362306a36Sopenharmony_ci * irdma_qp_round_up - return round up qp wq depth 121462306a36Sopenharmony_ci * @wqdepth: wq depth in quanta to round up 121562306a36Sopenharmony_ci */ 121662306a36Sopenharmony_cistatic int irdma_qp_round_up(u32 wqdepth) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci int scount = 1; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci for (wqdepth--; scount <= 16; scount *= 2) 122162306a36Sopenharmony_ci wqdepth |= wqdepth >> scount; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci return ++wqdepth; 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci/** 122762306a36Sopenharmony_ci * irdma_get_wqe_shift - get shift count for maximum wqe size 122862306a36Sopenharmony_ci * @uk_attrs: qp HW attributes 122962306a36Sopenharmony_ci * @sge: Maximum Scatter Gather Elements wqe 123062306a36Sopenharmony_ci * @inline_data: Maximum inline data size 123162306a36Sopenharmony_ci * @shift: Returns the shift needed based on sge 123262306a36Sopenharmony_ci * 123362306a36Sopenharmony_ci * Shift can be used to left shift the wqe size based on number of SGEs and inlind data size. 123462306a36Sopenharmony_ci * For 1 SGE or inline data <= 8, shift = 0 (wqe size of 32 123562306a36Sopenharmony_ci * bytes). For 2 or 3 SGEs or inline data <= 39, shift = 1 (wqe 123662306a36Sopenharmony_ci * size of 64 bytes). 123762306a36Sopenharmony_ci * For 4-7 SGE's and inline <= 101 Shift of 2 otherwise (wqe 123862306a36Sopenharmony_ci * size of 256 bytes). 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_civoid irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge, 124162306a36Sopenharmony_ci u32 inline_data, u8 *shift) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci *shift = 0; 124462306a36Sopenharmony_ci if (uk_attrs->hw_rev >= IRDMA_GEN_2) { 124562306a36Sopenharmony_ci if (sge > 1 || inline_data > 8) { 124662306a36Sopenharmony_ci if (sge < 4 && inline_data <= 39) 124762306a36Sopenharmony_ci *shift = 1; 124862306a36Sopenharmony_ci else if (sge < 8 && inline_data <= 101) 124962306a36Sopenharmony_ci *shift = 2; 125062306a36Sopenharmony_ci else 125162306a36Sopenharmony_ci *shift = 3; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci } else if (sge > 1 || inline_data > 16) { 125462306a36Sopenharmony_ci *shift = (sge < 4 && inline_data <= 48) ? 1 : 2; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci/* 125962306a36Sopenharmony_ci * irdma_get_sqdepth - get SQ depth (quanta) 126062306a36Sopenharmony_ci * @uk_attrs: qp HW attributes 126162306a36Sopenharmony_ci * @sq_size: SQ size 126262306a36Sopenharmony_ci * @shift: shift which determines size of WQE 126362306a36Sopenharmony_ci * @sqdepth: depth of SQ 126462306a36Sopenharmony_ci * 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_ciint irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, 126762306a36Sopenharmony_ci u32 *sqdepth) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci *sqdepth = irdma_qp_round_up((sq_size << shift) + IRDMA_SQ_RSVD); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (*sqdepth < min_size) 127462306a36Sopenharmony_ci *sqdepth = min_size; 127562306a36Sopenharmony_ci else if (*sqdepth > uk_attrs->max_hw_wq_quanta) 127662306a36Sopenharmony_ci return -EINVAL; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci return 0; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci/* 128262306a36Sopenharmony_ci * irdma_get_rqdepth - get RQ depth (quanta) 128362306a36Sopenharmony_ci * @uk_attrs: qp HW attributes 128462306a36Sopenharmony_ci * @rq_size: RQ size 128562306a36Sopenharmony_ci * @shift: shift which determines size of WQE 128662306a36Sopenharmony_ci * @rqdepth: depth of RQ 128762306a36Sopenharmony_ci */ 128862306a36Sopenharmony_ciint irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift, 128962306a36Sopenharmony_ci u32 *rqdepth) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci *rqdepth = irdma_qp_round_up((rq_size << shift) + IRDMA_RQ_RSVD); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (*rqdepth < min_size) 129662306a36Sopenharmony_ci *rqdepth = min_size; 129762306a36Sopenharmony_ci else if (*rqdepth > uk_attrs->max_hw_rq_quanta) 129862306a36Sopenharmony_ci return -EINVAL; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci return 0; 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic const struct irdma_wqe_uk_ops iw_wqe_uk_ops = { 130462306a36Sopenharmony_ci .iw_copy_inline_data = irdma_copy_inline_data, 130562306a36Sopenharmony_ci .iw_inline_data_size_to_quanta = irdma_inline_data_size_to_quanta, 130662306a36Sopenharmony_ci .iw_set_fragment = irdma_set_fragment, 130762306a36Sopenharmony_ci .iw_set_mw_bind_wqe = irdma_set_mw_bind_wqe, 130862306a36Sopenharmony_ci}; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic const struct irdma_wqe_uk_ops iw_wqe_uk_ops_gen_1 = { 131162306a36Sopenharmony_ci .iw_copy_inline_data = irdma_copy_inline_data_gen_1, 131262306a36Sopenharmony_ci .iw_inline_data_size_to_quanta = irdma_inline_data_size_to_quanta_gen_1, 131362306a36Sopenharmony_ci .iw_set_fragment = irdma_set_fragment_gen_1, 131462306a36Sopenharmony_ci .iw_set_mw_bind_wqe = irdma_set_mw_bind_wqe_gen_1, 131562306a36Sopenharmony_ci}; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci/** 131862306a36Sopenharmony_ci * irdma_setup_connection_wqes - setup WQEs necessary to complete 131962306a36Sopenharmony_ci * connection. 132062306a36Sopenharmony_ci * @qp: hw qp (user and kernel) 132162306a36Sopenharmony_ci * @info: qp initialization info 132262306a36Sopenharmony_ci */ 132362306a36Sopenharmony_cistatic void irdma_setup_connection_wqes(struct irdma_qp_uk *qp, 132462306a36Sopenharmony_ci struct irdma_qp_uk_init_info *info) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci u16 move_cnt = 1; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (!info->legacy_mode && 132962306a36Sopenharmony_ci (qp->uk_attrs->feature_flags & IRDMA_FEATURE_RTS_AE)) 133062306a36Sopenharmony_ci move_cnt = 3; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci qp->conn_wqes = move_cnt; 133362306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->sq_ring, move_cnt); 133462306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL_BY_COUNT(qp->sq_ring, move_cnt); 133562306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_BY_COUNT_NOCHECK(qp->initial_ring, move_cnt); 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci/** 133962306a36Sopenharmony_ci * irdma_uk_calc_shift_wq - calculate WQE shift for both SQ and RQ 134062306a36Sopenharmony_ci * @ukinfo: qp initialization info 134162306a36Sopenharmony_ci * @sq_shift: Returns shift of SQ 134262306a36Sopenharmony_ci * @rq_shift: Returns shift of RQ 134362306a36Sopenharmony_ci */ 134462306a36Sopenharmony_civoid irdma_uk_calc_shift_wq(struct irdma_qp_uk_init_info *ukinfo, u8 *sq_shift, 134562306a36Sopenharmony_ci u8 *rq_shift) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci bool imm_support = ukinfo->uk_attrs->hw_rev >= IRDMA_GEN_2; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci irdma_get_wqe_shift(ukinfo->uk_attrs, 135062306a36Sopenharmony_ci imm_support ? ukinfo->max_sq_frag_cnt + 1 : 135162306a36Sopenharmony_ci ukinfo->max_sq_frag_cnt, 135262306a36Sopenharmony_ci ukinfo->max_inline_data, sq_shift); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci irdma_get_wqe_shift(ukinfo->uk_attrs, ukinfo->max_rq_frag_cnt, 0, 135562306a36Sopenharmony_ci rq_shift); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (ukinfo->uk_attrs->hw_rev == IRDMA_GEN_1) { 135862306a36Sopenharmony_ci if (ukinfo->abi_ver > 4) 135962306a36Sopenharmony_ci *rq_shift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci/** 136462306a36Sopenharmony_ci * irdma_uk_calc_depth_shift_sq - calculate depth and shift for SQ size. 136562306a36Sopenharmony_ci * @ukinfo: qp initialization info 136662306a36Sopenharmony_ci * @sq_depth: Returns depth of SQ 136762306a36Sopenharmony_ci * @sq_shift: Returns shift of SQ 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_ciint irdma_uk_calc_depth_shift_sq(struct irdma_qp_uk_init_info *ukinfo, 137062306a36Sopenharmony_ci u32 *sq_depth, u8 *sq_shift) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci bool imm_support = ukinfo->uk_attrs->hw_rev >= IRDMA_GEN_2; 137362306a36Sopenharmony_ci int status; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci irdma_get_wqe_shift(ukinfo->uk_attrs, 137662306a36Sopenharmony_ci imm_support ? ukinfo->max_sq_frag_cnt + 1 : 137762306a36Sopenharmony_ci ukinfo->max_sq_frag_cnt, 137862306a36Sopenharmony_ci ukinfo->max_inline_data, sq_shift); 137962306a36Sopenharmony_ci status = irdma_get_sqdepth(ukinfo->uk_attrs, ukinfo->sq_size, 138062306a36Sopenharmony_ci *sq_shift, sq_depth); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return status; 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci/** 138662306a36Sopenharmony_ci * irdma_uk_calc_depth_shift_rq - calculate depth and shift for RQ size. 138762306a36Sopenharmony_ci * @ukinfo: qp initialization info 138862306a36Sopenharmony_ci * @rq_depth: Returns depth of RQ 138962306a36Sopenharmony_ci * @rq_shift: Returns shift of RQ 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ciint irdma_uk_calc_depth_shift_rq(struct irdma_qp_uk_init_info *ukinfo, 139262306a36Sopenharmony_ci u32 *rq_depth, u8 *rq_shift) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci int status; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci irdma_get_wqe_shift(ukinfo->uk_attrs, ukinfo->max_rq_frag_cnt, 0, 139762306a36Sopenharmony_ci rq_shift); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (ukinfo->uk_attrs->hw_rev == IRDMA_GEN_1) { 140062306a36Sopenharmony_ci if (ukinfo->abi_ver > 4) 140162306a36Sopenharmony_ci *rq_shift = IRDMA_MAX_RQ_WQE_SHIFT_GEN1; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci status = irdma_get_rqdepth(ukinfo->uk_attrs, ukinfo->rq_size, 140562306a36Sopenharmony_ci *rq_shift, rq_depth); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci return status; 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci/** 141162306a36Sopenharmony_ci * irdma_uk_qp_init - initialize shared qp 141262306a36Sopenharmony_ci * @qp: hw qp (user and kernel) 141362306a36Sopenharmony_ci * @info: qp initialization info 141462306a36Sopenharmony_ci * 141562306a36Sopenharmony_ci * initializes the vars used in both user and kernel mode. 141662306a36Sopenharmony_ci * size of the wqe depends on numbers of max. fragements 141762306a36Sopenharmony_ci * allowed. Then size of wqe * the number of wqes should be the 141862306a36Sopenharmony_ci * amount of memory allocated for sq and rq. 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_ciint irdma_uk_qp_init(struct irdma_qp_uk *qp, struct irdma_qp_uk_init_info *info) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci int ret_code = 0; 142362306a36Sopenharmony_ci u32 sq_ring_size; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci qp->uk_attrs = info->uk_attrs; 142662306a36Sopenharmony_ci if (info->max_sq_frag_cnt > qp->uk_attrs->max_hw_wq_frags || 142762306a36Sopenharmony_ci info->max_rq_frag_cnt > qp->uk_attrs->max_hw_wq_frags) 142862306a36Sopenharmony_ci return -EINVAL; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci qp->qp_caps = info->qp_caps; 143162306a36Sopenharmony_ci qp->sq_base = info->sq; 143262306a36Sopenharmony_ci qp->rq_base = info->rq; 143362306a36Sopenharmony_ci qp->qp_type = info->type ? info->type : IRDMA_QP_TYPE_IWARP; 143462306a36Sopenharmony_ci qp->shadow_area = info->shadow_area; 143562306a36Sopenharmony_ci qp->sq_wrtrk_array = info->sq_wrtrk_array; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci qp->rq_wrid_array = info->rq_wrid_array; 143862306a36Sopenharmony_ci qp->wqe_alloc_db = info->wqe_alloc_db; 143962306a36Sopenharmony_ci qp->qp_id = info->qp_id; 144062306a36Sopenharmony_ci qp->sq_size = info->sq_size; 144162306a36Sopenharmony_ci qp->max_sq_frag_cnt = info->max_sq_frag_cnt; 144262306a36Sopenharmony_ci sq_ring_size = qp->sq_size << info->sq_shift; 144362306a36Sopenharmony_ci IRDMA_RING_INIT(qp->sq_ring, sq_ring_size); 144462306a36Sopenharmony_ci IRDMA_RING_INIT(qp->initial_ring, sq_ring_size); 144562306a36Sopenharmony_ci if (info->first_sq_wq) { 144662306a36Sopenharmony_ci irdma_setup_connection_wqes(qp, info); 144762306a36Sopenharmony_ci qp->swqe_polarity = 1; 144862306a36Sopenharmony_ci qp->first_sq_wq = true; 144962306a36Sopenharmony_ci } else { 145062306a36Sopenharmony_ci qp->swqe_polarity = 0; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci qp->swqe_polarity_deferred = 1; 145362306a36Sopenharmony_ci qp->rwqe_polarity = 0; 145462306a36Sopenharmony_ci qp->rq_size = info->rq_size; 145562306a36Sopenharmony_ci qp->max_rq_frag_cnt = info->max_rq_frag_cnt; 145662306a36Sopenharmony_ci qp->max_inline_data = info->max_inline_data; 145762306a36Sopenharmony_ci qp->rq_wqe_size = info->rq_shift; 145862306a36Sopenharmony_ci IRDMA_RING_INIT(qp->rq_ring, qp->rq_size); 145962306a36Sopenharmony_ci qp->rq_wqe_size_multiplier = 1 << info->rq_shift; 146062306a36Sopenharmony_ci if (qp->uk_attrs->hw_rev == IRDMA_GEN_1) 146162306a36Sopenharmony_ci qp->wqe_ops = iw_wqe_uk_ops_gen_1; 146262306a36Sopenharmony_ci else 146362306a36Sopenharmony_ci qp->wqe_ops = iw_wqe_uk_ops; 146462306a36Sopenharmony_ci return ret_code; 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci/** 146862306a36Sopenharmony_ci * irdma_uk_cq_init - initialize shared cq (user and kernel) 146962306a36Sopenharmony_ci * @cq: hw cq 147062306a36Sopenharmony_ci * @info: hw cq initialization info 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_civoid irdma_uk_cq_init(struct irdma_cq_uk *cq, 147362306a36Sopenharmony_ci struct irdma_cq_uk_init_info *info) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci cq->cq_base = info->cq_base; 147662306a36Sopenharmony_ci cq->cq_id = info->cq_id; 147762306a36Sopenharmony_ci cq->cq_size = info->cq_size; 147862306a36Sopenharmony_ci cq->cqe_alloc_db = info->cqe_alloc_db; 147962306a36Sopenharmony_ci cq->cq_ack_db = info->cq_ack_db; 148062306a36Sopenharmony_ci cq->shadow_area = info->shadow_area; 148162306a36Sopenharmony_ci cq->avoid_mem_cflct = info->avoid_mem_cflct; 148262306a36Sopenharmony_ci IRDMA_RING_INIT(cq->cq_ring, cq->cq_size); 148362306a36Sopenharmony_ci cq->polarity = 1; 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci/** 148762306a36Sopenharmony_ci * irdma_uk_clean_cq - clean cq entries 148862306a36Sopenharmony_ci * @q: completion context 148962306a36Sopenharmony_ci * @cq: cq to clean 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_civoid irdma_uk_clean_cq(void *q, struct irdma_cq_uk *cq) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci __le64 *cqe; 149462306a36Sopenharmony_ci u64 qword3, comp_ctx; 149562306a36Sopenharmony_ci u32 cq_head; 149662306a36Sopenharmony_ci u8 polarity, temp; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci cq_head = cq->cq_ring.head; 149962306a36Sopenharmony_ci temp = cq->polarity; 150062306a36Sopenharmony_ci do { 150162306a36Sopenharmony_ci if (cq->avoid_mem_cflct) 150262306a36Sopenharmony_ci cqe = ((struct irdma_extended_cqe *)(cq->cq_base))[cq_head].buf; 150362306a36Sopenharmony_ci else 150462306a36Sopenharmony_ci cqe = cq->cq_base[cq_head].buf; 150562306a36Sopenharmony_ci get_64bit_val(cqe, 24, &qword3); 150662306a36Sopenharmony_ci polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword3); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (polarity != temp) 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci /* Ensure CQE contents are read after valid bit is checked */ 151262306a36Sopenharmony_ci dma_rmb(); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci get_64bit_val(cqe, 8, &comp_ctx); 151562306a36Sopenharmony_ci if ((void *)(unsigned long)comp_ctx == q) 151662306a36Sopenharmony_ci set_64bit_val(cqe, 8, 0); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci cq_head = (cq_head + 1) % cq->cq_ring.size; 151962306a36Sopenharmony_ci if (!cq_head) 152062306a36Sopenharmony_ci temp ^= 1; 152162306a36Sopenharmony_ci } while (true); 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci/** 152562306a36Sopenharmony_ci * irdma_nop - post a nop 152662306a36Sopenharmony_ci * @qp: hw qp ptr 152762306a36Sopenharmony_ci * @wr_id: work request id 152862306a36Sopenharmony_ci * @signaled: signaled for completion 152962306a36Sopenharmony_ci * @post_sq: ring doorbell 153062306a36Sopenharmony_ci */ 153162306a36Sopenharmony_ciint irdma_nop(struct irdma_qp_uk *qp, u64 wr_id, bool signaled, bool post_sq) 153262306a36Sopenharmony_ci{ 153362306a36Sopenharmony_ci __le64 *wqe; 153462306a36Sopenharmony_ci u64 hdr; 153562306a36Sopenharmony_ci u32 wqe_idx; 153662306a36Sopenharmony_ci struct irdma_post_sq_info info = {}; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci info.wr_id = wr_id; 153962306a36Sopenharmony_ci wqe = irdma_qp_get_next_send_wqe(qp, &wqe_idx, IRDMA_QP_WQE_MIN_QUANTA, 154062306a36Sopenharmony_ci 0, &info); 154162306a36Sopenharmony_ci if (!wqe) 154262306a36Sopenharmony_ci return -ENOMEM; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci irdma_clr_wqes(qp, wqe_idx); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci set_64bit_val(wqe, 0, 0); 154762306a36Sopenharmony_ci set_64bit_val(wqe, 8, 0); 154862306a36Sopenharmony_ci set_64bit_val(wqe, 16, 0); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci hdr = FIELD_PREP(IRDMAQPSQ_OPCODE, IRDMAQP_OP_NOP) | 155162306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_SIGCOMPL, signaled) | 155262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_VALID, qp->swqe_polarity); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is populated before valid bit is set */ 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 155762306a36Sopenharmony_ci if (post_sq) 155862306a36Sopenharmony_ci irdma_uk_qp_post_wr(qp); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci return 0; 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci/** 156462306a36Sopenharmony_ci * irdma_fragcnt_to_quanta_sq - calculate quanta based on fragment count for SQ 156562306a36Sopenharmony_ci * @frag_cnt: number of fragments 156662306a36Sopenharmony_ci * @quanta: quanta for frag_cnt 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_ciint irdma_fragcnt_to_quanta_sq(u32 frag_cnt, u16 *quanta) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci switch (frag_cnt) { 157162306a36Sopenharmony_ci case 0: 157262306a36Sopenharmony_ci case 1: 157362306a36Sopenharmony_ci *quanta = IRDMA_QP_WQE_MIN_QUANTA; 157462306a36Sopenharmony_ci break; 157562306a36Sopenharmony_ci case 2: 157662306a36Sopenharmony_ci case 3: 157762306a36Sopenharmony_ci *quanta = 2; 157862306a36Sopenharmony_ci break; 157962306a36Sopenharmony_ci case 4: 158062306a36Sopenharmony_ci case 5: 158162306a36Sopenharmony_ci *quanta = 3; 158262306a36Sopenharmony_ci break; 158362306a36Sopenharmony_ci case 6: 158462306a36Sopenharmony_ci case 7: 158562306a36Sopenharmony_ci *quanta = 4; 158662306a36Sopenharmony_ci break; 158762306a36Sopenharmony_ci case 8: 158862306a36Sopenharmony_ci case 9: 158962306a36Sopenharmony_ci *quanta = 5; 159062306a36Sopenharmony_ci break; 159162306a36Sopenharmony_ci case 10: 159262306a36Sopenharmony_ci case 11: 159362306a36Sopenharmony_ci *quanta = 6; 159462306a36Sopenharmony_ci break; 159562306a36Sopenharmony_ci case 12: 159662306a36Sopenharmony_ci case 13: 159762306a36Sopenharmony_ci *quanta = 7; 159862306a36Sopenharmony_ci break; 159962306a36Sopenharmony_ci case 14: 160062306a36Sopenharmony_ci case 15: /* when immediate data is present */ 160162306a36Sopenharmony_ci *quanta = 8; 160262306a36Sopenharmony_ci break; 160362306a36Sopenharmony_ci default: 160462306a36Sopenharmony_ci return -EINVAL; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci return 0; 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci/** 161162306a36Sopenharmony_ci * irdma_fragcnt_to_wqesize_rq - calculate wqe size based on fragment count for RQ 161262306a36Sopenharmony_ci * @frag_cnt: number of fragments 161362306a36Sopenharmony_ci * @wqe_size: size in bytes given frag_cnt 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_ciint irdma_fragcnt_to_wqesize_rq(u32 frag_cnt, u16 *wqe_size) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci switch (frag_cnt) { 161862306a36Sopenharmony_ci case 0: 161962306a36Sopenharmony_ci case 1: 162062306a36Sopenharmony_ci *wqe_size = 32; 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci case 2: 162362306a36Sopenharmony_ci case 3: 162462306a36Sopenharmony_ci *wqe_size = 64; 162562306a36Sopenharmony_ci break; 162662306a36Sopenharmony_ci case 4: 162762306a36Sopenharmony_ci case 5: 162862306a36Sopenharmony_ci case 6: 162962306a36Sopenharmony_ci case 7: 163062306a36Sopenharmony_ci *wqe_size = 128; 163162306a36Sopenharmony_ci break; 163262306a36Sopenharmony_ci case 8: 163362306a36Sopenharmony_ci case 9: 163462306a36Sopenharmony_ci case 10: 163562306a36Sopenharmony_ci case 11: 163662306a36Sopenharmony_ci case 12: 163762306a36Sopenharmony_ci case 13: 163862306a36Sopenharmony_ci case 14: 163962306a36Sopenharmony_ci *wqe_size = 256; 164062306a36Sopenharmony_ci break; 164162306a36Sopenharmony_ci default: 164262306a36Sopenharmony_ci return -EINVAL; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci return 0; 164662306a36Sopenharmony_ci} 1647