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(&param, qpn);
3588c2ecf20Sopenharmony_ci		return mlx4_cmd_imm(dev, param, &param, 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