162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* Authors: Cheng Xu <chengyou@linux.alibaba.com> */ 462306a36Sopenharmony_ci/* Kai Shen <kaishen@linux.alibaba.com> */ 562306a36Sopenharmony_ci/* Copyright (c) 2020-2022, Alibaba Group. */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "erdma_verbs.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cistatic void *get_next_valid_cqe(struct erdma_cq *cq) 1062306a36Sopenharmony_ci{ 1162306a36Sopenharmony_ci __be32 *cqe = get_queue_entry(cq->kern_cq.qbuf, cq->kern_cq.ci, 1262306a36Sopenharmony_ci cq->depth, CQE_SHIFT); 1362306a36Sopenharmony_ci u32 owner = FIELD_GET(ERDMA_CQE_HDR_OWNER_MASK, 1462306a36Sopenharmony_ci be32_to_cpu(READ_ONCE(*cqe))); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci return owner ^ !!(cq->kern_cq.ci & cq->depth) ? cqe : NULL; 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void notify_cq(struct erdma_cq *cq, u8 solcitied) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci u64 db_data = 2262306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_IDX_MASK, (cq->kern_cq.notify_cnt)) | 2362306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_CQN_MASK, cq->cqn) | 2462306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_ARM_MASK, 1) | 2562306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_SOL_MASK, solcitied) | 2662306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_CMDSN_MASK, cq->kern_cq.cmdsn) | 2762306a36Sopenharmony_ci FIELD_PREP(ERDMA_CQDB_CI_MASK, cq->kern_cq.ci); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci *cq->kern_cq.db_record = db_data; 3062306a36Sopenharmony_ci writeq(db_data, cq->kern_cq.db); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciint erdma_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct erdma_cq *cq = to_ecq(ibcq); 3662306a36Sopenharmony_ci unsigned long irq_flags; 3762306a36Sopenharmony_ci int ret = 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci spin_lock_irqsave(&cq->kern_cq.lock, irq_flags); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci notify_cq(cq, (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && get_next_valid_cqe(cq)) 4462306a36Sopenharmony_ci ret = 1; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci cq->kern_cq.notify_cnt++; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->kern_cq.lock, irq_flags); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return ret; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const enum ib_wc_opcode wc_mapping_table[ERDMA_NUM_OPCODES] = { 5462306a36Sopenharmony_ci [ERDMA_OP_WRITE] = IB_WC_RDMA_WRITE, 5562306a36Sopenharmony_ci [ERDMA_OP_READ] = IB_WC_RDMA_READ, 5662306a36Sopenharmony_ci [ERDMA_OP_SEND] = IB_WC_SEND, 5762306a36Sopenharmony_ci [ERDMA_OP_SEND_WITH_IMM] = IB_WC_SEND, 5862306a36Sopenharmony_ci [ERDMA_OP_RECEIVE] = IB_WC_RECV, 5962306a36Sopenharmony_ci [ERDMA_OP_RECV_IMM] = IB_WC_RECV_RDMA_WITH_IMM, 6062306a36Sopenharmony_ci [ERDMA_OP_RECV_INV] = IB_WC_RECV, 6162306a36Sopenharmony_ci [ERDMA_OP_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, 6262306a36Sopenharmony_ci [ERDMA_OP_RSP_SEND_IMM] = IB_WC_RECV, 6362306a36Sopenharmony_ci [ERDMA_OP_SEND_WITH_INV] = IB_WC_SEND, 6462306a36Sopenharmony_ci [ERDMA_OP_REG_MR] = IB_WC_REG_MR, 6562306a36Sopenharmony_ci [ERDMA_OP_LOCAL_INV] = IB_WC_LOCAL_INV, 6662306a36Sopenharmony_ci [ERDMA_OP_READ_WITH_INV] = IB_WC_RDMA_READ, 6762306a36Sopenharmony_ci [ERDMA_OP_ATOMIC_CAS] = IB_WC_COMP_SWAP, 6862306a36Sopenharmony_ci [ERDMA_OP_ATOMIC_FAA] = IB_WC_FETCH_ADD, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const struct { 7262306a36Sopenharmony_ci enum erdma_wc_status erdma; 7362306a36Sopenharmony_ci enum ib_wc_status base; 7462306a36Sopenharmony_ci enum erdma_vendor_err vendor; 7562306a36Sopenharmony_ci} map_cqe_status[ERDMA_NUM_WC_STATUS] = { 7662306a36Sopenharmony_ci { ERDMA_WC_SUCCESS, IB_WC_SUCCESS, ERDMA_WC_VENDOR_NO_ERR }, 7762306a36Sopenharmony_ci { ERDMA_WC_GENERAL_ERR, IB_WC_GENERAL_ERR, ERDMA_WC_VENDOR_NO_ERR }, 7862306a36Sopenharmony_ci { ERDMA_WC_RECV_WQE_FORMAT_ERR, IB_WC_GENERAL_ERR, 7962306a36Sopenharmony_ci ERDMA_WC_VENDOR_INVALID_RQE }, 8062306a36Sopenharmony_ci { ERDMA_WC_RECV_STAG_INVALID_ERR, IB_WC_REM_ACCESS_ERR, 8162306a36Sopenharmony_ci ERDMA_WC_VENDOR_RQE_INVALID_STAG }, 8262306a36Sopenharmony_ci { ERDMA_WC_RECV_ADDR_VIOLATION_ERR, IB_WC_REM_ACCESS_ERR, 8362306a36Sopenharmony_ci ERDMA_WC_VENDOR_RQE_ADDR_VIOLATION }, 8462306a36Sopenharmony_ci { ERDMA_WC_RECV_RIGHT_VIOLATION_ERR, IB_WC_REM_ACCESS_ERR, 8562306a36Sopenharmony_ci ERDMA_WC_VENDOR_RQE_ACCESS_RIGHT_ERR }, 8662306a36Sopenharmony_ci { ERDMA_WC_RECV_PDID_ERR, IB_WC_REM_ACCESS_ERR, 8762306a36Sopenharmony_ci ERDMA_WC_VENDOR_RQE_INVALID_PD }, 8862306a36Sopenharmony_ci { ERDMA_WC_RECV_WARRPING_ERR, IB_WC_REM_ACCESS_ERR, 8962306a36Sopenharmony_ci ERDMA_WC_VENDOR_RQE_WRAP_ERR }, 9062306a36Sopenharmony_ci { ERDMA_WC_SEND_WQE_FORMAT_ERR, IB_WC_LOC_QP_OP_ERR, 9162306a36Sopenharmony_ci ERDMA_WC_VENDOR_INVALID_SQE }, 9262306a36Sopenharmony_ci { ERDMA_WC_SEND_WQE_ORD_EXCEED, IB_WC_GENERAL_ERR, 9362306a36Sopenharmony_ci ERDMA_WC_VENDOR_ZERO_ORD }, 9462306a36Sopenharmony_ci { ERDMA_WC_SEND_STAG_INVALID_ERR, IB_WC_LOC_ACCESS_ERR, 9562306a36Sopenharmony_ci ERDMA_WC_VENDOR_SQE_INVALID_STAG }, 9662306a36Sopenharmony_ci { ERDMA_WC_SEND_ADDR_VIOLATION_ERR, IB_WC_LOC_ACCESS_ERR, 9762306a36Sopenharmony_ci ERDMA_WC_VENDOR_SQE_ADDR_VIOLATION }, 9862306a36Sopenharmony_ci { ERDMA_WC_SEND_RIGHT_VIOLATION_ERR, IB_WC_LOC_ACCESS_ERR, 9962306a36Sopenharmony_ci ERDMA_WC_VENDOR_SQE_ACCESS_ERR }, 10062306a36Sopenharmony_ci { ERDMA_WC_SEND_PDID_ERR, IB_WC_LOC_ACCESS_ERR, 10162306a36Sopenharmony_ci ERDMA_WC_VENDOR_SQE_INVALID_PD }, 10262306a36Sopenharmony_ci { ERDMA_WC_SEND_WARRPING_ERR, IB_WC_LOC_ACCESS_ERR, 10362306a36Sopenharmony_ci ERDMA_WC_VENDOR_SQE_WARP_ERR }, 10462306a36Sopenharmony_ci { ERDMA_WC_FLUSH_ERR, IB_WC_WR_FLUSH_ERR, ERDMA_WC_VENDOR_NO_ERR }, 10562306a36Sopenharmony_ci { ERDMA_WC_RETRY_EXC_ERR, IB_WC_RETRY_EXC_ERR, ERDMA_WC_VENDOR_NO_ERR }, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define ERDMA_POLLCQ_NO_QP 1 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int erdma_poll_one_cqe(struct erdma_cq *cq, struct ib_wc *wc) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct erdma_dev *dev = to_edev(cq->ibcq.device); 11362306a36Sopenharmony_ci u8 opcode, syndrome, qtype; 11462306a36Sopenharmony_ci struct erdma_kqp *kern_qp; 11562306a36Sopenharmony_ci struct erdma_cqe *cqe; 11662306a36Sopenharmony_ci struct erdma_qp *qp; 11762306a36Sopenharmony_ci u16 wqe_idx, depth; 11862306a36Sopenharmony_ci u32 qpn, cqe_hdr; 11962306a36Sopenharmony_ci u64 *id_table; 12062306a36Sopenharmony_ci u64 *wqe_hdr; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci cqe = get_next_valid_cqe(cq); 12362306a36Sopenharmony_ci if (!cqe) 12462306a36Sopenharmony_ci return -EAGAIN; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci cq->kern_cq.ci++; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* cqbuf should be ready when we poll */ 12962306a36Sopenharmony_ci dma_rmb(); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci qpn = be32_to_cpu(cqe->qpn); 13262306a36Sopenharmony_ci wqe_idx = be32_to_cpu(cqe->qe_idx); 13362306a36Sopenharmony_ci cqe_hdr = be32_to_cpu(cqe->hdr); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci qp = find_qp_by_qpn(dev, qpn); 13662306a36Sopenharmony_ci if (!qp) 13762306a36Sopenharmony_ci return ERDMA_POLLCQ_NO_QP; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci kern_qp = &qp->kern_qp; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci qtype = FIELD_GET(ERDMA_CQE_HDR_QTYPE_MASK, cqe_hdr); 14262306a36Sopenharmony_ci syndrome = FIELD_GET(ERDMA_CQE_HDR_SYNDROME_MASK, cqe_hdr); 14362306a36Sopenharmony_ci opcode = FIELD_GET(ERDMA_CQE_HDR_OPCODE_MASK, cqe_hdr); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (qtype == ERDMA_CQE_QTYPE_SQ) { 14662306a36Sopenharmony_ci id_table = kern_qp->swr_tbl; 14762306a36Sopenharmony_ci depth = qp->attrs.sq_size; 14862306a36Sopenharmony_ci wqe_hdr = get_queue_entry(qp->kern_qp.sq_buf, wqe_idx, 14962306a36Sopenharmony_ci qp->attrs.sq_size, SQEBB_SHIFT); 15062306a36Sopenharmony_ci kern_qp->sq_ci = 15162306a36Sopenharmony_ci FIELD_GET(ERDMA_SQE_HDR_WQEBB_CNT_MASK, *wqe_hdr) + 15262306a36Sopenharmony_ci wqe_idx + 1; 15362306a36Sopenharmony_ci } else { 15462306a36Sopenharmony_ci id_table = kern_qp->rwr_tbl; 15562306a36Sopenharmony_ci depth = qp->attrs.rq_size; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci wc->wr_id = id_table[wqe_idx & (depth - 1)]; 15862306a36Sopenharmony_ci wc->byte_len = be32_to_cpu(cqe->size); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci wc->wc_flags = 0; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci wc->opcode = wc_mapping_table[opcode]; 16362306a36Sopenharmony_ci if (opcode == ERDMA_OP_RECV_IMM || opcode == ERDMA_OP_RSP_SEND_IMM) { 16462306a36Sopenharmony_ci wc->ex.imm_data = cpu_to_be32(le32_to_cpu(cqe->imm_data)); 16562306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 16662306a36Sopenharmony_ci } else if (opcode == ERDMA_OP_RECV_INV) { 16762306a36Sopenharmony_ci wc->ex.invalidate_rkey = be32_to_cpu(cqe->inv_rkey); 16862306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_INVALIDATE; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (syndrome >= ERDMA_NUM_WC_STATUS) 17262306a36Sopenharmony_ci syndrome = ERDMA_WC_GENERAL_ERR; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci wc->status = map_cqe_status[syndrome].base; 17562306a36Sopenharmony_ci wc->vendor_err = map_cqe_status[syndrome].vendor; 17662306a36Sopenharmony_ci wc->qp = &qp->ibqp; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciint erdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct erdma_cq *cq = to_ecq(ibcq); 18462306a36Sopenharmony_ci unsigned long flags; 18562306a36Sopenharmony_ci int npolled, ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci spin_lock_irqsave(&cq->kern_cq.lock, flags); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (npolled = 0; npolled < num_entries;) { 19062306a36Sopenharmony_ci ret = erdma_poll_one_cqe(cq, wc + npolled); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (ret == -EAGAIN) /* no received new CQEs. */ 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci else if (ret) /* ignore invalid CQEs. */ 19562306a36Sopenharmony_ci continue; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci npolled++; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->kern_cq.lock, flags); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return npolled; 20362306a36Sopenharmony_ci} 204