18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 58c2ecf20Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 148c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 158c2ecf20Sopenharmony_ci * conditions are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 188c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 198c2ecf20Sopenharmony_ci * disclaimer. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 228c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 238c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 248c2ecf20Sopenharmony_ci * provided with the distribution. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 278c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 288c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 298c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 308c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 318c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 328c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 338c2ecf20Sopenharmony_ci * SOFTWARE. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/gfp.h> 378c2ecf20Sopenharmony_ci#include <linux/export.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 408c2ecf20Sopenharmony_ci#include <linux/mlx4/qp.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "mlx4.h" 438c2ecf20Sopenharmony_ci#include "icm.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* QP to support BF should have bits 6,7 cleared */ 468c2ecf20Sopenharmony_ci#define MLX4_BF_QP_SKIP_MASK 0xc0 478c2ecf20Sopenharmony_ci#define MLX4_MAX_BF_QP_RANGE 0x40 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_civoid mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 528c2ecf20Sopenharmony_ci struct mlx4_qp *qp; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci spin_lock(&qp_table->lock); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci qp = __mlx4_qp_lookup(dev, qpn); 578c2ecf20Sopenharmony_ci if (qp) 588c2ecf20Sopenharmony_ci refcount_inc(&qp->refcount); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci spin_unlock(&qp_table->lock); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!qp) { 638c2ecf20Sopenharmony_ci mlx4_dbg(dev, "Async event for none existent QP %08x\n", qpn); 648c2ecf20Sopenharmony_ci return; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci qp->event(qp, event_type); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&qp->refcount)) 708c2ecf20Sopenharmony_ci complete(&qp->free); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* used for INIT/CLOSE port logic */ 748c2ecf20Sopenharmony_cistatic int is_master_qp0(struct mlx4_dev *dev, struct mlx4_qp *qp, int *real_qp0, int *proxy_qp0) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci /* this procedure is called after we already know we are on the master */ 778c2ecf20Sopenharmony_ci /* qp0 is either the proxy qp0, or the real qp0 */ 788c2ecf20Sopenharmony_ci u32 pf_proxy_offset = dev->phys_caps.base_proxy_sqpn + 8 * mlx4_master_func_num(dev); 798c2ecf20Sopenharmony_ci *proxy_qp0 = qp->qpn >= pf_proxy_offset && qp->qpn <= pf_proxy_offset + 1; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci *real_qp0 = qp->qpn >= dev->phys_caps.base_sqpn && 828c2ecf20Sopenharmony_ci qp->qpn <= dev->phys_caps.base_sqpn + 1; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return *real_qp0 || *proxy_qp0; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int __mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 888c2ecf20Sopenharmony_ci enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, 898c2ecf20Sopenharmony_ci struct mlx4_qp_context *context, 908c2ecf20Sopenharmony_ci enum mlx4_qp_optpar optpar, 918c2ecf20Sopenharmony_ci int sqd_event, struct mlx4_qp *qp, int native) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = { 948c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = { 958c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 968c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 978c2ecf20Sopenharmony_ci [MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP, 988c2ecf20Sopenharmony_ci }, 998c2ecf20Sopenharmony_ci [MLX4_QP_STATE_INIT] = { 1008c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1018c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1028c2ecf20Sopenharmony_ci [MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP, 1038c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP, 1048c2ecf20Sopenharmony_ci }, 1058c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTR] = { 1068c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1078c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1088c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP, 1098c2ecf20Sopenharmony_ci }, 1108c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTS] = { 1118c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1128c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1138c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP, 1148c2ecf20Sopenharmony_ci [MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP, 1158c2ecf20Sopenharmony_ci }, 1168c2ecf20Sopenharmony_ci [MLX4_QP_STATE_SQD] = { 1178c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1188c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1198c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP, 1208c2ecf20Sopenharmony_ci [MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci [MLX4_QP_STATE_SQER] = { 1238c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1248c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1258c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP, 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = { 1288c2ecf20Sopenharmony_ci [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 1298c2ecf20Sopenharmony_ci [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci }; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1348c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 1358c2ecf20Sopenharmony_ci int ret = 0; 1368c2ecf20Sopenharmony_ci int real_qp0 = 0; 1378c2ecf20Sopenharmony_ci int proxy_qp0 = 0; 1388c2ecf20Sopenharmony_ci u8 port; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || 1418c2ecf20Sopenharmony_ci !op[cur_state][new_state]) 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) { 1458c2ecf20Sopenharmony_ci ret = mlx4_cmd(dev, 0, qp->qpn, 2, 1468c2ecf20Sopenharmony_ci MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A, native); 1478c2ecf20Sopenharmony_ci if (mlx4_is_master(dev) && cur_state != MLX4_QP_STATE_ERR && 1488c2ecf20Sopenharmony_ci cur_state != MLX4_QP_STATE_RST && 1498c2ecf20Sopenharmony_ci is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { 1508c2ecf20Sopenharmony_ci port = (qp->qpn & 1) + 1; 1518c2ecf20Sopenharmony_ci if (proxy_qp0) 1528c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].qp0_active = 0; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 1608c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 1618c2ecf20Sopenharmony_ci return PTR_ERR(mailbox); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { 1648c2ecf20Sopenharmony_ci u64 mtt_addr = mlx4_mtt_addr(dev, mtt); 1658c2ecf20Sopenharmony_ci context->mtt_base_addr_h = mtt_addr >> 32; 1668c2ecf20Sopenharmony_ci context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); 1678c2ecf20Sopenharmony_ci context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if ((cur_state == MLX4_QP_STATE_RTR) && 1718c2ecf20Sopenharmony_ci (new_state == MLX4_QP_STATE_RTS) && 1728c2ecf20Sopenharmony_ci dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) 1738c2ecf20Sopenharmony_ci context->roce_entropy = 1748c2ecf20Sopenharmony_ci cpu_to_be16(mlx4_qp_roce_entropy(dev, qp->qpn)); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci *(__be32 *) mailbox->buf = cpu_to_be32(optpar); 1778c2ecf20Sopenharmony_ci memcpy(mailbox->buf + 8, context, sizeof(*context)); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = 1808c2ecf20Sopenharmony_ci cpu_to_be32(qp->qpn); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = mlx4_cmd(dev, mailbox->dma, 1838c2ecf20Sopenharmony_ci qp->qpn | (!!sqd_event << 31), 1848c2ecf20Sopenharmony_ci new_state == MLX4_QP_STATE_RST ? 2 : 0, 1858c2ecf20Sopenharmony_ci op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C, native); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (mlx4_is_master(dev) && is_master_qp0(dev, qp, &real_qp0, &proxy_qp0)) { 1888c2ecf20Sopenharmony_ci port = (qp->qpn & 1) + 1; 1898c2ecf20Sopenharmony_ci if (cur_state != MLX4_QP_STATE_ERR && 1908c2ecf20Sopenharmony_ci cur_state != MLX4_QP_STATE_RST && 1918c2ecf20Sopenharmony_ci new_state == MLX4_QP_STATE_ERR) { 1928c2ecf20Sopenharmony_ci if (proxy_qp0) 1938c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].proxy_qp0_active = 0; 1948c2ecf20Sopenharmony_ci else 1958c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].qp0_active = 0; 1968c2ecf20Sopenharmony_ci } else if (new_state == MLX4_QP_STATE_RTR) { 1978c2ecf20Sopenharmony_ci if (proxy_qp0) 1988c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].proxy_qp0_active = 1; 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci priv->mfunc.master.qp0_state[port].qp0_active = 1; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciint mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 2098c2ecf20Sopenharmony_ci enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, 2108c2ecf20Sopenharmony_ci struct mlx4_qp_context *context, 2118c2ecf20Sopenharmony_ci enum mlx4_qp_optpar optpar, 2128c2ecf20Sopenharmony_ci int sqd_event, struct mlx4_qp *qp) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci return __mlx4_qp_modify(dev, mtt, cur_state, new_state, context, 2158c2ecf20Sopenharmony_ci optpar, sqd_event, qp, 0); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_modify); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciint __mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, 2208c2ecf20Sopenharmony_ci int *base, u8 flags) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u32 uid; 2238c2ecf20Sopenharmony_ci int bf_qp = !!(flags & (u8)MLX4_RESERVE_ETH_BF_QP); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2268c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &priv->qp_table; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (cnt > MLX4_MAX_BF_QP_RANGE && bf_qp) 2298c2ecf20Sopenharmony_ci return -ENOMEM; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci uid = MLX4_QP_TABLE_ZONE_GENERAL; 2328c2ecf20Sopenharmony_ci if (flags & (u8)MLX4_RESERVE_A0_QP) { 2338c2ecf20Sopenharmony_ci if (bf_qp) 2348c2ecf20Sopenharmony_ci uid = MLX4_QP_TABLE_ZONE_RAW_ETH; 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci uid = MLX4_QP_TABLE_ZONE_RSS; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci *base = mlx4_zone_alloc_entries(qp_table->zones, uid, cnt, align, 2408c2ecf20Sopenharmony_ci bf_qp ? MLX4_BF_QP_SKIP_MASK : 0, NULL); 2418c2ecf20Sopenharmony_ci if (*base == -1) 2428c2ecf20Sopenharmony_ci return -ENOMEM; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciint mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, 2488c2ecf20Sopenharmony_ci int *base, u8 flags, u8 usage) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci u32 in_modifier = RES_QP | (((u32)usage & 3) << 30); 2518c2ecf20Sopenharmony_ci u64 in_param = 0; 2528c2ecf20Sopenharmony_ci u64 out_param; 2538c2ecf20Sopenharmony_ci int err; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Turn off all unsupported QP allocation flags */ 2568c2ecf20Sopenharmony_ci flags &= dev->caps.alloc_res_qp_mask; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 2598c2ecf20Sopenharmony_ci set_param_l(&in_param, (((u32)flags) << 24) | (u32)cnt); 2608c2ecf20Sopenharmony_ci set_param_h(&in_param, align); 2618c2ecf20Sopenharmony_ci err = mlx4_cmd_imm(dev, in_param, &out_param, 2628c2ecf20Sopenharmony_ci in_modifier, RES_OP_RESERVE, 2638c2ecf20Sopenharmony_ci MLX4_CMD_ALLOC_RES, 2648c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 2658c2ecf20Sopenharmony_ci if (err) 2668c2ecf20Sopenharmony_ci return err; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci *base = get_param_l(&out_param); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci return __mlx4_qp_reserve_range(dev, cnt, align, base, flags); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_civoid __mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 2788c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &priv->qp_table; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (mlx4_is_qp_reserved(dev, (u32) base_qpn)) 2818c2ecf20Sopenharmony_ci return; 2828c2ecf20Sopenharmony_ci mlx4_zone_free_entries_unique(qp_table->zones, base_qpn, cnt); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_civoid mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u64 in_param = 0; 2888c2ecf20Sopenharmony_ci int err; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (!cnt) 2918c2ecf20Sopenharmony_ci return; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 2948c2ecf20Sopenharmony_ci set_param_l(&in_param, base_qpn); 2958c2ecf20Sopenharmony_ci set_param_h(&in_param, cnt); 2968c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, in_param, RES_QP, RES_OP_RESERVE, 2978c2ecf20Sopenharmony_ci MLX4_CMD_FREE_RES, 2988c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 2998c2ecf20Sopenharmony_ci if (err) { 3008c2ecf20Sopenharmony_ci mlx4_warn(dev, "Failed to release qp range base:%d cnt:%d\n", 3018c2ecf20Sopenharmony_ci base_qpn, cnt); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci } else 3048c2ecf20Sopenharmony_ci __mlx4_qp_release_range(dev, base_qpn, cnt); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_release_range); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ciint __mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 3118c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &priv->qp_table; 3128c2ecf20Sopenharmony_ci int err; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci err = mlx4_table_get(dev, &qp_table->qp_table, qpn); 3158c2ecf20Sopenharmony_ci if (err) 3168c2ecf20Sopenharmony_ci goto err_out; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci err = mlx4_table_get(dev, &qp_table->auxc_table, qpn); 3198c2ecf20Sopenharmony_ci if (err) 3208c2ecf20Sopenharmony_ci goto err_put_qp; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci err = mlx4_table_get(dev, &qp_table->altc_table, qpn); 3238c2ecf20Sopenharmony_ci if (err) 3248c2ecf20Sopenharmony_ci goto err_put_auxc; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn); 3278c2ecf20Sopenharmony_ci if (err) 3288c2ecf20Sopenharmony_ci goto err_put_altc; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn); 3318c2ecf20Sopenharmony_ci if (err) 3328c2ecf20Sopenharmony_ci goto err_put_rdmarc; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cierr_put_rdmarc: 3378c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cierr_put_altc: 3408c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->altc_table, qpn); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cierr_put_auxc: 3438c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->auxc_table, qpn); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cierr_put_qp: 3468c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->qp_table, qpn); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cierr_out: 3498c2ecf20Sopenharmony_ci return err; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci u64 param = 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 3578c2ecf20Sopenharmony_ci set_param_l(¶m, qpn); 3588c2ecf20Sopenharmony_ci return mlx4_cmd_imm(dev, param, ¶m, RES_QP, RES_OP_MAP_ICM, 3598c2ecf20Sopenharmony_ci MLX4_CMD_ALLOC_RES, MLX4_CMD_TIME_CLASS_A, 3608c2ecf20Sopenharmony_ci MLX4_CMD_WRAPPED); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci return __mlx4_qp_alloc_icm(dev, qpn); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_civoid __mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 3688c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &priv->qp_table; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->cmpt_table, qpn); 3718c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->rdmarc_table, qpn); 3728c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->altc_table, qpn); 3738c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->auxc_table, qpn); 3748c2ecf20Sopenharmony_ci mlx4_table_put(dev, &qp_table->qp_table, qpn); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci u64 in_param = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 3828c2ecf20Sopenharmony_ci set_param_l(&in_param, qpn); 3838c2ecf20Sopenharmony_ci if (mlx4_cmd(dev, in_param, RES_QP, RES_OP_MAP_ICM, 3848c2ecf20Sopenharmony_ci MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 3858c2ecf20Sopenharmony_ci MLX4_CMD_WRAPPED)) 3868c2ecf20Sopenharmony_ci mlx4_warn(dev, "Failed to free icm of qp:%d\n", qpn); 3878c2ecf20Sopenharmony_ci } else 3888c2ecf20Sopenharmony_ci __mlx4_qp_free_icm(dev, qpn); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistruct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 3948c2ecf20Sopenharmony_ci struct mlx4_qp *qp; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci spin_lock_irq(&qp_table->lock); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci qp = __mlx4_qp_lookup(dev, qpn); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci spin_unlock_irq(&qp_table->lock); 4018c2ecf20Sopenharmony_ci return qp; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciint mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 4078c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &priv->qp_table; 4088c2ecf20Sopenharmony_ci int err; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (!qpn) 4118c2ecf20Sopenharmony_ci return -EINVAL; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci qp->qpn = qpn; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci err = mlx4_qp_alloc_icm(dev, qpn); 4168c2ecf20Sopenharmony_ci if (err) 4178c2ecf20Sopenharmony_ci return err; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci spin_lock_irq(&qp_table->lock); 4208c2ecf20Sopenharmony_ci err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & 4218c2ecf20Sopenharmony_ci (dev->caps.num_qps - 1), qp); 4228c2ecf20Sopenharmony_ci spin_unlock_irq(&qp_table->lock); 4238c2ecf20Sopenharmony_ci if (err) 4248c2ecf20Sopenharmony_ci goto err_icm; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci refcount_set(&qp->refcount, 1); 4278c2ecf20Sopenharmony_ci init_completion(&qp->free); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cierr_icm: 4328c2ecf20Sopenharmony_ci mlx4_qp_free_icm(dev, qpn); 4338c2ecf20Sopenharmony_ci return err; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_alloc); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ciint mlx4_update_qp(struct mlx4_dev *dev, u32 qpn, 4398c2ecf20Sopenharmony_ci enum mlx4_update_qp_attr attr, 4408c2ecf20Sopenharmony_ci struct mlx4_update_qp_params *params) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 4438c2ecf20Sopenharmony_ci struct mlx4_update_qp_context *cmd; 4448c2ecf20Sopenharmony_ci u64 pri_addr_path_mask = 0; 4458c2ecf20Sopenharmony_ci u64 qp_mask = 0; 4468c2ecf20Sopenharmony_ci int err = 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (!attr || (attr & ~MLX4_UPDATE_QP_SUPPORTED_ATTRS)) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 4528c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 4538c2ecf20Sopenharmony_ci return PTR_ERR(mailbox); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci cmd = (struct mlx4_update_qp_context *)mailbox->buf; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (attr & MLX4_UPDATE_QP_SMAC) { 4588c2ecf20Sopenharmony_ci pri_addr_path_mask |= 1ULL << MLX4_UPD_QP_PATH_MASK_MAC_INDEX; 4598c2ecf20Sopenharmony_ci cmd->qp_context.pri_path.grh_mylmc = params->smac_index; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (attr & MLX4_UPDATE_QP_ETH_SRC_CHECK_MC_LB) { 4638c2ecf20Sopenharmony_ci if (!(dev->caps.flags2 4648c2ecf20Sopenharmony_ci & MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB)) { 4658c2ecf20Sopenharmony_ci mlx4_warn(dev, 4668c2ecf20Sopenharmony_ci "Trying to set src check LB, but it isn't supported\n"); 4678c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci pri_addr_path_mask |= 4718c2ecf20Sopenharmony_ci 1ULL << MLX4_UPD_QP_PATH_MASK_ETH_SRC_CHECK_MC_LB; 4728c2ecf20Sopenharmony_ci if (params->flags & 4738c2ecf20Sopenharmony_ci MLX4_UPDATE_QP_PARAMS_FLAGS_ETH_CHECK_MC_LB) { 4748c2ecf20Sopenharmony_ci cmd->qp_context.pri_path.fl |= 4758c2ecf20Sopenharmony_ci MLX4_FL_ETH_SRC_CHECK_MC_LB; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (attr & MLX4_UPDATE_QP_VSD) { 4808c2ecf20Sopenharmony_ci qp_mask |= 1ULL << MLX4_UPD_QP_MASK_VSD; 4818c2ecf20Sopenharmony_ci if (params->flags & MLX4_UPDATE_QP_PARAMS_FLAGS_VSD_ENABLE) 4828c2ecf20Sopenharmony_ci cmd->qp_context.param3 |= cpu_to_be32(MLX4_STRIP_VLAN); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (attr & MLX4_UPDATE_QP_RATE_LIMIT) { 4868c2ecf20Sopenharmony_ci qp_mask |= 1ULL << MLX4_UPD_QP_MASK_RATE_LIMIT; 4878c2ecf20Sopenharmony_ci cmd->qp_context.rate_limit_params = cpu_to_be16((params->rate_unit << 14) | params->rate_val); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (attr & MLX4_UPDATE_QP_QOS_VPORT) { 4918c2ecf20Sopenharmony_ci if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) { 4928c2ecf20Sopenharmony_ci mlx4_warn(dev, "Granular QoS per VF is not enabled\n"); 4938c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 4948c2ecf20Sopenharmony_ci goto out; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP; 4988c2ecf20Sopenharmony_ci cmd->qp_context.qos_vport = params->qos_vport; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci cmd->primary_addr_path_mask = cpu_to_be64(pri_addr_path_mask); 5028c2ecf20Sopenharmony_ci cmd->qp_mask = cpu_to_be64(qp_mask); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci err = mlx4_cmd(dev, mailbox->dma, qpn & 0xffffff, 0, 5058c2ecf20Sopenharmony_ci MLX4_CMD_UPDATE_QP, MLX4_CMD_TIME_CLASS_A, 5068c2ecf20Sopenharmony_ci MLX4_CMD_NATIVE); 5078c2ecf20Sopenharmony_ciout: 5088c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 5098c2ecf20Sopenharmony_ci return err; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_update_qp); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_civoid mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 5168c2ecf20Sopenharmony_ci unsigned long flags; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp_table->lock, flags); 5198c2ecf20Sopenharmony_ci radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); 5208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp_table->lock, flags); 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_remove); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_civoid mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&qp->refcount)) 5278c2ecf20Sopenharmony_ci complete(&qp->free); 5288c2ecf20Sopenharmony_ci wait_for_completion(&qp->free); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci mlx4_qp_free_icm(dev, qp->qpn); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_free); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP, 5378c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci#define MLX4_QP_TABLE_RSS_ETH_PRIORITY 2 5418c2ecf20Sopenharmony_ci#define MLX4_QP_TABLE_RAW_ETH_PRIORITY 1 5428c2ecf20Sopenharmony_ci#define MLX4_QP_TABLE_RAW_ETH_SIZE 256 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int mlx4_create_zones(struct mlx4_dev *dev, 5458c2ecf20Sopenharmony_ci u32 reserved_bottom_general, 5468c2ecf20Sopenharmony_ci u32 reserved_top_general, 5478c2ecf20Sopenharmony_ci u32 reserved_bottom_rss, 5488c2ecf20Sopenharmony_ci u32 start_offset_rss, 5498c2ecf20Sopenharmony_ci u32 max_table_offset) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 5528c2ecf20Sopenharmony_ci struct mlx4_bitmap (*bitmap)[MLX4_QP_TABLE_ZONE_NUM] = NULL; 5538c2ecf20Sopenharmony_ci int bitmap_initialized = 0; 5548c2ecf20Sopenharmony_ci u32 last_offset; 5558c2ecf20Sopenharmony_ci int k; 5568c2ecf20Sopenharmony_ci int err; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci qp_table->zones = mlx4_zone_allocator_create(MLX4_ZONE_ALLOC_FLAGS_NO_OVERLAP); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (NULL == qp_table->zones) 5618c2ecf20Sopenharmony_ci return -ENOMEM; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (NULL == bitmap) { 5668c2ecf20Sopenharmony_ci err = -ENOMEM; 5678c2ecf20Sopenharmony_ci goto free_zone; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci err = mlx4_bitmap_init(*bitmap + MLX4_QP_TABLE_ZONE_GENERAL, dev->caps.num_qps, 5718c2ecf20Sopenharmony_ci (1 << 23) - 1, reserved_bottom_general, 5728c2ecf20Sopenharmony_ci reserved_top_general); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (err) 5758c2ecf20Sopenharmony_ci goto free_bitmap; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci ++bitmap_initialized; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = mlx4_zone_add_one(qp_table->zones, *bitmap + MLX4_QP_TABLE_ZONE_GENERAL, 5808c2ecf20Sopenharmony_ci MLX4_ZONE_FALLBACK_TO_HIGHER_PRIO | 5818c2ecf20Sopenharmony_ci MLX4_ZONE_USE_RR, 0, 5828c2ecf20Sopenharmony_ci 0, qp_table->zones_uids + MLX4_QP_TABLE_ZONE_GENERAL); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (err) 5858c2ecf20Sopenharmony_ci goto free_bitmap; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci err = mlx4_bitmap_init(*bitmap + MLX4_QP_TABLE_ZONE_RSS, 5888c2ecf20Sopenharmony_ci reserved_bottom_rss, 5898c2ecf20Sopenharmony_ci reserved_bottom_rss - 1, 5908c2ecf20Sopenharmony_ci dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 5918c2ecf20Sopenharmony_ci reserved_bottom_rss - start_offset_rss); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (err) 5948c2ecf20Sopenharmony_ci goto free_bitmap; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci ++bitmap_initialized; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci err = mlx4_zone_add_one(qp_table->zones, *bitmap + MLX4_QP_TABLE_ZONE_RSS, 5998c2ecf20Sopenharmony_ci MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO | 6008c2ecf20Sopenharmony_ci MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO | 6018c2ecf20Sopenharmony_ci MLX4_ZONE_USE_RR, MLX4_QP_TABLE_RSS_ETH_PRIORITY, 6028c2ecf20Sopenharmony_ci 0, qp_table->zones_uids + MLX4_QP_TABLE_ZONE_RSS); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (err) 6058c2ecf20Sopenharmony_ci goto free_bitmap; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci last_offset = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW]; 6088c2ecf20Sopenharmony_ci /* We have a single zone for the A0 steering QPs area of the FW. This area 6098c2ecf20Sopenharmony_ci * needs to be split into subareas. One set of subareas is for RSS QPs 6108c2ecf20Sopenharmony_ci * (in which qp number bits 6 and/or 7 are set); the other set of subareas 6118c2ecf20Sopenharmony_ci * is for RAW_ETH QPs, which require that both bits 6 and 7 are zero. 6128c2ecf20Sopenharmony_ci * Currently, the values returned by the FW (A0 steering area starting qp number 6138c2ecf20Sopenharmony_ci * and A0 steering area size) are such that there are only two subareas -- one 6148c2ecf20Sopenharmony_ci * for RSS and one for RAW_ETH. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci for (k = MLX4_QP_TABLE_ZONE_RSS + 1; k < sizeof(*bitmap)/sizeof((*bitmap)[0]); 6178c2ecf20Sopenharmony_ci k++) { 6188c2ecf20Sopenharmony_ci int size; 6198c2ecf20Sopenharmony_ci u32 offset = start_offset_rss; 6208c2ecf20Sopenharmony_ci u32 bf_mask; 6218c2ecf20Sopenharmony_ci u32 requested_size; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* Assuming MLX4_BF_QP_SKIP_MASK is consecutive ones, this calculates 6248c2ecf20Sopenharmony_ci * a mask of all LSB bits set until (and not including) the first 6258c2ecf20Sopenharmony_ci * set bit of MLX4_BF_QP_SKIP_MASK. For example, if MLX4_BF_QP_SKIP_MASK 6268c2ecf20Sopenharmony_ci * is 0xc0, bf_mask will be 0x3f. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci bf_mask = (MLX4_BF_QP_SKIP_MASK & ~(MLX4_BF_QP_SKIP_MASK - 1)) - 1; 6298c2ecf20Sopenharmony_ci requested_size = min((u32)MLX4_QP_TABLE_RAW_ETH_SIZE, bf_mask + 1); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (((last_offset & MLX4_BF_QP_SKIP_MASK) && 6328c2ecf20Sopenharmony_ci ((int)(max_table_offset - last_offset)) >= 6338c2ecf20Sopenharmony_ci roundup_pow_of_two(MLX4_BF_QP_SKIP_MASK)) || 6348c2ecf20Sopenharmony_ci (!(last_offset & MLX4_BF_QP_SKIP_MASK) && 6358c2ecf20Sopenharmony_ci !((last_offset + requested_size - 1) & 6368c2ecf20Sopenharmony_ci MLX4_BF_QP_SKIP_MASK))) 6378c2ecf20Sopenharmony_ci size = requested_size; 6388c2ecf20Sopenharmony_ci else { 6398c2ecf20Sopenharmony_ci u32 candidate_offset = 6408c2ecf20Sopenharmony_ci (last_offset | MLX4_BF_QP_SKIP_MASK | bf_mask) + 1; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (last_offset & MLX4_BF_QP_SKIP_MASK) 6438c2ecf20Sopenharmony_ci last_offset = candidate_offset; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* From this point, the BF bits are 0 */ 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (last_offset > max_table_offset) { 6488c2ecf20Sopenharmony_ci /* need to skip */ 6498c2ecf20Sopenharmony_ci size = -1; 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci size = min3(max_table_offset - last_offset, 6528c2ecf20Sopenharmony_ci bf_mask - (last_offset & bf_mask), 6538c2ecf20Sopenharmony_ci requested_size); 6548c2ecf20Sopenharmony_ci if (size < requested_size) { 6558c2ecf20Sopenharmony_ci int candidate_size; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci candidate_size = min3( 6588c2ecf20Sopenharmony_ci max_table_offset - candidate_offset, 6598c2ecf20Sopenharmony_ci bf_mask - (last_offset & bf_mask), 6608c2ecf20Sopenharmony_ci requested_size); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* We will not take this path if last_offset was 6638c2ecf20Sopenharmony_ci * already set above to candidate_offset 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_ci if (candidate_size > size) { 6668c2ecf20Sopenharmony_ci last_offset = candidate_offset; 6678c2ecf20Sopenharmony_ci size = candidate_size; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (size > 0) { 6748c2ecf20Sopenharmony_ci /* mlx4_bitmap_alloc_range will find a contiguous range of "size" 6758c2ecf20Sopenharmony_ci * QPs in which both bits 6 and 7 are zero, because we pass it the 6768c2ecf20Sopenharmony_ci * MLX4_BF_SKIP_MASK). 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci offset = mlx4_bitmap_alloc_range( 6798c2ecf20Sopenharmony_ci *bitmap + MLX4_QP_TABLE_ZONE_RSS, 6808c2ecf20Sopenharmony_ci size, 1, 6818c2ecf20Sopenharmony_ci MLX4_BF_QP_SKIP_MASK); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (offset == (u32)-1) { 6848c2ecf20Sopenharmony_ci err = -ENOMEM; 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci last_offset = offset + size; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci err = mlx4_bitmap_init(*bitmap + k, roundup_pow_of_two(size), 6918c2ecf20Sopenharmony_ci roundup_pow_of_two(size) - 1, 0, 6928c2ecf20Sopenharmony_ci roundup_pow_of_two(size) - size); 6938c2ecf20Sopenharmony_ci } else { 6948c2ecf20Sopenharmony_ci /* Add an empty bitmap, we'll allocate from different zones (since 6958c2ecf20Sopenharmony_ci * at least one is reserved) 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci err = mlx4_bitmap_init(*bitmap + k, 1, 6988c2ecf20Sopenharmony_ci MLX4_QP_TABLE_RAW_ETH_SIZE - 1, 0, 6998c2ecf20Sopenharmony_ci 0); 7008c2ecf20Sopenharmony_ci if (!err) 7018c2ecf20Sopenharmony_ci mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (err) 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ++bitmap_initialized; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci err = mlx4_zone_add_one(qp_table->zones, *bitmap + k, 7108c2ecf20Sopenharmony_ci MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO | 7118c2ecf20Sopenharmony_ci MLX4_ZONE_ALLOW_ALLOC_FROM_EQ_PRIO | 7128c2ecf20Sopenharmony_ci MLX4_ZONE_USE_RR, MLX4_QP_TABLE_RAW_ETH_PRIORITY, 7138c2ecf20Sopenharmony_ci offset, qp_table->zones_uids + k); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (err) 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (err) 7208c2ecf20Sopenharmony_ci goto free_bitmap; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci qp_table->bitmap_gen = *bitmap; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci return err; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cifree_bitmap: 7278c2ecf20Sopenharmony_ci for (k = 0; k < bitmap_initialized; k++) 7288c2ecf20Sopenharmony_ci mlx4_bitmap_cleanup(*bitmap + k); 7298c2ecf20Sopenharmony_ci kfree(bitmap); 7308c2ecf20Sopenharmony_cifree_zone: 7318c2ecf20Sopenharmony_ci mlx4_zone_allocator_destroy(qp_table->zones); 7328c2ecf20Sopenharmony_ci return err; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic void mlx4_cleanup_qp_zones(struct mlx4_dev *dev) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (qp_table->zones) { 7408c2ecf20Sopenharmony_ci int i; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci for (i = 0; 7438c2ecf20Sopenharmony_ci i < sizeof(qp_table->zones_uids)/sizeof(qp_table->zones_uids[0]); 7448c2ecf20Sopenharmony_ci i++) { 7458c2ecf20Sopenharmony_ci struct mlx4_bitmap *bitmap = 7468c2ecf20Sopenharmony_ci mlx4_zone_get_bitmap(qp_table->zones, 7478c2ecf20Sopenharmony_ci qp_table->zones_uids[i]); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci mlx4_zone_remove_one(qp_table->zones, qp_table->zones_uids[i]); 7508c2ecf20Sopenharmony_ci if (NULL == bitmap) 7518c2ecf20Sopenharmony_ci continue; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci mlx4_bitmap_cleanup(bitmap); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci mlx4_zone_allocator_destroy(qp_table->zones); 7568c2ecf20Sopenharmony_ci kfree(qp_table->bitmap_gen); 7578c2ecf20Sopenharmony_ci qp_table->bitmap_gen = NULL; 7588c2ecf20Sopenharmony_ci qp_table->zones = NULL; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ciint mlx4_init_qp_table(struct mlx4_dev *dev) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 7658c2ecf20Sopenharmony_ci int err; 7668c2ecf20Sopenharmony_ci int reserved_from_top = 0; 7678c2ecf20Sopenharmony_ci int reserved_from_bot; 7688c2ecf20Sopenharmony_ci int k; 7698c2ecf20Sopenharmony_ci int fixed_reserved_from_bot_rv = 0; 7708c2ecf20Sopenharmony_ci int bottom_reserved_for_rss_bitmap; 7718c2ecf20Sopenharmony_ci u32 max_table_offset = dev->caps.dmfs_high_rate_qpn_base + 7728c2ecf20Sopenharmony_ci dev->caps.dmfs_high_rate_qpn_range; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci spin_lock_init(&qp_table->lock); 7758c2ecf20Sopenharmony_ci INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); 7768c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* We reserve 2 extra QPs per port for the special QPs. The 7808c2ecf20Sopenharmony_ci * block of special QPs must be aligned to a multiple of 8, so 7818c2ecf20Sopenharmony_ci * round up. 7828c2ecf20Sopenharmony_ci * 7838c2ecf20Sopenharmony_ci * We also reserve the MSB of the 24-bit QP number to indicate 7848c2ecf20Sopenharmony_ci * that a QP is an XRC QP. 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_ci for (k = 0; k <= MLX4_QP_REGION_BOTTOM; k++) 7878c2ecf20Sopenharmony_ci fixed_reserved_from_bot_rv += dev->caps.reserved_qps_cnt[k]; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (fixed_reserved_from_bot_rv < max_table_offset) 7908c2ecf20Sopenharmony_ci fixed_reserved_from_bot_rv = max_table_offset; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* We reserve at least 1 extra for bitmaps that we don't have enough space for*/ 7938c2ecf20Sopenharmony_ci bottom_reserved_for_rss_bitmap = 7948c2ecf20Sopenharmony_ci roundup_pow_of_two(fixed_reserved_from_bot_rv + 1); 7958c2ecf20Sopenharmony_ci dev->phys_caps.base_sqpn = ALIGN(bottom_reserved_for_rss_bitmap, 8); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci { 7988c2ecf20Sopenharmony_ci int sort[MLX4_NUM_QP_REGION]; 7998c2ecf20Sopenharmony_ci int i, j; 8008c2ecf20Sopenharmony_ci int last_base = dev->caps.num_qps; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci for (i = 1; i < MLX4_NUM_QP_REGION; ++i) 8038c2ecf20Sopenharmony_ci sort[i] = i; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci for (i = MLX4_NUM_QP_REGION; i > MLX4_QP_REGION_BOTTOM; --i) { 8068c2ecf20Sopenharmony_ci for (j = MLX4_QP_REGION_BOTTOM + 2; j < i; ++j) { 8078c2ecf20Sopenharmony_ci if (dev->caps.reserved_qps_cnt[sort[j]] > 8088c2ecf20Sopenharmony_ci dev->caps.reserved_qps_cnt[sort[j - 1]]) 8098c2ecf20Sopenharmony_ci swap(sort[j], sort[j - 1]); 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci for (i = MLX4_QP_REGION_BOTTOM + 1; i < MLX4_NUM_QP_REGION; ++i) { 8148c2ecf20Sopenharmony_ci last_base -= dev->caps.reserved_qps_cnt[sort[i]]; 8158c2ecf20Sopenharmony_ci dev->caps.reserved_qps_base[sort[i]] = last_base; 8168c2ecf20Sopenharmony_ci reserved_from_top += 8178c2ecf20Sopenharmony_ci dev->caps.reserved_qps_cnt[sort[i]]; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Reserve 8 real SQPs in both native and SRIOV modes. 8228c2ecf20Sopenharmony_ci * In addition, in SRIOV mode, reserve 8 proxy SQPs per function 8238c2ecf20Sopenharmony_ci * (for all PFs and VFs), and 8 corresponding tunnel QPs. 8248c2ecf20Sopenharmony_ci * Each proxy SQP works opposite its own tunnel QP. 8258c2ecf20Sopenharmony_ci * 8268c2ecf20Sopenharmony_ci * The QPs are arranged as follows: 8278c2ecf20Sopenharmony_ci * a. 8 real SQPs 8288c2ecf20Sopenharmony_ci * b. All the proxy SQPs (8 per function) 8298c2ecf20Sopenharmony_ci * c. All the tunnel QPs (8 per function) 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci reserved_from_bot = mlx4_num_reserved_sqps(dev); 8328c2ecf20Sopenharmony_ci if (reserved_from_bot + reserved_from_top > dev->caps.num_qps) { 8338c2ecf20Sopenharmony_ci mlx4_err(dev, "Number of reserved QPs is higher than number of QPs\n"); 8348c2ecf20Sopenharmony_ci return -EINVAL; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci err = mlx4_create_zones(dev, reserved_from_bot, reserved_from_bot, 8388c2ecf20Sopenharmony_ci bottom_reserved_for_rss_bitmap, 8398c2ecf20Sopenharmony_ci fixed_reserved_from_bot_rv, 8408c2ecf20Sopenharmony_ci max_table_offset); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (err) 8438c2ecf20Sopenharmony_ci return err; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev)) { 8468c2ecf20Sopenharmony_ci /* for PPF use */ 8478c2ecf20Sopenharmony_ci dev->phys_caps.base_proxy_sqpn = dev->phys_caps.base_sqpn + 8; 8488c2ecf20Sopenharmony_ci dev->phys_caps.base_tunnel_sqpn = dev->phys_caps.base_sqpn + 8 + 8 * MLX4_MFUNC_MAX; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* In mfunc, calculate proxy and tunnel qp offsets for the PF here, 8518c2ecf20Sopenharmony_ci * since the PF does not call mlx4_slave_caps */ 8528c2ecf20Sopenharmony_ci dev->caps.spec_qps = kcalloc(dev->caps.num_ports, 8538c2ecf20Sopenharmony_ci sizeof(*dev->caps.spec_qps), 8548c2ecf20Sopenharmony_ci GFP_KERNEL); 8558c2ecf20Sopenharmony_ci if (!dev->caps.spec_qps) { 8568c2ecf20Sopenharmony_ci err = -ENOMEM; 8578c2ecf20Sopenharmony_ci goto err_mem; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci for (k = 0; k < dev->caps.num_ports; k++) { 8618c2ecf20Sopenharmony_ci dev->caps.spec_qps[k].qp0_proxy = dev->phys_caps.base_proxy_sqpn + 8628c2ecf20Sopenharmony_ci 8 * mlx4_master_func_num(dev) + k; 8638c2ecf20Sopenharmony_ci dev->caps.spec_qps[k].qp0_tunnel = dev->caps.spec_qps[k].qp0_proxy + 8 * MLX4_MFUNC_MAX; 8648c2ecf20Sopenharmony_ci dev->caps.spec_qps[k].qp1_proxy = dev->phys_caps.base_proxy_sqpn + 8658c2ecf20Sopenharmony_ci 8 * mlx4_master_func_num(dev) + MLX4_MAX_PORTS + k; 8668c2ecf20Sopenharmony_ci dev->caps.spec_qps[k].qp1_tunnel = dev->caps.spec_qps[k].qp1_proxy + 8 * MLX4_MFUNC_MAX; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci err = mlx4_CONF_SPECIAL_QP(dev, dev->phys_caps.base_sqpn); 8728c2ecf20Sopenharmony_ci if (err) 8738c2ecf20Sopenharmony_ci goto err_mem; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci return err; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cierr_mem: 8788c2ecf20Sopenharmony_ci kfree(dev->caps.spec_qps); 8798c2ecf20Sopenharmony_ci dev->caps.spec_qps = NULL; 8808c2ecf20Sopenharmony_ci mlx4_cleanup_qp_zones(dev); 8818c2ecf20Sopenharmony_ci return err; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_civoid mlx4_cleanup_qp_table(struct mlx4_dev *dev) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) 8878c2ecf20Sopenharmony_ci return; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci mlx4_CONF_SPECIAL_QP(dev, 0); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci mlx4_cleanup_qp_zones(dev); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ciint mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, 8958c2ecf20Sopenharmony_ci struct mlx4_qp_context *context) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *mailbox; 8988c2ecf20Sopenharmony_ci int err; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci mailbox = mlx4_alloc_cmd_mailbox(dev); 9018c2ecf20Sopenharmony_ci if (IS_ERR(mailbox)) 9028c2ecf20Sopenharmony_ci return PTR_ERR(mailbox); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0, 9058c2ecf20Sopenharmony_ci MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A, 9068c2ecf20Sopenharmony_ci MLX4_CMD_WRAPPED); 9078c2ecf20Sopenharmony_ci if (!err) 9088c2ecf20Sopenharmony_ci memcpy(context, mailbox->buf + 8, sizeof(*context)); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev, mailbox); 9118c2ecf20Sopenharmony_ci return err; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_query); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ciint mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 9168c2ecf20Sopenharmony_ci struct mlx4_qp_context *context, 9178c2ecf20Sopenharmony_ci struct mlx4_qp *qp, enum mlx4_qp_state *qp_state) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci int err; 9208c2ecf20Sopenharmony_ci int i; 9218c2ecf20Sopenharmony_ci enum mlx4_qp_state states[] = { 9228c2ecf20Sopenharmony_ci MLX4_QP_STATE_RST, 9238c2ecf20Sopenharmony_ci MLX4_QP_STATE_INIT, 9248c2ecf20Sopenharmony_ci MLX4_QP_STATE_RTR, 9258c2ecf20Sopenharmony_ci MLX4_QP_STATE_RTS 9268c2ecf20Sopenharmony_ci }; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { 9298c2ecf20Sopenharmony_ci context->flags &= cpu_to_be32(~(0xf << 28)); 9308c2ecf20Sopenharmony_ci context->flags |= cpu_to_be32(states[i + 1] << 28); 9318c2ecf20Sopenharmony_ci if (states[i + 1] != MLX4_QP_STATE_RTR) 9328c2ecf20Sopenharmony_ci context->params2 &= ~cpu_to_be32(MLX4_QP_BIT_FPP); 9338c2ecf20Sopenharmony_ci err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], 9348c2ecf20Sopenharmony_ci context, 0, 0, qp); 9358c2ecf20Sopenharmony_ci if (err) { 9368c2ecf20Sopenharmony_ci mlx4_err(dev, "Failed to bring QP to state: %d with error: %d\n", 9378c2ecf20Sopenharmony_ci states[i + 1], err); 9388c2ecf20Sopenharmony_ci return err; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci *qp_state = states[i + 1]; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_qp_to_ready); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ciu16 mlx4_qp_roce_entropy(struct mlx4_dev *dev, u32 qpn) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct mlx4_qp_context context; 9518c2ecf20Sopenharmony_ci struct mlx4_qp qp; 9528c2ecf20Sopenharmony_ci int err; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci qp.qpn = qpn; 9558c2ecf20Sopenharmony_ci err = mlx4_qp_query(dev, &qp, &context); 9568c2ecf20Sopenharmony_ci if (!err) { 9578c2ecf20Sopenharmony_ci u32 dest_qpn = be32_to_cpu(context.remote_qpn) & 0xffffff; 9588c2ecf20Sopenharmony_ci u16 folded_dst = folded_qp(dest_qpn); 9598c2ecf20Sopenharmony_ci u16 folded_src = folded_qp(qpn); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci return (dest_qpn != qpn) ? 9628c2ecf20Sopenharmony_ci ((folded_dst ^ folded_src) | 0xC000) : 9638c2ecf20Sopenharmony_ci folded_src | 0xC000; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci return 0xdead; 9668c2ecf20Sopenharmony_ci} 967