18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/kref.h> 348c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 358c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 368c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h> 378c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 388c2ecf20Sopenharmony_ci#include "srq.h" 398c2ecf20Sopenharmony_ci#include "qp.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void mlx5_ib_cq_comp(struct mlx5_core_cq *cq, struct mlx5_eqe *eqe) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct ib_cq *ibcq = &to_mibcq(cq)->ibcq; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ibcq->comp_handler(ibcq, ibcq->cq_context); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void mlx5_ib_cq_event(struct mlx5_core_cq *mcq, enum mlx5_event type) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = container_of(mcq, struct mlx5_ib_cq, mcq); 518c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 528c2ecf20Sopenharmony_ci struct ib_cq *ibcq = &cq->ibcq; 538c2ecf20Sopenharmony_ci struct ib_event event; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (type != MLX5_EVENT_TYPE_CQ_ERROR) { 568c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "Unexpected event type %d on CQ %06x\n", 578c2ecf20Sopenharmony_ci type, mcq->cqn); 588c2ecf20Sopenharmony_ci return; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (ibcq->event_handler) { 628c2ecf20Sopenharmony_ci event.device = &dev->ib_dev; 638c2ecf20Sopenharmony_ci event.event = IB_EVENT_CQ_ERR; 648c2ecf20Sopenharmony_ci event.element.cq = ibcq; 658c2ecf20Sopenharmony_ci ibcq->event_handler(&event, ibcq->cq_context); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void *get_cqe(struct mlx5_ib_cq *cq, int n) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci return mlx5_frag_buf_get_wqe(&cq->buf.fbc, n); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic u8 sw_ownership_bit(int n, int nent) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return (n & nent) ? 1 : 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void *get_sw_cqe(struct mlx5_ib_cq *cq, int n) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci void *cqe = get_cqe(cq, n & cq->ibcq.cqe); 828c2ecf20Sopenharmony_ci struct mlx5_cqe64 *cqe64; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (likely(get_cqe_opcode(cqe64) != MLX5_CQE_INVALID) && 878c2ecf20Sopenharmony_ci !((cqe64->op_own & MLX5_CQE_OWNER_MASK) ^ !!(n & (cq->ibcq.cqe + 1)))) { 888c2ecf20Sopenharmony_ci return cqe; 898c2ecf20Sopenharmony_ci } else { 908c2ecf20Sopenharmony_ci return NULL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void *next_cqe_sw(struct mlx5_ib_cq *cq) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci return get_sw_cqe(cq, cq->mcq.cons_index); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic enum ib_wc_opcode get_umr_comp(struct mlx5_ib_wq *wq, int idx) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci switch (wq->wr_data[idx]) { 1028c2ecf20Sopenharmony_ci case MLX5_IB_WR_UMR: 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: 1068c2ecf20Sopenharmony_ci return IB_WC_LOCAL_INV; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci case IB_WR_REG_MR: 1098c2ecf20Sopenharmony_ci return IB_WC_REG_MR; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci default: 1128c2ecf20Sopenharmony_ci pr_warn("unknown completion status\n"); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void handle_good_req(struct ib_wc *wc, struct mlx5_cqe64 *cqe, 1188c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq, int idx) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci wc->wc_flags = 0; 1218c2ecf20Sopenharmony_ci switch (be32_to_cpu(cqe->sop_drop_qpn) >> 24) { 1228c2ecf20Sopenharmony_ci case MLX5_OPCODE_RDMA_WRITE_IMM: 1238c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 1248c2ecf20Sopenharmony_ci fallthrough; 1258c2ecf20Sopenharmony_ci case MLX5_OPCODE_RDMA_WRITE: 1268c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RDMA_WRITE; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case MLX5_OPCODE_SEND_IMM: 1298c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 1308c2ecf20Sopenharmony_ci fallthrough; 1318c2ecf20Sopenharmony_ci case MLX5_OPCODE_SEND: 1328c2ecf20Sopenharmony_ci case MLX5_OPCODE_SEND_INVAL: 1338c2ecf20Sopenharmony_ci wc->opcode = IB_WC_SEND; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci case MLX5_OPCODE_RDMA_READ: 1368c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RDMA_READ; 1378c2ecf20Sopenharmony_ci wc->byte_len = be32_to_cpu(cqe->byte_cnt); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci case MLX5_OPCODE_ATOMIC_CS: 1408c2ecf20Sopenharmony_ci wc->opcode = IB_WC_COMP_SWAP; 1418c2ecf20Sopenharmony_ci wc->byte_len = 8; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case MLX5_OPCODE_ATOMIC_FA: 1448c2ecf20Sopenharmony_ci wc->opcode = IB_WC_FETCH_ADD; 1458c2ecf20Sopenharmony_ci wc->byte_len = 8; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case MLX5_OPCODE_ATOMIC_MASKED_CS: 1488c2ecf20Sopenharmony_ci wc->opcode = IB_WC_MASKED_COMP_SWAP; 1498c2ecf20Sopenharmony_ci wc->byte_len = 8; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci case MLX5_OPCODE_ATOMIC_MASKED_FA: 1528c2ecf20Sopenharmony_ci wc->opcode = IB_WC_MASKED_FETCH_ADD; 1538c2ecf20Sopenharmony_ci wc->byte_len = 8; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case MLX5_OPCODE_UMR: 1568c2ecf20Sopenharmony_ci wc->opcode = get_umr_comp(wq, idx); 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cienum { 1628c2ecf20Sopenharmony_ci MLX5_GRH_IN_BUFFER = 1, 1638c2ecf20Sopenharmony_ci MLX5_GRH_IN_CQE = 2, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, 1678c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci enum rdma_link_layer ll = rdma_port_get_link_layer(qp->ibqp.device, 1); 1708c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device); 1718c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq = NULL; 1728c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq; 1738c2ecf20Sopenharmony_ci u16 wqe_ctr; 1748c2ecf20Sopenharmony_ci u8 roce_packet_type; 1758c2ecf20Sopenharmony_ci bool vlan_present; 1768c2ecf20Sopenharmony_ci u8 g; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (qp->ibqp.srq || qp->ibqp.xrcd) { 1798c2ecf20Sopenharmony_ci struct mlx5_core_srq *msrq = NULL; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (qp->ibqp.xrcd) { 1828c2ecf20Sopenharmony_ci msrq = mlx5_cmd_get_srq(dev, be32_to_cpu(cqe->srqn)); 1838c2ecf20Sopenharmony_ci if (msrq) 1848c2ecf20Sopenharmony_ci srq = to_mibsrq(msrq); 1858c2ecf20Sopenharmony_ci } else { 1868c2ecf20Sopenharmony_ci srq = to_msrq(qp->ibqp.srq); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci if (srq) { 1898c2ecf20Sopenharmony_ci wqe_ctr = be16_to_cpu(cqe->wqe_counter); 1908c2ecf20Sopenharmony_ci wc->wr_id = srq->wrid[wqe_ctr]; 1918c2ecf20Sopenharmony_ci mlx5_ib_free_srq_wqe(srq, wqe_ctr); 1928c2ecf20Sopenharmony_ci if (msrq) 1938c2ecf20Sopenharmony_ci mlx5_core_res_put(&msrq->common); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci wq = &qp->rq; 1978c2ecf20Sopenharmony_ci wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; 1988c2ecf20Sopenharmony_ci ++wq->tail; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci wc->byte_len = be32_to_cpu(cqe->byte_cnt); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci switch (get_cqe_opcode(cqe)) { 2038c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_WR_IMM: 2048c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; 2058c2ecf20Sopenharmony_ci wc->wc_flags = IB_WC_WITH_IMM; 2068c2ecf20Sopenharmony_ci wc->ex.imm_data = cqe->immediate; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND: 2098c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV; 2108c2ecf20Sopenharmony_ci wc->wc_flags = IB_WC_IP_CSUM_OK; 2118c2ecf20Sopenharmony_ci if (unlikely(!((cqe->hds_ip_ext & CQE_L3_OK) && 2128c2ecf20Sopenharmony_ci (cqe->hds_ip_ext & CQE_L4_OK)))) 2138c2ecf20Sopenharmony_ci wc->wc_flags = 0; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND_IMM: 2168c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV; 2178c2ecf20Sopenharmony_ci wc->wc_flags = IB_WC_WITH_IMM; 2188c2ecf20Sopenharmony_ci wc->ex.imm_data = cqe->immediate; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND_INV: 2218c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV; 2228c2ecf20Sopenharmony_ci wc->wc_flags = IB_WC_WITH_INVALIDATE; 2238c2ecf20Sopenharmony_ci wc->ex.invalidate_rkey = be32_to_cpu(cqe->inval_rkey); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; 2278c2ecf20Sopenharmony_ci wc->dlid_path_bits = cqe->ml_path; 2288c2ecf20Sopenharmony_ci g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; 2298c2ecf20Sopenharmony_ci wc->wc_flags |= g ? IB_WC_GRH : 0; 2308c2ecf20Sopenharmony_ci if (unlikely(is_qp1(qp->ibqp.qp_type))) { 2318c2ecf20Sopenharmony_ci u16 pkey = be32_to_cpu(cqe->pkey) & 0xffff; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ib_find_cached_pkey(&dev->ib_dev, qp->port, pkey, 2348c2ecf20Sopenharmony_ci &wc->pkey_index); 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci wc->pkey_index = 0; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (ll != IB_LINK_LAYER_ETHERNET) { 2408c2ecf20Sopenharmony_ci wc->slid = be16_to_cpu(cqe->slid); 2418c2ecf20Sopenharmony_ci wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; 2428c2ecf20Sopenharmony_ci return; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci wc->slid = 0; 2468c2ecf20Sopenharmony_ci vlan_present = cqe->l4_l3_hdr_type & 0x1; 2478c2ecf20Sopenharmony_ci roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; 2488c2ecf20Sopenharmony_ci if (vlan_present) { 2498c2ecf20Sopenharmony_ci wc->vlan_id = (be16_to_cpu(cqe->vlan_info)) & 0xfff; 2508c2ecf20Sopenharmony_ci wc->sl = (be16_to_cpu(cqe->vlan_info) >> 13) & 0x7; 2518c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_VLAN; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci wc->sl = 0; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci switch (roce_packet_type) { 2578c2ecf20Sopenharmony_ci case MLX5_CQE_ROCE_L3_HEADER_TYPE_GRH: 2588c2ecf20Sopenharmony_ci wc->network_hdr_type = RDMA_NETWORK_ROCE_V1; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci case MLX5_CQE_ROCE_L3_HEADER_TYPE_IPV6: 2618c2ecf20Sopenharmony_ci wc->network_hdr_type = RDMA_NETWORK_IPV6; 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci case MLX5_CQE_ROCE_L3_HEADER_TYPE_IPV4: 2648c2ecf20Sopenharmony_ci wc->network_hdr_type = RDMA_NETWORK_IPV4; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_NETWORK_HDR_TYPE; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void dump_cqe(struct mlx5_ib_dev *dev, struct mlx5_err_cqe *cqe) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "dump error cqe\n"); 2738c2ecf20Sopenharmony_ci mlx5_dump_err_cqe(dev->mdev, cqe); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void mlx5_handle_error_cqe(struct mlx5_ib_dev *dev, 2778c2ecf20Sopenharmony_ci struct mlx5_err_cqe *cqe, 2788c2ecf20Sopenharmony_ci struct ib_wc *wc) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci int dump = 1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci switch (cqe->syndrome) { 2838c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR: 2848c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_LEN_ERR; 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR: 2878c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_QP_OP_ERR; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_LOCAL_PROT_ERR: 2908c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_PROT_ERR; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_WR_FLUSH_ERR: 2938c2ecf20Sopenharmony_ci dump = 0; 2948c2ecf20Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_MW_BIND_ERR: 2978c2ecf20Sopenharmony_ci wc->status = IB_WC_MW_BIND_ERR; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_BAD_RESP_ERR: 3008c2ecf20Sopenharmony_ci wc->status = IB_WC_BAD_RESP_ERR; 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR: 3038c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_ACCESS_ERR; 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: 3068c2ecf20Sopenharmony_ci wc->status = IB_WC_REM_INV_REQ_ERR; 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR: 3098c2ecf20Sopenharmony_ci wc->status = IB_WC_REM_ACCESS_ERR; 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_REMOTE_OP_ERR: 3128c2ecf20Sopenharmony_ci wc->status = IB_WC_REM_OP_ERR; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: 3158c2ecf20Sopenharmony_ci wc->status = IB_WC_RETRY_EXC_ERR; 3168c2ecf20Sopenharmony_ci dump = 0; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR: 3198c2ecf20Sopenharmony_ci wc->status = IB_WC_RNR_RETRY_EXC_ERR; 3208c2ecf20Sopenharmony_ci dump = 0; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR: 3238c2ecf20Sopenharmony_ci wc->status = IB_WC_REM_ABORT_ERR; 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci default: 3268c2ecf20Sopenharmony_ci wc->status = IB_WC_GENERAL_ERR; 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci wc->vendor_err = cqe->vendor_err_synd; 3318c2ecf20Sopenharmony_ci if (dump) 3328c2ecf20Sopenharmony_ci dump_cqe(dev, cqe); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64, 3368c2ecf20Sopenharmony_ci u16 tail, u16 head) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci u16 idx; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci do { 3418c2ecf20Sopenharmony_ci idx = tail & (qp->sq.wqe_cnt - 1); 3428c2ecf20Sopenharmony_ci if (idx == head) 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci tail = qp->sq.w_list[idx].next; 3468c2ecf20Sopenharmony_ci } while (1); 3478c2ecf20Sopenharmony_ci tail = qp->sq.w_list[idx].next; 3488c2ecf20Sopenharmony_ci qp->sq.last_poll = tail; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci mlx5_frag_buf_free(dev->mdev, &buf->frag_buf); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void get_sig_err_item(struct mlx5_sig_err_cqe *cqe, 3578c2ecf20Sopenharmony_ci struct ib_sig_err *item) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u16 syndrome = be16_to_cpu(cqe->syndrome); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci#define GUARD_ERR (1 << 13) 3628c2ecf20Sopenharmony_ci#define APPTAG_ERR (1 << 12) 3638c2ecf20Sopenharmony_ci#define REFTAG_ERR (1 << 11) 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (syndrome & GUARD_ERR) { 3668c2ecf20Sopenharmony_ci item->err_type = IB_SIG_BAD_GUARD; 3678c2ecf20Sopenharmony_ci item->expected = be32_to_cpu(cqe->expected_trans_sig) >> 16; 3688c2ecf20Sopenharmony_ci item->actual = be32_to_cpu(cqe->actual_trans_sig) >> 16; 3698c2ecf20Sopenharmony_ci } else 3708c2ecf20Sopenharmony_ci if (syndrome & REFTAG_ERR) { 3718c2ecf20Sopenharmony_ci item->err_type = IB_SIG_BAD_REFTAG; 3728c2ecf20Sopenharmony_ci item->expected = be32_to_cpu(cqe->expected_reftag); 3738c2ecf20Sopenharmony_ci item->actual = be32_to_cpu(cqe->actual_reftag); 3748c2ecf20Sopenharmony_ci } else 3758c2ecf20Sopenharmony_ci if (syndrome & APPTAG_ERR) { 3768c2ecf20Sopenharmony_ci item->err_type = IB_SIG_BAD_APPTAG; 3778c2ecf20Sopenharmony_ci item->expected = be32_to_cpu(cqe->expected_trans_sig) & 0xffff; 3788c2ecf20Sopenharmony_ci item->actual = be32_to_cpu(cqe->actual_trans_sig) & 0xffff; 3798c2ecf20Sopenharmony_ci } else { 3808c2ecf20Sopenharmony_ci pr_err("Got signature completion error with bad syndrome %04x\n", 3818c2ecf20Sopenharmony_ci syndrome); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci item->sig_err_offset = be64_to_cpu(cqe->err_offset); 3858c2ecf20Sopenharmony_ci item->key = be32_to_cpu(cqe->mkey); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void sw_comp(struct mlx5_ib_qp *qp, int num_entries, struct ib_wc *wc, 3898c2ecf20Sopenharmony_ci int *npolled, bool is_send) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq; 3928c2ecf20Sopenharmony_ci unsigned int cur; 3938c2ecf20Sopenharmony_ci int np; 3948c2ecf20Sopenharmony_ci int i; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci wq = (is_send) ? &qp->sq : &qp->rq; 3978c2ecf20Sopenharmony_ci cur = wq->head - wq->tail; 3988c2ecf20Sopenharmony_ci np = *npolled; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (cur == 0) 4018c2ecf20Sopenharmony_ci return; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci for (i = 0; i < cur && np < num_entries; i++) { 4048c2ecf20Sopenharmony_ci unsigned int idx; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci idx = (is_send) ? wq->last_poll : wq->tail; 4078c2ecf20Sopenharmony_ci idx &= (wq->wqe_cnt - 1); 4088c2ecf20Sopenharmony_ci wc->wr_id = wq->wrid[idx]; 4098c2ecf20Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 4108c2ecf20Sopenharmony_ci wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; 4118c2ecf20Sopenharmony_ci wq->tail++; 4128c2ecf20Sopenharmony_ci if (is_send) 4138c2ecf20Sopenharmony_ci wq->last_poll = wq->w_list[idx].next; 4148c2ecf20Sopenharmony_ci np++; 4158c2ecf20Sopenharmony_ci wc->qp = &qp->ibqp; 4168c2ecf20Sopenharmony_ci wc++; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci *npolled = np; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void mlx5_ib_poll_sw_comp(struct mlx5_ib_cq *cq, int num_entries, 4228c2ecf20Sopenharmony_ci struct ib_wc *wc, int *npolled) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci *npolled = 0; 4278c2ecf20Sopenharmony_ci /* Find uncompleted WQEs belonging to that cq and return mmics ones */ 4288c2ecf20Sopenharmony_ci list_for_each_entry(qp, &cq->list_send_qp, cq_send_list) { 4298c2ecf20Sopenharmony_ci sw_comp(qp, num_entries, wc + *npolled, npolled, true); 4308c2ecf20Sopenharmony_ci if (*npolled >= num_entries) 4318c2ecf20Sopenharmony_ci return; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci list_for_each_entry(qp, &cq->list_recv_qp, cq_recv_list) { 4358c2ecf20Sopenharmony_ci sw_comp(qp, num_entries, wc + *npolled, npolled, false); 4368c2ecf20Sopenharmony_ci if (*npolled >= num_entries) 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int mlx5_poll_one(struct mlx5_ib_cq *cq, 4428c2ecf20Sopenharmony_ci struct mlx5_ib_qp **cur_qp, 4438c2ecf20Sopenharmony_ci struct ib_wc *wc) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 4468c2ecf20Sopenharmony_ci struct mlx5_err_cqe *err_cqe; 4478c2ecf20Sopenharmony_ci struct mlx5_cqe64 *cqe64; 4488c2ecf20Sopenharmony_ci struct mlx5_core_qp *mqp; 4498c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq; 4508c2ecf20Sopenharmony_ci uint8_t opcode; 4518c2ecf20Sopenharmony_ci uint32_t qpn; 4528c2ecf20Sopenharmony_ci u16 wqe_ctr; 4538c2ecf20Sopenharmony_ci void *cqe; 4548c2ecf20Sopenharmony_ci int idx; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cirepoll: 4578c2ecf20Sopenharmony_ci cqe = next_cqe_sw(cq); 4588c2ecf20Sopenharmony_ci if (!cqe) 4598c2ecf20Sopenharmony_ci return -EAGAIN; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ++cq->mcq.cons_index; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Make sure we read CQ entry contents after we've checked the 4668c2ecf20Sopenharmony_ci * ownership bit. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci rmb(); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci opcode = get_cqe_opcode(cqe64); 4718c2ecf20Sopenharmony_ci if (unlikely(opcode == MLX5_CQE_RESIZE_CQ)) { 4728c2ecf20Sopenharmony_ci if (likely(cq->resize_buf)) { 4738c2ecf20Sopenharmony_ci free_cq_buf(dev, &cq->buf); 4748c2ecf20Sopenharmony_ci cq->buf = *cq->resize_buf; 4758c2ecf20Sopenharmony_ci kfree(cq->resize_buf); 4768c2ecf20Sopenharmony_ci cq->resize_buf = NULL; 4778c2ecf20Sopenharmony_ci goto repoll; 4788c2ecf20Sopenharmony_ci } else { 4798c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unexpected resize cqe\n"); 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci qpn = ntohl(cqe64->sop_drop_qpn) & 0xffffff; 4848c2ecf20Sopenharmony_ci if (!*cur_qp || (qpn != (*cur_qp)->ibqp.qp_num)) { 4858c2ecf20Sopenharmony_ci /* We do not have to take the QP table lock here, 4868c2ecf20Sopenharmony_ci * because CQs will be locked while QPs are removed 4878c2ecf20Sopenharmony_ci * from the table. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_ci mqp = radix_tree_lookup(&dev->qp_table.tree, qpn); 4908c2ecf20Sopenharmony_ci *cur_qp = to_mibqp(mqp); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci wc->qp = &(*cur_qp)->ibqp; 4948c2ecf20Sopenharmony_ci switch (opcode) { 4958c2ecf20Sopenharmony_ci case MLX5_CQE_REQ: 4968c2ecf20Sopenharmony_ci wq = &(*cur_qp)->sq; 4978c2ecf20Sopenharmony_ci wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 4988c2ecf20Sopenharmony_ci idx = wqe_ctr & (wq->wqe_cnt - 1); 4998c2ecf20Sopenharmony_ci handle_good_req(wc, cqe64, wq, idx); 5008c2ecf20Sopenharmony_ci handle_atomics(*cur_qp, cqe64, wq->last_poll, idx); 5018c2ecf20Sopenharmony_ci wc->wr_id = wq->wrid[idx]; 5028c2ecf20Sopenharmony_ci wq->tail = wq->wqe_head[idx] + 1; 5038c2ecf20Sopenharmony_ci wc->status = IB_WC_SUCCESS; 5048c2ecf20Sopenharmony_ci break; 5058c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_WR_IMM: 5068c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND: 5078c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND_IMM: 5088c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_SEND_INV: 5098c2ecf20Sopenharmony_ci handle_responder(wc, cqe64, *cur_qp); 5108c2ecf20Sopenharmony_ci wc->status = IB_WC_SUCCESS; 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case MLX5_CQE_RESIZE_CQ: 5138c2ecf20Sopenharmony_ci break; 5148c2ecf20Sopenharmony_ci case MLX5_CQE_REQ_ERR: 5158c2ecf20Sopenharmony_ci case MLX5_CQE_RESP_ERR: 5168c2ecf20Sopenharmony_ci err_cqe = (struct mlx5_err_cqe *)cqe64; 5178c2ecf20Sopenharmony_ci mlx5_handle_error_cqe(dev, err_cqe, wc); 5188c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "%s error cqe on cqn 0x%x:\n", 5198c2ecf20Sopenharmony_ci opcode == MLX5_CQE_REQ_ERR ? 5208c2ecf20Sopenharmony_ci "Requestor" : "Responder", cq->mcq.cqn); 5218c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "syndrome 0x%x, vendor syndrome 0x%x\n", 5228c2ecf20Sopenharmony_ci err_cqe->syndrome, err_cqe->vendor_err_synd); 5238c2ecf20Sopenharmony_ci if (opcode == MLX5_CQE_REQ_ERR) { 5248c2ecf20Sopenharmony_ci wq = &(*cur_qp)->sq; 5258c2ecf20Sopenharmony_ci wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 5268c2ecf20Sopenharmony_ci idx = wqe_ctr & (wq->wqe_cnt - 1); 5278c2ecf20Sopenharmony_ci wc->wr_id = wq->wrid[idx]; 5288c2ecf20Sopenharmony_ci wq->tail = wq->wqe_head[idx] + 1; 5298c2ecf20Sopenharmony_ci } else { 5308c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if ((*cur_qp)->ibqp.srq) { 5338c2ecf20Sopenharmony_ci srq = to_msrq((*cur_qp)->ibqp.srq); 5348c2ecf20Sopenharmony_ci wqe_ctr = be16_to_cpu(cqe64->wqe_counter); 5358c2ecf20Sopenharmony_ci wc->wr_id = srq->wrid[wqe_ctr]; 5368c2ecf20Sopenharmony_ci mlx5_ib_free_srq_wqe(srq, wqe_ctr); 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci wq = &(*cur_qp)->rq; 5398c2ecf20Sopenharmony_ci wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; 5408c2ecf20Sopenharmony_ci ++wq->tail; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci case MLX5_CQE_SIG_ERR: { 5458c2ecf20Sopenharmony_ci struct mlx5_sig_err_cqe *sig_err_cqe = 5468c2ecf20Sopenharmony_ci (struct mlx5_sig_err_cqe *)cqe64; 5478c2ecf20Sopenharmony_ci struct mlx5_core_sig_ctx *sig; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci xa_lock(&dev->sig_mrs); 5508c2ecf20Sopenharmony_ci sig = xa_load(&dev->sig_mrs, 5518c2ecf20Sopenharmony_ci mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey))); 5528c2ecf20Sopenharmony_ci get_sig_err_item(sig_err_cqe, &sig->err_item); 5538c2ecf20Sopenharmony_ci sig->sig_err_exists = true; 5548c2ecf20Sopenharmony_ci sig->sigerr_count++; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "CQN: 0x%x Got SIGERR on key: 0x%x err_type %x err_offset %llx expected %x actual %x\n", 5578c2ecf20Sopenharmony_ci cq->mcq.cqn, sig->err_item.key, 5588c2ecf20Sopenharmony_ci sig->err_item.err_type, 5598c2ecf20Sopenharmony_ci sig->err_item.sig_err_offset, 5608c2ecf20Sopenharmony_ci sig->err_item.expected, 5618c2ecf20Sopenharmony_ci sig->err_item.actual); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci xa_unlock(&dev->sig_mrs); 5648c2ecf20Sopenharmony_ci goto repoll; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries, 5728c2ecf20Sopenharmony_ci struct ib_wc *wc, bool is_fatal_err) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 5758c2ecf20Sopenharmony_ci struct mlx5_ib_wc *soft_wc, *next; 5768c2ecf20Sopenharmony_ci int npolled = 0; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci list_for_each_entry_safe(soft_wc, next, &cq->wc_list, list) { 5798c2ecf20Sopenharmony_ci if (npolled >= num_entries) 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "polled software generated completion on CQ 0x%x\n", 5838c2ecf20Sopenharmony_ci cq->mcq.cqn); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (unlikely(is_fatal_err)) { 5868c2ecf20Sopenharmony_ci soft_wc->wc.status = IB_WC_WR_FLUSH_ERR; 5878c2ecf20Sopenharmony_ci soft_wc->wc.vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci wc[npolled++] = soft_wc->wc; 5908c2ecf20Sopenharmony_ci list_del(&soft_wc->list); 5918c2ecf20Sopenharmony_ci kfree(soft_wc); 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return npolled; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ciint mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = to_mcq(ibcq); 6008c2ecf20Sopenharmony_ci struct mlx5_ib_qp *cur_qp = NULL; 6018c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 6028c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 6038c2ecf20Sopenharmony_ci unsigned long flags; 6048c2ecf20Sopenharmony_ci int soft_polled = 0; 6058c2ecf20Sopenharmony_ci int npolled; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 6088c2ecf20Sopenharmony_ci if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { 6098c2ecf20Sopenharmony_ci /* make sure no soft wqe's are waiting */ 6108c2ecf20Sopenharmony_ci if (unlikely(!list_empty(&cq->wc_list))) 6118c2ecf20Sopenharmony_ci soft_polled = poll_soft_wc(cq, num_entries, wc, true); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci mlx5_ib_poll_sw_comp(cq, num_entries - soft_polled, 6148c2ecf20Sopenharmony_ci wc + soft_polled, &npolled); 6158c2ecf20Sopenharmony_ci goto out; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (unlikely(!list_empty(&cq->wc_list))) 6198c2ecf20Sopenharmony_ci soft_polled = poll_soft_wc(cq, num_entries, wc, false); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci for (npolled = 0; npolled < num_entries - soft_polled; npolled++) { 6228c2ecf20Sopenharmony_ci if (mlx5_poll_one(cq, &cur_qp, wc + soft_polled + npolled)) 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (npolled) 6278c2ecf20Sopenharmony_ci mlx5_cq_set_ci(&cq->mcq); 6288c2ecf20Sopenharmony_ciout: 6298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return soft_polled + npolled; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ciint mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = to_mdev(ibcq->device)->mdev; 6378c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = to_mcq(ibcq); 6388c2ecf20Sopenharmony_ci void __iomem *uar_page = mdev->priv.uar->map; 6398c2ecf20Sopenharmony_ci unsigned long irq_flags; 6408c2ecf20Sopenharmony_ci int ret = 0; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, irq_flags); 6438c2ecf20Sopenharmony_ci if (cq->notify_flags != IB_CQ_NEXT_COMP) 6448c2ecf20Sopenharmony_ci cq->notify_flags = flags & IB_CQ_SOLICITED_MASK; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !list_empty(&cq->wc_list)) 6478c2ecf20Sopenharmony_ci ret = 1; 6488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, irq_flags); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci mlx5_cq_arm(&cq->mcq, 6518c2ecf20Sopenharmony_ci (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? 6528c2ecf20Sopenharmony_ci MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT, 6538c2ecf20Sopenharmony_ci uar_page, to_mcq(ibcq)->mcq.cons_index); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int alloc_cq_frag_buf(struct mlx5_ib_dev *dev, 6598c2ecf20Sopenharmony_ci struct mlx5_ib_cq_buf *buf, 6608c2ecf20Sopenharmony_ci int nent, 6618c2ecf20Sopenharmony_ci int cqe_size) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct mlx5_frag_buf *frag_buf = &buf->frag_buf; 6648c2ecf20Sopenharmony_ci u8 log_wq_stride = 6 + (cqe_size == 128 ? 1 : 0); 6658c2ecf20Sopenharmony_ci u8 log_wq_sz = ilog2(cqe_size); 6668c2ecf20Sopenharmony_ci int err; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci err = mlx5_frag_buf_alloc_node(dev->mdev, 6698c2ecf20Sopenharmony_ci nent * cqe_size, 6708c2ecf20Sopenharmony_ci frag_buf, 6718c2ecf20Sopenharmony_ci dev->mdev->priv.numa_node); 6728c2ecf20Sopenharmony_ci if (err) 6738c2ecf20Sopenharmony_ci return err; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci mlx5_init_fbc(frag_buf->frags, log_wq_stride, log_wq_sz, &buf->fbc); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci buf->cqe_size = cqe_size; 6788c2ecf20Sopenharmony_ci buf->nent = nent; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cienum { 6848c2ecf20Sopenharmony_ci MLX5_CQE_RES_FORMAT_HASH = 0, 6858c2ecf20Sopenharmony_ci MLX5_CQE_RES_FORMAT_CSUM = 1, 6868c2ecf20Sopenharmony_ci MLX5_CQE_RES_FORMAT_CSUM_STRIDX = 3, 6878c2ecf20Sopenharmony_ci}; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int mini_cqe_res_format_to_hw(struct mlx5_ib_dev *dev, u8 format) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci switch (format) { 6928c2ecf20Sopenharmony_ci case MLX5_IB_CQE_RES_FORMAT_HASH: 6938c2ecf20Sopenharmony_ci return MLX5_CQE_RES_FORMAT_HASH; 6948c2ecf20Sopenharmony_ci case MLX5_IB_CQE_RES_FORMAT_CSUM: 6958c2ecf20Sopenharmony_ci return MLX5_CQE_RES_FORMAT_CSUM; 6968c2ecf20Sopenharmony_ci case MLX5_IB_CQE_RES_FORMAT_CSUM_STRIDX: 6978c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, mini_cqe_resp_stride_index)) 6988c2ecf20Sopenharmony_ci return MLX5_CQE_RES_FORMAT_CSUM_STRIDX; 6998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7008c2ecf20Sopenharmony_ci default: 7018c2ecf20Sopenharmony_ci return -EINVAL; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, 7068c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq, int entries, u32 **cqb, 7078c2ecf20Sopenharmony_ci int *cqe_size, int *index, int *inlen) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct mlx5_ib_create_cq ucmd = {}; 7108c2ecf20Sopenharmony_ci size_t ucmdlen; 7118c2ecf20Sopenharmony_ci int page_shift; 7128c2ecf20Sopenharmony_ci __be64 *pas; 7138c2ecf20Sopenharmony_ci int npages; 7148c2ecf20Sopenharmony_ci int ncont; 7158c2ecf20Sopenharmony_ci void *cqc; 7168c2ecf20Sopenharmony_ci int err; 7178c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *context = rdma_udata_to_drv_context( 7188c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ucmdlen = min(udata->inlen, sizeof(ucmd)); 7218c2ecf20Sopenharmony_ci if (ucmdlen < offsetof(struct mlx5_ib_create_cq, flags)) 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) 7258c2ecf20Sopenharmony_ci return -EFAULT; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if ((ucmd.flags & ~(MLX5_IB_CREATE_CQ_FLAGS_CQE_128B_PAD | 7288c2ecf20Sopenharmony_ci MLX5_IB_CREATE_CQ_FLAGS_UAR_PAGE_INDEX))) 7298c2ecf20Sopenharmony_ci return -EINVAL; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if ((ucmd.cqe_size != 64 && ucmd.cqe_size != 128) || 7328c2ecf20Sopenharmony_ci ucmd.reserved0 || ucmd.reserved1) 7338c2ecf20Sopenharmony_ci return -EINVAL; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci *cqe_size = ucmd.cqe_size; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci cq->buf.umem = 7388c2ecf20Sopenharmony_ci ib_umem_get(&dev->ib_dev, ucmd.buf_addr, 7398c2ecf20Sopenharmony_ci entries * ucmd.cqe_size, IB_ACCESS_LOCAL_WRITE); 7408c2ecf20Sopenharmony_ci if (IS_ERR(cq->buf.umem)) { 7418c2ecf20Sopenharmony_ci err = PTR_ERR(cq->buf.umem); 7428c2ecf20Sopenharmony_ci return err; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci err = mlx5_ib_db_map_user(context, udata, ucmd.db_addr, &cq->db); 7468c2ecf20Sopenharmony_ci if (err) 7478c2ecf20Sopenharmony_ci goto err_umem; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, 0, &npages, &page_shift, 7508c2ecf20Sopenharmony_ci &ncont, NULL); 7518c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "addr 0x%llx, size %u, npages %d, page_shift %d, ncont %d\n", 7528c2ecf20Sopenharmony_ci ucmd.buf_addr, entries * ucmd.cqe_size, npages, page_shift, ncont); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 7558c2ecf20Sopenharmony_ci MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * ncont; 7568c2ecf20Sopenharmony_ci *cqb = kvzalloc(*inlen, GFP_KERNEL); 7578c2ecf20Sopenharmony_ci if (!*cqb) { 7588c2ecf20Sopenharmony_ci err = -ENOMEM; 7598c2ecf20Sopenharmony_ci goto err_db; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, *cqb, pas); 7638c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, cq->buf.umem, page_shift, pas, 0); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci cqc = MLX5_ADDR_OF(create_cq_in, *cqb, cq_context); 7668c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, log_page_size, 7678c2ecf20Sopenharmony_ci page_shift - MLX5_ADAPTER_PAGE_SHIFT); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (ucmd.flags & MLX5_IB_CREATE_CQ_FLAGS_UAR_PAGE_INDEX) { 7708c2ecf20Sopenharmony_ci *index = ucmd.uar_page_index; 7718c2ecf20Sopenharmony_ci } else if (context->bfregi.lib_uar_dyn) { 7728c2ecf20Sopenharmony_ci err = -EINVAL; 7738c2ecf20Sopenharmony_ci goto err_cqb; 7748c2ecf20Sopenharmony_ci } else { 7758c2ecf20Sopenharmony_ci *index = context->bfregi.sys_pages[0]; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (ucmd.cqe_comp_en == 1) { 7798c2ecf20Sopenharmony_ci int mini_cqe_format; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!((*cqe_size == 128 && 7828c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, cqe_compression_128)) || 7838c2ecf20Sopenharmony_ci (*cqe_size == 64 && 7848c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, cqe_compression)))) { 7858c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 7868c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "CQE compression is not supported for size %d!\n", 7878c2ecf20Sopenharmony_ci *cqe_size); 7888c2ecf20Sopenharmony_ci goto err_cqb; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci mini_cqe_format = 7928c2ecf20Sopenharmony_ci mini_cqe_res_format_to_hw(dev, 7938c2ecf20Sopenharmony_ci ucmd.cqe_comp_res_format); 7948c2ecf20Sopenharmony_ci if (mini_cqe_format < 0) { 7958c2ecf20Sopenharmony_ci err = mini_cqe_format; 7968c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "CQE compression res format %d error: %d\n", 7978c2ecf20Sopenharmony_ci ucmd.cqe_comp_res_format, err); 7988c2ecf20Sopenharmony_ci goto err_cqb; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, cqe_comp_en, 1); 8028c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, mini_cqe_res_format, mini_cqe_format); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (ucmd.flags & MLX5_IB_CREATE_CQ_FLAGS_CQE_128B_PAD) { 8068c2ecf20Sopenharmony_ci if (*cqe_size != 128 || 8078c2ecf20Sopenharmony_ci !MLX5_CAP_GEN(dev->mdev, cqe_128_always)) { 8088c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 8098c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, 8108c2ecf20Sopenharmony_ci "CQE padding is not supported for CQE size of %dB!\n", 8118c2ecf20Sopenharmony_ci *cqe_size); 8128c2ecf20Sopenharmony_ci goto err_cqb; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci cq->private_flags |= MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci MLX5_SET(create_cq_in, *cqb, uid, context->devx_uid); 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cierr_cqb: 8228c2ecf20Sopenharmony_ci kvfree(*cqb); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cierr_db: 8258c2ecf20Sopenharmony_ci mlx5_ib_db_unmap_user(context, &cq->db); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cierr_umem: 8288c2ecf20Sopenharmony_ci ib_umem_release(cq->buf.umem); 8298c2ecf20Sopenharmony_ci return err; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic void destroy_cq_user(struct mlx5_ib_cq *cq, struct ib_udata *udata) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *context = rdma_udata_to_drv_context( 8358c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci mlx5_ib_db_unmap_user(context, &cq->db); 8388c2ecf20Sopenharmony_ci ib_umem_release(cq->buf.umem); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic void init_cq_frag_buf(struct mlx5_ib_cq_buf *buf) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci int i; 8448c2ecf20Sopenharmony_ci void *cqe; 8458c2ecf20Sopenharmony_ci struct mlx5_cqe64 *cqe64; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = 0; i < buf->nent; i++) { 8488c2ecf20Sopenharmony_ci cqe = mlx5_frag_buf_get_wqe(&buf->fbc, i); 8498c2ecf20Sopenharmony_ci cqe64 = buf->cqe_size == 64 ? cqe : cqe + 64; 8508c2ecf20Sopenharmony_ci cqe64->op_own = MLX5_CQE_INVALID << 4; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, 8558c2ecf20Sopenharmony_ci int entries, int cqe_size, 8568c2ecf20Sopenharmony_ci u32 **cqb, int *index, int *inlen) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci __be64 *pas; 8598c2ecf20Sopenharmony_ci void *cqc; 8608c2ecf20Sopenharmony_ci int err; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci err = mlx5_db_alloc(dev->mdev, &cq->db); 8638c2ecf20Sopenharmony_ci if (err) 8648c2ecf20Sopenharmony_ci return err; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci cq->mcq.set_ci_db = cq->db.db; 8678c2ecf20Sopenharmony_ci cq->mcq.arm_db = cq->db.db + 1; 8688c2ecf20Sopenharmony_ci cq->mcq.cqe_sz = cqe_size; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci err = alloc_cq_frag_buf(dev, &cq->buf, entries, cqe_size); 8718c2ecf20Sopenharmony_ci if (err) 8728c2ecf20Sopenharmony_ci goto err_db; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci init_cq_frag_buf(&cq->buf); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(create_cq_in) + 8778c2ecf20Sopenharmony_ci MLX5_FLD_SZ_BYTES(create_cq_in, pas[0]) * 8788c2ecf20Sopenharmony_ci cq->buf.frag_buf.npages; 8798c2ecf20Sopenharmony_ci *cqb = kvzalloc(*inlen, GFP_KERNEL); 8808c2ecf20Sopenharmony_ci if (!*cqb) { 8818c2ecf20Sopenharmony_ci err = -ENOMEM; 8828c2ecf20Sopenharmony_ci goto err_buf; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, *cqb, pas); 8868c2ecf20Sopenharmony_ci mlx5_fill_page_frag_array(&cq->buf.frag_buf, pas); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci cqc = MLX5_ADDR_OF(create_cq_in, *cqb, cq_context); 8898c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, log_page_size, 8908c2ecf20Sopenharmony_ci cq->buf.frag_buf.page_shift - 8918c2ecf20Sopenharmony_ci MLX5_ADAPTER_PAGE_SHIFT); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci *index = dev->mdev->priv.uar->index; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return 0; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cierr_buf: 8988c2ecf20Sopenharmony_ci free_cq_buf(dev, &cq->buf); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cierr_db: 9018c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &cq->db); 9028c2ecf20Sopenharmony_ci return err; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void destroy_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci free_cq_buf(dev, &cq->buf); 9088c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &cq->db); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void notify_soft_wc_handler(struct work_struct *work) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = container_of(work, struct mlx5_ib_cq, 9148c2ecf20Sopenharmony_ci notify_work); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ciint mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 9208c2ecf20Sopenharmony_ci struct ib_udata *udata) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct ib_device *ibdev = ibcq->device; 9238c2ecf20Sopenharmony_ci int entries = attr->cqe; 9248c2ecf20Sopenharmony_ci int vector = attr->comp_vector; 9258c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibdev); 9268c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = to_mcq(ibcq); 9278c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_cq_out)]; 9288c2ecf20Sopenharmony_ci int index; 9298c2ecf20Sopenharmony_ci int inlen; 9308c2ecf20Sopenharmony_ci u32 *cqb = NULL; 9318c2ecf20Sopenharmony_ci void *cqc; 9328c2ecf20Sopenharmony_ci int cqe_size; 9338c2ecf20Sopenharmony_ci int eqn; 9348c2ecf20Sopenharmony_ci int err; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (entries < 0 || 9378c2ecf20Sopenharmony_ci (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)))) 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (check_cq_create_flags(attr->flags)) 9418c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci entries = roundup_pow_of_two(entries + 1); 9448c2ecf20Sopenharmony_ci if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))) 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci cq->ibcq.cqe = entries - 1; 9488c2ecf20Sopenharmony_ci mutex_init(&cq->resize_mutex); 9498c2ecf20Sopenharmony_ci spin_lock_init(&cq->lock); 9508c2ecf20Sopenharmony_ci cq->resize_buf = NULL; 9518c2ecf20Sopenharmony_ci cq->resize_umem = NULL; 9528c2ecf20Sopenharmony_ci cq->create_flags = attr->flags; 9538c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cq->list_send_qp); 9548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cq->list_recv_qp); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (udata) { 9578c2ecf20Sopenharmony_ci err = create_cq_user(dev, udata, cq, entries, &cqb, &cqe_size, 9588c2ecf20Sopenharmony_ci &index, &inlen); 9598c2ecf20Sopenharmony_ci if (err) 9608c2ecf20Sopenharmony_ci return err; 9618c2ecf20Sopenharmony_ci } else { 9628c2ecf20Sopenharmony_ci cqe_size = cache_line_size() == 128 ? 128 : 64; 9638c2ecf20Sopenharmony_ci err = create_cq_kernel(dev, cq, entries, cqe_size, &cqb, 9648c2ecf20Sopenharmony_ci &index, &inlen); 9658c2ecf20Sopenharmony_ci if (err) 9668c2ecf20Sopenharmony_ci return err; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci INIT_WORK(&cq->notify_work, notify_soft_wc_handler); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci err = mlx5_vector2eqn(dev->mdev, vector, &eqn); 9728c2ecf20Sopenharmony_ci if (err) 9738c2ecf20Sopenharmony_ci goto err_cqb; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci cq->cqe_size = cqe_size; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci cqc = MLX5_ADDR_OF(create_cq_in, cqb, cq_context); 9788c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, cqe_sz, 9798c2ecf20Sopenharmony_ci cqe_sz_to_mlx_sz(cqe_size, 9808c2ecf20Sopenharmony_ci cq->private_flags & 9818c2ecf20Sopenharmony_ci MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD)); 9828c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, log_cq_size, ilog2(entries)); 9838c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, uar_page, index); 9848c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, c_eqn, eqn); 9858c2ecf20Sopenharmony_ci MLX5_SET64(cqc, cqc, dbr_addr, cq->db.dma); 9868c2ecf20Sopenharmony_ci if (cq->create_flags & IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN) 9878c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, oi, 1); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci err = mlx5_core_create_cq(dev->mdev, &cq->mcq, cqb, inlen, out, sizeof(out)); 9908c2ecf20Sopenharmony_ci if (err) 9918c2ecf20Sopenharmony_ci goto err_cqb; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "cqn 0x%x\n", cq->mcq.cqn); 9948c2ecf20Sopenharmony_ci if (udata) 9958c2ecf20Sopenharmony_ci cq->mcq.tasklet_ctx.comp = mlx5_ib_cq_comp; 9968c2ecf20Sopenharmony_ci else 9978c2ecf20Sopenharmony_ci cq->mcq.comp = mlx5_ib_cq_comp; 9988c2ecf20Sopenharmony_ci cq->mcq.event = mlx5_ib_cq_event; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cq->wc_list); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (udata) 10038c2ecf20Sopenharmony_ci if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof(__u32))) { 10048c2ecf20Sopenharmony_ci err = -EFAULT; 10058c2ecf20Sopenharmony_ci goto err_cmd; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci kvfree(cqb); 10108c2ecf20Sopenharmony_ci return 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cierr_cmd: 10138c2ecf20Sopenharmony_ci mlx5_core_destroy_cq(dev->mdev, &cq->mcq); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cierr_cqb: 10168c2ecf20Sopenharmony_ci kvfree(cqb); 10178c2ecf20Sopenharmony_ci if (udata) 10188c2ecf20Sopenharmony_ci destroy_cq_user(cq, udata); 10198c2ecf20Sopenharmony_ci else 10208c2ecf20Sopenharmony_ci destroy_cq_kernel(dev, cq); 10218c2ecf20Sopenharmony_ci return err; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ciint mlx5_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->device); 10278c2ecf20Sopenharmony_ci struct mlx5_ib_cq *mcq = to_mcq(cq); 10288c2ecf20Sopenharmony_ci int ret; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci ret = mlx5_core_destroy_cq(dev->mdev, &mcq->mcq); 10318c2ecf20Sopenharmony_ci if (ret) 10328c2ecf20Sopenharmony_ci return ret; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (udata) 10358c2ecf20Sopenharmony_ci destroy_cq_user(mcq, udata); 10368c2ecf20Sopenharmony_ci else 10378c2ecf20Sopenharmony_ci destroy_cq_kernel(dev, mcq); 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic int is_equal_rsn(struct mlx5_cqe64 *cqe64, u32 rsn) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci return rsn == (ntohl(cqe64->sop_drop_qpn) & 0xffffff); 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_civoid __mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 rsn, struct mlx5_ib_srq *srq) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct mlx5_cqe64 *cqe64, *dest64; 10498c2ecf20Sopenharmony_ci void *cqe, *dest; 10508c2ecf20Sopenharmony_ci u32 prod_index; 10518c2ecf20Sopenharmony_ci int nfreed = 0; 10528c2ecf20Sopenharmony_ci u8 owner_bit; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (!cq) 10558c2ecf20Sopenharmony_ci return; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* First we need to find the current producer index, so we 10588c2ecf20Sopenharmony_ci * know where to start cleaning from. It doesn't matter if HW 10598c2ecf20Sopenharmony_ci * adds new entries after this loop -- the QP we're worried 10608c2ecf20Sopenharmony_ci * about is already in RESET, so the new entries won't come 10618c2ecf20Sopenharmony_ci * from our QP and therefore don't need to be checked. 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); prod_index++) 10648c2ecf20Sopenharmony_ci if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe) 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Now sweep backwards through the CQ, removing CQ entries 10688c2ecf20Sopenharmony_ci * that match our QP by copying older entries on top of them. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { 10718c2ecf20Sopenharmony_ci cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); 10728c2ecf20Sopenharmony_ci cqe64 = (cq->mcq.cqe_sz == 64) ? cqe : cqe + 64; 10738c2ecf20Sopenharmony_ci if (is_equal_rsn(cqe64, rsn)) { 10748c2ecf20Sopenharmony_ci if (srq && (ntohl(cqe64->srqn) & 0xffffff)) 10758c2ecf20Sopenharmony_ci mlx5_ib_free_srq_wqe(srq, be16_to_cpu(cqe64->wqe_counter)); 10768c2ecf20Sopenharmony_ci ++nfreed; 10778c2ecf20Sopenharmony_ci } else if (nfreed) { 10788c2ecf20Sopenharmony_ci dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe); 10798c2ecf20Sopenharmony_ci dest64 = (cq->mcq.cqe_sz == 64) ? dest : dest + 64; 10808c2ecf20Sopenharmony_ci owner_bit = dest64->op_own & MLX5_CQE_OWNER_MASK; 10818c2ecf20Sopenharmony_ci memcpy(dest, cqe, cq->mcq.cqe_sz); 10828c2ecf20Sopenharmony_ci dest64->op_own = owner_bit | 10838c2ecf20Sopenharmony_ci (dest64->op_own & ~MLX5_CQE_OWNER_MASK); 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (nfreed) { 10888c2ecf20Sopenharmony_ci cq->mcq.cons_index += nfreed; 10898c2ecf20Sopenharmony_ci /* Make sure update of buffer contents is done before 10908c2ecf20Sopenharmony_ci * updating consumer index. 10918c2ecf20Sopenharmony_ci */ 10928c2ecf20Sopenharmony_ci wmb(); 10938c2ecf20Sopenharmony_ci mlx5_cq_set_ci(&cq->mcq); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_civoid mlx5_ib_cq_clean(struct mlx5_ib_cq *cq, u32 qpn, struct mlx5_ib_srq *srq) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci if (!cq) 11008c2ecf20Sopenharmony_ci return; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci spin_lock_irq(&cq->lock); 11038c2ecf20Sopenharmony_ci __mlx5_ib_cq_clean(cq, qpn, srq); 11048c2ecf20Sopenharmony_ci spin_unlock_irq(&cq->lock); 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ciint mlx5_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->device); 11108c2ecf20Sopenharmony_ci struct mlx5_ib_cq *mcq = to_mcq(cq); 11118c2ecf20Sopenharmony_ci int err; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, cq_moderation)) 11148c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (cq_period > MLX5_MAX_CQ_PERIOD) 11178c2ecf20Sopenharmony_ci return -EINVAL; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci err = mlx5_core_modify_cq_moderation(dev->mdev, &mcq->mcq, 11208c2ecf20Sopenharmony_ci cq_period, cq_count); 11218c2ecf20Sopenharmony_ci if (err) 11228c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "modify cq 0x%x failed\n", mcq->mcq.cqn); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci return err; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, 11288c2ecf20Sopenharmony_ci int entries, struct ib_udata *udata, int *npas, 11298c2ecf20Sopenharmony_ci int *page_shift, int *cqe_size) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct mlx5_ib_resize_cq ucmd; 11328c2ecf20Sopenharmony_ci struct ib_umem *umem; 11338c2ecf20Sopenharmony_ci int err; 11348c2ecf20Sopenharmony_ci int npages; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)); 11378c2ecf20Sopenharmony_ci if (err) 11388c2ecf20Sopenharmony_ci return err; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (ucmd.reserved0 || ucmd.reserved1) 11418c2ecf20Sopenharmony_ci return -EINVAL; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* check multiplication overflow */ 11448c2ecf20Sopenharmony_ci if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) 11458c2ecf20Sopenharmony_ci return -EINVAL; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci umem = ib_umem_get(&dev->ib_dev, ucmd.buf_addr, 11488c2ecf20Sopenharmony_ci (size_t)ucmd.cqe_size * entries, 11498c2ecf20Sopenharmony_ci IB_ACCESS_LOCAL_WRITE); 11508c2ecf20Sopenharmony_ci if (IS_ERR(umem)) { 11518c2ecf20Sopenharmony_ci err = PTR_ERR(umem); 11528c2ecf20Sopenharmony_ci return err; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci mlx5_ib_cont_pages(umem, ucmd.buf_addr, 0, &npages, page_shift, 11568c2ecf20Sopenharmony_ci npas, NULL); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci cq->resize_umem = umem; 11598c2ecf20Sopenharmony_ci *cqe_size = ucmd.cqe_size; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci return 0; 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic int resize_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, 11658c2ecf20Sopenharmony_ci int entries, int cqe_size) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci int err; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci cq->resize_buf = kzalloc(sizeof(*cq->resize_buf), GFP_KERNEL); 11708c2ecf20Sopenharmony_ci if (!cq->resize_buf) 11718c2ecf20Sopenharmony_ci return -ENOMEM; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci err = alloc_cq_frag_buf(dev, cq->resize_buf, entries, cqe_size); 11748c2ecf20Sopenharmony_ci if (err) 11758c2ecf20Sopenharmony_ci goto ex; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci init_cq_frag_buf(cq->resize_buf); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci return 0; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ciex: 11828c2ecf20Sopenharmony_ci kfree(cq->resize_buf); 11838c2ecf20Sopenharmony_ci return err; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic int copy_resize_cqes(struct mlx5_ib_cq *cq) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); 11898c2ecf20Sopenharmony_ci struct mlx5_cqe64 *scqe64; 11908c2ecf20Sopenharmony_ci struct mlx5_cqe64 *dcqe64; 11918c2ecf20Sopenharmony_ci void *start_cqe; 11928c2ecf20Sopenharmony_ci void *scqe; 11938c2ecf20Sopenharmony_ci void *dcqe; 11948c2ecf20Sopenharmony_ci int ssize; 11958c2ecf20Sopenharmony_ci int dsize; 11968c2ecf20Sopenharmony_ci int i; 11978c2ecf20Sopenharmony_ci u8 sw_own; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci ssize = cq->buf.cqe_size; 12008c2ecf20Sopenharmony_ci dsize = cq->resize_buf->cqe_size; 12018c2ecf20Sopenharmony_ci if (ssize != dsize) { 12028c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "resize from different cqe size is not supported\n"); 12038c2ecf20Sopenharmony_ci return -EINVAL; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci i = cq->mcq.cons_index; 12078c2ecf20Sopenharmony_ci scqe = get_sw_cqe(cq, i); 12088c2ecf20Sopenharmony_ci scqe64 = ssize == 64 ? scqe : scqe + 64; 12098c2ecf20Sopenharmony_ci start_cqe = scqe; 12108c2ecf20Sopenharmony_ci if (!scqe) { 12118c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "expected cqe in sw ownership\n"); 12128c2ecf20Sopenharmony_ci return -EINVAL; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci while (get_cqe_opcode(scqe64) != MLX5_CQE_RESIZE_CQ) { 12168c2ecf20Sopenharmony_ci dcqe = mlx5_frag_buf_get_wqe(&cq->resize_buf->fbc, 12178c2ecf20Sopenharmony_ci (i + 1) & cq->resize_buf->nent); 12188c2ecf20Sopenharmony_ci dcqe64 = dsize == 64 ? dcqe : dcqe + 64; 12198c2ecf20Sopenharmony_ci sw_own = sw_ownership_bit(i + 1, cq->resize_buf->nent); 12208c2ecf20Sopenharmony_ci memcpy(dcqe, scqe, dsize); 12218c2ecf20Sopenharmony_ci dcqe64->op_own = (dcqe64->op_own & ~MLX5_CQE_OWNER_MASK) | sw_own; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci ++i; 12248c2ecf20Sopenharmony_ci scqe = get_sw_cqe(cq, i); 12258c2ecf20Sopenharmony_ci scqe64 = ssize == 64 ? scqe : scqe + 64; 12268c2ecf20Sopenharmony_ci if (!scqe) { 12278c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "expected cqe in sw ownership\n"); 12288c2ecf20Sopenharmony_ci return -EINVAL; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (scqe == start_cqe) { 12328c2ecf20Sopenharmony_ci pr_warn("resize CQ failed to get resize CQE, CQN 0x%x\n", 12338c2ecf20Sopenharmony_ci cq->mcq.cqn); 12348c2ecf20Sopenharmony_ci return -ENOMEM; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci ++cq->mcq.cons_index; 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ciint mlx5_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibcq->device); 12448c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = to_mcq(ibcq); 12458c2ecf20Sopenharmony_ci void *cqc; 12468c2ecf20Sopenharmony_ci u32 *in; 12478c2ecf20Sopenharmony_ci int err; 12488c2ecf20Sopenharmony_ci int npas; 12498c2ecf20Sopenharmony_ci __be64 *pas; 12508c2ecf20Sopenharmony_ci int page_shift; 12518c2ecf20Sopenharmony_ci int inlen; 12528c2ecf20Sopenharmony_ci int cqe_size; 12538c2ecf20Sopenharmony_ci unsigned long flags; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, cq_resize)) { 12568c2ecf20Sopenharmony_ci pr_info("Firmware does not support resize CQ\n"); 12578c2ecf20Sopenharmony_ci return -ENOSYS; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (entries < 1 || 12618c2ecf20Sopenharmony_ci entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz))) { 12628c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "wrong entries number %d, max %d\n", 12638c2ecf20Sopenharmony_ci entries, 12648c2ecf20Sopenharmony_ci 1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)); 12658c2ecf20Sopenharmony_ci return -EINVAL; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci entries = roundup_pow_of_two(entries + 1); 12698c2ecf20Sopenharmony_ci if (entries > (1 << MLX5_CAP_GEN(dev->mdev, log_max_cq_sz)) + 1) 12708c2ecf20Sopenharmony_ci return -EINVAL; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (entries == ibcq->cqe + 1) 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci mutex_lock(&cq->resize_mutex); 12768c2ecf20Sopenharmony_ci if (udata) { 12778c2ecf20Sopenharmony_ci err = resize_user(dev, cq, entries, udata, &npas, &page_shift, 12788c2ecf20Sopenharmony_ci &cqe_size); 12798c2ecf20Sopenharmony_ci } else { 12808c2ecf20Sopenharmony_ci cqe_size = 64; 12818c2ecf20Sopenharmony_ci err = resize_kernel(dev, cq, entries, cqe_size); 12828c2ecf20Sopenharmony_ci if (!err) { 12838c2ecf20Sopenharmony_ci struct mlx5_frag_buf *frag_buf = &cq->resize_buf->frag_buf; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci npas = frag_buf->npages; 12868c2ecf20Sopenharmony_ci page_shift = frag_buf->page_shift; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (err) 12918c2ecf20Sopenharmony_ci goto ex; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_cq_in) + 12948c2ecf20Sopenharmony_ci MLX5_FLD_SZ_BYTES(modify_cq_in, pas[0]) * npas; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 12978c2ecf20Sopenharmony_ci if (!in) { 12988c2ecf20Sopenharmony_ci err = -ENOMEM; 12998c2ecf20Sopenharmony_ci goto ex_resize; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(modify_cq_in, in, pas); 13038c2ecf20Sopenharmony_ci if (udata) 13048c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, cq->resize_umem, page_shift, 13058c2ecf20Sopenharmony_ci pas, 0); 13068c2ecf20Sopenharmony_ci else 13078c2ecf20Sopenharmony_ci mlx5_fill_page_frag_array(&cq->resize_buf->frag_buf, pas); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci MLX5_SET(modify_cq_in, in, 13108c2ecf20Sopenharmony_ci modify_field_select_resize_field_select.resize_field_select.resize_field_select, 13118c2ecf20Sopenharmony_ci MLX5_MODIFY_CQ_MASK_LOG_SIZE | 13128c2ecf20Sopenharmony_ci MLX5_MODIFY_CQ_MASK_PG_OFFSET | 13138c2ecf20Sopenharmony_ci MLX5_MODIFY_CQ_MASK_PG_SIZE); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, log_page_size, 13188c2ecf20Sopenharmony_ci page_shift - MLX5_ADAPTER_PAGE_SHIFT); 13198c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, cqe_sz, 13208c2ecf20Sopenharmony_ci cqe_sz_to_mlx_sz(cqe_size, 13218c2ecf20Sopenharmony_ci cq->private_flags & 13228c2ecf20Sopenharmony_ci MLX5_IB_CQ_PR_FLAGS_CQE_128_PAD)); 13238c2ecf20Sopenharmony_ci MLX5_SET(cqc, cqc, log_cq_size, ilog2(entries)); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci MLX5_SET(modify_cq_in, in, op_mod, MLX5_CQ_OPMOD_RESIZE); 13268c2ecf20Sopenharmony_ci MLX5_SET(modify_cq_in, in, cqn, cq->mcq.cqn); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci err = mlx5_core_modify_cq(dev->mdev, &cq->mcq, in, inlen); 13298c2ecf20Sopenharmony_ci if (err) 13308c2ecf20Sopenharmony_ci goto ex_alloc; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if (udata) { 13338c2ecf20Sopenharmony_ci cq->ibcq.cqe = entries - 1; 13348c2ecf20Sopenharmony_ci ib_umem_release(cq->buf.umem); 13358c2ecf20Sopenharmony_ci cq->buf.umem = cq->resize_umem; 13368c2ecf20Sopenharmony_ci cq->resize_umem = NULL; 13378c2ecf20Sopenharmony_ci } else { 13388c2ecf20Sopenharmony_ci struct mlx5_ib_cq_buf tbuf; 13398c2ecf20Sopenharmony_ci int resized = 0; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 13428c2ecf20Sopenharmony_ci if (cq->resize_buf) { 13438c2ecf20Sopenharmony_ci err = copy_resize_cqes(cq); 13448c2ecf20Sopenharmony_ci if (!err) { 13458c2ecf20Sopenharmony_ci tbuf = cq->buf; 13468c2ecf20Sopenharmony_ci cq->buf = *cq->resize_buf; 13478c2ecf20Sopenharmony_ci kfree(cq->resize_buf); 13488c2ecf20Sopenharmony_ci cq->resize_buf = NULL; 13498c2ecf20Sopenharmony_ci resized = 1; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci cq->ibcq.cqe = entries - 1; 13538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 13548c2ecf20Sopenharmony_ci if (resized) 13558c2ecf20Sopenharmony_ci free_cq_buf(dev, &tbuf); 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci mutex_unlock(&cq->resize_mutex); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci kvfree(in); 13608c2ecf20Sopenharmony_ci return 0; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ciex_alloc: 13638c2ecf20Sopenharmony_ci kvfree(in); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ciex_resize: 13668c2ecf20Sopenharmony_ci ib_umem_release(cq->resize_umem); 13678c2ecf20Sopenharmony_ci if (!udata) { 13688c2ecf20Sopenharmony_ci free_cq_buf(dev, cq->resize_buf); 13698c2ecf20Sopenharmony_ci cq->resize_buf = NULL; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ciex: 13728c2ecf20Sopenharmony_ci mutex_unlock(&cq->resize_mutex); 13738c2ecf20Sopenharmony_ci return err; 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ciint mlx5_ib_get_cqe_size(struct ib_cq *ibcq) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!ibcq) 13818c2ecf20Sopenharmony_ci return 128; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci cq = to_mcq(ibcq); 13848c2ecf20Sopenharmony_ci return cq->cqe_size; 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci/* Called from atomic context */ 13888c2ecf20Sopenharmony_ciint mlx5_ib_generate_wc(struct ib_cq *ibcq, struct ib_wc *wc) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct mlx5_ib_wc *soft_wc; 13918c2ecf20Sopenharmony_ci struct mlx5_ib_cq *cq = to_mcq(ibcq); 13928c2ecf20Sopenharmony_ci unsigned long flags; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci soft_wc = kmalloc(sizeof(*soft_wc), GFP_ATOMIC); 13958c2ecf20Sopenharmony_ci if (!soft_wc) 13968c2ecf20Sopenharmony_ci return -ENOMEM; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci soft_wc->wc = *wc; 13998c2ecf20Sopenharmony_ci spin_lock_irqsave(&cq->lock, flags); 14008c2ecf20Sopenharmony_ci list_add_tail(&soft_wc->list, &cq->wc_list); 14018c2ecf20Sopenharmony_ci if (cq->notify_flags == IB_CQ_NEXT_COMP || 14028c2ecf20Sopenharmony_ci wc->status != IB_WC_SUCCESS) { 14038c2ecf20Sopenharmony_ci cq->notify_flags = 0; 14048c2ecf20Sopenharmony_ci schedule_work(&cq->notify_work); 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cq->lock, flags); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci return 0; 14098c2ecf20Sopenharmony_ci} 1410