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/module.h> 348c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 358c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h> 368c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 378c2ecf20Sopenharmony_ci#include <rdma/rdma_counter.h> 388c2ecf20Sopenharmony_ci#include <linux/mlx5/fs.h> 398c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 408c2ecf20Sopenharmony_ci#include "ib_rep.h" 418c2ecf20Sopenharmony_ci#include "counters.h" 428c2ecf20Sopenharmony_ci#include "cmd.h" 438c2ecf20Sopenharmony_ci#include "qp.h" 448c2ecf20Sopenharmony_ci#include "wr.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cienum { 478c2ecf20Sopenharmony_ci MLX5_IB_ACK_REQ_FREQ = 8, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cienum { 518c2ecf20Sopenharmony_ci MLX5_IB_DEFAULT_SCHED_QUEUE = 0x83, 528c2ecf20Sopenharmony_ci MLX5_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f, 538c2ecf20Sopenharmony_ci MLX5_IB_LINK_TYPE_IB = 0, 548c2ecf20Sopenharmony_ci MLX5_IB_LINK_TYPE_ETH = 1 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cienum raw_qp_set_mask_map { 588c2ecf20Sopenharmony_ci MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID = 1UL << 0, 598c2ecf20Sopenharmony_ci MLX5_RAW_QP_RATE_LIMIT = 1UL << 1, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct mlx5_modify_raw_qp_param { 638c2ecf20Sopenharmony_ci u16 operation; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci u32 set_mask; /* raw_qp_set_mask_map */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci struct mlx5_rate_limit rl; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci u8 rq_q_ctr_id; 708c2ecf20Sopenharmony_ci u16 port; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void get_cqs(enum ib_qp_type qp_type, 748c2ecf20Sopenharmony_ci struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq, 758c2ecf20Sopenharmony_ci struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int is_qp0(enum ib_qp_type qp_type) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return qp_type == IB_QPT_SMI; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int is_sqp(enum ib_qp_type qp_type) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return is_qp0(qp_type) || is_qp1(qp_type); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * mlx5_ib_read_user_wqe_common() - Copy a WQE (or part of) from user WQ 898c2ecf20Sopenharmony_ci * to kernel buffer 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * @umem: User space memory where the WQ is 928c2ecf20Sopenharmony_ci * @buffer: buffer to copy to 938c2ecf20Sopenharmony_ci * @buflen: buffer length 948c2ecf20Sopenharmony_ci * @wqe_index: index of WQE to copy from 958c2ecf20Sopenharmony_ci * @wq_offset: offset to start of WQ 968c2ecf20Sopenharmony_ci * @wq_wqe_cnt: number of WQEs in WQ 978c2ecf20Sopenharmony_ci * @wq_wqe_shift: log2 of WQE size 988c2ecf20Sopenharmony_ci * @bcnt: number of bytes to copy 998c2ecf20Sopenharmony_ci * @bytes_copied: number of bytes to copy (return value) 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * Copies from start of WQE bcnt or less bytes. 1028c2ecf20Sopenharmony_ci * Does not gurantee to copy the entire WQE. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Return: zero on success, or an error code. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_common(struct ib_umem *umem, void *buffer, 1078c2ecf20Sopenharmony_ci size_t buflen, int wqe_index, 1088c2ecf20Sopenharmony_ci int wq_offset, int wq_wqe_cnt, 1098c2ecf20Sopenharmony_ci int wq_wqe_shift, int bcnt, 1108c2ecf20Sopenharmony_ci size_t *bytes_copied) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci size_t offset = wq_offset + ((wqe_index % wq_wqe_cnt) << wq_wqe_shift); 1138c2ecf20Sopenharmony_ci size_t wq_end = wq_offset + (wq_wqe_cnt << wq_wqe_shift); 1148c2ecf20Sopenharmony_ci size_t copy_length; 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* don't copy more than requested, more than buffer length or 1188c2ecf20Sopenharmony_ci * beyond WQ end 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci copy_length = min_t(u32, buflen, wq_end - offset); 1218c2ecf20Sopenharmony_ci copy_length = min_t(u32, copy_length, bcnt); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci ret = ib_umem_copy_from(buffer, umem, offset, copy_length); 1248c2ecf20Sopenharmony_ci if (ret) 1258c2ecf20Sopenharmony_ci return ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!ret && bytes_copied) 1288c2ecf20Sopenharmony_ci *bytes_copied = copy_length; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int mlx5_ib_read_kernel_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index, 1348c2ecf20Sopenharmony_ci void *buffer, size_t buflen, size_t *bc) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct mlx5_wqe_ctrl_seg *ctrl; 1378c2ecf20Sopenharmony_ci size_t bytes_copied = 0; 1388c2ecf20Sopenharmony_ci size_t wqe_length; 1398c2ecf20Sopenharmony_ci void *p; 1408c2ecf20Sopenharmony_ci int ds; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci wqe_index = wqe_index & qp->sq.fbc.sz_m1; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* read the control segment first */ 1458c2ecf20Sopenharmony_ci p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, wqe_index); 1468c2ecf20Sopenharmony_ci ctrl = p; 1478c2ecf20Sopenharmony_ci ds = be32_to_cpu(ctrl->qpn_ds) & MLX5_WQE_CTRL_DS_MASK; 1488c2ecf20Sopenharmony_ci wqe_length = ds * MLX5_WQE_DS_UNITS; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* read rest of WQE if it spreads over more than one stride */ 1518c2ecf20Sopenharmony_ci while (bytes_copied < wqe_length) { 1528c2ecf20Sopenharmony_ci size_t copy_length = 1538c2ecf20Sopenharmony_ci min_t(size_t, buflen - bytes_copied, MLX5_SEND_WQE_BB); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!copy_length) 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci memcpy(buffer + bytes_copied, p, copy_length); 1598c2ecf20Sopenharmony_ci bytes_copied += copy_length; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci wqe_index = (wqe_index + 1) & qp->sq.fbc.sz_m1; 1628c2ecf20Sopenharmony_ci p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, wqe_index); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci *bc = bytes_copied; 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index, 1698c2ecf20Sopenharmony_ci void *buffer, size_t buflen, size_t *bc) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base = &qp->trans_qp.base; 1728c2ecf20Sopenharmony_ci struct ib_umem *umem = base->ubuffer.umem; 1738c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq = &qp->sq; 1748c2ecf20Sopenharmony_ci struct mlx5_wqe_ctrl_seg *ctrl; 1758c2ecf20Sopenharmony_ci size_t bytes_copied; 1768c2ecf20Sopenharmony_ci size_t bytes_copied2; 1778c2ecf20Sopenharmony_ci size_t wqe_length; 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci int ds; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* at first read as much as possible */ 1828c2ecf20Sopenharmony_ci ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index, 1838c2ecf20Sopenharmony_ci wq->offset, wq->wqe_cnt, 1848c2ecf20Sopenharmony_ci wq->wqe_shift, buflen, 1858c2ecf20Sopenharmony_ci &bytes_copied); 1868c2ecf20Sopenharmony_ci if (ret) 1878c2ecf20Sopenharmony_ci return ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* we need at least control segment size to proceed */ 1908c2ecf20Sopenharmony_ci if (bytes_copied < sizeof(*ctrl)) 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ctrl = buffer; 1948c2ecf20Sopenharmony_ci ds = be32_to_cpu(ctrl->qpn_ds) & MLX5_WQE_CTRL_DS_MASK; 1958c2ecf20Sopenharmony_ci wqe_length = ds * MLX5_WQE_DS_UNITS; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* if we copied enough then we are done */ 1988c2ecf20Sopenharmony_ci if (bytes_copied >= wqe_length) { 1998c2ecf20Sopenharmony_ci *bc = bytes_copied; 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* otherwise this a wrapped around wqe 2048c2ecf20Sopenharmony_ci * so read the remaining bytes starting 2058c2ecf20Sopenharmony_ci * from wqe_index 0 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci ret = mlx5_ib_read_user_wqe_common(umem, buffer + bytes_copied, 2088c2ecf20Sopenharmony_ci buflen - bytes_copied, 0, wq->offset, 2098c2ecf20Sopenharmony_ci wq->wqe_cnt, wq->wqe_shift, 2108c2ecf20Sopenharmony_ci wqe_length - bytes_copied, 2118c2ecf20Sopenharmony_ci &bytes_copied2); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (ret) 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci *bc = bytes_copied + bytes_copied2; 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index, void *buffer, 2208c2ecf20Sopenharmony_ci size_t buflen, size_t *bc) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base = &qp->trans_qp.base; 2238c2ecf20Sopenharmony_ci struct ib_umem *umem = base->ubuffer.umem; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (buflen < sizeof(struct mlx5_wqe_ctrl_seg)) 2268c2ecf20Sopenharmony_ci return -EINVAL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!umem) 2298c2ecf20Sopenharmony_ci return mlx5_ib_read_kernel_wqe_sq(qp, wqe_index, buffer, 2308c2ecf20Sopenharmony_ci buflen, bc); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return mlx5_ib_read_user_wqe_sq(qp, wqe_index, buffer, buflen, bc); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_rq(struct mlx5_ib_qp *qp, int wqe_index, 2368c2ecf20Sopenharmony_ci void *buffer, size_t buflen, size_t *bc) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base = &qp->trans_qp.base; 2398c2ecf20Sopenharmony_ci struct ib_umem *umem = base->ubuffer.umem; 2408c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq = &qp->rq; 2418c2ecf20Sopenharmony_ci size_t bytes_copied; 2428c2ecf20Sopenharmony_ci int ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index, 2458c2ecf20Sopenharmony_ci wq->offset, wq->wqe_cnt, 2468c2ecf20Sopenharmony_ci wq->wqe_shift, buflen, 2478c2ecf20Sopenharmony_ci &bytes_copied); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (ret) 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci *bc = bytes_copied; 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_rq(struct mlx5_ib_qp *qp, int wqe_index, void *buffer, 2568c2ecf20Sopenharmony_ci size_t buflen, size_t *bc) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base = &qp->trans_qp.base; 2598c2ecf20Sopenharmony_ci struct ib_umem *umem = base->ubuffer.umem; 2608c2ecf20Sopenharmony_ci struct mlx5_ib_wq *wq = &qp->rq; 2618c2ecf20Sopenharmony_ci size_t wqe_size = 1 << wq->wqe_shift; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (buflen < wqe_size) 2648c2ecf20Sopenharmony_ci return -EINVAL; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!umem) 2678c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return mlx5_ib_read_user_wqe_rq(qp, wqe_index, buffer, buflen, bc); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, 2738c2ecf20Sopenharmony_ci void *buffer, size_t buflen, size_t *bc) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct ib_umem *umem = srq->umem; 2768c2ecf20Sopenharmony_ci size_t bytes_copied; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index, 0, 2808c2ecf20Sopenharmony_ci srq->msrq.max, srq->msrq.wqe_shift, 2818c2ecf20Sopenharmony_ci buflen, &bytes_copied); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (ret) 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci *bc = bytes_copied; 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, void *buffer, 2908c2ecf20Sopenharmony_ci size_t buflen, size_t *bc) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ib_umem *umem = srq->umem; 2938c2ecf20Sopenharmony_ci size_t wqe_size = 1 << srq->msrq.wqe_shift; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (buflen < wqe_size) 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!umem) 2998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return mlx5_ib_read_user_wqe_srq(srq, wqe_index, buffer, buflen, bc); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct ib_qp *ibqp = &to_mibqp(qp)->ibqp; 3078c2ecf20Sopenharmony_ci struct ib_event event; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (type == MLX5_EVENT_TYPE_PATH_MIG) { 3108c2ecf20Sopenharmony_ci /* This event is only valid for trans_qps */ 3118c2ecf20Sopenharmony_ci to_mibqp(qp)->port = to_mibqp(qp)->trans_qp.alt_port; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ibqp->event_handler) { 3158c2ecf20Sopenharmony_ci event.device = ibqp->device; 3168c2ecf20Sopenharmony_ci event.element.qp = ibqp; 3178c2ecf20Sopenharmony_ci switch (type) { 3188c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_PATH_MIG: 3198c2ecf20Sopenharmony_ci event.event = IB_EVENT_PATH_MIG; 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_COMM_EST: 3228c2ecf20Sopenharmony_ci event.event = IB_EVENT_COMM_EST; 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_SQ_DRAINED: 3258c2ecf20Sopenharmony_ci event.event = IB_EVENT_SQ_DRAINED; 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_SRQ_LAST_WQE: 3288c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_LAST_WQE_REACHED; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: 3318c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_FATAL; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_PATH_MIG_FAILED: 3348c2ecf20Sopenharmony_ci event.event = IB_EVENT_PATH_MIG_ERR; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR: 3378c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_REQ_ERR; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR: 3408c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_ACCESS_ERR; 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn); 3448c2ecf20Sopenharmony_ci return; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci ibqp->event_handler(&event, ibqp->qp_context); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, 3528c2ecf20Sopenharmony_ci int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci int wqe_size; 3558c2ecf20Sopenharmony_ci int wq_size; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Sanity check RQ size before proceeding */ 3588c2ecf20Sopenharmony_ci if (cap->max_recv_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (!has_rq) { 3628c2ecf20Sopenharmony_ci qp->rq.max_gs = 0; 3638c2ecf20Sopenharmony_ci qp->rq.wqe_cnt = 0; 3648c2ecf20Sopenharmony_ci qp->rq.wqe_shift = 0; 3658c2ecf20Sopenharmony_ci cap->max_recv_wr = 0; 3668c2ecf20Sopenharmony_ci cap->max_recv_sge = 0; 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci int wq_sig = !!(qp->flags_en & MLX5_QP_FLAG_SIGNATURE); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (ucmd) { 3718c2ecf20Sopenharmony_ci qp->rq.wqe_cnt = ucmd->rq_wqe_count; 3728c2ecf20Sopenharmony_ci if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift)) 3738c2ecf20Sopenharmony_ci return -EINVAL; 3748c2ecf20Sopenharmony_ci qp->rq.wqe_shift = ucmd->rq_wqe_shift; 3758c2ecf20Sopenharmony_ci if ((1 << qp->rq.wqe_shift) / 3768c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg) < 3778c2ecf20Sopenharmony_ci wq_sig) 3788c2ecf20Sopenharmony_ci return -EINVAL; 3798c2ecf20Sopenharmony_ci qp->rq.max_gs = 3808c2ecf20Sopenharmony_ci (1 << qp->rq.wqe_shift) / 3818c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg) - 3828c2ecf20Sopenharmony_ci wq_sig; 3838c2ecf20Sopenharmony_ci qp->rq.max_post = qp->rq.wqe_cnt; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci wqe_size = 3868c2ecf20Sopenharmony_ci wq_sig ? sizeof(struct mlx5_wqe_signature_seg) : 3878c2ecf20Sopenharmony_ci 0; 3888c2ecf20Sopenharmony_ci wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg); 3898c2ecf20Sopenharmony_ci wqe_size = roundup_pow_of_two(wqe_size); 3908c2ecf20Sopenharmony_ci wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size; 3918c2ecf20Sopenharmony_ci wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB); 3928c2ecf20Sopenharmony_ci qp->rq.wqe_cnt = wq_size / wqe_size; 3938c2ecf20Sopenharmony_ci if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq)) { 3948c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "wqe_size %d, max %d\n", 3958c2ecf20Sopenharmony_ci wqe_size, 3968c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, 3978c2ecf20Sopenharmony_ci max_wqe_sz_rq)); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci qp->rq.wqe_shift = ilog2(wqe_size); 4018c2ecf20Sopenharmony_ci qp->rq.max_gs = 4028c2ecf20Sopenharmony_ci (1 << qp->rq.wqe_shift) / 4038c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg) - 4048c2ecf20Sopenharmony_ci wq_sig; 4058c2ecf20Sopenharmony_ci qp->rq.max_post = qp->rq.wqe_cnt; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int sq_overhead(struct ib_qp_init_attr *attr) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci int size = 0; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci switch (attr->qp_type) { 4178c2ecf20Sopenharmony_ci case IB_QPT_XRC_INI: 4188c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_xrc_seg); 4198c2ecf20Sopenharmony_ci fallthrough; 4208c2ecf20Sopenharmony_ci case IB_QPT_RC: 4218c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_ctrl_seg) + 4228c2ecf20Sopenharmony_ci max(sizeof(struct mlx5_wqe_atomic_seg) + 4238c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_raddr_seg), 4248c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_umr_ctrl_seg) + 4258c2ecf20Sopenharmony_ci sizeof(struct mlx5_mkey_seg) + 4268c2ecf20Sopenharmony_ci MLX5_IB_SQ_UMR_INLINE_THRESHOLD / 4278c2ecf20Sopenharmony_ci MLX5_IB_UMR_OCTOWORD); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci case IB_QPT_XRC_TGT: 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci case IB_QPT_UC: 4348c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_ctrl_seg) + 4358c2ecf20Sopenharmony_ci max(sizeof(struct mlx5_wqe_raddr_seg), 4368c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_umr_ctrl_seg) + 4378c2ecf20Sopenharmony_ci sizeof(struct mlx5_mkey_seg)); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci case IB_QPT_UD: 4418c2ecf20Sopenharmony_ci if (attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) 4428c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_eth_pad) + 4438c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_eth_seg); 4448c2ecf20Sopenharmony_ci fallthrough; 4458c2ecf20Sopenharmony_ci case IB_QPT_SMI: 4468c2ecf20Sopenharmony_ci case MLX5_IB_QPT_HW_GSI: 4478c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_ctrl_seg) + 4488c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_datagram_seg); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci case MLX5_IB_QPT_REG_UMR: 4528c2ecf20Sopenharmony_ci size += sizeof(struct mlx5_wqe_ctrl_seg) + 4538c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_umr_ctrl_seg) + 4548c2ecf20Sopenharmony_ci sizeof(struct mlx5_mkey_seg); 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci default: 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return size; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int calc_send_wqe(struct ib_qp_init_attr *attr) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci int inl_size = 0; 4678c2ecf20Sopenharmony_ci int size; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci size = sq_overhead(attr); 4708c2ecf20Sopenharmony_ci if (size < 0) 4718c2ecf20Sopenharmony_ci return size; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (attr->cap.max_inline_data) { 4748c2ecf20Sopenharmony_ci inl_size = size + sizeof(struct mlx5_wqe_inline_seg) + 4758c2ecf20Sopenharmony_ci attr->cap.max_inline_data; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg); 4798c2ecf20Sopenharmony_ci if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN && 4808c2ecf20Sopenharmony_ci ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE) 4818c2ecf20Sopenharmony_ci return MLX5_SIG_WQE_SIZE; 4828c2ecf20Sopenharmony_ci else 4838c2ecf20Sopenharmony_ci return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int get_send_sge(struct ib_qp_init_attr *attr, int wqe_size) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int max_sge; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (attr->qp_type == IB_QPT_RC) 4918c2ecf20Sopenharmony_ci max_sge = (min_t(int, wqe_size, 512) - 4928c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_ctrl_seg) - 4938c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_raddr_seg)) / 4948c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg); 4958c2ecf20Sopenharmony_ci else if (attr->qp_type == IB_QPT_XRC_INI) 4968c2ecf20Sopenharmony_ci max_sge = (min_t(int, wqe_size, 512) - 4978c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_ctrl_seg) - 4988c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_xrc_seg) - 4998c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_raddr_seg)) / 5008c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg); 5018c2ecf20Sopenharmony_ci else 5028c2ecf20Sopenharmony_ci max_sge = (wqe_size - sq_overhead(attr)) / 5038c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return min_t(int, max_sge, wqe_size - sq_overhead(attr) / 5068c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg)); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, 5108c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci int wqe_size; 5138c2ecf20Sopenharmony_ci int wq_size; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (!attr->cap.max_send_wr) 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci wqe_size = calc_send_wqe(attr); 5198c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size); 5208c2ecf20Sopenharmony_ci if (wqe_size < 0) 5218c2ecf20Sopenharmony_ci return wqe_size; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) { 5248c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n", 5258c2ecf20Sopenharmony_ci wqe_size, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)); 5268c2ecf20Sopenharmony_ci return -EINVAL; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci qp->max_inline_data = wqe_size - sq_overhead(attr) - 5308c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_inline_seg); 5318c2ecf20Sopenharmony_ci attr->cap.max_inline_data = qp->max_inline_data; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); 5348c2ecf20Sopenharmony_ci qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; 5358c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) { 5368c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "send queue size (%d * %d / %d -> %d) exceeds limits(%d)\n", 5378c2ecf20Sopenharmony_ci attr->cap.max_send_wr, wqe_size, MLX5_SEND_WQE_BB, 5388c2ecf20Sopenharmony_ci qp->sq.wqe_cnt, 5398c2ecf20Sopenharmony_ci 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)); 5408c2ecf20Sopenharmony_ci return -ENOMEM; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); 5438c2ecf20Sopenharmony_ci qp->sq.max_gs = get_send_sge(attr, wqe_size); 5448c2ecf20Sopenharmony_ci if (qp->sq.max_gs < attr->cap.max_send_sge) 5458c2ecf20Sopenharmony_ci return -ENOMEM; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci attr->cap.max_send_sge = qp->sq.max_gs; 5488c2ecf20Sopenharmony_ci qp->sq.max_post = wq_size / wqe_size; 5498c2ecf20Sopenharmony_ci attr->cap.max_send_wr = qp->sq.max_post; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return wq_size; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int set_user_buf_size(struct mlx5_ib_dev *dev, 5558c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 5568c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp *ucmd, 5578c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base, 5588c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci int desc_sz = 1 << qp->sq.wqe_shift; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (desc_sz > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) { 5638c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n", 5648c2ecf20Sopenharmony_ci desc_sz, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)); 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (ucmd->sq_wqe_count && !is_power_of_2(ucmd->sq_wqe_count)) { 5698c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "sq_wqe_count %d is not a power of two\n", 5708c2ecf20Sopenharmony_ci ucmd->sq_wqe_count); 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci qp->sq.wqe_cnt = ucmd->sq_wqe_count; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) { 5778c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n", 5788c2ecf20Sopenharmony_ci qp->sq.wqe_cnt, 5798c2ecf20Sopenharmony_ci 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)); 5808c2ecf20Sopenharmony_ci return -EINVAL; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (attr->qp_type == IB_QPT_RAW_PACKET || 5848c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) { 5858c2ecf20Sopenharmony_ci base->ubuffer.buf_size = qp->rq.wqe_cnt << qp->rq.wqe_shift; 5868c2ecf20Sopenharmony_ci qp->raw_packet_qp.sq.ubuffer.buf_size = qp->sq.wqe_cnt << 6; 5878c2ecf20Sopenharmony_ci } else { 5888c2ecf20Sopenharmony_ci base->ubuffer.buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + 5898c2ecf20Sopenharmony_ci (qp->sq.wqe_cnt << 6); 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int qp_has_rq(struct ib_qp_init_attr *attr) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci if (attr->qp_type == IB_QPT_XRC_INI || 5988c2ecf20Sopenharmony_ci attr->qp_type == IB_QPT_XRC_TGT || attr->srq || 5998c2ecf20Sopenharmony_ci attr->qp_type == MLX5_IB_QPT_REG_UMR || 6008c2ecf20Sopenharmony_ci !attr->cap.max_recv_wr) 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 1; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cienum { 6078c2ecf20Sopenharmony_ci /* this is the first blue flame register in the array of bfregs assigned 6088c2ecf20Sopenharmony_ci * to a processes. Since we do not use it for blue flame but rather 6098c2ecf20Sopenharmony_ci * regular 64 bit doorbells, we do not need a lock for maintaiing 6108c2ecf20Sopenharmony_ci * "odd/even" order 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci NUM_NON_BLUE_FLAME_BFREGS = 1, 6138c2ecf20Sopenharmony_ci}; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int max_bfregs(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci return get_num_static_uars(dev, bfregi) * MLX5_NON_FP_BFREGS_PER_UAR; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int num_med_bfreg(struct mlx5_ib_dev *dev, 6218c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci int n; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci n = max_bfregs(dev, bfregi) - bfregi->num_low_latency_bfregs - 6268c2ecf20Sopenharmony_ci NUM_NON_BLUE_FLAME_BFREGS; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci return n >= 0 ? n : 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic int first_med_bfreg(struct mlx5_ib_dev *dev, 6328c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci return num_med_bfreg(dev, bfregi) ? 1 : -ENOMEM; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int first_hi_bfreg(struct mlx5_ib_dev *dev, 6388c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci int med; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci med = num_med_bfreg(dev, bfregi); 6438c2ecf20Sopenharmony_ci return ++med; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int alloc_high_class_bfreg(struct mlx5_ib_dev *dev, 6478c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci int i; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci for (i = first_hi_bfreg(dev, bfregi); i < max_bfregs(dev, bfregi); i++) { 6528c2ecf20Sopenharmony_ci if (!bfregi->count[i]) { 6538c2ecf20Sopenharmony_ci bfregi->count[i]++; 6548c2ecf20Sopenharmony_ci return i; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return -ENOMEM; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int alloc_med_class_bfreg(struct mlx5_ib_dev *dev, 6628c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int minidx = first_med_bfreg(dev, bfregi); 6658c2ecf20Sopenharmony_ci int i; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (minidx < 0) 6688c2ecf20Sopenharmony_ci return minidx; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci for (i = minidx; i < first_hi_bfreg(dev, bfregi); i++) { 6718c2ecf20Sopenharmony_ci if (bfregi->count[i] < bfregi->count[minidx]) 6728c2ecf20Sopenharmony_ci minidx = i; 6738c2ecf20Sopenharmony_ci if (!bfregi->count[minidx]) 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci bfregi->count[minidx]++; 6788c2ecf20Sopenharmony_ci return minidx; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int alloc_bfreg(struct mlx5_ib_dev *dev, 6828c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci int bfregn = -ENOMEM; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (bfregi->lib_uar_dyn) 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci mutex_lock(&bfregi->lock); 6908c2ecf20Sopenharmony_ci if (bfregi->ver >= 2) { 6918c2ecf20Sopenharmony_ci bfregn = alloc_high_class_bfreg(dev, bfregi); 6928c2ecf20Sopenharmony_ci if (bfregn < 0) 6938c2ecf20Sopenharmony_ci bfregn = alloc_med_class_bfreg(dev, bfregi); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (bfregn < 0) { 6978c2ecf20Sopenharmony_ci BUILD_BUG_ON(NUM_NON_BLUE_FLAME_BFREGS != 1); 6988c2ecf20Sopenharmony_ci bfregn = 0; 6998c2ecf20Sopenharmony_ci bfregi->count[bfregn]++; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci mutex_unlock(&bfregi->lock); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return bfregn; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_civoid mlx5_ib_free_bfreg(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi, int bfregn) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci mutex_lock(&bfregi->lock); 7098c2ecf20Sopenharmony_ci bfregi->count[bfregn]--; 7108c2ecf20Sopenharmony_ci mutex_unlock(&bfregi->lock); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci switch (state) { 7168c2ecf20Sopenharmony_ci case IB_QPS_RESET: return MLX5_QP_STATE_RST; 7178c2ecf20Sopenharmony_ci case IB_QPS_INIT: return MLX5_QP_STATE_INIT; 7188c2ecf20Sopenharmony_ci case IB_QPS_RTR: return MLX5_QP_STATE_RTR; 7198c2ecf20Sopenharmony_ci case IB_QPS_RTS: return MLX5_QP_STATE_RTS; 7208c2ecf20Sopenharmony_ci case IB_QPS_SQD: return MLX5_QP_STATE_SQD; 7218c2ecf20Sopenharmony_ci case IB_QPS_SQE: return MLX5_QP_STATE_SQER; 7228c2ecf20Sopenharmony_ci case IB_QPS_ERR: return MLX5_QP_STATE_ERR; 7238c2ecf20Sopenharmony_ci default: return -1; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic int to_mlx5_st(enum ib_qp_type type) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci switch (type) { 7308c2ecf20Sopenharmony_ci case IB_QPT_RC: return MLX5_QP_ST_RC; 7318c2ecf20Sopenharmony_ci case IB_QPT_UC: return MLX5_QP_ST_UC; 7328c2ecf20Sopenharmony_ci case IB_QPT_UD: return MLX5_QP_ST_UD; 7338c2ecf20Sopenharmony_ci case MLX5_IB_QPT_REG_UMR: return MLX5_QP_ST_REG_UMR; 7348c2ecf20Sopenharmony_ci case IB_QPT_XRC_INI: 7358c2ecf20Sopenharmony_ci case IB_QPT_XRC_TGT: return MLX5_QP_ST_XRC; 7368c2ecf20Sopenharmony_ci case IB_QPT_SMI: return MLX5_QP_ST_QP0; 7378c2ecf20Sopenharmony_ci case MLX5_IB_QPT_HW_GSI: return MLX5_QP_ST_QP1; 7388c2ecf20Sopenharmony_ci case MLX5_IB_QPT_DCI: return MLX5_QP_ST_DCI; 7398c2ecf20Sopenharmony_ci case IB_QPT_RAW_PACKET: return MLX5_QP_ST_RAW_ETHERTYPE; 7408c2ecf20Sopenharmony_ci default: return -EINVAL; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, 7458c2ecf20Sopenharmony_ci struct mlx5_ib_cq *recv_cq); 7468c2ecf20Sopenharmony_cistatic void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, 7478c2ecf20Sopenharmony_ci struct mlx5_ib_cq *recv_cq); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciint bfregn_to_uar_index(struct mlx5_ib_dev *dev, 7508c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi, u32 bfregn, 7518c2ecf20Sopenharmony_ci bool dyn_bfreg) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci unsigned int bfregs_per_sys_page; 7548c2ecf20Sopenharmony_ci u32 index_of_sys_page; 7558c2ecf20Sopenharmony_ci u32 offset; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (bfregi->lib_uar_dyn) 7588c2ecf20Sopenharmony_ci return -EINVAL; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci bfregs_per_sys_page = get_uars_per_sys_page(dev, bfregi->lib_uar_4k) * 7618c2ecf20Sopenharmony_ci MLX5_NON_FP_BFREGS_PER_UAR; 7628c2ecf20Sopenharmony_ci index_of_sys_page = bfregn / bfregs_per_sys_page; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (dyn_bfreg) { 7658c2ecf20Sopenharmony_ci index_of_sys_page += bfregi->num_static_sys_pages; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (index_of_sys_page >= bfregi->num_sys_pages) 7688c2ecf20Sopenharmony_ci return -EINVAL; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (bfregn > bfregi->num_dyn_bfregs || 7718c2ecf20Sopenharmony_ci bfregi->sys_pages[index_of_sys_page] == MLX5_IB_INVALID_UAR_INDEX) { 7728c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Invalid dynamic uar index\n"); 7738c2ecf20Sopenharmony_ci return -EINVAL; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci offset = bfregn % bfregs_per_sys_page / MLX5_NON_FP_BFREGS_PER_UAR; 7788c2ecf20Sopenharmony_ci return bfregi->sys_pages[index_of_sys_page] + offset; 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int mlx5_ib_umem_get(struct mlx5_ib_dev *dev, struct ib_udata *udata, 7828c2ecf20Sopenharmony_ci unsigned long addr, size_t size, 7838c2ecf20Sopenharmony_ci struct ib_umem **umem, int *npages, int *page_shift, 7848c2ecf20Sopenharmony_ci int *ncont, u32 *offset) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci int err; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci *umem = ib_umem_get(&dev->ib_dev, addr, size, 0); 7898c2ecf20Sopenharmony_ci if (IS_ERR(*umem)) { 7908c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "umem_get failed\n"); 7918c2ecf20Sopenharmony_ci return PTR_ERR(*umem); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci mlx5_ib_cont_pages(*umem, addr, 0, npages, page_shift, ncont, NULL); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci err = mlx5_ib_get_buf_offset(addr, *page_shift, offset); 7978c2ecf20Sopenharmony_ci if (err) { 7988c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "bad offset\n"); 7998c2ecf20Sopenharmony_ci goto err_umem; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "addr 0x%lx, size %zu, npages %d, page_shift %d, ncont %d, offset %d\n", 8038c2ecf20Sopenharmony_ci addr, size, *npages, *page_shift, *ncont, *offset); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cierr_umem: 8088c2ecf20Sopenharmony_ci ib_umem_release(*umem); 8098c2ecf20Sopenharmony_ci *umem = NULL; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return err; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic void destroy_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, 8158c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq, struct ib_udata *udata) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *context = 8188c2ecf20Sopenharmony_ci rdma_udata_to_drv_context( 8198c2ecf20Sopenharmony_ci udata, 8208c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext, 8218c2ecf20Sopenharmony_ci ibucontext); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (rwq->create_flags & MLX5_IB_WQ_FLAGS_DELAY_DROP) 8248c2ecf20Sopenharmony_ci atomic_dec(&dev->delay_drop.rqs_cnt); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci mlx5_ib_db_unmap_user(context, &rwq->db); 8278c2ecf20Sopenharmony_ci ib_umem_release(rwq->umem); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, 8318c2ecf20Sopenharmony_ci struct ib_udata *udata, struct mlx5_ib_rwq *rwq, 8328c2ecf20Sopenharmony_ci struct mlx5_ib_create_wq *ucmd) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 8358c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 8368c2ecf20Sopenharmony_ci int page_shift = 0; 8378c2ecf20Sopenharmony_ci int npages; 8388c2ecf20Sopenharmony_ci u32 offset = 0; 8398c2ecf20Sopenharmony_ci int ncont = 0; 8408c2ecf20Sopenharmony_ci int err; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!ucmd->buf_addr) 8438c2ecf20Sopenharmony_ci return -EINVAL; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci rwq->umem = ib_umem_get(&dev->ib_dev, ucmd->buf_addr, rwq->buf_size, 0); 8468c2ecf20Sopenharmony_ci if (IS_ERR(rwq->umem)) { 8478c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "umem_get failed\n"); 8488c2ecf20Sopenharmony_ci err = PTR_ERR(rwq->umem); 8498c2ecf20Sopenharmony_ci return err; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, 0, &npages, &page_shift, 8538c2ecf20Sopenharmony_ci &ncont, NULL); 8548c2ecf20Sopenharmony_ci err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift, 8558c2ecf20Sopenharmony_ci &rwq->rq_page_offset); 8568c2ecf20Sopenharmony_ci if (err) { 8578c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "bad offset\n"); 8588c2ecf20Sopenharmony_ci goto err_umem; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci rwq->rq_num_pas = ncont; 8628c2ecf20Sopenharmony_ci rwq->page_shift = page_shift; 8638c2ecf20Sopenharmony_ci rwq->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT; 8648c2ecf20Sopenharmony_ci rwq->wq_sig = !!(ucmd->flags & MLX5_WQ_FLAG_SIGNATURE); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "addr 0x%llx, size %zd, npages %d, page_shift %d, ncont %d, offset %d\n", 8678c2ecf20Sopenharmony_ci (unsigned long long)ucmd->buf_addr, rwq->buf_size, 8688c2ecf20Sopenharmony_ci npages, page_shift, ncont, offset); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci err = mlx5_ib_db_map_user(ucontext, udata, ucmd->db_addr, &rwq->db); 8718c2ecf20Sopenharmony_ci if (err) { 8728c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "map failed\n"); 8738c2ecf20Sopenharmony_ci goto err_umem; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cierr_umem: 8798c2ecf20Sopenharmony_ci ib_umem_release(rwq->umem); 8808c2ecf20Sopenharmony_ci return err; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int adjust_bfregn(struct mlx5_ib_dev *dev, 8848c2ecf20Sopenharmony_ci struct mlx5_bfreg_info *bfregi, int bfregn) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci return bfregn / MLX5_NON_FP_BFREGS_PER_UAR * MLX5_BFREGS_PER_UAR + 8878c2ecf20Sopenharmony_ci bfregn % MLX5_NON_FP_BFREGS_PER_UAR; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic int _create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, 8918c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, struct ib_udata *udata, 8928c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr, u32 **in, 8938c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp_resp *resp, int *inlen, 8948c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base, 8958c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp *ucmd) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *context; 8988c2ecf20Sopenharmony_ci struct mlx5_ib_ubuffer *ubuffer = &base->ubuffer; 8998c2ecf20Sopenharmony_ci int page_shift = 0; 9008c2ecf20Sopenharmony_ci int uar_index = 0; 9018c2ecf20Sopenharmony_ci int npages; 9028c2ecf20Sopenharmony_ci u32 offset = 0; 9038c2ecf20Sopenharmony_ci int bfregn; 9048c2ecf20Sopenharmony_ci int ncont = 0; 9058c2ecf20Sopenharmony_ci __be64 *pas; 9068c2ecf20Sopenharmony_ci void *qpc; 9078c2ecf20Sopenharmony_ci int err; 9088c2ecf20Sopenharmony_ci u16 uid; 9098c2ecf20Sopenharmony_ci u32 uar_flags; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci context = rdma_udata_to_drv_context(udata, struct mlx5_ib_ucontext, 9128c2ecf20Sopenharmony_ci ibucontext); 9138c2ecf20Sopenharmony_ci uar_flags = qp->flags_en & 9148c2ecf20Sopenharmony_ci (MLX5_QP_FLAG_UAR_PAGE_INDEX | MLX5_QP_FLAG_BFREG_INDEX); 9158c2ecf20Sopenharmony_ci switch (uar_flags) { 9168c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_UAR_PAGE_INDEX: 9178c2ecf20Sopenharmony_ci uar_index = ucmd->bfreg_index; 9188c2ecf20Sopenharmony_ci bfregn = MLX5_IB_INVALID_BFREG; 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_BFREG_INDEX: 9218c2ecf20Sopenharmony_ci uar_index = bfregn_to_uar_index(dev, &context->bfregi, 9228c2ecf20Sopenharmony_ci ucmd->bfreg_index, true); 9238c2ecf20Sopenharmony_ci if (uar_index < 0) 9248c2ecf20Sopenharmony_ci return uar_index; 9258c2ecf20Sopenharmony_ci bfregn = MLX5_IB_INVALID_BFREG; 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci case 0: 9288c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL) 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci bfregn = alloc_bfreg(dev, &context->bfregi); 9318c2ecf20Sopenharmony_ci if (bfregn < 0) 9328c2ecf20Sopenharmony_ci return bfregn; 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci default: 9358c2ecf20Sopenharmony_ci return -EINVAL; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "bfregn 0x%x, uar_index 0x%x\n", bfregn, uar_index); 9398c2ecf20Sopenharmony_ci if (bfregn != MLX5_IB_INVALID_BFREG) 9408c2ecf20Sopenharmony_ci uar_index = bfregn_to_uar_index(dev, &context->bfregi, bfregn, 9418c2ecf20Sopenharmony_ci false); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci qp->rq.offset = 0; 9448c2ecf20Sopenharmony_ci qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); 9458c2ecf20Sopenharmony_ci qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci err = set_user_buf_size(dev, qp, ucmd, base, attr); 9488c2ecf20Sopenharmony_ci if (err) 9498c2ecf20Sopenharmony_ci goto err_bfreg; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (ucmd->buf_addr && ubuffer->buf_size) { 9528c2ecf20Sopenharmony_ci ubuffer->buf_addr = ucmd->buf_addr; 9538c2ecf20Sopenharmony_ci err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr, 9548c2ecf20Sopenharmony_ci ubuffer->buf_size, &ubuffer->umem, 9558c2ecf20Sopenharmony_ci &npages, &page_shift, &ncont, &offset); 9568c2ecf20Sopenharmony_ci if (err) 9578c2ecf20Sopenharmony_ci goto err_bfreg; 9588c2ecf20Sopenharmony_ci } else { 9598c2ecf20Sopenharmony_ci ubuffer->umem = NULL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + 9638c2ecf20Sopenharmony_ci MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * ncont; 9648c2ecf20Sopenharmony_ci *in = kvzalloc(*inlen, GFP_KERNEL); 9658c2ecf20Sopenharmony_ci if (!*in) { 9668c2ecf20Sopenharmony_ci err = -ENOMEM; 9678c2ecf20Sopenharmony_ci goto err_umem; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci uid = (attr->qp_type != IB_QPT_XRC_INI) ? to_mpd(pd)->uid : 0; 9718c2ecf20Sopenharmony_ci MLX5_SET(create_qp_in, *in, uid, uid); 9728c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas); 9738c2ecf20Sopenharmony_ci if (ubuffer->umem) 9748c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, ubuffer->umem, page_shift, pas, 0); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_page_size, page_shift - MLX5_ADAPTER_PAGE_SHIFT); 9798c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, page_offset, offset); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, uar_page, uar_index); 9828c2ecf20Sopenharmony_ci if (bfregn != MLX5_IB_INVALID_BFREG) 9838c2ecf20Sopenharmony_ci resp->bfreg_index = adjust_bfregn(dev, &context->bfregi, bfregn); 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci resp->bfreg_index = MLX5_IB_INVALID_BFREG; 9868c2ecf20Sopenharmony_ci qp->bfregn = bfregn; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci err = mlx5_ib_db_map_user(context, udata, ucmd->db_addr, &qp->db); 9898c2ecf20Sopenharmony_ci if (err) { 9908c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "map failed\n"); 9918c2ecf20Sopenharmony_ci goto err_free; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cierr_free: 9978c2ecf20Sopenharmony_ci kvfree(*in); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cierr_umem: 10008c2ecf20Sopenharmony_ci ib_umem_release(ubuffer->umem); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cierr_bfreg: 10038c2ecf20Sopenharmony_ci if (bfregn != MLX5_IB_INVALID_BFREG) 10048c2ecf20Sopenharmony_ci mlx5_ib_free_bfreg(dev, &context->bfregi, bfregn); 10058c2ecf20Sopenharmony_ci return err; 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic void destroy_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 10098c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base, struct ib_udata *udata) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *context = rdma_udata_to_drv_context( 10128c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (udata) { 10158c2ecf20Sopenharmony_ci /* User QP */ 10168c2ecf20Sopenharmony_ci mlx5_ib_db_unmap_user(context, &qp->db); 10178c2ecf20Sopenharmony_ci ib_umem_release(base->ubuffer.umem); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* 10208c2ecf20Sopenharmony_ci * Free only the BFREGs which are handled by the kernel. 10218c2ecf20Sopenharmony_ci * BFREGs of UARs allocated dynamically are handled by user. 10228c2ecf20Sopenharmony_ci */ 10238c2ecf20Sopenharmony_ci if (qp->bfregn != MLX5_IB_INVALID_BFREG) 10248c2ecf20Sopenharmony_ci mlx5_ib_free_bfreg(dev, &context->bfregi, qp->bfregn); 10258c2ecf20Sopenharmony_ci return; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Kernel QP */ 10298c2ecf20Sopenharmony_ci kvfree(qp->sq.wqe_head); 10308c2ecf20Sopenharmony_ci kvfree(qp->sq.w_list); 10318c2ecf20Sopenharmony_ci kvfree(qp->sq.wrid); 10328c2ecf20Sopenharmony_ci kvfree(qp->sq.wr_data); 10338c2ecf20Sopenharmony_ci kvfree(qp->rq.wrid); 10348c2ecf20Sopenharmony_ci if (qp->db.db) 10358c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &qp->db); 10368c2ecf20Sopenharmony_ci if (qp->buf.frags) 10378c2ecf20Sopenharmony_ci mlx5_frag_buf_free(dev->mdev, &qp->buf); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int _create_kernel_qp(struct mlx5_ib_dev *dev, 10418c2ecf20Sopenharmony_ci struct ib_qp_init_attr *init_attr, 10428c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, u32 **in, int *inlen, 10438c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci int uar_index; 10468c2ecf20Sopenharmony_ci void *qpc; 10478c2ecf20Sopenharmony_ci int err; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR) 10508c2ecf20Sopenharmony_ci qp->bf.bfreg = &dev->fp_bfreg; 10518c2ecf20Sopenharmony_ci else if (qp->flags & MLX5_IB_QP_CREATE_WC_TEST) 10528c2ecf20Sopenharmony_ci qp->bf.bfreg = &dev->wc_bfreg; 10538c2ecf20Sopenharmony_ci else 10548c2ecf20Sopenharmony_ci qp->bf.bfreg = &dev->bfreg; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* We need to divide by two since each register is comprised of 10578c2ecf20Sopenharmony_ci * two buffers of identical size, namely odd and even 10588c2ecf20Sopenharmony_ci */ 10598c2ecf20Sopenharmony_ci qp->bf.buf_size = (1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size)) / 2; 10608c2ecf20Sopenharmony_ci uar_index = qp->bf.bfreg->index; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci err = calc_sq_size(dev, init_attr, qp); 10638c2ecf20Sopenharmony_ci if (err < 0) { 10648c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 10658c2ecf20Sopenharmony_ci return err; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci qp->rq.offset = 0; 10698c2ecf20Sopenharmony_ci qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; 10708c2ecf20Sopenharmony_ci base->ubuffer.buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci err = mlx5_frag_buf_alloc_node(dev->mdev, base->ubuffer.buf_size, 10738c2ecf20Sopenharmony_ci &qp->buf, dev->mdev->priv.numa_node); 10748c2ecf20Sopenharmony_ci if (err) { 10758c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 10768c2ecf20Sopenharmony_ci return err; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) 10808c2ecf20Sopenharmony_ci mlx5_init_fbc(qp->buf.frags, qp->rq.wqe_shift, 10818c2ecf20Sopenharmony_ci ilog2(qp->rq.wqe_cnt), &qp->rq.fbc); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) { 10848c2ecf20Sopenharmony_ci int sq_strides_offset = (qp->sq.offset & (PAGE_SIZE - 1)) / 10858c2ecf20Sopenharmony_ci MLX5_SEND_WQE_BB; 10868c2ecf20Sopenharmony_ci mlx5_init_fbc_offset(qp->buf.frags + 10878c2ecf20Sopenharmony_ci (qp->sq.offset / PAGE_SIZE), 10888c2ecf20Sopenharmony_ci ilog2(MLX5_SEND_WQE_BB), 10898c2ecf20Sopenharmony_ci ilog2(qp->sq.wqe_cnt), 10908c2ecf20Sopenharmony_ci sq_strides_offset, &qp->sq.fbc); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci qp->sq.cur_edge = get_sq_edge(&qp->sq, 0); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci *inlen = MLX5_ST_SZ_BYTES(create_qp_in) + 10968c2ecf20Sopenharmony_ci MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * qp->buf.npages; 10978c2ecf20Sopenharmony_ci *in = kvzalloc(*inlen, GFP_KERNEL); 10988c2ecf20Sopenharmony_ci if (!*in) { 10998c2ecf20Sopenharmony_ci err = -ENOMEM; 11008c2ecf20Sopenharmony_ci goto err_buf; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc); 11048c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, uar_page, uar_index); 11058c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_page_size, qp->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Set "fast registration enabled" for all kernel QPs */ 11088c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, fre, 1); 11098c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rlky, 1); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (qp->flags & MLX5_IB_QP_CREATE_SQPN_QP1) 11128c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, deth_sqpn, 1); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci mlx5_fill_page_frag_array(&qp->buf, 11158c2ecf20Sopenharmony_ci (__be64 *)MLX5_ADDR_OF(create_qp_in, 11168c2ecf20Sopenharmony_ci *in, pas)); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci err = mlx5_db_alloc(dev->mdev, &qp->db); 11198c2ecf20Sopenharmony_ci if (err) { 11208c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 11218c2ecf20Sopenharmony_ci goto err_free; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci qp->sq.wrid = kvmalloc_array(qp->sq.wqe_cnt, 11258c2ecf20Sopenharmony_ci sizeof(*qp->sq.wrid), GFP_KERNEL); 11268c2ecf20Sopenharmony_ci qp->sq.wr_data = kvmalloc_array(qp->sq.wqe_cnt, 11278c2ecf20Sopenharmony_ci sizeof(*qp->sq.wr_data), GFP_KERNEL); 11288c2ecf20Sopenharmony_ci qp->rq.wrid = kvmalloc_array(qp->rq.wqe_cnt, 11298c2ecf20Sopenharmony_ci sizeof(*qp->rq.wrid), GFP_KERNEL); 11308c2ecf20Sopenharmony_ci qp->sq.w_list = kvmalloc_array(qp->sq.wqe_cnt, 11318c2ecf20Sopenharmony_ci sizeof(*qp->sq.w_list), GFP_KERNEL); 11328c2ecf20Sopenharmony_ci qp->sq.wqe_head = kvmalloc_array(qp->sq.wqe_cnt, 11338c2ecf20Sopenharmony_ci sizeof(*qp->sq.wqe_head), GFP_KERNEL); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid || 11368c2ecf20Sopenharmony_ci !qp->sq.w_list || !qp->sq.wqe_head) { 11378c2ecf20Sopenharmony_ci err = -ENOMEM; 11388c2ecf20Sopenharmony_ci goto err_wrid; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return 0; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cierr_wrid: 11448c2ecf20Sopenharmony_ci kvfree(qp->sq.wqe_head); 11458c2ecf20Sopenharmony_ci kvfree(qp->sq.w_list); 11468c2ecf20Sopenharmony_ci kvfree(qp->sq.wrid); 11478c2ecf20Sopenharmony_ci kvfree(qp->sq.wr_data); 11488c2ecf20Sopenharmony_ci kvfree(qp->rq.wrid); 11498c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &qp->db); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cierr_free: 11528c2ecf20Sopenharmony_ci kvfree(*in); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cierr_buf: 11558c2ecf20Sopenharmony_ci mlx5_frag_buf_free(dev->mdev, &qp->buf); 11568c2ecf20Sopenharmony_ci return err; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic u32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci if (attr->srq || (qp->type == IB_QPT_XRC_TGT) || 11628c2ecf20Sopenharmony_ci (qp->type == MLX5_IB_QPT_DCI) || (qp->type == IB_QPT_XRC_INI)) 11638c2ecf20Sopenharmony_ci return MLX5_SRQ_RQ; 11648c2ecf20Sopenharmony_ci else if (!qp->has_rq) 11658c2ecf20Sopenharmony_ci return MLX5_ZERO_LEN_RQ; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return MLX5_NON_ZERO_RQ; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev, 11718c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 11728c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, u32 tdn, 11738c2ecf20Sopenharmony_ci struct ib_pd *pd) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {}; 11768c2ecf20Sopenharmony_ci void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid); 11798c2ecf20Sopenharmony_ci MLX5_SET(tisc, tisc, transport_domain, tdn); 11808c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_SOURCE_QPN) 11818c2ecf20Sopenharmony_ci MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci return mlx5_core_create_tis(dev->mdev, in, &sq->tisn); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_tis(struct mlx5_ib_dev *dev, 11878c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, struct ib_pd *pd) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci mlx5_cmd_destroy_tis(dev->mdev, sq->tisn, to_mpd(pd)->uid); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic void destroy_flow_rule_vport_sq(struct mlx5_ib_sq *sq) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci if (sq->flow_rule) 11958c2ecf20Sopenharmony_ci mlx5_del_flow_rules(sq->flow_rule); 11968c2ecf20Sopenharmony_ci sq->flow_rule = NULL; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev, 12008c2ecf20Sopenharmony_ci struct ib_udata *udata, 12018c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, void *qpin, 12028c2ecf20Sopenharmony_ci struct ib_pd *pd) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct mlx5_ib_ubuffer *ubuffer = &sq->ubuffer; 12058c2ecf20Sopenharmony_ci __be64 *pas; 12068c2ecf20Sopenharmony_ci void *in; 12078c2ecf20Sopenharmony_ci void *sqc; 12088c2ecf20Sopenharmony_ci void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc); 12098c2ecf20Sopenharmony_ci void *wq; 12108c2ecf20Sopenharmony_ci int inlen; 12118c2ecf20Sopenharmony_ci int err; 12128c2ecf20Sopenharmony_ci int page_shift = 0; 12138c2ecf20Sopenharmony_ci int npages; 12148c2ecf20Sopenharmony_ci int ncont = 0; 12158c2ecf20Sopenharmony_ci u32 offset = 0; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr, ubuffer->buf_size, 12188c2ecf20Sopenharmony_ci &sq->ubuffer.umem, &npages, &page_shift, &ncont, 12198c2ecf20Sopenharmony_ci &offset); 12208c2ecf20Sopenharmony_ci if (err) 12218c2ecf20Sopenharmony_ci return err; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * ncont; 12248c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 12258c2ecf20Sopenharmony_ci if (!in) { 12268c2ecf20Sopenharmony_ci err = -ENOMEM; 12278c2ecf20Sopenharmony_ci goto err_umem; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci MLX5_SET(create_sq_in, in, uid, to_mpd(pd)->uid); 12318c2ecf20Sopenharmony_ci sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); 12328c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, flush_in_error_en, 1); 12338c2ecf20Sopenharmony_ci if (MLX5_CAP_ETH(dev->mdev, multi_pkt_send_wqe)) 12348c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, allow_multi_pkt_send_wqe, 1); 12358c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); 12368c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, user_index, MLX5_GET(qpc, qpc, user_index)); 12378c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, cqn, MLX5_GET(qpc, qpc, cqn_snd)); 12388c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, tis_lst_sz, 1); 12398c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, tis_num_0, sq->tisn); 12408c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads) && 12418c2ecf20Sopenharmony_ci MLX5_CAP_ETH(dev->mdev, swp)) 12428c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, allow_swp, 1); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci wq = MLX5_ADDR_OF(sqc, sqc, wq); 12458c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); 12468c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd)); 12478c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, uar_page, MLX5_GET(qpc, qpc, uar_page)); 12488c2ecf20Sopenharmony_ci MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr)); 12498c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); 12508c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_sq_size)); 12518c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_pg_sz, page_shift - MLX5_ADAPTER_PAGE_SHIFT); 12528c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, page_offset, offset); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas); 12558c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, sq->ubuffer.umem, page_shift, pas, 0); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci err = mlx5_core_create_sq_tracked(dev, in, inlen, &sq->base.mqp); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci kvfree(in); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (err) 12628c2ecf20Sopenharmony_ci goto err_umem; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci return 0; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cierr_umem: 12678c2ecf20Sopenharmony_ci ib_umem_release(sq->ubuffer.umem); 12688c2ecf20Sopenharmony_ci sq->ubuffer.umem = NULL; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return err; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_sq(struct mlx5_ib_dev *dev, 12748c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci destroy_flow_rule_vport_sq(sq); 12778c2ecf20Sopenharmony_ci mlx5_core_destroy_sq_tracked(dev, &sq->base.mqp); 12788c2ecf20Sopenharmony_ci ib_umem_release(sq->ubuffer.umem); 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic size_t get_rq_pas_size(void *qpc) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci u32 log_page_size = MLX5_GET(qpc, qpc, log_page_size) + 12; 12848c2ecf20Sopenharmony_ci u32 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride); 12858c2ecf20Sopenharmony_ci u32 log_rq_size = MLX5_GET(qpc, qpc, log_rq_size); 12868c2ecf20Sopenharmony_ci u32 page_offset = MLX5_GET(qpc, qpc, page_offset); 12878c2ecf20Sopenharmony_ci u32 po_quanta = 1 << (log_page_size - 6); 12888c2ecf20Sopenharmony_ci u32 rq_sz = 1 << (log_rq_size + 4 + log_rq_stride); 12898c2ecf20Sopenharmony_ci u32 page_size = 1 << log_page_size; 12908c2ecf20Sopenharmony_ci u32 rq_sz_po = rq_sz + (page_offset * po_quanta); 12918c2ecf20Sopenharmony_ci u32 rq_num_pas = (rq_sz_po + page_size - 1) / page_size; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return rq_num_pas * sizeof(u64); 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, 12978c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq, void *qpin, 12988c2ecf20Sopenharmony_ci size_t qpinlen, struct ib_pd *pd) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = rq->base.container_mibqp; 13018c2ecf20Sopenharmony_ci __be64 *pas; 13028c2ecf20Sopenharmony_ci __be64 *qp_pas; 13038c2ecf20Sopenharmony_ci void *in; 13048c2ecf20Sopenharmony_ci void *rqc; 13058c2ecf20Sopenharmony_ci void *wq; 13068c2ecf20Sopenharmony_ci void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc); 13078c2ecf20Sopenharmony_ci size_t rq_pas_size = get_rq_pas_size(qpc); 13088c2ecf20Sopenharmony_ci size_t inlen; 13098c2ecf20Sopenharmony_ci int err; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (qpinlen < rq_pas_size + MLX5_BYTE_OFF(create_qp_in, pas)) 13128c2ecf20Sopenharmony_ci return -EINVAL; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size; 13158c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 13168c2ecf20Sopenharmony_ci if (!in) 13178c2ecf20Sopenharmony_ci return -ENOMEM; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid); 13208c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); 13218c2ecf20Sopenharmony_ci if (!(rq->flags & MLX5_IB_RQ_CVLAN_STRIPPING)) 13228c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, vsd, 1); 13238c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, mem_rq_type, MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE); 13248c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); 13258c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, flush_in_error_en, 1); 13268c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, user_index, MLX5_GET(qpc, qpc, user_index)); 13278c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, cqn, MLX5_GET(qpc, qpc, cqn_rcv)); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (mqp->flags & IB_QP_CREATE_SCATTER_FCS) 13308c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, scatter_fcs, 1); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci wq = MLX5_ADDR_OF(rqc, rqc, wq); 13338c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); 13348c2ecf20Sopenharmony_ci if (rq->flags & MLX5_IB_RQ_PCI_WRITE_END_PADDING) 13358c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN); 13368c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, page_offset, MLX5_GET(qpc, qpc, page_offset)); 13378c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd)); 13388c2ecf20Sopenharmony_ci MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr)); 13398c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(qpc, qpc, log_rq_stride) + 4); 13408c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(qpc, qpc, log_page_size)); 13418c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_rq_size)); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas); 13448c2ecf20Sopenharmony_ci qp_pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, qpin, pas); 13458c2ecf20Sopenharmony_ci memcpy(pas, qp_pas, rq_pas_size); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci err = mlx5_core_create_rq_tracked(dev, in, inlen, &rq->base.mqp); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci kvfree(in); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci return err; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_rq(struct mlx5_ib_dev *dev, 13558c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci mlx5_core_destroy_rq_tracked(dev, &rq->base.mqp); 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev, 13618c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq, 13628c2ecf20Sopenharmony_ci u32 qp_flags_en, 13638c2ecf20Sopenharmony_ci struct ib_pd *pd) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci if (qp_flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | 13668c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) 13678c2ecf20Sopenharmony_ci mlx5_ib_disable_lb(dev, false, true); 13688c2ecf20Sopenharmony_ci mlx5_cmd_destroy_tir(dev->mdev, rq->tirn, to_mpd(pd)->uid); 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev, 13728c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq, u32 tdn, 13738c2ecf20Sopenharmony_ci u32 *qp_flags_en, struct ib_pd *pd, 13748c2ecf20Sopenharmony_ci u32 *out) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci u8 lb_flag = 0; 13778c2ecf20Sopenharmony_ci u32 *in; 13788c2ecf20Sopenharmony_ci void *tirc; 13798c2ecf20Sopenharmony_ci int inlen; 13808c2ecf20Sopenharmony_ci int err; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_tir_in); 13838c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 13848c2ecf20Sopenharmony_ci if (!in) 13858c2ecf20Sopenharmony_ci return -ENOMEM; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid); 13888c2ecf20Sopenharmony_ci tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 13898c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT); 13908c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn); 13918c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, transport_domain, tdn); 13928c2ecf20Sopenharmony_ci if (*qp_flags_en & MLX5_QP_FLAG_TUNNEL_OFFLOADS) 13938c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, tunneled_offload_en, 1); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC) 13968c2ecf20Sopenharmony_ci lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) 13998c2ecf20Sopenharmony_ci lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (dev->is_rep) { 14028c2ecf20Sopenharmony_ci lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; 14038c2ecf20Sopenharmony_ci *qp_flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, self_lb_block, lb_flag); 14078c2ecf20Sopenharmony_ci MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR); 14088c2ecf20Sopenharmony_ci err = mlx5_cmd_exec_inout(dev->mdev, create_tir, in, out); 14098c2ecf20Sopenharmony_ci rq->tirn = MLX5_GET(create_tir_out, out, tirn); 14108c2ecf20Sopenharmony_ci if (!err && MLX5_GET(tirc, tirc, self_lb_block)) { 14118c2ecf20Sopenharmony_ci err = mlx5_ib_enable_lb(dev, false, true); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (err) 14148c2ecf20Sopenharmony_ci destroy_raw_packet_qp_tir(dev, rq, 0, pd); 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci kvfree(in); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci return err; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 14228c2ecf20Sopenharmony_ci u32 *in, size_t inlen, 14238c2ecf20Sopenharmony_ci struct ib_pd *pd, 14248c2ecf20Sopenharmony_ci struct ib_udata *udata, 14258c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp_resp *resp) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; 14288c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq = &raw_packet_qp->sq; 14298c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 14308c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *mucontext = rdma_udata_to_drv_context( 14318c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 14328c2ecf20Sopenharmony_ci int err; 14338c2ecf20Sopenharmony_ci u32 tdn = mucontext->tdn; 14348c2ecf20Sopenharmony_ci u16 uid = to_mpd(pd)->uid; 14358c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_tir_out)] = {}; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (!qp->sq.wqe_cnt && !qp->rq.wqe_cnt) 14388c2ecf20Sopenharmony_ci return -EINVAL; 14398c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) { 14408c2ecf20Sopenharmony_ci err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd); 14418c2ecf20Sopenharmony_ci if (err) 14428c2ecf20Sopenharmony_ci return err; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci err = create_raw_packet_qp_sq(dev, udata, sq, in, pd); 14458c2ecf20Sopenharmony_ci if (err) 14468c2ecf20Sopenharmony_ci goto err_destroy_tis; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (uid) { 14498c2ecf20Sopenharmony_ci resp->tisn = sq->tisn; 14508c2ecf20Sopenharmony_ci resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TISN; 14518c2ecf20Sopenharmony_ci resp->sqn = sq->base.mqp.qpn; 14528c2ecf20Sopenharmony_ci resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_SQN; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci sq->base.container_mibqp = qp; 14568c2ecf20Sopenharmony_ci sq->base.mqp.event = mlx5_ib_qp_event; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) { 14608c2ecf20Sopenharmony_ci rq->base.container_mibqp = qp; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_CVLAN_STRIPPING) 14638c2ecf20Sopenharmony_ci rq->flags |= MLX5_IB_RQ_CVLAN_STRIPPING; 14648c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING) 14658c2ecf20Sopenharmony_ci rq->flags |= MLX5_IB_RQ_PCI_WRITE_END_PADDING; 14668c2ecf20Sopenharmony_ci err = create_raw_packet_qp_rq(dev, rq, in, inlen, pd); 14678c2ecf20Sopenharmony_ci if (err) 14688c2ecf20Sopenharmony_ci goto err_destroy_sq; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en, pd, 14718c2ecf20Sopenharmony_ci out); 14728c2ecf20Sopenharmony_ci if (err) 14738c2ecf20Sopenharmony_ci goto err_destroy_rq; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (uid) { 14768c2ecf20Sopenharmony_ci resp->rqn = rq->base.mqp.qpn; 14778c2ecf20Sopenharmony_ci resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_RQN; 14788c2ecf20Sopenharmony_ci resp->tirn = rq->tirn; 14798c2ecf20Sopenharmony_ci resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN; 14808c2ecf20Sopenharmony_ci if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner) || 14818c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner_v2)) { 14828c2ecf20Sopenharmony_ci resp->tir_icm_addr = MLX5_GET( 14838c2ecf20Sopenharmony_ci create_tir_out, out, icm_address_31_0); 14848c2ecf20Sopenharmony_ci resp->tir_icm_addr |= 14858c2ecf20Sopenharmony_ci (u64)MLX5_GET(create_tir_out, out, 14868c2ecf20Sopenharmony_ci icm_address_39_32) 14878c2ecf20Sopenharmony_ci << 32; 14888c2ecf20Sopenharmony_ci resp->tir_icm_addr |= 14898c2ecf20Sopenharmony_ci (u64)MLX5_GET(create_tir_out, out, 14908c2ecf20Sopenharmony_ci icm_address_63_40) 14918c2ecf20Sopenharmony_ci << 40; 14928c2ecf20Sopenharmony_ci resp->comp_mask |= 14938c2ecf20Sopenharmony_ci MLX5_IB_CREATE_QP_RESP_MASK_TIR_ICM_ADDR; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci qp->trans_qp.base.mqp.qpn = qp->sq.wqe_cnt ? sq->base.mqp.qpn : 14998c2ecf20Sopenharmony_ci rq->base.mqp.qpn; 15008c2ecf20Sopenharmony_ci return 0; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cierr_destroy_rq: 15038c2ecf20Sopenharmony_ci destroy_raw_packet_qp_rq(dev, rq); 15048c2ecf20Sopenharmony_cierr_destroy_sq: 15058c2ecf20Sopenharmony_ci if (!qp->sq.wqe_cnt) 15068c2ecf20Sopenharmony_ci return err; 15078c2ecf20Sopenharmony_ci destroy_raw_packet_qp_sq(dev, sq); 15088c2ecf20Sopenharmony_cierr_destroy_tis: 15098c2ecf20Sopenharmony_ci destroy_raw_packet_qp_tis(dev, sq, pd); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci return err; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp(struct mlx5_ib_dev *dev, 15158c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; 15188c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq = &raw_packet_qp->sq; 15198c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) { 15228c2ecf20Sopenharmony_ci destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, qp->ibqp.pd); 15238c2ecf20Sopenharmony_ci destroy_raw_packet_qp_rq(dev, rq); 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) { 15278c2ecf20Sopenharmony_ci destroy_raw_packet_qp_sq(dev, sq); 15288c2ecf20Sopenharmony_ci destroy_raw_packet_qp_tis(dev, sq, qp->ibqp.pd); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cistatic void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp, 15338c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq = &raw_packet_qp->sq; 15368c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci sq->sq = &qp->sq; 15398c2ecf20Sopenharmony_ci rq->rq = &qp->rq; 15408c2ecf20Sopenharmony_ci sq->doorbell = &qp->db; 15418c2ecf20Sopenharmony_ci rq->doorbell = &qp->db; 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_cistatic void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci if (qp->flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | 15478c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)) 15488c2ecf20Sopenharmony_ci mlx5_ib_disable_lb(dev, false, true); 15498c2ecf20Sopenharmony_ci mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, 15508c2ecf20Sopenharmony_ci to_mpd(qp->ibqp.pd)->uid); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistruct mlx5_create_qp_params { 15548c2ecf20Sopenharmony_ci struct ib_udata *udata; 15558c2ecf20Sopenharmony_ci size_t inlen; 15568c2ecf20Sopenharmony_ci size_t outlen; 15578c2ecf20Sopenharmony_ci size_t ucmd_size; 15588c2ecf20Sopenharmony_ci void *ucmd; 15598c2ecf20Sopenharmony_ci u8 is_rss_raw : 1; 15608c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr; 15618c2ecf20Sopenharmony_ci u32 uidx; 15628c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp_resp resp; 15638c2ecf20Sopenharmony_ci}; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct ib_pd *pd, 15668c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 15678c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct ib_qp_init_attr *init_attr = params->attr; 15708c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp_rss *ucmd = params->ucmd; 15718c2ecf20Sopenharmony_ci struct ib_udata *udata = params->udata; 15728c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *mucontext = rdma_udata_to_drv_context( 15738c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 15748c2ecf20Sopenharmony_ci int inlen; 15758c2ecf20Sopenharmony_ci int outlen; 15768c2ecf20Sopenharmony_ci int err; 15778c2ecf20Sopenharmony_ci u32 *in; 15788c2ecf20Sopenharmony_ci u32 *out; 15798c2ecf20Sopenharmony_ci void *tirc; 15808c2ecf20Sopenharmony_ci void *hfso; 15818c2ecf20Sopenharmony_ci u32 selected_fields = 0; 15828c2ecf20Sopenharmony_ci u32 outer_l4; 15838c2ecf20Sopenharmony_ci u32 tdn = mucontext->tdn; 15848c2ecf20Sopenharmony_ci u8 lb_flag = 0; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if (ucmd->comp_mask) { 15878c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid comp mask\n"); 15888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_INNER && 15928c2ecf20Sopenharmony_ci !(ucmd->flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS)) { 15938c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Tunnel offloads must be set for inner RSS\n"); 15948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci if (dev->is_rep) 15988c2ecf20Sopenharmony_ci qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (qp->flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC) 16018c2ecf20Sopenharmony_ci lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (qp->flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC) 16048c2ecf20Sopenharmony_ci lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_tir_in); 16078c2ecf20Sopenharmony_ci outlen = MLX5_ST_SZ_BYTES(create_tir_out); 16088c2ecf20Sopenharmony_ci in = kvzalloc(inlen + outlen, GFP_KERNEL); 16098c2ecf20Sopenharmony_ci if (!in) 16108c2ecf20Sopenharmony_ci return -ENOMEM; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci out = in + MLX5_ST_SZ_DW(create_tir_in); 16138c2ecf20Sopenharmony_ci MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid); 16148c2ecf20Sopenharmony_ci tirc = MLX5_ADDR_OF(create_tir_in, in, ctx); 16158c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, disp_type, 16168c2ecf20Sopenharmony_ci MLX5_TIRC_DISP_TYPE_INDIRECT); 16178c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, indirect_table, 16188c2ecf20Sopenharmony_ci init_attr->rwq_ind_tbl->ind_tbl_num); 16198c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, transport_domain, tdn); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (ucmd->flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS) 16248c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, tunneled_offload_en, 1); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, self_lb_block, lb_flag); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_INNER) 16298c2ecf20Sopenharmony_ci hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_inner); 16308c2ecf20Sopenharmony_ci else 16318c2ecf20Sopenharmony_ci hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci switch (ucmd->rx_hash_function) { 16348c2ecf20Sopenharmony_ci case MLX5_RX_HASH_FUNC_TOEPLITZ: 16358c2ecf20Sopenharmony_ci { 16368c2ecf20Sopenharmony_ci void *rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key); 16378c2ecf20Sopenharmony_ci size_t len = MLX5_FLD_SZ_BYTES(tirc, rx_hash_toeplitz_key); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (len != ucmd->rx_key_len) { 16408c2ecf20Sopenharmony_ci err = -EINVAL; 16418c2ecf20Sopenharmony_ci goto err; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ); 16458c2ecf20Sopenharmony_ci memcpy(rss_key, ucmd->rx_hash_key, len); 16468c2ecf20Sopenharmony_ci break; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci default: 16498c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 16508c2ecf20Sopenharmony_ci goto err; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (!ucmd->rx_hash_fields_mask) { 16548c2ecf20Sopenharmony_ci /* special case when this TIR serves as steering entry without hashing */ 16558c2ecf20Sopenharmony_ci if (!init_attr->rwq_ind_tbl->log_ind_tbl_size) 16568c2ecf20Sopenharmony_ci goto create_tir; 16578c2ecf20Sopenharmony_ci err = -EINVAL; 16588c2ecf20Sopenharmony_ci goto err; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) || 16628c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4)) && 16638c2ecf20Sopenharmony_ci ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) || 16648c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))) { 16658c2ecf20Sopenharmony_ci err = -EINVAL; 16668c2ecf20Sopenharmony_ci goto err; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci /* If none of IPV4 & IPV6 SRC/DST was set - this bit field is ignored */ 16708c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) || 16718c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4)) 16728c2ecf20Sopenharmony_ci MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, 16738c2ecf20Sopenharmony_ci MLX5_L3_PROT_TYPE_IPV4); 16748c2ecf20Sopenharmony_ci else if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) || 16758c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6)) 16768c2ecf20Sopenharmony_ci MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, 16778c2ecf20Sopenharmony_ci MLX5_L3_PROT_TYPE_IPV6); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci outer_l4 = ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) || 16808c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP)) 16818c2ecf20Sopenharmony_ci << 0 | 16828c2ecf20Sopenharmony_ci ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) || 16838c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP)) 16848c2ecf20Sopenharmony_ci << 1 | 16858c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_IPSEC_SPI) << 2; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci /* Check that only one l4 protocol is set */ 16888c2ecf20Sopenharmony_ci if (outer_l4 & (outer_l4 - 1)) { 16898c2ecf20Sopenharmony_ci err = -EINVAL; 16908c2ecf20Sopenharmony_ci goto err; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* If none of TCP & UDP SRC/DST was set - this bit field is ignored */ 16948c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) || 16958c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP)) 16968c2ecf20Sopenharmony_ci MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, 16978c2ecf20Sopenharmony_ci MLX5_L4_PROT_TYPE_TCP); 16988c2ecf20Sopenharmony_ci else if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) || 16998c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP)) 17008c2ecf20Sopenharmony_ci MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, 17018c2ecf20Sopenharmony_ci MLX5_L4_PROT_TYPE_UDP); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) || 17048c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6)) 17058c2ecf20Sopenharmony_ci selected_fields |= MLX5_HASH_FIELD_SEL_SRC_IP; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4) || 17088c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6)) 17098c2ecf20Sopenharmony_ci selected_fields |= MLX5_HASH_FIELD_SEL_DST_IP; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) || 17128c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP)) 17138c2ecf20Sopenharmony_ci selected_fields |= MLX5_HASH_FIELD_SEL_L4_SPORT; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP) || 17168c2ecf20Sopenharmony_ci (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP)) 17178c2ecf20Sopenharmony_ci selected_fields |= MLX5_HASH_FIELD_SEL_L4_DPORT; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_IPSEC_SPI) 17208c2ecf20Sopenharmony_ci selected_fields |= MLX5_HASH_FIELD_SEL_IPSEC_SPI; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_cicreate_tir: 17258c2ecf20Sopenharmony_ci MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR); 17268c2ecf20Sopenharmony_ci err = mlx5_cmd_exec_inout(dev->mdev, create_tir, in, out); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci qp->rss_qp.tirn = MLX5_GET(create_tir_out, out, tirn); 17298c2ecf20Sopenharmony_ci if (!err && MLX5_GET(tirc, tirc, self_lb_block)) { 17308c2ecf20Sopenharmony_ci err = mlx5_ib_enable_lb(dev, false, true); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci if (err) 17338c2ecf20Sopenharmony_ci mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn, 17348c2ecf20Sopenharmony_ci to_mpd(pd)->uid); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (err) 17388c2ecf20Sopenharmony_ci goto err; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (mucontext->devx_uid) { 17418c2ecf20Sopenharmony_ci params->resp.comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN; 17428c2ecf20Sopenharmony_ci params->resp.tirn = qp->rss_qp.tirn; 17438c2ecf20Sopenharmony_ci if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner) || 17448c2ecf20Sopenharmony_ci MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner_v2)) { 17458c2ecf20Sopenharmony_ci params->resp.tir_icm_addr = 17468c2ecf20Sopenharmony_ci MLX5_GET(create_tir_out, out, icm_address_31_0); 17478c2ecf20Sopenharmony_ci params->resp.tir_icm_addr |= 17488c2ecf20Sopenharmony_ci (u64)MLX5_GET(create_tir_out, out, 17498c2ecf20Sopenharmony_ci icm_address_39_32) 17508c2ecf20Sopenharmony_ci << 32; 17518c2ecf20Sopenharmony_ci params->resp.tir_icm_addr |= 17528c2ecf20Sopenharmony_ci (u64)MLX5_GET(create_tir_out, out, 17538c2ecf20Sopenharmony_ci icm_address_63_40) 17548c2ecf20Sopenharmony_ci << 40; 17558c2ecf20Sopenharmony_ci params->resp.comp_mask |= 17568c2ecf20Sopenharmony_ci MLX5_IB_CREATE_QP_RESP_MASK_TIR_ICM_ADDR; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci kvfree(in); 17618c2ecf20Sopenharmony_ci /* qpn is reserved for that QP */ 17628c2ecf20Sopenharmony_ci qp->trans_qp.base.mqp.qpn = 0; 17638c2ecf20Sopenharmony_ci qp->is_rss = true; 17648c2ecf20Sopenharmony_ci return 0; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_cierr: 17678c2ecf20Sopenharmony_ci kvfree(in); 17688c2ecf20Sopenharmony_ci return err; 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_cistatic void configure_requester_scat_cqe(struct mlx5_ib_dev *dev, 17728c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 17738c2ecf20Sopenharmony_ci struct ib_qp_init_attr *init_attr, 17748c2ecf20Sopenharmony_ci void *qpc) 17758c2ecf20Sopenharmony_ci{ 17768c2ecf20Sopenharmony_ci int scqe_sz; 17778c2ecf20Sopenharmony_ci bool allow_scat_cqe = false; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci allow_scat_cqe = qp->flags_en & MLX5_QP_FLAG_ALLOW_SCATTER_CQE; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (!allow_scat_cqe && init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) 17828c2ecf20Sopenharmony_ci return; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci scqe_sz = mlx5_ib_get_cqe_size(init_attr->send_cq); 17858c2ecf20Sopenharmony_ci if (scqe_sz == 128) { 17868c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE); 17878c2ecf20Sopenharmony_ci return; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (init_attr->qp_type != MLX5_IB_QPT_DCI || 17918c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, dc_req_scat_data_cqe)) 17928c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE); 17938c2ecf20Sopenharmony_ci} 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic int atomic_size_to_mode(int size_mask) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci /* driver does not support atomic_size > 256B 17988c2ecf20Sopenharmony_ci * and does not know how to translate bigger sizes 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_ci int supported_size_mask = size_mask & 0x1ff; 18018c2ecf20Sopenharmony_ci int log_max_size; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (!supported_size_mask) 18048c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci log_max_size = __fls(supported_size_mask); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (log_max_size > 3) 18098c2ecf20Sopenharmony_ci return log_max_size; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci return MLX5_ATOMIC_MODE_8B; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic int get_atomic_mode(struct mlx5_ib_dev *dev, 18158c2ecf20Sopenharmony_ci enum ib_qp_type qp_type) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations); 18188c2ecf20Sopenharmony_ci u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic); 18198c2ecf20Sopenharmony_ci int atomic_mode = -EOPNOTSUPP; 18208c2ecf20Sopenharmony_ci int atomic_size_mask; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (!atomic) 18238c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci if (qp_type == MLX5_IB_QPT_DCT) 18268c2ecf20Sopenharmony_ci atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc); 18278c2ecf20Sopenharmony_ci else 18288c2ecf20Sopenharmony_ci atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if ((atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP) || 18318c2ecf20Sopenharmony_ci (atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD)) 18328c2ecf20Sopenharmony_ci atomic_mode = atomic_size_to_mode(atomic_size_mask); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (atomic_mode <= 0 && 18358c2ecf20Sopenharmony_ci (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP && 18368c2ecf20Sopenharmony_ci atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD)) 18378c2ecf20Sopenharmony_ci atomic_mode = MLX5_ATOMIC_MODE_IB_COMP; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci return atomic_mode; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cistatic int create_xrc_tgt_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 18438c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr = params->attr; 18468c2ecf20Sopenharmony_ci u32 uidx = params->uidx; 18478c2ecf20Sopenharmony_ci struct mlx5_ib_resources *devr = &dev->devr; 18488c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 18498c2ecf20Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 18508c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 18518c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base; 18528c2ecf20Sopenharmony_ci unsigned long flags; 18538c2ecf20Sopenharmony_ci void *qpc; 18548c2ecf20Sopenharmony_ci u32 *in; 18558c2ecf20Sopenharmony_ci int err; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (attr->sq_sig_type == IB_SIGNAL_ALL_WR) 18588c2ecf20Sopenharmony_ci qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 18618c2ecf20Sopenharmony_ci if (!in) 18628c2ecf20Sopenharmony_ci return -ENOMEM; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, st, MLX5_QP_ST_XRC); 18678c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 18688c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pd, to_mpd(devr->p0)->pdn); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) 18718c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, block_lb_mc, 1); 18728c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL) 18738c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_master, 1); 18748c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_MANAGED_SEND) 18758c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_slave_send, 1); 18768c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_MANAGED_RECV) 18778c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_slave_receive, 1); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rq_type, MLX5_SRQ_RQ); 18808c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, no_sq, 1); 18818c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn); 18828c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_snd, to_mcq(devr->c0)->mcq.cqn); 18838c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s0)->msrq.srqn); 18848c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, to_mxrcd(attr->xrcd)->xrcdn); 18858c2ecf20Sopenharmony_ci MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* 0xffffff means we ask to work with cqe version 0 */ 18888c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1) 18898c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, user_index, uidx); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING) { 18928c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, end_padding_mode, 18938c2ecf20Sopenharmony_ci MLX5_WQ_END_PAD_MODE_ALIGN); 18948c2ecf20Sopenharmony_ci /* Special case to clean flag */ 18958c2ecf20Sopenharmony_ci qp->flags &= ~IB_QP_CREATE_PCI_WRITE_END_PADDING; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci base = &qp->trans_qp.base; 18998c2ecf20Sopenharmony_ci err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out); 19008c2ecf20Sopenharmony_ci kvfree(in); 19018c2ecf20Sopenharmony_ci if (err) 19028c2ecf20Sopenharmony_ci return err; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci base->container_mibqp = qp; 19058c2ecf20Sopenharmony_ci base->mqp.event = mlx5_ib_qp_event; 19068c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, ece_support)) 19078c2ecf20Sopenharmony_ci params->resp.ece_options = MLX5_GET(create_qp_out, out, ece); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); 19108c2ecf20Sopenharmony_ci list_add_tail(&qp->qps_list, &dev->qp_list); 19118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci qp->trans_qp.xrcdn = to_mxrcd(attr->xrcd)->xrcdn; 19148c2ecf20Sopenharmony_ci return 0; 19158c2ecf20Sopenharmony_ci} 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, 19188c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 19198c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci struct ib_qp_init_attr *init_attr = params->attr; 19228c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp *ucmd = params->ucmd; 19238c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 19248c2ecf20Sopenharmony_ci struct ib_udata *udata = params->udata; 19258c2ecf20Sopenharmony_ci u32 uidx = params->uidx; 19268c2ecf20Sopenharmony_ci struct mlx5_ib_resources *devr = &dev->devr; 19278c2ecf20Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 19288c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 19298c2ecf20Sopenharmony_ci struct mlx5_ib_cq *send_cq; 19308c2ecf20Sopenharmony_ci struct mlx5_ib_cq *recv_cq; 19318c2ecf20Sopenharmony_ci unsigned long flags; 19328c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base; 19338c2ecf20Sopenharmony_ci int mlx5_st; 19348c2ecf20Sopenharmony_ci void *qpc; 19358c2ecf20Sopenharmony_ci u32 *in; 19368c2ecf20Sopenharmony_ci int err; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci spin_lock_init(&qp->sq.lock); 19398c2ecf20Sopenharmony_ci spin_lock_init(&qp->rq.lock); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci mlx5_st = to_mlx5_st(qp->type); 19428c2ecf20Sopenharmony_ci if (mlx5_st < 0) 19438c2ecf20Sopenharmony_ci return -EINVAL; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) 19468c2ecf20Sopenharmony_ci qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_SOURCE_QPN) 19498c2ecf20Sopenharmony_ci qp->underlay_qpn = init_attr->source_qpn; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci base = (init_attr->qp_type == IB_QPT_RAW_PACKET || 19528c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) ? 19538c2ecf20Sopenharmony_ci &qp->raw_packet_qp.rq.base : 19548c2ecf20Sopenharmony_ci &qp->trans_qp.base; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci qp->has_rq = qp_has_rq(init_attr); 19578c2ecf20Sopenharmony_ci err = set_rq_size(dev, &init_attr->cap, qp->has_rq, qp, ucmd); 19588c2ecf20Sopenharmony_ci if (err) { 19598c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 19608c2ecf20Sopenharmony_ci return err; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (ucmd->rq_wqe_shift != qp->rq.wqe_shift || 19648c2ecf20Sopenharmony_ci ucmd->rq_wqe_count != qp->rq.wqe_cnt) 19658c2ecf20Sopenharmony_ci return -EINVAL; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (ucmd->sq_wqe_count > (1 << MLX5_CAP_GEN(mdev, log_max_qp_sz))) 19688c2ecf20Sopenharmony_ci return -EINVAL; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci err = _create_user_qp(dev, pd, qp, udata, init_attr, &in, ¶ms->resp, 19718c2ecf20Sopenharmony_ci &inlen, base, ucmd); 19728c2ecf20Sopenharmony_ci if (err) 19738c2ecf20Sopenharmony_ci return err; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (is_sqp(init_attr->qp_type)) 19768c2ecf20Sopenharmony_ci qp->port = init_attr->port_num; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, ece_support)) 19798c2ecf20Sopenharmony_ci MLX5_SET(create_qp_in, in, ece, ucmd->ece_options); 19808c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, st, mlx5_st); 19838c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 19848c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pd, to_mpd(pd)->pdn); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) 19878c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, wq_signature, 1); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) 19908c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, block_lb_mc, 1); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL) 19938c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_master, 1); 19948c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_MANAGED_SEND) 19958c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_slave_send, 1); 19968c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_MANAGED_RECV) 19978c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cd_slave_receive, 1); 19988c2ecf20Sopenharmony_ci if (qp->flags_en & MLX5_QP_FLAG_PACKET_BASED_CREDIT_MODE) 19998c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, req_e2e_credit_mode, 1); 20008c2ecf20Sopenharmony_ci if ((qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) && 20018c2ecf20Sopenharmony_ci (init_attr->qp_type == IB_QPT_RC || 20028c2ecf20Sopenharmony_ci init_attr->qp_type == IB_QPT_UC)) { 20038c2ecf20Sopenharmony_ci int rcqe_sz = mlx5_ib_get_cqe_size(init_attr->recv_cq); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cs_res, 20068c2ecf20Sopenharmony_ci rcqe_sz == 128 ? MLX5_RES_SCAT_DATA64_CQE : 20078c2ecf20Sopenharmony_ci MLX5_RES_SCAT_DATA32_CQE); 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci if ((qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) && 20108c2ecf20Sopenharmony_ci (qp->type == MLX5_IB_QPT_DCI || qp->type == IB_QPT_RC)) 20118c2ecf20Sopenharmony_ci configure_requester_scat_cqe(dev, qp, init_attr, qpc); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) { 20148c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_rq_stride, qp->rq.wqe_shift - 4); 20158c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_rq_size, ilog2(qp->rq.wqe_cnt)); 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rq_type, get_rx_type(qp, init_attr)); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) { 20218c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_sq_size, ilog2(qp->sq.wqe_cnt)); 20228c2ecf20Sopenharmony_ci } else { 20238c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, no_sq, 1); 20248c2ecf20Sopenharmony_ci if (init_attr->srq && 20258c2ecf20Sopenharmony_ci init_attr->srq->srq_type == IB_SRQT_TM) 20268c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, offload_type, 20278c2ecf20Sopenharmony_ci MLX5_QPC_OFFLOAD_TYPE_RNDV); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci /* Set default resources */ 20318c2ecf20Sopenharmony_ci switch (init_attr->qp_type) { 20328c2ecf20Sopenharmony_ci case IB_QPT_XRC_INI: 20338c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn); 20348c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1); 20358c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s0)->msrq.srqn); 20368c2ecf20Sopenharmony_ci break; 20378c2ecf20Sopenharmony_ci default: 20388c2ecf20Sopenharmony_ci if (init_attr->srq) { 20398c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, devr->xrcdn0); 20408c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(init_attr->srq)->msrq.srqn); 20418c2ecf20Sopenharmony_ci } else { 20428c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1); 20438c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s1)->msrq.srqn); 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci if (init_attr->send_cq) 20488c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_snd, to_mcq(init_attr->send_cq)->mcq.cqn); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci if (init_attr->recv_cq) 20518c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(init_attr->recv_cq)->mcq.cqn); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* 0xffffff means we ask to work with cqe version 0 */ 20568c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1) 20578c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, user_index, uidx); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING && 20608c2ecf20Sopenharmony_ci init_attr->qp_type != IB_QPT_RAW_PACKET) { 20618c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, end_padding_mode, 20628c2ecf20Sopenharmony_ci MLX5_WQ_END_PAD_MODE_ALIGN); 20638c2ecf20Sopenharmony_ci /* Special case to clean flag */ 20648c2ecf20Sopenharmony_ci qp->flags &= ~IB_QP_CREATE_PCI_WRITE_END_PADDING; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (init_attr->qp_type == IB_QPT_RAW_PACKET || 20688c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) { 20698c2ecf20Sopenharmony_ci qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd->sq_buf_addr; 20708c2ecf20Sopenharmony_ci raw_packet_qp_copy_info(qp, &qp->raw_packet_qp); 20718c2ecf20Sopenharmony_ci err = create_raw_packet_qp(dev, qp, in, inlen, pd, udata, 20728c2ecf20Sopenharmony_ci ¶ms->resp); 20738c2ecf20Sopenharmony_ci } else 20748c2ecf20Sopenharmony_ci err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci kvfree(in); 20778c2ecf20Sopenharmony_ci if (err) 20788c2ecf20Sopenharmony_ci goto err_create; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci base->container_mibqp = qp; 20818c2ecf20Sopenharmony_ci base->mqp.event = mlx5_ib_qp_event; 20828c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, ece_support)) 20838c2ecf20Sopenharmony_ci params->resp.ece_options = MLX5_GET(create_qp_out, out, ece); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci get_cqs(qp->type, init_attr->send_cq, init_attr->recv_cq, 20868c2ecf20Sopenharmony_ci &send_cq, &recv_cq); 20878c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); 20888c2ecf20Sopenharmony_ci mlx5_ib_lock_cqs(send_cq, recv_cq); 20898c2ecf20Sopenharmony_ci /* Maintain device to QPs access, needed for further handling via reset 20908c2ecf20Sopenharmony_ci * flow 20918c2ecf20Sopenharmony_ci */ 20928c2ecf20Sopenharmony_ci list_add_tail(&qp->qps_list, &dev->qp_list); 20938c2ecf20Sopenharmony_ci /* Maintain CQ to QPs access, needed for further handling via reset flow 20948c2ecf20Sopenharmony_ci */ 20958c2ecf20Sopenharmony_ci if (send_cq) 20968c2ecf20Sopenharmony_ci list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp); 20978c2ecf20Sopenharmony_ci if (recv_cq) 20988c2ecf20Sopenharmony_ci list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp); 20998c2ecf20Sopenharmony_ci mlx5_ib_unlock_cqs(send_cq, recv_cq); 21008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci return 0; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_cierr_create: 21058c2ecf20Sopenharmony_ci destroy_qp(dev, qp, base, udata); 21068c2ecf20Sopenharmony_ci return err; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic int create_kernel_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, 21108c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 21118c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr = params->attr; 21148c2ecf20Sopenharmony_ci u32 uidx = params->uidx; 21158c2ecf20Sopenharmony_ci struct mlx5_ib_resources *devr = &dev->devr; 21168c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; 21178c2ecf20Sopenharmony_ci int inlen = MLX5_ST_SZ_BYTES(create_qp_in); 21188c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 21198c2ecf20Sopenharmony_ci struct mlx5_ib_cq *send_cq; 21208c2ecf20Sopenharmony_ci struct mlx5_ib_cq *recv_cq; 21218c2ecf20Sopenharmony_ci unsigned long flags; 21228c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base; 21238c2ecf20Sopenharmony_ci int mlx5_st; 21248c2ecf20Sopenharmony_ci void *qpc; 21258c2ecf20Sopenharmony_ci u32 *in; 21268c2ecf20Sopenharmony_ci int err; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci spin_lock_init(&qp->sq.lock); 21298c2ecf20Sopenharmony_ci spin_lock_init(&qp->rq.lock); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci mlx5_st = to_mlx5_st(qp->type); 21328c2ecf20Sopenharmony_ci if (mlx5_st < 0) 21338c2ecf20Sopenharmony_ci return -EINVAL; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if (attr->sq_sig_type == IB_SIGNAL_ALL_WR) 21368c2ecf20Sopenharmony_ci qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci base = &qp->trans_qp.base; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci qp->has_rq = qp_has_rq(attr); 21418c2ecf20Sopenharmony_ci err = set_rq_size(dev, &attr->cap, qp->has_rq, qp, NULL); 21428c2ecf20Sopenharmony_ci if (err) { 21438c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 21448c2ecf20Sopenharmony_ci return err; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci err = _create_kernel_qp(dev, attr, qp, &in, &inlen, base); 21488c2ecf20Sopenharmony_ci if (err) 21498c2ecf20Sopenharmony_ci return err; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci if (is_sqp(attr->qp_type)) 21528c2ecf20Sopenharmony_ci qp->port = attr->port_num; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, st, mlx5_st); 21578c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci if (attr->qp_type != MLX5_IB_QPT_REG_UMR) 21608c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pd, to_mpd(pd ? pd : devr->p0)->pdn); 21618c2ecf20Sopenharmony_ci else 21628c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, latency_sensitive, 1); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) 21668c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, block_lb_mc, 1); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) { 21698c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_rq_stride, qp->rq.wqe_shift - 4); 21708c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_rq_size, ilog2(qp->rq.wqe_cnt)); 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rq_type, get_rx_type(qp, attr)); 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) 21768c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_sq_size, ilog2(qp->sq.wqe_cnt)); 21778c2ecf20Sopenharmony_ci else 21788c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, no_sq, 1); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci if (attr->srq) { 21818c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, devr->xrcdn0); 21828c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, 21838c2ecf20Sopenharmony_ci to_msrq(attr->srq)->msrq.srqn); 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1); 21868c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, 21878c2ecf20Sopenharmony_ci to_msrq(devr->s1)->msrq.srqn); 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci if (attr->send_cq) 21918c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_snd, to_mcq(attr->send_cq)->mcq.cqn); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (attr->recv_cq) 21948c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(attr->recv_cq)->mcq.cqn); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci /* 0xffffff means we ask to work with cqe version 0 */ 21998c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1) 22008c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, user_index, uidx); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci /* we use IB_QP_CREATE_IPOIB_UD_LSO to indicates ipoib qp */ 22038c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) 22048c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, 1); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out); 22078c2ecf20Sopenharmony_ci kvfree(in); 22088c2ecf20Sopenharmony_ci if (err) 22098c2ecf20Sopenharmony_ci goto err_create; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci base->container_mibqp = qp; 22128c2ecf20Sopenharmony_ci base->mqp.event = mlx5_ib_qp_event; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci get_cqs(qp->type, attr->send_cq, attr->recv_cq, 22158c2ecf20Sopenharmony_ci &send_cq, &recv_cq); 22168c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); 22178c2ecf20Sopenharmony_ci mlx5_ib_lock_cqs(send_cq, recv_cq); 22188c2ecf20Sopenharmony_ci /* Maintain device to QPs access, needed for further handling via reset 22198c2ecf20Sopenharmony_ci * flow 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_ci list_add_tail(&qp->qps_list, &dev->qp_list); 22228c2ecf20Sopenharmony_ci /* Maintain CQ to QPs access, needed for further handling via reset flow 22238c2ecf20Sopenharmony_ci */ 22248c2ecf20Sopenharmony_ci if (send_cq) 22258c2ecf20Sopenharmony_ci list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp); 22268c2ecf20Sopenharmony_ci if (recv_cq) 22278c2ecf20Sopenharmony_ci list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp); 22288c2ecf20Sopenharmony_ci mlx5_ib_unlock_cqs(send_cq, recv_cq); 22298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return 0; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cierr_create: 22348c2ecf20Sopenharmony_ci destroy_qp(dev, qp, base, NULL); 22358c2ecf20Sopenharmony_ci return err; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq) 22398c2ecf20Sopenharmony_ci __acquires(&send_cq->lock) __acquires(&recv_cq->lock) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci if (send_cq) { 22428c2ecf20Sopenharmony_ci if (recv_cq) { 22438c2ecf20Sopenharmony_ci if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { 22448c2ecf20Sopenharmony_ci spin_lock(&send_cq->lock); 22458c2ecf20Sopenharmony_ci spin_lock_nested(&recv_cq->lock, 22468c2ecf20Sopenharmony_ci SINGLE_DEPTH_NESTING); 22478c2ecf20Sopenharmony_ci } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { 22488c2ecf20Sopenharmony_ci spin_lock(&send_cq->lock); 22498c2ecf20Sopenharmony_ci __acquire(&recv_cq->lock); 22508c2ecf20Sopenharmony_ci } else { 22518c2ecf20Sopenharmony_ci spin_lock(&recv_cq->lock); 22528c2ecf20Sopenharmony_ci spin_lock_nested(&send_cq->lock, 22538c2ecf20Sopenharmony_ci SINGLE_DEPTH_NESTING); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci } else { 22568c2ecf20Sopenharmony_ci spin_lock(&send_cq->lock); 22578c2ecf20Sopenharmony_ci __acquire(&recv_cq->lock); 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci } else if (recv_cq) { 22608c2ecf20Sopenharmony_ci spin_lock(&recv_cq->lock); 22618c2ecf20Sopenharmony_ci __acquire(&send_cq->lock); 22628c2ecf20Sopenharmony_ci } else { 22638c2ecf20Sopenharmony_ci __acquire(&send_cq->lock); 22648c2ecf20Sopenharmony_ci __acquire(&recv_cq->lock); 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci} 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_cistatic void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq) 22698c2ecf20Sopenharmony_ci __releases(&send_cq->lock) __releases(&recv_cq->lock) 22708c2ecf20Sopenharmony_ci{ 22718c2ecf20Sopenharmony_ci if (send_cq) { 22728c2ecf20Sopenharmony_ci if (recv_cq) { 22738c2ecf20Sopenharmony_ci if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { 22748c2ecf20Sopenharmony_ci spin_unlock(&recv_cq->lock); 22758c2ecf20Sopenharmony_ci spin_unlock(&send_cq->lock); 22768c2ecf20Sopenharmony_ci } else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) { 22778c2ecf20Sopenharmony_ci __release(&recv_cq->lock); 22788c2ecf20Sopenharmony_ci spin_unlock(&send_cq->lock); 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci spin_unlock(&send_cq->lock); 22818c2ecf20Sopenharmony_ci spin_unlock(&recv_cq->lock); 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci } else { 22848c2ecf20Sopenharmony_ci __release(&recv_cq->lock); 22858c2ecf20Sopenharmony_ci spin_unlock(&send_cq->lock); 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } else if (recv_cq) { 22888c2ecf20Sopenharmony_ci __release(&send_cq->lock); 22898c2ecf20Sopenharmony_ci spin_unlock(&recv_cq->lock); 22908c2ecf20Sopenharmony_ci } else { 22918c2ecf20Sopenharmony_ci __release(&recv_cq->lock); 22928c2ecf20Sopenharmony_ci __release(&send_cq->lock); 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic void get_cqs(enum ib_qp_type qp_type, 22978c2ecf20Sopenharmony_ci struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq, 22988c2ecf20Sopenharmony_ci struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq) 22998c2ecf20Sopenharmony_ci{ 23008c2ecf20Sopenharmony_ci switch (qp_type) { 23018c2ecf20Sopenharmony_ci case IB_QPT_XRC_TGT: 23028c2ecf20Sopenharmony_ci *send_cq = NULL; 23038c2ecf20Sopenharmony_ci *recv_cq = NULL; 23048c2ecf20Sopenharmony_ci break; 23058c2ecf20Sopenharmony_ci case MLX5_IB_QPT_REG_UMR: 23068c2ecf20Sopenharmony_ci case IB_QPT_XRC_INI: 23078c2ecf20Sopenharmony_ci *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL; 23088c2ecf20Sopenharmony_ci *recv_cq = NULL; 23098c2ecf20Sopenharmony_ci break; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci case IB_QPT_SMI: 23128c2ecf20Sopenharmony_ci case MLX5_IB_QPT_HW_GSI: 23138c2ecf20Sopenharmony_ci case IB_QPT_RC: 23148c2ecf20Sopenharmony_ci case IB_QPT_UC: 23158c2ecf20Sopenharmony_ci case IB_QPT_UD: 23168c2ecf20Sopenharmony_ci case IB_QPT_RAW_PACKET: 23178c2ecf20Sopenharmony_ci *send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL; 23188c2ecf20Sopenharmony_ci *recv_cq = ib_recv_cq ? to_mcq(ib_recv_cq) : NULL; 23198c2ecf20Sopenharmony_ci break; 23208c2ecf20Sopenharmony_ci default: 23218c2ecf20Sopenharmony_ci *send_cq = NULL; 23228c2ecf20Sopenharmony_ci *recv_cq = NULL; 23238c2ecf20Sopenharmony_ci break; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci} 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 23288c2ecf20Sopenharmony_ci const struct mlx5_modify_raw_qp_param *raw_qp_param, 23298c2ecf20Sopenharmony_ci u8 lag_tx_affinity); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_cistatic void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 23328c2ecf20Sopenharmony_ci struct ib_udata *udata) 23338c2ecf20Sopenharmony_ci{ 23348c2ecf20Sopenharmony_ci struct mlx5_ib_cq *send_cq, *recv_cq; 23358c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base; 23368c2ecf20Sopenharmony_ci unsigned long flags; 23378c2ecf20Sopenharmony_ci int err; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (qp->is_rss) { 23408c2ecf20Sopenharmony_ci destroy_rss_raw_qp_tir(dev, qp); 23418c2ecf20Sopenharmony_ci return; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci base = (qp->type == IB_QPT_RAW_PACKET || 23458c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) ? 23468c2ecf20Sopenharmony_ci &qp->raw_packet_qp.rq.base : 23478c2ecf20Sopenharmony_ci &qp->trans_qp.base; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci if (qp->state != IB_QPS_RESET) { 23508c2ecf20Sopenharmony_ci if (qp->type != IB_QPT_RAW_PACKET && 23518c2ecf20Sopenharmony_ci !(qp->flags & IB_QP_CREATE_SOURCE_QPN)) { 23528c2ecf20Sopenharmony_ci err = mlx5_core_qp_modify(dev, MLX5_CMD_OP_2RST_QP, 0, 23538c2ecf20Sopenharmony_ci NULL, &base->mqp, NULL); 23548c2ecf20Sopenharmony_ci } else { 23558c2ecf20Sopenharmony_ci struct mlx5_modify_raw_qp_param raw_qp_param = { 23568c2ecf20Sopenharmony_ci .operation = MLX5_CMD_OP_2RST_QP 23578c2ecf20Sopenharmony_ci }; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci err = modify_raw_packet_qp(dev, qp, &raw_qp_param, 0); 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci if (err) 23628c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "mlx5_ib: modify QP 0x%06x to RESET failed\n", 23638c2ecf20Sopenharmony_ci base->mqp.qpn); 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci get_cqs(qp->type, qp->ibqp.send_cq, qp->ibqp.recv_cq, &send_cq, 23678c2ecf20Sopenharmony_ci &recv_cq); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); 23708c2ecf20Sopenharmony_ci mlx5_ib_lock_cqs(send_cq, recv_cq); 23718c2ecf20Sopenharmony_ci /* del from lists under both locks above to protect reset flow paths */ 23728c2ecf20Sopenharmony_ci list_del(&qp->qps_list); 23738c2ecf20Sopenharmony_ci if (send_cq) 23748c2ecf20Sopenharmony_ci list_del(&qp->cq_send_list); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (recv_cq) 23778c2ecf20Sopenharmony_ci list_del(&qp->cq_recv_list); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (!udata) { 23808c2ecf20Sopenharmony_ci __mlx5_ib_cq_clean(recv_cq, base->mqp.qpn, 23818c2ecf20Sopenharmony_ci qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); 23828c2ecf20Sopenharmony_ci if (send_cq != recv_cq) 23838c2ecf20Sopenharmony_ci __mlx5_ib_cq_clean(send_cq, base->mqp.qpn, 23848c2ecf20Sopenharmony_ci NULL); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci mlx5_ib_unlock_cqs(send_cq, recv_cq); 23878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (qp->type == IB_QPT_RAW_PACKET || 23908c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) { 23918c2ecf20Sopenharmony_ci destroy_raw_packet_qp(dev, qp); 23928c2ecf20Sopenharmony_ci } else { 23938c2ecf20Sopenharmony_ci err = mlx5_core_destroy_qp(dev, &base->mqp); 23948c2ecf20Sopenharmony_ci if (err) 23958c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n", 23968c2ecf20Sopenharmony_ci base->mqp.qpn); 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci destroy_qp(dev, qp, base, udata); 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic int create_dct(struct mlx5_ib_dev *dev, struct ib_pd *pd, 24038c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 24048c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 24058c2ecf20Sopenharmony_ci{ 24068c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr = params->attr; 24078c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp *ucmd = params->ucmd; 24088c2ecf20Sopenharmony_ci u32 uidx = params->uidx; 24098c2ecf20Sopenharmony_ci void *dctc; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci if (mlx5_lag_is_active(dev->mdev) && !MLX5_CAP_GEN(dev->mdev, lag_dct)) 24128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci qp->dct.in = kzalloc(MLX5_ST_SZ_BYTES(create_dct_in), GFP_KERNEL); 24158c2ecf20Sopenharmony_ci if (!qp->dct.in) 24168c2ecf20Sopenharmony_ci return -ENOMEM; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci MLX5_SET(create_dct_in, qp->dct.in, uid, to_mpd(pd)->uid); 24198c2ecf20Sopenharmony_ci dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry); 24208c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, pd, to_mpd(pd)->pdn); 24218c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, srqn_xrqn, to_msrq(attr->srq)->msrq.srqn); 24228c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, cqn, to_mcq(attr->recv_cq)->mcq.cqn); 24238c2ecf20Sopenharmony_ci MLX5_SET64(dctc, dctc, dc_access_key, ucmd->access_key); 24248c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, user_index, uidx); 24258c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, ece_support)) 24268c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, ece, ucmd->ece_options); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci if (qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) { 24298c2ecf20Sopenharmony_ci int rcqe_sz = mlx5_ib_get_cqe_size(attr->recv_cq); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci if (rcqe_sz == 128) 24328c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, cs_res, MLX5_RES_SCAT_DATA64_CQE); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci qp->state = IB_QPS_RESET; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci return 0; 24388c2ecf20Sopenharmony_ci} 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_cistatic int check_qp_type(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, 24418c2ecf20Sopenharmony_ci enum ib_qp_type *type) 24428c2ecf20Sopenharmony_ci{ 24438c2ecf20Sopenharmony_ci if (attr->qp_type == IB_QPT_DRIVER && !MLX5_CAP_GEN(dev->mdev, dct)) 24448c2ecf20Sopenharmony_ci goto out; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci switch (attr->qp_type) { 24478c2ecf20Sopenharmony_ci case IB_QPT_XRC_TGT: 24488c2ecf20Sopenharmony_ci case IB_QPT_XRC_INI: 24498c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, xrc)) 24508c2ecf20Sopenharmony_ci goto out; 24518c2ecf20Sopenharmony_ci fallthrough; 24528c2ecf20Sopenharmony_ci case IB_QPT_RC: 24538c2ecf20Sopenharmony_ci case IB_QPT_UC: 24548c2ecf20Sopenharmony_ci case IB_QPT_SMI: 24558c2ecf20Sopenharmony_ci case MLX5_IB_QPT_HW_GSI: 24568c2ecf20Sopenharmony_ci case IB_QPT_DRIVER: 24578c2ecf20Sopenharmony_ci case IB_QPT_GSI: 24588c2ecf20Sopenharmony_ci case IB_QPT_RAW_PACKET: 24598c2ecf20Sopenharmony_ci case IB_QPT_UD: 24608c2ecf20Sopenharmony_ci case MLX5_IB_QPT_REG_UMR: 24618c2ecf20Sopenharmony_ci break; 24628c2ecf20Sopenharmony_ci default: 24638c2ecf20Sopenharmony_ci goto out; 24648c2ecf20Sopenharmony_ci } 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci *type = attr->qp_type; 24678c2ecf20Sopenharmony_ci return 0; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ciout: 24708c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Unsupported QP type %d\n", attr->qp_type); 24718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24728c2ecf20Sopenharmony_ci} 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_cistatic int check_valid_flow(struct mlx5_ib_dev *dev, struct ib_pd *pd, 24758c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr, 24768c2ecf20Sopenharmony_ci struct ib_udata *udata) 24778c2ecf20Sopenharmony_ci{ 24788c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 24798c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci if (!udata) { 24828c2ecf20Sopenharmony_ci /* Kernel create_qp callers */ 24838c2ecf20Sopenharmony_ci if (attr->rwq_ind_tbl) 24848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci switch (attr->qp_type) { 24878c2ecf20Sopenharmony_ci case IB_QPT_RAW_PACKET: 24888c2ecf20Sopenharmony_ci case IB_QPT_DRIVER: 24898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24908c2ecf20Sopenharmony_ci default: 24918c2ecf20Sopenharmony_ci return 0; 24928c2ecf20Sopenharmony_ci } 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci /* Userspace create_qp callers */ 24968c2ecf20Sopenharmony_ci if (attr->qp_type == IB_QPT_RAW_PACKET && !ucontext->cqe_version) { 24978c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, 24988c2ecf20Sopenharmony_ci "Raw Packet QP is only supported for CQE version > 0\n"); 24998c2ecf20Sopenharmony_ci return -EINVAL; 25008c2ecf20Sopenharmony_ci } 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci if (attr->qp_type != IB_QPT_RAW_PACKET && attr->rwq_ind_tbl) { 25038c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, 25048c2ecf20Sopenharmony_ci "Wrong QP type %d for the RWQ indirect table\n", 25058c2ecf20Sopenharmony_ci attr->qp_type); 25068c2ecf20Sopenharmony_ci return -EINVAL; 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* 25108c2ecf20Sopenharmony_ci * We don't need to see this warning, it means that kernel code 25118c2ecf20Sopenharmony_ci * missing ib_pd. Placed here to catch developer's mistakes. 25128c2ecf20Sopenharmony_ci */ 25138c2ecf20Sopenharmony_ci WARN_ONCE(!pd && attr->qp_type != IB_QPT_XRC_TGT, 25148c2ecf20Sopenharmony_ci "There is a missing PD pointer assignment\n"); 25158c2ecf20Sopenharmony_ci return 0; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cistatic void process_vendor_flag(struct mlx5_ib_dev *dev, int *flags, int flag, 25198c2ecf20Sopenharmony_ci bool cond, struct mlx5_ib_qp *qp) 25208c2ecf20Sopenharmony_ci{ 25218c2ecf20Sopenharmony_ci if (!(*flags & flag)) 25228c2ecf20Sopenharmony_ci return; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci if (cond) { 25258c2ecf20Sopenharmony_ci qp->flags_en |= flag; 25268c2ecf20Sopenharmony_ci *flags &= ~flag; 25278c2ecf20Sopenharmony_ci return; 25288c2ecf20Sopenharmony_ci } 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci switch (flag) { 25318c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_SCATTER_CQE: 25328c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_ALLOW_SCATTER_CQE: 25338c2ecf20Sopenharmony_ci /* 25348c2ecf20Sopenharmony_ci * We don't return error if these flags were provided, 25358c2ecf20Sopenharmony_ci * and mlx5 doesn't have right capability. 25368c2ecf20Sopenharmony_ci */ 25378c2ecf20Sopenharmony_ci *flags &= ~(MLX5_QP_FLAG_SCATTER_CQE | 25388c2ecf20Sopenharmony_ci MLX5_QP_FLAG_ALLOW_SCATTER_CQE); 25398c2ecf20Sopenharmony_ci return; 25408c2ecf20Sopenharmony_ci default: 25418c2ecf20Sopenharmony_ci break; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Vendor create QP flag 0x%X is not supported\n", flag); 25448c2ecf20Sopenharmony_ci} 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_cistatic int process_vendor_flags(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 25478c2ecf20Sopenharmony_ci void *ucmd, struct ib_qp_init_attr *attr) 25488c2ecf20Sopenharmony_ci{ 25498c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 25508c2ecf20Sopenharmony_ci bool cond; 25518c2ecf20Sopenharmony_ci int flags; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci if (attr->rwq_ind_tbl) 25548c2ecf20Sopenharmony_ci flags = ((struct mlx5_ib_create_qp_rss *)ucmd)->flags; 25558c2ecf20Sopenharmony_ci else 25568c2ecf20Sopenharmony_ci flags = ((struct mlx5_ib_create_qp *)ucmd)->flags; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci switch (flags & (MLX5_QP_FLAG_TYPE_DCT | MLX5_QP_FLAG_TYPE_DCI)) { 25598c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_TYPE_DCI: 25608c2ecf20Sopenharmony_ci qp->type = MLX5_IB_QPT_DCI; 25618c2ecf20Sopenharmony_ci break; 25628c2ecf20Sopenharmony_ci case MLX5_QP_FLAG_TYPE_DCT: 25638c2ecf20Sopenharmony_ci qp->type = MLX5_IB_QPT_DCT; 25648c2ecf20Sopenharmony_ci break; 25658c2ecf20Sopenharmony_ci default: 25668c2ecf20Sopenharmony_ci if (qp->type != IB_QPT_DRIVER) 25678c2ecf20Sopenharmony_ci break; 25688c2ecf20Sopenharmony_ci /* 25698c2ecf20Sopenharmony_ci * It is IB_QPT_DRIVER and or no subtype or 25708c2ecf20Sopenharmony_ci * wrong subtype were provided. 25718c2ecf20Sopenharmony_ci */ 25728c2ecf20Sopenharmony_ci return -EINVAL; 25738c2ecf20Sopenharmony_ci } 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TYPE_DCI, true, qp); 25768c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TYPE_DCT, true, qp); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_SIGNATURE, true, qp); 25798c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_SCATTER_CQE, 25808c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, sctr_data_cqe), qp); 25818c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_ALLOW_SCATTER_CQE, 25828c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, sctr_data_cqe), qp); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (qp->type == IB_QPT_RAW_PACKET) { 25858c2ecf20Sopenharmony_ci cond = MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan) || 25868c2ecf20Sopenharmony_ci MLX5_CAP_ETH(mdev, tunnel_stateless_gre) || 25878c2ecf20Sopenharmony_ci MLX5_CAP_ETH(mdev, tunnel_stateless_geneve_rx); 25888c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TUNNEL_OFFLOADS, 25898c2ecf20Sopenharmony_ci cond, qp); 25908c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, 25918c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC, true, 25928c2ecf20Sopenharmony_ci qp); 25938c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, 25948c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC, true, 25958c2ecf20Sopenharmony_ci qp); 25968c2ecf20Sopenharmony_ci } 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci if (qp->type == IB_QPT_RC) 25998c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, 26008c2ecf20Sopenharmony_ci MLX5_QP_FLAG_PACKET_BASED_CREDIT_MODE, 26018c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, qp_packet_based), qp); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_BFREG_INDEX, true, qp); 26048c2ecf20Sopenharmony_ci process_vendor_flag(dev, &flags, MLX5_QP_FLAG_UAR_PAGE_INDEX, true, qp); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci cond = qp->flags_en & ~(MLX5_QP_FLAG_TUNNEL_OFFLOADS | 26078c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC | 26088c2ecf20Sopenharmony_ci MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC); 26098c2ecf20Sopenharmony_ci if (attr->rwq_ind_tbl && cond) { 26108c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "RSS RAW QP has unsupported flags 0x%X\n", 26118c2ecf20Sopenharmony_ci cond); 26128c2ecf20Sopenharmony_ci return -EINVAL; 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci if (flags) 26168c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "udata has unsupported flags 0x%X\n", flags); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci return (flags) ? -EINVAL : 0; 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_cistatic void process_create_flag(struct mlx5_ib_dev *dev, int *flags, int flag, 26228c2ecf20Sopenharmony_ci bool cond, struct mlx5_ib_qp *qp) 26238c2ecf20Sopenharmony_ci{ 26248c2ecf20Sopenharmony_ci if (!(*flags & flag)) 26258c2ecf20Sopenharmony_ci return; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci if (cond) { 26288c2ecf20Sopenharmony_ci qp->flags |= flag; 26298c2ecf20Sopenharmony_ci *flags &= ~flag; 26308c2ecf20Sopenharmony_ci return; 26318c2ecf20Sopenharmony_ci } 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (flag == MLX5_IB_QP_CREATE_WC_TEST) { 26348c2ecf20Sopenharmony_ci /* 26358c2ecf20Sopenharmony_ci * Special case, if condition didn't meet, it won't be error, 26368c2ecf20Sopenharmony_ci * just different in-kernel flow. 26378c2ecf20Sopenharmony_ci */ 26388c2ecf20Sopenharmony_ci *flags &= ~MLX5_IB_QP_CREATE_WC_TEST; 26398c2ecf20Sopenharmony_ci return; 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Verbs create QP flag 0x%X is not supported\n", flag); 26428c2ecf20Sopenharmony_ci} 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_cistatic int process_create_flags(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 26458c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci enum ib_qp_type qp_type = qp->type; 26488c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 26498c2ecf20Sopenharmony_ci int create_flags = attr->create_flags; 26508c2ecf20Sopenharmony_ci bool cond; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci if (qp_type == MLX5_IB_QPT_DCT) 26538c2ecf20Sopenharmony_ci return (create_flags) ? -EINVAL : 0; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci if (qp_type == IB_QPT_RAW_PACKET && attr->rwq_ind_tbl) 26568c2ecf20Sopenharmony_ci return (create_flags) ? -EINVAL : 0; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, IB_QP_CREATE_NETIF_QP, 26598c2ecf20Sopenharmony_ci mlx5_get_flow_namespace(dev->mdev, 26608c2ecf20Sopenharmony_ci MLX5_FLOW_NAMESPACE_BYPASS), 26618c2ecf20Sopenharmony_ci qp); 26628c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26638c2ecf20Sopenharmony_ci IB_QP_CREATE_INTEGRITY_EN, 26648c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, sho), qp); 26658c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26668c2ecf20Sopenharmony_ci IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK, 26678c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, block_lb_mc), qp); 26688c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, IB_QP_CREATE_CROSS_CHANNEL, 26698c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, cd), qp); 26708c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, IB_QP_CREATE_MANAGED_SEND, 26718c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, cd), qp); 26728c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, IB_QP_CREATE_MANAGED_RECV, 26738c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, cd), qp); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci if (qp_type == IB_QPT_UD) { 26768c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26778c2ecf20Sopenharmony_ci IB_QP_CREATE_IPOIB_UD_LSO, 26788c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, ipoib_basic_offloads), 26798c2ecf20Sopenharmony_ci qp); 26808c2ecf20Sopenharmony_ci cond = MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_IB; 26818c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, IB_QP_CREATE_SOURCE_QPN, 26828c2ecf20Sopenharmony_ci cond, qp); 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci if (qp_type == IB_QPT_RAW_PACKET) { 26868c2ecf20Sopenharmony_ci cond = MLX5_CAP_GEN(mdev, eth_net_offloads) && 26878c2ecf20Sopenharmony_ci MLX5_CAP_ETH(mdev, scatter_fcs); 26888c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26898c2ecf20Sopenharmony_ci IB_QP_CREATE_SCATTER_FCS, cond, qp); 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci cond = MLX5_CAP_GEN(mdev, eth_net_offloads) && 26928c2ecf20Sopenharmony_ci MLX5_CAP_ETH(mdev, vlan_cap); 26938c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26948c2ecf20Sopenharmony_ci IB_QP_CREATE_CVLAN_STRIPPING, cond, qp); 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, 26988c2ecf20Sopenharmony_ci IB_QP_CREATE_PCI_WRITE_END_PADDING, 26998c2ecf20Sopenharmony_ci MLX5_CAP_GEN(mdev, end_pad), qp); 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, MLX5_IB_QP_CREATE_WC_TEST, 27028c2ecf20Sopenharmony_ci qp_type != MLX5_IB_QPT_REG_UMR, qp); 27038c2ecf20Sopenharmony_ci process_create_flag(dev, &create_flags, MLX5_IB_QP_CREATE_SQPN_QP1, 27048c2ecf20Sopenharmony_ci true, qp); 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci if (create_flags) 27078c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Create QP has unsupported flags 0x%X\n", 27088c2ecf20Sopenharmony_ci create_flags); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci return (create_flags) ? -EINVAL : 0; 27118c2ecf20Sopenharmony_ci} 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_cistatic int process_udata_size(struct mlx5_ib_dev *dev, 27148c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 27158c2ecf20Sopenharmony_ci{ 27168c2ecf20Sopenharmony_ci size_t ucmd = sizeof(struct mlx5_ib_create_qp); 27178c2ecf20Sopenharmony_ci struct ib_udata *udata = params->udata; 27188c2ecf20Sopenharmony_ci size_t outlen = udata->outlen; 27198c2ecf20Sopenharmony_ci size_t inlen = udata->inlen; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci params->outlen = min(outlen, sizeof(struct mlx5_ib_create_qp_resp)); 27228c2ecf20Sopenharmony_ci params->ucmd_size = ucmd; 27238c2ecf20Sopenharmony_ci if (!params->is_rss_raw) { 27248c2ecf20Sopenharmony_ci /* User has old rdma-core, which doesn't support ECE */ 27258c2ecf20Sopenharmony_ci size_t min_inlen = 27268c2ecf20Sopenharmony_ci offsetof(struct mlx5_ib_create_qp, ece_options); 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci /* 27298c2ecf20Sopenharmony_ci * We will check in check_ucmd_data() that user 27308c2ecf20Sopenharmony_ci * cleared everything after inlen. 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_ci params->inlen = (inlen < min_inlen) ? 0 : min(inlen, ucmd); 27338c2ecf20Sopenharmony_ci goto out; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* RSS RAW QP */ 27378c2ecf20Sopenharmony_ci if (inlen < offsetofend(struct mlx5_ib_create_qp_rss, flags)) 27388c2ecf20Sopenharmony_ci return -EINVAL; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci if (outlen < offsetofend(struct mlx5_ib_create_qp_resp, bfreg_index)) 27418c2ecf20Sopenharmony_ci return -EINVAL; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci ucmd = sizeof(struct mlx5_ib_create_qp_rss); 27448c2ecf20Sopenharmony_ci params->ucmd_size = ucmd; 27458c2ecf20Sopenharmony_ci if (inlen > ucmd && !ib_is_udata_cleared(udata, ucmd, inlen - ucmd)) 27468c2ecf20Sopenharmony_ci return -EINVAL; 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci params->inlen = min(ucmd, inlen); 27498c2ecf20Sopenharmony_ciout: 27508c2ecf20Sopenharmony_ci if (!params->inlen) 27518c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "udata is too small\n"); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci return (params->inlen) ? 0 : -EINVAL; 27548c2ecf20Sopenharmony_ci} 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_cistatic int create_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, 27578c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 27588c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci int err; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci if (params->is_rss_raw) { 27638c2ecf20Sopenharmony_ci err = create_rss_raw_qp_tir(dev, pd, qp, params); 27648c2ecf20Sopenharmony_ci goto out; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci switch (qp->type) { 27688c2ecf20Sopenharmony_ci case MLX5_IB_QPT_DCT: 27698c2ecf20Sopenharmony_ci err = create_dct(dev, pd, qp, params); 27708c2ecf20Sopenharmony_ci break; 27718c2ecf20Sopenharmony_ci case IB_QPT_XRC_TGT: 27728c2ecf20Sopenharmony_ci err = create_xrc_tgt_qp(dev, qp, params); 27738c2ecf20Sopenharmony_ci break; 27748c2ecf20Sopenharmony_ci case IB_QPT_GSI: 27758c2ecf20Sopenharmony_ci err = mlx5_ib_create_gsi(pd, qp, params->attr); 27768c2ecf20Sopenharmony_ci break; 27778c2ecf20Sopenharmony_ci default: 27788c2ecf20Sopenharmony_ci if (params->udata) 27798c2ecf20Sopenharmony_ci err = create_user_qp(dev, pd, qp, params); 27808c2ecf20Sopenharmony_ci else 27818c2ecf20Sopenharmony_ci err = create_kernel_qp(dev, pd, qp, params); 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ciout: 27858c2ecf20Sopenharmony_ci if (err) { 27868c2ecf20Sopenharmony_ci mlx5_ib_err(dev, "Create QP type %d failed\n", qp->type); 27878c2ecf20Sopenharmony_ci return err; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (is_qp0(qp->type)) 27918c2ecf20Sopenharmony_ci qp->ibqp.qp_num = 0; 27928c2ecf20Sopenharmony_ci else if (is_qp1(qp->type)) 27938c2ecf20Sopenharmony_ci qp->ibqp.qp_num = 1; 27948c2ecf20Sopenharmony_ci else 27958c2ecf20Sopenharmony_ci qp->ibqp.qp_num = qp->trans_qp.base.mqp.qpn; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, 27988c2ecf20Sopenharmony_ci "QP type %d, ib qpn 0x%X, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x, ece 0x%x\n", 27998c2ecf20Sopenharmony_ci qp->type, qp->ibqp.qp_num, qp->trans_qp.base.mqp.qpn, 28008c2ecf20Sopenharmony_ci params->attr->recv_cq ? to_mcq(params->attr->recv_cq)->mcq.cqn : 28018c2ecf20Sopenharmony_ci -1, 28028c2ecf20Sopenharmony_ci params->attr->send_cq ? to_mcq(params->attr->send_cq)->mcq.cqn : 28038c2ecf20Sopenharmony_ci -1, 28048c2ecf20Sopenharmony_ci params->resp.ece_options); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci return 0; 28078c2ecf20Sopenharmony_ci} 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_cistatic int check_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 28108c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr) 28118c2ecf20Sopenharmony_ci{ 28128c2ecf20Sopenharmony_ci int ret = 0; 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci switch (qp->type) { 28158c2ecf20Sopenharmony_ci case MLX5_IB_QPT_DCT: 28168c2ecf20Sopenharmony_ci ret = (!attr->srq || !attr->recv_cq) ? -EINVAL : 0; 28178c2ecf20Sopenharmony_ci break; 28188c2ecf20Sopenharmony_ci case MLX5_IB_QPT_DCI: 28198c2ecf20Sopenharmony_ci ret = (attr->cap.max_recv_wr || attr->cap.max_recv_sge) ? 28208c2ecf20Sopenharmony_ci -EINVAL : 28218c2ecf20Sopenharmony_ci 0; 28228c2ecf20Sopenharmony_ci break; 28238c2ecf20Sopenharmony_ci case IB_QPT_RAW_PACKET: 28248c2ecf20Sopenharmony_ci ret = (attr->rwq_ind_tbl && attr->send_cq) ? -EINVAL : 0; 28258c2ecf20Sopenharmony_ci break; 28268c2ecf20Sopenharmony_ci default: 28278c2ecf20Sopenharmony_ci break; 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (ret) 28318c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "QP type %d has wrong attributes\n", qp->type); 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci return ret; 28348c2ecf20Sopenharmony_ci} 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_cistatic int get_qp_uidx(struct mlx5_ib_qp *qp, 28378c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci struct mlx5_ib_create_qp *ucmd = params->ucmd; 28408c2ecf20Sopenharmony_ci struct ib_udata *udata = params->udata; 28418c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 28428c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci if (params->is_rss_raw) 28458c2ecf20Sopenharmony_ci return 0; 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci return get_qp_user_index(ucontext, ucmd, sizeof(*ucmd), ¶ms->uidx); 28488c2ecf20Sopenharmony_ci} 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_cistatic int mlx5_ib_destroy_dct(struct mlx5_ib_qp *mqp) 28518c2ecf20Sopenharmony_ci{ 28528c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(mqp->ibqp.device); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci if (mqp->state == IB_QPS_RTR) { 28558c2ecf20Sopenharmony_ci int err; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci err = mlx5_core_destroy_dct(dev, &mqp->dct.mdct); 28588c2ecf20Sopenharmony_ci if (err) { 28598c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "failed to destroy DCT %d\n", err); 28608c2ecf20Sopenharmony_ci return err; 28618c2ecf20Sopenharmony_ci } 28628c2ecf20Sopenharmony_ci } 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci kfree(mqp->dct.in); 28658c2ecf20Sopenharmony_ci kfree(mqp); 28668c2ecf20Sopenharmony_ci return 0; 28678c2ecf20Sopenharmony_ci} 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_cistatic int check_ucmd_data(struct mlx5_ib_dev *dev, 28708c2ecf20Sopenharmony_ci struct mlx5_create_qp_params *params) 28718c2ecf20Sopenharmony_ci{ 28728c2ecf20Sopenharmony_ci struct ib_udata *udata = params->udata; 28738c2ecf20Sopenharmony_ci size_t size, last; 28748c2ecf20Sopenharmony_ci int ret; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci if (params->is_rss_raw) 28778c2ecf20Sopenharmony_ci /* 28788c2ecf20Sopenharmony_ci * These QPs don't have "reserved" field in their 28798c2ecf20Sopenharmony_ci * create_qp input struct, so their data is always valid. 28808c2ecf20Sopenharmony_ci */ 28818c2ecf20Sopenharmony_ci last = sizeof(struct mlx5_ib_create_qp_rss); 28828c2ecf20Sopenharmony_ci else 28838c2ecf20Sopenharmony_ci last = offsetof(struct mlx5_ib_create_qp, reserved); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci if (udata->inlen <= last) 28868c2ecf20Sopenharmony_ci return 0; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci /* 28898c2ecf20Sopenharmony_ci * User provides different create_qp structures based on the 28908c2ecf20Sopenharmony_ci * flow and we need to know if he cleared memory after our 28918c2ecf20Sopenharmony_ci * struct create_qp ends. 28928c2ecf20Sopenharmony_ci */ 28938c2ecf20Sopenharmony_ci size = udata->inlen - last; 28948c2ecf20Sopenharmony_ci ret = ib_is_udata_cleared(params->udata, last, size); 28958c2ecf20Sopenharmony_ci if (!ret) 28968c2ecf20Sopenharmony_ci mlx5_ib_dbg( 28978c2ecf20Sopenharmony_ci dev, 28988c2ecf20Sopenharmony_ci "udata is not cleared, inlen = %zu, ucmd = %zu, last = %zu, size = %zu\n", 28998c2ecf20Sopenharmony_ci udata->inlen, params->ucmd_size, last, size); 29008c2ecf20Sopenharmony_ci return ret ? 0 : -EINVAL; 29018c2ecf20Sopenharmony_ci} 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_cistruct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attr, 29048c2ecf20Sopenharmony_ci struct ib_udata *udata) 29058c2ecf20Sopenharmony_ci{ 29068c2ecf20Sopenharmony_ci struct mlx5_create_qp_params params = {}; 29078c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev; 29088c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp; 29098c2ecf20Sopenharmony_ci enum ib_qp_type type; 29108c2ecf20Sopenharmony_ci int err; 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci dev = pd ? to_mdev(pd->device) : 29138c2ecf20Sopenharmony_ci to_mdev(to_mxrcd(attr->xrcd)->ibxrcd.device); 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci err = check_qp_type(dev, attr, &type); 29168c2ecf20Sopenharmony_ci if (err) 29178c2ecf20Sopenharmony_ci return ERR_PTR(err); 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci err = check_valid_flow(dev, pd, attr, udata); 29208c2ecf20Sopenharmony_ci if (err) 29218c2ecf20Sopenharmony_ci return ERR_PTR(err); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci params.udata = udata; 29248c2ecf20Sopenharmony_ci params.uidx = MLX5_IB_DEFAULT_UIDX; 29258c2ecf20Sopenharmony_ci params.attr = attr; 29268c2ecf20Sopenharmony_ci params.is_rss_raw = !!attr->rwq_ind_tbl; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci if (udata) { 29298c2ecf20Sopenharmony_ci err = process_udata_size(dev, ¶ms); 29308c2ecf20Sopenharmony_ci if (err) 29318c2ecf20Sopenharmony_ci return ERR_PTR(err); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci err = check_ucmd_data(dev, ¶ms); 29348c2ecf20Sopenharmony_ci if (err) 29358c2ecf20Sopenharmony_ci return ERR_PTR(err); 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci params.ucmd = kzalloc(params.ucmd_size, GFP_KERNEL); 29388c2ecf20Sopenharmony_ci if (!params.ucmd) 29398c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci err = ib_copy_from_udata(params.ucmd, udata, params.inlen); 29428c2ecf20Sopenharmony_ci if (err) 29438c2ecf20Sopenharmony_ci goto free_ucmd; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci qp = kzalloc(sizeof(*qp), GFP_KERNEL); 29478c2ecf20Sopenharmony_ci if (!qp) { 29488c2ecf20Sopenharmony_ci err = -ENOMEM; 29498c2ecf20Sopenharmony_ci goto free_ucmd; 29508c2ecf20Sopenharmony_ci } 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci mutex_init(&qp->mutex); 29538c2ecf20Sopenharmony_ci qp->type = type; 29548c2ecf20Sopenharmony_ci if (udata) { 29558c2ecf20Sopenharmony_ci err = process_vendor_flags(dev, qp, params.ucmd, attr); 29568c2ecf20Sopenharmony_ci if (err) 29578c2ecf20Sopenharmony_ci goto free_qp; 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci err = get_qp_uidx(qp, ¶ms); 29608c2ecf20Sopenharmony_ci if (err) 29618c2ecf20Sopenharmony_ci goto free_qp; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci err = process_create_flags(dev, qp, attr); 29648c2ecf20Sopenharmony_ci if (err) 29658c2ecf20Sopenharmony_ci goto free_qp; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci err = check_qp_attr(dev, qp, attr); 29688c2ecf20Sopenharmony_ci if (err) 29698c2ecf20Sopenharmony_ci goto free_qp; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci err = create_qp(dev, pd, qp, ¶ms); 29728c2ecf20Sopenharmony_ci if (err) 29738c2ecf20Sopenharmony_ci goto free_qp; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci kfree(params.ucmd); 29768c2ecf20Sopenharmony_ci params.ucmd = NULL; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci if (udata) 29798c2ecf20Sopenharmony_ci /* 29808c2ecf20Sopenharmony_ci * It is safe to copy response for all user create QP flows, 29818c2ecf20Sopenharmony_ci * including MLX5_IB_QPT_DCT, which doesn't need it. 29828c2ecf20Sopenharmony_ci * In that case, resp will be filled with zeros. 29838c2ecf20Sopenharmony_ci */ 29848c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, ¶ms.resp, params.outlen); 29858c2ecf20Sopenharmony_ci if (err) 29868c2ecf20Sopenharmony_ci goto destroy_qp; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci return &qp->ibqp; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_cidestroy_qp: 29918c2ecf20Sopenharmony_ci switch (qp->type) { 29928c2ecf20Sopenharmony_ci case MLX5_IB_QPT_DCT: 29938c2ecf20Sopenharmony_ci mlx5_ib_destroy_dct(qp); 29948c2ecf20Sopenharmony_ci break; 29958c2ecf20Sopenharmony_ci case IB_QPT_GSI: 29968c2ecf20Sopenharmony_ci mlx5_ib_destroy_gsi(qp); 29978c2ecf20Sopenharmony_ci break; 29988c2ecf20Sopenharmony_ci default: 29998c2ecf20Sopenharmony_ci /* 30008c2ecf20Sopenharmony_ci * These lines below are temp solution till QP allocation 30018c2ecf20Sopenharmony_ci * will be moved to be under IB/core responsiblity. 30028c2ecf20Sopenharmony_ci */ 30038c2ecf20Sopenharmony_ci qp->ibqp.send_cq = attr->send_cq; 30048c2ecf20Sopenharmony_ci qp->ibqp.recv_cq = attr->recv_cq; 30058c2ecf20Sopenharmony_ci qp->ibqp.pd = pd; 30068c2ecf20Sopenharmony_ci destroy_qp_common(dev, qp, udata); 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci qp = NULL; 30108c2ecf20Sopenharmony_cifree_qp: 30118c2ecf20Sopenharmony_ci kfree(qp); 30128c2ecf20Sopenharmony_cifree_ucmd: 30138c2ecf20Sopenharmony_ci kfree(params.ucmd); 30148c2ecf20Sopenharmony_ci return ERR_PTR(err); 30158c2ecf20Sopenharmony_ci} 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ciint mlx5_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata) 30188c2ecf20Sopenharmony_ci{ 30198c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 30208c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (unlikely(qp->qp_type == IB_QPT_GSI)) 30238c2ecf20Sopenharmony_ci return mlx5_ib_destroy_gsi(mqp); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (mqp->type == MLX5_IB_QPT_DCT) 30268c2ecf20Sopenharmony_ci return mlx5_ib_destroy_dct(mqp); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci destroy_qp_common(dev, mqp, udata); 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci kfree(mqp); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci return 0; 30338c2ecf20Sopenharmony_ci} 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_cistatic int set_qpc_atomic_flags(struct mlx5_ib_qp *qp, 30368c2ecf20Sopenharmony_ci const struct ib_qp_attr *attr, int attr_mask, 30378c2ecf20Sopenharmony_ci void *qpc) 30388c2ecf20Sopenharmony_ci{ 30398c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device); 30408c2ecf20Sopenharmony_ci u8 dest_rd_atomic; 30418c2ecf20Sopenharmony_ci u32 access_flags; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 30448c2ecf20Sopenharmony_ci dest_rd_atomic = attr->max_dest_rd_atomic; 30458c2ecf20Sopenharmony_ci else 30468c2ecf20Sopenharmony_ci dest_rd_atomic = qp->trans_qp.resp_depth; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ACCESS_FLAGS) 30498c2ecf20Sopenharmony_ci access_flags = attr->qp_access_flags; 30508c2ecf20Sopenharmony_ci else 30518c2ecf20Sopenharmony_ci access_flags = qp->trans_qp.atomic_rd_en; 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci if (!dest_rd_atomic) 30548c2ecf20Sopenharmony_ci access_flags &= IB_ACCESS_REMOTE_WRITE; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rre, !!(access_flags & IB_ACCESS_REMOTE_READ)); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci if (access_flags & IB_ACCESS_REMOTE_ATOMIC) { 30598c2ecf20Sopenharmony_ci int atomic_mode; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type); 30628c2ecf20Sopenharmony_ci if (atomic_mode < 0) 30638c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rae, 1); 30668c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, atomic_mode, atomic_mode); 30678c2ecf20Sopenharmony_ci } 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rwe, !!(access_flags & IB_ACCESS_REMOTE_WRITE)); 30708c2ecf20Sopenharmony_ci return 0; 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_cienum { 30748c2ecf20Sopenharmony_ci MLX5_PATH_FLAG_FL = 1 << 0, 30758c2ecf20Sopenharmony_ci MLX5_PATH_FLAG_FREE_AR = 1 << 1, 30768c2ecf20Sopenharmony_ci MLX5_PATH_FLAG_COUNTER = 1 << 2, 30778c2ecf20Sopenharmony_ci}; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_cistatic int mlx5_to_ib_rate_map(u8 rate) 30808c2ecf20Sopenharmony_ci{ 30818c2ecf20Sopenharmony_ci static const int rates[] = { IB_RATE_PORT_CURRENT, IB_RATE_56_GBPS, 30828c2ecf20Sopenharmony_ci IB_RATE_25_GBPS, IB_RATE_100_GBPS, 30838c2ecf20Sopenharmony_ci IB_RATE_200_GBPS, IB_RATE_50_GBPS, 30848c2ecf20Sopenharmony_ci IB_RATE_400_GBPS }; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci if (rate < ARRAY_SIZE(rates)) 30878c2ecf20Sopenharmony_ci return rates[rate]; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci return rate - MLX5_STAT_RATE_OFFSET; 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_cistatic int ib_to_mlx5_rate_map(u8 rate) 30938c2ecf20Sopenharmony_ci{ 30948c2ecf20Sopenharmony_ci switch (rate) { 30958c2ecf20Sopenharmony_ci case IB_RATE_PORT_CURRENT: 30968c2ecf20Sopenharmony_ci return 0; 30978c2ecf20Sopenharmony_ci case IB_RATE_56_GBPS: 30988c2ecf20Sopenharmony_ci return 1; 30998c2ecf20Sopenharmony_ci case IB_RATE_25_GBPS: 31008c2ecf20Sopenharmony_ci return 2; 31018c2ecf20Sopenharmony_ci case IB_RATE_100_GBPS: 31028c2ecf20Sopenharmony_ci return 3; 31038c2ecf20Sopenharmony_ci case IB_RATE_200_GBPS: 31048c2ecf20Sopenharmony_ci return 4; 31058c2ecf20Sopenharmony_ci case IB_RATE_50_GBPS: 31068c2ecf20Sopenharmony_ci return 5; 31078c2ecf20Sopenharmony_ci default: 31088c2ecf20Sopenharmony_ci return rate + MLX5_STAT_RATE_OFFSET; 31098c2ecf20Sopenharmony_ci }; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci return 0; 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate) 31158c2ecf20Sopenharmony_ci{ 31168c2ecf20Sopenharmony_ci u32 stat_rate_support; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci if (rate == IB_RATE_PORT_CURRENT) 31198c2ecf20Sopenharmony_ci return 0; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_600_GBPS) 31228c2ecf20Sopenharmony_ci return -EINVAL; 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci stat_rate_support = MLX5_CAP_GEN(dev->mdev, stat_rate_support); 31258c2ecf20Sopenharmony_ci while (rate != IB_RATE_PORT_CURRENT && 31268c2ecf20Sopenharmony_ci !(1 << ib_to_mlx5_rate_map(rate) & stat_rate_support)) 31278c2ecf20Sopenharmony_ci --rate; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci return ib_to_mlx5_rate_map(rate); 31308c2ecf20Sopenharmony_ci} 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_cistatic int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev, 31338c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, u8 sl, 31348c2ecf20Sopenharmony_ci struct ib_pd *pd) 31358c2ecf20Sopenharmony_ci{ 31368c2ecf20Sopenharmony_ci void *in; 31378c2ecf20Sopenharmony_ci void *tisc; 31388c2ecf20Sopenharmony_ci int inlen; 31398c2ecf20Sopenharmony_ci int err; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_tis_in); 31428c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 31438c2ecf20Sopenharmony_ci if (!in) 31448c2ecf20Sopenharmony_ci return -ENOMEM; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci MLX5_SET(modify_tis_in, in, bitmask.prio, 1); 31478c2ecf20Sopenharmony_ci MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid); 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx); 31508c2ecf20Sopenharmony_ci MLX5_SET(tisc, tisc, prio, ((sl & 0x7) << 1)); 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci err = mlx5_core_modify_tis(dev, sq->tisn, in); 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci kvfree(in); 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci return err; 31578c2ecf20Sopenharmony_ci} 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_cistatic int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev, 31608c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, u8 tx_affinity, 31618c2ecf20Sopenharmony_ci struct ib_pd *pd) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci void *in; 31648c2ecf20Sopenharmony_ci void *tisc; 31658c2ecf20Sopenharmony_ci int inlen; 31668c2ecf20Sopenharmony_ci int err; 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_tis_in); 31698c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 31708c2ecf20Sopenharmony_ci if (!in) 31718c2ecf20Sopenharmony_ci return -ENOMEM; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1); 31748c2ecf20Sopenharmony_ci MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx); 31778c2ecf20Sopenharmony_ci MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci err = mlx5_core_modify_tis(dev, sq->tisn, in); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci kvfree(in); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci return err; 31848c2ecf20Sopenharmony_ci} 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_cistatic void mlx5_set_path_udp_sport(void *path, const struct rdma_ah_attr *ah, 31878c2ecf20Sopenharmony_ci u32 lqpn, u32 rqpn) 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci{ 31908c2ecf20Sopenharmony_ci u32 fl = ah->grh.flow_label; 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci if (!fl) 31938c2ecf20Sopenharmony_ci fl = rdma_calc_flow_label(lqpn, rqpn); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci MLX5_SET(ads, path, udp_sport, rdma_flow_label_to_udp_sport(fl)); 31968c2ecf20Sopenharmony_ci} 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_cistatic int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 31998c2ecf20Sopenharmony_ci const struct rdma_ah_attr *ah, void *path, u8 port, 32008c2ecf20Sopenharmony_ci int attr_mask, u32 path_flags, 32018c2ecf20Sopenharmony_ci const struct ib_qp_attr *attr, bool alt) 32028c2ecf20Sopenharmony_ci{ 32038c2ecf20Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(ah); 32048c2ecf20Sopenharmony_ci int err; 32058c2ecf20Sopenharmony_ci enum ib_gid_type gid_type; 32068c2ecf20Sopenharmony_ci u8 ah_flags = rdma_ah_get_ah_flags(ah); 32078c2ecf20Sopenharmony_ci u8 sl = rdma_ah_get_sl(ah); 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 32108c2ecf20Sopenharmony_ci MLX5_SET(ads, path, pkey_index, 32118c2ecf20Sopenharmony_ci alt ? attr->alt_pkey_index : attr->pkey_index); 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (ah_flags & IB_AH_GRH) { 32148c2ecf20Sopenharmony_ci if (grh->sgid_index >= 32158c2ecf20Sopenharmony_ci dev->mdev->port_caps[port - 1].gid_table_len) { 32168c2ecf20Sopenharmony_ci pr_err("sgid_index (%u) too large. max is %d\n", 32178c2ecf20Sopenharmony_ci grh->sgid_index, 32188c2ecf20Sopenharmony_ci dev->mdev->port_caps[port - 1].gid_table_len); 32198c2ecf20Sopenharmony_ci return -EINVAL; 32208c2ecf20Sopenharmony_ci } 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci if (ah->type == RDMA_AH_ATTR_TYPE_ROCE) { 32248c2ecf20Sopenharmony_ci if (!(ah_flags & IB_AH_GRH)) 32258c2ecf20Sopenharmony_ci return -EINVAL; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci ether_addr_copy(MLX5_ADDR_OF(ads, path, rmac_47_32), 32288c2ecf20Sopenharmony_ci ah->roce.dmac); 32298c2ecf20Sopenharmony_ci if ((qp->ibqp.qp_type == IB_QPT_RC || 32308c2ecf20Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_UC || 32318c2ecf20Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_XRC_INI || 32328c2ecf20Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_XRC_TGT) && 32338c2ecf20Sopenharmony_ci (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) && 32348c2ecf20Sopenharmony_ci (attr_mask & IB_QP_DEST_QPN)) 32358c2ecf20Sopenharmony_ci mlx5_set_path_udp_sport(path, ah, 32368c2ecf20Sopenharmony_ci qp->ibqp.qp_num, 32378c2ecf20Sopenharmony_ci attr->dest_qp_num); 32388c2ecf20Sopenharmony_ci MLX5_SET(ads, path, eth_prio, sl & 0x7); 32398c2ecf20Sopenharmony_ci gid_type = ah->grh.sgid_attr->gid_type; 32408c2ecf20Sopenharmony_ci if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) 32418c2ecf20Sopenharmony_ci MLX5_SET(ads, path, dscp, grh->traffic_class >> 2); 32428c2ecf20Sopenharmony_ci } else { 32438c2ecf20Sopenharmony_ci MLX5_SET(ads, path, fl, !!(path_flags & MLX5_PATH_FLAG_FL)); 32448c2ecf20Sopenharmony_ci MLX5_SET(ads, path, free_ar, 32458c2ecf20Sopenharmony_ci !!(path_flags & MLX5_PATH_FLAG_FREE_AR)); 32468c2ecf20Sopenharmony_ci MLX5_SET(ads, path, rlid, rdma_ah_get_dlid(ah)); 32478c2ecf20Sopenharmony_ci MLX5_SET(ads, path, mlid, rdma_ah_get_path_bits(ah)); 32488c2ecf20Sopenharmony_ci MLX5_SET(ads, path, grh, !!(ah_flags & IB_AH_GRH)); 32498c2ecf20Sopenharmony_ci MLX5_SET(ads, path, sl, sl); 32508c2ecf20Sopenharmony_ci } 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci if (ah_flags & IB_AH_GRH) { 32538c2ecf20Sopenharmony_ci MLX5_SET(ads, path, src_addr_index, grh->sgid_index); 32548c2ecf20Sopenharmony_ci MLX5_SET(ads, path, hop_limit, grh->hop_limit); 32558c2ecf20Sopenharmony_ci MLX5_SET(ads, path, tclass, grh->traffic_class); 32568c2ecf20Sopenharmony_ci MLX5_SET(ads, path, flow_label, grh->flow_label); 32578c2ecf20Sopenharmony_ci memcpy(MLX5_ADDR_OF(ads, path, rgid_rip), grh->dgid.raw, 32588c2ecf20Sopenharmony_ci sizeof(grh->dgid.raw)); 32598c2ecf20Sopenharmony_ci } 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci err = ib_rate_to_mlx5(dev, rdma_ah_get_static_rate(ah)); 32628c2ecf20Sopenharmony_ci if (err < 0) 32638c2ecf20Sopenharmony_ci return err; 32648c2ecf20Sopenharmony_ci MLX5_SET(ads, path, stat_rate, err); 32658c2ecf20Sopenharmony_ci MLX5_SET(ads, path, vhca_port_num, port); 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_TIMEOUT) 32688c2ecf20Sopenharmony_ci MLX5_SET(ads, path, ack_timeout, 32698c2ecf20Sopenharmony_ci alt ? attr->alt_timeout : attr->timeout); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci if ((qp->ibqp.qp_type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt) 32728c2ecf20Sopenharmony_ci return modify_raw_packet_eth_prio(dev->mdev, 32738c2ecf20Sopenharmony_ci &qp->raw_packet_qp.sq, 32748c2ecf20Sopenharmony_ci sl & 0xf, qp->ibqp.pd); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci return 0; 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_cistatic enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = { 32808c2ecf20Sopenharmony_ci [MLX5_QP_STATE_INIT] = { 32818c2ecf20Sopenharmony_ci [MLX5_QP_STATE_INIT] = { 32828c2ecf20Sopenharmony_ci [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE | 32838c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 32848c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 32858c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 32868c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PRI_PORT | 32878c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 32888c2ecf20Sopenharmony_ci [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE | 32898c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 32908c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PRI_PORT | 32918c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 32928c2ecf20Sopenharmony_ci [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | 32938c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_Q_KEY | 32948c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PRI_PORT, 32958c2ecf20Sopenharmony_ci [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | 32968c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 32978c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 32988c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 32998c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PRI_PORT | 33008c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 33018c2ecf20Sopenharmony_ci }, 33028c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTR] = { 33038c2ecf20Sopenharmony_ci [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33048c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE | 33058c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33068c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33078c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 33088c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 33098c2ecf20Sopenharmony_ci [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33108c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33118c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 33128c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 33138c2ecf20Sopenharmony_ci [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | 33148c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_Q_KEY, 33158c2ecf20Sopenharmony_ci [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX | 33168c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_Q_KEY, 33178c2ecf20Sopenharmony_ci [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33188c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE | 33198c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33208c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33218c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PKEY_INDEX | 33228c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_LAG_TX_AFF, 33238c2ecf20Sopenharmony_ci }, 33248c2ecf20Sopenharmony_ci }, 33258c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTR] = { 33268c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = { 33278c2ecf20Sopenharmony_ci [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33288c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE | 33298c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33308c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33318c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE | 33328c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RNR_TIMEOUT, 33338c2ecf20Sopenharmony_ci [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33348c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33358c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE, 33368c2ecf20Sopenharmony_ci [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, 33378c2ecf20Sopenharmony_ci [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | 33388c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE | 33398c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33408c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33418c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE | 33428c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RNR_TIMEOUT, 33438c2ecf20Sopenharmony_ci }, 33448c2ecf20Sopenharmony_ci }, 33458c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = { 33468c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = { 33478c2ecf20Sopenharmony_ci [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE | 33488c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33498c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33508c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RNR_TIMEOUT | 33518c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE | 33528c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_ALT_ADDR_PATH, 33538c2ecf20Sopenharmony_ci [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE | 33548c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE | 33558c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_ALT_ADDR_PATH, 33568c2ecf20Sopenharmony_ci [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY | 33578c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_SRQN | 33588c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_CQN_RCV, 33598c2ecf20Sopenharmony_ci [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | 33608c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33618c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33628c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RNR_TIMEOUT | 33638c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PM_STATE | 33648c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_ALT_ADDR_PATH, 33658c2ecf20Sopenharmony_ci }, 33668c2ecf20Sopenharmony_ci }, 33678c2ecf20Sopenharmony_ci [MLX5_QP_STATE_SQER] = { 33688c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = { 33698c2ecf20Sopenharmony_ci [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, 33708c2ecf20Sopenharmony_ci [MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY, 33718c2ecf20Sopenharmony_ci [MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE, 33728c2ecf20Sopenharmony_ci [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RNR_TIMEOUT | 33738c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33748c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33758c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE, 33768c2ecf20Sopenharmony_ci [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RNR_TIMEOUT | 33778c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RWE | 33788c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE | 33798c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE, 33808c2ecf20Sopenharmony_ci }, 33818c2ecf20Sopenharmony_ci }, 33828c2ecf20Sopenharmony_ci}; 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_cistatic int ib_nr_to_mlx5_nr(int ib_mask) 33858c2ecf20Sopenharmony_ci{ 33868c2ecf20Sopenharmony_ci switch (ib_mask) { 33878c2ecf20Sopenharmony_ci case IB_QP_STATE: 33888c2ecf20Sopenharmony_ci return 0; 33898c2ecf20Sopenharmony_ci case IB_QP_CUR_STATE: 33908c2ecf20Sopenharmony_ci return 0; 33918c2ecf20Sopenharmony_ci case IB_QP_EN_SQD_ASYNC_NOTIFY: 33928c2ecf20Sopenharmony_ci return 0; 33938c2ecf20Sopenharmony_ci case IB_QP_ACCESS_FLAGS: 33948c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE | 33958c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RAE; 33968c2ecf20Sopenharmony_ci case IB_QP_PKEY_INDEX: 33978c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_PKEY_INDEX; 33988c2ecf20Sopenharmony_ci case IB_QP_PORT: 33998c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_PRI_PORT; 34008c2ecf20Sopenharmony_ci case IB_QP_QKEY: 34018c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_Q_KEY; 34028c2ecf20Sopenharmony_ci case IB_QP_AV: 34038c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH | 34048c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_PRI_PORT; 34058c2ecf20Sopenharmony_ci case IB_QP_PATH_MTU: 34068c2ecf20Sopenharmony_ci return 0; 34078c2ecf20Sopenharmony_ci case IB_QP_TIMEOUT: 34088c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_ACK_TIMEOUT; 34098c2ecf20Sopenharmony_ci case IB_QP_RETRY_CNT: 34108c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_RETRY_COUNT; 34118c2ecf20Sopenharmony_ci case IB_QP_RNR_RETRY: 34128c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_RNR_RETRY; 34138c2ecf20Sopenharmony_ci case IB_QP_RQ_PSN: 34148c2ecf20Sopenharmony_ci return 0; 34158c2ecf20Sopenharmony_ci case IB_QP_MAX_QP_RD_ATOMIC: 34168c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_SRA_MAX; 34178c2ecf20Sopenharmony_ci case IB_QP_ALT_PATH: 34188c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_ALT_ADDR_PATH; 34198c2ecf20Sopenharmony_ci case IB_QP_MIN_RNR_TIMER: 34208c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_RNR_TIMEOUT; 34218c2ecf20Sopenharmony_ci case IB_QP_SQ_PSN: 34228c2ecf20Sopenharmony_ci return 0; 34238c2ecf20Sopenharmony_ci case IB_QP_MAX_DEST_RD_ATOMIC: 34248c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE | 34258c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE; 34268c2ecf20Sopenharmony_ci case IB_QP_PATH_MIG_STATE: 34278c2ecf20Sopenharmony_ci return MLX5_QP_OPTPAR_PM_STATE; 34288c2ecf20Sopenharmony_ci case IB_QP_CAP: 34298c2ecf20Sopenharmony_ci return 0; 34308c2ecf20Sopenharmony_ci case IB_QP_DEST_QPN: 34318c2ecf20Sopenharmony_ci return 0; 34328c2ecf20Sopenharmony_ci } 34338c2ecf20Sopenharmony_ci return 0; 34348c2ecf20Sopenharmony_ci} 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_cistatic int ib_mask_to_mlx5_opt(int ib_mask) 34378c2ecf20Sopenharmony_ci{ 34388c2ecf20Sopenharmony_ci int result = 0; 34398c2ecf20Sopenharmony_ci int i; 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci for (i = 0; i < 8 * sizeof(int); i++) { 34428c2ecf20Sopenharmony_ci if ((1 << i) & ib_mask) 34438c2ecf20Sopenharmony_ci result |= ib_nr_to_mlx5_nr(1 << i); 34448c2ecf20Sopenharmony_ci } 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci return result; 34478c2ecf20Sopenharmony_ci} 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp_rq( 34508c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, int new_state, 34518c2ecf20Sopenharmony_ci const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd) 34528c2ecf20Sopenharmony_ci{ 34538c2ecf20Sopenharmony_ci void *in; 34548c2ecf20Sopenharmony_ci void *rqc; 34558c2ecf20Sopenharmony_ci int inlen; 34568c2ecf20Sopenharmony_ci int err; 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_rq_in); 34598c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 34608c2ecf20Sopenharmony_ci if (!in) 34618c2ecf20Sopenharmony_ci return -ENOMEM; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, rq_state, rq->state); 34648c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, uid, to_mpd(pd)->uid); 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); 34678c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, state, new_state); 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci if (raw_qp_param->set_mask & MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID) { 34708c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, modify_rq_counter_set_id)) { 34718c2ecf20Sopenharmony_ci MLX5_SET64(modify_rq_in, in, modify_bitmask, 34728c2ecf20Sopenharmony_ci MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID); 34738c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id); 34748c2ecf20Sopenharmony_ci } else 34758c2ecf20Sopenharmony_ci dev_info_once( 34768c2ecf20Sopenharmony_ci &dev->ib_dev.dev, 34778c2ecf20Sopenharmony_ci "RAW PACKET QP counters are not supported on current FW\n"); 34788c2ecf20Sopenharmony_ci } 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci err = mlx5_core_modify_rq(dev->mdev, rq->base.mqp.qpn, in); 34818c2ecf20Sopenharmony_ci if (err) 34828c2ecf20Sopenharmony_ci goto out; 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_ci rq->state = new_state; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ciout: 34878c2ecf20Sopenharmony_ci kvfree(in); 34888c2ecf20Sopenharmony_ci return err; 34898c2ecf20Sopenharmony_ci} 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp_sq( 34928c2ecf20Sopenharmony_ci struct mlx5_core_dev *dev, struct mlx5_ib_sq *sq, int new_state, 34938c2ecf20Sopenharmony_ci const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd) 34948c2ecf20Sopenharmony_ci{ 34958c2ecf20Sopenharmony_ci struct mlx5_ib_qp *ibqp = sq->base.container_mibqp; 34968c2ecf20Sopenharmony_ci struct mlx5_rate_limit old_rl = ibqp->rl; 34978c2ecf20Sopenharmony_ci struct mlx5_rate_limit new_rl = old_rl; 34988c2ecf20Sopenharmony_ci bool new_rate_added = false; 34998c2ecf20Sopenharmony_ci u16 rl_index = 0; 35008c2ecf20Sopenharmony_ci void *in; 35018c2ecf20Sopenharmony_ci void *sqc; 35028c2ecf20Sopenharmony_ci int inlen; 35038c2ecf20Sopenharmony_ci int err; 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_sq_in); 35068c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 35078c2ecf20Sopenharmony_ci if (!in) 35088c2ecf20Sopenharmony_ci return -ENOMEM; 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci MLX5_SET(modify_sq_in, in, uid, to_mpd(pd)->uid); 35118c2ecf20Sopenharmony_ci MLX5_SET(modify_sq_in, in, sq_state, sq->state); 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); 35148c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, state, new_state); 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci if (raw_qp_param->set_mask & MLX5_RAW_QP_RATE_LIMIT) { 35178c2ecf20Sopenharmony_ci if (new_state != MLX5_SQC_STATE_RDY) 35188c2ecf20Sopenharmony_ci pr_warn("%s: Rate limit can only be changed when SQ is moving to RDY\n", 35198c2ecf20Sopenharmony_ci __func__); 35208c2ecf20Sopenharmony_ci else 35218c2ecf20Sopenharmony_ci new_rl = raw_qp_param->rl; 35228c2ecf20Sopenharmony_ci } 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci if (!mlx5_rl_are_equal(&old_rl, &new_rl)) { 35258c2ecf20Sopenharmony_ci if (new_rl.rate) { 35268c2ecf20Sopenharmony_ci err = mlx5_rl_add_rate(dev, &rl_index, &new_rl); 35278c2ecf20Sopenharmony_ci if (err) { 35288c2ecf20Sopenharmony_ci pr_err("Failed configuring rate limit(err %d): \ 35298c2ecf20Sopenharmony_ci rate %u, max_burst_sz %u, typical_pkt_sz %u\n", 35308c2ecf20Sopenharmony_ci err, new_rl.rate, new_rl.max_burst_sz, 35318c2ecf20Sopenharmony_ci new_rl.typical_pkt_sz); 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci goto out; 35348c2ecf20Sopenharmony_ci } 35358c2ecf20Sopenharmony_ci new_rate_added = true; 35368c2ecf20Sopenharmony_ci } 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci MLX5_SET64(modify_sq_in, in, modify_bitmask, 1); 35398c2ecf20Sopenharmony_ci /* index 0 means no limit */ 35408c2ecf20Sopenharmony_ci MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index); 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci err = mlx5_core_modify_sq(dev, sq->base.mqp.qpn, in); 35448c2ecf20Sopenharmony_ci if (err) { 35458c2ecf20Sopenharmony_ci /* Remove new rate from table if failed */ 35468c2ecf20Sopenharmony_ci if (new_rate_added) 35478c2ecf20Sopenharmony_ci mlx5_rl_remove_rate(dev, &new_rl); 35488c2ecf20Sopenharmony_ci goto out; 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci /* Only remove the old rate after new rate was set */ 35528c2ecf20Sopenharmony_ci if ((old_rl.rate && !mlx5_rl_are_equal(&old_rl, &new_rl)) || 35538c2ecf20Sopenharmony_ci (new_state != MLX5_SQC_STATE_RDY)) { 35548c2ecf20Sopenharmony_ci mlx5_rl_remove_rate(dev, &old_rl); 35558c2ecf20Sopenharmony_ci if (new_state != MLX5_SQC_STATE_RDY) 35568c2ecf20Sopenharmony_ci memset(&new_rl, 0, sizeof(new_rl)); 35578c2ecf20Sopenharmony_ci } 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci ibqp->rl = new_rl; 35608c2ecf20Sopenharmony_ci sq->state = new_state; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ciout: 35638c2ecf20Sopenharmony_ci kvfree(in); 35648c2ecf20Sopenharmony_ci return err; 35658c2ecf20Sopenharmony_ci} 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 35688c2ecf20Sopenharmony_ci const struct mlx5_modify_raw_qp_param *raw_qp_param, 35698c2ecf20Sopenharmony_ci u8 tx_affinity) 35708c2ecf20Sopenharmony_ci{ 35718c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; 35728c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 35738c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq = &raw_packet_qp->sq; 35748c2ecf20Sopenharmony_ci int modify_rq = !!qp->rq.wqe_cnt; 35758c2ecf20Sopenharmony_ci int modify_sq = !!qp->sq.wqe_cnt; 35768c2ecf20Sopenharmony_ci int rq_state; 35778c2ecf20Sopenharmony_ci int sq_state; 35788c2ecf20Sopenharmony_ci int err; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci switch (raw_qp_param->operation) { 35818c2ecf20Sopenharmony_ci case MLX5_CMD_OP_RST2INIT_QP: 35828c2ecf20Sopenharmony_ci rq_state = MLX5_RQC_STATE_RDY; 35838c2ecf20Sopenharmony_ci sq_state = MLX5_SQC_STATE_RST; 35848c2ecf20Sopenharmony_ci break; 35858c2ecf20Sopenharmony_ci case MLX5_CMD_OP_2ERR_QP: 35868c2ecf20Sopenharmony_ci rq_state = MLX5_RQC_STATE_ERR; 35878c2ecf20Sopenharmony_ci sq_state = MLX5_SQC_STATE_ERR; 35888c2ecf20Sopenharmony_ci break; 35898c2ecf20Sopenharmony_ci case MLX5_CMD_OP_2RST_QP: 35908c2ecf20Sopenharmony_ci rq_state = MLX5_RQC_STATE_RST; 35918c2ecf20Sopenharmony_ci sq_state = MLX5_SQC_STATE_RST; 35928c2ecf20Sopenharmony_ci break; 35938c2ecf20Sopenharmony_ci case MLX5_CMD_OP_RTR2RTS_QP: 35948c2ecf20Sopenharmony_ci case MLX5_CMD_OP_RTS2RTS_QP: 35958c2ecf20Sopenharmony_ci if (raw_qp_param->set_mask & ~MLX5_RAW_QP_RATE_LIMIT) 35968c2ecf20Sopenharmony_ci return -EINVAL; 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci modify_rq = 0; 35998c2ecf20Sopenharmony_ci sq_state = MLX5_SQC_STATE_RDY; 36008c2ecf20Sopenharmony_ci break; 36018c2ecf20Sopenharmony_ci case MLX5_CMD_OP_INIT2INIT_QP: 36028c2ecf20Sopenharmony_ci case MLX5_CMD_OP_INIT2RTR_QP: 36038c2ecf20Sopenharmony_ci if (raw_qp_param->set_mask) 36048c2ecf20Sopenharmony_ci return -EINVAL; 36058c2ecf20Sopenharmony_ci else 36068c2ecf20Sopenharmony_ci return 0; 36078c2ecf20Sopenharmony_ci default: 36088c2ecf20Sopenharmony_ci WARN_ON(1); 36098c2ecf20Sopenharmony_ci return -EINVAL; 36108c2ecf20Sopenharmony_ci } 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci if (modify_rq) { 36138c2ecf20Sopenharmony_ci err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param, 36148c2ecf20Sopenharmony_ci qp->ibqp.pd); 36158c2ecf20Sopenharmony_ci if (err) 36168c2ecf20Sopenharmony_ci return err; 36178c2ecf20Sopenharmony_ci } 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci if (modify_sq) { 36208c2ecf20Sopenharmony_ci struct mlx5_flow_handle *flow_rule; 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci if (tx_affinity) { 36238c2ecf20Sopenharmony_ci err = modify_raw_packet_tx_affinity(dev->mdev, sq, 36248c2ecf20Sopenharmony_ci tx_affinity, 36258c2ecf20Sopenharmony_ci qp->ibqp.pd); 36268c2ecf20Sopenharmony_ci if (err) 36278c2ecf20Sopenharmony_ci return err; 36288c2ecf20Sopenharmony_ci } 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci flow_rule = create_flow_rule_vport_sq(dev, sq, 36318c2ecf20Sopenharmony_ci raw_qp_param->port); 36328c2ecf20Sopenharmony_ci if (IS_ERR(flow_rule)) 36338c2ecf20Sopenharmony_ci return PTR_ERR(flow_rule); 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci err = modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, 36368c2ecf20Sopenharmony_ci raw_qp_param, qp->ibqp.pd); 36378c2ecf20Sopenharmony_ci if (err) { 36388c2ecf20Sopenharmony_ci if (flow_rule) 36398c2ecf20Sopenharmony_ci mlx5_del_flow_rules(flow_rule); 36408c2ecf20Sopenharmony_ci return err; 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci if (flow_rule) { 36448c2ecf20Sopenharmony_ci destroy_flow_rule_vport_sq(sq); 36458c2ecf20Sopenharmony_ci sq->flow_rule = flow_rule; 36468c2ecf20Sopenharmony_ci } 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci return err; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci return 0; 36528c2ecf20Sopenharmony_ci} 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_cistatic unsigned int get_tx_affinity_rr(struct mlx5_ib_dev *dev, 36558c2ecf20Sopenharmony_ci struct ib_udata *udata) 36568c2ecf20Sopenharmony_ci{ 36578c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 36588c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 36598c2ecf20Sopenharmony_ci u8 port_num = mlx5_core_native_port_num(dev->mdev) - 1; 36608c2ecf20Sopenharmony_ci atomic_t *tx_port_affinity; 36618c2ecf20Sopenharmony_ci 36628c2ecf20Sopenharmony_ci if (ucontext) 36638c2ecf20Sopenharmony_ci tx_port_affinity = &ucontext->tx_port_affinity; 36648c2ecf20Sopenharmony_ci else 36658c2ecf20Sopenharmony_ci tx_port_affinity = &dev->port[port_num].roce.tx_port_affinity; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci return (unsigned int)atomic_add_return(1, tx_port_affinity) % 36688c2ecf20Sopenharmony_ci MLX5_MAX_PORTS + 1; 36698c2ecf20Sopenharmony_ci} 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_cistatic bool qp_supports_affinity(struct mlx5_ib_qp *qp) 36728c2ecf20Sopenharmony_ci{ 36738c2ecf20Sopenharmony_ci if ((qp->type == IB_QPT_RC) || (qp->type == IB_QPT_UD) || 36748c2ecf20Sopenharmony_ci (qp->type == IB_QPT_UC) || (qp->type == IB_QPT_RAW_PACKET) || 36758c2ecf20Sopenharmony_ci (qp->type == IB_QPT_XRC_INI) || (qp->type == IB_QPT_XRC_TGT) || 36768c2ecf20Sopenharmony_ci (qp->type == MLX5_IB_QPT_DCI)) 36778c2ecf20Sopenharmony_ci return true; 36788c2ecf20Sopenharmony_ci return false; 36798c2ecf20Sopenharmony_ci} 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_cistatic unsigned int get_tx_affinity(struct ib_qp *qp, 36828c2ecf20Sopenharmony_ci const struct ib_qp_attr *attr, 36838c2ecf20Sopenharmony_ci int attr_mask, u8 init, 36848c2ecf20Sopenharmony_ci struct ib_udata *udata) 36858c2ecf20Sopenharmony_ci{ 36868c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 36878c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 36888c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 36898c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 36908c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *qp_base; 36918c2ecf20Sopenharmony_ci unsigned int tx_affinity; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci if (!(mlx5_ib_lag_should_assign_affinity(dev) && 36948c2ecf20Sopenharmony_ci qp_supports_affinity(mqp))) 36958c2ecf20Sopenharmony_ci return 0; 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci if (mqp->flags & MLX5_IB_QP_CREATE_SQPN_QP1) 36988c2ecf20Sopenharmony_ci tx_affinity = mqp->gsi_lag_port; 36998c2ecf20Sopenharmony_ci else if (init) 37008c2ecf20Sopenharmony_ci tx_affinity = get_tx_affinity_rr(dev, udata); 37018c2ecf20Sopenharmony_ci else if ((attr_mask & IB_QP_AV) && attr->xmit_slave) 37028c2ecf20Sopenharmony_ci tx_affinity = 37038c2ecf20Sopenharmony_ci mlx5_lag_get_slave_port(dev->mdev, attr->xmit_slave); 37048c2ecf20Sopenharmony_ci else 37058c2ecf20Sopenharmony_ci return 0; 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci qp_base = &mqp->trans_qp.base; 37088c2ecf20Sopenharmony_ci if (ucontext) 37098c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x ucontext %p\n", 37108c2ecf20Sopenharmony_ci tx_affinity, qp_base->mqp.qpn, ucontext); 37118c2ecf20Sopenharmony_ci else 37128c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x\n", 37138c2ecf20Sopenharmony_ci tx_affinity, qp_base->mqp.qpn); 37148c2ecf20Sopenharmony_ci return tx_affinity; 37158c2ecf20Sopenharmony_ci} 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_cistatic int __mlx5_ib_qp_set_raw_qp_counter(struct mlx5_ib_qp *qp, u32 set_id, 37188c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev) 37198c2ecf20Sopenharmony_ci{ 37208c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; 37218c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 37228c2ecf20Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(modify_rq_in)] = {}; 37238c2ecf20Sopenharmony_ci void *rqc; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci if (!qp->rq.wqe_cnt) 37268c2ecf20Sopenharmony_ci return 0; 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, rq_state, rq->state); 37298c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, uid, to_mpd(qp->ibqp.pd)->uid); 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); 37328c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RDY); 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci MLX5_SET64(modify_rq_in, in, modify_bitmask, 37358c2ecf20Sopenharmony_ci MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID); 37368c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, counter_set_id, set_id); 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci return mlx5_core_modify_rq(mdev, rq->base.mqp.qpn, in); 37398c2ecf20Sopenharmony_ci} 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_cistatic int __mlx5_ib_qp_set_counter(struct ib_qp *qp, 37428c2ecf20Sopenharmony_ci struct rdma_counter *counter) 37438c2ecf20Sopenharmony_ci{ 37448c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 37458c2ecf20Sopenharmony_ci u32 in[MLX5_ST_SZ_DW(rts2rts_qp_in)] = {}; 37468c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 37478c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base; 37488c2ecf20Sopenharmony_ci u32 set_id; 37498c2ecf20Sopenharmony_ci u32 *qpc; 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci if (counter) 37528c2ecf20Sopenharmony_ci set_id = counter->id; 37538c2ecf20Sopenharmony_ci else 37548c2ecf20Sopenharmony_ci set_id = mlx5_ib_get_counters_id(dev, mqp->port - 1); 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci if (mqp->type == IB_QPT_RAW_PACKET) 37578c2ecf20Sopenharmony_ci return __mlx5_ib_qp_set_raw_qp_counter(mqp, set_id, dev->mdev); 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci base = &mqp->trans_qp.base; 37608c2ecf20Sopenharmony_ci MLX5_SET(rts2rts_qp_in, in, opcode, MLX5_CMD_OP_RTS2RTS_QP); 37618c2ecf20Sopenharmony_ci MLX5_SET(rts2rts_qp_in, in, qpn, base->mqp.qpn); 37628c2ecf20Sopenharmony_ci MLX5_SET(rts2rts_qp_in, in, uid, base->mqp.uid); 37638c2ecf20Sopenharmony_ci MLX5_SET(rts2rts_qp_in, in, opt_param_mask, 37648c2ecf20Sopenharmony_ci MLX5_QP_OPTPAR_COUNTER_SET_ID); 37658c2ecf20Sopenharmony_ci 37668c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(rts2rts_qp_in, in, qpc); 37678c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, counter_set_id, set_id); 37688c2ecf20Sopenharmony_ci return mlx5_cmd_exec_in(dev->mdev, rts2rts_qp, in); 37698c2ecf20Sopenharmony_ci} 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_cistatic int __mlx5_ib_modify_qp(struct ib_qp *ibqp, 37728c2ecf20Sopenharmony_ci const struct ib_qp_attr *attr, int attr_mask, 37738c2ecf20Sopenharmony_ci enum ib_qp_state cur_state, 37748c2ecf20Sopenharmony_ci enum ib_qp_state new_state, 37758c2ecf20Sopenharmony_ci const struct mlx5_ib_modify_qp *ucmd, 37768c2ecf20Sopenharmony_ci struct mlx5_ib_modify_qp_resp *resp, 37778c2ecf20Sopenharmony_ci struct ib_udata *udata) 37788c2ecf20Sopenharmony_ci{ 37798c2ecf20Sopenharmony_ci static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = { 37808c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = { 37818c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 37828c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 37838c2ecf20Sopenharmony_ci [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_RST2INIT_QP, 37848c2ecf20Sopenharmony_ci }, 37858c2ecf20Sopenharmony_ci [MLX5_QP_STATE_INIT] = { 37868c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 37878c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 37888c2ecf20Sopenharmony_ci [MLX5_QP_STATE_INIT] = MLX5_CMD_OP_INIT2INIT_QP, 37898c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTR] = MLX5_CMD_OP_INIT2RTR_QP, 37908c2ecf20Sopenharmony_ci }, 37918c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTR] = { 37928c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 37938c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 37948c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTR2RTS_QP, 37958c2ecf20Sopenharmony_ci }, 37968c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = { 37978c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 37988c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 37998c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_RTS2RTS_QP, 38008c2ecf20Sopenharmony_ci }, 38018c2ecf20Sopenharmony_ci [MLX5_QP_STATE_SQD] = { 38028c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 38038c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 38048c2ecf20Sopenharmony_ci }, 38058c2ecf20Sopenharmony_ci [MLX5_QP_STATE_SQER] = { 38068c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 38078c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 38088c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RTS] = MLX5_CMD_OP_SQERR2RTS_QP, 38098c2ecf20Sopenharmony_ci }, 38108c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = { 38118c2ecf20Sopenharmony_ci [MLX5_QP_STATE_RST] = MLX5_CMD_OP_2RST_QP, 38128c2ecf20Sopenharmony_ci [MLX5_QP_STATE_ERR] = MLX5_CMD_OP_2ERR_QP, 38138c2ecf20Sopenharmony_ci } 38148c2ecf20Sopenharmony_ci }; 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 38178c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp = to_mqp(ibqp); 38188c2ecf20Sopenharmony_ci struct mlx5_ib_qp_base *base = &qp->trans_qp.base; 38198c2ecf20Sopenharmony_ci struct mlx5_ib_cq *send_cq, *recv_cq; 38208c2ecf20Sopenharmony_ci struct mlx5_ib_pd *pd; 38218c2ecf20Sopenharmony_ci enum mlx5_qp_state mlx5_cur, mlx5_new; 38228c2ecf20Sopenharmony_ci void *qpc, *pri_path, *alt_path; 38238c2ecf20Sopenharmony_ci enum mlx5_qp_optpar optpar = 0; 38248c2ecf20Sopenharmony_ci u32 set_id = 0; 38258c2ecf20Sopenharmony_ci int mlx5_st; 38268c2ecf20Sopenharmony_ci int err; 38278c2ecf20Sopenharmony_ci u16 op; 38288c2ecf20Sopenharmony_ci u8 tx_affinity = 0; 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci mlx5_st = to_mlx5_st(qp->type); 38318c2ecf20Sopenharmony_ci if (mlx5_st < 0) 38328c2ecf20Sopenharmony_ci return -EINVAL; 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci qpc = kzalloc(MLX5_ST_SZ_BYTES(qpc), GFP_KERNEL); 38358c2ecf20Sopenharmony_ci if (!qpc) 38368c2ecf20Sopenharmony_ci return -ENOMEM; 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci pd = to_mpd(qp->ibqp.pd); 38398c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, st, mlx5_st); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci if (!(attr_mask & IB_QP_PATH_MIG_STATE)) { 38428c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 38438c2ecf20Sopenharmony_ci } else { 38448c2ecf20Sopenharmony_ci switch (attr->path_mig_state) { 38458c2ecf20Sopenharmony_ci case IB_MIG_MIGRATED: 38468c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); 38478c2ecf20Sopenharmony_ci break; 38488c2ecf20Sopenharmony_ci case IB_MIG_REARM: 38498c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_REARM); 38508c2ecf20Sopenharmony_ci break; 38518c2ecf20Sopenharmony_ci case IB_MIG_ARMED: 38528c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_ARMED); 38538c2ecf20Sopenharmony_ci break; 38548c2ecf20Sopenharmony_ci } 38558c2ecf20Sopenharmony_ci } 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci tx_affinity = get_tx_affinity(ibqp, attr, attr_mask, 38588c2ecf20Sopenharmony_ci cur_state == IB_QPS_RESET && 38598c2ecf20Sopenharmony_ci new_state == IB_QPS_INIT, udata); 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, lag_tx_port_affinity, tx_affinity); 38628c2ecf20Sopenharmony_ci if (tx_affinity && new_state == IB_QPS_RTR && 38638c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, init2_lag_tx_port_affinity)) 38648c2ecf20Sopenharmony_ci optpar |= MLX5_QP_OPTPAR_LAG_TX_AFF; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci if (is_sqp(ibqp->qp_type)) { 38678c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, IB_MTU_256); 38688c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_msg_max, 8); 38698c2ecf20Sopenharmony_ci } else if ((ibqp->qp_type == IB_QPT_UD && 38708c2ecf20Sopenharmony_ci !(qp->flags & IB_QP_CREATE_SOURCE_QPN)) || 38718c2ecf20Sopenharmony_ci ibqp->qp_type == MLX5_IB_QPT_REG_UMR) { 38728c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, IB_MTU_4096); 38738c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_msg_max, 12); 38748c2ecf20Sopenharmony_ci } else if (attr_mask & IB_QP_PATH_MTU) { 38758c2ecf20Sopenharmony_ci if (attr->path_mtu < IB_MTU_256 || 38768c2ecf20Sopenharmony_ci attr->path_mtu > IB_MTU_4096) { 38778c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu); 38788c2ecf20Sopenharmony_ci err = -EINVAL; 38798c2ecf20Sopenharmony_ci goto out; 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, mtu, attr->path_mtu); 38828c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_msg_max, 38838c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, log_max_msg)); 38848c2ecf20Sopenharmony_ci } 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) 38878c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, remote_qpn, attr->dest_qp_num); 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci pri_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 38908c2ecf20Sopenharmony_ci alt_path = MLX5_ADDR_OF(qpc, qpc, secondary_address_path); 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 38938c2ecf20Sopenharmony_ci MLX5_SET(ads, pri_path, pkey_index, attr->pkey_index); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci /* todo implement counter_index functionality */ 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci if (is_sqp(ibqp->qp_type)) 38988c2ecf20Sopenharmony_ci MLX5_SET(ads, pri_path, vhca_port_num, qp->port); 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PORT) 39018c2ecf20Sopenharmony_ci MLX5_SET(ads, pri_path, vhca_port_num, attr->port_num); 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_AV) { 39048c2ecf20Sopenharmony_ci err = mlx5_set_path(dev, qp, &attr->ah_attr, pri_path, 39058c2ecf20Sopenharmony_ci attr_mask & IB_QP_PORT ? attr->port_num : 39068c2ecf20Sopenharmony_ci qp->port, 39078c2ecf20Sopenharmony_ci attr_mask, 0, attr, false); 39088c2ecf20Sopenharmony_ci if (err) 39098c2ecf20Sopenharmony_ci goto out; 39108c2ecf20Sopenharmony_ci } 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_TIMEOUT) 39138c2ecf20Sopenharmony_ci MLX5_SET(ads, pri_path, ack_timeout, attr->timeout); 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 39168c2ecf20Sopenharmony_ci err = mlx5_set_path(dev, qp, &attr->alt_ah_attr, alt_path, 39178c2ecf20Sopenharmony_ci attr->alt_port_num, 39188c2ecf20Sopenharmony_ci attr_mask | IB_QP_PKEY_INDEX | 39198c2ecf20Sopenharmony_ci IB_QP_TIMEOUT, 39208c2ecf20Sopenharmony_ci 0, attr, true); 39218c2ecf20Sopenharmony_ci if (err) 39228c2ecf20Sopenharmony_ci goto out; 39238c2ecf20Sopenharmony_ci } 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq, 39268c2ecf20Sopenharmony_ci &send_cq, &recv_cq); 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, pd, pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn); 39298c2ecf20Sopenharmony_ci if (send_cq) 39308c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_snd, send_cq->mcq.cqn); 39318c2ecf20Sopenharmony_ci if (recv_cq) 39328c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, cqn_rcv, recv_cq->mcq.cqn); 39338c2ecf20Sopenharmony_ci 39348c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_ack_req_freq, MLX5_IB_ACK_REQ_FREQ); 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) 39378c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rnr_retry, attr->rnr_retry); 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) 39408c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt); 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && attr->max_rd_atomic) 39438c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_sra_max, ilog2(attr->max_rd_atomic)); 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_SQ_PSN) 39468c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, next_send_psn, attr->sq_psn); 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && attr->max_dest_rd_atomic) 39498c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, log_rra_max, 39508c2ecf20Sopenharmony_ci ilog2(attr->max_dest_rd_atomic)); 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { 39538c2ecf20Sopenharmony_ci err = set_qpc_atomic_flags(qp, attr, attr_mask, qpc); 39548c2ecf20Sopenharmony_ci if (err) 39558c2ecf20Sopenharmony_ci goto out; 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) 39598c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, min_rnr_nak, attr->min_rnr_timer); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RQ_PSN) 39628c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, next_rcv_psn, attr->rq_psn); 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_QKEY) 39658c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, q_key, attr->qkey); 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 39688c2ecf20Sopenharmony_ci MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma); 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { 39718c2ecf20Sopenharmony_ci u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num : 39728c2ecf20Sopenharmony_ci qp->port) - 1; 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci /* Underlay port should be used - index 0 function per port */ 39758c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_SOURCE_QPN) 39768c2ecf20Sopenharmony_ci port_num = 0; 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ci if (ibqp->counter) 39798c2ecf20Sopenharmony_ci set_id = ibqp->counter->id; 39808c2ecf20Sopenharmony_ci else 39818c2ecf20Sopenharmony_ci set_id = mlx5_ib_get_counters_id(dev, port_num); 39828c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, counter_set_id, set_id); 39838c2ecf20Sopenharmony_ci } 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 39868c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, rlky, 1); 39878c2ecf20Sopenharmony_ci 39888c2ecf20Sopenharmony_ci if (qp->flags & MLX5_IB_QP_CREATE_SQPN_QP1) 39898c2ecf20Sopenharmony_ci MLX5_SET(qpc, qpc, deth_sqpn, 1); 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci mlx5_cur = to_mlx5_state(cur_state); 39928c2ecf20Sopenharmony_ci mlx5_new = to_mlx5_state(new_state); 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE || 39958c2ecf20Sopenharmony_ci !optab[mlx5_cur][mlx5_new]) { 39968c2ecf20Sopenharmony_ci err = -EINVAL; 39978c2ecf20Sopenharmony_ci goto out; 39988c2ecf20Sopenharmony_ci } 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci op = optab[mlx5_cur][mlx5_new]; 40018c2ecf20Sopenharmony_ci optpar |= ib_mask_to_mlx5_opt(attr_mask); 40028c2ecf20Sopenharmony_ci optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st]; 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET || 40058c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) { 40068c2ecf20Sopenharmony_ci struct mlx5_modify_raw_qp_param raw_qp_param = {}; 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ci raw_qp_param.operation = op; 40098c2ecf20Sopenharmony_ci if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { 40108c2ecf20Sopenharmony_ci raw_qp_param.rq_q_ctr_id = set_id; 40118c2ecf20Sopenharmony_ci raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID; 40128c2ecf20Sopenharmony_ci } 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PORT) 40158c2ecf20Sopenharmony_ci raw_qp_param.port = attr->port_num; 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RATE_LIMIT) { 40188c2ecf20Sopenharmony_ci raw_qp_param.rl.rate = attr->rate_limit; 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci if (ucmd->burst_info.max_burst_sz) { 40218c2ecf20Sopenharmony_ci if (attr->rate_limit && 40228c2ecf20Sopenharmony_ci MLX5_CAP_QOS(dev->mdev, packet_pacing_burst_bound)) { 40238c2ecf20Sopenharmony_ci raw_qp_param.rl.max_burst_sz = 40248c2ecf20Sopenharmony_ci ucmd->burst_info.max_burst_sz; 40258c2ecf20Sopenharmony_ci } else { 40268c2ecf20Sopenharmony_ci err = -EINVAL; 40278c2ecf20Sopenharmony_ci goto out; 40288c2ecf20Sopenharmony_ci } 40298c2ecf20Sopenharmony_ci } 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci if (ucmd->burst_info.typical_pkt_sz) { 40328c2ecf20Sopenharmony_ci if (attr->rate_limit && 40338c2ecf20Sopenharmony_ci MLX5_CAP_QOS(dev->mdev, packet_pacing_typical_size)) { 40348c2ecf20Sopenharmony_ci raw_qp_param.rl.typical_pkt_sz = 40358c2ecf20Sopenharmony_ci ucmd->burst_info.typical_pkt_sz; 40368c2ecf20Sopenharmony_ci } else { 40378c2ecf20Sopenharmony_ci err = -EINVAL; 40388c2ecf20Sopenharmony_ci goto out; 40398c2ecf20Sopenharmony_ci } 40408c2ecf20Sopenharmony_ci } 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci raw_qp_param.set_mask |= MLX5_RAW_QP_RATE_LIMIT; 40438c2ecf20Sopenharmony_ci } 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci err = modify_raw_packet_qp(dev, qp, &raw_qp_param, tx_affinity); 40468c2ecf20Sopenharmony_ci } else { 40478c2ecf20Sopenharmony_ci if (udata) { 40488c2ecf20Sopenharmony_ci /* For the kernel flows, the resp will stay zero */ 40498c2ecf20Sopenharmony_ci resp->ece_options = 40508c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, ece_support) ? 40518c2ecf20Sopenharmony_ci ucmd->ece_options : 0; 40528c2ecf20Sopenharmony_ci resp->response_length = sizeof(*resp); 40538c2ecf20Sopenharmony_ci } 40548c2ecf20Sopenharmony_ci err = mlx5_core_qp_modify(dev, op, optpar, qpc, &base->mqp, 40558c2ecf20Sopenharmony_ci &resp->ece_options); 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci if (err) 40598c2ecf20Sopenharmony_ci goto out; 40608c2ecf20Sopenharmony_ci 40618c2ecf20Sopenharmony_ci qp->state = new_state; 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ACCESS_FLAGS) 40648c2ecf20Sopenharmony_ci qp->trans_qp.atomic_rd_en = attr->qp_access_flags; 40658c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 40668c2ecf20Sopenharmony_ci qp->trans_qp.resp_depth = attr->max_dest_rd_atomic; 40678c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PORT) 40688c2ecf20Sopenharmony_ci qp->port = attr->port_num; 40698c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) 40708c2ecf20Sopenharmony_ci qp->trans_qp.alt_port = attr->alt_port_num; 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci /* 40738c2ecf20Sopenharmony_ci * If we moved a kernel QP to RESET, clean up all old CQ 40748c2ecf20Sopenharmony_ci * entries and reinitialize the QP. 40758c2ecf20Sopenharmony_ci */ 40768c2ecf20Sopenharmony_ci if (new_state == IB_QPS_RESET && 40778c2ecf20Sopenharmony_ci !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) { 40788c2ecf20Sopenharmony_ci mlx5_ib_cq_clean(recv_cq, base->mqp.qpn, 40798c2ecf20Sopenharmony_ci ibqp->srq ? to_msrq(ibqp->srq) : NULL); 40808c2ecf20Sopenharmony_ci if (send_cq != recv_cq) 40818c2ecf20Sopenharmony_ci mlx5_ib_cq_clean(send_cq, base->mqp.qpn, NULL); 40828c2ecf20Sopenharmony_ci 40838c2ecf20Sopenharmony_ci qp->rq.head = 0; 40848c2ecf20Sopenharmony_ci qp->rq.tail = 0; 40858c2ecf20Sopenharmony_ci qp->sq.head = 0; 40868c2ecf20Sopenharmony_ci qp->sq.tail = 0; 40878c2ecf20Sopenharmony_ci qp->sq.cur_post = 0; 40888c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) 40898c2ecf20Sopenharmony_ci qp->sq.cur_edge = get_sq_edge(&qp->sq, 0); 40908c2ecf20Sopenharmony_ci qp->sq.last_poll = 0; 40918c2ecf20Sopenharmony_ci qp->db.db[MLX5_RCV_DBR] = 0; 40928c2ecf20Sopenharmony_ci qp->db.db[MLX5_SND_DBR] = 0; 40938c2ecf20Sopenharmony_ci } 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci if ((new_state == IB_QPS_RTS) && qp->counter_pending) { 40968c2ecf20Sopenharmony_ci err = __mlx5_ib_qp_set_counter(ibqp, ibqp->counter); 40978c2ecf20Sopenharmony_ci if (!err) 40988c2ecf20Sopenharmony_ci qp->counter_pending = 0; 40998c2ecf20Sopenharmony_ci } 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_ciout: 41028c2ecf20Sopenharmony_ci kfree(qpc); 41038c2ecf20Sopenharmony_ci return err; 41048c2ecf20Sopenharmony_ci} 41058c2ecf20Sopenharmony_ci 41068c2ecf20Sopenharmony_cistatic inline bool is_valid_mask(int mask, int req, int opt) 41078c2ecf20Sopenharmony_ci{ 41088c2ecf20Sopenharmony_ci if ((mask & req) != req) 41098c2ecf20Sopenharmony_ci return false; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci if (mask & ~(req | opt)) 41128c2ecf20Sopenharmony_ci return false; 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci return true; 41158c2ecf20Sopenharmony_ci} 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci/* check valid transition for driver QP types 41188c2ecf20Sopenharmony_ci * for now the only QP type that this function supports is DCI 41198c2ecf20Sopenharmony_ci */ 41208c2ecf20Sopenharmony_cistatic bool modify_dci_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state new_state, 41218c2ecf20Sopenharmony_ci enum ib_qp_attr_mask attr_mask) 41228c2ecf20Sopenharmony_ci{ 41238c2ecf20Sopenharmony_ci int req = IB_QP_STATE; 41248c2ecf20Sopenharmony_ci int opt = 0; 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci if (new_state == IB_QPS_RESET) { 41278c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41288c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { 41298c2ecf20Sopenharmony_ci req |= IB_QP_PKEY_INDEX | IB_QP_PORT; 41308c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41318c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) { 41328c2ecf20Sopenharmony_ci opt = IB_QP_PKEY_INDEX | IB_QP_PORT; 41338c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41348c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { 41358c2ecf20Sopenharmony_ci req |= IB_QP_PATH_MTU; 41368c2ecf20Sopenharmony_ci opt = IB_QP_PKEY_INDEX | IB_QP_AV; 41378c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41388c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_RTR && new_state == IB_QPS_RTS) { 41398c2ecf20Sopenharmony_ci req |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | IB_QP_RNR_RETRY | 41408c2ecf20Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC | IB_QP_SQ_PSN; 41418c2ecf20Sopenharmony_ci opt = IB_QP_MIN_RNR_TIMER; 41428c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41438c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_RTS && new_state == IB_QPS_RTS) { 41448c2ecf20Sopenharmony_ci opt = IB_QP_MIN_RNR_TIMER; 41458c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41468c2ecf20Sopenharmony_ci } else if (cur_state != IB_QPS_RESET && new_state == IB_QPS_ERR) { 41478c2ecf20Sopenharmony_ci return is_valid_mask(attr_mask, req, opt); 41488c2ecf20Sopenharmony_ci } 41498c2ecf20Sopenharmony_ci return false; 41508c2ecf20Sopenharmony_ci} 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci/* mlx5_ib_modify_dct: modify a DCT QP 41538c2ecf20Sopenharmony_ci * valid transitions are: 41548c2ecf20Sopenharmony_ci * RESET to INIT: must set access_flags, pkey_index and port 41558c2ecf20Sopenharmony_ci * INIT to RTR : must set min_rnr_timer, tclass, flow_label, 41568c2ecf20Sopenharmony_ci * mtu, gid_index and hop_limit 41578c2ecf20Sopenharmony_ci * Other transitions and attributes are illegal 41588c2ecf20Sopenharmony_ci */ 41598c2ecf20Sopenharmony_cistatic int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, 41608c2ecf20Sopenharmony_ci int attr_mask, struct mlx5_ib_modify_qp *ucmd, 41618c2ecf20Sopenharmony_ci struct ib_udata *udata) 41628c2ecf20Sopenharmony_ci{ 41638c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp = to_mqp(ibqp); 41648c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 41658c2ecf20Sopenharmony_ci enum ib_qp_state cur_state, new_state; 41668c2ecf20Sopenharmony_ci int required = IB_QP_STATE; 41678c2ecf20Sopenharmony_ci void *dctc; 41688c2ecf20Sopenharmony_ci int err; 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci if (!(attr_mask & IB_QP_STATE)) 41718c2ecf20Sopenharmony_ci return -EINVAL; 41728c2ecf20Sopenharmony_ci 41738c2ecf20Sopenharmony_ci cur_state = qp->state; 41748c2ecf20Sopenharmony_ci new_state = attr->qp_state; 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry); 41778c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, ece_support) && ucmd->ece_options) 41788c2ecf20Sopenharmony_ci /* 41798c2ecf20Sopenharmony_ci * DCT doesn't initialize QP till modify command is executed, 41808c2ecf20Sopenharmony_ci * so we need to overwrite previously set ECE field if user 41818c2ecf20Sopenharmony_ci * provided any value except zero, which means not set/not 41828c2ecf20Sopenharmony_ci * valid. 41838c2ecf20Sopenharmony_ci */ 41848c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, ece, ucmd->ece_options); 41858c2ecf20Sopenharmony_ci 41868c2ecf20Sopenharmony_ci if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { 41878c2ecf20Sopenharmony_ci u16 set_id; 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci required |= IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT; 41908c2ecf20Sopenharmony_ci if (!is_valid_mask(attr_mask, required, 0)) 41918c2ecf20Sopenharmony_ci return -EINVAL; 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci if (attr->port_num == 0 || 41948c2ecf20Sopenharmony_ci attr->port_num > dev->num_ports) { 41958c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n", 41968c2ecf20Sopenharmony_ci attr->port_num, dev->num_ports); 41978c2ecf20Sopenharmony_ci return -EINVAL; 41988c2ecf20Sopenharmony_ci } 41998c2ecf20Sopenharmony_ci if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) 42008c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, rre, 1); 42018c2ecf20Sopenharmony_ci if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) 42028c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, rwe, 1); 42038c2ecf20Sopenharmony_ci if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) { 42048c2ecf20Sopenharmony_ci int atomic_mode; 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_ci atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT); 42078c2ecf20Sopenharmony_ci if (atomic_mode < 0) 42088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, atomic_mode, atomic_mode); 42118c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, rae, 1); 42128c2ecf20Sopenharmony_ci } 42138c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, pkey_index, attr->pkey_index); 42148c2ecf20Sopenharmony_ci if (mlx5_lag_is_active(dev->mdev)) 42158c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, port, 42168c2ecf20Sopenharmony_ci get_tx_affinity_rr(dev, udata)); 42178c2ecf20Sopenharmony_ci else 42188c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, port, attr->port_num); 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci set_id = mlx5_ib_get_counters_id(dev, attr->port_num - 1); 42218c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, counter_set_id, set_id); 42228c2ecf20Sopenharmony_ci } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { 42238c2ecf20Sopenharmony_ci struct mlx5_ib_modify_qp_resp resp = {}; 42248c2ecf20Sopenharmony_ci u32 out[MLX5_ST_SZ_DW(create_dct_out)] = {}; 42258c2ecf20Sopenharmony_ci u32 min_resp_len = offsetofend(typeof(resp), dctn); 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci if (udata->outlen < min_resp_len) 42288c2ecf20Sopenharmony_ci return -EINVAL; 42298c2ecf20Sopenharmony_ci /* 42308c2ecf20Sopenharmony_ci * If we don't have enough space for the ECE options, 42318c2ecf20Sopenharmony_ci * simply indicate it with resp.response_length. 42328c2ecf20Sopenharmony_ci */ 42338c2ecf20Sopenharmony_ci resp.response_length = (udata->outlen < sizeof(resp)) ? 42348c2ecf20Sopenharmony_ci min_resp_len : 42358c2ecf20Sopenharmony_ci sizeof(resp); 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci required |= IB_QP_MIN_RNR_TIMER | IB_QP_AV | IB_QP_PATH_MTU; 42388c2ecf20Sopenharmony_ci if (!is_valid_mask(attr_mask, required, 0)) 42398c2ecf20Sopenharmony_ci return -EINVAL; 42408c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, min_rnr_nak, attr->min_rnr_timer); 42418c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, tclass, attr->ah_attr.grh.traffic_class); 42428c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, flow_label, attr->ah_attr.grh.flow_label); 42438c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, mtu, attr->path_mtu); 42448c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, my_addr_index, attr->ah_attr.grh.sgid_index); 42458c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, hop_limit, attr->ah_attr.grh.hop_limit); 42468c2ecf20Sopenharmony_ci if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE) 42478c2ecf20Sopenharmony_ci MLX5_SET(dctc, dctc, eth_prio, attr->ah_attr.sl & 0x7); 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci err = mlx5_core_create_dct(dev, &qp->dct.mdct, qp->dct.in, 42508c2ecf20Sopenharmony_ci MLX5_ST_SZ_BYTES(create_dct_in), out, 42518c2ecf20Sopenharmony_ci sizeof(out)); 42528c2ecf20Sopenharmony_ci if (err) 42538c2ecf20Sopenharmony_ci return err; 42548c2ecf20Sopenharmony_ci resp.dctn = qp->dct.mdct.mqp.qpn; 42558c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, ece_support)) 42568c2ecf20Sopenharmony_ci resp.ece_options = MLX5_GET(create_dct_out, out, ece); 42578c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &resp, resp.response_length); 42588c2ecf20Sopenharmony_ci if (err) { 42598c2ecf20Sopenharmony_ci mlx5_core_destroy_dct(dev, &qp->dct.mdct); 42608c2ecf20Sopenharmony_ci return err; 42618c2ecf20Sopenharmony_ci } 42628c2ecf20Sopenharmony_ci } else { 42638c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "Modify DCT: Invalid transition from %d to %d\n", cur_state, new_state); 42648c2ecf20Sopenharmony_ci return -EINVAL; 42658c2ecf20Sopenharmony_ci } 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci qp->state = new_state; 42688c2ecf20Sopenharmony_ci return 0; 42698c2ecf20Sopenharmony_ci} 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_cistatic bool mlx5_ib_modify_qp_allowed(struct mlx5_ib_dev *dev, 42728c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 42738c2ecf20Sopenharmony_ci enum ib_qp_type qp_type) 42748c2ecf20Sopenharmony_ci{ 42758c2ecf20Sopenharmony_ci if (dev->profile != &raw_eth_profile) 42768c2ecf20Sopenharmony_ci return true; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci if (qp_type == IB_QPT_RAW_PACKET || qp_type == MLX5_IB_QPT_REG_UMR) 42798c2ecf20Sopenharmony_ci return true; 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci /* Internal QP used for wc testing, with NOPs in wq */ 42828c2ecf20Sopenharmony_ci if (qp->flags & MLX5_IB_QP_CREATE_WC_TEST) 42838c2ecf20Sopenharmony_ci return true; 42848c2ecf20Sopenharmony_ci 42858c2ecf20Sopenharmony_ci return false; 42868c2ecf20Sopenharmony_ci} 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_cistatic int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr, 42898c2ecf20Sopenharmony_ci int attr_mask, enum ib_qp_type qp_type) 42908c2ecf20Sopenharmony_ci{ 42918c2ecf20Sopenharmony_ci int log_max_ra_res; 42928c2ecf20Sopenharmony_ci int log_max_ra_req; 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci if (qp_type == MLX5_IB_QPT_DCI) { 42958c2ecf20Sopenharmony_ci log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, 42968c2ecf20Sopenharmony_ci log_max_ra_res_dc); 42978c2ecf20Sopenharmony_ci log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, 42988c2ecf20Sopenharmony_ci log_max_ra_req_dc); 42998c2ecf20Sopenharmony_ci } else { 43008c2ecf20Sopenharmony_ci log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, 43018c2ecf20Sopenharmony_ci log_max_ra_res_qp); 43028c2ecf20Sopenharmony_ci log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, 43038c2ecf20Sopenharmony_ci log_max_ra_req_qp); 43048c2ecf20Sopenharmony_ci } 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && 43078c2ecf20Sopenharmony_ci attr->max_rd_atomic > log_max_ra_res) { 43088c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n", 43098c2ecf20Sopenharmony_ci attr->max_rd_atomic); 43108c2ecf20Sopenharmony_ci return false; 43118c2ecf20Sopenharmony_ci } 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && 43148c2ecf20Sopenharmony_ci attr->max_dest_rd_atomic > log_max_ra_req) { 43158c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n", 43168c2ecf20Sopenharmony_ci attr->max_dest_rd_atomic); 43178c2ecf20Sopenharmony_ci return false; 43188c2ecf20Sopenharmony_ci } 43198c2ecf20Sopenharmony_ci return true; 43208c2ecf20Sopenharmony_ci} 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ciint mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 43238c2ecf20Sopenharmony_ci int attr_mask, struct ib_udata *udata) 43248c2ecf20Sopenharmony_ci{ 43258c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 43268c2ecf20Sopenharmony_ci struct mlx5_ib_modify_qp_resp resp = {}; 43278c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp = to_mqp(ibqp); 43288c2ecf20Sopenharmony_ci struct mlx5_ib_modify_qp ucmd = {}; 43298c2ecf20Sopenharmony_ci enum ib_qp_type qp_type; 43308c2ecf20Sopenharmony_ci enum ib_qp_state cur_state, new_state; 43318c2ecf20Sopenharmony_ci int err = -EINVAL; 43328c2ecf20Sopenharmony_ci int port; 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci if (!mlx5_ib_modify_qp_allowed(dev, qp, ibqp->qp_type)) 43358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci if (ibqp->rwq_ind_tbl) 43388c2ecf20Sopenharmony_ci return -ENOSYS; 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci if (udata && udata->inlen) { 43418c2ecf20Sopenharmony_ci if (udata->inlen < offsetofend(typeof(ucmd), ece_options)) 43428c2ecf20Sopenharmony_ci return -EINVAL; 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci if (udata->inlen > sizeof(ucmd) && 43458c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, sizeof(ucmd), 43468c2ecf20Sopenharmony_ci udata->inlen - sizeof(ucmd))) 43478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, 43508c2ecf20Sopenharmony_ci min(udata->inlen, sizeof(ucmd)))) 43518c2ecf20Sopenharmony_ci return -EFAULT; 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci if (ucmd.comp_mask || 43548c2ecf20Sopenharmony_ci memchr_inv(&ucmd.burst_info.reserved, 0, 43558c2ecf20Sopenharmony_ci sizeof(ucmd.burst_info.reserved))) 43568c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci } 43598c2ecf20Sopenharmony_ci 43608c2ecf20Sopenharmony_ci if (unlikely(ibqp->qp_type == IB_QPT_GSI)) 43618c2ecf20Sopenharmony_ci return mlx5_ib_gsi_modify_qp(ibqp, attr, attr_mask); 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci qp_type = (unlikely(ibqp->qp_type == MLX5_IB_QPT_HW_GSI)) ? IB_QPT_GSI : 43648c2ecf20Sopenharmony_ci qp->type; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci if (qp_type == MLX5_IB_QPT_DCT) 43678c2ecf20Sopenharmony_ci return mlx5_ib_modify_dct(ibqp, attr, attr_mask, &ucmd, udata); 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci mutex_lock(&qp->mutex); 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; 43728c2ecf20Sopenharmony_ci new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci if (!(cur_state == new_state && cur_state == IB_QPS_RESET)) { 43758c2ecf20Sopenharmony_ci port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; 43768c2ecf20Sopenharmony_ci } 43778c2ecf20Sopenharmony_ci 43788c2ecf20Sopenharmony_ci if (qp->flags & IB_QP_CREATE_SOURCE_QPN) { 43798c2ecf20Sopenharmony_ci if (attr_mask & ~(IB_QP_STATE | IB_QP_CUR_STATE)) { 43808c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid attr_mask 0x%x when underlay QP is used\n", 43818c2ecf20Sopenharmony_ci attr_mask); 43828c2ecf20Sopenharmony_ci goto out; 43838c2ecf20Sopenharmony_ci } 43848c2ecf20Sopenharmony_ci } else if (qp_type != MLX5_IB_QPT_REG_UMR && 43858c2ecf20Sopenharmony_ci qp_type != MLX5_IB_QPT_DCI && 43868c2ecf20Sopenharmony_ci !ib_modify_qp_is_ok(cur_state, new_state, qp_type, 43878c2ecf20Sopenharmony_ci attr_mask)) { 43888c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n", 43898c2ecf20Sopenharmony_ci cur_state, new_state, ibqp->qp_type, attr_mask); 43908c2ecf20Sopenharmony_ci goto out; 43918c2ecf20Sopenharmony_ci } else if (qp_type == MLX5_IB_QPT_DCI && 43928c2ecf20Sopenharmony_ci !modify_dci_qp_is_ok(cur_state, new_state, attr_mask)) { 43938c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n", 43948c2ecf20Sopenharmony_ci cur_state, new_state, qp_type, attr_mask); 43958c2ecf20Sopenharmony_ci goto out; 43968c2ecf20Sopenharmony_ci } 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci if ((attr_mask & IB_QP_PORT) && 43998c2ecf20Sopenharmony_ci (attr->port_num == 0 || 44008c2ecf20Sopenharmony_ci attr->port_num > dev->num_ports)) { 44018c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n", 44028c2ecf20Sopenharmony_ci attr->port_num, dev->num_ports); 44038c2ecf20Sopenharmony_ci goto out; 44048c2ecf20Sopenharmony_ci } 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) { 44078c2ecf20Sopenharmony_ci port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; 44088c2ecf20Sopenharmony_ci if (attr->pkey_index >= 44098c2ecf20Sopenharmony_ci dev->mdev->port_caps[port - 1].pkey_table_len) { 44108c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid pkey index %d\n", 44118c2ecf20Sopenharmony_ci attr->pkey_index); 44128c2ecf20Sopenharmony_ci goto out; 44138c2ecf20Sopenharmony_ci } 44148c2ecf20Sopenharmony_ci } 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci if (!validate_rd_atomic(dev, attr, attr_mask, qp_type)) 44178c2ecf20Sopenharmony_ci goto out; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci if (cur_state == new_state && cur_state == IB_QPS_RESET) { 44208c2ecf20Sopenharmony_ci err = 0; 44218c2ecf20Sopenharmony_ci goto out; 44228c2ecf20Sopenharmony_ci } 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state, 44258c2ecf20Sopenharmony_ci new_state, &ucmd, &resp, udata); 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_ci /* resp.response_length is set in ECE supported flows only */ 44288c2ecf20Sopenharmony_ci if (!err && resp.response_length && 44298c2ecf20Sopenharmony_ci udata->outlen >= resp.response_length) 44308c2ecf20Sopenharmony_ci /* Return -EFAULT to the user and expect him to destroy QP. */ 44318c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &resp, resp.response_length); 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ciout: 44348c2ecf20Sopenharmony_ci mutex_unlock(&qp->mutex); 44358c2ecf20Sopenharmony_ci return err; 44368c2ecf20Sopenharmony_ci} 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_cistatic inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state) 44398c2ecf20Sopenharmony_ci{ 44408c2ecf20Sopenharmony_ci switch (mlx5_state) { 44418c2ecf20Sopenharmony_ci case MLX5_QP_STATE_RST: return IB_QPS_RESET; 44428c2ecf20Sopenharmony_ci case MLX5_QP_STATE_INIT: return IB_QPS_INIT; 44438c2ecf20Sopenharmony_ci case MLX5_QP_STATE_RTR: return IB_QPS_RTR; 44448c2ecf20Sopenharmony_ci case MLX5_QP_STATE_RTS: return IB_QPS_RTS; 44458c2ecf20Sopenharmony_ci case MLX5_QP_STATE_SQ_DRAINING: 44468c2ecf20Sopenharmony_ci case MLX5_QP_STATE_SQD: return IB_QPS_SQD; 44478c2ecf20Sopenharmony_ci case MLX5_QP_STATE_SQER: return IB_QPS_SQE; 44488c2ecf20Sopenharmony_ci case MLX5_QP_STATE_ERR: return IB_QPS_ERR; 44498c2ecf20Sopenharmony_ci default: return -1; 44508c2ecf20Sopenharmony_ci } 44518c2ecf20Sopenharmony_ci} 44528c2ecf20Sopenharmony_ci 44538c2ecf20Sopenharmony_cistatic inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state) 44548c2ecf20Sopenharmony_ci{ 44558c2ecf20Sopenharmony_ci switch (mlx5_mig_state) { 44568c2ecf20Sopenharmony_ci case MLX5_QP_PM_ARMED: return IB_MIG_ARMED; 44578c2ecf20Sopenharmony_ci case MLX5_QP_PM_REARM: return IB_MIG_REARM; 44588c2ecf20Sopenharmony_ci case MLX5_QP_PM_MIGRATED: return IB_MIG_MIGRATED; 44598c2ecf20Sopenharmony_ci default: return -1; 44608c2ecf20Sopenharmony_ci } 44618c2ecf20Sopenharmony_ci} 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_cistatic void to_rdma_ah_attr(struct mlx5_ib_dev *ibdev, 44648c2ecf20Sopenharmony_ci struct rdma_ah_attr *ah_attr, void *path) 44658c2ecf20Sopenharmony_ci{ 44668c2ecf20Sopenharmony_ci int port = MLX5_GET(ads, path, vhca_port_num); 44678c2ecf20Sopenharmony_ci int static_rate; 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_ci memset(ah_attr, 0, sizeof(*ah_attr)); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (!port || port > ibdev->num_ports) 44728c2ecf20Sopenharmony_ci return; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, port); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci rdma_ah_set_port_num(ah_attr, port); 44778c2ecf20Sopenharmony_ci rdma_ah_set_sl(ah_attr, MLX5_GET(ads, path, sl)); 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci rdma_ah_set_dlid(ah_attr, MLX5_GET(ads, path, rlid)); 44808c2ecf20Sopenharmony_ci rdma_ah_set_path_bits(ah_attr, MLX5_GET(ads, path, mlid)); 44818c2ecf20Sopenharmony_ci 44828c2ecf20Sopenharmony_ci static_rate = MLX5_GET(ads, path, stat_rate); 44838c2ecf20Sopenharmony_ci rdma_ah_set_static_rate(ah_attr, mlx5_to_ib_rate_map(static_rate)); 44848c2ecf20Sopenharmony_ci if (MLX5_GET(ads, path, grh) || 44858c2ecf20Sopenharmony_ci ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) { 44868c2ecf20Sopenharmony_ci rdma_ah_set_grh(ah_attr, NULL, MLX5_GET(ads, path, flow_label), 44878c2ecf20Sopenharmony_ci MLX5_GET(ads, path, src_addr_index), 44888c2ecf20Sopenharmony_ci MLX5_GET(ads, path, hop_limit), 44898c2ecf20Sopenharmony_ci MLX5_GET(ads, path, tclass)); 44908c2ecf20Sopenharmony_ci rdma_ah_set_dgid_raw(ah_attr, MLX5_ADDR_OF(ads, path, rgid_rip)); 44918c2ecf20Sopenharmony_ci } 44928c2ecf20Sopenharmony_ci} 44938c2ecf20Sopenharmony_ci 44948c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_sq_state(struct mlx5_ib_dev *dev, 44958c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq, 44968c2ecf20Sopenharmony_ci u8 *sq_state) 44978c2ecf20Sopenharmony_ci{ 44988c2ecf20Sopenharmony_ci int err; 44998c2ecf20Sopenharmony_ci 45008c2ecf20Sopenharmony_ci err = mlx5_core_query_sq_state(dev->mdev, sq->base.mqp.qpn, sq_state); 45018c2ecf20Sopenharmony_ci if (err) 45028c2ecf20Sopenharmony_ci goto out; 45038c2ecf20Sopenharmony_ci sq->state = *sq_state; 45048c2ecf20Sopenharmony_ci 45058c2ecf20Sopenharmony_ciout: 45068c2ecf20Sopenharmony_ci return err; 45078c2ecf20Sopenharmony_ci} 45088c2ecf20Sopenharmony_ci 45098c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_rq_state(struct mlx5_ib_dev *dev, 45108c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq, 45118c2ecf20Sopenharmony_ci u8 *rq_state) 45128c2ecf20Sopenharmony_ci{ 45138c2ecf20Sopenharmony_ci void *out; 45148c2ecf20Sopenharmony_ci void *rqc; 45158c2ecf20Sopenharmony_ci int inlen; 45168c2ecf20Sopenharmony_ci int err; 45178c2ecf20Sopenharmony_ci 45188c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(query_rq_out); 45198c2ecf20Sopenharmony_ci out = kvzalloc(inlen, GFP_KERNEL); 45208c2ecf20Sopenharmony_ci if (!out) 45218c2ecf20Sopenharmony_ci return -ENOMEM; 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci err = mlx5_core_query_rq(dev->mdev, rq->base.mqp.qpn, out); 45248c2ecf20Sopenharmony_ci if (err) 45258c2ecf20Sopenharmony_ci goto out; 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(query_rq_out, out, rq_context); 45288c2ecf20Sopenharmony_ci *rq_state = MLX5_GET(rqc, rqc, state); 45298c2ecf20Sopenharmony_ci rq->state = *rq_state; 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ciout: 45328c2ecf20Sopenharmony_ci kvfree(out); 45338c2ecf20Sopenharmony_ci return err; 45348c2ecf20Sopenharmony_ci} 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_cistatic int sqrq_state_to_qp_state(u8 sq_state, u8 rq_state, 45378c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, u8 *qp_state) 45388c2ecf20Sopenharmony_ci{ 45398c2ecf20Sopenharmony_ci static const u8 sqrq_trans[MLX5_RQ_NUM_STATE][MLX5_SQ_NUM_STATE] = { 45408c2ecf20Sopenharmony_ci [MLX5_RQC_STATE_RST] = { 45418c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RST] = IB_QPS_RESET, 45428c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RDY] = MLX5_QP_STATE_BAD, 45438c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_ERR] = MLX5_QP_STATE_BAD, 45448c2ecf20Sopenharmony_ci [MLX5_SQ_STATE_NA] = IB_QPS_RESET, 45458c2ecf20Sopenharmony_ci }, 45468c2ecf20Sopenharmony_ci [MLX5_RQC_STATE_RDY] = { 45478c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RST] = MLX5_QP_STATE, 45488c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RDY] = MLX5_QP_STATE, 45498c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_ERR] = IB_QPS_SQE, 45508c2ecf20Sopenharmony_ci [MLX5_SQ_STATE_NA] = MLX5_QP_STATE, 45518c2ecf20Sopenharmony_ci }, 45528c2ecf20Sopenharmony_ci [MLX5_RQC_STATE_ERR] = { 45538c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RST] = MLX5_QP_STATE_BAD, 45548c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RDY] = MLX5_QP_STATE_BAD, 45558c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_ERR] = IB_QPS_ERR, 45568c2ecf20Sopenharmony_ci [MLX5_SQ_STATE_NA] = IB_QPS_ERR, 45578c2ecf20Sopenharmony_ci }, 45588c2ecf20Sopenharmony_ci [MLX5_RQ_STATE_NA] = { 45598c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RST] = MLX5_QP_STATE, 45608c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_RDY] = MLX5_QP_STATE, 45618c2ecf20Sopenharmony_ci [MLX5_SQC_STATE_ERR] = MLX5_QP_STATE, 45628c2ecf20Sopenharmony_ci [MLX5_SQ_STATE_NA] = MLX5_QP_STATE_BAD, 45638c2ecf20Sopenharmony_ci }, 45648c2ecf20Sopenharmony_ci }; 45658c2ecf20Sopenharmony_ci 45668c2ecf20Sopenharmony_ci *qp_state = sqrq_trans[rq_state][sq_state]; 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci if (*qp_state == MLX5_QP_STATE_BAD) { 45698c2ecf20Sopenharmony_ci WARN(1, "Buggy Raw Packet QP state, SQ 0x%x state: 0x%x, RQ 0x%x state: 0x%x", 45708c2ecf20Sopenharmony_ci qp->raw_packet_qp.sq.base.mqp.qpn, sq_state, 45718c2ecf20Sopenharmony_ci qp->raw_packet_qp.rq.base.mqp.qpn, rq_state); 45728c2ecf20Sopenharmony_ci return -EINVAL; 45738c2ecf20Sopenharmony_ci } 45748c2ecf20Sopenharmony_ci 45758c2ecf20Sopenharmony_ci if (*qp_state == MLX5_QP_STATE) 45768c2ecf20Sopenharmony_ci *qp_state = qp->state; 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci return 0; 45798c2ecf20Sopenharmony_ci} 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_state(struct mlx5_ib_dev *dev, 45828c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp, 45838c2ecf20Sopenharmony_ci u8 *raw_packet_qp_state) 45848c2ecf20Sopenharmony_ci{ 45858c2ecf20Sopenharmony_ci struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; 45868c2ecf20Sopenharmony_ci struct mlx5_ib_sq *sq = &raw_packet_qp->sq; 45878c2ecf20Sopenharmony_ci struct mlx5_ib_rq *rq = &raw_packet_qp->rq; 45888c2ecf20Sopenharmony_ci int err; 45898c2ecf20Sopenharmony_ci u8 sq_state = MLX5_SQ_STATE_NA; 45908c2ecf20Sopenharmony_ci u8 rq_state = MLX5_RQ_STATE_NA; 45918c2ecf20Sopenharmony_ci 45928c2ecf20Sopenharmony_ci if (qp->sq.wqe_cnt) { 45938c2ecf20Sopenharmony_ci err = query_raw_packet_qp_sq_state(dev, sq, &sq_state); 45948c2ecf20Sopenharmony_ci if (err) 45958c2ecf20Sopenharmony_ci return err; 45968c2ecf20Sopenharmony_ci } 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci if (qp->rq.wqe_cnt) { 45998c2ecf20Sopenharmony_ci err = query_raw_packet_qp_rq_state(dev, rq, &rq_state); 46008c2ecf20Sopenharmony_ci if (err) 46018c2ecf20Sopenharmony_ci return err; 46028c2ecf20Sopenharmony_ci } 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci return sqrq_state_to_qp_state(sq_state, rq_state, qp, 46058c2ecf20Sopenharmony_ci raw_packet_qp_state); 46068c2ecf20Sopenharmony_ci} 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_cistatic int query_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, 46098c2ecf20Sopenharmony_ci struct ib_qp_attr *qp_attr) 46108c2ecf20Sopenharmony_ci{ 46118c2ecf20Sopenharmony_ci int outlen = MLX5_ST_SZ_BYTES(query_qp_out); 46128c2ecf20Sopenharmony_ci void *qpc, *pri_path, *alt_path; 46138c2ecf20Sopenharmony_ci u32 *outb; 46148c2ecf20Sopenharmony_ci int err; 46158c2ecf20Sopenharmony_ci 46168c2ecf20Sopenharmony_ci outb = kzalloc(outlen, GFP_KERNEL); 46178c2ecf20Sopenharmony_ci if (!outb) 46188c2ecf20Sopenharmony_ci return -ENOMEM; 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci err = mlx5_core_qp_query(dev, &qp->trans_qp.base.mqp, outb, outlen); 46218c2ecf20Sopenharmony_ci if (err) 46228c2ecf20Sopenharmony_ci goto out; 46238c2ecf20Sopenharmony_ci 46248c2ecf20Sopenharmony_ci qpc = MLX5_ADDR_OF(query_qp_out, outb, qpc); 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci qp->state = to_ib_qp_state(MLX5_GET(qpc, qpc, state)); 46278c2ecf20Sopenharmony_ci if (MLX5_GET(qpc, qpc, state) == MLX5_QP_STATE_SQ_DRAINING) 46288c2ecf20Sopenharmony_ci qp_attr->sq_draining = 1; 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci qp_attr->path_mtu = MLX5_GET(qpc, qpc, mtu); 46318c2ecf20Sopenharmony_ci qp_attr->path_mig_state = to_ib_mig_state(MLX5_GET(qpc, qpc, pm_state)); 46328c2ecf20Sopenharmony_ci qp_attr->qkey = MLX5_GET(qpc, qpc, q_key); 46338c2ecf20Sopenharmony_ci qp_attr->rq_psn = MLX5_GET(qpc, qpc, next_rcv_psn); 46348c2ecf20Sopenharmony_ci qp_attr->sq_psn = MLX5_GET(qpc, qpc, next_send_psn); 46358c2ecf20Sopenharmony_ci qp_attr->dest_qp_num = MLX5_GET(qpc, qpc, remote_qpn); 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci if (MLX5_GET(qpc, qpc, rre)) 46388c2ecf20Sopenharmony_ci qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ; 46398c2ecf20Sopenharmony_ci if (MLX5_GET(qpc, qpc, rwe)) 46408c2ecf20Sopenharmony_ci qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_WRITE; 46418c2ecf20Sopenharmony_ci if (MLX5_GET(qpc, qpc, rae)) 46428c2ecf20Sopenharmony_ci qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_ATOMIC; 46438c2ecf20Sopenharmony_ci 46448c2ecf20Sopenharmony_ci qp_attr->max_rd_atomic = 1 << MLX5_GET(qpc, qpc, log_sra_max); 46458c2ecf20Sopenharmony_ci qp_attr->max_dest_rd_atomic = 1 << MLX5_GET(qpc, qpc, log_rra_max); 46468c2ecf20Sopenharmony_ci qp_attr->min_rnr_timer = MLX5_GET(qpc, qpc, min_rnr_nak); 46478c2ecf20Sopenharmony_ci qp_attr->retry_cnt = MLX5_GET(qpc, qpc, retry_count); 46488c2ecf20Sopenharmony_ci qp_attr->rnr_retry = MLX5_GET(qpc, qpc, rnr_retry); 46498c2ecf20Sopenharmony_ci 46508c2ecf20Sopenharmony_ci pri_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path); 46518c2ecf20Sopenharmony_ci alt_path = MLX5_ADDR_OF(qpc, qpc, secondary_address_path); 46528c2ecf20Sopenharmony_ci 46538c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) { 46548c2ecf20Sopenharmony_ci to_rdma_ah_attr(dev, &qp_attr->ah_attr, pri_path); 46558c2ecf20Sopenharmony_ci to_rdma_ah_attr(dev, &qp_attr->alt_ah_attr, alt_path); 46568c2ecf20Sopenharmony_ci qp_attr->alt_pkey_index = MLX5_GET(ads, alt_path, pkey_index); 46578c2ecf20Sopenharmony_ci qp_attr->alt_port_num = MLX5_GET(ads, alt_path, vhca_port_num); 46588c2ecf20Sopenharmony_ci } 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_ci qp_attr->pkey_index = MLX5_GET(ads, pri_path, pkey_index); 46618c2ecf20Sopenharmony_ci qp_attr->port_num = MLX5_GET(ads, pri_path, vhca_port_num); 46628c2ecf20Sopenharmony_ci qp_attr->timeout = MLX5_GET(ads, pri_path, ack_timeout); 46638c2ecf20Sopenharmony_ci qp_attr->alt_timeout = MLX5_GET(ads, alt_path, ack_timeout); 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_ciout: 46668c2ecf20Sopenharmony_ci kfree(outb); 46678c2ecf20Sopenharmony_ci return err; 46688c2ecf20Sopenharmony_ci} 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_cistatic int mlx5_ib_dct_query_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *mqp, 46718c2ecf20Sopenharmony_ci struct ib_qp_attr *qp_attr, int qp_attr_mask, 46728c2ecf20Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr) 46738c2ecf20Sopenharmony_ci{ 46748c2ecf20Sopenharmony_ci struct mlx5_core_dct *dct = &mqp->dct.mdct; 46758c2ecf20Sopenharmony_ci u32 *out; 46768c2ecf20Sopenharmony_ci u32 access_flags = 0; 46778c2ecf20Sopenharmony_ci int outlen = MLX5_ST_SZ_BYTES(query_dct_out); 46788c2ecf20Sopenharmony_ci void *dctc; 46798c2ecf20Sopenharmony_ci int err; 46808c2ecf20Sopenharmony_ci int supported_mask = IB_QP_STATE | 46818c2ecf20Sopenharmony_ci IB_QP_ACCESS_FLAGS | 46828c2ecf20Sopenharmony_ci IB_QP_PORT | 46838c2ecf20Sopenharmony_ci IB_QP_MIN_RNR_TIMER | 46848c2ecf20Sopenharmony_ci IB_QP_AV | 46858c2ecf20Sopenharmony_ci IB_QP_PATH_MTU | 46868c2ecf20Sopenharmony_ci IB_QP_PKEY_INDEX; 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci if (qp_attr_mask & ~supported_mask) 46898c2ecf20Sopenharmony_ci return -EINVAL; 46908c2ecf20Sopenharmony_ci if (mqp->state != IB_QPS_RTR) 46918c2ecf20Sopenharmony_ci return -EINVAL; 46928c2ecf20Sopenharmony_ci 46938c2ecf20Sopenharmony_ci out = kzalloc(outlen, GFP_KERNEL); 46948c2ecf20Sopenharmony_ci if (!out) 46958c2ecf20Sopenharmony_ci return -ENOMEM; 46968c2ecf20Sopenharmony_ci 46978c2ecf20Sopenharmony_ci err = mlx5_core_dct_query(dev, dct, out, outlen); 46988c2ecf20Sopenharmony_ci if (err) 46998c2ecf20Sopenharmony_ci goto out; 47008c2ecf20Sopenharmony_ci 47018c2ecf20Sopenharmony_ci dctc = MLX5_ADDR_OF(query_dct_out, out, dct_context_entry); 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_STATE) 47048c2ecf20Sopenharmony_ci qp_attr->qp_state = IB_QPS_RTR; 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_ACCESS_FLAGS) { 47078c2ecf20Sopenharmony_ci if (MLX5_GET(dctc, dctc, rre)) 47088c2ecf20Sopenharmony_ci access_flags |= IB_ACCESS_REMOTE_READ; 47098c2ecf20Sopenharmony_ci if (MLX5_GET(dctc, dctc, rwe)) 47108c2ecf20Sopenharmony_ci access_flags |= IB_ACCESS_REMOTE_WRITE; 47118c2ecf20Sopenharmony_ci if (MLX5_GET(dctc, dctc, rae)) 47128c2ecf20Sopenharmony_ci access_flags |= IB_ACCESS_REMOTE_ATOMIC; 47138c2ecf20Sopenharmony_ci qp_attr->qp_access_flags = access_flags; 47148c2ecf20Sopenharmony_ci } 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_PORT) 47178c2ecf20Sopenharmony_ci qp_attr->port_num = MLX5_GET(dctc, dctc, port); 47188c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_MIN_RNR_TIMER) 47198c2ecf20Sopenharmony_ci qp_attr->min_rnr_timer = MLX5_GET(dctc, dctc, min_rnr_nak); 47208c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_AV) { 47218c2ecf20Sopenharmony_ci qp_attr->ah_attr.grh.traffic_class = MLX5_GET(dctc, dctc, tclass); 47228c2ecf20Sopenharmony_ci qp_attr->ah_attr.grh.flow_label = MLX5_GET(dctc, dctc, flow_label); 47238c2ecf20Sopenharmony_ci qp_attr->ah_attr.grh.sgid_index = MLX5_GET(dctc, dctc, my_addr_index); 47248c2ecf20Sopenharmony_ci qp_attr->ah_attr.grh.hop_limit = MLX5_GET(dctc, dctc, hop_limit); 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_PATH_MTU) 47278c2ecf20Sopenharmony_ci qp_attr->path_mtu = MLX5_GET(dctc, dctc, mtu); 47288c2ecf20Sopenharmony_ci if (qp_attr_mask & IB_QP_PKEY_INDEX) 47298c2ecf20Sopenharmony_ci qp_attr->pkey_index = MLX5_GET(dctc, dctc, pkey_index); 47308c2ecf20Sopenharmony_ciout: 47318c2ecf20Sopenharmony_ci kfree(out); 47328c2ecf20Sopenharmony_ci return err; 47338c2ecf20Sopenharmony_ci} 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ciint mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, 47368c2ecf20Sopenharmony_ci int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) 47378c2ecf20Sopenharmony_ci{ 47388c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibqp->device); 47398c2ecf20Sopenharmony_ci struct mlx5_ib_qp *qp = to_mqp(ibqp); 47408c2ecf20Sopenharmony_ci int err = 0; 47418c2ecf20Sopenharmony_ci u8 raw_packet_qp_state; 47428c2ecf20Sopenharmony_ci 47438c2ecf20Sopenharmony_ci if (ibqp->rwq_ind_tbl) 47448c2ecf20Sopenharmony_ci return -ENOSYS; 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci if (unlikely(ibqp->qp_type == IB_QPT_GSI)) 47478c2ecf20Sopenharmony_ci return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask, 47488c2ecf20Sopenharmony_ci qp_init_attr); 47498c2ecf20Sopenharmony_ci 47508c2ecf20Sopenharmony_ci /* Not all of output fields are applicable, make sure to zero them */ 47518c2ecf20Sopenharmony_ci memset(qp_init_attr, 0, sizeof(*qp_init_attr)); 47528c2ecf20Sopenharmony_ci memset(qp_attr, 0, sizeof(*qp_attr)); 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_ci if (unlikely(qp->type == MLX5_IB_QPT_DCT)) 47558c2ecf20Sopenharmony_ci return mlx5_ib_dct_query_qp(dev, qp, qp_attr, 47568c2ecf20Sopenharmony_ci qp_attr_mask, qp_init_attr); 47578c2ecf20Sopenharmony_ci 47588c2ecf20Sopenharmony_ci mutex_lock(&qp->mutex); 47598c2ecf20Sopenharmony_ci 47608c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET || 47618c2ecf20Sopenharmony_ci qp->flags & IB_QP_CREATE_SOURCE_QPN) { 47628c2ecf20Sopenharmony_ci err = query_raw_packet_qp_state(dev, qp, &raw_packet_qp_state); 47638c2ecf20Sopenharmony_ci if (err) 47648c2ecf20Sopenharmony_ci goto out; 47658c2ecf20Sopenharmony_ci qp->state = raw_packet_qp_state; 47668c2ecf20Sopenharmony_ci qp_attr->port_num = 1; 47678c2ecf20Sopenharmony_ci } else { 47688c2ecf20Sopenharmony_ci err = query_qp_attr(dev, qp, qp_attr); 47698c2ecf20Sopenharmony_ci if (err) 47708c2ecf20Sopenharmony_ci goto out; 47718c2ecf20Sopenharmony_ci } 47728c2ecf20Sopenharmony_ci 47738c2ecf20Sopenharmony_ci qp_attr->qp_state = qp->state; 47748c2ecf20Sopenharmony_ci qp_attr->cur_qp_state = qp_attr->qp_state; 47758c2ecf20Sopenharmony_ci qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; 47768c2ecf20Sopenharmony_ci qp_attr->cap.max_recv_sge = qp->rq.max_gs; 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_ci if (!ibqp->uobject) { 47798c2ecf20Sopenharmony_ci qp_attr->cap.max_send_wr = qp->sq.max_post; 47808c2ecf20Sopenharmony_ci qp_attr->cap.max_send_sge = qp->sq.max_gs; 47818c2ecf20Sopenharmony_ci qp_init_attr->qp_context = ibqp->qp_context; 47828c2ecf20Sopenharmony_ci } else { 47838c2ecf20Sopenharmony_ci qp_attr->cap.max_send_wr = 0; 47848c2ecf20Sopenharmony_ci qp_attr->cap.max_send_sge = 0; 47858c2ecf20Sopenharmony_ci } 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_ci qp_init_attr->qp_type = ibqp->qp_type; 47888c2ecf20Sopenharmony_ci qp_init_attr->recv_cq = ibqp->recv_cq; 47898c2ecf20Sopenharmony_ci qp_init_attr->send_cq = ibqp->send_cq; 47908c2ecf20Sopenharmony_ci qp_init_attr->srq = ibqp->srq; 47918c2ecf20Sopenharmony_ci qp_attr->cap.max_inline_data = qp->max_inline_data; 47928c2ecf20Sopenharmony_ci 47938c2ecf20Sopenharmony_ci qp_init_attr->cap = qp_attr->cap; 47948c2ecf20Sopenharmony_ci 47958c2ecf20Sopenharmony_ci qp_init_attr->create_flags = qp->flags; 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_ci qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ? 47988c2ecf20Sopenharmony_ci IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 47998c2ecf20Sopenharmony_ci 48008c2ecf20Sopenharmony_ciout: 48018c2ecf20Sopenharmony_ci mutex_unlock(&qp->mutex); 48028c2ecf20Sopenharmony_ci return err; 48038c2ecf20Sopenharmony_ci} 48048c2ecf20Sopenharmony_ci 48058c2ecf20Sopenharmony_ciint mlx5_ib_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata) 48068c2ecf20Sopenharmony_ci{ 48078c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibxrcd->device); 48088c2ecf20Sopenharmony_ci struct mlx5_ib_xrcd *xrcd = to_mxrcd(ibxrcd); 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, xrc)) 48118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 48128c2ecf20Sopenharmony_ci 48138c2ecf20Sopenharmony_ci return mlx5_cmd_xrcd_alloc(dev->mdev, &xrcd->xrcdn, 0); 48148c2ecf20Sopenharmony_ci} 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_ciint mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd, struct ib_udata *udata) 48178c2ecf20Sopenharmony_ci{ 48188c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(xrcd->device); 48198c2ecf20Sopenharmony_ci u32 xrcdn = to_mxrcd(xrcd)->xrcdn; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci return mlx5_cmd_xrcd_dealloc(dev->mdev, xrcdn, 0); 48228c2ecf20Sopenharmony_ci} 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_cistatic void mlx5_ib_wq_event(struct mlx5_core_qp *core_qp, int type) 48258c2ecf20Sopenharmony_ci{ 48268c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq = to_mibrwq(core_qp); 48278c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(rwq->ibwq.device); 48288c2ecf20Sopenharmony_ci struct ib_event event; 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci if (rwq->ibwq.event_handler) { 48318c2ecf20Sopenharmony_ci event.device = rwq->ibwq.device; 48328c2ecf20Sopenharmony_ci event.element.wq = &rwq->ibwq; 48338c2ecf20Sopenharmony_ci switch (type) { 48348c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_WQ_CATAS_ERROR: 48358c2ecf20Sopenharmony_ci event.event = IB_EVENT_WQ_FATAL; 48368c2ecf20Sopenharmony_ci break; 48378c2ecf20Sopenharmony_ci default: 48388c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "Unexpected event type %d on WQ %06x\n", type, core_qp->qpn); 48398c2ecf20Sopenharmony_ci return; 48408c2ecf20Sopenharmony_ci } 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci rwq->ibwq.event_handler(&event, rwq->ibwq.wq_context); 48438c2ecf20Sopenharmony_ci } 48448c2ecf20Sopenharmony_ci} 48458c2ecf20Sopenharmony_ci 48468c2ecf20Sopenharmony_cistatic int set_delay_drop(struct mlx5_ib_dev *dev) 48478c2ecf20Sopenharmony_ci{ 48488c2ecf20Sopenharmony_ci int err = 0; 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci mutex_lock(&dev->delay_drop.lock); 48518c2ecf20Sopenharmony_ci if (dev->delay_drop.activate) 48528c2ecf20Sopenharmony_ci goto out; 48538c2ecf20Sopenharmony_ci 48548c2ecf20Sopenharmony_ci err = mlx5_core_set_delay_drop(dev, dev->delay_drop.timeout); 48558c2ecf20Sopenharmony_ci if (err) 48568c2ecf20Sopenharmony_ci goto out; 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_ci dev->delay_drop.activate = true; 48598c2ecf20Sopenharmony_ciout: 48608c2ecf20Sopenharmony_ci mutex_unlock(&dev->delay_drop.lock); 48618c2ecf20Sopenharmony_ci 48628c2ecf20Sopenharmony_ci if (!err) 48638c2ecf20Sopenharmony_ci atomic_inc(&dev->delay_drop.rqs_cnt); 48648c2ecf20Sopenharmony_ci return err; 48658c2ecf20Sopenharmony_ci} 48668c2ecf20Sopenharmony_ci 48678c2ecf20Sopenharmony_cistatic int create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd, 48688c2ecf20Sopenharmony_ci struct ib_wq_init_attr *init_attr) 48698c2ecf20Sopenharmony_ci{ 48708c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev; 48718c2ecf20Sopenharmony_ci int has_net_offloads; 48728c2ecf20Sopenharmony_ci __be64 *rq_pas0; 48738c2ecf20Sopenharmony_ci void *in; 48748c2ecf20Sopenharmony_ci void *rqc; 48758c2ecf20Sopenharmony_ci void *wq; 48768c2ecf20Sopenharmony_ci int inlen; 48778c2ecf20Sopenharmony_ci int err; 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci dev = to_mdev(pd->device); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas; 48828c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 48838c2ecf20Sopenharmony_ci if (!in) 48848c2ecf20Sopenharmony_ci return -ENOMEM; 48858c2ecf20Sopenharmony_ci 48868c2ecf20Sopenharmony_ci MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid); 48878c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(create_rq_in, in, ctx); 48888c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, mem_rq_type, 48898c2ecf20Sopenharmony_ci MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE); 48908c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, user_index, rwq->user_index); 48918c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, cqn, to_mcq(init_attr->cq)->mcq.cqn); 48928c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); 48938c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, flush_in_error_en, 1); 48948c2ecf20Sopenharmony_ci wq = MLX5_ADDR_OF(rqc, rqc, wq); 48958c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, wq_type, 48968c2ecf20Sopenharmony_ci rwq->create_flags & MLX5_IB_WQ_FLAGS_STRIDING_RQ ? 48978c2ecf20Sopenharmony_ci MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ : MLX5_WQ_TYPE_CYCLIC); 48988c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_WQ_FLAGS_PCI_WRITE_END_PADDING) { 48998c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, end_pad)) { 49008c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Scatter end padding is not supported\n"); 49018c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 49028c2ecf20Sopenharmony_ci goto out; 49038c2ecf20Sopenharmony_ci } else { 49048c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN); 49058c2ecf20Sopenharmony_ci } 49068c2ecf20Sopenharmony_ci } 49078c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_stride, rwq->log_rq_stride); 49088c2ecf20Sopenharmony_ci if (rwq->create_flags & MLX5_IB_WQ_FLAGS_STRIDING_RQ) { 49098c2ecf20Sopenharmony_ci /* 49108c2ecf20Sopenharmony_ci * In Firmware number of strides in each WQE is: 49118c2ecf20Sopenharmony_ci * "512 * 2^single_wqe_log_num_of_strides" 49128c2ecf20Sopenharmony_ci * Values 3 to 8 are accepted as 10 to 15, 9 to 18 are 49138c2ecf20Sopenharmony_ci * accepted as 0 to 9 49148c2ecf20Sopenharmony_ci */ 49158c2ecf20Sopenharmony_ci static const u8 fw_map[] = { 10, 11, 12, 13, 14, 15, 0, 1, 49168c2ecf20Sopenharmony_ci 2, 3, 4, 5, 6, 7, 8, 9 }; 49178c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, two_byte_shift_en, rwq->two_byte_shift_en); 49188c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wqe_stride_size, 49198c2ecf20Sopenharmony_ci rwq->single_stride_log_num_of_bytes - 49208c2ecf20Sopenharmony_ci MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES); 49218c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wqe_num_of_strides, 49228c2ecf20Sopenharmony_ci fw_map[rwq->log_num_strides - 49238c2ecf20Sopenharmony_ci MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES]); 49248c2ecf20Sopenharmony_ci } 49258c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_sz, rwq->log_rq_size); 49268c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, pd, to_mpd(pd)->pdn); 49278c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, page_offset, rwq->rq_page_offset); 49288c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, log_wq_pg_sz, rwq->log_page_size); 49298c2ecf20Sopenharmony_ci MLX5_SET(wq, wq, wq_signature, rwq->wq_sig); 49308c2ecf20Sopenharmony_ci MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma); 49318c2ecf20Sopenharmony_ci has_net_offloads = MLX5_CAP_GEN(dev->mdev, eth_net_offloads); 49328c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_WQ_FLAGS_CVLAN_STRIPPING) { 49338c2ecf20Sopenharmony_ci if (!(has_net_offloads && MLX5_CAP_ETH(dev->mdev, vlan_cap))) { 49348c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "VLAN offloads are not supported\n"); 49358c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 49368c2ecf20Sopenharmony_ci goto out; 49378c2ecf20Sopenharmony_ci } 49388c2ecf20Sopenharmony_ci } else { 49398c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, vsd, 1); 49408c2ecf20Sopenharmony_ci } 49418c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_WQ_FLAGS_SCATTER_FCS) { 49428c2ecf20Sopenharmony_ci if (!(has_net_offloads && MLX5_CAP_ETH(dev->mdev, scatter_fcs))) { 49438c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Scatter FCS is not supported\n"); 49448c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 49458c2ecf20Sopenharmony_ci goto out; 49468c2ecf20Sopenharmony_ci } 49478c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, scatter_fcs, 1); 49488c2ecf20Sopenharmony_ci } 49498c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) { 49508c2ecf20Sopenharmony_ci if (!(dev->ib_dev.attrs.raw_packet_caps & 49518c2ecf20Sopenharmony_ci IB_RAW_PACKET_CAP_DELAY_DROP)) { 49528c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Delay drop is not supported\n"); 49538c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 49548c2ecf20Sopenharmony_ci goto out; 49558c2ecf20Sopenharmony_ci } 49568c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, delay_drop_en, 1); 49578c2ecf20Sopenharmony_ci } 49588c2ecf20Sopenharmony_ci rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas); 49598c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0); 49608c2ecf20Sopenharmony_ci err = mlx5_core_create_rq_tracked(dev, in, inlen, &rwq->core_qp); 49618c2ecf20Sopenharmony_ci if (!err && init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) { 49628c2ecf20Sopenharmony_ci err = set_delay_drop(dev); 49638c2ecf20Sopenharmony_ci if (err) { 49648c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "Failed to enable delay drop err=%d\n", 49658c2ecf20Sopenharmony_ci err); 49668c2ecf20Sopenharmony_ci mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp); 49678c2ecf20Sopenharmony_ci } else { 49688c2ecf20Sopenharmony_ci rwq->create_flags |= MLX5_IB_WQ_FLAGS_DELAY_DROP; 49698c2ecf20Sopenharmony_ci } 49708c2ecf20Sopenharmony_ci } 49718c2ecf20Sopenharmony_ciout: 49728c2ecf20Sopenharmony_ci kvfree(in); 49738c2ecf20Sopenharmony_ci return err; 49748c2ecf20Sopenharmony_ci} 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_cistatic int set_user_rq_size(struct mlx5_ib_dev *dev, 49778c2ecf20Sopenharmony_ci struct ib_wq_init_attr *wq_init_attr, 49788c2ecf20Sopenharmony_ci struct mlx5_ib_create_wq *ucmd, 49798c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq) 49808c2ecf20Sopenharmony_ci{ 49818c2ecf20Sopenharmony_ci /* Sanity check RQ size before proceeding */ 49828c2ecf20Sopenharmony_ci if (wq_init_attr->max_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_wq_sz))) 49838c2ecf20Sopenharmony_ci return -EINVAL; 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ci if (!ucmd->rq_wqe_count) 49868c2ecf20Sopenharmony_ci return -EINVAL; 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci rwq->wqe_count = ucmd->rq_wqe_count; 49898c2ecf20Sopenharmony_ci rwq->wqe_shift = ucmd->rq_wqe_shift; 49908c2ecf20Sopenharmony_ci if (check_shl_overflow(rwq->wqe_count, rwq->wqe_shift, &rwq->buf_size)) 49918c2ecf20Sopenharmony_ci return -EINVAL; 49928c2ecf20Sopenharmony_ci 49938c2ecf20Sopenharmony_ci rwq->log_rq_stride = rwq->wqe_shift; 49948c2ecf20Sopenharmony_ci rwq->log_rq_size = ilog2(rwq->wqe_count); 49958c2ecf20Sopenharmony_ci return 0; 49968c2ecf20Sopenharmony_ci} 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_cistatic bool log_of_strides_valid(struct mlx5_ib_dev *dev, u32 log_num_strides) 49998c2ecf20Sopenharmony_ci{ 50008c2ecf20Sopenharmony_ci if ((log_num_strides > MLX5_MAX_SINGLE_WQE_LOG_NUM_STRIDES) || 50018c2ecf20Sopenharmony_ci (log_num_strides < MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES)) 50028c2ecf20Sopenharmony_ci return false; 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, ext_stride_num_range) && 50058c2ecf20Sopenharmony_ci (log_num_strides < MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES)) 50068c2ecf20Sopenharmony_ci return false; 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci return true; 50098c2ecf20Sopenharmony_ci} 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_cistatic int prepare_user_rq(struct ib_pd *pd, 50128c2ecf20Sopenharmony_ci struct ib_wq_init_attr *init_attr, 50138c2ecf20Sopenharmony_ci struct ib_udata *udata, 50148c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq) 50158c2ecf20Sopenharmony_ci{ 50168c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(pd->device); 50178c2ecf20Sopenharmony_ci struct mlx5_ib_create_wq ucmd = {}; 50188c2ecf20Sopenharmony_ci int err; 50198c2ecf20Sopenharmony_ci size_t required_cmd_sz; 50208c2ecf20Sopenharmony_ci 50218c2ecf20Sopenharmony_ci required_cmd_sz = offsetofend(struct mlx5_ib_create_wq, 50228c2ecf20Sopenharmony_ci single_stride_log_num_of_bytes); 50238c2ecf20Sopenharmony_ci if (udata->inlen < required_cmd_sz) { 50248c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid inlen\n"); 50258c2ecf20Sopenharmony_ci return -EINVAL; 50268c2ecf20Sopenharmony_ci } 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci if (udata->inlen > sizeof(ucmd) && 50298c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, sizeof(ucmd), 50308c2ecf20Sopenharmony_ci udata->inlen - sizeof(ucmd))) { 50318c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "inlen is not supported\n"); 50328c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 50338c2ecf20Sopenharmony_ci } 50348c2ecf20Sopenharmony_ci 50358c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) { 50368c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "copy failed\n"); 50378c2ecf20Sopenharmony_ci return -EFAULT; 50388c2ecf20Sopenharmony_ci } 50398c2ecf20Sopenharmony_ci 50408c2ecf20Sopenharmony_ci if (ucmd.comp_mask & (~MLX5_IB_CREATE_WQ_STRIDING_RQ)) { 50418c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid comp mask\n"); 50428c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 50438c2ecf20Sopenharmony_ci } else if (ucmd.comp_mask & MLX5_IB_CREATE_WQ_STRIDING_RQ) { 50448c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, striding_rq)) { 50458c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Striding RQ is not supported\n"); 50468c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 50478c2ecf20Sopenharmony_ci } 50488c2ecf20Sopenharmony_ci if ((ucmd.single_stride_log_num_of_bytes < 50498c2ecf20Sopenharmony_ci MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES) || 50508c2ecf20Sopenharmony_ci (ucmd.single_stride_log_num_of_bytes > 50518c2ecf20Sopenharmony_ci MLX5_MAX_SINGLE_STRIDE_LOG_NUM_BYTES)) { 50528c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Invalid log stride size (%u. Range is %u - %u)\n", 50538c2ecf20Sopenharmony_ci ucmd.single_stride_log_num_of_bytes, 50548c2ecf20Sopenharmony_ci MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES, 50558c2ecf20Sopenharmony_ci MLX5_MAX_SINGLE_STRIDE_LOG_NUM_BYTES); 50568c2ecf20Sopenharmony_ci return -EINVAL; 50578c2ecf20Sopenharmony_ci } 50588c2ecf20Sopenharmony_ci if (!log_of_strides_valid(dev, 50598c2ecf20Sopenharmony_ci ucmd.single_wqe_log_num_of_strides)) { 50608c2ecf20Sopenharmony_ci mlx5_ib_dbg( 50618c2ecf20Sopenharmony_ci dev, 50628c2ecf20Sopenharmony_ci "Invalid log num strides (%u. Range is %u - %u)\n", 50638c2ecf20Sopenharmony_ci ucmd.single_wqe_log_num_of_strides, 50648c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, ext_stride_num_range) ? 50658c2ecf20Sopenharmony_ci MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES : 50668c2ecf20Sopenharmony_ci MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES, 50678c2ecf20Sopenharmony_ci MLX5_MAX_SINGLE_WQE_LOG_NUM_STRIDES); 50688c2ecf20Sopenharmony_ci return -EINVAL; 50698c2ecf20Sopenharmony_ci } 50708c2ecf20Sopenharmony_ci rwq->single_stride_log_num_of_bytes = 50718c2ecf20Sopenharmony_ci ucmd.single_stride_log_num_of_bytes; 50728c2ecf20Sopenharmony_ci rwq->log_num_strides = ucmd.single_wqe_log_num_of_strides; 50738c2ecf20Sopenharmony_ci rwq->two_byte_shift_en = !!ucmd.two_byte_shift_en; 50748c2ecf20Sopenharmony_ci rwq->create_flags |= MLX5_IB_WQ_FLAGS_STRIDING_RQ; 50758c2ecf20Sopenharmony_ci } 50768c2ecf20Sopenharmony_ci 50778c2ecf20Sopenharmony_ci err = set_user_rq_size(dev, init_attr, &ucmd, rwq); 50788c2ecf20Sopenharmony_ci if (err) { 50798c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 50808c2ecf20Sopenharmony_ci return err; 50818c2ecf20Sopenharmony_ci } 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci err = create_user_rq(dev, pd, udata, rwq, &ucmd); 50848c2ecf20Sopenharmony_ci if (err) { 50858c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "err %d\n", err); 50868c2ecf20Sopenharmony_ci return err; 50878c2ecf20Sopenharmony_ci } 50888c2ecf20Sopenharmony_ci 50898c2ecf20Sopenharmony_ci rwq->user_index = ucmd.user_index; 50908c2ecf20Sopenharmony_ci return 0; 50918c2ecf20Sopenharmony_ci} 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_cistruct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd, 50948c2ecf20Sopenharmony_ci struct ib_wq_init_attr *init_attr, 50958c2ecf20Sopenharmony_ci struct ib_udata *udata) 50968c2ecf20Sopenharmony_ci{ 50978c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev; 50988c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq; 50998c2ecf20Sopenharmony_ci struct mlx5_ib_create_wq_resp resp = {}; 51008c2ecf20Sopenharmony_ci size_t min_resp_len; 51018c2ecf20Sopenharmony_ci int err; 51028c2ecf20Sopenharmony_ci 51038c2ecf20Sopenharmony_ci if (!udata) 51048c2ecf20Sopenharmony_ci return ERR_PTR(-ENOSYS); 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci min_resp_len = offsetofend(struct mlx5_ib_create_wq_resp, reserved); 51078c2ecf20Sopenharmony_ci if (udata->outlen && udata->outlen < min_resp_len) 51088c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 51098c2ecf20Sopenharmony_ci 51108c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_RAWIO) && 51118c2ecf20Sopenharmony_ci init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) 51128c2ecf20Sopenharmony_ci return ERR_PTR(-EPERM); 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci dev = to_mdev(pd->device); 51158c2ecf20Sopenharmony_ci switch (init_attr->wq_type) { 51168c2ecf20Sopenharmony_ci case IB_WQT_RQ: 51178c2ecf20Sopenharmony_ci rwq = kzalloc(sizeof(*rwq), GFP_KERNEL); 51188c2ecf20Sopenharmony_ci if (!rwq) 51198c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 51208c2ecf20Sopenharmony_ci err = prepare_user_rq(pd, init_attr, udata, rwq); 51218c2ecf20Sopenharmony_ci if (err) 51228c2ecf20Sopenharmony_ci goto err; 51238c2ecf20Sopenharmony_ci err = create_rq(rwq, pd, init_attr); 51248c2ecf20Sopenharmony_ci if (err) 51258c2ecf20Sopenharmony_ci goto err_user_rq; 51268c2ecf20Sopenharmony_ci break; 51278c2ecf20Sopenharmony_ci default: 51288c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "unsupported wq type %d\n", 51298c2ecf20Sopenharmony_ci init_attr->wq_type); 51308c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 51318c2ecf20Sopenharmony_ci } 51328c2ecf20Sopenharmony_ci 51338c2ecf20Sopenharmony_ci rwq->ibwq.wq_num = rwq->core_qp.qpn; 51348c2ecf20Sopenharmony_ci rwq->ibwq.state = IB_WQS_RESET; 51358c2ecf20Sopenharmony_ci if (udata->outlen) { 51368c2ecf20Sopenharmony_ci resp.response_length = offsetofend( 51378c2ecf20Sopenharmony_ci struct mlx5_ib_create_wq_resp, response_length); 51388c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &resp, resp.response_length); 51398c2ecf20Sopenharmony_ci if (err) 51408c2ecf20Sopenharmony_ci goto err_copy; 51418c2ecf20Sopenharmony_ci } 51428c2ecf20Sopenharmony_ci 51438c2ecf20Sopenharmony_ci rwq->core_qp.event = mlx5_ib_wq_event; 51448c2ecf20Sopenharmony_ci rwq->ibwq.event_handler = init_attr->event_handler; 51458c2ecf20Sopenharmony_ci return &rwq->ibwq; 51468c2ecf20Sopenharmony_ci 51478c2ecf20Sopenharmony_cierr_copy: 51488c2ecf20Sopenharmony_ci mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp); 51498c2ecf20Sopenharmony_cierr_user_rq: 51508c2ecf20Sopenharmony_ci destroy_user_rq(dev, pd, rwq, udata); 51518c2ecf20Sopenharmony_cierr: 51528c2ecf20Sopenharmony_ci kfree(rwq); 51538c2ecf20Sopenharmony_ci return ERR_PTR(err); 51548c2ecf20Sopenharmony_ci} 51558c2ecf20Sopenharmony_ci 51568c2ecf20Sopenharmony_ciint mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata) 51578c2ecf20Sopenharmony_ci{ 51588c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(wq->device); 51598c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq = to_mrwq(wq); 51608c2ecf20Sopenharmony_ci int ret; 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_ci ret = mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp); 51638c2ecf20Sopenharmony_ci if (ret) 51648c2ecf20Sopenharmony_ci return ret; 51658c2ecf20Sopenharmony_ci destroy_user_rq(dev, wq->pd, rwq, udata); 51668c2ecf20Sopenharmony_ci kfree(rwq); 51678c2ecf20Sopenharmony_ci return 0; 51688c2ecf20Sopenharmony_ci} 51698c2ecf20Sopenharmony_ci 51708c2ecf20Sopenharmony_ciint mlx5_ib_create_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_table, 51718c2ecf20Sopenharmony_ci struct ib_rwq_ind_table_init_attr *init_attr, 51728c2ecf20Sopenharmony_ci struct ib_udata *udata) 51738c2ecf20Sopenharmony_ci{ 51748c2ecf20Sopenharmony_ci struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = 51758c2ecf20Sopenharmony_ci to_mrwq_ind_table(ib_rwq_ind_table); 51768c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_table->device); 51778c2ecf20Sopenharmony_ci int sz = 1 << init_attr->log_ind_tbl_size; 51788c2ecf20Sopenharmony_ci struct mlx5_ib_create_rwq_ind_tbl_resp resp = {}; 51798c2ecf20Sopenharmony_ci size_t min_resp_len; 51808c2ecf20Sopenharmony_ci int inlen; 51818c2ecf20Sopenharmony_ci int err; 51828c2ecf20Sopenharmony_ci int i; 51838c2ecf20Sopenharmony_ci u32 *in; 51848c2ecf20Sopenharmony_ci void *rqtc; 51858c2ecf20Sopenharmony_ci 51868c2ecf20Sopenharmony_ci if (udata->inlen > 0 && 51878c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, 0, 51888c2ecf20Sopenharmony_ci udata->inlen)) 51898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 51908c2ecf20Sopenharmony_ci 51918c2ecf20Sopenharmony_ci if (init_attr->log_ind_tbl_size > 51928c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, log_max_rqt_size)) { 51938c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "log_ind_tbl_size = %d is bigger than supported = %d\n", 51948c2ecf20Sopenharmony_ci init_attr->log_ind_tbl_size, 51958c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, log_max_rqt_size)); 51968c2ecf20Sopenharmony_ci return -EINVAL; 51978c2ecf20Sopenharmony_ci } 51988c2ecf20Sopenharmony_ci 51998c2ecf20Sopenharmony_ci min_resp_len = 52008c2ecf20Sopenharmony_ci offsetofend(struct mlx5_ib_create_rwq_ind_tbl_resp, reserved); 52018c2ecf20Sopenharmony_ci if (udata->outlen && udata->outlen < min_resp_len) 52028c2ecf20Sopenharmony_ci return -EINVAL; 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; 52058c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 52068c2ecf20Sopenharmony_ci if (!in) 52078c2ecf20Sopenharmony_ci return -ENOMEM; 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); 52108c2ecf20Sopenharmony_ci 52118c2ecf20Sopenharmony_ci MLX5_SET(rqtc, rqtc, rqt_actual_size, sz); 52128c2ecf20Sopenharmony_ci MLX5_SET(rqtc, rqtc, rqt_max_size, sz); 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci for (i = 0; i < sz; i++) 52158c2ecf20Sopenharmony_ci MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num); 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci rwq_ind_tbl->uid = to_mpd(init_attr->ind_tbl[0]->pd)->uid; 52188c2ecf20Sopenharmony_ci MLX5_SET(create_rqt_in, in, uid, rwq_ind_tbl->uid); 52198c2ecf20Sopenharmony_ci 52208c2ecf20Sopenharmony_ci err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn); 52218c2ecf20Sopenharmony_ci kvfree(in); 52228c2ecf20Sopenharmony_ci if (err) 52238c2ecf20Sopenharmony_ci return err; 52248c2ecf20Sopenharmony_ci 52258c2ecf20Sopenharmony_ci rwq_ind_tbl->ib_rwq_ind_tbl.ind_tbl_num = rwq_ind_tbl->rqtn; 52268c2ecf20Sopenharmony_ci if (udata->outlen) { 52278c2ecf20Sopenharmony_ci resp.response_length = 52288c2ecf20Sopenharmony_ci offsetofend(struct mlx5_ib_create_rwq_ind_tbl_resp, 52298c2ecf20Sopenharmony_ci response_length); 52308c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &resp, resp.response_length); 52318c2ecf20Sopenharmony_ci if (err) 52328c2ecf20Sopenharmony_ci goto err_copy; 52338c2ecf20Sopenharmony_ci } 52348c2ecf20Sopenharmony_ci 52358c2ecf20Sopenharmony_ci return 0; 52368c2ecf20Sopenharmony_ci 52378c2ecf20Sopenharmony_cierr_copy: 52388c2ecf20Sopenharmony_ci mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid); 52398c2ecf20Sopenharmony_ci return err; 52408c2ecf20Sopenharmony_ci} 52418c2ecf20Sopenharmony_ci 52428c2ecf20Sopenharmony_ciint mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl) 52438c2ecf20Sopenharmony_ci{ 52448c2ecf20Sopenharmony_ci struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl); 52458c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device); 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci return mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid); 52488c2ecf20Sopenharmony_ci} 52498c2ecf20Sopenharmony_ci 52508c2ecf20Sopenharmony_ciint mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr, 52518c2ecf20Sopenharmony_ci u32 wq_attr_mask, struct ib_udata *udata) 52528c2ecf20Sopenharmony_ci{ 52538c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(wq->device); 52548c2ecf20Sopenharmony_ci struct mlx5_ib_rwq *rwq = to_mrwq(wq); 52558c2ecf20Sopenharmony_ci struct mlx5_ib_modify_wq ucmd = {}; 52568c2ecf20Sopenharmony_ci size_t required_cmd_sz; 52578c2ecf20Sopenharmony_ci int curr_wq_state; 52588c2ecf20Sopenharmony_ci int wq_state; 52598c2ecf20Sopenharmony_ci int inlen; 52608c2ecf20Sopenharmony_ci int err; 52618c2ecf20Sopenharmony_ci void *rqc; 52628c2ecf20Sopenharmony_ci void *in; 52638c2ecf20Sopenharmony_ci 52648c2ecf20Sopenharmony_ci required_cmd_sz = offsetofend(struct mlx5_ib_modify_wq, reserved); 52658c2ecf20Sopenharmony_ci if (udata->inlen < required_cmd_sz) 52668c2ecf20Sopenharmony_ci return -EINVAL; 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_ci if (udata->inlen > sizeof(ucmd) && 52698c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, sizeof(ucmd), 52708c2ecf20Sopenharmony_ci udata->inlen - sizeof(ucmd))) 52718c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 52728c2ecf20Sopenharmony_ci 52738c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) 52748c2ecf20Sopenharmony_ci return -EFAULT; 52758c2ecf20Sopenharmony_ci 52768c2ecf20Sopenharmony_ci if (ucmd.comp_mask || ucmd.reserved) 52778c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 52788c2ecf20Sopenharmony_ci 52798c2ecf20Sopenharmony_ci inlen = MLX5_ST_SZ_BYTES(modify_rq_in); 52808c2ecf20Sopenharmony_ci in = kvzalloc(inlen, GFP_KERNEL); 52818c2ecf20Sopenharmony_ci if (!in) 52828c2ecf20Sopenharmony_ci return -ENOMEM; 52838c2ecf20Sopenharmony_ci 52848c2ecf20Sopenharmony_ci rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx); 52858c2ecf20Sopenharmony_ci 52868c2ecf20Sopenharmony_ci curr_wq_state = wq_attr->curr_wq_state; 52878c2ecf20Sopenharmony_ci wq_state = wq_attr->wq_state; 52888c2ecf20Sopenharmony_ci if (curr_wq_state == IB_WQS_ERR) 52898c2ecf20Sopenharmony_ci curr_wq_state = MLX5_RQC_STATE_ERR; 52908c2ecf20Sopenharmony_ci if (wq_state == IB_WQS_ERR) 52918c2ecf20Sopenharmony_ci wq_state = MLX5_RQC_STATE_ERR; 52928c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state); 52938c2ecf20Sopenharmony_ci MLX5_SET(modify_rq_in, in, uid, to_mpd(wq->pd)->uid); 52948c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, state, wq_state); 52958c2ecf20Sopenharmony_ci 52968c2ecf20Sopenharmony_ci if (wq_attr_mask & IB_WQ_FLAGS) { 52978c2ecf20Sopenharmony_ci if (wq_attr->flags_mask & IB_WQ_FLAGS_CVLAN_STRIPPING) { 52988c2ecf20Sopenharmony_ci if (!(MLX5_CAP_GEN(dev->mdev, eth_net_offloads) && 52998c2ecf20Sopenharmony_ci MLX5_CAP_ETH(dev->mdev, vlan_cap))) { 53008c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "VLAN offloads are not " 53018c2ecf20Sopenharmony_ci "supported\n"); 53028c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 53038c2ecf20Sopenharmony_ci goto out; 53048c2ecf20Sopenharmony_ci } 53058c2ecf20Sopenharmony_ci MLX5_SET64(modify_rq_in, in, modify_bitmask, 53068c2ecf20Sopenharmony_ci MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD); 53078c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, vsd, 53088c2ecf20Sopenharmony_ci (wq_attr->flags & IB_WQ_FLAGS_CVLAN_STRIPPING) ? 0 : 1); 53098c2ecf20Sopenharmony_ci } 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_ci if (wq_attr->flags_mask & IB_WQ_FLAGS_PCI_WRITE_END_PADDING) { 53128c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "Modifying scatter end padding is not supported\n"); 53138c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 53148c2ecf20Sopenharmony_ci goto out; 53158c2ecf20Sopenharmony_ci } 53168c2ecf20Sopenharmony_ci } 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci if (curr_wq_state == IB_WQS_RESET && wq_state == IB_WQS_RDY) { 53198c2ecf20Sopenharmony_ci u16 set_id; 53208c2ecf20Sopenharmony_ci 53218c2ecf20Sopenharmony_ci set_id = mlx5_ib_get_counters_id(dev, 0); 53228c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, modify_rq_counter_set_id)) { 53238c2ecf20Sopenharmony_ci MLX5_SET64(modify_rq_in, in, modify_bitmask, 53248c2ecf20Sopenharmony_ci MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID); 53258c2ecf20Sopenharmony_ci MLX5_SET(rqc, rqc, counter_set_id, set_id); 53268c2ecf20Sopenharmony_ci } else 53278c2ecf20Sopenharmony_ci dev_info_once( 53288c2ecf20Sopenharmony_ci &dev->ib_dev.dev, 53298c2ecf20Sopenharmony_ci "Receive WQ counters are not supported on current FW\n"); 53308c2ecf20Sopenharmony_ci } 53318c2ecf20Sopenharmony_ci 53328c2ecf20Sopenharmony_ci err = mlx5_core_modify_rq(dev->mdev, rwq->core_qp.qpn, in); 53338c2ecf20Sopenharmony_ci if (!err) 53348c2ecf20Sopenharmony_ci rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state; 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ciout: 53378c2ecf20Sopenharmony_ci kvfree(in); 53388c2ecf20Sopenharmony_ci return err; 53398c2ecf20Sopenharmony_ci} 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_cistruct mlx5_ib_drain_cqe { 53428c2ecf20Sopenharmony_ci struct ib_cqe cqe; 53438c2ecf20Sopenharmony_ci struct completion done; 53448c2ecf20Sopenharmony_ci}; 53458c2ecf20Sopenharmony_ci 53468c2ecf20Sopenharmony_cistatic void mlx5_ib_drain_qp_done(struct ib_cq *cq, struct ib_wc *wc) 53478c2ecf20Sopenharmony_ci{ 53488c2ecf20Sopenharmony_ci struct mlx5_ib_drain_cqe *cqe = container_of(wc->wr_cqe, 53498c2ecf20Sopenharmony_ci struct mlx5_ib_drain_cqe, 53508c2ecf20Sopenharmony_ci cqe); 53518c2ecf20Sopenharmony_ci 53528c2ecf20Sopenharmony_ci complete(&cqe->done); 53538c2ecf20Sopenharmony_ci} 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci/* This function returns only once the drained WR was completed */ 53568c2ecf20Sopenharmony_cistatic void handle_drain_completion(struct ib_cq *cq, 53578c2ecf20Sopenharmony_ci struct mlx5_ib_drain_cqe *sdrain, 53588c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev) 53598c2ecf20Sopenharmony_ci{ 53608c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 53618c2ecf20Sopenharmony_ci 53628c2ecf20Sopenharmony_ci if (cq->poll_ctx == IB_POLL_DIRECT) { 53638c2ecf20Sopenharmony_ci while (wait_for_completion_timeout(&sdrain->done, HZ / 10) <= 0) 53648c2ecf20Sopenharmony_ci ib_process_cq_direct(cq, -1); 53658c2ecf20Sopenharmony_ci return; 53668c2ecf20Sopenharmony_ci } 53678c2ecf20Sopenharmony_ci 53688c2ecf20Sopenharmony_ci if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { 53698c2ecf20Sopenharmony_ci struct mlx5_ib_cq *mcq = to_mcq(cq); 53708c2ecf20Sopenharmony_ci bool triggered = false; 53718c2ecf20Sopenharmony_ci unsigned long flags; 53728c2ecf20Sopenharmony_ci 53738c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->reset_flow_resource_lock, flags); 53748c2ecf20Sopenharmony_ci /* Make sure that the CQ handler won't run if wasn't run yet */ 53758c2ecf20Sopenharmony_ci if (!mcq->mcq.reset_notify_added) 53768c2ecf20Sopenharmony_ci mcq->mcq.reset_notify_added = 1; 53778c2ecf20Sopenharmony_ci else 53788c2ecf20Sopenharmony_ci triggered = true; 53798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags); 53808c2ecf20Sopenharmony_ci 53818c2ecf20Sopenharmony_ci if (triggered) { 53828c2ecf20Sopenharmony_ci /* Wait for any scheduled/running task to be ended */ 53838c2ecf20Sopenharmony_ci switch (cq->poll_ctx) { 53848c2ecf20Sopenharmony_ci case IB_POLL_SOFTIRQ: 53858c2ecf20Sopenharmony_ci irq_poll_disable(&cq->iop); 53868c2ecf20Sopenharmony_ci irq_poll_enable(&cq->iop); 53878c2ecf20Sopenharmony_ci break; 53888c2ecf20Sopenharmony_ci case IB_POLL_WORKQUEUE: 53898c2ecf20Sopenharmony_ci cancel_work_sync(&cq->work); 53908c2ecf20Sopenharmony_ci break; 53918c2ecf20Sopenharmony_ci default: 53928c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 53938c2ecf20Sopenharmony_ci } 53948c2ecf20Sopenharmony_ci } 53958c2ecf20Sopenharmony_ci 53968c2ecf20Sopenharmony_ci /* Run the CQ handler - this makes sure that the drain WR will 53978c2ecf20Sopenharmony_ci * be processed if wasn't processed yet. 53988c2ecf20Sopenharmony_ci */ 53998c2ecf20Sopenharmony_ci mcq->mcq.comp(&mcq->mcq, NULL); 54008c2ecf20Sopenharmony_ci } 54018c2ecf20Sopenharmony_ci 54028c2ecf20Sopenharmony_ci wait_for_completion(&sdrain->done); 54038c2ecf20Sopenharmony_ci} 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_civoid mlx5_ib_drain_sq(struct ib_qp *qp) 54068c2ecf20Sopenharmony_ci{ 54078c2ecf20Sopenharmony_ci struct ib_cq *cq = qp->send_cq; 54088c2ecf20Sopenharmony_ci struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; 54098c2ecf20Sopenharmony_ci struct mlx5_ib_drain_cqe sdrain; 54108c2ecf20Sopenharmony_ci const struct ib_send_wr *bad_swr; 54118c2ecf20Sopenharmony_ci struct ib_rdma_wr swr = { 54128c2ecf20Sopenharmony_ci .wr = { 54138c2ecf20Sopenharmony_ci .next = NULL, 54148c2ecf20Sopenharmony_ci { .wr_cqe = &sdrain.cqe, }, 54158c2ecf20Sopenharmony_ci .opcode = IB_WR_RDMA_WRITE, 54168c2ecf20Sopenharmony_ci }, 54178c2ecf20Sopenharmony_ci }; 54188c2ecf20Sopenharmony_ci int ret; 54198c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 54208c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 54218c2ecf20Sopenharmony_ci 54228c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 54238c2ecf20Sopenharmony_ci if (ret && mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR) { 54248c2ecf20Sopenharmony_ci WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); 54258c2ecf20Sopenharmony_ci return; 54268c2ecf20Sopenharmony_ci } 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci sdrain.cqe.done = mlx5_ib_drain_qp_done; 54298c2ecf20Sopenharmony_ci init_completion(&sdrain.done); 54308c2ecf20Sopenharmony_ci 54318c2ecf20Sopenharmony_ci ret = mlx5_ib_post_send_drain(qp, &swr.wr, &bad_swr); 54328c2ecf20Sopenharmony_ci if (ret) { 54338c2ecf20Sopenharmony_ci WARN_ONCE(ret, "failed to drain send queue: %d\n", ret); 54348c2ecf20Sopenharmony_ci return; 54358c2ecf20Sopenharmony_ci } 54368c2ecf20Sopenharmony_ci 54378c2ecf20Sopenharmony_ci handle_drain_completion(cq, &sdrain, dev); 54388c2ecf20Sopenharmony_ci} 54398c2ecf20Sopenharmony_ci 54408c2ecf20Sopenharmony_civoid mlx5_ib_drain_rq(struct ib_qp *qp) 54418c2ecf20Sopenharmony_ci{ 54428c2ecf20Sopenharmony_ci struct ib_cq *cq = qp->recv_cq; 54438c2ecf20Sopenharmony_ci struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR }; 54448c2ecf20Sopenharmony_ci struct mlx5_ib_drain_cqe rdrain; 54458c2ecf20Sopenharmony_ci struct ib_recv_wr rwr = {}; 54468c2ecf20Sopenharmony_ci const struct ib_recv_wr *bad_rwr; 54478c2ecf20Sopenharmony_ci int ret; 54488c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 54498c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 54508c2ecf20Sopenharmony_ci 54518c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 54528c2ecf20Sopenharmony_ci if (ret && mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR) { 54538c2ecf20Sopenharmony_ci WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret); 54548c2ecf20Sopenharmony_ci return; 54558c2ecf20Sopenharmony_ci } 54568c2ecf20Sopenharmony_ci 54578c2ecf20Sopenharmony_ci rwr.wr_cqe = &rdrain.cqe; 54588c2ecf20Sopenharmony_ci rdrain.cqe.done = mlx5_ib_drain_qp_done; 54598c2ecf20Sopenharmony_ci init_completion(&rdrain.done); 54608c2ecf20Sopenharmony_ci 54618c2ecf20Sopenharmony_ci ret = mlx5_ib_post_recv_drain(qp, &rwr, &bad_rwr); 54628c2ecf20Sopenharmony_ci if (ret) { 54638c2ecf20Sopenharmony_ci WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret); 54648c2ecf20Sopenharmony_ci return; 54658c2ecf20Sopenharmony_ci } 54668c2ecf20Sopenharmony_ci 54678c2ecf20Sopenharmony_ci handle_drain_completion(cq, &rdrain, dev); 54688c2ecf20Sopenharmony_ci} 54698c2ecf20Sopenharmony_ci 54708c2ecf20Sopenharmony_ci/** 54718c2ecf20Sopenharmony_ci * Bind a qp to a counter. If @counter is NULL then bind the qp to 54728c2ecf20Sopenharmony_ci * the default counter 54738c2ecf20Sopenharmony_ci */ 54748c2ecf20Sopenharmony_ciint mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter) 54758c2ecf20Sopenharmony_ci{ 54768c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 54778c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 54788c2ecf20Sopenharmony_ci int err = 0; 54798c2ecf20Sopenharmony_ci 54808c2ecf20Sopenharmony_ci mutex_lock(&mqp->mutex); 54818c2ecf20Sopenharmony_ci if (mqp->state == IB_QPS_RESET) { 54828c2ecf20Sopenharmony_ci qp->counter = counter; 54838c2ecf20Sopenharmony_ci goto out; 54848c2ecf20Sopenharmony_ci } 54858c2ecf20Sopenharmony_ci 54868c2ecf20Sopenharmony_ci if (!MLX5_CAP_GEN(dev->mdev, rts2rts_qp_counters_set_id)) { 54878c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 54888c2ecf20Sopenharmony_ci goto out; 54898c2ecf20Sopenharmony_ci } 54908c2ecf20Sopenharmony_ci 54918c2ecf20Sopenharmony_ci if (mqp->state == IB_QPS_RTS) { 54928c2ecf20Sopenharmony_ci err = __mlx5_ib_qp_set_counter(qp, counter); 54938c2ecf20Sopenharmony_ci if (!err) 54948c2ecf20Sopenharmony_ci qp->counter = counter; 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci goto out; 54978c2ecf20Sopenharmony_ci } 54988c2ecf20Sopenharmony_ci 54998c2ecf20Sopenharmony_ci mqp->counter_pending = 1; 55008c2ecf20Sopenharmony_ci qp->counter = counter; 55018c2ecf20Sopenharmony_ci 55028c2ecf20Sopenharmony_ciout: 55038c2ecf20Sopenharmony_ci mutex_unlock(&mqp->mutex); 55048c2ecf20Sopenharmony_ci return err; 55058c2ecf20Sopenharmony_ci} 5506