18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2016, 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 "mlx5_ib.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct mlx5_ib_gsi_wr { 368c2ecf20Sopenharmony_ci struct ib_cqe cqe; 378c2ecf20Sopenharmony_ci struct ib_wc wc; 388c2ecf20Sopenharmony_ci bool completed:1; 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic bool mlx5_ib_deth_sqpn_cap(struct mlx5_ib_dev *dev) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci return MLX5_CAP_GEN(dev->mdev, set_deth_sqpn); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* Call with gsi->lock locked */ 478c2ecf20Sopenharmony_cistatic void generate_completions(struct mlx5_ib_qp *mqp) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 508c2ecf20Sopenharmony_ci struct ib_cq *gsi_cq = mqp->ibqp.send_cq; 518c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_wr *wr; 528c2ecf20Sopenharmony_ci u32 index; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci for (index = gsi->outstanding_ci; index != gsi->outstanding_pi; 558c2ecf20Sopenharmony_ci index++) { 568c2ecf20Sopenharmony_ci wr = &gsi->outstanding_wrs[index % gsi->cap.max_send_wr]; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (!wr->completed) 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci WARN_ON_ONCE(mlx5_ib_generate_wc(gsi_cq, &wr->wc)); 628c2ecf20Sopenharmony_ci wr->completed = false; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci gsi->outstanding_ci = index; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void handle_single_completion(struct ib_cq *cq, struct ib_wc *wc) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = cq->cq_context; 718c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_wr *wr = 728c2ecf20Sopenharmony_ci container_of(wc->wr_cqe, struct mlx5_ib_gsi_wr, cqe); 738c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = container_of(gsi, struct mlx5_ib_qp, gsi); 748c2ecf20Sopenharmony_ci u64 wr_id; 758c2ecf20Sopenharmony_ci unsigned long flags; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci spin_lock_irqsave(&gsi->lock, flags); 788c2ecf20Sopenharmony_ci wr->completed = true; 798c2ecf20Sopenharmony_ci wr_id = wr->wc.wr_id; 808c2ecf20Sopenharmony_ci wr->wc = *wc; 818c2ecf20Sopenharmony_ci wr->wc.wr_id = wr_id; 828c2ecf20Sopenharmony_ci wr->wc.qp = &mqp->ibqp; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci generate_completions(mqp); 858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ciint mlx5_ib_create_gsi(struct ib_pd *pd, struct mlx5_ib_qp *mqp, 898c2ecf20Sopenharmony_ci struct ib_qp_init_attr *attr) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(pd->device); 928c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi; 938c2ecf20Sopenharmony_ci struct ib_qp_init_attr hw_init_attr = *attr; 948c2ecf20Sopenharmony_ci const u8 port_num = attr->port_num; 958c2ecf20Sopenharmony_ci int num_qps = 0; 968c2ecf20Sopenharmony_ci int ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (mlx5_ib_deth_sqpn_cap(dev)) { 998c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, 1008c2ecf20Sopenharmony_ci port_type) == MLX5_CAP_PORT_TYPE_IB) 1018c2ecf20Sopenharmony_ci num_qps = pd->device->attrs.max_pkeys; 1028c2ecf20Sopenharmony_ci else if (dev->lag_active) 1038c2ecf20Sopenharmony_ci num_qps = MLX5_MAX_PORTS; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci gsi = &mqp->gsi; 1078c2ecf20Sopenharmony_ci gsi->tx_qps = kcalloc(num_qps, sizeof(*gsi->tx_qps), GFP_KERNEL); 1088c2ecf20Sopenharmony_ci if (!gsi->tx_qps) 1098c2ecf20Sopenharmony_ci return -ENOMEM; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci gsi->outstanding_wrs = 1128c2ecf20Sopenharmony_ci kcalloc(attr->cap.max_send_wr, sizeof(*gsi->outstanding_wrs), 1138c2ecf20Sopenharmony_ci GFP_KERNEL); 1148c2ecf20Sopenharmony_ci if (!gsi->outstanding_wrs) { 1158c2ecf20Sopenharmony_ci ret = -ENOMEM; 1168c2ecf20Sopenharmony_ci goto err_free_tx; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci mutex_lock(&dev->devr.mutex); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (dev->devr.ports[port_num - 1].gsi) { 1228c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "GSI QP already exists on port %d\n", 1238c2ecf20Sopenharmony_ci port_num); 1248c2ecf20Sopenharmony_ci ret = -EBUSY; 1258c2ecf20Sopenharmony_ci goto err_free_wrs; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci gsi->num_qps = num_qps; 1288c2ecf20Sopenharmony_ci spin_lock_init(&gsi->lock); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci gsi->cap = attr->cap; 1318c2ecf20Sopenharmony_ci gsi->port_num = port_num; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci gsi->cq = ib_alloc_cq(pd->device, gsi, attr->cap.max_send_wr, 0, 1348c2ecf20Sopenharmony_ci IB_POLL_SOFTIRQ); 1358c2ecf20Sopenharmony_ci if (IS_ERR(gsi->cq)) { 1368c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to create send CQ for GSI QP. error %ld\n", 1378c2ecf20Sopenharmony_ci PTR_ERR(gsi->cq)); 1388c2ecf20Sopenharmony_ci ret = PTR_ERR(gsi->cq); 1398c2ecf20Sopenharmony_ci goto err_free_wrs; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci hw_init_attr.qp_type = MLX5_IB_QPT_HW_GSI; 1438c2ecf20Sopenharmony_ci hw_init_attr.send_cq = gsi->cq; 1448c2ecf20Sopenharmony_ci if (num_qps) { 1458c2ecf20Sopenharmony_ci hw_init_attr.cap.max_send_wr = 0; 1468c2ecf20Sopenharmony_ci hw_init_attr.cap.max_send_sge = 0; 1478c2ecf20Sopenharmony_ci hw_init_attr.cap.max_inline_data = 0; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci gsi->rx_qp = mlx5_ib_create_qp(pd, &hw_init_attr, NULL); 1518c2ecf20Sopenharmony_ci if (IS_ERR(gsi->rx_qp)) { 1528c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to create hardware GSI QP. error %ld\n", 1538c2ecf20Sopenharmony_ci PTR_ERR(gsi->rx_qp)); 1548c2ecf20Sopenharmony_ci ret = PTR_ERR(gsi->rx_qp); 1558c2ecf20Sopenharmony_ci goto err_destroy_cq; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci gsi->rx_qp->device = pd->device; 1588c2ecf20Sopenharmony_ci gsi->rx_qp->pd = pd; 1598c2ecf20Sopenharmony_ci gsi->rx_qp->real_qp = gsi->rx_qp; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci gsi->rx_qp->qp_type = hw_init_attr.qp_type; 1628c2ecf20Sopenharmony_ci gsi->rx_qp->send_cq = hw_init_attr.send_cq; 1638c2ecf20Sopenharmony_ci gsi->rx_qp->recv_cq = hw_init_attr.recv_cq; 1648c2ecf20Sopenharmony_ci gsi->rx_qp->event_handler = hw_init_attr.event_handler; 1658c2ecf20Sopenharmony_ci spin_lock_init(&gsi->rx_qp->mr_lock); 1668c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gsi->rx_qp->rdma_mrs); 1678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&gsi->rx_qp->sig_mrs); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci dev->devr.ports[attr->port_num - 1].gsi = gsi; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci mutex_unlock(&dev->devr.mutex); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cierr_destroy_cq: 1768c2ecf20Sopenharmony_ci ib_free_cq(gsi->cq); 1778c2ecf20Sopenharmony_cierr_free_wrs: 1788c2ecf20Sopenharmony_ci mutex_unlock(&dev->devr.mutex); 1798c2ecf20Sopenharmony_ci kfree(gsi->outstanding_wrs); 1808c2ecf20Sopenharmony_cierr_free_tx: 1818c2ecf20Sopenharmony_ci kfree(gsi->tx_qps); 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciint mlx5_ib_destroy_gsi(struct mlx5_ib_qp *mqp) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(mqp->ibqp.device); 1888c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 1898c2ecf20Sopenharmony_ci const int port_num = gsi->port_num; 1908c2ecf20Sopenharmony_ci int qp_index; 1918c2ecf20Sopenharmony_ci int ret; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci mutex_lock(&dev->devr.mutex); 1948c2ecf20Sopenharmony_ci ret = mlx5_ib_destroy_qp(gsi->rx_qp, NULL); 1958c2ecf20Sopenharmony_ci if (ret) { 1968c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to destroy hardware GSI QP. error %d\n", 1978c2ecf20Sopenharmony_ci ret); 1988c2ecf20Sopenharmony_ci mutex_unlock(&dev->devr.mutex); 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci dev->devr.ports[port_num - 1].gsi = NULL; 2028c2ecf20Sopenharmony_ci mutex_unlock(&dev->devr.mutex); 2038c2ecf20Sopenharmony_ci gsi->rx_qp = NULL; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci for (qp_index = 0; qp_index < gsi->num_qps; ++qp_index) { 2068c2ecf20Sopenharmony_ci if (!gsi->tx_qps[qp_index]) 2078c2ecf20Sopenharmony_ci continue; 2088c2ecf20Sopenharmony_ci WARN_ON_ONCE(ib_destroy_qp(gsi->tx_qps[qp_index])); 2098c2ecf20Sopenharmony_ci gsi->tx_qps[qp_index] = NULL; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ib_free_cq(gsi->cq); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci kfree(gsi->outstanding_wrs); 2158c2ecf20Sopenharmony_ci kfree(gsi->tx_qps); 2168c2ecf20Sopenharmony_ci kfree(mqp); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic struct ib_qp *create_gsi_ud_qp(struct mlx5_ib_gsi_qp *gsi) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct ib_pd *pd = gsi->rx_qp->pd; 2248c2ecf20Sopenharmony_ci struct ib_qp_init_attr init_attr = { 2258c2ecf20Sopenharmony_ci .event_handler = gsi->rx_qp->event_handler, 2268c2ecf20Sopenharmony_ci .qp_context = gsi->rx_qp->qp_context, 2278c2ecf20Sopenharmony_ci .send_cq = gsi->cq, 2288c2ecf20Sopenharmony_ci .recv_cq = gsi->rx_qp->recv_cq, 2298c2ecf20Sopenharmony_ci .cap = { 2308c2ecf20Sopenharmony_ci .max_send_wr = gsi->cap.max_send_wr, 2318c2ecf20Sopenharmony_ci .max_send_sge = gsi->cap.max_send_sge, 2328c2ecf20Sopenharmony_ci .max_inline_data = gsi->cap.max_inline_data, 2338c2ecf20Sopenharmony_ci }, 2348c2ecf20Sopenharmony_ci .qp_type = IB_QPT_UD, 2358c2ecf20Sopenharmony_ci .create_flags = MLX5_IB_QP_CREATE_SQPN_QP1, 2368c2ecf20Sopenharmony_ci }; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return ib_create_qp(pd, &init_attr); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int modify_to_rts(struct mlx5_ib_gsi_qp *gsi, struct ib_qp *qp, 2428c2ecf20Sopenharmony_ci u16 pkey_index) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 2458c2ecf20Sopenharmony_ci struct ib_qp_attr attr; 2468c2ecf20Sopenharmony_ci int mask; 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY | IB_QP_PORT; 2508c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_INIT; 2518c2ecf20Sopenharmony_ci attr.pkey_index = pkey_index; 2528c2ecf20Sopenharmony_ci attr.qkey = IB_QP1_QKEY; 2538c2ecf20Sopenharmony_ci attr.port_num = gsi->port_num; 2548c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &attr, mask); 2558c2ecf20Sopenharmony_ci if (ret) { 2568c2ecf20Sopenharmony_ci mlx5_ib_err(dev, "could not change QP%d state to INIT: %d\n", 2578c2ecf20Sopenharmony_ci qp->qp_num, ret); 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_RTR; 2628c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE); 2638c2ecf20Sopenharmony_ci if (ret) { 2648c2ecf20Sopenharmony_ci mlx5_ib_err(dev, "could not change QP%d state to RTR: %d\n", 2658c2ecf20Sopenharmony_ci qp->qp_num, ret); 2668c2ecf20Sopenharmony_ci return ret; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_RTS; 2708c2ecf20Sopenharmony_ci attr.sq_psn = 0; 2718c2ecf20Sopenharmony_ci ret = ib_modify_qp(qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); 2728c2ecf20Sopenharmony_ci if (ret) { 2738c2ecf20Sopenharmony_ci mlx5_ib_err(dev, "could not change QP%d state to RTS: %d\n", 2748c2ecf20Sopenharmony_ci qp->qp_num, ret); 2758c2ecf20Sopenharmony_ci return ret; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic void setup_qp(struct mlx5_ib_gsi_qp *gsi, u16 qp_index) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct ib_device *device = gsi->rx_qp->device; 2848c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(device); 2858c2ecf20Sopenharmony_ci int pkey_index = qp_index; 2868c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp; 2878c2ecf20Sopenharmony_ci struct ib_qp *qp; 2888c2ecf20Sopenharmony_ci unsigned long flags; 2898c2ecf20Sopenharmony_ci u16 pkey; 2908c2ecf20Sopenharmony_ci int ret; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, port_type) != MLX5_CAP_PORT_TYPE_IB) 2938c2ecf20Sopenharmony_ci pkey_index = 0; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci ret = ib_query_pkey(device, gsi->port_num, pkey_index, &pkey); 2968c2ecf20Sopenharmony_ci if (ret) { 2978c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to read P_Key at port %d, index %d\n", 2988c2ecf20Sopenharmony_ci gsi->port_num, qp_index); 2998c2ecf20Sopenharmony_ci return; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!pkey) { 3038c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "invalid P_Key at port %d, index %d. Skipping.\n", 3048c2ecf20Sopenharmony_ci gsi->port_num, qp_index); 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci spin_lock_irqsave(&gsi->lock, flags); 3098c2ecf20Sopenharmony_ci qp = gsi->tx_qps[qp_index]; 3108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 3118c2ecf20Sopenharmony_ci if (qp) { 3128c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "already existing GSI TX QP at port %d, index %d. Skipping\n", 3138c2ecf20Sopenharmony_ci gsi->port_num, qp_index); 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci qp = create_gsi_ud_qp(gsi); 3188c2ecf20Sopenharmony_ci if (IS_ERR(qp)) { 3198c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to create hardware UD QP for GSI: %ld\n", 3208c2ecf20Sopenharmony_ci PTR_ERR(qp)); 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci mqp = to_mqp(qp); 3258c2ecf20Sopenharmony_ci if (dev->lag_active) 3268c2ecf20Sopenharmony_ci mqp->gsi_lag_port = qp_index + 1; 3278c2ecf20Sopenharmony_ci ret = modify_to_rts(gsi, qp, pkey_index); 3288c2ecf20Sopenharmony_ci if (ret) 3298c2ecf20Sopenharmony_ci goto err_destroy_qp; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci spin_lock_irqsave(&gsi->lock, flags); 3328c2ecf20Sopenharmony_ci WARN_ON_ONCE(gsi->tx_qps[qp_index]); 3338c2ecf20Sopenharmony_ci gsi->tx_qps[qp_index] = qp; 3348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cierr_destroy_qp: 3398c2ecf20Sopenharmony_ci WARN_ON_ONCE(qp); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void setup_qps(struct mlx5_ib_gsi_qp *gsi) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(gsi->rx_qp->device); 3458c2ecf20Sopenharmony_ci u16 qp_index; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci mutex_lock(&dev->devr.mutex); 3488c2ecf20Sopenharmony_ci for (qp_index = 0; qp_index < gsi->num_qps; ++qp_index) 3498c2ecf20Sopenharmony_ci setup_qp(gsi, qp_index); 3508c2ecf20Sopenharmony_ci mutex_unlock(&dev->devr.mutex); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint mlx5_ib_gsi_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr, 3548c2ecf20Sopenharmony_ci int attr_mask) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(qp->device); 3578c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 3588c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "modifying GSI QP to state %d\n", attr->qp_state); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ret = ib_modify_qp(gsi->rx_qp, attr, attr_mask); 3648c2ecf20Sopenharmony_ci if (ret) { 3658c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "unable to modify GSI rx QP: %d\n", ret); 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (to_mqp(gsi->rx_qp)->state == IB_QPS_RTS) 3708c2ecf20Sopenharmony_ci setup_qps(gsi); 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciint mlx5_ib_gsi_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr, 3758c2ecf20Sopenharmony_ci int qp_attr_mask, 3768c2ecf20Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 3798c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 3808c2ecf20Sopenharmony_ci int ret; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ret = ib_query_qp(gsi->rx_qp, qp_attr, qp_attr_mask, qp_init_attr); 3838c2ecf20Sopenharmony_ci qp_init_attr->cap = gsi->cap; 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/* Call with gsi->lock locked */ 3888c2ecf20Sopenharmony_cistatic int mlx5_ib_add_outstanding_wr(struct mlx5_ib_qp *mqp, 3898c2ecf20Sopenharmony_ci struct ib_ud_wr *wr, struct ib_wc *wc) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 3928c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(gsi->rx_qp->device); 3938c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_wr *gsi_wr; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (gsi->outstanding_pi == gsi->outstanding_ci + gsi->cap.max_send_wr) { 3968c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "no available GSI work request.\n"); 3978c2ecf20Sopenharmony_ci return -ENOMEM; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci gsi_wr = &gsi->outstanding_wrs[gsi->outstanding_pi % 4018c2ecf20Sopenharmony_ci gsi->cap.max_send_wr]; 4028c2ecf20Sopenharmony_ci gsi->outstanding_pi++; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (!wc) { 4058c2ecf20Sopenharmony_ci memset(&gsi_wr->wc, 0, sizeof(gsi_wr->wc)); 4068c2ecf20Sopenharmony_ci gsi_wr->wc.pkey_index = wr->pkey_index; 4078c2ecf20Sopenharmony_ci gsi_wr->wc.wr_id = wr->wr.wr_id; 4088c2ecf20Sopenharmony_ci } else { 4098c2ecf20Sopenharmony_ci gsi_wr->wc = *wc; 4108c2ecf20Sopenharmony_ci gsi_wr->completed = true; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci gsi_wr->cqe.done = &handle_single_completion; 4148c2ecf20Sopenharmony_ci wr->wr.wr_cqe = &gsi_wr->cqe; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* Call with gsi->lock locked */ 4208c2ecf20Sopenharmony_cistatic int mlx5_ib_gsi_silent_drop(struct mlx5_ib_qp *mqp, struct ib_ud_wr *wr) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct ib_wc wc = { 4238c2ecf20Sopenharmony_ci { .wr_id = wr->wr.wr_id }, 4248c2ecf20Sopenharmony_ci .status = IB_WC_SUCCESS, 4258c2ecf20Sopenharmony_ci .opcode = IB_WC_SEND, 4268c2ecf20Sopenharmony_ci .qp = &mqp->ibqp, 4278c2ecf20Sopenharmony_ci }; 4288c2ecf20Sopenharmony_ci int ret; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci ret = mlx5_ib_add_outstanding_wr(mqp, wr, &wc); 4318c2ecf20Sopenharmony_ci if (ret) 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci generate_completions(mqp); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* Call with gsi->lock locked */ 4408c2ecf20Sopenharmony_cistatic struct ib_qp *get_tx_qp(struct mlx5_ib_gsi_qp *gsi, struct ib_ud_wr *wr) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(gsi->rx_qp->device); 4438c2ecf20Sopenharmony_ci struct mlx5_ib_ah *ah = to_mah(wr->ah); 4448c2ecf20Sopenharmony_ci int qp_index = wr->pkey_index; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!gsi->num_qps) 4478c2ecf20Sopenharmony_ci return gsi->rx_qp; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (dev->lag_active && ah->xmit_port) 4508c2ecf20Sopenharmony_ci qp_index = ah->xmit_port - 1; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (qp_index >= gsi->num_qps) 4538c2ecf20Sopenharmony_ci return NULL; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return gsi->tx_qps[qp_index]; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ciint mlx5_ib_gsi_post_send(struct ib_qp *qp, const struct ib_send_wr *wr, 4598c2ecf20Sopenharmony_ci const struct ib_send_wr **bad_wr) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 4628c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 4638c2ecf20Sopenharmony_ci struct ib_qp *tx_qp; 4648c2ecf20Sopenharmony_ci unsigned long flags; 4658c2ecf20Sopenharmony_ci int ret; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci for (; wr; wr = wr->next) { 4688c2ecf20Sopenharmony_ci struct ib_ud_wr cur_wr = *ud_wr(wr); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci cur_wr.wr.next = NULL; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci spin_lock_irqsave(&gsi->lock, flags); 4738c2ecf20Sopenharmony_ci tx_qp = get_tx_qp(gsi, &cur_wr); 4748c2ecf20Sopenharmony_ci if (!tx_qp) { 4758c2ecf20Sopenharmony_ci ret = mlx5_ib_gsi_silent_drop(mqp, &cur_wr); 4768c2ecf20Sopenharmony_ci if (ret) 4778c2ecf20Sopenharmony_ci goto err; 4788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 4798c2ecf20Sopenharmony_ci continue; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ret = mlx5_ib_add_outstanding_wr(mqp, &cur_wr, NULL); 4838c2ecf20Sopenharmony_ci if (ret) 4848c2ecf20Sopenharmony_ci goto err; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ret = ib_post_send(tx_qp, &cur_wr.wr, bad_wr); 4878c2ecf20Sopenharmony_ci if (ret) { 4888c2ecf20Sopenharmony_ci /* Undo the effect of adding the outstanding wr */ 4898c2ecf20Sopenharmony_ci gsi->outstanding_pi--; 4908c2ecf20Sopenharmony_ci goto err; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cierr: 4988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gsi->lock, flags); 4998c2ecf20Sopenharmony_ci *bad_wr = wr; 5008c2ecf20Sopenharmony_ci return ret; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ciint mlx5_ib_gsi_post_recv(struct ib_qp *qp, const struct ib_recv_wr *wr, 5048c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct mlx5_ib_qp *mqp = to_mqp(qp); 5078c2ecf20Sopenharmony_ci struct mlx5_ib_gsi_qp *gsi = &mqp->gsi; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return ib_post_recv(gsi->rx_qp, wr, bad_wr); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_civoid mlx5_ib_gsi_pkey_change(struct mlx5_ib_gsi_qp *gsi) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci if (!gsi) 5158c2ecf20Sopenharmony_ci return; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci setup_qps(gsi); 5188c2ecf20Sopenharmony_ci} 519