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 "hmc.h" 562306a36Sopenharmony_ci#include "defs.h" 662306a36Sopenharmony_ci#include "type.h" 762306a36Sopenharmony_ci#include "protos.h" 862306a36Sopenharmony_ci#include "puda.h" 962306a36Sopenharmony_ci#include "ws.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic void irdma_ieq_receive(struct irdma_sc_vsi *vsi, 1262306a36Sopenharmony_ci struct irdma_puda_buf *buf); 1362306a36Sopenharmony_cistatic void irdma_ieq_tx_compl(struct irdma_sc_vsi *vsi, void *sqwrid); 1462306a36Sopenharmony_cistatic void irdma_ilq_putback_rcvbuf(struct irdma_sc_qp *qp, 1562306a36Sopenharmony_ci struct irdma_puda_buf *buf, u32 wqe_idx); 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * irdma_puda_get_listbuf - get buffer from puda list 1862306a36Sopenharmony_ci * @list: list to use for buffers (ILQ or IEQ) 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_cistatic struct irdma_puda_buf *irdma_puda_get_listbuf(struct list_head *list) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct irdma_puda_buf *buf = NULL; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (!list_empty(list)) { 2562306a36Sopenharmony_ci buf = (struct irdma_puda_buf *)list->next; 2662306a36Sopenharmony_ci list_del((struct list_head *)&buf->list); 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci return buf; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/** 3362306a36Sopenharmony_ci * irdma_puda_get_bufpool - return buffer from resource 3462306a36Sopenharmony_ci * @rsrc: resource to use for buffer 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistruct irdma_puda_buf *irdma_puda_get_bufpool(struct irdma_puda_rsrc *rsrc) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct irdma_puda_buf *buf = NULL; 3962306a36Sopenharmony_ci struct list_head *list = &rsrc->bufpool; 4062306a36Sopenharmony_ci unsigned long flags; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci spin_lock_irqsave(&rsrc->bufpool_lock, flags); 4362306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(list); 4462306a36Sopenharmony_ci if (buf) { 4562306a36Sopenharmony_ci rsrc->avail_buf_count--; 4662306a36Sopenharmony_ci buf->vsi = rsrc->vsi; 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci rsrc->stats_buf_alloc_fail++; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return buf; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** 5662306a36Sopenharmony_ci * irdma_puda_ret_bufpool - return buffer to rsrc list 5762306a36Sopenharmony_ci * @rsrc: resource to use for buffer 5862306a36Sopenharmony_ci * @buf: buffer to return to resource 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_civoid irdma_puda_ret_bufpool(struct irdma_puda_rsrc *rsrc, 6162306a36Sopenharmony_ci struct irdma_puda_buf *buf) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci unsigned long flags; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci buf->do_lpb = false; 6662306a36Sopenharmony_ci spin_lock_irqsave(&rsrc->bufpool_lock, flags); 6762306a36Sopenharmony_ci list_add(&buf->list, &rsrc->bufpool); 6862306a36Sopenharmony_ci spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); 6962306a36Sopenharmony_ci rsrc->avail_buf_count++; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * irdma_puda_post_recvbuf - set wqe for rcv buffer 7462306a36Sopenharmony_ci * @rsrc: resource ptr 7562306a36Sopenharmony_ci * @wqe_idx: wqe index to use 7662306a36Sopenharmony_ci * @buf: puda buffer for rcv q 7762306a36Sopenharmony_ci * @initial: flag if during init time 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cistatic void irdma_puda_post_recvbuf(struct irdma_puda_rsrc *rsrc, u32 wqe_idx, 8062306a36Sopenharmony_ci struct irdma_puda_buf *buf, bool initial) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci __le64 *wqe; 8362306a36Sopenharmony_ci struct irdma_sc_qp *qp = &rsrc->qp; 8462306a36Sopenharmony_ci u64 offset24 = 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Synch buffer for use by device */ 8762306a36Sopenharmony_ci dma_sync_single_for_device(rsrc->dev->hw->device, buf->mem.pa, 8862306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 8962306a36Sopenharmony_ci qp->qp_uk.rq_wrid_array[wqe_idx] = (uintptr_t)buf; 9062306a36Sopenharmony_ci wqe = qp->qp_uk.rq_base[wqe_idx].elem; 9162306a36Sopenharmony_ci if (!initial) 9262306a36Sopenharmony_ci get_64bit_val(wqe, 24, &offset24); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci offset24 = (offset24) ? 0 : FIELD_PREP(IRDMAQPSQ_VALID, 1); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci set_64bit_val(wqe, 16, 0); 9762306a36Sopenharmony_ci set_64bit_val(wqe, 0, buf->mem.pa); 9862306a36Sopenharmony_ci if (qp->qp_uk.uk_attrs->hw_rev == IRDMA_GEN_1) { 9962306a36Sopenharmony_ci set_64bit_val(wqe, 8, 10062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, buf->mem.size)); 10162306a36Sopenharmony_ci } else { 10262306a36Sopenharmony_ci set_64bit_val(wqe, 8, 10362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_LEN, buf->mem.size) | 10462306a36Sopenharmony_ci offset24); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is written before valid bit is set */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci set_64bit_val(wqe, 24, offset24); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/** 11262306a36Sopenharmony_ci * irdma_puda_replenish_rq - post rcv buffers 11362306a36Sopenharmony_ci * @rsrc: resource to use for buffer 11462306a36Sopenharmony_ci * @initial: flag if during init time 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic int irdma_puda_replenish_rq(struct irdma_puda_rsrc *rsrc, bool initial) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci u32 i; 11962306a36Sopenharmony_ci u32 invalid_cnt = rsrc->rxq_invalid_cnt; 12062306a36Sopenharmony_ci struct irdma_puda_buf *buf = NULL; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci for (i = 0; i < invalid_cnt; i++) { 12362306a36Sopenharmony_ci buf = irdma_puda_get_bufpool(rsrc); 12462306a36Sopenharmony_ci if (!buf) 12562306a36Sopenharmony_ci return -ENOBUFS; 12662306a36Sopenharmony_ci irdma_puda_post_recvbuf(rsrc, rsrc->rx_wqe_idx, buf, initial); 12762306a36Sopenharmony_ci rsrc->rx_wqe_idx = ((rsrc->rx_wqe_idx + 1) % rsrc->rq_size); 12862306a36Sopenharmony_ci rsrc->rxq_invalid_cnt--; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * irdma_puda_alloc_buf - allocate mem for buffer 13662306a36Sopenharmony_ci * @dev: iwarp device 13762306a36Sopenharmony_ci * @len: length of buffer 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistatic struct irdma_puda_buf *irdma_puda_alloc_buf(struct irdma_sc_dev *dev, 14062306a36Sopenharmony_ci u32 len) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct irdma_puda_buf *buf; 14362306a36Sopenharmony_ci struct irdma_virt_mem buf_mem; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci buf_mem.size = sizeof(struct irdma_puda_buf); 14662306a36Sopenharmony_ci buf_mem.va = kzalloc(buf_mem.size, GFP_KERNEL); 14762306a36Sopenharmony_ci if (!buf_mem.va) 14862306a36Sopenharmony_ci return NULL; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci buf = buf_mem.va; 15162306a36Sopenharmony_ci buf->mem.size = len; 15262306a36Sopenharmony_ci buf->mem.va = kzalloc(buf->mem.size, GFP_KERNEL); 15362306a36Sopenharmony_ci if (!buf->mem.va) 15462306a36Sopenharmony_ci goto free_virt; 15562306a36Sopenharmony_ci buf->mem.pa = dma_map_single(dev->hw->device, buf->mem.va, 15662306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 15762306a36Sopenharmony_ci if (dma_mapping_error(dev->hw->device, buf->mem.pa)) { 15862306a36Sopenharmony_ci kfree(buf->mem.va); 15962306a36Sopenharmony_ci goto free_virt; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci buf->buf_mem.va = buf_mem.va; 16362306a36Sopenharmony_ci buf->buf_mem.size = buf_mem.size; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return buf; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cifree_virt: 16862306a36Sopenharmony_ci kfree(buf_mem.va); 16962306a36Sopenharmony_ci return NULL; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * irdma_puda_dele_buf - delete buffer back to system 17462306a36Sopenharmony_ci * @dev: iwarp device 17562306a36Sopenharmony_ci * @buf: buffer to free 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic void irdma_puda_dele_buf(struct irdma_sc_dev *dev, 17862306a36Sopenharmony_ci struct irdma_puda_buf *buf) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci dma_unmap_single(dev->hw->device, buf->mem.pa, buf->mem.size, 18162306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 18262306a36Sopenharmony_ci kfree(buf->mem.va); 18362306a36Sopenharmony_ci kfree(buf->buf_mem.va); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/** 18762306a36Sopenharmony_ci * irdma_puda_get_next_send_wqe - return next wqe for processing 18862306a36Sopenharmony_ci * @qp: puda qp for wqe 18962306a36Sopenharmony_ci * @wqe_idx: wqe index for caller 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic __le64 *irdma_puda_get_next_send_wqe(struct irdma_qp_uk *qp, 19262306a36Sopenharmony_ci u32 *wqe_idx) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int ret_code = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci *wqe_idx = IRDMA_RING_CURRENT_HEAD(qp->sq_ring); 19762306a36Sopenharmony_ci if (!*wqe_idx) 19862306a36Sopenharmony_ci qp->swqe_polarity = !qp->swqe_polarity; 19962306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD(qp->sq_ring, ret_code); 20062306a36Sopenharmony_ci if (ret_code) 20162306a36Sopenharmony_ci return NULL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return qp->sq_base[*wqe_idx].elem; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/** 20762306a36Sopenharmony_ci * irdma_puda_poll_info - poll cq for completion 20862306a36Sopenharmony_ci * @cq: cq for poll 20962306a36Sopenharmony_ci * @info: info return for successful completion 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic int irdma_puda_poll_info(struct irdma_sc_cq *cq, 21262306a36Sopenharmony_ci struct irdma_puda_cmpl_info *info) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct irdma_cq_uk *cq_uk = &cq->cq_uk; 21562306a36Sopenharmony_ci u64 qword0, qword2, qword3, qword6; 21662306a36Sopenharmony_ci __le64 *cqe; 21762306a36Sopenharmony_ci __le64 *ext_cqe = NULL; 21862306a36Sopenharmony_ci u64 qword7 = 0; 21962306a36Sopenharmony_ci u64 comp_ctx; 22062306a36Sopenharmony_ci bool valid_bit; 22162306a36Sopenharmony_ci bool ext_valid = 0; 22262306a36Sopenharmony_ci u32 major_err, minor_err; 22362306a36Sopenharmony_ci u32 peek_head; 22462306a36Sopenharmony_ci bool error; 22562306a36Sopenharmony_ci u8 polarity; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci cqe = IRDMA_GET_CURRENT_CQ_ELEM(&cq->cq_uk); 22862306a36Sopenharmony_ci get_64bit_val(cqe, 24, &qword3); 22962306a36Sopenharmony_ci valid_bit = (bool)FIELD_GET(IRDMA_CQ_VALID, qword3); 23062306a36Sopenharmony_ci if (valid_bit != cq_uk->polarity) 23162306a36Sopenharmony_ci return -ENOENT; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Ensure CQE contents are read after valid bit is checked */ 23462306a36Sopenharmony_ci dma_rmb(); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (cq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) 23762306a36Sopenharmony_ci ext_valid = (bool)FIELD_GET(IRDMA_CQ_EXTCQE, qword3); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (ext_valid) { 24062306a36Sopenharmony_ci peek_head = (cq_uk->cq_ring.head + 1) % cq_uk->cq_ring.size; 24162306a36Sopenharmony_ci ext_cqe = cq_uk->cq_base[peek_head].buf; 24262306a36Sopenharmony_ci get_64bit_val(ext_cqe, 24, &qword7); 24362306a36Sopenharmony_ci polarity = (u8)FIELD_GET(IRDMA_CQ_VALID, qword7); 24462306a36Sopenharmony_ci if (!peek_head) 24562306a36Sopenharmony_ci polarity ^= 1; 24662306a36Sopenharmony_ci if (polarity != cq_uk->polarity) 24762306a36Sopenharmony_ci return -ENOENT; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Ensure ext CQE contents are read after ext valid bit is checked */ 25062306a36Sopenharmony_ci dma_rmb(); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(cq_uk->cq_ring); 25362306a36Sopenharmony_ci if (!IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring)) 25462306a36Sopenharmony_ci cq_uk->polarity = !cq_uk->polarity; 25562306a36Sopenharmony_ci /* update cq tail in cq shadow memory also */ 25662306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL(cq_uk->cq_ring); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA CQE", DUMP_PREFIX_OFFSET, 16, 8, cqe, 26062306a36Sopenharmony_ci 32, false); 26162306a36Sopenharmony_ci if (ext_valid) 26262306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA EXT-CQE", DUMP_PREFIX_OFFSET, 26362306a36Sopenharmony_ci 16, 8, ext_cqe, 32, false); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci error = (bool)FIELD_GET(IRDMA_CQ_ERROR, qword3); 26662306a36Sopenharmony_ci if (error) { 26762306a36Sopenharmony_ci ibdev_dbg(to_ibdev(cq->dev), "PUDA: receive error\n"); 26862306a36Sopenharmony_ci major_err = (u32)(FIELD_GET(IRDMA_CQ_MAJERR, qword3)); 26962306a36Sopenharmony_ci minor_err = (u32)(FIELD_GET(IRDMA_CQ_MINERR, qword3)); 27062306a36Sopenharmony_ci info->compl_error = major_err << 16 | minor_err; 27162306a36Sopenharmony_ci return -EIO; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci get_64bit_val(cqe, 0, &qword0); 27562306a36Sopenharmony_ci get_64bit_val(cqe, 16, &qword2); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci info->q_type = (u8)FIELD_GET(IRDMA_CQ_SQ, qword3); 27862306a36Sopenharmony_ci info->qp_id = (u32)FIELD_GET(IRDMACQ_QPID, qword2); 27962306a36Sopenharmony_ci if (cq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) 28062306a36Sopenharmony_ci info->ipv4 = (bool)FIELD_GET(IRDMACQ_IPV4, qword3); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci get_64bit_val(cqe, 8, &comp_ctx); 28362306a36Sopenharmony_ci info->qp = (struct irdma_qp_uk *)(unsigned long)comp_ctx; 28462306a36Sopenharmony_ci info->wqe_idx = (u32)FIELD_GET(IRDMA_CQ_WQEIDX, qword3); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (info->q_type == IRDMA_CQE_QTYPE_RQ) { 28762306a36Sopenharmony_ci if (ext_valid) { 28862306a36Sopenharmony_ci info->vlan_valid = (bool)FIELD_GET(IRDMA_CQ_UDVLANVALID, qword7); 28962306a36Sopenharmony_ci if (info->vlan_valid) { 29062306a36Sopenharmony_ci get_64bit_val(ext_cqe, 16, &qword6); 29162306a36Sopenharmony_ci info->vlan = (u16)FIELD_GET(IRDMA_CQ_UDVLAN, qword6); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci info->smac_valid = (bool)FIELD_GET(IRDMA_CQ_UDSMACVALID, qword7); 29462306a36Sopenharmony_ci if (info->smac_valid) { 29562306a36Sopenharmony_ci get_64bit_val(ext_cqe, 16, &qword6); 29662306a36Sopenharmony_ci info->smac[0] = (u8)((qword6 >> 40) & 0xFF); 29762306a36Sopenharmony_ci info->smac[1] = (u8)((qword6 >> 32) & 0xFF); 29862306a36Sopenharmony_ci info->smac[2] = (u8)((qword6 >> 24) & 0xFF); 29962306a36Sopenharmony_ci info->smac[3] = (u8)((qword6 >> 16) & 0xFF); 30062306a36Sopenharmony_ci info->smac[4] = (u8)((qword6 >> 8) & 0xFF); 30162306a36Sopenharmony_ci info->smac[5] = (u8)(qword6 & 0xFF); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (cq->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) { 30662306a36Sopenharmony_ci info->vlan_valid = (bool)FIELD_GET(IRDMA_VLAN_TAG_VALID, qword3); 30762306a36Sopenharmony_ci info->l4proto = (u8)FIELD_GET(IRDMA_UDA_L4PROTO, qword2); 30862306a36Sopenharmony_ci info->l3proto = (u8)FIELD_GET(IRDMA_UDA_L3PROTO, qword2); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci info->payload_len = (u32)FIELD_GET(IRDMACQ_PAYLDLEN, qword0); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return 0; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/** 31862306a36Sopenharmony_ci * irdma_puda_poll_cmpl - processes completion for cq 31962306a36Sopenharmony_ci * @dev: iwarp device 32062306a36Sopenharmony_ci * @cq: cq getting interrupt 32162306a36Sopenharmony_ci * @compl_err: return any completion err 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ciint irdma_puda_poll_cmpl(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq, 32462306a36Sopenharmony_ci u32 *compl_err) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct irdma_qp_uk *qp; 32762306a36Sopenharmony_ci struct irdma_cq_uk *cq_uk = &cq->cq_uk; 32862306a36Sopenharmony_ci struct irdma_puda_cmpl_info info = {}; 32962306a36Sopenharmony_ci int ret = 0; 33062306a36Sopenharmony_ci struct irdma_puda_buf *buf; 33162306a36Sopenharmony_ci struct irdma_puda_rsrc *rsrc; 33262306a36Sopenharmony_ci u8 cq_type = cq->cq_type; 33362306a36Sopenharmony_ci unsigned long flags; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (cq_type == IRDMA_CQ_TYPE_ILQ || cq_type == IRDMA_CQ_TYPE_IEQ) { 33662306a36Sopenharmony_ci rsrc = (cq_type == IRDMA_CQ_TYPE_ILQ) ? cq->vsi->ilq : 33762306a36Sopenharmony_ci cq->vsi->ieq; 33862306a36Sopenharmony_ci } else { 33962306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: qp_type error\n"); 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ret = irdma_puda_poll_info(cq, &info); 34462306a36Sopenharmony_ci *compl_err = info.compl_error; 34562306a36Sopenharmony_ci if (ret == -ENOENT) 34662306a36Sopenharmony_ci return ret; 34762306a36Sopenharmony_ci if (ret) 34862306a36Sopenharmony_ci goto done; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci qp = info.qp; 35162306a36Sopenharmony_ci if (!qp || !rsrc) { 35262306a36Sopenharmony_ci ret = -EFAULT; 35362306a36Sopenharmony_ci goto done; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (qp->qp_id != rsrc->qp_id) { 35762306a36Sopenharmony_ci ret = -EFAULT; 35862306a36Sopenharmony_ci goto done; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (info.q_type == IRDMA_CQE_QTYPE_RQ) { 36262306a36Sopenharmony_ci buf = (struct irdma_puda_buf *)(uintptr_t) 36362306a36Sopenharmony_ci qp->rq_wrid_array[info.wqe_idx]; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* reusing so synch the buffer for CPU use */ 36662306a36Sopenharmony_ci dma_sync_single_for_cpu(dev->hw->device, buf->mem.pa, 36762306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 36862306a36Sopenharmony_ci /* Get all the tcpip information in the buf header */ 36962306a36Sopenharmony_ci ret = irdma_puda_get_tcpip_info(&info, buf); 37062306a36Sopenharmony_ci if (ret) { 37162306a36Sopenharmony_ci rsrc->stats_rcvd_pkt_err++; 37262306a36Sopenharmony_ci if (cq_type == IRDMA_CQ_TYPE_ILQ) { 37362306a36Sopenharmony_ci irdma_ilq_putback_rcvbuf(&rsrc->qp, buf, 37462306a36Sopenharmony_ci info.wqe_idx); 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci irdma_puda_ret_bufpool(rsrc, buf); 37762306a36Sopenharmony_ci irdma_puda_replenish_rq(rsrc, false); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci goto done; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci rsrc->stats_pkt_rcvd++; 38362306a36Sopenharmony_ci rsrc->compl_rxwqe_idx = info.wqe_idx; 38462306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: RQ completion\n"); 38562306a36Sopenharmony_ci rsrc->receive(rsrc->vsi, buf); 38662306a36Sopenharmony_ci if (cq_type == IRDMA_CQ_TYPE_ILQ) 38762306a36Sopenharmony_ci irdma_ilq_putback_rcvbuf(&rsrc->qp, buf, info.wqe_idx); 38862306a36Sopenharmony_ci else 38962306a36Sopenharmony_ci irdma_puda_replenish_rq(rsrc, false); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci } else { 39262306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: SQ completion\n"); 39362306a36Sopenharmony_ci buf = (struct irdma_puda_buf *)(uintptr_t) 39462306a36Sopenharmony_ci qp->sq_wrtrk_array[info.wqe_idx].wrid; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* reusing so synch the buffer for CPU use */ 39762306a36Sopenharmony_ci dma_sync_single_for_cpu(dev->hw->device, buf->mem.pa, 39862306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 39962306a36Sopenharmony_ci IRDMA_RING_SET_TAIL(qp->sq_ring, info.wqe_idx); 40062306a36Sopenharmony_ci rsrc->xmit_complete(rsrc->vsi, buf); 40162306a36Sopenharmony_ci spin_lock_irqsave(&rsrc->bufpool_lock, flags); 40262306a36Sopenharmony_ci rsrc->tx_wqe_avail_cnt++; 40362306a36Sopenharmony_ci spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); 40462306a36Sopenharmony_ci if (!list_empty(&rsrc->txpend)) 40562306a36Sopenharmony_ci irdma_puda_send_buf(rsrc, NULL); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cidone: 40962306a36Sopenharmony_ci IRDMA_RING_MOVE_HEAD_NOCHECK(cq_uk->cq_ring); 41062306a36Sopenharmony_ci if (!IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring)) 41162306a36Sopenharmony_ci cq_uk->polarity = !cq_uk->polarity; 41262306a36Sopenharmony_ci /* update cq tail in cq shadow memory also */ 41362306a36Sopenharmony_ci IRDMA_RING_MOVE_TAIL(cq_uk->cq_ring); 41462306a36Sopenharmony_ci set_64bit_val(cq_uk->shadow_area, 0, 41562306a36Sopenharmony_ci IRDMA_RING_CURRENT_HEAD(cq_uk->cq_ring)); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/** 42162306a36Sopenharmony_ci * irdma_puda_send - complete send wqe for transmit 42262306a36Sopenharmony_ci * @qp: puda qp for send 42362306a36Sopenharmony_ci * @info: buffer information for transmit 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ciint irdma_puda_send(struct irdma_sc_qp *qp, struct irdma_puda_send_info *info) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci __le64 *wqe; 42862306a36Sopenharmony_ci u32 iplen, l4len; 42962306a36Sopenharmony_ci u64 hdr[2]; 43062306a36Sopenharmony_ci u32 wqe_idx; 43162306a36Sopenharmony_ci u8 iipt; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* number of 32 bits DWORDS in header */ 43462306a36Sopenharmony_ci l4len = info->tcplen >> 2; 43562306a36Sopenharmony_ci if (info->ipv4) { 43662306a36Sopenharmony_ci iipt = 3; 43762306a36Sopenharmony_ci iplen = 5; 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci iipt = 1; 44062306a36Sopenharmony_ci iplen = 10; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci wqe = irdma_puda_get_next_send_wqe(&qp->qp_uk, &wqe_idx); 44462306a36Sopenharmony_ci if (!wqe) 44562306a36Sopenharmony_ci return -ENOMEM; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci qp->qp_uk.sq_wrtrk_array[wqe_idx].wrid = (uintptr_t)info->scratch; 44862306a36Sopenharmony_ci /* Third line of WQE descriptor */ 44962306a36Sopenharmony_ci /* maclen is in words */ 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (qp->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 45262306a36Sopenharmony_ci hdr[0] = 0; /* Dest_QPN and Dest_QKey only for UD */ 45362306a36Sopenharmony_ci hdr[1] = FIELD_PREP(IRDMA_UDA_QPSQ_OPCODE, IRDMA_OP_TYPE_SEND) | 45462306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_L4LEN, l4len) | 45562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_AHID, info->ah_id) | 45662306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_SIGCOMPL, 1) | 45762306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_VALID, 45862306a36Sopenharmony_ci qp->qp_uk.swqe_polarity); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Forth line of WQE descriptor */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci set_64bit_val(wqe, 0, info->paddr); 46362306a36Sopenharmony_ci set_64bit_val(wqe, 8, 46462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_FRAG_LEN, info->len) | 46562306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_VALID, qp->qp_uk.swqe_polarity)); 46662306a36Sopenharmony_ci } else { 46762306a36Sopenharmony_ci hdr[0] = FIELD_PREP(IRDMA_UDA_QPSQ_MACLEN, info->maclen >> 1) | 46862306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_IPLEN, iplen) | 46962306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_L4T, 1) | 47062306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_IIPT, iipt) | 47162306a36Sopenharmony_ci FIELD_PREP(IRDMA_GEN1_UDA_QPSQ_L4LEN, l4len); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci hdr[1] = FIELD_PREP(IRDMA_UDA_QPSQ_OPCODE, IRDMA_OP_TYPE_SEND) | 47462306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_SIGCOMPL, 1) | 47562306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_DOLOOPBACK, info->do_lpb) | 47662306a36Sopenharmony_ci FIELD_PREP(IRDMA_UDA_QPSQ_VALID, qp->qp_uk.swqe_polarity); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Forth line of WQE descriptor */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci set_64bit_val(wqe, 0, info->paddr); 48162306a36Sopenharmony_ci set_64bit_val(wqe, 8, 48262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPSQ_GEN1_FRAG_LEN, info->len)); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci set_64bit_val(wqe, 16, hdr[0]); 48662306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is written before valid bit is set */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr[1]); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA SEND WQE", DUMP_PREFIX_OFFSET, 16, 8, 49162306a36Sopenharmony_ci wqe, 32, false); 49262306a36Sopenharmony_ci irdma_uk_qp_post_wr(&qp->qp_uk); 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/** 49762306a36Sopenharmony_ci * irdma_puda_send_buf - transmit puda buffer 49862306a36Sopenharmony_ci * @rsrc: resource to use for buffer 49962306a36Sopenharmony_ci * @buf: puda buffer to transmit 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_civoid irdma_puda_send_buf(struct irdma_puda_rsrc *rsrc, 50262306a36Sopenharmony_ci struct irdma_puda_buf *buf) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct irdma_puda_send_info info; 50562306a36Sopenharmony_ci int ret = 0; 50662306a36Sopenharmony_ci unsigned long flags; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci spin_lock_irqsave(&rsrc->bufpool_lock, flags); 50962306a36Sopenharmony_ci /* if no wqe available or not from a completion and we have 51062306a36Sopenharmony_ci * pending buffers, we must queue new buffer 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci if (!rsrc->tx_wqe_avail_cnt || (buf && !list_empty(&rsrc->txpend))) { 51362306a36Sopenharmony_ci list_add_tail(&buf->list, &rsrc->txpend); 51462306a36Sopenharmony_ci spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); 51562306a36Sopenharmony_ci rsrc->stats_sent_pkt_q++; 51662306a36Sopenharmony_ci if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ) 51762306a36Sopenharmony_ci ibdev_dbg(to_ibdev(rsrc->dev), 51862306a36Sopenharmony_ci "PUDA: adding to txpend\n"); 51962306a36Sopenharmony_ci return; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci rsrc->tx_wqe_avail_cnt--; 52262306a36Sopenharmony_ci /* if we are coming from a completion and have pending buffers 52362306a36Sopenharmony_ci * then Get one from pending list 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci if (!buf) { 52662306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(&rsrc->txpend); 52762306a36Sopenharmony_ci if (!buf) 52862306a36Sopenharmony_ci goto done; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci info.scratch = buf; 53262306a36Sopenharmony_ci info.paddr = buf->mem.pa; 53362306a36Sopenharmony_ci info.len = buf->totallen; 53462306a36Sopenharmony_ci info.tcplen = buf->tcphlen; 53562306a36Sopenharmony_ci info.ipv4 = buf->ipv4; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (rsrc->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 53862306a36Sopenharmony_ci info.ah_id = buf->ah_id; 53962306a36Sopenharmony_ci } else { 54062306a36Sopenharmony_ci info.maclen = buf->maclen; 54162306a36Sopenharmony_ci info.do_lpb = buf->do_lpb; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Synch buffer for use by device */ 54562306a36Sopenharmony_ci dma_sync_single_for_cpu(rsrc->dev->hw->device, buf->mem.pa, 54662306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 54762306a36Sopenharmony_ci ret = irdma_puda_send(&rsrc->qp, &info); 54862306a36Sopenharmony_ci if (ret) { 54962306a36Sopenharmony_ci rsrc->tx_wqe_avail_cnt++; 55062306a36Sopenharmony_ci rsrc->stats_sent_pkt_q++; 55162306a36Sopenharmony_ci list_add(&buf->list, &rsrc->txpend); 55262306a36Sopenharmony_ci if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ) 55362306a36Sopenharmony_ci ibdev_dbg(to_ibdev(rsrc->dev), 55462306a36Sopenharmony_ci "PUDA: adding to puda_send\n"); 55562306a36Sopenharmony_ci } else { 55662306a36Sopenharmony_ci rsrc->stats_pkt_sent++; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_cidone: 55962306a36Sopenharmony_ci spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/** 56362306a36Sopenharmony_ci * irdma_puda_qp_setctx - during init, set qp's context 56462306a36Sopenharmony_ci * @rsrc: qp's resource 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_cistatic void irdma_puda_qp_setctx(struct irdma_puda_rsrc *rsrc) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct irdma_sc_qp *qp = &rsrc->qp; 56962306a36Sopenharmony_ci __le64 *qp_ctx = qp->hw_host_ctx; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci set_64bit_val(qp_ctx, 8, qp->sq_pa); 57262306a36Sopenharmony_ci set_64bit_val(qp_ctx, 16, qp->rq_pa); 57362306a36Sopenharmony_ci set_64bit_val(qp_ctx, 24, 57462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_RQSIZE, qp->hw_rq_size) | 57562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_SQSIZE, qp->hw_sq_size)); 57662306a36Sopenharmony_ci set_64bit_val(qp_ctx, 48, 57762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_SNDMSS, rsrc->buf_size)); 57862306a36Sopenharmony_ci set_64bit_val(qp_ctx, 56, 0); 57962306a36Sopenharmony_ci if (qp->dev->hw_attrs.uk_attrs.hw_rev == IRDMA_GEN_1) 58062306a36Sopenharmony_ci set_64bit_val(qp_ctx, 64, 1); 58162306a36Sopenharmony_ci set_64bit_val(qp_ctx, 136, 58262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_TXCQNUM, rsrc->cq_id) | 58362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_RXCQNUM, rsrc->cq_id)); 58462306a36Sopenharmony_ci set_64bit_val(qp_ctx, 144, 58562306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_STAT_INDEX, rsrc->stats_idx)); 58662306a36Sopenharmony_ci set_64bit_val(qp_ctx, 160, 58762306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_PRIVEN, 1) | 58862306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_USESTATSINSTANCE, rsrc->stats_idx_valid)); 58962306a36Sopenharmony_ci set_64bit_val(qp_ctx, 168, 59062306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_QPCOMPCTX, (uintptr_t)qp)); 59162306a36Sopenharmony_ci set_64bit_val(qp_ctx, 176, 59262306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_SQTPHVAL, qp->sq_tph_val) | 59362306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_RQTPHVAL, qp->rq_tph_val) | 59462306a36Sopenharmony_ci FIELD_PREP(IRDMAQPC_QSHANDLE, qp->qs_handle)); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA QP CONTEXT", DUMP_PREFIX_OFFSET, 16, 59762306a36Sopenharmony_ci 8, qp_ctx, IRDMA_QP_CTX_SIZE, false); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/** 60162306a36Sopenharmony_ci * irdma_puda_qp_wqe - setup wqe for qp create 60262306a36Sopenharmony_ci * @dev: Device 60362306a36Sopenharmony_ci * @qp: Resource qp 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_cistatic int irdma_puda_qp_wqe(struct irdma_sc_dev *dev, struct irdma_sc_qp *qp) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct irdma_sc_cqp *cqp; 60862306a36Sopenharmony_ci __le64 *wqe; 60962306a36Sopenharmony_ci u64 hdr; 61062306a36Sopenharmony_ci struct irdma_ccq_cqe_info compl_info; 61162306a36Sopenharmony_ci int status = 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci cqp = dev->cqp; 61462306a36Sopenharmony_ci wqe = irdma_sc_cqp_get_next_send_wqe(cqp, 0); 61562306a36Sopenharmony_ci if (!wqe) 61662306a36Sopenharmony_ci return -ENOMEM; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci set_64bit_val(wqe, 16, qp->hw_host_ctx_pa); 61962306a36Sopenharmony_ci set_64bit_val(wqe, 40, qp->shadow_area_pa); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci hdr = qp->qp_uk.qp_id | 62262306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_QP) | 62362306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_QP_QPTYPE, IRDMA_QP_TYPE_UDA) | 62462306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_QP_CQNUMVALID, 1) | 62562306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_QP_NEXTIWSTATE, 2) | 62662306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity); 62762306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is written before valid bit is set */ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA QP CREATE", DUMP_PREFIX_OFFSET, 16, 63262306a36Sopenharmony_ci 8, wqe, 40, false); 63362306a36Sopenharmony_ci irdma_sc_cqp_post_sq(cqp); 63462306a36Sopenharmony_ci status = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_CREATE_QP, 63562306a36Sopenharmony_ci &compl_info); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return status; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/** 64162306a36Sopenharmony_ci * irdma_puda_qp_create - create qp for resource 64262306a36Sopenharmony_ci * @rsrc: resource to use for buffer 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_cistatic int irdma_puda_qp_create(struct irdma_puda_rsrc *rsrc) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct irdma_sc_qp *qp = &rsrc->qp; 64762306a36Sopenharmony_ci struct irdma_qp_uk *ukqp = &qp->qp_uk; 64862306a36Sopenharmony_ci int ret = 0; 64962306a36Sopenharmony_ci u32 sq_size, rq_size; 65062306a36Sopenharmony_ci struct irdma_dma_mem *mem; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci sq_size = rsrc->sq_size * IRDMA_QP_WQE_MIN_SIZE; 65362306a36Sopenharmony_ci rq_size = rsrc->rq_size * IRDMA_QP_WQE_MIN_SIZE; 65462306a36Sopenharmony_ci rsrc->qpmem.size = ALIGN((sq_size + rq_size + (IRDMA_SHADOW_AREA_SIZE << 3) + IRDMA_QP_CTX_SIZE), 65562306a36Sopenharmony_ci IRDMA_HW_PAGE_SIZE); 65662306a36Sopenharmony_ci rsrc->qpmem.va = dma_alloc_coherent(rsrc->dev->hw->device, 65762306a36Sopenharmony_ci rsrc->qpmem.size, &rsrc->qpmem.pa, 65862306a36Sopenharmony_ci GFP_KERNEL); 65962306a36Sopenharmony_ci if (!rsrc->qpmem.va) 66062306a36Sopenharmony_ci return -ENOMEM; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci mem = &rsrc->qpmem; 66362306a36Sopenharmony_ci memset(mem->va, 0, rsrc->qpmem.size); 66462306a36Sopenharmony_ci qp->hw_sq_size = irdma_get_encoded_wqe_size(rsrc->sq_size, IRDMA_QUEUE_TYPE_SQ_RQ); 66562306a36Sopenharmony_ci qp->hw_rq_size = irdma_get_encoded_wqe_size(rsrc->rq_size, IRDMA_QUEUE_TYPE_SQ_RQ); 66662306a36Sopenharmony_ci qp->pd = &rsrc->sc_pd; 66762306a36Sopenharmony_ci qp->qp_uk.qp_type = IRDMA_QP_TYPE_UDA; 66862306a36Sopenharmony_ci qp->dev = rsrc->dev; 66962306a36Sopenharmony_ci qp->qp_uk.back_qp = rsrc; 67062306a36Sopenharmony_ci qp->sq_pa = mem->pa; 67162306a36Sopenharmony_ci qp->rq_pa = qp->sq_pa + sq_size; 67262306a36Sopenharmony_ci qp->vsi = rsrc->vsi; 67362306a36Sopenharmony_ci ukqp->sq_base = mem->va; 67462306a36Sopenharmony_ci ukqp->rq_base = &ukqp->sq_base[rsrc->sq_size]; 67562306a36Sopenharmony_ci ukqp->shadow_area = ukqp->rq_base[rsrc->rq_size].elem; 67662306a36Sopenharmony_ci ukqp->uk_attrs = &qp->dev->hw_attrs.uk_attrs; 67762306a36Sopenharmony_ci qp->shadow_area_pa = qp->rq_pa + rq_size; 67862306a36Sopenharmony_ci qp->hw_host_ctx = ukqp->shadow_area + IRDMA_SHADOW_AREA_SIZE; 67962306a36Sopenharmony_ci qp->hw_host_ctx_pa = qp->shadow_area_pa + (IRDMA_SHADOW_AREA_SIZE << 3); 68062306a36Sopenharmony_ci qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX; 68162306a36Sopenharmony_ci ukqp->qp_id = rsrc->qp_id; 68262306a36Sopenharmony_ci ukqp->sq_wrtrk_array = rsrc->sq_wrtrk_array; 68362306a36Sopenharmony_ci ukqp->rq_wrid_array = rsrc->rq_wrid_array; 68462306a36Sopenharmony_ci ukqp->sq_size = rsrc->sq_size; 68562306a36Sopenharmony_ci ukqp->rq_size = rsrc->rq_size; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci IRDMA_RING_INIT(ukqp->sq_ring, ukqp->sq_size); 68862306a36Sopenharmony_ci IRDMA_RING_INIT(ukqp->initial_ring, ukqp->sq_size); 68962306a36Sopenharmony_ci IRDMA_RING_INIT(ukqp->rq_ring, ukqp->rq_size); 69062306a36Sopenharmony_ci ukqp->wqe_alloc_db = qp->pd->dev->wqe_alloc_db; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ret = rsrc->dev->ws_add(qp->vsi, qp->user_pri); 69362306a36Sopenharmony_ci if (ret) { 69462306a36Sopenharmony_ci dma_free_coherent(rsrc->dev->hw->device, rsrc->qpmem.size, 69562306a36Sopenharmony_ci rsrc->qpmem.va, rsrc->qpmem.pa); 69662306a36Sopenharmony_ci rsrc->qpmem.va = NULL; 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci irdma_qp_add_qos(qp); 70162306a36Sopenharmony_ci irdma_puda_qp_setctx(rsrc); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (rsrc->dev->ceq_valid) 70462306a36Sopenharmony_ci ret = irdma_cqp_qp_create_cmd(rsrc->dev, qp); 70562306a36Sopenharmony_ci else 70662306a36Sopenharmony_ci ret = irdma_puda_qp_wqe(rsrc->dev, qp); 70762306a36Sopenharmony_ci if (ret) { 70862306a36Sopenharmony_ci irdma_qp_rem_qos(qp); 70962306a36Sopenharmony_ci rsrc->dev->ws_remove(qp->vsi, qp->user_pri); 71062306a36Sopenharmony_ci dma_free_coherent(rsrc->dev->hw->device, rsrc->qpmem.size, 71162306a36Sopenharmony_ci rsrc->qpmem.va, rsrc->qpmem.pa); 71262306a36Sopenharmony_ci rsrc->qpmem.va = NULL; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci return ret; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci/** 71962306a36Sopenharmony_ci * irdma_puda_cq_wqe - setup wqe for CQ create 72062306a36Sopenharmony_ci * @dev: Device 72162306a36Sopenharmony_ci * @cq: resource for cq 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_cistatic int irdma_puda_cq_wqe(struct irdma_sc_dev *dev, struct irdma_sc_cq *cq) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci __le64 *wqe; 72662306a36Sopenharmony_ci struct irdma_sc_cqp *cqp; 72762306a36Sopenharmony_ci u64 hdr; 72862306a36Sopenharmony_ci struct irdma_ccq_cqe_info compl_info; 72962306a36Sopenharmony_ci int status = 0; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci cqp = dev->cqp; 73262306a36Sopenharmony_ci wqe = irdma_sc_cqp_get_next_send_wqe(cqp, 0); 73362306a36Sopenharmony_ci if (!wqe) 73462306a36Sopenharmony_ci return -ENOMEM; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci set_64bit_val(wqe, 0, cq->cq_uk.cq_size); 73762306a36Sopenharmony_ci set_64bit_val(wqe, 8, (uintptr_t)cq >> 1); 73862306a36Sopenharmony_ci set_64bit_val(wqe, 16, 73962306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_CQ_SHADOW_READ_THRESHOLD, cq->shadow_read_threshold)); 74062306a36Sopenharmony_ci set_64bit_val(wqe, 32, cq->cq_pa); 74162306a36Sopenharmony_ci set_64bit_val(wqe, 40, cq->shadow_area_pa); 74262306a36Sopenharmony_ci set_64bit_val(wqe, 56, 74362306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_TPHVAL, cq->tph_val) | 74462306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_VSIIDX, cq->vsi->vsi_idx)); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci hdr = cq->cq_uk.cq_id | 74762306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_OPCODE, IRDMA_CQP_OP_CREATE_CQ) | 74862306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_CQ_CHKOVERFLOW, 1) | 74962306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_CQ_ENCEQEMASK, 1) | 75062306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_CQ_CEQIDVALID, 1) | 75162306a36Sopenharmony_ci FIELD_PREP(IRDMA_CQPSQ_WQEVALID, cqp->polarity); 75262306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is written before valid bit is set */ 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci set_64bit_val(wqe, 24, hdr); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci print_hex_dump_debug("PUDA: PUDA CREATE CQ", DUMP_PREFIX_OFFSET, 16, 75762306a36Sopenharmony_ci 8, wqe, IRDMA_CQP_WQE_SIZE * 8, false); 75862306a36Sopenharmony_ci irdma_sc_cqp_post_sq(dev->cqp); 75962306a36Sopenharmony_ci status = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_CREATE_CQ, 76062306a36Sopenharmony_ci &compl_info); 76162306a36Sopenharmony_ci if (!status) { 76262306a36Sopenharmony_ci struct irdma_sc_ceq *ceq = dev->ceq[0]; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (ceq && ceq->reg_cq) 76562306a36Sopenharmony_ci status = irdma_sc_add_cq_ctx(ceq, cq); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return status; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/** 77262306a36Sopenharmony_ci * irdma_puda_cq_create - create cq for resource 77362306a36Sopenharmony_ci * @rsrc: resource for which cq to create 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_cistatic int irdma_puda_cq_create(struct irdma_puda_rsrc *rsrc) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct irdma_sc_dev *dev = rsrc->dev; 77862306a36Sopenharmony_ci struct irdma_sc_cq *cq = &rsrc->cq; 77962306a36Sopenharmony_ci int ret = 0; 78062306a36Sopenharmony_ci u32 cqsize; 78162306a36Sopenharmony_ci struct irdma_dma_mem *mem; 78262306a36Sopenharmony_ci struct irdma_cq_init_info info = {}; 78362306a36Sopenharmony_ci struct irdma_cq_uk_init_info *init_info = &info.cq_uk_init_info; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci cq->vsi = rsrc->vsi; 78662306a36Sopenharmony_ci cqsize = rsrc->cq_size * (sizeof(struct irdma_cqe)); 78762306a36Sopenharmony_ci rsrc->cqmem.size = ALIGN(cqsize + sizeof(struct irdma_cq_shadow_area), 78862306a36Sopenharmony_ci IRDMA_CQ0_ALIGNMENT); 78962306a36Sopenharmony_ci rsrc->cqmem.va = dma_alloc_coherent(dev->hw->device, rsrc->cqmem.size, 79062306a36Sopenharmony_ci &rsrc->cqmem.pa, GFP_KERNEL); 79162306a36Sopenharmony_ci if (!rsrc->cqmem.va) 79262306a36Sopenharmony_ci return -ENOMEM; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci mem = &rsrc->cqmem; 79562306a36Sopenharmony_ci info.dev = dev; 79662306a36Sopenharmony_ci info.type = (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ) ? 79762306a36Sopenharmony_ci IRDMA_CQ_TYPE_ILQ : IRDMA_CQ_TYPE_IEQ; 79862306a36Sopenharmony_ci info.shadow_read_threshold = rsrc->cq_size >> 2; 79962306a36Sopenharmony_ci info.cq_base_pa = mem->pa; 80062306a36Sopenharmony_ci info.shadow_area_pa = mem->pa + cqsize; 80162306a36Sopenharmony_ci init_info->cq_base = mem->va; 80262306a36Sopenharmony_ci init_info->shadow_area = (__le64 *)((u8 *)mem->va + cqsize); 80362306a36Sopenharmony_ci init_info->cq_size = rsrc->cq_size; 80462306a36Sopenharmony_ci init_info->cq_id = rsrc->cq_id; 80562306a36Sopenharmony_ci info.ceqe_mask = true; 80662306a36Sopenharmony_ci info.ceq_id_valid = true; 80762306a36Sopenharmony_ci info.vsi = rsrc->vsi; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci ret = irdma_sc_cq_init(cq, &info); 81062306a36Sopenharmony_ci if (ret) 81162306a36Sopenharmony_ci goto error; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (rsrc->dev->ceq_valid) 81462306a36Sopenharmony_ci ret = irdma_cqp_cq_create_cmd(dev, cq); 81562306a36Sopenharmony_ci else 81662306a36Sopenharmony_ci ret = irdma_puda_cq_wqe(dev, cq); 81762306a36Sopenharmony_cierror: 81862306a36Sopenharmony_ci if (ret) { 81962306a36Sopenharmony_ci dma_free_coherent(dev->hw->device, rsrc->cqmem.size, 82062306a36Sopenharmony_ci rsrc->cqmem.va, rsrc->cqmem.pa); 82162306a36Sopenharmony_ci rsrc->cqmem.va = NULL; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return ret; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/** 82862306a36Sopenharmony_ci * irdma_puda_free_qp - free qp for resource 82962306a36Sopenharmony_ci * @rsrc: resource for which qp to free 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_cistatic void irdma_puda_free_qp(struct irdma_puda_rsrc *rsrc) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci int ret; 83462306a36Sopenharmony_ci struct irdma_ccq_cqe_info compl_info; 83562306a36Sopenharmony_ci struct irdma_sc_dev *dev = rsrc->dev; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (rsrc->dev->ceq_valid) { 83862306a36Sopenharmony_ci irdma_cqp_qp_destroy_cmd(dev, &rsrc->qp); 83962306a36Sopenharmony_ci rsrc->dev->ws_remove(rsrc->qp.vsi, rsrc->qp.user_pri); 84062306a36Sopenharmony_ci return; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci ret = irdma_sc_qp_destroy(&rsrc->qp, 0, false, true, true); 84462306a36Sopenharmony_ci if (ret) 84562306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), 84662306a36Sopenharmony_ci "PUDA: error puda qp destroy wqe, status = %d\n", 84762306a36Sopenharmony_ci ret); 84862306a36Sopenharmony_ci if (!ret) { 84962306a36Sopenharmony_ci ret = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_DESTROY_QP, 85062306a36Sopenharmony_ci &compl_info); 85162306a36Sopenharmony_ci if (ret) 85262306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), 85362306a36Sopenharmony_ci "PUDA: error puda qp destroy failed, status = %d\n", 85462306a36Sopenharmony_ci ret); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci rsrc->dev->ws_remove(rsrc->qp.vsi, rsrc->qp.user_pri); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/** 86062306a36Sopenharmony_ci * irdma_puda_free_cq - free cq for resource 86162306a36Sopenharmony_ci * @rsrc: resource for which cq to free 86262306a36Sopenharmony_ci */ 86362306a36Sopenharmony_cistatic void irdma_puda_free_cq(struct irdma_puda_rsrc *rsrc) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci int ret; 86662306a36Sopenharmony_ci struct irdma_ccq_cqe_info compl_info; 86762306a36Sopenharmony_ci struct irdma_sc_dev *dev = rsrc->dev; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (rsrc->dev->ceq_valid) { 87062306a36Sopenharmony_ci irdma_cqp_cq_destroy_cmd(dev, &rsrc->cq); 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ret = irdma_sc_cq_destroy(&rsrc->cq, 0, true); 87562306a36Sopenharmony_ci if (ret) 87662306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: error ieq cq destroy\n"); 87762306a36Sopenharmony_ci if (!ret) { 87862306a36Sopenharmony_ci ret = irdma_sc_poll_for_cqp_op_done(dev->cqp, IRDMA_CQP_OP_DESTROY_CQ, 87962306a36Sopenharmony_ci &compl_info); 88062306a36Sopenharmony_ci if (ret) 88162306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), 88262306a36Sopenharmony_ci "PUDA: error ieq qp destroy done\n"); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * irdma_puda_dele_rsrc - delete all resources during close 88862306a36Sopenharmony_ci * @vsi: VSI structure of device 88962306a36Sopenharmony_ci * @type: type of resource to dele 89062306a36Sopenharmony_ci * @reset: true if reset chip 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_civoid irdma_puda_dele_rsrc(struct irdma_sc_vsi *vsi, enum puda_rsrc_type type, 89362306a36Sopenharmony_ci bool reset) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct irdma_sc_dev *dev = vsi->dev; 89662306a36Sopenharmony_ci struct irdma_puda_rsrc *rsrc; 89762306a36Sopenharmony_ci struct irdma_puda_buf *buf = NULL; 89862306a36Sopenharmony_ci struct irdma_puda_buf *nextbuf = NULL; 89962306a36Sopenharmony_ci struct irdma_virt_mem *vmem; 90062306a36Sopenharmony_ci struct irdma_sc_ceq *ceq; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ceq = vsi->dev->ceq[0]; 90362306a36Sopenharmony_ci switch (type) { 90462306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_ILQ: 90562306a36Sopenharmony_ci rsrc = vsi->ilq; 90662306a36Sopenharmony_ci vmem = &vsi->ilq_mem; 90762306a36Sopenharmony_ci vsi->ilq = NULL; 90862306a36Sopenharmony_ci if (ceq && ceq->reg_cq) 90962306a36Sopenharmony_ci irdma_sc_remove_cq_ctx(ceq, &rsrc->cq); 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_IEQ: 91262306a36Sopenharmony_ci rsrc = vsi->ieq; 91362306a36Sopenharmony_ci vmem = &vsi->ieq_mem; 91462306a36Sopenharmony_ci vsi->ieq = NULL; 91562306a36Sopenharmony_ci if (ceq && ceq->reg_cq) 91662306a36Sopenharmony_ci irdma_sc_remove_cq_ctx(ceq, &rsrc->cq); 91762306a36Sopenharmony_ci break; 91862306a36Sopenharmony_ci default: 91962306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: error resource type = 0x%x\n", 92062306a36Sopenharmony_ci type); 92162306a36Sopenharmony_ci return; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci switch (rsrc->cmpl) { 92562306a36Sopenharmony_ci case PUDA_HASH_CRC_COMPLETE: 92662306a36Sopenharmony_ci irdma_free_hash_desc(rsrc->hash_desc); 92762306a36Sopenharmony_ci fallthrough; 92862306a36Sopenharmony_ci case PUDA_QP_CREATED: 92962306a36Sopenharmony_ci irdma_qp_rem_qos(&rsrc->qp); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!reset) 93262306a36Sopenharmony_ci irdma_puda_free_qp(rsrc); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci dma_free_coherent(dev->hw->device, rsrc->qpmem.size, 93562306a36Sopenharmony_ci rsrc->qpmem.va, rsrc->qpmem.pa); 93662306a36Sopenharmony_ci rsrc->qpmem.va = NULL; 93762306a36Sopenharmony_ci fallthrough; 93862306a36Sopenharmony_ci case PUDA_CQ_CREATED: 93962306a36Sopenharmony_ci if (!reset) 94062306a36Sopenharmony_ci irdma_puda_free_cq(rsrc); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci dma_free_coherent(dev->hw->device, rsrc->cqmem.size, 94362306a36Sopenharmony_ci rsrc->cqmem.va, rsrc->cqmem.pa); 94462306a36Sopenharmony_ci rsrc->cqmem.va = NULL; 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci default: 94762306a36Sopenharmony_ci ibdev_dbg(to_ibdev(rsrc->dev), "PUDA: error no resources\n"); 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci /* Free all allocated puda buffers for both tx and rx */ 95162306a36Sopenharmony_ci buf = rsrc->alloclist; 95262306a36Sopenharmony_ci while (buf) { 95362306a36Sopenharmony_ci nextbuf = buf->next; 95462306a36Sopenharmony_ci irdma_puda_dele_buf(dev, buf); 95562306a36Sopenharmony_ci buf = nextbuf; 95662306a36Sopenharmony_ci rsrc->alloc_buf_count--; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci kfree(vmem->va); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/** 96362306a36Sopenharmony_ci * irdma_puda_allocbufs - allocate buffers for resource 96462306a36Sopenharmony_ci * @rsrc: resource for buffer allocation 96562306a36Sopenharmony_ci * @count: number of buffers to create 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_cistatic int irdma_puda_allocbufs(struct irdma_puda_rsrc *rsrc, u32 count) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci u32 i; 97062306a36Sopenharmony_ci struct irdma_puda_buf *buf; 97162306a36Sopenharmony_ci struct irdma_puda_buf *nextbuf; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 97462306a36Sopenharmony_ci buf = irdma_puda_alloc_buf(rsrc->dev, rsrc->buf_size); 97562306a36Sopenharmony_ci if (!buf) { 97662306a36Sopenharmony_ci rsrc->stats_buf_alloc_fail++; 97762306a36Sopenharmony_ci return -ENOMEM; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci irdma_puda_ret_bufpool(rsrc, buf); 98062306a36Sopenharmony_ci rsrc->alloc_buf_count++; 98162306a36Sopenharmony_ci if (!rsrc->alloclist) { 98262306a36Sopenharmony_ci rsrc->alloclist = buf; 98362306a36Sopenharmony_ci } else { 98462306a36Sopenharmony_ci nextbuf = rsrc->alloclist; 98562306a36Sopenharmony_ci rsrc->alloclist = buf; 98662306a36Sopenharmony_ci buf->next = nextbuf; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci rsrc->avail_buf_count = rsrc->alloc_buf_count; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return 0; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci/** 99662306a36Sopenharmony_ci * irdma_puda_create_rsrc - create resource (ilq or ieq) 99762306a36Sopenharmony_ci * @vsi: sc VSI struct 99862306a36Sopenharmony_ci * @info: resource information 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ciint irdma_puda_create_rsrc(struct irdma_sc_vsi *vsi, 100162306a36Sopenharmony_ci struct irdma_puda_rsrc_info *info) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci struct irdma_sc_dev *dev = vsi->dev; 100462306a36Sopenharmony_ci int ret = 0; 100562306a36Sopenharmony_ci struct irdma_puda_rsrc *rsrc; 100662306a36Sopenharmony_ci u32 pudasize; 100762306a36Sopenharmony_ci u32 sqwridsize, rqwridsize; 100862306a36Sopenharmony_ci struct irdma_virt_mem *vmem; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci info->count = 1; 101162306a36Sopenharmony_ci pudasize = sizeof(struct irdma_puda_rsrc); 101262306a36Sopenharmony_ci sqwridsize = info->sq_size * sizeof(struct irdma_sq_uk_wr_trk_info); 101362306a36Sopenharmony_ci rqwridsize = info->rq_size * 8; 101462306a36Sopenharmony_ci switch (info->type) { 101562306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_ILQ: 101662306a36Sopenharmony_ci vmem = &vsi->ilq_mem; 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_IEQ: 101962306a36Sopenharmony_ci vmem = &vsi->ieq_mem; 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci default: 102262306a36Sopenharmony_ci return -EOPNOTSUPP; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci vmem->size = pudasize + sqwridsize + rqwridsize; 102562306a36Sopenharmony_ci vmem->va = kzalloc(vmem->size, GFP_KERNEL); 102662306a36Sopenharmony_ci if (!vmem->va) 102762306a36Sopenharmony_ci return -ENOMEM; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci rsrc = vmem->va; 103062306a36Sopenharmony_ci spin_lock_init(&rsrc->bufpool_lock); 103162306a36Sopenharmony_ci switch (info->type) { 103262306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_ILQ: 103362306a36Sopenharmony_ci vsi->ilq = vmem->va; 103462306a36Sopenharmony_ci vsi->ilq_count = info->count; 103562306a36Sopenharmony_ci rsrc->receive = info->receive; 103662306a36Sopenharmony_ci rsrc->xmit_complete = info->xmit_complete; 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case IRDMA_PUDA_RSRC_TYPE_IEQ: 103962306a36Sopenharmony_ci vsi->ieq_count = info->count; 104062306a36Sopenharmony_ci vsi->ieq = vmem->va; 104162306a36Sopenharmony_ci rsrc->receive = irdma_ieq_receive; 104262306a36Sopenharmony_ci rsrc->xmit_complete = irdma_ieq_tx_compl; 104362306a36Sopenharmony_ci break; 104462306a36Sopenharmony_ci default: 104562306a36Sopenharmony_ci return -EOPNOTSUPP; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci rsrc->type = info->type; 104962306a36Sopenharmony_ci rsrc->sq_wrtrk_array = (struct irdma_sq_uk_wr_trk_info *) 105062306a36Sopenharmony_ci ((u8 *)vmem->va + pudasize); 105162306a36Sopenharmony_ci rsrc->rq_wrid_array = (u64 *)((u8 *)vmem->va + pudasize + sqwridsize); 105262306a36Sopenharmony_ci /* Initialize all ieq lists */ 105362306a36Sopenharmony_ci INIT_LIST_HEAD(&rsrc->bufpool); 105462306a36Sopenharmony_ci INIT_LIST_HEAD(&rsrc->txpend); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci rsrc->tx_wqe_avail_cnt = info->sq_size - 1; 105762306a36Sopenharmony_ci irdma_sc_pd_init(dev, &rsrc->sc_pd, info->pd_id, info->abi_ver); 105862306a36Sopenharmony_ci rsrc->qp_id = info->qp_id; 105962306a36Sopenharmony_ci rsrc->cq_id = info->cq_id; 106062306a36Sopenharmony_ci rsrc->sq_size = info->sq_size; 106162306a36Sopenharmony_ci rsrc->rq_size = info->rq_size; 106262306a36Sopenharmony_ci rsrc->cq_size = info->rq_size + info->sq_size; 106362306a36Sopenharmony_ci if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 106462306a36Sopenharmony_ci if (rsrc->type == IRDMA_PUDA_RSRC_TYPE_ILQ) 106562306a36Sopenharmony_ci rsrc->cq_size += info->rq_size; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci rsrc->buf_size = info->buf_size; 106862306a36Sopenharmony_ci rsrc->dev = dev; 106962306a36Sopenharmony_ci rsrc->vsi = vsi; 107062306a36Sopenharmony_ci rsrc->stats_idx = info->stats_idx; 107162306a36Sopenharmony_ci rsrc->stats_idx_valid = info->stats_idx_valid; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ret = irdma_puda_cq_create(rsrc); 107462306a36Sopenharmony_ci if (!ret) { 107562306a36Sopenharmony_ci rsrc->cmpl = PUDA_CQ_CREATED; 107662306a36Sopenharmony_ci ret = irdma_puda_qp_create(rsrc); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci if (ret) { 107962306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), 108062306a36Sopenharmony_ci "PUDA: error qp_create type=%d, status=%d\n", 108162306a36Sopenharmony_ci rsrc->type, ret); 108262306a36Sopenharmony_ci goto error; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci rsrc->cmpl = PUDA_QP_CREATED; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ret = irdma_puda_allocbufs(rsrc, info->tx_buf_cnt + info->rq_size); 108762306a36Sopenharmony_ci if (ret) { 108862306a36Sopenharmony_ci ibdev_dbg(to_ibdev(dev), "PUDA: error alloc_buf\n"); 108962306a36Sopenharmony_ci goto error; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci rsrc->rxq_invalid_cnt = info->rq_size; 109362306a36Sopenharmony_ci ret = irdma_puda_replenish_rq(rsrc, true); 109462306a36Sopenharmony_ci if (ret) 109562306a36Sopenharmony_ci goto error; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (info->type == IRDMA_PUDA_RSRC_TYPE_IEQ) { 109862306a36Sopenharmony_ci if (!irdma_init_hash_desc(&rsrc->hash_desc)) { 109962306a36Sopenharmony_ci rsrc->check_crc = true; 110062306a36Sopenharmony_ci rsrc->cmpl = PUDA_HASH_CRC_COMPLETE; 110162306a36Sopenharmony_ci ret = 0; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci irdma_sc_ccq_arm(&rsrc->cq); 110662306a36Sopenharmony_ci return ret; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cierror: 110962306a36Sopenharmony_ci irdma_puda_dele_rsrc(vsi, info->type, false); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci return ret; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci/** 111562306a36Sopenharmony_ci * irdma_ilq_putback_rcvbuf - ilq buffer to put back on rq 111662306a36Sopenharmony_ci * @qp: ilq's qp resource 111762306a36Sopenharmony_ci * @buf: puda buffer for rcv q 111862306a36Sopenharmony_ci * @wqe_idx: wqe index of completed rcvbuf 111962306a36Sopenharmony_ci */ 112062306a36Sopenharmony_cistatic void irdma_ilq_putback_rcvbuf(struct irdma_sc_qp *qp, 112162306a36Sopenharmony_ci struct irdma_puda_buf *buf, u32 wqe_idx) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci __le64 *wqe; 112462306a36Sopenharmony_ci u64 offset8, offset24; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* Synch buffer for use by device */ 112762306a36Sopenharmony_ci dma_sync_single_for_device(qp->dev->hw->device, buf->mem.pa, 112862306a36Sopenharmony_ci buf->mem.size, DMA_BIDIRECTIONAL); 112962306a36Sopenharmony_ci wqe = qp->qp_uk.rq_base[wqe_idx].elem; 113062306a36Sopenharmony_ci get_64bit_val(wqe, 24, &offset24); 113162306a36Sopenharmony_ci if (qp->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 113262306a36Sopenharmony_ci get_64bit_val(wqe, 8, &offset8); 113362306a36Sopenharmony_ci if (offset24) 113462306a36Sopenharmony_ci offset8 &= ~FIELD_PREP(IRDMAQPSQ_VALID, 1); 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci offset8 |= FIELD_PREP(IRDMAQPSQ_VALID, 1); 113762306a36Sopenharmony_ci set_64bit_val(wqe, 8, offset8); 113862306a36Sopenharmony_ci dma_wmb(); /* make sure WQE is written before valid bit is set */ 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci if (offset24) 114162306a36Sopenharmony_ci offset24 = 0; 114262306a36Sopenharmony_ci else 114362306a36Sopenharmony_ci offset24 = FIELD_PREP(IRDMAQPSQ_VALID, 1); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci set_64bit_val(wqe, 24, offset24); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci/** 114962306a36Sopenharmony_ci * irdma_ieq_get_fpdu_len - get length of fpdu with or without marker 115062306a36Sopenharmony_ci * @pfpdu: pointer to fpdu 115162306a36Sopenharmony_ci * @datap: pointer to data in the buffer 115262306a36Sopenharmony_ci * @rcv_seq: seqnum of the data buffer 115362306a36Sopenharmony_ci */ 115462306a36Sopenharmony_cistatic u16 irdma_ieq_get_fpdu_len(struct irdma_pfpdu *pfpdu, u8 *datap, 115562306a36Sopenharmony_ci u32 rcv_seq) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci u32 marker_seq, end_seq, blk_start; 115862306a36Sopenharmony_ci u8 marker_len = pfpdu->marker_len; 115962306a36Sopenharmony_ci u16 total_len = 0; 116062306a36Sopenharmony_ci u16 fpdu_len; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci blk_start = (pfpdu->rcv_start_seq - rcv_seq) & (IRDMA_MRK_BLK_SZ - 1); 116362306a36Sopenharmony_ci if (!blk_start) { 116462306a36Sopenharmony_ci total_len = marker_len; 116562306a36Sopenharmony_ci marker_seq = rcv_seq + IRDMA_MRK_BLK_SZ; 116662306a36Sopenharmony_ci if (marker_len && *(u32 *)datap) 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci } else { 116962306a36Sopenharmony_ci marker_seq = rcv_seq + blk_start; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci datap += total_len; 117362306a36Sopenharmony_ci fpdu_len = ntohs(*(__be16 *)datap); 117462306a36Sopenharmony_ci fpdu_len += IRDMA_IEQ_MPA_FRAMING; 117562306a36Sopenharmony_ci fpdu_len = (fpdu_len + 3) & 0xfffc; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (fpdu_len > pfpdu->max_fpdu_data) 117862306a36Sopenharmony_ci return 0; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci total_len += fpdu_len; 118162306a36Sopenharmony_ci end_seq = rcv_seq + total_len; 118262306a36Sopenharmony_ci while ((int)(marker_seq - end_seq) < 0) { 118362306a36Sopenharmony_ci total_len += marker_len; 118462306a36Sopenharmony_ci end_seq += marker_len; 118562306a36Sopenharmony_ci marker_seq += IRDMA_MRK_BLK_SZ; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return total_len; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci/** 119262306a36Sopenharmony_ci * irdma_ieq_copy_to_txbuf - copydata from rcv buf to tx buf 119362306a36Sopenharmony_ci * @buf: rcv buffer with partial 119462306a36Sopenharmony_ci * @txbuf: tx buffer for sending back 119562306a36Sopenharmony_ci * @buf_offset: rcv buffer offset to copy from 119662306a36Sopenharmony_ci * @txbuf_offset: at offset in tx buf to copy 119762306a36Sopenharmony_ci * @len: length of data to copy 119862306a36Sopenharmony_ci */ 119962306a36Sopenharmony_cistatic void irdma_ieq_copy_to_txbuf(struct irdma_puda_buf *buf, 120062306a36Sopenharmony_ci struct irdma_puda_buf *txbuf, 120162306a36Sopenharmony_ci u16 buf_offset, u32 txbuf_offset, u32 len) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci void *mem1 = (u8 *)buf->mem.va + buf_offset; 120462306a36Sopenharmony_ci void *mem2 = (u8 *)txbuf->mem.va + txbuf_offset; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci memcpy(mem2, mem1, len); 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/** 121062306a36Sopenharmony_ci * irdma_ieq_setup_tx_buf - setup tx buffer for partial handling 121162306a36Sopenharmony_ci * @buf: reeive buffer with partial 121262306a36Sopenharmony_ci * @txbuf: buffer to prepare 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_cistatic void irdma_ieq_setup_tx_buf(struct irdma_puda_buf *buf, 121562306a36Sopenharmony_ci struct irdma_puda_buf *txbuf) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci txbuf->tcphlen = buf->tcphlen; 121862306a36Sopenharmony_ci txbuf->ipv4 = buf->ipv4; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 122162306a36Sopenharmony_ci txbuf->hdrlen = txbuf->tcphlen; 122262306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, IRDMA_TCP_OFFSET, 0, 122362306a36Sopenharmony_ci txbuf->hdrlen); 122462306a36Sopenharmony_ci } else { 122562306a36Sopenharmony_ci txbuf->maclen = buf->maclen; 122662306a36Sopenharmony_ci txbuf->hdrlen = buf->hdrlen; 122762306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, 0, 0, buf->hdrlen); 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/** 123262306a36Sopenharmony_ci * irdma_ieq_check_first_buf - check if rcv buffer's seq is in range 123362306a36Sopenharmony_ci * @buf: receive exception buffer 123462306a36Sopenharmony_ci * @fps: first partial sequence number 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_cistatic void irdma_ieq_check_first_buf(struct irdma_puda_buf *buf, u32 fps) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci u32 offset; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (buf->seqnum < fps) { 124162306a36Sopenharmony_ci offset = fps - buf->seqnum; 124262306a36Sopenharmony_ci if (offset > buf->datalen) 124362306a36Sopenharmony_ci return; 124462306a36Sopenharmony_ci buf->data += offset; 124562306a36Sopenharmony_ci buf->datalen -= (u16)offset; 124662306a36Sopenharmony_ci buf->seqnum = fps; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci/** 125162306a36Sopenharmony_ci * irdma_ieq_compl_pfpdu - write txbuf with full fpdu 125262306a36Sopenharmony_ci * @ieq: ieq resource 125362306a36Sopenharmony_ci * @rxlist: ieq's received buffer list 125462306a36Sopenharmony_ci * @pbufl: temporary list for buffers for fpddu 125562306a36Sopenharmony_ci * @txbuf: tx buffer for fpdu 125662306a36Sopenharmony_ci * @fpdu_len: total length of fpdu 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_cistatic void irdma_ieq_compl_pfpdu(struct irdma_puda_rsrc *ieq, 125962306a36Sopenharmony_ci struct list_head *rxlist, 126062306a36Sopenharmony_ci struct list_head *pbufl, 126162306a36Sopenharmony_ci struct irdma_puda_buf *txbuf, u16 fpdu_len) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct irdma_puda_buf *buf; 126462306a36Sopenharmony_ci u32 nextseqnum; 126562306a36Sopenharmony_ci u16 txoffset, bufoffset; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(pbufl); 126862306a36Sopenharmony_ci if (!buf) 126962306a36Sopenharmony_ci return; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci nextseqnum = buf->seqnum + fpdu_len; 127262306a36Sopenharmony_ci irdma_ieq_setup_tx_buf(buf, txbuf); 127362306a36Sopenharmony_ci if (buf->vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 127462306a36Sopenharmony_ci txoffset = txbuf->hdrlen; 127562306a36Sopenharmony_ci txbuf->totallen = txbuf->hdrlen + fpdu_len; 127662306a36Sopenharmony_ci txbuf->data = (u8 *)txbuf->mem.va + txoffset; 127762306a36Sopenharmony_ci } else { 127862306a36Sopenharmony_ci txoffset = buf->hdrlen; 127962306a36Sopenharmony_ci txbuf->totallen = buf->hdrlen + fpdu_len; 128062306a36Sopenharmony_ci txbuf->data = (u8 *)txbuf->mem.va + buf->hdrlen; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci bufoffset = (u16)(buf->data - (u8 *)buf->mem.va); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci do { 128562306a36Sopenharmony_ci if (buf->datalen >= fpdu_len) { 128662306a36Sopenharmony_ci /* copied full fpdu */ 128762306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset, 128862306a36Sopenharmony_ci fpdu_len); 128962306a36Sopenharmony_ci buf->datalen -= fpdu_len; 129062306a36Sopenharmony_ci buf->data += fpdu_len; 129162306a36Sopenharmony_ci buf->seqnum = nextseqnum; 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci /* copy partial fpdu */ 129562306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, bufoffset, txoffset, 129662306a36Sopenharmony_ci buf->datalen); 129762306a36Sopenharmony_ci txoffset += buf->datalen; 129862306a36Sopenharmony_ci fpdu_len -= buf->datalen; 129962306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 130062306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(pbufl); 130162306a36Sopenharmony_ci if (!buf) 130262306a36Sopenharmony_ci return; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci bufoffset = (u16)(buf->data - (u8 *)buf->mem.va); 130562306a36Sopenharmony_ci } while (1); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* last buffer on the list*/ 130862306a36Sopenharmony_ci if (buf->datalen) 130962306a36Sopenharmony_ci list_add(&buf->list, rxlist); 131062306a36Sopenharmony_ci else 131162306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci/** 131562306a36Sopenharmony_ci * irdma_ieq_create_pbufl - create buffer list for single fpdu 131662306a36Sopenharmony_ci * @pfpdu: pointer to fpdu 131762306a36Sopenharmony_ci * @rxlist: resource list for receive ieq buffes 131862306a36Sopenharmony_ci * @pbufl: temp. list for buffers for fpddu 131962306a36Sopenharmony_ci * @buf: first receive buffer 132062306a36Sopenharmony_ci * @fpdu_len: total length of fpdu 132162306a36Sopenharmony_ci */ 132262306a36Sopenharmony_cistatic int irdma_ieq_create_pbufl(struct irdma_pfpdu *pfpdu, 132362306a36Sopenharmony_ci struct list_head *rxlist, 132462306a36Sopenharmony_ci struct list_head *pbufl, 132562306a36Sopenharmony_ci struct irdma_puda_buf *buf, u16 fpdu_len) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci int status = 0; 132862306a36Sopenharmony_ci struct irdma_puda_buf *nextbuf; 132962306a36Sopenharmony_ci u32 nextseqnum; 133062306a36Sopenharmony_ci u16 plen = fpdu_len - buf->datalen; 133162306a36Sopenharmony_ci bool done = false; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci nextseqnum = buf->seqnum + buf->datalen; 133462306a36Sopenharmony_ci do { 133562306a36Sopenharmony_ci nextbuf = irdma_puda_get_listbuf(rxlist); 133662306a36Sopenharmony_ci if (!nextbuf) { 133762306a36Sopenharmony_ci status = -ENOBUFS; 133862306a36Sopenharmony_ci break; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci list_add_tail(&nextbuf->list, pbufl); 134162306a36Sopenharmony_ci if (nextbuf->seqnum != nextseqnum) { 134262306a36Sopenharmony_ci pfpdu->bad_seq_num++; 134362306a36Sopenharmony_ci status = -ERANGE; 134462306a36Sopenharmony_ci break; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci if (nextbuf->datalen >= plen) { 134762306a36Sopenharmony_ci done = true; 134862306a36Sopenharmony_ci } else { 134962306a36Sopenharmony_ci plen -= nextbuf->datalen; 135062306a36Sopenharmony_ci nextseqnum = nextbuf->seqnum + nextbuf->datalen; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci } while (!done); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci return status; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci/** 135962306a36Sopenharmony_ci * irdma_ieq_handle_partial - process partial fpdu buffer 136062306a36Sopenharmony_ci * @ieq: ieq resource 136162306a36Sopenharmony_ci * @pfpdu: partial management per user qp 136262306a36Sopenharmony_ci * @buf: receive buffer 136362306a36Sopenharmony_ci * @fpdu_len: fpdu len in the buffer 136462306a36Sopenharmony_ci */ 136562306a36Sopenharmony_cistatic int irdma_ieq_handle_partial(struct irdma_puda_rsrc *ieq, 136662306a36Sopenharmony_ci struct irdma_pfpdu *pfpdu, 136762306a36Sopenharmony_ci struct irdma_puda_buf *buf, u16 fpdu_len) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci int status = 0; 137062306a36Sopenharmony_ci u8 *crcptr; 137162306a36Sopenharmony_ci u32 mpacrc; 137262306a36Sopenharmony_ci u32 seqnum = buf->seqnum; 137362306a36Sopenharmony_ci struct list_head pbufl; /* partial buffer list */ 137462306a36Sopenharmony_ci struct irdma_puda_buf *txbuf = NULL; 137562306a36Sopenharmony_ci struct list_head *rxlist = &pfpdu->rxlist; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci ieq->partials_handled++; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci INIT_LIST_HEAD(&pbufl); 138062306a36Sopenharmony_ci list_add(&buf->list, &pbufl); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci status = irdma_ieq_create_pbufl(pfpdu, rxlist, &pbufl, buf, fpdu_len); 138362306a36Sopenharmony_ci if (status) 138462306a36Sopenharmony_ci goto error; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci txbuf = irdma_puda_get_bufpool(ieq); 138762306a36Sopenharmony_ci if (!txbuf) { 138862306a36Sopenharmony_ci pfpdu->no_tx_bufs++; 138962306a36Sopenharmony_ci status = -ENOBUFS; 139062306a36Sopenharmony_ci goto error; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci irdma_ieq_compl_pfpdu(ieq, rxlist, &pbufl, txbuf, fpdu_len); 139462306a36Sopenharmony_ci irdma_ieq_update_tcpip_info(txbuf, fpdu_len, seqnum); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci crcptr = txbuf->data + fpdu_len - 4; 139762306a36Sopenharmony_ci mpacrc = *(u32 *)crcptr; 139862306a36Sopenharmony_ci if (ieq->check_crc) { 139962306a36Sopenharmony_ci status = irdma_ieq_check_mpacrc(ieq->hash_desc, txbuf->data, 140062306a36Sopenharmony_ci (fpdu_len - 4), mpacrc); 140162306a36Sopenharmony_ci if (status) { 140262306a36Sopenharmony_ci ibdev_dbg(to_ibdev(ieq->dev), "IEQ: error bad crc\n"); 140362306a36Sopenharmony_ci goto error; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci print_hex_dump_debug("IEQ: IEQ TX BUFFER", DUMP_PREFIX_OFFSET, 16, 8, 140862306a36Sopenharmony_ci txbuf->mem.va, txbuf->totallen, false); 140962306a36Sopenharmony_ci if (ieq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) 141062306a36Sopenharmony_ci txbuf->ah_id = pfpdu->ah->ah_info.ah_idx; 141162306a36Sopenharmony_ci txbuf->do_lpb = true; 141262306a36Sopenharmony_ci irdma_puda_send_buf(ieq, txbuf); 141362306a36Sopenharmony_ci pfpdu->rcv_nxt = seqnum + fpdu_len; 141462306a36Sopenharmony_ci return status; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_cierror: 141762306a36Sopenharmony_ci while (!list_empty(&pbufl)) { 141862306a36Sopenharmony_ci buf = list_last_entry(&pbufl, struct irdma_puda_buf, list); 141962306a36Sopenharmony_ci list_move(&buf->list, rxlist); 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci if (txbuf) 142262306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, txbuf); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return status; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci/** 142862306a36Sopenharmony_ci * irdma_ieq_process_buf - process buffer rcvd for ieq 142962306a36Sopenharmony_ci * @ieq: ieq resource 143062306a36Sopenharmony_ci * @pfpdu: partial management per user qp 143162306a36Sopenharmony_ci * @buf: receive buffer 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_cistatic int irdma_ieq_process_buf(struct irdma_puda_rsrc *ieq, 143462306a36Sopenharmony_ci struct irdma_pfpdu *pfpdu, 143562306a36Sopenharmony_ci struct irdma_puda_buf *buf) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci u16 fpdu_len = 0; 143862306a36Sopenharmony_ci u16 datalen = buf->datalen; 143962306a36Sopenharmony_ci u8 *datap = buf->data; 144062306a36Sopenharmony_ci u8 *crcptr; 144162306a36Sopenharmony_ci u16 ioffset = 0; 144262306a36Sopenharmony_ci u32 mpacrc; 144362306a36Sopenharmony_ci u32 seqnum = buf->seqnum; 144462306a36Sopenharmony_ci u16 len = 0; 144562306a36Sopenharmony_ci u16 full = 0; 144662306a36Sopenharmony_ci bool partial = false; 144762306a36Sopenharmony_ci struct irdma_puda_buf *txbuf; 144862306a36Sopenharmony_ci struct list_head *rxlist = &pfpdu->rxlist; 144962306a36Sopenharmony_ci int ret = 0; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ioffset = (u16)(buf->data - (u8 *)buf->mem.va); 145262306a36Sopenharmony_ci while (datalen) { 145362306a36Sopenharmony_ci fpdu_len = irdma_ieq_get_fpdu_len(pfpdu, datap, buf->seqnum); 145462306a36Sopenharmony_ci if (!fpdu_len) { 145562306a36Sopenharmony_ci ibdev_dbg(to_ibdev(ieq->dev), 145662306a36Sopenharmony_ci "IEQ: error bad fpdu len\n"); 145762306a36Sopenharmony_ci list_add(&buf->list, rxlist); 145862306a36Sopenharmony_ci return -EINVAL; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (datalen < fpdu_len) { 146262306a36Sopenharmony_ci partial = true; 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci crcptr = datap + fpdu_len - 4; 146662306a36Sopenharmony_ci mpacrc = *(u32 *)crcptr; 146762306a36Sopenharmony_ci if (ieq->check_crc) 146862306a36Sopenharmony_ci ret = irdma_ieq_check_mpacrc(ieq->hash_desc, datap, 146962306a36Sopenharmony_ci fpdu_len - 4, mpacrc); 147062306a36Sopenharmony_ci if (ret) { 147162306a36Sopenharmony_ci list_add(&buf->list, rxlist); 147262306a36Sopenharmony_ci ibdev_dbg(to_ibdev(ieq->dev), 147362306a36Sopenharmony_ci "ERR: IRDMA_ERR_MPA_CRC\n"); 147462306a36Sopenharmony_ci return -EINVAL; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci full++; 147762306a36Sopenharmony_ci pfpdu->fpdu_processed++; 147862306a36Sopenharmony_ci ieq->fpdu_processed++; 147962306a36Sopenharmony_ci datap += fpdu_len; 148062306a36Sopenharmony_ci len += fpdu_len; 148162306a36Sopenharmony_ci datalen -= fpdu_len; 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci if (full) { 148462306a36Sopenharmony_ci /* copy full pdu's in the txbuf and send them out */ 148562306a36Sopenharmony_ci txbuf = irdma_puda_get_bufpool(ieq); 148662306a36Sopenharmony_ci if (!txbuf) { 148762306a36Sopenharmony_ci pfpdu->no_tx_bufs++; 148862306a36Sopenharmony_ci list_add(&buf->list, rxlist); 148962306a36Sopenharmony_ci return -ENOBUFS; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci /* modify txbuf's buffer header */ 149262306a36Sopenharmony_ci irdma_ieq_setup_tx_buf(buf, txbuf); 149362306a36Sopenharmony_ci /* copy full fpdu's to new buffer */ 149462306a36Sopenharmony_ci if (ieq->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) { 149562306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, ioffset, 149662306a36Sopenharmony_ci txbuf->hdrlen, len); 149762306a36Sopenharmony_ci txbuf->totallen = txbuf->hdrlen + len; 149862306a36Sopenharmony_ci txbuf->ah_id = pfpdu->ah->ah_info.ah_idx; 149962306a36Sopenharmony_ci } else { 150062306a36Sopenharmony_ci irdma_ieq_copy_to_txbuf(buf, txbuf, ioffset, 150162306a36Sopenharmony_ci buf->hdrlen, len); 150262306a36Sopenharmony_ci txbuf->totallen = buf->hdrlen + len; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci irdma_ieq_update_tcpip_info(txbuf, len, buf->seqnum); 150562306a36Sopenharmony_ci print_hex_dump_debug("IEQ: IEQ TX BUFFER", DUMP_PREFIX_OFFSET, 150662306a36Sopenharmony_ci 16, 8, txbuf->mem.va, txbuf->totallen, 150762306a36Sopenharmony_ci false); 150862306a36Sopenharmony_ci txbuf->do_lpb = true; 150962306a36Sopenharmony_ci irdma_puda_send_buf(ieq, txbuf); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (!datalen) { 151262306a36Sopenharmony_ci pfpdu->rcv_nxt = buf->seqnum + len; 151362306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 151462306a36Sopenharmony_ci return 0; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci buf->data = datap; 151762306a36Sopenharmony_ci buf->seqnum = seqnum + len; 151862306a36Sopenharmony_ci buf->datalen = datalen; 151962306a36Sopenharmony_ci pfpdu->rcv_nxt = buf->seqnum; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci if (partial) 152262306a36Sopenharmony_ci return irdma_ieq_handle_partial(ieq, pfpdu, buf, fpdu_len); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 0; 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci/** 152862306a36Sopenharmony_ci * irdma_ieq_process_fpdus - process fpdu's buffers on its list 152962306a36Sopenharmony_ci * @qp: qp for which partial fpdus 153062306a36Sopenharmony_ci * @ieq: ieq resource 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_civoid irdma_ieq_process_fpdus(struct irdma_sc_qp *qp, 153362306a36Sopenharmony_ci struct irdma_puda_rsrc *ieq) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci struct irdma_pfpdu *pfpdu = &qp->pfpdu; 153662306a36Sopenharmony_ci struct list_head *rxlist = &pfpdu->rxlist; 153762306a36Sopenharmony_ci struct irdma_puda_buf *buf; 153862306a36Sopenharmony_ci int status; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci do { 154162306a36Sopenharmony_ci if (list_empty(rxlist)) 154262306a36Sopenharmony_ci break; 154362306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(rxlist); 154462306a36Sopenharmony_ci if (!buf) { 154562306a36Sopenharmony_ci ibdev_dbg(to_ibdev(ieq->dev), "IEQ: error no buf\n"); 154662306a36Sopenharmony_ci break; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci if (buf->seqnum != pfpdu->rcv_nxt) { 154962306a36Sopenharmony_ci /* This could be out of order or missing packet */ 155062306a36Sopenharmony_ci pfpdu->out_of_order++; 155162306a36Sopenharmony_ci list_add(&buf->list, rxlist); 155262306a36Sopenharmony_ci break; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci /* keep processing buffers from the head of the list */ 155562306a36Sopenharmony_ci status = irdma_ieq_process_buf(ieq, pfpdu, buf); 155662306a36Sopenharmony_ci if (status == -EINVAL) { 155762306a36Sopenharmony_ci pfpdu->mpa_crc_err = true; 155862306a36Sopenharmony_ci while (!list_empty(rxlist)) { 155962306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(rxlist); 156062306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 156162306a36Sopenharmony_ci pfpdu->crc_err++; 156262306a36Sopenharmony_ci ieq->crc_err++; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci /* create CQP for AE */ 156562306a36Sopenharmony_ci irdma_ieq_mpa_crc_ae(ieq->dev, qp); 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci } while (!status); 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci/** 157162306a36Sopenharmony_ci * irdma_ieq_create_ah - create an address handle for IEQ 157262306a36Sopenharmony_ci * @qp: qp pointer 157362306a36Sopenharmony_ci * @buf: buf received on IEQ used to create AH 157462306a36Sopenharmony_ci */ 157562306a36Sopenharmony_cistatic int irdma_ieq_create_ah(struct irdma_sc_qp *qp, struct irdma_puda_buf *buf) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct irdma_ah_info ah_info = {}; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci qp->pfpdu.ah_buf = buf; 158062306a36Sopenharmony_ci irdma_puda_ieq_get_ah_info(qp, &ah_info); 158162306a36Sopenharmony_ci return irdma_puda_create_ah(qp->vsi->dev, &ah_info, false, 158262306a36Sopenharmony_ci IRDMA_PUDA_RSRC_TYPE_IEQ, qp, 158362306a36Sopenharmony_ci &qp->pfpdu.ah); 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci/** 158762306a36Sopenharmony_ci * irdma_ieq_handle_exception - handle qp's exception 158862306a36Sopenharmony_ci * @ieq: ieq resource 158962306a36Sopenharmony_ci * @qp: qp receiving excpetion 159062306a36Sopenharmony_ci * @buf: receive buffer 159162306a36Sopenharmony_ci */ 159262306a36Sopenharmony_cistatic void irdma_ieq_handle_exception(struct irdma_puda_rsrc *ieq, 159362306a36Sopenharmony_ci struct irdma_sc_qp *qp, 159462306a36Sopenharmony_ci struct irdma_puda_buf *buf) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci struct irdma_pfpdu *pfpdu = &qp->pfpdu; 159762306a36Sopenharmony_ci u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx; 159862306a36Sopenharmony_ci u32 rcv_wnd = hw_host_ctx[23]; 159962306a36Sopenharmony_ci /* first partial seq # in q2 */ 160062306a36Sopenharmony_ci u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET); 160162306a36Sopenharmony_ci struct list_head *rxlist = &pfpdu->rxlist; 160262306a36Sopenharmony_ci unsigned long flags = 0; 160362306a36Sopenharmony_ci u8 hw_rev = qp->dev->hw_attrs.uk_attrs.hw_rev; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci print_hex_dump_debug("IEQ: IEQ RX BUFFER", DUMP_PREFIX_OFFSET, 16, 8, 160662306a36Sopenharmony_ci buf->mem.va, buf->totallen, false); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci spin_lock_irqsave(&pfpdu->lock, flags); 160962306a36Sopenharmony_ci pfpdu->total_ieq_bufs++; 161062306a36Sopenharmony_ci if (pfpdu->mpa_crc_err) { 161162306a36Sopenharmony_ci pfpdu->crc_err++; 161262306a36Sopenharmony_ci goto error; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci if (pfpdu->mode && fps != pfpdu->fps) { 161562306a36Sopenharmony_ci /* clean up qp as it is new partial sequence */ 161662306a36Sopenharmony_ci irdma_ieq_cleanup_qp(ieq, qp); 161762306a36Sopenharmony_ci ibdev_dbg(to_ibdev(ieq->dev), "IEQ: restarting new partial\n"); 161862306a36Sopenharmony_ci pfpdu->mode = false; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (!pfpdu->mode) { 162262306a36Sopenharmony_ci print_hex_dump_debug("IEQ: Q2 BUFFER", DUMP_PREFIX_OFFSET, 16, 162362306a36Sopenharmony_ci 8, (u64 *)qp->q2_buf, 128, false); 162462306a36Sopenharmony_ci /* First_Partial_Sequence_Number check */ 162562306a36Sopenharmony_ci pfpdu->rcv_nxt = fps; 162662306a36Sopenharmony_ci pfpdu->fps = fps; 162762306a36Sopenharmony_ci pfpdu->mode = true; 162862306a36Sopenharmony_ci pfpdu->max_fpdu_data = (buf->ipv4) ? 162962306a36Sopenharmony_ci (ieq->vsi->mtu - IRDMA_MTU_TO_MSS_IPV4) : 163062306a36Sopenharmony_ci (ieq->vsi->mtu - IRDMA_MTU_TO_MSS_IPV6); 163162306a36Sopenharmony_ci pfpdu->pmode_count++; 163262306a36Sopenharmony_ci ieq->pmode_count++; 163362306a36Sopenharmony_ci INIT_LIST_HEAD(rxlist); 163462306a36Sopenharmony_ci irdma_ieq_check_first_buf(buf, fps); 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (!(rcv_wnd >= (buf->seqnum - pfpdu->rcv_nxt))) { 163862306a36Sopenharmony_ci pfpdu->bad_seq_num++; 163962306a36Sopenharmony_ci ieq->bad_seq_num++; 164062306a36Sopenharmony_ci goto error; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (!list_empty(rxlist)) { 164462306a36Sopenharmony_ci if (buf->seqnum != pfpdu->nextseqnum) { 164562306a36Sopenharmony_ci irdma_send_ieq_ack(qp); 164662306a36Sopenharmony_ci /* throw away out-of-order, duplicates*/ 164762306a36Sopenharmony_ci goto error; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci /* Insert buf before head */ 165162306a36Sopenharmony_ci list_add_tail(&buf->list, rxlist); 165262306a36Sopenharmony_ci pfpdu->nextseqnum = buf->seqnum + buf->datalen; 165362306a36Sopenharmony_ci pfpdu->lastrcv_buf = buf; 165462306a36Sopenharmony_ci if (hw_rev >= IRDMA_GEN_2 && !pfpdu->ah) { 165562306a36Sopenharmony_ci irdma_ieq_create_ah(qp, buf); 165662306a36Sopenharmony_ci if (!pfpdu->ah) 165762306a36Sopenharmony_ci goto error; 165862306a36Sopenharmony_ci goto exit; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci if (hw_rev == IRDMA_GEN_1) 166162306a36Sopenharmony_ci irdma_ieq_process_fpdus(qp, ieq); 166262306a36Sopenharmony_ci else if (pfpdu->ah && pfpdu->ah->ah_info.ah_valid) 166362306a36Sopenharmony_ci irdma_ieq_process_fpdus(qp, ieq); 166462306a36Sopenharmony_ciexit: 166562306a36Sopenharmony_ci spin_unlock_irqrestore(&pfpdu->lock, flags); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci return; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cierror: 167062306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 167162306a36Sopenharmony_ci spin_unlock_irqrestore(&pfpdu->lock, flags); 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci/** 167562306a36Sopenharmony_ci * irdma_ieq_receive - received exception buffer 167662306a36Sopenharmony_ci * @vsi: VSI of device 167762306a36Sopenharmony_ci * @buf: exception buffer received 167862306a36Sopenharmony_ci */ 167962306a36Sopenharmony_cistatic void irdma_ieq_receive(struct irdma_sc_vsi *vsi, 168062306a36Sopenharmony_ci struct irdma_puda_buf *buf) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci struct irdma_puda_rsrc *ieq = vsi->ieq; 168362306a36Sopenharmony_ci struct irdma_sc_qp *qp = NULL; 168462306a36Sopenharmony_ci u32 wqe_idx = ieq->compl_rxwqe_idx; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci qp = irdma_ieq_get_qp(vsi->dev, buf); 168762306a36Sopenharmony_ci if (!qp) { 168862306a36Sopenharmony_ci ieq->stats_bad_qp_id++; 168962306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 169062306a36Sopenharmony_ci } else { 169162306a36Sopenharmony_ci irdma_ieq_handle_exception(ieq, qp, buf); 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci /* 169462306a36Sopenharmony_ci * ieq->rx_wqe_idx is used by irdma_puda_replenish_rq() 169562306a36Sopenharmony_ci * on which wqe_idx to start replenish rq 169662306a36Sopenharmony_ci */ 169762306a36Sopenharmony_ci if (!ieq->rxq_invalid_cnt) 169862306a36Sopenharmony_ci ieq->rx_wqe_idx = wqe_idx; 169962306a36Sopenharmony_ci ieq->rxq_invalid_cnt++; 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci/** 170362306a36Sopenharmony_ci * irdma_ieq_tx_compl - put back after sending completed exception buffer 170462306a36Sopenharmony_ci * @vsi: sc VSI struct 170562306a36Sopenharmony_ci * @sqwrid: pointer to puda buffer 170662306a36Sopenharmony_ci */ 170762306a36Sopenharmony_cistatic void irdma_ieq_tx_compl(struct irdma_sc_vsi *vsi, void *sqwrid) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci struct irdma_puda_rsrc *ieq = vsi->ieq; 171062306a36Sopenharmony_ci struct irdma_puda_buf *buf = sqwrid; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 171362306a36Sopenharmony_ci} 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci/** 171662306a36Sopenharmony_ci * irdma_ieq_cleanup_qp - qp is being destroyed 171762306a36Sopenharmony_ci * @ieq: ieq resource 171862306a36Sopenharmony_ci * @qp: all pending fpdu buffers 171962306a36Sopenharmony_ci */ 172062306a36Sopenharmony_civoid irdma_ieq_cleanup_qp(struct irdma_puda_rsrc *ieq, struct irdma_sc_qp *qp) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci struct irdma_puda_buf *buf; 172362306a36Sopenharmony_ci struct irdma_pfpdu *pfpdu = &qp->pfpdu; 172462306a36Sopenharmony_ci struct list_head *rxlist = &pfpdu->rxlist; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (qp->pfpdu.ah) { 172762306a36Sopenharmony_ci irdma_puda_free_ah(ieq->dev, qp->pfpdu.ah); 172862306a36Sopenharmony_ci qp->pfpdu.ah = NULL; 172962306a36Sopenharmony_ci qp->pfpdu.ah_buf = NULL; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (!pfpdu->mode) 173362306a36Sopenharmony_ci return; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci while (!list_empty(rxlist)) { 173662306a36Sopenharmony_ci buf = irdma_puda_get_listbuf(rxlist); 173762306a36Sopenharmony_ci irdma_puda_ret_bufpool(ieq, buf); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci} 1740