18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
78c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
138c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
148c2ecf20Sopenharmony_ci *     conditions are met:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
178c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
188c2ecf20Sopenharmony_ci *        disclaimer.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
218c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
228c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
238c2ecf20Sopenharmony_ci *        provided with the distribution.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
328c2ecf20Sopenharmony_ci * SOFTWARE.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/sched.h>
368c2ecf20Sopenharmony_ci#include <linux/slab.h>
378c2ecf20Sopenharmony_ci#include <linux/export.h>
388c2ecf20Sopenharmony_ci#include <linux/pci.h>
398c2ecf20Sopenharmony_ci#include <linux/errno.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h>
428c2ecf20Sopenharmony_ci#include <linux/mlx4/device.h>
438c2ecf20Sopenharmony_ci#include <linux/semaphore.h>
448c2ecf20Sopenharmony_ci#include <rdma/ib_smi.h>
458c2ecf20Sopenharmony_ci#include <linux/delay.h>
468c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include <asm/io.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include "mlx4.h"
518c2ecf20Sopenharmony_ci#include "fw.h"
528c2ecf20Sopenharmony_ci#include "fw_qos.h"
538c2ecf20Sopenharmony_ci#include "mlx4_stats.h"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define CMD_POLL_TOKEN 0xffff
568c2ecf20Sopenharmony_ci#define INBOX_MASK	0xffffffffffffff00ULL
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define CMD_CHAN_VER 1
598c2ecf20Sopenharmony_ci#define CMD_CHAN_IF_REV 1
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cienum {
628c2ecf20Sopenharmony_ci	/* command completed successfully: */
638c2ecf20Sopenharmony_ci	CMD_STAT_OK		= 0x00,
648c2ecf20Sopenharmony_ci	/* Internal error (such as a bus error) occurred while processing command: */
658c2ecf20Sopenharmony_ci	CMD_STAT_INTERNAL_ERR	= 0x01,
668c2ecf20Sopenharmony_ci	/* Operation/command not supported or opcode modifier not supported: */
678c2ecf20Sopenharmony_ci	CMD_STAT_BAD_OP		= 0x02,
688c2ecf20Sopenharmony_ci	/* Parameter not supported or parameter out of range: */
698c2ecf20Sopenharmony_ci	CMD_STAT_BAD_PARAM	= 0x03,
708c2ecf20Sopenharmony_ci	/* System not enabled or bad system state: */
718c2ecf20Sopenharmony_ci	CMD_STAT_BAD_SYS_STATE	= 0x04,
728c2ecf20Sopenharmony_ci	/* Attempt to access reserved or unallocaterd resource: */
738c2ecf20Sopenharmony_ci	CMD_STAT_BAD_RESOURCE	= 0x05,
748c2ecf20Sopenharmony_ci	/* Requested resource is currently executing a command, or is otherwise busy: */
758c2ecf20Sopenharmony_ci	CMD_STAT_RESOURCE_BUSY	= 0x06,
768c2ecf20Sopenharmony_ci	/* Required capability exceeds device limits: */
778c2ecf20Sopenharmony_ci	CMD_STAT_EXCEED_LIM	= 0x08,
788c2ecf20Sopenharmony_ci	/* Resource is not in the appropriate state or ownership: */
798c2ecf20Sopenharmony_ci	CMD_STAT_BAD_RES_STATE	= 0x09,
808c2ecf20Sopenharmony_ci	/* Index out of range: */
818c2ecf20Sopenharmony_ci	CMD_STAT_BAD_INDEX	= 0x0a,
828c2ecf20Sopenharmony_ci	/* FW image corrupted: */
838c2ecf20Sopenharmony_ci	CMD_STAT_BAD_NVMEM	= 0x0b,
848c2ecf20Sopenharmony_ci	/* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */
858c2ecf20Sopenharmony_ci	CMD_STAT_ICM_ERROR	= 0x0c,
868c2ecf20Sopenharmony_ci	/* Attempt to modify a QP/EE which is not in the presumed state: */
878c2ecf20Sopenharmony_ci	CMD_STAT_BAD_QP_STATE   = 0x10,
888c2ecf20Sopenharmony_ci	/* Bad segment parameters (Address/Size): */
898c2ecf20Sopenharmony_ci	CMD_STAT_BAD_SEG_PARAM	= 0x20,
908c2ecf20Sopenharmony_ci	/* Memory Region has Memory Windows bound to: */
918c2ecf20Sopenharmony_ci	CMD_STAT_REG_BOUND	= 0x21,
928c2ecf20Sopenharmony_ci	/* HCA local attached memory not present: */
938c2ecf20Sopenharmony_ci	CMD_STAT_LAM_NOT_PRE	= 0x22,
948c2ecf20Sopenharmony_ci	/* Bad management packet (silently discarded): */
958c2ecf20Sopenharmony_ci	CMD_STAT_BAD_PKT	= 0x30,
968c2ecf20Sopenharmony_ci	/* More outstanding CQEs in CQ than new CQ size: */
978c2ecf20Sopenharmony_ci	CMD_STAT_BAD_SIZE	= 0x40,
988c2ecf20Sopenharmony_ci	/* Multi Function device support required: */
998c2ecf20Sopenharmony_ci	CMD_STAT_MULTI_FUNC_REQ	= 0x50,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cienum {
1038c2ecf20Sopenharmony_ci	HCR_IN_PARAM_OFFSET	= 0x00,
1048c2ecf20Sopenharmony_ci	HCR_IN_MODIFIER_OFFSET	= 0x08,
1058c2ecf20Sopenharmony_ci	HCR_OUT_PARAM_OFFSET	= 0x0c,
1068c2ecf20Sopenharmony_ci	HCR_TOKEN_OFFSET	= 0x14,
1078c2ecf20Sopenharmony_ci	HCR_STATUS_OFFSET	= 0x18,
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	HCR_OPMOD_SHIFT		= 12,
1108c2ecf20Sopenharmony_ci	HCR_T_BIT		= 21,
1118c2ecf20Sopenharmony_ci	HCR_E_BIT		= 22,
1128c2ecf20Sopenharmony_ci	HCR_GO_BIT		= 23
1138c2ecf20Sopenharmony_ci};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cienum {
1168c2ecf20Sopenharmony_ci	GO_BIT_TIMEOUT_MSECS	= 10000
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cienum mlx4_vlan_transition {
1208c2ecf20Sopenharmony_ci	MLX4_VLAN_TRANSITION_VST_VST = 0,
1218c2ecf20Sopenharmony_ci	MLX4_VLAN_TRANSITION_VST_VGT = 1,
1228c2ecf20Sopenharmony_ci	MLX4_VLAN_TRANSITION_VGT_VST = 2,
1238c2ecf20Sopenharmony_ci	MLX4_VLAN_TRANSITION_VGT_VGT = 3,
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistruct mlx4_cmd_context {
1288c2ecf20Sopenharmony_ci	struct completion	done;
1298c2ecf20Sopenharmony_ci	int			result;
1308c2ecf20Sopenharmony_ci	int			next;
1318c2ecf20Sopenharmony_ci	u64			out_param;
1328c2ecf20Sopenharmony_ci	u16			token;
1338c2ecf20Sopenharmony_ci	u8			fw_status;
1348c2ecf20Sopenharmony_ci};
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
1378c2ecf20Sopenharmony_ci				    struct mlx4_vhcr_cmd *in_vhcr);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int mlx4_status_to_errno(u8 status)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	static const int trans_table[] = {
1428c2ecf20Sopenharmony_ci		[CMD_STAT_INTERNAL_ERR]	  = -EIO,
1438c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_OP]	  = -EPERM,
1448c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_PARAM]	  = -EINVAL,
1458c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
1468c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_RESOURCE]	  = -EBADF,
1478c2ecf20Sopenharmony_ci		[CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
1488c2ecf20Sopenharmony_ci		[CMD_STAT_EXCEED_LIM]	  = -ENOMEM,
1498c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_RES_STATE]  = -EBADF,
1508c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_INDEX]	  = -EBADF,
1518c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_NVMEM]	  = -EFAULT,
1528c2ecf20Sopenharmony_ci		[CMD_STAT_ICM_ERROR]	  = -ENFILE,
1538c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_QP_STATE]   = -EINVAL,
1548c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
1558c2ecf20Sopenharmony_ci		[CMD_STAT_REG_BOUND]	  = -EBUSY,
1568c2ecf20Sopenharmony_ci		[CMD_STAT_LAM_NOT_PRE]	  = -EAGAIN,
1578c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_PKT]	  = -EINVAL,
1588c2ecf20Sopenharmony_ci		[CMD_STAT_BAD_SIZE]	  = -ENOMEM,
1598c2ecf20Sopenharmony_ci		[CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
1608c2ecf20Sopenharmony_ci	};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (status >= ARRAY_SIZE(trans_table) ||
1638c2ecf20Sopenharmony_ci	    (status != CMD_STAT_OK && trans_table[status] == 0))
1648c2ecf20Sopenharmony_ci		return -EIO;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return trans_table[status];
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic u8 mlx4_errno_to_status(int errno)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	switch (errno) {
1728c2ecf20Sopenharmony_ci	case -EPERM:
1738c2ecf20Sopenharmony_ci		return CMD_STAT_BAD_OP;
1748c2ecf20Sopenharmony_ci	case -EINVAL:
1758c2ecf20Sopenharmony_ci		return CMD_STAT_BAD_PARAM;
1768c2ecf20Sopenharmony_ci	case -ENXIO:
1778c2ecf20Sopenharmony_ci		return CMD_STAT_BAD_SYS_STATE;
1788c2ecf20Sopenharmony_ci	case -EBUSY:
1798c2ecf20Sopenharmony_ci		return CMD_STAT_RESOURCE_BUSY;
1808c2ecf20Sopenharmony_ci	case -ENOMEM:
1818c2ecf20Sopenharmony_ci		return CMD_STAT_EXCEED_LIM;
1828c2ecf20Sopenharmony_ci	case -ENFILE:
1838c2ecf20Sopenharmony_ci		return CMD_STAT_ICM_ERROR;
1848c2ecf20Sopenharmony_ci	default:
1858c2ecf20Sopenharmony_ci		return CMD_STAT_INTERNAL_ERR;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op,
1908c2ecf20Sopenharmony_ci				       u8 op_modifier)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	switch (op) {
1938c2ecf20Sopenharmony_ci	case MLX4_CMD_UNMAP_ICM:
1948c2ecf20Sopenharmony_ci	case MLX4_CMD_UNMAP_ICM_AUX:
1958c2ecf20Sopenharmony_ci	case MLX4_CMD_UNMAP_FA:
1968c2ecf20Sopenharmony_ci	case MLX4_CMD_2RST_QP:
1978c2ecf20Sopenharmony_ci	case MLX4_CMD_HW2SW_EQ:
1988c2ecf20Sopenharmony_ci	case MLX4_CMD_HW2SW_CQ:
1998c2ecf20Sopenharmony_ci	case MLX4_CMD_HW2SW_SRQ:
2008c2ecf20Sopenharmony_ci	case MLX4_CMD_HW2SW_MPT:
2018c2ecf20Sopenharmony_ci	case MLX4_CMD_CLOSE_HCA:
2028c2ecf20Sopenharmony_ci	case MLX4_QP_FLOW_STEERING_DETACH:
2038c2ecf20Sopenharmony_ci	case MLX4_CMD_FREE_RES:
2048c2ecf20Sopenharmony_ci	case MLX4_CMD_CLOSE_PORT:
2058c2ecf20Sopenharmony_ci		return CMD_STAT_OK;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	case MLX4_CMD_QP_ATTACH:
2088c2ecf20Sopenharmony_ci		/* On Detach case return success */
2098c2ecf20Sopenharmony_ci		if (op_modifier == 0)
2108c2ecf20Sopenharmony_ci			return CMD_STAT_OK;
2118c2ecf20Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	default:
2148c2ecf20Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	/* Any error during the closing commands below is considered fatal */
2218c2ecf20Sopenharmony_ci	if (op == MLX4_CMD_CLOSE_HCA ||
2228c2ecf20Sopenharmony_ci	    op == MLX4_CMD_HW2SW_EQ ||
2238c2ecf20Sopenharmony_ci	    op == MLX4_CMD_HW2SW_CQ ||
2248c2ecf20Sopenharmony_ci	    op == MLX4_CMD_2RST_QP ||
2258c2ecf20Sopenharmony_ci	    op == MLX4_CMD_HW2SW_SRQ ||
2268c2ecf20Sopenharmony_ci	    op == MLX4_CMD_SYNC_TPT ||
2278c2ecf20Sopenharmony_ci	    op == MLX4_CMD_UNMAP_ICM ||
2288c2ecf20Sopenharmony_ci	    op == MLX4_CMD_UNMAP_ICM_AUX ||
2298c2ecf20Sopenharmony_ci	    op == MLX4_CMD_UNMAP_FA)
2308c2ecf20Sopenharmony_ci		return 1;
2318c2ecf20Sopenharmony_ci	/* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals
2328c2ecf20Sopenharmony_ci	  * CMD_STAT_REG_BOUND.
2338c2ecf20Sopenharmony_ci	  * This status indicates that memory region has memory windows bound to it
2348c2ecf20Sopenharmony_ci	  * which may result from invalid user space usage and is not fatal.
2358c2ecf20Sopenharmony_ci	  */
2368c2ecf20Sopenharmony_ci	if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND)
2378c2ecf20Sopenharmony_ci		return 1;
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier,
2428c2ecf20Sopenharmony_ci			       int err)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	/* Only if reset flow is really active return code is based on
2458c2ecf20Sopenharmony_ci	  * command, otherwise current error code is returned.
2468c2ecf20Sopenharmony_ci	  */
2478c2ecf20Sopenharmony_ci	if (mlx4_internal_err_reset) {
2488c2ecf20Sopenharmony_ci		mlx4_enter_error_state(dev->persist);
2498c2ecf20Sopenharmony_ci		err = mlx4_internal_err_ret_value(dev, op, op_modifier);
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return err;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int comm_pending(struct mlx4_dev *dev)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
2588c2ecf20Sopenharmony_ci	u32 status = readl(&priv->mfunc.comm->slave_read);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return (swab32(status) >> 31) != priv->cmd.comm_toggle;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
2668c2ecf20Sopenharmony_ci	u32 val;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* To avoid writing to unknown addresses after the device state was
2698c2ecf20Sopenharmony_ci	 * changed to internal error and the function was rest,
2708c2ecf20Sopenharmony_ci	 * check the INTERNAL_ERROR flag which is updated under
2718c2ecf20Sopenharmony_ci	 * device_state_mutex lock.
2728c2ecf20Sopenharmony_ci	 */
2738c2ecf20Sopenharmony_ci	mutex_lock(&dev->persist->device_state_mutex);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
2768c2ecf20Sopenharmony_ci		mutex_unlock(&dev->persist->device_state_mutex);
2778c2ecf20Sopenharmony_ci		return -EIO;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	priv->cmd.comm_toggle ^= 1;
2818c2ecf20Sopenharmony_ci	val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31);
2828c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(val),
2838c2ecf20Sopenharmony_ci		     &priv->mfunc.comm->slave_write);
2848c2ecf20Sopenharmony_ci	mutex_unlock(&dev->persist->device_state_mutex);
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
2898c2ecf20Sopenharmony_ci		       unsigned long timeout)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
2928c2ecf20Sopenharmony_ci	unsigned long end;
2938c2ecf20Sopenharmony_ci	int err = 0;
2948c2ecf20Sopenharmony_ci	int ret_from_pending = 0;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* First, verify that the master reports correct status */
2978c2ecf20Sopenharmony_ci	if (comm_pending(dev)) {
2988c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Communication channel is not idle - my toggle is %d (cmd:0x%x)\n",
2998c2ecf20Sopenharmony_ci			  priv->cmd.comm_toggle, cmd);
3008c2ecf20Sopenharmony_ci		return -EAGAIN;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Write command */
3048c2ecf20Sopenharmony_ci	down(&priv->cmd.poll_sem);
3058c2ecf20Sopenharmony_ci	if (mlx4_comm_cmd_post(dev, cmd, param)) {
3068c2ecf20Sopenharmony_ci		/* Only in case the device state is INTERNAL_ERROR,
3078c2ecf20Sopenharmony_ci		 * mlx4_comm_cmd_post returns with an error
3088c2ecf20Sopenharmony_ci		 */
3098c2ecf20Sopenharmony_ci		err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
3108c2ecf20Sopenharmony_ci		goto out;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	end = msecs_to_jiffies(timeout) + jiffies;
3148c2ecf20Sopenharmony_ci	while (comm_pending(dev) && time_before(jiffies, end))
3158c2ecf20Sopenharmony_ci		cond_resched();
3168c2ecf20Sopenharmony_ci	ret_from_pending = comm_pending(dev);
3178c2ecf20Sopenharmony_ci	if (ret_from_pending) {
3188c2ecf20Sopenharmony_ci		/* check if the slave is trying to boot in the middle of
3198c2ecf20Sopenharmony_ci		 * FLR process. The only non-zero result in the RESET command
3208c2ecf20Sopenharmony_ci		 * is MLX4_DELAY_RESET_SLAVE*/
3218c2ecf20Sopenharmony_ci		if ((MLX4_COMM_CMD_RESET == cmd)) {
3228c2ecf20Sopenharmony_ci			err = MLX4_DELAY_RESET_SLAVE;
3238c2ecf20Sopenharmony_ci			goto out;
3248c2ecf20Sopenharmony_ci		} else {
3258c2ecf20Sopenharmony_ci			mlx4_warn(dev, "Communication channel command 0x%x timed out\n",
3268c2ecf20Sopenharmony_ci				  cmd);
3278c2ecf20Sopenharmony_ci			err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
3288c2ecf20Sopenharmony_ci		}
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (err)
3328c2ecf20Sopenharmony_ci		mlx4_enter_error_state(dev->persist);
3338c2ecf20Sopenharmony_ciout:
3348c2ecf20Sopenharmony_ci	up(&priv->cmd.poll_sem);
3358c2ecf20Sopenharmony_ci	return err;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd,
3398c2ecf20Sopenharmony_ci			      u16 param, u16 op, unsigned long timeout)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
3428c2ecf20Sopenharmony_ci	struct mlx4_cmd_context *context;
3438c2ecf20Sopenharmony_ci	unsigned long end;
3448c2ecf20Sopenharmony_ci	int err = 0;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	down(&cmd->event_sem);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	spin_lock(&cmd->context_lock);
3498c2ecf20Sopenharmony_ci	BUG_ON(cmd->free_head < 0);
3508c2ecf20Sopenharmony_ci	context = &cmd->context[cmd->free_head];
3518c2ecf20Sopenharmony_ci	context->token += cmd->token_mask + 1;
3528c2ecf20Sopenharmony_ci	cmd->free_head = context->next;
3538c2ecf20Sopenharmony_ci	spin_unlock(&cmd->context_lock);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	reinit_completion(&context->done);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) {
3588c2ecf20Sopenharmony_ci		/* Only in case the device state is INTERNAL_ERROR,
3598c2ecf20Sopenharmony_ci		 * mlx4_comm_cmd_post returns with an error
3608c2ecf20Sopenharmony_ci		 */
3618c2ecf20Sopenharmony_ci		err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
3628c2ecf20Sopenharmony_ci		goto out;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&context->done,
3668c2ecf20Sopenharmony_ci					 msecs_to_jiffies(timeout))) {
3678c2ecf20Sopenharmony_ci		mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n",
3688c2ecf20Sopenharmony_ci			  vhcr_cmd, op);
3698c2ecf20Sopenharmony_ci		goto out_reset;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	err = context->result;
3738c2ecf20Sopenharmony_ci	if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) {
3748c2ecf20Sopenharmony_ci		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
3758c2ecf20Sopenharmony_ci			 vhcr_cmd, context->fw_status);
3768c2ecf20Sopenharmony_ci		if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
3778c2ecf20Sopenharmony_ci			goto out_reset;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* wait for comm channel ready
3818c2ecf20Sopenharmony_ci	 * this is necessary for prevention the race
3828c2ecf20Sopenharmony_ci	 * when switching between event to polling mode
3838c2ecf20Sopenharmony_ci	 * Skipping this section in case the device is in FATAL_ERROR state,
3848c2ecf20Sopenharmony_ci	 * In this state, no commands are sent via the comm channel until
3858c2ecf20Sopenharmony_ci	 * the device has returned from reset.
3868c2ecf20Sopenharmony_ci	 */
3878c2ecf20Sopenharmony_ci	if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
3888c2ecf20Sopenharmony_ci		end = msecs_to_jiffies(timeout) + jiffies;
3898c2ecf20Sopenharmony_ci		while (comm_pending(dev) && time_before(jiffies, end))
3908c2ecf20Sopenharmony_ci			cond_resched();
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci	goto out;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciout_reset:
3958c2ecf20Sopenharmony_ci	err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
3968c2ecf20Sopenharmony_ci	mlx4_enter_error_state(dev->persist);
3978c2ecf20Sopenharmony_ciout:
3988c2ecf20Sopenharmony_ci	spin_lock(&cmd->context_lock);
3998c2ecf20Sopenharmony_ci	context->next = cmd->free_head;
4008c2ecf20Sopenharmony_ci	cmd->free_head = context - cmd->context;
4018c2ecf20Sopenharmony_ci	spin_unlock(&cmd->context_lock);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	up(&cmd->event_sem);
4048c2ecf20Sopenharmony_ci	return err;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ciint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
4088c2ecf20Sopenharmony_ci		  u16 op, unsigned long timeout)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
4118c2ecf20Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (mlx4_priv(dev)->cmd.use_events)
4148c2ecf20Sopenharmony_ci		return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout);
4158c2ecf20Sopenharmony_ci	return mlx4_comm_cmd_poll(dev, cmd, param, timeout);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int cmd_pending(struct mlx4_dev *dev)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	u32 status;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev))
4238c2ecf20Sopenharmony_ci		return -EIO;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return (status & swab32(1 << HCR_GO_BIT)) ||
4288c2ecf20Sopenharmony_ci		(mlx4_priv(dev)->cmd.toggle ==
4298c2ecf20Sopenharmony_ci		 !!(status & swab32(1 << HCR_T_BIT)));
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
4338c2ecf20Sopenharmony_ci			 u32 in_modifier, u8 op_modifier, u16 op, u16 token,
4348c2ecf20Sopenharmony_ci			 int event)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
4378c2ecf20Sopenharmony_ci	u32 __iomem *hcr = cmd->hcr;
4388c2ecf20Sopenharmony_ci	int ret = -EIO;
4398c2ecf20Sopenharmony_ci	unsigned long end;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	mutex_lock(&dev->persist->device_state_mutex);
4428c2ecf20Sopenharmony_ci	/* To avoid writing to unknown addresses after the device state was
4438c2ecf20Sopenharmony_ci	  * changed to internal error and the chip was reset,
4448c2ecf20Sopenharmony_ci	  * check the INTERNAL_ERROR flag which is updated under
4458c2ecf20Sopenharmony_ci	  * device_state_mutex lock.
4468c2ecf20Sopenharmony_ci	  */
4478c2ecf20Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev) ||
4488c2ecf20Sopenharmony_ci	    (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
4498c2ecf20Sopenharmony_ci		/*
4508c2ecf20Sopenharmony_ci		 * Device is going through error recovery
4518c2ecf20Sopenharmony_ci		 * and cannot accept commands.
4528c2ecf20Sopenharmony_ci		 */
4538c2ecf20Sopenharmony_ci		goto out;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	end = jiffies;
4578c2ecf20Sopenharmony_ci	if (event)
4588c2ecf20Sopenharmony_ci		end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	while (cmd_pending(dev)) {
4618c2ecf20Sopenharmony_ci		if (pci_channel_offline(dev->persist->pdev)) {
4628c2ecf20Sopenharmony_ci			/*
4638c2ecf20Sopenharmony_ci			 * Device is going through error recovery
4648c2ecf20Sopenharmony_ci			 * and cannot accept commands.
4658c2ecf20Sopenharmony_ci			 */
4668c2ecf20Sopenharmony_ci			goto out;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		if (time_after_eq(jiffies, end)) {
4708c2ecf20Sopenharmony_ci			mlx4_err(dev, "%s:cmd_pending failed\n", __func__);
4718c2ecf20Sopenharmony_ci			goto out;
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci		cond_resched();
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/*
4778c2ecf20Sopenharmony_ci	 * We use writel (instead of something like memcpy_toio)
4788c2ecf20Sopenharmony_ci	 * because writes of less than 32 bits to the HCR don't work
4798c2ecf20Sopenharmony_ci	 * (and some architectures such as ia64 implement memcpy_toio
4808c2ecf20Sopenharmony_ci	 * in terms of writeb).
4818c2ecf20Sopenharmony_ci	 */
4828c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),		  hcr + 0);
4838c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  hcr + 1);
4848c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_modifier),		  hcr + 2);
4858c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),	  hcr + 3);
4868c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4);
4878c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(token << 16),		  hcr + 5);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* __raw_writel may not order writes. */
4908c2ecf20Sopenharmony_ci	wmb();
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)		|
4938c2ecf20Sopenharmony_ci					       (cmd->toggle << HCR_T_BIT)	|
4948c2ecf20Sopenharmony_ci					       (event ? (1 << HCR_E_BIT) : 0)	|
4958c2ecf20Sopenharmony_ci					       (op_modifier << HCR_OPMOD_SHIFT) |
4968c2ecf20Sopenharmony_ci					       op), hcr + 6);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	cmd->toggle = cmd->toggle ^ 1;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	ret = 0;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ciout:
5038c2ecf20Sopenharmony_ci	if (ret)
5048c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Could not post command 0x%x: ret=%d, in_param=0x%llx, in_mod=0x%x, op_mod=0x%x\n",
5058c2ecf20Sopenharmony_ci			  op, ret, in_param, in_modifier, op_modifier);
5068c2ecf20Sopenharmony_ci	mutex_unlock(&dev->persist->device_state_mutex);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return ret;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
5128c2ecf20Sopenharmony_ci			  int out_is_imm, u32 in_modifier, u8 op_modifier,
5138c2ecf20Sopenharmony_ci			  u16 op, unsigned long timeout)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
5168c2ecf20Sopenharmony_ci	struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr;
5178c2ecf20Sopenharmony_ci	int ret;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	mutex_lock(&priv->cmd.slave_cmd_mutex);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	vhcr->in_param = cpu_to_be64(in_param);
5228c2ecf20Sopenharmony_ci	vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0;
5238c2ecf20Sopenharmony_ci	vhcr->in_modifier = cpu_to_be32(in_modifier);
5248c2ecf20Sopenharmony_ci	vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff));
5258c2ecf20Sopenharmony_ci	vhcr->token = cpu_to_be16(CMD_POLL_TOKEN);
5268c2ecf20Sopenharmony_ci	vhcr->status = 0;
5278c2ecf20Sopenharmony_ci	vhcr->flags = !!(priv->cmd.use_events) << 6;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (mlx4_is_master(dev)) {
5308c2ecf20Sopenharmony_ci		ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr);
5318c2ecf20Sopenharmony_ci		if (!ret) {
5328c2ecf20Sopenharmony_ci			if (out_is_imm) {
5338c2ecf20Sopenharmony_ci				if (out_param)
5348c2ecf20Sopenharmony_ci					*out_param =
5358c2ecf20Sopenharmony_ci						be64_to_cpu(vhcr->out_param);
5368c2ecf20Sopenharmony_ci				else {
5378c2ecf20Sopenharmony_ci					mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
5388c2ecf20Sopenharmony_ci						 op);
5398c2ecf20Sopenharmony_ci					vhcr->status = CMD_STAT_BAD_PARAM;
5408c2ecf20Sopenharmony_ci				}
5418c2ecf20Sopenharmony_ci			}
5428c2ecf20Sopenharmony_ci			ret = mlx4_status_to_errno(vhcr->status);
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci		if (ret &&
5458c2ecf20Sopenharmony_ci		    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
5468c2ecf20Sopenharmony_ci			ret = mlx4_internal_err_ret_value(dev, op, op_modifier);
5478c2ecf20Sopenharmony_ci	} else {
5488c2ecf20Sopenharmony_ci		ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op,
5498c2ecf20Sopenharmony_ci				    MLX4_COMM_TIME + timeout);
5508c2ecf20Sopenharmony_ci		if (!ret) {
5518c2ecf20Sopenharmony_ci			if (out_is_imm) {
5528c2ecf20Sopenharmony_ci				if (out_param)
5538c2ecf20Sopenharmony_ci					*out_param =
5548c2ecf20Sopenharmony_ci						be64_to_cpu(vhcr->out_param);
5558c2ecf20Sopenharmony_ci				else {
5568c2ecf20Sopenharmony_ci					mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
5578c2ecf20Sopenharmony_ci						 op);
5588c2ecf20Sopenharmony_ci					vhcr->status = CMD_STAT_BAD_PARAM;
5598c2ecf20Sopenharmony_ci				}
5608c2ecf20Sopenharmony_ci			}
5618c2ecf20Sopenharmony_ci			ret = mlx4_status_to_errno(vhcr->status);
5628c2ecf20Sopenharmony_ci		} else {
5638c2ecf20Sopenharmony_ci			if (dev->persist->state &
5648c2ecf20Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR)
5658c2ecf20Sopenharmony_ci				ret = mlx4_internal_err_ret_value(dev, op,
5668c2ecf20Sopenharmony_ci								  op_modifier);
5678c2ecf20Sopenharmony_ci			else
5688c2ecf20Sopenharmony_ci				mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op);
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	mutex_unlock(&priv->cmd.slave_cmd_mutex);
5738c2ecf20Sopenharmony_ci	return ret;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
5778c2ecf20Sopenharmony_ci			 int out_is_imm, u32 in_modifier, u8 op_modifier,
5788c2ecf20Sopenharmony_ci			 u16 op, unsigned long timeout)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
5818c2ecf20Sopenharmony_ci	void __iomem *hcr = priv->cmd.hcr;
5828c2ecf20Sopenharmony_ci	int err = 0;
5838c2ecf20Sopenharmony_ci	unsigned long end;
5848c2ecf20Sopenharmony_ci	u32 stat;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	down(&priv->cmd.poll_sem);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
5898c2ecf20Sopenharmony_ci		/*
5908c2ecf20Sopenharmony_ci		 * Device is going through error recovery
5918c2ecf20Sopenharmony_ci		 * and cannot accept commands.
5928c2ecf20Sopenharmony_ci		 */
5938c2ecf20Sopenharmony_ci		err = mlx4_internal_err_ret_value(dev, op, op_modifier);
5948c2ecf20Sopenharmony_ci		goto out;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (out_is_imm && !out_param) {
5988c2ecf20Sopenharmony_ci		mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
5998c2ecf20Sopenharmony_ci			 op);
6008c2ecf20Sopenharmony_ci		err = -EINVAL;
6018c2ecf20Sopenharmony_ci		goto out;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
6058c2ecf20Sopenharmony_ci			    in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
6068c2ecf20Sopenharmony_ci	if (err)
6078c2ecf20Sopenharmony_ci		goto out_reset;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	end = msecs_to_jiffies(timeout) + jiffies;
6108c2ecf20Sopenharmony_ci	while (cmd_pending(dev) && time_before(jiffies, end)) {
6118c2ecf20Sopenharmony_ci		if (pci_channel_offline(dev->persist->pdev)) {
6128c2ecf20Sopenharmony_ci			/*
6138c2ecf20Sopenharmony_ci			 * Device is going through error recovery
6148c2ecf20Sopenharmony_ci			 * and cannot accept commands.
6158c2ecf20Sopenharmony_ci			 */
6168c2ecf20Sopenharmony_ci			err = -EIO;
6178c2ecf20Sopenharmony_ci			goto out_reset;
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
6218c2ecf20Sopenharmony_ci			err = mlx4_internal_err_ret_value(dev, op, op_modifier);
6228c2ecf20Sopenharmony_ci			goto out;
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		cond_resched();
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (cmd_pending(dev)) {
6298c2ecf20Sopenharmony_ci		mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
6308c2ecf20Sopenharmony_ci			  op);
6318c2ecf20Sopenharmony_ci		err = -EIO;
6328c2ecf20Sopenharmony_ci		goto out_reset;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (out_is_imm)
6368c2ecf20Sopenharmony_ci		*out_param =
6378c2ecf20Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
6388c2ecf20Sopenharmony_ci					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
6398c2ecf20Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
6408c2ecf20Sopenharmony_ci					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
6418c2ecf20Sopenharmony_ci	stat = be32_to_cpu((__force __be32)
6428c2ecf20Sopenharmony_ci			   __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24;
6438c2ecf20Sopenharmony_ci	err = mlx4_status_to_errno(stat);
6448c2ecf20Sopenharmony_ci	if (err) {
6458c2ecf20Sopenharmony_ci		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
6468c2ecf20Sopenharmony_ci			 op, stat);
6478c2ecf20Sopenharmony_ci		if (mlx4_closing_cmd_fatal_error(op, stat))
6488c2ecf20Sopenharmony_ci			goto out_reset;
6498c2ecf20Sopenharmony_ci		goto out;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ciout_reset:
6538c2ecf20Sopenharmony_ci	if (err)
6548c2ecf20Sopenharmony_ci		err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
6558c2ecf20Sopenharmony_ciout:
6568c2ecf20Sopenharmony_ci	up(&priv->cmd.poll_sem);
6578c2ecf20Sopenharmony_ci	return err;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_civoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
6638c2ecf20Sopenharmony_ci	struct mlx4_cmd_context *context =
6648c2ecf20Sopenharmony_ci		&priv->cmd.context[token & priv->cmd.token_mask];
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	/* previously timed out command completing at long last */
6678c2ecf20Sopenharmony_ci	if (token != context->token)
6688c2ecf20Sopenharmony_ci		return;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	context->fw_status = status;
6718c2ecf20Sopenharmony_ci	context->result    = mlx4_status_to_errno(status);
6728c2ecf20Sopenharmony_ci	context->out_param = out_param;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	complete(&context->done);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
6788c2ecf20Sopenharmony_ci			 int out_is_imm, u32 in_modifier, u8 op_modifier,
6798c2ecf20Sopenharmony_ci			 u16 op, unsigned long timeout)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
6828c2ecf20Sopenharmony_ci	struct mlx4_cmd_context *context;
6838c2ecf20Sopenharmony_ci	long ret_wait;
6848c2ecf20Sopenharmony_ci	int err = 0;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	down(&cmd->event_sem);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	spin_lock(&cmd->context_lock);
6898c2ecf20Sopenharmony_ci	BUG_ON(cmd->free_head < 0);
6908c2ecf20Sopenharmony_ci	context = &cmd->context[cmd->free_head];
6918c2ecf20Sopenharmony_ci	context->token += cmd->token_mask + 1;
6928c2ecf20Sopenharmony_ci	cmd->free_head = context->next;
6938c2ecf20Sopenharmony_ci	spin_unlock(&cmd->context_lock);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (out_is_imm && !out_param) {
6968c2ecf20Sopenharmony_ci		mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
6978c2ecf20Sopenharmony_ci			 op);
6988c2ecf20Sopenharmony_ci		err = -EINVAL;
6998c2ecf20Sopenharmony_ci		goto out;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	reinit_completion(&context->done);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
7058c2ecf20Sopenharmony_ci			    in_modifier, op_modifier, op, context->token, 1);
7068c2ecf20Sopenharmony_ci	if (err)
7078c2ecf20Sopenharmony_ci		goto out_reset;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (op == MLX4_CMD_SENSE_PORT) {
7108c2ecf20Sopenharmony_ci		ret_wait =
7118c2ecf20Sopenharmony_ci			wait_for_completion_interruptible_timeout(&context->done,
7128c2ecf20Sopenharmony_ci								  msecs_to_jiffies(timeout));
7138c2ecf20Sopenharmony_ci		if (ret_wait < 0) {
7148c2ecf20Sopenharmony_ci			context->fw_status = 0;
7158c2ecf20Sopenharmony_ci			context->out_param = 0;
7168c2ecf20Sopenharmony_ci			context->result = 0;
7178c2ecf20Sopenharmony_ci		}
7188c2ecf20Sopenharmony_ci	} else {
7198c2ecf20Sopenharmony_ci		ret_wait = (long)wait_for_completion_timeout(&context->done,
7208c2ecf20Sopenharmony_ci							     msecs_to_jiffies(timeout));
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci	if (!ret_wait) {
7238c2ecf20Sopenharmony_ci		mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
7248c2ecf20Sopenharmony_ci			  op);
7258c2ecf20Sopenharmony_ci		if (op == MLX4_CMD_NOP) {
7268c2ecf20Sopenharmony_ci			err = -EBUSY;
7278c2ecf20Sopenharmony_ci			goto out;
7288c2ecf20Sopenharmony_ci		} else {
7298c2ecf20Sopenharmony_ci			err = -EIO;
7308c2ecf20Sopenharmony_ci			goto out_reset;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	err = context->result;
7358c2ecf20Sopenharmony_ci	if (err) {
7368c2ecf20Sopenharmony_ci		/* Since we do not want to have this error message always
7378c2ecf20Sopenharmony_ci		 * displayed at driver start when there are ConnectX2 HCAs
7388c2ecf20Sopenharmony_ci		 * on the host, we deprecate the error message for this
7398c2ecf20Sopenharmony_ci		 * specific command/input_mod/opcode_mod/fw-status to be debug.
7408c2ecf20Sopenharmony_ci		 */
7418c2ecf20Sopenharmony_ci		if (op == MLX4_CMD_SET_PORT &&
7428c2ecf20Sopenharmony_ci		    (in_modifier == 1 || in_modifier == 2) &&
7438c2ecf20Sopenharmony_ci		    op_modifier == MLX4_SET_PORT_IB_OPCODE &&
7448c2ecf20Sopenharmony_ci		    context->fw_status == CMD_STAT_BAD_SIZE)
7458c2ecf20Sopenharmony_ci			mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
7468c2ecf20Sopenharmony_ci				 op, context->fw_status);
7478c2ecf20Sopenharmony_ci		else
7488c2ecf20Sopenharmony_ci			mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
7498c2ecf20Sopenharmony_ci				 op, context->fw_status);
7508c2ecf20Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
7518c2ecf20Sopenharmony_ci			err = mlx4_internal_err_ret_value(dev, op, op_modifier);
7528c2ecf20Sopenharmony_ci		else if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
7538c2ecf20Sopenharmony_ci			goto out_reset;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		goto out;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (out_is_imm)
7598c2ecf20Sopenharmony_ci		*out_param = context->out_param;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ciout_reset:
7628c2ecf20Sopenharmony_ci	if (err)
7638c2ecf20Sopenharmony_ci		err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
7648c2ecf20Sopenharmony_ciout:
7658c2ecf20Sopenharmony_ci	spin_lock(&cmd->context_lock);
7668c2ecf20Sopenharmony_ci	context->next = cmd->free_head;
7678c2ecf20Sopenharmony_ci	cmd->free_head = context - cmd->context;
7688c2ecf20Sopenharmony_ci	spin_unlock(&cmd->context_lock);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	up(&cmd->event_sem);
7718c2ecf20Sopenharmony_ci	return err;
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ciint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
7758c2ecf20Sopenharmony_ci	       int out_is_imm, u32 in_modifier, u8 op_modifier,
7768c2ecf20Sopenharmony_ci	       u16 op, unsigned long timeout, int native)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev))
7798c2ecf20Sopenharmony_ci		return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
7828c2ecf20Sopenharmony_ci		int ret;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
7858c2ecf20Sopenharmony_ci			return mlx4_internal_err_ret_value(dev, op,
7868c2ecf20Sopenharmony_ci							  op_modifier);
7878c2ecf20Sopenharmony_ci		down_read(&mlx4_priv(dev)->cmd.switch_sem);
7888c2ecf20Sopenharmony_ci		if (mlx4_priv(dev)->cmd.use_events)
7898c2ecf20Sopenharmony_ci			ret = mlx4_cmd_wait(dev, in_param, out_param,
7908c2ecf20Sopenharmony_ci					    out_is_imm, in_modifier,
7918c2ecf20Sopenharmony_ci					    op_modifier, op, timeout);
7928c2ecf20Sopenharmony_ci		else
7938c2ecf20Sopenharmony_ci			ret = mlx4_cmd_poll(dev, in_param, out_param,
7948c2ecf20Sopenharmony_ci					    out_is_imm, in_modifier,
7958c2ecf20Sopenharmony_ci					    op_modifier, op, timeout);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		up_read(&mlx4_priv(dev)->cmd.switch_sem);
7988c2ecf20Sopenharmony_ci		return ret;
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci	return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm,
8018c2ecf20Sopenharmony_ci			      in_modifier, op_modifier, op, timeout);
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mlx4_cmd);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ciint mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL,
8098c2ecf20Sopenharmony_ci			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cistatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr,
8138c2ecf20Sopenharmony_ci			   int slave, u64 slave_addr,
8148c2ecf20Sopenharmony_ci			   int size, int is_read)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	u64 in_param;
8178c2ecf20Sopenharmony_ci	u64 out_param;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	if ((slave_addr & 0xfff) | (master_addr & 0xfff) |
8208c2ecf20Sopenharmony_ci	    (slave & ~0x7f) | (size & 0xff)) {
8218c2ecf20Sopenharmony_ci		mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx master_addr:0x%llx slave_id:%d size:%d\n",
8228c2ecf20Sopenharmony_ci			 slave_addr, master_addr, slave, size);
8238c2ecf20Sopenharmony_ci		return -EINVAL;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (is_read) {
8278c2ecf20Sopenharmony_ci		in_param = (u64) slave | slave_addr;
8288c2ecf20Sopenharmony_ci		out_param = (u64) dev->caps.function | master_addr;
8298c2ecf20Sopenharmony_ci	} else {
8308c2ecf20Sopenharmony_ci		in_param = (u64) dev->caps.function | master_addr;
8318c2ecf20Sopenharmony_ci		out_param = (u64) slave | slave_addr;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	return mlx4_cmd_imm(dev, in_param, &out_param, size, 0,
8358c2ecf20Sopenharmony_ci			    MLX4_CMD_ACCESS_MEM,
8368c2ecf20Sopenharmony_ci			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey,
8408c2ecf20Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
8418c2ecf20Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf);
8448c2ecf20Sopenharmony_ci	struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf);
8458c2ecf20Sopenharmony_ci	int err;
8468c2ecf20Sopenharmony_ci	int i;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (index & 0x1f)
8498c2ecf20Sopenharmony_ci		return -EINVAL;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(index / 32);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
8548c2ecf20Sopenharmony_ci			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
8558c2ecf20Sopenharmony_ci			   MLX4_CMD_NATIVE);
8568c2ecf20Sopenharmony_ci	if (err)
8578c2ecf20Sopenharmony_ci		return err;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	for (i = 0; i < 32; ++i)
8608c2ecf20Sopenharmony_ci		pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return err;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table,
8668c2ecf20Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
8678c2ecf20Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	int i;
8708c2ecf20Sopenharmony_ci	int err;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) {
8738c2ecf20Sopenharmony_ci		err = query_pkey_block(dev, port, i, table + i, inbox, outbox);
8748c2ecf20Sopenharmony_ci		if (err)
8758c2ecf20Sopenharmony_ci			return err;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return 0;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci#define PORT_CAPABILITY_LOCATION_IN_SMP 20
8818c2ecf20Sopenharmony_ci#define PORT_STATE_OFFSET 32
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP)
8868c2ecf20Sopenharmony_ci		return IB_PORT_ACTIVE;
8878c2ecf20Sopenharmony_ci	else
8888c2ecf20Sopenharmony_ci		return IB_PORT_DOWN;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
8928c2ecf20Sopenharmony_ci				struct mlx4_vhcr *vhcr,
8938c2ecf20Sopenharmony_ci				struct mlx4_cmd_mailbox *inbox,
8948c2ecf20Sopenharmony_ci				struct mlx4_cmd_mailbox *outbox,
8958c2ecf20Sopenharmony_ci				struct mlx4_cmd_info *cmd)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	struct ib_smp *smp = inbox->buf;
8988c2ecf20Sopenharmony_ci	u32 index;
8998c2ecf20Sopenharmony_ci	u8 port, slave_port;
9008c2ecf20Sopenharmony_ci	u8 opcode_modifier;
9018c2ecf20Sopenharmony_ci	u16 *table;
9028c2ecf20Sopenharmony_ci	int err;
9038c2ecf20Sopenharmony_ci	int vidx, pidx;
9048c2ecf20Sopenharmony_ci	int network_view;
9058c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
9068c2ecf20Sopenharmony_ci	struct ib_smp *outsmp = outbox->buf;
9078c2ecf20Sopenharmony_ci	__be16 *outtab = (__be16 *)(outsmp->data);
9088c2ecf20Sopenharmony_ci	__be32 slave_cap_mask;
9098c2ecf20Sopenharmony_ci	__be64 slave_node_guid;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	slave_port = vhcr->in_modifier;
9128c2ecf20Sopenharmony_ci	port = mlx4_slave_convert_port(dev, slave, slave_port);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	/* network-view bit is for driver use only, and should not be passed to FW */
9158c2ecf20Sopenharmony_ci	opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */
9168c2ecf20Sopenharmony_ci	network_view = !!(vhcr->op_modifier & 0x8);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (smp->base_version == 1 &&
9198c2ecf20Sopenharmony_ci	    smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
9208c2ecf20Sopenharmony_ci	    smp->class_version == 1) {
9218c2ecf20Sopenharmony_ci		/* host view is paravirtualized */
9228c2ecf20Sopenharmony_ci		if (!network_view && smp->method == IB_MGMT_METHOD_GET) {
9238c2ecf20Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) {
9248c2ecf20Sopenharmony_ci				index = be32_to_cpu(smp->attr_mod);
9258c2ecf20Sopenharmony_ci				if (port < 1 || port > dev->caps.num_ports)
9268c2ecf20Sopenharmony_ci					return -EINVAL;
9278c2ecf20Sopenharmony_ci				table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1,
9288c2ecf20Sopenharmony_ci						sizeof(*table) * 32, GFP_KERNEL);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci				if (!table)
9318c2ecf20Sopenharmony_ci					return -ENOMEM;
9328c2ecf20Sopenharmony_ci				/* need to get the full pkey table because the paravirtualized
9338c2ecf20Sopenharmony_ci				 * pkeys may be scattered among several pkey blocks.
9348c2ecf20Sopenharmony_ci				 */
9358c2ecf20Sopenharmony_ci				err = get_full_pkey_table(dev, port, table, inbox, outbox);
9368c2ecf20Sopenharmony_ci				if (!err) {
9378c2ecf20Sopenharmony_ci					for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) {
9388c2ecf20Sopenharmony_ci						pidx = priv->virt2phys_pkey[slave][port - 1][vidx];
9398c2ecf20Sopenharmony_ci						outtab[vidx % 32] = cpu_to_be16(table[pidx]);
9408c2ecf20Sopenharmony_ci					}
9418c2ecf20Sopenharmony_ci				}
9428c2ecf20Sopenharmony_ci				kfree(table);
9438c2ecf20Sopenharmony_ci				return err;
9448c2ecf20Sopenharmony_ci			}
9458c2ecf20Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) {
9468c2ecf20Sopenharmony_ci				/*get the slave specific caps:*/
9478c2ecf20Sopenharmony_ci				/*do the command */
9488c2ecf20Sopenharmony_ci				smp->attr_mod = cpu_to_be32(port);
9498c2ecf20Sopenharmony_ci				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
9508c2ecf20Sopenharmony_ci					    port, opcode_modifier,
9518c2ecf20Sopenharmony_ci					    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
9528c2ecf20Sopenharmony_ci				/* modify the response for slaves */
9538c2ecf20Sopenharmony_ci				if (!err && slave != mlx4_master_func_num(dev)) {
9548c2ecf20Sopenharmony_ci					u8 *state = outsmp->data + PORT_STATE_OFFSET;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci					*state = (*state & 0xf0) | vf_port_state(dev, port, slave);
9578c2ecf20Sopenharmony_ci					slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
9588c2ecf20Sopenharmony_ci					memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4);
9598c2ecf20Sopenharmony_ci				}
9608c2ecf20Sopenharmony_ci				return err;
9618c2ecf20Sopenharmony_ci			}
9628c2ecf20Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) {
9638c2ecf20Sopenharmony_ci				__be64 guid = mlx4_get_admin_guid(dev, slave,
9648c2ecf20Sopenharmony_ci								  port);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci				/* set the PF admin guid to the FW/HW burned
9678c2ecf20Sopenharmony_ci				 * GUID, if it wasn't yet set
9688c2ecf20Sopenharmony_ci				 */
9698c2ecf20Sopenharmony_ci				if (slave == 0 && guid == 0) {
9708c2ecf20Sopenharmony_ci					smp->attr_mod = 0;
9718c2ecf20Sopenharmony_ci					err = mlx4_cmd_box(dev,
9728c2ecf20Sopenharmony_ci							   inbox->dma,
9738c2ecf20Sopenharmony_ci							   outbox->dma,
9748c2ecf20Sopenharmony_ci							   vhcr->in_modifier,
9758c2ecf20Sopenharmony_ci							   opcode_modifier,
9768c2ecf20Sopenharmony_ci							   vhcr->op,
9778c2ecf20Sopenharmony_ci							   MLX4_CMD_TIME_CLASS_C,
9788c2ecf20Sopenharmony_ci							   MLX4_CMD_NATIVE);
9798c2ecf20Sopenharmony_ci					if (err)
9808c2ecf20Sopenharmony_ci						return err;
9818c2ecf20Sopenharmony_ci					mlx4_set_admin_guid(dev,
9828c2ecf20Sopenharmony_ci							    *(__be64 *)outsmp->
9838c2ecf20Sopenharmony_ci							    data, slave, port);
9848c2ecf20Sopenharmony_ci				} else {
9858c2ecf20Sopenharmony_ci					memcpy(outsmp->data, &guid, 8);
9868c2ecf20Sopenharmony_ci				}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci				/* clean all other gids */
9898c2ecf20Sopenharmony_ci				memset(outsmp->data + 8, 0, 56);
9908c2ecf20Sopenharmony_ci				return 0;
9918c2ecf20Sopenharmony_ci			}
9928c2ecf20Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) {
9938c2ecf20Sopenharmony_ci				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
9948c2ecf20Sopenharmony_ci					     port, opcode_modifier,
9958c2ecf20Sopenharmony_ci					     vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
9968c2ecf20Sopenharmony_ci				if (!err) {
9978c2ecf20Sopenharmony_ci					slave_node_guid =  mlx4_get_slave_node_guid(dev, slave);
9988c2ecf20Sopenharmony_ci					memcpy(outsmp->data + 12, &slave_node_guid, 8);
9998c2ecf20Sopenharmony_ci				}
10008c2ecf20Sopenharmony_ci				return err;
10018c2ecf20Sopenharmony_ci			}
10028c2ecf20Sopenharmony_ci		}
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	/* Non-privileged VFs are only allowed "host" view LID-routed 'Get' MADs.
10068c2ecf20Sopenharmony_ci	 * These are the MADs used by ib verbs (such as ib_query_gids).
10078c2ecf20Sopenharmony_ci	 */
10088c2ecf20Sopenharmony_ci	if (slave != mlx4_master_func_num(dev) &&
10098c2ecf20Sopenharmony_ci	    !mlx4_vf_smi_enabled(dev, slave, port)) {
10108c2ecf20Sopenharmony_ci		if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
10118c2ecf20Sopenharmony_ci		      smp->method == IB_MGMT_METHOD_GET) || network_view) {
10128c2ecf20Sopenharmony_ci			mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n",
10138c2ecf20Sopenharmony_ci				 slave, smp->mgmt_class, smp->method,
10148c2ecf20Sopenharmony_ci				 network_view ? "Network" : "Host",
10158c2ecf20Sopenharmony_ci				 be16_to_cpu(smp->attr_id));
10168c2ecf20Sopenharmony_ci			return -EPERM;
10178c2ecf20Sopenharmony_ci		}
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return mlx4_cmd_box(dev, inbox->dma, outbox->dma,
10218c2ecf20Sopenharmony_ci				    vhcr->in_modifier, opcode_modifier,
10228c2ecf20Sopenharmony_ci				    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave,
10268c2ecf20Sopenharmony_ci		     struct mlx4_vhcr *vhcr,
10278c2ecf20Sopenharmony_ci		     struct mlx4_cmd_mailbox *inbox,
10288c2ecf20Sopenharmony_ci		     struct mlx4_cmd_mailbox *outbox,
10298c2ecf20Sopenharmony_ci		     struct mlx4_cmd_info *cmd)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	return -EPERM;
10328c2ecf20Sopenharmony_ci}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ciint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
10358c2ecf20Sopenharmony_ci		     struct mlx4_vhcr *vhcr,
10368c2ecf20Sopenharmony_ci		     struct mlx4_cmd_mailbox *inbox,
10378c2ecf20Sopenharmony_ci		     struct mlx4_cmd_mailbox *outbox,
10388c2ecf20Sopenharmony_ci		     struct mlx4_cmd_info *cmd)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	u64 in_param;
10418c2ecf20Sopenharmony_ci	u64 out_param;
10428c2ecf20Sopenharmony_ci	int err;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param;
10458c2ecf20Sopenharmony_ci	out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param;
10468c2ecf20Sopenharmony_ci	if (cmd->encode_slave_id) {
10478c2ecf20Sopenharmony_ci		in_param &= 0xffffffffffffff00ll;
10488c2ecf20Sopenharmony_ci		in_param |= slave;
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm,
10528c2ecf20Sopenharmony_ci			 vhcr->in_modifier, vhcr->op_modifier, vhcr->op,
10538c2ecf20Sopenharmony_ci			 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (cmd->out_is_imm)
10568c2ecf20Sopenharmony_ci		vhcr->out_param = out_param;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return err;
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic struct mlx4_cmd_info cmd_info[] = {
10628c2ecf20Sopenharmony_ci	{
10638c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_FW,
10648c2ecf20Sopenharmony_ci		.has_inbox = false,
10658c2ecf20Sopenharmony_ci		.has_outbox = true,
10668c2ecf20Sopenharmony_ci		.out_is_imm = false,
10678c2ecf20Sopenharmony_ci		.encode_slave_id = false,
10688c2ecf20Sopenharmony_ci		.verify = NULL,
10698c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_FW_wrapper
10708c2ecf20Sopenharmony_ci	},
10718c2ecf20Sopenharmony_ci	{
10728c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_HCA,
10738c2ecf20Sopenharmony_ci		.has_inbox = false,
10748c2ecf20Sopenharmony_ci		.has_outbox = true,
10758c2ecf20Sopenharmony_ci		.out_is_imm = false,
10768c2ecf20Sopenharmony_ci		.encode_slave_id = false,
10778c2ecf20Sopenharmony_ci		.verify = NULL,
10788c2ecf20Sopenharmony_ci		.wrapper = NULL
10798c2ecf20Sopenharmony_ci	},
10808c2ecf20Sopenharmony_ci	{
10818c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_DEV_CAP,
10828c2ecf20Sopenharmony_ci		.has_inbox = false,
10838c2ecf20Sopenharmony_ci		.has_outbox = true,
10848c2ecf20Sopenharmony_ci		.out_is_imm = false,
10858c2ecf20Sopenharmony_ci		.encode_slave_id = false,
10868c2ecf20Sopenharmony_ci		.verify = NULL,
10878c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_DEV_CAP_wrapper
10888c2ecf20Sopenharmony_ci	},
10898c2ecf20Sopenharmony_ci	{
10908c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_FUNC_CAP,
10918c2ecf20Sopenharmony_ci		.has_inbox = false,
10928c2ecf20Sopenharmony_ci		.has_outbox = true,
10938c2ecf20Sopenharmony_ci		.out_is_imm = false,
10948c2ecf20Sopenharmony_ci		.encode_slave_id = false,
10958c2ecf20Sopenharmony_ci		.verify = NULL,
10968c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_FUNC_CAP_wrapper
10978c2ecf20Sopenharmony_ci	},
10988c2ecf20Sopenharmony_ci	{
10998c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_ADAPTER,
11008c2ecf20Sopenharmony_ci		.has_inbox = false,
11018c2ecf20Sopenharmony_ci		.has_outbox = true,
11028c2ecf20Sopenharmony_ci		.out_is_imm = false,
11038c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11048c2ecf20Sopenharmony_ci		.verify = NULL,
11058c2ecf20Sopenharmony_ci		.wrapper = NULL
11068c2ecf20Sopenharmony_ci	},
11078c2ecf20Sopenharmony_ci	{
11088c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_INIT_PORT,
11098c2ecf20Sopenharmony_ci		.has_inbox = false,
11108c2ecf20Sopenharmony_ci		.has_outbox = false,
11118c2ecf20Sopenharmony_ci		.out_is_imm = false,
11128c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11138c2ecf20Sopenharmony_ci		.verify = NULL,
11148c2ecf20Sopenharmony_ci		.wrapper = mlx4_INIT_PORT_wrapper
11158c2ecf20Sopenharmony_ci	},
11168c2ecf20Sopenharmony_ci	{
11178c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_CLOSE_PORT,
11188c2ecf20Sopenharmony_ci		.has_inbox = false,
11198c2ecf20Sopenharmony_ci		.has_outbox = false,
11208c2ecf20Sopenharmony_ci		.out_is_imm  = false,
11218c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11228c2ecf20Sopenharmony_ci		.verify = NULL,
11238c2ecf20Sopenharmony_ci		.wrapper = mlx4_CLOSE_PORT_wrapper
11248c2ecf20Sopenharmony_ci	},
11258c2ecf20Sopenharmony_ci	{
11268c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_PORT,
11278c2ecf20Sopenharmony_ci		.has_inbox = false,
11288c2ecf20Sopenharmony_ci		.has_outbox = true,
11298c2ecf20Sopenharmony_ci		.out_is_imm = false,
11308c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11318c2ecf20Sopenharmony_ci		.verify = NULL,
11328c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_PORT_wrapper
11338c2ecf20Sopenharmony_ci	},
11348c2ecf20Sopenharmony_ci	{
11358c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SET_PORT,
11368c2ecf20Sopenharmony_ci		.has_inbox = true,
11378c2ecf20Sopenharmony_ci		.has_outbox = false,
11388c2ecf20Sopenharmony_ci		.out_is_imm = false,
11398c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11408c2ecf20Sopenharmony_ci		.verify = NULL,
11418c2ecf20Sopenharmony_ci		.wrapper = mlx4_SET_PORT_wrapper
11428c2ecf20Sopenharmony_ci	},
11438c2ecf20Sopenharmony_ci	{
11448c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_MAP_EQ,
11458c2ecf20Sopenharmony_ci		.has_inbox = false,
11468c2ecf20Sopenharmony_ci		.has_outbox = false,
11478c2ecf20Sopenharmony_ci		.out_is_imm = false,
11488c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11498c2ecf20Sopenharmony_ci		.verify = NULL,
11508c2ecf20Sopenharmony_ci		.wrapper = mlx4_MAP_EQ_wrapper
11518c2ecf20Sopenharmony_ci	},
11528c2ecf20Sopenharmony_ci	{
11538c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_EQ,
11548c2ecf20Sopenharmony_ci		.has_inbox = true,
11558c2ecf20Sopenharmony_ci		.has_outbox = false,
11568c2ecf20Sopenharmony_ci		.out_is_imm = false,
11578c2ecf20Sopenharmony_ci		.encode_slave_id = true,
11588c2ecf20Sopenharmony_ci		.verify = NULL,
11598c2ecf20Sopenharmony_ci		.wrapper = mlx4_SW2HW_EQ_wrapper
11608c2ecf20Sopenharmony_ci	},
11618c2ecf20Sopenharmony_ci	{
11628c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_HW_HEALTH_CHECK,
11638c2ecf20Sopenharmony_ci		.has_inbox = false,
11648c2ecf20Sopenharmony_ci		.has_outbox = false,
11658c2ecf20Sopenharmony_ci		.out_is_imm = false,
11668c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11678c2ecf20Sopenharmony_ci		.verify = NULL,
11688c2ecf20Sopenharmony_ci		.wrapper = NULL
11698c2ecf20Sopenharmony_ci	},
11708c2ecf20Sopenharmony_ci	{
11718c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_NOP,
11728c2ecf20Sopenharmony_ci		.has_inbox = false,
11738c2ecf20Sopenharmony_ci		.has_outbox = false,
11748c2ecf20Sopenharmony_ci		.out_is_imm = false,
11758c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11768c2ecf20Sopenharmony_ci		.verify = NULL,
11778c2ecf20Sopenharmony_ci		.wrapper = NULL
11788c2ecf20Sopenharmony_ci	},
11798c2ecf20Sopenharmony_ci	{
11808c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_CONFIG_DEV,
11818c2ecf20Sopenharmony_ci		.has_inbox = false,
11828c2ecf20Sopenharmony_ci		.has_outbox = true,
11838c2ecf20Sopenharmony_ci		.out_is_imm = false,
11848c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11858c2ecf20Sopenharmony_ci		.verify = NULL,
11868c2ecf20Sopenharmony_ci		.wrapper = mlx4_CONFIG_DEV_wrapper
11878c2ecf20Sopenharmony_ci	},
11888c2ecf20Sopenharmony_ci	{
11898c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_ALLOC_RES,
11908c2ecf20Sopenharmony_ci		.has_inbox = false,
11918c2ecf20Sopenharmony_ci		.has_outbox = false,
11928c2ecf20Sopenharmony_ci		.out_is_imm = true,
11938c2ecf20Sopenharmony_ci		.encode_slave_id = false,
11948c2ecf20Sopenharmony_ci		.verify = NULL,
11958c2ecf20Sopenharmony_ci		.wrapper = mlx4_ALLOC_RES_wrapper
11968c2ecf20Sopenharmony_ci	},
11978c2ecf20Sopenharmony_ci	{
11988c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_FREE_RES,
11998c2ecf20Sopenharmony_ci		.has_inbox = false,
12008c2ecf20Sopenharmony_ci		.has_outbox = false,
12018c2ecf20Sopenharmony_ci		.out_is_imm = false,
12028c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12038c2ecf20Sopenharmony_ci		.verify = NULL,
12048c2ecf20Sopenharmony_ci		.wrapper = mlx4_FREE_RES_wrapper
12058c2ecf20Sopenharmony_ci	},
12068c2ecf20Sopenharmony_ci	{
12078c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_MPT,
12088c2ecf20Sopenharmony_ci		.has_inbox = true,
12098c2ecf20Sopenharmony_ci		.has_outbox = false,
12108c2ecf20Sopenharmony_ci		.out_is_imm = false,
12118c2ecf20Sopenharmony_ci		.encode_slave_id = true,
12128c2ecf20Sopenharmony_ci		.verify = NULL,
12138c2ecf20Sopenharmony_ci		.wrapper = mlx4_SW2HW_MPT_wrapper
12148c2ecf20Sopenharmony_ci	},
12158c2ecf20Sopenharmony_ci	{
12168c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_MPT,
12178c2ecf20Sopenharmony_ci		.has_inbox = false,
12188c2ecf20Sopenharmony_ci		.has_outbox = true,
12198c2ecf20Sopenharmony_ci		.out_is_imm = false,
12208c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12218c2ecf20Sopenharmony_ci		.verify = NULL,
12228c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_MPT_wrapper
12238c2ecf20Sopenharmony_ci	},
12248c2ecf20Sopenharmony_ci	{
12258c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_MPT,
12268c2ecf20Sopenharmony_ci		.has_inbox = false,
12278c2ecf20Sopenharmony_ci		.has_outbox = false,
12288c2ecf20Sopenharmony_ci		.out_is_imm = false,
12298c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12308c2ecf20Sopenharmony_ci		.verify = NULL,
12318c2ecf20Sopenharmony_ci		.wrapper = mlx4_HW2SW_MPT_wrapper
12328c2ecf20Sopenharmony_ci	},
12338c2ecf20Sopenharmony_ci	{
12348c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_READ_MTT,
12358c2ecf20Sopenharmony_ci		.has_inbox = false,
12368c2ecf20Sopenharmony_ci		.has_outbox = true,
12378c2ecf20Sopenharmony_ci		.out_is_imm = false,
12388c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12398c2ecf20Sopenharmony_ci		.verify = NULL,
12408c2ecf20Sopenharmony_ci		.wrapper = NULL
12418c2ecf20Sopenharmony_ci	},
12428c2ecf20Sopenharmony_ci	{
12438c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_WRITE_MTT,
12448c2ecf20Sopenharmony_ci		.has_inbox = true,
12458c2ecf20Sopenharmony_ci		.has_outbox = false,
12468c2ecf20Sopenharmony_ci		.out_is_imm = false,
12478c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12488c2ecf20Sopenharmony_ci		.verify = NULL,
12498c2ecf20Sopenharmony_ci		.wrapper = mlx4_WRITE_MTT_wrapper
12508c2ecf20Sopenharmony_ci	},
12518c2ecf20Sopenharmony_ci	{
12528c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SYNC_TPT,
12538c2ecf20Sopenharmony_ci		.has_inbox = true,
12548c2ecf20Sopenharmony_ci		.has_outbox = false,
12558c2ecf20Sopenharmony_ci		.out_is_imm = false,
12568c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12578c2ecf20Sopenharmony_ci		.verify = NULL,
12588c2ecf20Sopenharmony_ci		.wrapper = NULL
12598c2ecf20Sopenharmony_ci	},
12608c2ecf20Sopenharmony_ci	{
12618c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_EQ,
12628c2ecf20Sopenharmony_ci		.has_inbox = false,
12638c2ecf20Sopenharmony_ci		.has_outbox = false,
12648c2ecf20Sopenharmony_ci		.out_is_imm = false,
12658c2ecf20Sopenharmony_ci		.encode_slave_id = true,
12668c2ecf20Sopenharmony_ci		.verify = NULL,
12678c2ecf20Sopenharmony_ci		.wrapper = mlx4_HW2SW_EQ_wrapper
12688c2ecf20Sopenharmony_ci	},
12698c2ecf20Sopenharmony_ci	{
12708c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_EQ,
12718c2ecf20Sopenharmony_ci		.has_inbox = false,
12728c2ecf20Sopenharmony_ci		.has_outbox = true,
12738c2ecf20Sopenharmony_ci		.out_is_imm = false,
12748c2ecf20Sopenharmony_ci		.encode_slave_id = true,
12758c2ecf20Sopenharmony_ci		.verify = NULL,
12768c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_EQ_wrapper
12778c2ecf20Sopenharmony_ci	},
12788c2ecf20Sopenharmony_ci	{
12798c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_CQ,
12808c2ecf20Sopenharmony_ci		.has_inbox = true,
12818c2ecf20Sopenharmony_ci		.has_outbox = false,
12828c2ecf20Sopenharmony_ci		.out_is_imm = false,
12838c2ecf20Sopenharmony_ci		.encode_slave_id = true,
12848c2ecf20Sopenharmony_ci		.verify = NULL,
12858c2ecf20Sopenharmony_ci		.wrapper = mlx4_SW2HW_CQ_wrapper
12868c2ecf20Sopenharmony_ci	},
12878c2ecf20Sopenharmony_ci	{
12888c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_CQ,
12898c2ecf20Sopenharmony_ci		.has_inbox = false,
12908c2ecf20Sopenharmony_ci		.has_outbox = false,
12918c2ecf20Sopenharmony_ci		.out_is_imm = false,
12928c2ecf20Sopenharmony_ci		.encode_slave_id = false,
12938c2ecf20Sopenharmony_ci		.verify = NULL,
12948c2ecf20Sopenharmony_ci		.wrapper = mlx4_HW2SW_CQ_wrapper
12958c2ecf20Sopenharmony_ci	},
12968c2ecf20Sopenharmony_ci	{
12978c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_CQ,
12988c2ecf20Sopenharmony_ci		.has_inbox = false,
12998c2ecf20Sopenharmony_ci		.has_outbox = true,
13008c2ecf20Sopenharmony_ci		.out_is_imm = false,
13018c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13028c2ecf20Sopenharmony_ci		.verify = NULL,
13038c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_CQ_wrapper
13048c2ecf20Sopenharmony_ci	},
13058c2ecf20Sopenharmony_ci	{
13068c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_MODIFY_CQ,
13078c2ecf20Sopenharmony_ci		.has_inbox = true,
13088c2ecf20Sopenharmony_ci		.has_outbox = false,
13098c2ecf20Sopenharmony_ci		.out_is_imm = true,
13108c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13118c2ecf20Sopenharmony_ci		.verify = NULL,
13128c2ecf20Sopenharmony_ci		.wrapper = mlx4_MODIFY_CQ_wrapper
13138c2ecf20Sopenharmony_ci	},
13148c2ecf20Sopenharmony_ci	{
13158c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_SRQ,
13168c2ecf20Sopenharmony_ci		.has_inbox = true,
13178c2ecf20Sopenharmony_ci		.has_outbox = false,
13188c2ecf20Sopenharmony_ci		.out_is_imm = false,
13198c2ecf20Sopenharmony_ci		.encode_slave_id = true,
13208c2ecf20Sopenharmony_ci		.verify = NULL,
13218c2ecf20Sopenharmony_ci		.wrapper = mlx4_SW2HW_SRQ_wrapper
13228c2ecf20Sopenharmony_ci	},
13238c2ecf20Sopenharmony_ci	{
13248c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_SRQ,
13258c2ecf20Sopenharmony_ci		.has_inbox = false,
13268c2ecf20Sopenharmony_ci		.has_outbox = false,
13278c2ecf20Sopenharmony_ci		.out_is_imm = false,
13288c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13298c2ecf20Sopenharmony_ci		.verify = NULL,
13308c2ecf20Sopenharmony_ci		.wrapper = mlx4_HW2SW_SRQ_wrapper
13318c2ecf20Sopenharmony_ci	},
13328c2ecf20Sopenharmony_ci	{
13338c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_SRQ,
13348c2ecf20Sopenharmony_ci		.has_inbox = false,
13358c2ecf20Sopenharmony_ci		.has_outbox = true,
13368c2ecf20Sopenharmony_ci		.out_is_imm = false,
13378c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13388c2ecf20Sopenharmony_ci		.verify = NULL,
13398c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_SRQ_wrapper
13408c2ecf20Sopenharmony_ci	},
13418c2ecf20Sopenharmony_ci	{
13428c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_ARM_SRQ,
13438c2ecf20Sopenharmony_ci		.has_inbox = false,
13448c2ecf20Sopenharmony_ci		.has_outbox = false,
13458c2ecf20Sopenharmony_ci		.out_is_imm = false,
13468c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13478c2ecf20Sopenharmony_ci		.verify = NULL,
13488c2ecf20Sopenharmony_ci		.wrapper = mlx4_ARM_SRQ_wrapper
13498c2ecf20Sopenharmony_ci	},
13508c2ecf20Sopenharmony_ci	{
13518c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_RST2INIT_QP,
13528c2ecf20Sopenharmony_ci		.has_inbox = true,
13538c2ecf20Sopenharmony_ci		.has_outbox = false,
13548c2ecf20Sopenharmony_ci		.out_is_imm = false,
13558c2ecf20Sopenharmony_ci		.encode_slave_id = true,
13568c2ecf20Sopenharmony_ci		.verify = NULL,
13578c2ecf20Sopenharmony_ci		.wrapper = mlx4_RST2INIT_QP_wrapper
13588c2ecf20Sopenharmony_ci	},
13598c2ecf20Sopenharmony_ci	{
13608c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_INIT2INIT_QP,
13618c2ecf20Sopenharmony_ci		.has_inbox = true,
13628c2ecf20Sopenharmony_ci		.has_outbox = false,
13638c2ecf20Sopenharmony_ci		.out_is_imm = false,
13648c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13658c2ecf20Sopenharmony_ci		.verify = NULL,
13668c2ecf20Sopenharmony_ci		.wrapper = mlx4_INIT2INIT_QP_wrapper
13678c2ecf20Sopenharmony_ci	},
13688c2ecf20Sopenharmony_ci	{
13698c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_INIT2RTR_QP,
13708c2ecf20Sopenharmony_ci		.has_inbox = true,
13718c2ecf20Sopenharmony_ci		.has_outbox = false,
13728c2ecf20Sopenharmony_ci		.out_is_imm = false,
13738c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13748c2ecf20Sopenharmony_ci		.verify = NULL,
13758c2ecf20Sopenharmony_ci		.wrapper = mlx4_INIT2RTR_QP_wrapper
13768c2ecf20Sopenharmony_ci	},
13778c2ecf20Sopenharmony_ci	{
13788c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_RTR2RTS_QP,
13798c2ecf20Sopenharmony_ci		.has_inbox = true,
13808c2ecf20Sopenharmony_ci		.has_outbox = false,
13818c2ecf20Sopenharmony_ci		.out_is_imm = false,
13828c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13838c2ecf20Sopenharmony_ci		.verify = NULL,
13848c2ecf20Sopenharmony_ci		.wrapper = mlx4_RTR2RTS_QP_wrapper
13858c2ecf20Sopenharmony_ci	},
13868c2ecf20Sopenharmony_ci	{
13878c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_RTS2RTS_QP,
13888c2ecf20Sopenharmony_ci		.has_inbox = true,
13898c2ecf20Sopenharmony_ci		.has_outbox = false,
13908c2ecf20Sopenharmony_ci		.out_is_imm = false,
13918c2ecf20Sopenharmony_ci		.encode_slave_id = false,
13928c2ecf20Sopenharmony_ci		.verify = NULL,
13938c2ecf20Sopenharmony_ci		.wrapper = mlx4_RTS2RTS_QP_wrapper
13948c2ecf20Sopenharmony_ci	},
13958c2ecf20Sopenharmony_ci	{
13968c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SQERR2RTS_QP,
13978c2ecf20Sopenharmony_ci		.has_inbox = true,
13988c2ecf20Sopenharmony_ci		.has_outbox = false,
13998c2ecf20Sopenharmony_ci		.out_is_imm = false,
14008c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14018c2ecf20Sopenharmony_ci		.verify = NULL,
14028c2ecf20Sopenharmony_ci		.wrapper = mlx4_SQERR2RTS_QP_wrapper
14038c2ecf20Sopenharmony_ci	},
14048c2ecf20Sopenharmony_ci	{
14058c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_2ERR_QP,
14068c2ecf20Sopenharmony_ci		.has_inbox = false,
14078c2ecf20Sopenharmony_ci		.has_outbox = false,
14088c2ecf20Sopenharmony_ci		.out_is_imm = false,
14098c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14108c2ecf20Sopenharmony_ci		.verify = NULL,
14118c2ecf20Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
14128c2ecf20Sopenharmony_ci	},
14138c2ecf20Sopenharmony_ci	{
14148c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_RTS2SQD_QP,
14158c2ecf20Sopenharmony_ci		.has_inbox = false,
14168c2ecf20Sopenharmony_ci		.has_outbox = false,
14178c2ecf20Sopenharmony_ci		.out_is_imm = false,
14188c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14198c2ecf20Sopenharmony_ci		.verify = NULL,
14208c2ecf20Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
14218c2ecf20Sopenharmony_ci	},
14228c2ecf20Sopenharmony_ci	{
14238c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SQD2SQD_QP,
14248c2ecf20Sopenharmony_ci		.has_inbox = true,
14258c2ecf20Sopenharmony_ci		.has_outbox = false,
14268c2ecf20Sopenharmony_ci		.out_is_imm = false,
14278c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14288c2ecf20Sopenharmony_ci		.verify = NULL,
14298c2ecf20Sopenharmony_ci		.wrapper = mlx4_SQD2SQD_QP_wrapper
14308c2ecf20Sopenharmony_ci	},
14318c2ecf20Sopenharmony_ci	{
14328c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SQD2RTS_QP,
14338c2ecf20Sopenharmony_ci		.has_inbox = true,
14348c2ecf20Sopenharmony_ci		.has_outbox = false,
14358c2ecf20Sopenharmony_ci		.out_is_imm = false,
14368c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14378c2ecf20Sopenharmony_ci		.verify = NULL,
14388c2ecf20Sopenharmony_ci		.wrapper = mlx4_SQD2RTS_QP_wrapper
14398c2ecf20Sopenharmony_ci	},
14408c2ecf20Sopenharmony_ci	{
14418c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_2RST_QP,
14428c2ecf20Sopenharmony_ci		.has_inbox = false,
14438c2ecf20Sopenharmony_ci		.has_outbox = false,
14448c2ecf20Sopenharmony_ci		.out_is_imm = false,
14458c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14468c2ecf20Sopenharmony_ci		.verify = NULL,
14478c2ecf20Sopenharmony_ci		.wrapper = mlx4_2RST_QP_wrapper
14488c2ecf20Sopenharmony_ci	},
14498c2ecf20Sopenharmony_ci	{
14508c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_QP,
14518c2ecf20Sopenharmony_ci		.has_inbox = false,
14528c2ecf20Sopenharmony_ci		.has_outbox = true,
14538c2ecf20Sopenharmony_ci		.out_is_imm = false,
14548c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14558c2ecf20Sopenharmony_ci		.verify = NULL,
14568c2ecf20Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
14578c2ecf20Sopenharmony_ci	},
14588c2ecf20Sopenharmony_ci	{
14598c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SUSPEND_QP,
14608c2ecf20Sopenharmony_ci		.has_inbox = false,
14618c2ecf20Sopenharmony_ci		.has_outbox = false,
14628c2ecf20Sopenharmony_ci		.out_is_imm = false,
14638c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14648c2ecf20Sopenharmony_ci		.verify = NULL,
14658c2ecf20Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
14668c2ecf20Sopenharmony_ci	},
14678c2ecf20Sopenharmony_ci	{
14688c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_UNSUSPEND_QP,
14698c2ecf20Sopenharmony_ci		.has_inbox = false,
14708c2ecf20Sopenharmony_ci		.has_outbox = false,
14718c2ecf20Sopenharmony_ci		.out_is_imm = false,
14728c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14738c2ecf20Sopenharmony_ci		.verify = NULL,
14748c2ecf20Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
14758c2ecf20Sopenharmony_ci	},
14768c2ecf20Sopenharmony_ci	{
14778c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_UPDATE_QP,
14788c2ecf20Sopenharmony_ci		.has_inbox = true,
14798c2ecf20Sopenharmony_ci		.has_outbox = false,
14808c2ecf20Sopenharmony_ci		.out_is_imm = false,
14818c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14828c2ecf20Sopenharmony_ci		.verify = NULL,
14838c2ecf20Sopenharmony_ci		.wrapper = mlx4_UPDATE_QP_wrapper
14848c2ecf20Sopenharmony_ci	},
14858c2ecf20Sopenharmony_ci	{
14868c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_GET_OP_REQ,
14878c2ecf20Sopenharmony_ci		.has_inbox = false,
14888c2ecf20Sopenharmony_ci		.has_outbox = false,
14898c2ecf20Sopenharmony_ci		.out_is_imm = false,
14908c2ecf20Sopenharmony_ci		.encode_slave_id = false,
14918c2ecf20Sopenharmony_ci		.verify = NULL,
14928c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
14938c2ecf20Sopenharmony_ci	},
14948c2ecf20Sopenharmony_ci	{
14958c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_ALLOCATE_VPP,
14968c2ecf20Sopenharmony_ci		.has_inbox = false,
14978c2ecf20Sopenharmony_ci		.has_outbox = true,
14988c2ecf20Sopenharmony_ci		.out_is_imm = false,
14998c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15008c2ecf20Sopenharmony_ci		.verify = NULL,
15018c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
15028c2ecf20Sopenharmony_ci	},
15038c2ecf20Sopenharmony_ci	{
15048c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SET_VPORT_QOS,
15058c2ecf20Sopenharmony_ci		.has_inbox = false,
15068c2ecf20Sopenharmony_ci		.has_outbox = true,
15078c2ecf20Sopenharmony_ci		.out_is_imm = false,
15088c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15098c2ecf20Sopenharmony_ci		.verify = NULL,
15108c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
15118c2ecf20Sopenharmony_ci	},
15128c2ecf20Sopenharmony_ci	{
15138c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_CONF_SPECIAL_QP,
15148c2ecf20Sopenharmony_ci		.has_inbox = false,
15158c2ecf20Sopenharmony_ci		.has_outbox = false,
15168c2ecf20Sopenharmony_ci		.out_is_imm = false,
15178c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15188c2ecf20Sopenharmony_ci		.verify = NULL, /* XXX verify: only demux can do this */
15198c2ecf20Sopenharmony_ci		.wrapper = NULL
15208c2ecf20Sopenharmony_ci	},
15218c2ecf20Sopenharmony_ci	{
15228c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_MAD_IFC,
15238c2ecf20Sopenharmony_ci		.has_inbox = true,
15248c2ecf20Sopenharmony_ci		.has_outbox = true,
15258c2ecf20Sopenharmony_ci		.out_is_imm = false,
15268c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15278c2ecf20Sopenharmony_ci		.verify = NULL,
15288c2ecf20Sopenharmony_ci		.wrapper = mlx4_MAD_IFC_wrapper
15298c2ecf20Sopenharmony_ci	},
15308c2ecf20Sopenharmony_ci	{
15318c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_MAD_DEMUX,
15328c2ecf20Sopenharmony_ci		.has_inbox = false,
15338c2ecf20Sopenharmony_ci		.has_outbox = false,
15348c2ecf20Sopenharmony_ci		.out_is_imm = false,
15358c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15368c2ecf20Sopenharmony_ci		.verify = NULL,
15378c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
15388c2ecf20Sopenharmony_ci	},
15398c2ecf20Sopenharmony_ci	{
15408c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_IF_STAT,
15418c2ecf20Sopenharmony_ci		.has_inbox = false,
15428c2ecf20Sopenharmony_ci		.has_outbox = true,
15438c2ecf20Sopenharmony_ci		.out_is_imm = false,
15448c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15458c2ecf20Sopenharmony_ci		.verify = NULL,
15468c2ecf20Sopenharmony_ci		.wrapper = mlx4_QUERY_IF_STAT_wrapper
15478c2ecf20Sopenharmony_ci	},
15488c2ecf20Sopenharmony_ci	{
15498c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_ACCESS_REG,
15508c2ecf20Sopenharmony_ci		.has_inbox = true,
15518c2ecf20Sopenharmony_ci		.has_outbox = true,
15528c2ecf20Sopenharmony_ci		.out_is_imm = false,
15538c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15548c2ecf20Sopenharmony_ci		.verify = NULL,
15558c2ecf20Sopenharmony_ci		.wrapper = mlx4_ACCESS_REG_wrapper,
15568c2ecf20Sopenharmony_ci	},
15578c2ecf20Sopenharmony_ci	{
15588c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_CONGESTION_CTRL_OPCODE,
15598c2ecf20Sopenharmony_ci		.has_inbox = false,
15608c2ecf20Sopenharmony_ci		.has_outbox = false,
15618c2ecf20Sopenharmony_ci		.out_is_imm = false,
15628c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15638c2ecf20Sopenharmony_ci		.verify = NULL,
15648c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
15658c2ecf20Sopenharmony_ci	},
15668c2ecf20Sopenharmony_ci	/* Native multicast commands are not available for guests */
15678c2ecf20Sopenharmony_ci	{
15688c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_QP_ATTACH,
15698c2ecf20Sopenharmony_ci		.has_inbox = true,
15708c2ecf20Sopenharmony_ci		.has_outbox = false,
15718c2ecf20Sopenharmony_ci		.out_is_imm = false,
15728c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15738c2ecf20Sopenharmony_ci		.verify = NULL,
15748c2ecf20Sopenharmony_ci		.wrapper = mlx4_QP_ATTACH_wrapper
15758c2ecf20Sopenharmony_ci	},
15768c2ecf20Sopenharmony_ci	{
15778c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_PROMISC,
15788c2ecf20Sopenharmony_ci		.has_inbox = false,
15798c2ecf20Sopenharmony_ci		.has_outbox = false,
15808c2ecf20Sopenharmony_ci		.out_is_imm = false,
15818c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15828c2ecf20Sopenharmony_ci		.verify = NULL,
15838c2ecf20Sopenharmony_ci		.wrapper = mlx4_PROMISC_wrapper
15848c2ecf20Sopenharmony_ci	},
15858c2ecf20Sopenharmony_ci	/* Ethernet specific commands */
15868c2ecf20Sopenharmony_ci	{
15878c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SET_VLAN_FLTR,
15888c2ecf20Sopenharmony_ci		.has_inbox = true,
15898c2ecf20Sopenharmony_ci		.has_outbox = false,
15908c2ecf20Sopenharmony_ci		.out_is_imm = false,
15918c2ecf20Sopenharmony_ci		.encode_slave_id = false,
15928c2ecf20Sopenharmony_ci		.verify = NULL,
15938c2ecf20Sopenharmony_ci		.wrapper = mlx4_SET_VLAN_FLTR_wrapper
15948c2ecf20Sopenharmony_ci	},
15958c2ecf20Sopenharmony_ci	{
15968c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_SET_MCAST_FLTR,
15978c2ecf20Sopenharmony_ci		.has_inbox = false,
15988c2ecf20Sopenharmony_ci		.has_outbox = false,
15998c2ecf20Sopenharmony_ci		.out_is_imm = false,
16008c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16018c2ecf20Sopenharmony_ci		.verify = NULL,
16028c2ecf20Sopenharmony_ci		.wrapper = mlx4_SET_MCAST_FLTR_wrapper
16038c2ecf20Sopenharmony_ci	},
16048c2ecf20Sopenharmony_ci	{
16058c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_DUMP_ETH_STATS,
16068c2ecf20Sopenharmony_ci		.has_inbox = false,
16078c2ecf20Sopenharmony_ci		.has_outbox = true,
16088c2ecf20Sopenharmony_ci		.out_is_imm = false,
16098c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16108c2ecf20Sopenharmony_ci		.verify = NULL,
16118c2ecf20Sopenharmony_ci		.wrapper = mlx4_DUMP_ETH_STATS_wrapper
16128c2ecf20Sopenharmony_ci	},
16138c2ecf20Sopenharmony_ci	{
16148c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_INFORM_FLR_DONE,
16158c2ecf20Sopenharmony_ci		.has_inbox = false,
16168c2ecf20Sopenharmony_ci		.has_outbox = false,
16178c2ecf20Sopenharmony_ci		.out_is_imm = false,
16188c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16198c2ecf20Sopenharmony_ci		.verify = NULL,
16208c2ecf20Sopenharmony_ci		.wrapper = NULL
16218c2ecf20Sopenharmony_ci	},
16228c2ecf20Sopenharmony_ci	/* flow steering commands */
16238c2ecf20Sopenharmony_ci	{
16248c2ecf20Sopenharmony_ci		.opcode = MLX4_QP_FLOW_STEERING_ATTACH,
16258c2ecf20Sopenharmony_ci		.has_inbox = true,
16268c2ecf20Sopenharmony_ci		.has_outbox = false,
16278c2ecf20Sopenharmony_ci		.out_is_imm = true,
16288c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16298c2ecf20Sopenharmony_ci		.verify = NULL,
16308c2ecf20Sopenharmony_ci		.wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper
16318c2ecf20Sopenharmony_ci	},
16328c2ecf20Sopenharmony_ci	{
16338c2ecf20Sopenharmony_ci		.opcode = MLX4_QP_FLOW_STEERING_DETACH,
16348c2ecf20Sopenharmony_ci		.has_inbox = false,
16358c2ecf20Sopenharmony_ci		.has_outbox = false,
16368c2ecf20Sopenharmony_ci		.out_is_imm = false,
16378c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16388c2ecf20Sopenharmony_ci		.verify = NULL,
16398c2ecf20Sopenharmony_ci		.wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper
16408c2ecf20Sopenharmony_ci	},
16418c2ecf20Sopenharmony_ci	{
16428c2ecf20Sopenharmony_ci		.opcode = MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
16438c2ecf20Sopenharmony_ci		.has_inbox = false,
16448c2ecf20Sopenharmony_ci		.has_outbox = false,
16458c2ecf20Sopenharmony_ci		.out_is_imm = false,
16468c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16478c2ecf20Sopenharmony_ci		.verify = NULL,
16488c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
16498c2ecf20Sopenharmony_ci	},
16508c2ecf20Sopenharmony_ci	{
16518c2ecf20Sopenharmony_ci		.opcode = MLX4_CMD_VIRT_PORT_MAP,
16528c2ecf20Sopenharmony_ci		.has_inbox = false,
16538c2ecf20Sopenharmony_ci		.has_outbox = false,
16548c2ecf20Sopenharmony_ci		.out_is_imm = false,
16558c2ecf20Sopenharmony_ci		.encode_slave_id = false,
16568c2ecf20Sopenharmony_ci		.verify = NULL,
16578c2ecf20Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
16588c2ecf20Sopenharmony_ci	},
16598c2ecf20Sopenharmony_ci};
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
16628c2ecf20Sopenharmony_ci				    struct mlx4_vhcr_cmd *in_vhcr)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
16658c2ecf20Sopenharmony_ci	struct mlx4_cmd_info *cmd = NULL;
16668c2ecf20Sopenharmony_ci	struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr;
16678c2ecf20Sopenharmony_ci	struct mlx4_vhcr *vhcr;
16688c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *inbox = NULL;
16698c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *outbox = NULL;
16708c2ecf20Sopenharmony_ci	u64 in_param;
16718c2ecf20Sopenharmony_ci	u64 out_param;
16728c2ecf20Sopenharmony_ci	int ret = 0;
16738c2ecf20Sopenharmony_ci	int i;
16748c2ecf20Sopenharmony_ci	int err = 0;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	/* Create sw representation of Virtual HCR */
16778c2ecf20Sopenharmony_ci	vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL);
16788c2ecf20Sopenharmony_ci	if (!vhcr)
16798c2ecf20Sopenharmony_ci		return -ENOMEM;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	/* DMA in the vHCR */
16828c2ecf20Sopenharmony_ci	if (!in_vhcr) {
16838c2ecf20Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
16848c2ecf20Sopenharmony_ci				      priv->mfunc.master.slave_state[slave].vhcr_dma,
16858c2ecf20Sopenharmony_ci				      ALIGN(sizeof(struct mlx4_vhcr_cmd),
16868c2ecf20Sopenharmony_ci					    MLX4_ACCESS_MEM_ALIGN), 1);
16878c2ecf20Sopenharmony_ci		if (ret) {
16888c2ecf20Sopenharmony_ci			if (!(dev->persist->state &
16898c2ecf20Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
16908c2ecf20Sopenharmony_ci				mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n",
16918c2ecf20Sopenharmony_ci					 __func__, ret);
16928c2ecf20Sopenharmony_ci			kfree(vhcr);
16938c2ecf20Sopenharmony_ci			return ret;
16948c2ecf20Sopenharmony_ci		}
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	/* Fill SW VHCR fields */
16988c2ecf20Sopenharmony_ci	vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param);
16998c2ecf20Sopenharmony_ci	vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param);
17008c2ecf20Sopenharmony_ci	vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier);
17018c2ecf20Sopenharmony_ci	vhcr->token = be16_to_cpu(vhcr_cmd->token);
17028c2ecf20Sopenharmony_ci	vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff;
17038c2ecf20Sopenharmony_ci	vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12);
17048c2ecf20Sopenharmony_ci	vhcr->e_bit = vhcr_cmd->flags & (1 << 6);
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	/* Lookup command */
17078c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) {
17088c2ecf20Sopenharmony_ci		if (vhcr->op == cmd_info[i].opcode) {
17098c2ecf20Sopenharmony_ci			cmd = &cmd_info[i];
17108c2ecf20Sopenharmony_ci			break;
17118c2ecf20Sopenharmony_ci		}
17128c2ecf20Sopenharmony_ci	}
17138c2ecf20Sopenharmony_ci	if (!cmd) {
17148c2ecf20Sopenharmony_ci		mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n",
17158c2ecf20Sopenharmony_ci			 vhcr->op, slave);
17168c2ecf20Sopenharmony_ci		vhcr_cmd->status = CMD_STAT_BAD_PARAM;
17178c2ecf20Sopenharmony_ci		goto out_status;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	/* Read inbox */
17218c2ecf20Sopenharmony_ci	if (cmd->has_inbox) {
17228c2ecf20Sopenharmony_ci		vhcr->in_param &= INBOX_MASK;
17238c2ecf20Sopenharmony_ci		inbox = mlx4_alloc_cmd_mailbox(dev);
17248c2ecf20Sopenharmony_ci		if (IS_ERR(inbox)) {
17258c2ecf20Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
17268c2ecf20Sopenharmony_ci			inbox = NULL;
17278c2ecf20Sopenharmony_ci			goto out_status;
17288c2ecf20Sopenharmony_ci		}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave,
17318c2ecf20Sopenharmony_ci				      vhcr->in_param,
17328c2ecf20Sopenharmony_ci				      MLX4_MAILBOX_SIZE, 1);
17338c2ecf20Sopenharmony_ci		if (ret) {
17348c2ecf20Sopenharmony_ci			if (!(dev->persist->state &
17358c2ecf20Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
17368c2ecf20Sopenharmony_ci				mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
17378c2ecf20Sopenharmony_ci					 __func__, cmd->opcode);
17388c2ecf20Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_INTERNAL_ERR;
17398c2ecf20Sopenharmony_ci			goto out_status;
17408c2ecf20Sopenharmony_ci		}
17418c2ecf20Sopenharmony_ci	}
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	/* Apply permission and bound checks if applicable */
17448c2ecf20Sopenharmony_ci	if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) {
17458c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Command:0x%x from slave: %d failed protection checks for resource_id:%d\n",
17468c2ecf20Sopenharmony_ci			  vhcr->op, slave, vhcr->in_modifier);
17478c2ecf20Sopenharmony_ci		vhcr_cmd->status = CMD_STAT_BAD_OP;
17488c2ecf20Sopenharmony_ci		goto out_status;
17498c2ecf20Sopenharmony_ci	}
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	/* Allocate outbox */
17528c2ecf20Sopenharmony_ci	if (cmd->has_outbox) {
17538c2ecf20Sopenharmony_ci		outbox = mlx4_alloc_cmd_mailbox(dev);
17548c2ecf20Sopenharmony_ci		if (IS_ERR(outbox)) {
17558c2ecf20Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
17568c2ecf20Sopenharmony_ci			outbox = NULL;
17578c2ecf20Sopenharmony_ci			goto out_status;
17588c2ecf20Sopenharmony_ci		}
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	/* Execute the command! */
17628c2ecf20Sopenharmony_ci	if (cmd->wrapper) {
17638c2ecf20Sopenharmony_ci		err = cmd->wrapper(dev, slave, vhcr, inbox, outbox,
17648c2ecf20Sopenharmony_ci				   cmd);
17658c2ecf20Sopenharmony_ci		if (cmd->out_is_imm)
17668c2ecf20Sopenharmony_ci			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
17678c2ecf20Sopenharmony_ci	} else {
17688c2ecf20Sopenharmony_ci		in_param = cmd->has_inbox ? (u64) inbox->dma :
17698c2ecf20Sopenharmony_ci			vhcr->in_param;
17708c2ecf20Sopenharmony_ci		out_param = cmd->has_outbox ? (u64) outbox->dma :
17718c2ecf20Sopenharmony_ci			vhcr->out_param;
17728c2ecf20Sopenharmony_ci		err = __mlx4_cmd(dev, in_param, &out_param,
17738c2ecf20Sopenharmony_ci				 cmd->out_is_imm, vhcr->in_modifier,
17748c2ecf20Sopenharmony_ci				 vhcr->op_modifier, vhcr->op,
17758c2ecf20Sopenharmony_ci				 MLX4_CMD_TIME_CLASS_A,
17768c2ecf20Sopenharmony_ci				 MLX4_CMD_NATIVE);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		if (cmd->out_is_imm) {
17798c2ecf20Sopenharmony_ci			vhcr->out_param = out_param;
17808c2ecf20Sopenharmony_ci			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
17818c2ecf20Sopenharmony_ci		}
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	if (err) {
17858c2ecf20Sopenharmony_ci		if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
17868c2ecf20Sopenharmony_ci			if (vhcr->op == MLX4_CMD_ALLOC_RES &&
17878c2ecf20Sopenharmony_ci			    (vhcr->in_modifier & 0xff) == RES_COUNTER &&
17888c2ecf20Sopenharmony_ci			    err == -EDQUOT)
17898c2ecf20Sopenharmony_ci				mlx4_dbg(dev,
17908c2ecf20Sopenharmony_ci					 "Unable to allocate counter for slave %d (%d)\n",
17918c2ecf20Sopenharmony_ci					 slave, err);
17928c2ecf20Sopenharmony_ci			else
17938c2ecf20Sopenharmony_ci				mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n",
17948c2ecf20Sopenharmony_ci					  vhcr->op, slave, vhcr->errno, err);
17958c2ecf20Sopenharmony_ci		}
17968c2ecf20Sopenharmony_ci		vhcr_cmd->status = mlx4_errno_to_status(err);
17978c2ecf20Sopenharmony_ci		goto out_status;
17988c2ecf20Sopenharmony_ci	}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	/* Write outbox if command completed successfully */
18028c2ecf20Sopenharmony_ci	if (cmd->has_outbox && !vhcr_cmd->status) {
18038c2ecf20Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave,
18048c2ecf20Sopenharmony_ci				      vhcr->out_param,
18058c2ecf20Sopenharmony_ci				      MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED);
18068c2ecf20Sopenharmony_ci		if (ret) {
18078c2ecf20Sopenharmony_ci			/* If we failed to write back the outbox after the
18088c2ecf20Sopenharmony_ci			 *command was successfully executed, we must fail this
18098c2ecf20Sopenharmony_ci			 * slave, as it is now in undefined state */
18108c2ecf20Sopenharmony_ci			if (!(dev->persist->state &
18118c2ecf20Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
18128c2ecf20Sopenharmony_ci				mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
18138c2ecf20Sopenharmony_ci			goto out;
18148c2ecf20Sopenharmony_ci		}
18158c2ecf20Sopenharmony_ci	}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ciout_status:
18188c2ecf20Sopenharmony_ci	/* DMA back vhcr result */
18198c2ecf20Sopenharmony_ci	if (!in_vhcr) {
18208c2ecf20Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
18218c2ecf20Sopenharmony_ci				      priv->mfunc.master.slave_state[slave].vhcr_dma,
18228c2ecf20Sopenharmony_ci				      ALIGN(sizeof(struct mlx4_vhcr),
18238c2ecf20Sopenharmony_ci					    MLX4_ACCESS_MEM_ALIGN),
18248c2ecf20Sopenharmony_ci				      MLX4_CMD_WRAPPED);
18258c2ecf20Sopenharmony_ci		if (ret)
18268c2ecf20Sopenharmony_ci			mlx4_err(dev, "%s:Failed writing vhcr result\n",
18278c2ecf20Sopenharmony_ci				 __func__);
18288c2ecf20Sopenharmony_ci		else if (vhcr->e_bit &&
18298c2ecf20Sopenharmony_ci			 mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe))
18308c2ecf20Sopenharmony_ci				mlx4_warn(dev, "Failed to generate command completion eqe for slave %d\n",
18318c2ecf20Sopenharmony_ci					  slave);
18328c2ecf20Sopenharmony_ci	}
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ciout:
18358c2ecf20Sopenharmony_ci	kfree(vhcr);
18368c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, inbox);
18378c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, outbox);
18388c2ecf20Sopenharmony_ci	return ret;
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
18428c2ecf20Sopenharmony_ci					    int slave, int port)
18438c2ecf20Sopenharmony_ci{
18448c2ecf20Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
18458c2ecf20Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
18468c2ecf20Sopenharmony_ci	struct mlx4_vf_immed_vlan_work *work;
18478c2ecf20Sopenharmony_ci	struct mlx4_dev *dev = &(priv->dev);
18488c2ecf20Sopenharmony_ci	int err;
18498c2ecf20Sopenharmony_ci	int admin_vlan_ix = NO_INDX;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
18528c2ecf20Sopenharmony_ci	vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	if (vp_oper->state.default_vlan == vp_admin->default_vlan &&
18558c2ecf20Sopenharmony_ci	    vp_oper->state.default_qos == vp_admin->default_qos &&
18568c2ecf20Sopenharmony_ci	    vp_oper->state.vlan_proto == vp_admin->vlan_proto &&
18578c2ecf20Sopenharmony_ci	    vp_oper->state.link_state == vp_admin->link_state &&
18588c2ecf20Sopenharmony_ci	    vp_oper->state.qos_vport == vp_admin->qos_vport)
18598c2ecf20Sopenharmony_ci		return 0;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	if (!(priv->mfunc.master.slave_state[slave].active &&
18628c2ecf20Sopenharmony_ci	      dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)) {
18638c2ecf20Sopenharmony_ci		/* even if the UPDATE_QP command isn't supported, we still want
18648c2ecf20Sopenharmony_ci		 * to set this VF link according to the admin directive
18658c2ecf20Sopenharmony_ci		 */
18668c2ecf20Sopenharmony_ci		vp_oper->state.link_state = vp_admin->link_state;
18678c2ecf20Sopenharmony_ci		return -1;
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n",
18718c2ecf20Sopenharmony_ci		 slave, port);
18728c2ecf20Sopenharmony_ci	mlx4_dbg(dev, "vlan %d QoS %d link down %d\n",
18738c2ecf20Sopenharmony_ci		 vp_admin->default_vlan, vp_admin->default_qos,
18748c2ecf20Sopenharmony_ci		 vp_admin->link_state);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	work = kzalloc(sizeof(*work), GFP_KERNEL);
18778c2ecf20Sopenharmony_ci	if (!work)
18788c2ecf20Sopenharmony_ci		return -ENOMEM;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	if (vp_oper->state.default_vlan != vp_admin->default_vlan) {
18818c2ecf20Sopenharmony_ci		if (MLX4_VGT != vp_admin->default_vlan) {
18828c2ecf20Sopenharmony_ci			err = __mlx4_register_vlan(&priv->dev, port,
18838c2ecf20Sopenharmony_ci						   vp_admin->default_vlan,
18848c2ecf20Sopenharmony_ci						   &admin_vlan_ix);
18858c2ecf20Sopenharmony_ci			if (err) {
18868c2ecf20Sopenharmony_ci				kfree(work);
18878c2ecf20Sopenharmony_ci				mlx4_warn(&priv->dev,
18888c2ecf20Sopenharmony_ci					  "No vlan resources slave %d, port %d\n",
18898c2ecf20Sopenharmony_ci					  slave, port);
18908c2ecf20Sopenharmony_ci				return err;
18918c2ecf20Sopenharmony_ci			}
18928c2ecf20Sopenharmony_ci		} else {
18938c2ecf20Sopenharmony_ci			admin_vlan_ix = NO_INDX;
18948c2ecf20Sopenharmony_ci		}
18958c2ecf20Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN;
18968c2ecf20Sopenharmony_ci		mlx4_dbg(&priv->dev,
18978c2ecf20Sopenharmony_ci			 "alloc vlan %d idx  %d slave %d port %d\n",
18988c2ecf20Sopenharmony_ci			 (int)(vp_admin->default_vlan),
18998c2ecf20Sopenharmony_ci			 admin_vlan_ix, slave, port);
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	/* save original vlan ix and vlan id */
19038c2ecf20Sopenharmony_ci	work->orig_vlan_id = vp_oper->state.default_vlan;
19048c2ecf20Sopenharmony_ci	work->orig_vlan_ix = vp_oper->vlan_idx;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	/* handle new qos */
19078c2ecf20Sopenharmony_ci	if (vp_oper->state.default_qos != vp_admin->default_qos)
19088c2ecf20Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN)
19118c2ecf20Sopenharmony_ci		vp_oper->vlan_idx = admin_vlan_ix;
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	vp_oper->state.default_vlan = vp_admin->default_vlan;
19148c2ecf20Sopenharmony_ci	vp_oper->state.default_qos = vp_admin->default_qos;
19158c2ecf20Sopenharmony_ci	vp_oper->state.vlan_proto = vp_admin->vlan_proto;
19168c2ecf20Sopenharmony_ci	vp_oper->state.link_state = vp_admin->link_state;
19178c2ecf20Sopenharmony_ci	vp_oper->state.qos_vport = vp_admin->qos_vport;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE)
19208c2ecf20Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	/* iterate over QPs owned by this slave, using UPDATE_QP */
19238c2ecf20Sopenharmony_ci	work->port = port;
19248c2ecf20Sopenharmony_ci	work->slave = slave;
19258c2ecf20Sopenharmony_ci	work->qos = vp_oper->state.default_qos;
19268c2ecf20Sopenharmony_ci	work->qos_vport = vp_oper->state.qos_vport;
19278c2ecf20Sopenharmony_ci	work->vlan_id = vp_oper->state.default_vlan;
19288c2ecf20Sopenharmony_ci	work->vlan_ix = vp_oper->vlan_idx;
19298c2ecf20Sopenharmony_ci	work->vlan_proto = vp_oper->state.vlan_proto;
19308c2ecf20Sopenharmony_ci	work->priv = priv;
19318c2ecf20Sopenharmony_ci	INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler);
19328c2ecf20Sopenharmony_ci	queue_work(priv->mfunc.master.comm_wq, &work->work);
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	return 0;
19358c2ecf20Sopenharmony_ci}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_cistatic void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port)
19388c2ecf20Sopenharmony_ci{
19398c2ecf20Sopenharmony_ci	struct mlx4_qos_manager *port_qos_ctl;
19408c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	port_qos_ctl = &priv->mfunc.master.qos_ctl[port];
19438c2ecf20Sopenharmony_ci	bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP);
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	/* Enable only default prio at PF init routine */
19468c2ecf20Sopenharmony_ci	set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm);
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port)
19508c2ecf20Sopenharmony_ci{
19518c2ecf20Sopenharmony_ci	int i;
19528c2ecf20Sopenharmony_ci	int err;
19538c2ecf20Sopenharmony_ci	int num_vfs;
19548c2ecf20Sopenharmony_ci	u16 available_vpp;
19558c2ecf20Sopenharmony_ci	u8 vpp_param[MLX4_NUM_UP];
19568c2ecf20Sopenharmony_ci	struct mlx4_qos_manager *port_qos;
19578c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param);
19608c2ecf20Sopenharmony_ci	if (err) {
19618c2ecf20Sopenharmony_ci		mlx4_info(dev, "Failed query available VPPs\n");
19628c2ecf20Sopenharmony_ci		return;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	port_qos = &priv->mfunc.master.qos_ctl[port];
19668c2ecf20Sopenharmony_ci	num_vfs = (available_vpp /
19678c2ecf20Sopenharmony_ci		   bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP));
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++) {
19708c2ecf20Sopenharmony_ci		if (test_bit(i, port_qos->priority_bm))
19718c2ecf20Sopenharmony_ci			vpp_param[i] = num_vfs;
19728c2ecf20Sopenharmony_ci	}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param);
19758c2ecf20Sopenharmony_ci	if (err) {
19768c2ecf20Sopenharmony_ci		mlx4_info(dev, "Failed allocating VPPs\n");
19778c2ecf20Sopenharmony_ci		return;
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	/* Query actual allocated VPP, just to make sure */
19818c2ecf20Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param);
19828c2ecf20Sopenharmony_ci	if (err) {
19838c2ecf20Sopenharmony_ci		mlx4_info(dev, "Failed query available VPPs\n");
19848c2ecf20Sopenharmony_ci		return;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	port_qos->num_of_qos_vfs = num_vfs;
19888c2ecf20Sopenharmony_ci	mlx4_dbg(dev, "Port %d Available VPPs %d\n", port, available_vpp);
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++)
19918c2ecf20Sopenharmony_ci		mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i,
19928c2ecf20Sopenharmony_ci			 vpp_param[i]);
19938c2ecf20Sopenharmony_ci}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_cistatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
19968c2ecf20Sopenharmony_ci{
19978c2ecf20Sopenharmony_ci	int port, err;
19988c2ecf20Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
19998c2ecf20Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
20008c2ecf20Sopenharmony_ci	struct mlx4_slave_state *slave_state =
20018c2ecf20Sopenharmony_ci		&priv->mfunc.master.slave_state[slave];
20028c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
20038c2ecf20Sopenharmony_ci			&priv->dev, slave);
20048c2ecf20Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports,
20058c2ecf20Sopenharmony_ci				      priv->dev.caps.num_ports) + 1;
20068c2ecf20Sopenharmony_ci	int max_port = min_port - 1 +
20078c2ecf20Sopenharmony_ci		bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	for (port = min_port; port <= max_port; port++) {
20108c2ecf20Sopenharmony_ci		if (!test_bit(port - 1, actv_ports.ports))
20118c2ecf20Sopenharmony_ci			continue;
20128c2ecf20Sopenharmony_ci		priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
20138c2ecf20Sopenharmony_ci			priv->mfunc.master.vf_admin[slave].enable_smi[port];
20148c2ecf20Sopenharmony_ci		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
20158c2ecf20Sopenharmony_ci		vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
20168c2ecf20Sopenharmony_ci		if (vp_admin->vlan_proto != htons(ETH_P_8021AD) ||
20178c2ecf20Sopenharmony_ci		    slave_state->vst_qinq_supported) {
20188c2ecf20Sopenharmony_ci			vp_oper->state.vlan_proto   = vp_admin->vlan_proto;
20198c2ecf20Sopenharmony_ci			vp_oper->state.default_vlan = vp_admin->default_vlan;
20208c2ecf20Sopenharmony_ci			vp_oper->state.default_qos  = vp_admin->default_qos;
20218c2ecf20Sopenharmony_ci		}
20228c2ecf20Sopenharmony_ci		vp_oper->state.link_state = vp_admin->link_state;
20238c2ecf20Sopenharmony_ci		vp_oper->state.mac        = vp_admin->mac;
20248c2ecf20Sopenharmony_ci		vp_oper->state.spoofchk   = vp_admin->spoofchk;
20258c2ecf20Sopenharmony_ci		vp_oper->state.tx_rate    = vp_admin->tx_rate;
20268c2ecf20Sopenharmony_ci		vp_oper->state.qos_vport  = vp_admin->qos_vport;
20278c2ecf20Sopenharmony_ci		vp_oper->state.guid       = vp_admin->guid;
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		if (MLX4_VGT != vp_admin->default_vlan) {
20308c2ecf20Sopenharmony_ci			err = __mlx4_register_vlan(&priv->dev, port,
20318c2ecf20Sopenharmony_ci						   vp_admin->default_vlan, &(vp_oper->vlan_idx));
20328c2ecf20Sopenharmony_ci			if (err) {
20338c2ecf20Sopenharmony_ci				vp_oper->vlan_idx = NO_INDX;
20348c2ecf20Sopenharmony_ci				vp_oper->state.default_vlan = MLX4_VGT;
20358c2ecf20Sopenharmony_ci				vp_oper->state.vlan_proto = htons(ETH_P_8021Q);
20368c2ecf20Sopenharmony_ci				mlx4_warn(&priv->dev,
20378c2ecf20Sopenharmony_ci					  "No vlan resources slave %d, port %d\n",
20388c2ecf20Sopenharmony_ci					  slave, port);
20398c2ecf20Sopenharmony_ci				return err;
20408c2ecf20Sopenharmony_ci			}
20418c2ecf20Sopenharmony_ci			mlx4_dbg(&priv->dev, "alloc vlan %d idx  %d slave %d port %d\n",
20428c2ecf20Sopenharmony_ci				 (int)(vp_oper->state.default_vlan),
20438c2ecf20Sopenharmony_ci				 vp_oper->vlan_idx, slave, port);
20448c2ecf20Sopenharmony_ci		}
20458c2ecf20Sopenharmony_ci		if (vp_admin->spoofchk) {
20468c2ecf20Sopenharmony_ci			vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
20478c2ecf20Sopenharmony_ci							       port,
20488c2ecf20Sopenharmony_ci							       vp_admin->mac);
20498c2ecf20Sopenharmony_ci			if (0 > vp_oper->mac_idx) {
20508c2ecf20Sopenharmony_ci				err = vp_oper->mac_idx;
20518c2ecf20Sopenharmony_ci				vp_oper->mac_idx = NO_INDX;
20528c2ecf20Sopenharmony_ci				mlx4_warn(&priv->dev,
20538c2ecf20Sopenharmony_ci					  "No mac resources slave %d, port %d\n",
20548c2ecf20Sopenharmony_ci					  slave, port);
20558c2ecf20Sopenharmony_ci				return err;
20568c2ecf20Sopenharmony_ci			}
20578c2ecf20Sopenharmony_ci			mlx4_dbg(&priv->dev, "alloc mac %llx idx  %d slave %d port %d\n",
20588c2ecf20Sopenharmony_ci				 vp_oper->state.mac, vp_oper->mac_idx, slave, port);
20598c2ecf20Sopenharmony_ci		}
20608c2ecf20Sopenharmony_ci	}
20618c2ecf20Sopenharmony_ci	return 0;
20628c2ecf20Sopenharmony_ci}
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_cistatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
20658c2ecf20Sopenharmony_ci{
20668c2ecf20Sopenharmony_ci	int port;
20678c2ecf20Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
20688c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
20698c2ecf20Sopenharmony_ci			&priv->dev, slave);
20708c2ecf20Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports,
20718c2ecf20Sopenharmony_ci				      priv->dev.caps.num_ports) + 1;
20728c2ecf20Sopenharmony_ci	int max_port = min_port - 1 +
20738c2ecf20Sopenharmony_ci		bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	for (port = min_port; port <= max_port; port++) {
20778c2ecf20Sopenharmony_ci		if (!test_bit(port - 1, actv_ports.ports))
20788c2ecf20Sopenharmony_ci			continue;
20798c2ecf20Sopenharmony_ci		priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
20808c2ecf20Sopenharmony_ci			MLX4_VF_SMI_DISABLED;
20818c2ecf20Sopenharmony_ci		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
20828c2ecf20Sopenharmony_ci		if (NO_INDX != vp_oper->vlan_idx) {
20838c2ecf20Sopenharmony_ci			__mlx4_unregister_vlan(&priv->dev,
20848c2ecf20Sopenharmony_ci					       port, vp_oper->state.default_vlan);
20858c2ecf20Sopenharmony_ci			vp_oper->vlan_idx = NO_INDX;
20868c2ecf20Sopenharmony_ci		}
20878c2ecf20Sopenharmony_ci		if (NO_INDX != vp_oper->mac_idx) {
20888c2ecf20Sopenharmony_ci			__mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac);
20898c2ecf20Sopenharmony_ci			vp_oper->mac_idx = NO_INDX;
20908c2ecf20Sopenharmony_ci		}
20918c2ecf20Sopenharmony_ci	}
20928c2ecf20Sopenharmony_ci	return;
20938c2ecf20Sopenharmony_ci}
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_cistatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
20968c2ecf20Sopenharmony_ci			       u16 param, u8 toggle)
20978c2ecf20Sopenharmony_ci{
20988c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
20998c2ecf20Sopenharmony_ci	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
21008c2ecf20Sopenharmony_ci	u32 reply;
21018c2ecf20Sopenharmony_ci	u8 is_going_down = 0;
21028c2ecf20Sopenharmony_ci	int i;
21038c2ecf20Sopenharmony_ci	unsigned long flags;
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	slave_state[slave].comm_toggle ^= 1;
21068c2ecf20Sopenharmony_ci	reply = (u32) slave_state[slave].comm_toggle << 31;
21078c2ecf20Sopenharmony_ci	if (toggle != slave_state[slave].comm_toggle) {
21088c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER STATE COMPROMISED ***\n",
21098c2ecf20Sopenharmony_ci			  toggle, slave);
21108c2ecf20Sopenharmony_ci		goto reset_slave;
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci	if (cmd == MLX4_COMM_CMD_RESET) {
21138c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Received reset from slave:%d\n", slave);
21148c2ecf20Sopenharmony_ci		slave_state[slave].active = false;
21158c2ecf20Sopenharmony_ci		slave_state[slave].old_vlan_api = false;
21168c2ecf20Sopenharmony_ci		slave_state[slave].vst_qinq_supported = false;
21178c2ecf20Sopenharmony_ci		mlx4_master_deactivate_admin_state(priv, slave);
21188c2ecf20Sopenharmony_ci		for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
21198c2ecf20Sopenharmony_ci				slave_state[slave].event_eq[i].eqn = -1;
21208c2ecf20Sopenharmony_ci				slave_state[slave].event_eq[i].token = 0;
21218c2ecf20Sopenharmony_ci		}
21228c2ecf20Sopenharmony_ci		/*check if we are in the middle of FLR process,
21238c2ecf20Sopenharmony_ci		if so return "retry" status to the slave*/
21248c2ecf20Sopenharmony_ci		if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
21258c2ecf20Sopenharmony_ci			goto inform_slave_state;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, slave);
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci		/* write the version in the event field */
21308c2ecf20Sopenharmony_ci		reply |= mlx4_comm_get_version();
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci		goto reset_slave;
21338c2ecf20Sopenharmony_ci	}
21348c2ecf20Sopenharmony_ci	/*command from slave in the middle of FLR*/
21358c2ecf20Sopenharmony_ci	if (cmd != MLX4_COMM_CMD_RESET &&
21368c2ecf20Sopenharmony_ci	    MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) {
21378c2ecf20Sopenharmony_ci		mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) in the middle of FLR\n",
21388c2ecf20Sopenharmony_ci			  slave, cmd);
21398c2ecf20Sopenharmony_ci		return;
21408c2ecf20Sopenharmony_ci	}
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	switch (cmd) {
21438c2ecf20Sopenharmony_ci	case MLX4_COMM_CMD_VHCR0:
21448c2ecf20Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET)
21458c2ecf20Sopenharmony_ci			goto reset_slave;
21468c2ecf20Sopenharmony_ci		slave_state[slave].vhcr_dma = ((u64) param) << 48;
21478c2ecf20Sopenharmony_ci		priv->mfunc.master.slave_state[slave].cookie = 0;
21488c2ecf20Sopenharmony_ci		break;
21498c2ecf20Sopenharmony_ci	case MLX4_COMM_CMD_VHCR1:
21508c2ecf20Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
21518c2ecf20Sopenharmony_ci			goto reset_slave;
21528c2ecf20Sopenharmony_ci		slave_state[slave].vhcr_dma |= ((u64) param) << 32;
21538c2ecf20Sopenharmony_ci		break;
21548c2ecf20Sopenharmony_ci	case MLX4_COMM_CMD_VHCR2:
21558c2ecf20Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1)
21568c2ecf20Sopenharmony_ci			goto reset_slave;
21578c2ecf20Sopenharmony_ci		slave_state[slave].vhcr_dma |= ((u64) param) << 16;
21588c2ecf20Sopenharmony_ci		break;
21598c2ecf20Sopenharmony_ci	case MLX4_COMM_CMD_VHCR_EN:
21608c2ecf20Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
21618c2ecf20Sopenharmony_ci			goto reset_slave;
21628c2ecf20Sopenharmony_ci		slave_state[slave].vhcr_dma |= param;
21638c2ecf20Sopenharmony_ci		if (mlx4_master_activate_admin_state(priv, slave))
21648c2ecf20Sopenharmony_ci				goto reset_slave;
21658c2ecf20Sopenharmony_ci		slave_state[slave].active = true;
21668c2ecf20Sopenharmony_ci		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
21678c2ecf20Sopenharmony_ci		break;
21688c2ecf20Sopenharmony_ci	case MLX4_COMM_CMD_VHCR_POST:
21698c2ecf20Sopenharmony_ci		if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
21708c2ecf20Sopenharmony_ci		    (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) {
21718c2ecf20Sopenharmony_ci			mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n",
21728c2ecf20Sopenharmony_ci				  slave, cmd, slave_state[slave].last_cmd);
21738c2ecf20Sopenharmony_ci			goto reset_slave;
21748c2ecf20Sopenharmony_ci		}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
21778c2ecf20Sopenharmony_ci		if (mlx4_master_process_vhcr(dev, slave, NULL)) {
21788c2ecf20Sopenharmony_ci			mlx4_err(dev, "Failed processing vhcr for slave:%d, resetting slave\n",
21798c2ecf20Sopenharmony_ci				 slave);
21808c2ecf20Sopenharmony_ci			mutex_unlock(&priv->cmd.slave_cmd_mutex);
21818c2ecf20Sopenharmony_ci			goto reset_slave;
21828c2ecf20Sopenharmony_ci		}
21838c2ecf20Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
21848c2ecf20Sopenharmony_ci		break;
21858c2ecf20Sopenharmony_ci	default:
21868c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave);
21878c2ecf20Sopenharmony_ci		goto reset_slave;
21888c2ecf20Sopenharmony_ci	}
21898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
21908c2ecf20Sopenharmony_ci	if (!slave_state[slave].is_slave_going_down)
21918c2ecf20Sopenharmony_ci		slave_state[slave].last_cmd = cmd;
21928c2ecf20Sopenharmony_ci	else
21938c2ecf20Sopenharmony_ci		is_going_down = 1;
21948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
21958c2ecf20Sopenharmony_ci	if (is_going_down) {
21968c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Slave is going down aborting command(%d) executing from slave:%d\n",
21978c2ecf20Sopenharmony_ci			  cmd, slave);
21988c2ecf20Sopenharmony_ci		return;
21998c2ecf20Sopenharmony_ci	}
22008c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(reply),
22018c2ecf20Sopenharmony_ci		     &priv->mfunc.comm[slave].slave_read);
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	return;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_cireset_slave:
22068c2ecf20Sopenharmony_ci	/* cleanup any slave resources */
22078c2ecf20Sopenharmony_ci	if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP)
22088c2ecf20Sopenharmony_ci		mlx4_delete_all_resources_for_slave(dev, slave);
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	if (cmd != MLX4_COMM_CMD_RESET) {
22118c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n",
22128c2ecf20Sopenharmony_ci			  slave, cmd);
22138c2ecf20Sopenharmony_ci		/* Turn on internal error letting slave reset itself immeditaly,
22148c2ecf20Sopenharmony_ci		 * otherwise it might take till timeout on command is passed
22158c2ecf20Sopenharmony_ci		 */
22168c2ecf20Sopenharmony_ci		reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR);
22178c2ecf20Sopenharmony_ci	}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
22208c2ecf20Sopenharmony_ci	if (!slave_state[slave].is_slave_going_down)
22218c2ecf20Sopenharmony_ci		slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET;
22228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
22238c2ecf20Sopenharmony_ci	/*with slave in the middle of flr, no need to clean resources again.*/
22248c2ecf20Sopenharmony_ciinform_slave_state:
22258c2ecf20Sopenharmony_ci	memset(&slave_state[slave].event_eq, 0,
22268c2ecf20Sopenharmony_ci	       sizeof(struct mlx4_slave_event_eq_info));
22278c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(reply),
22288c2ecf20Sopenharmony_ci		     &priv->mfunc.comm[slave].slave_read);
22298c2ecf20Sopenharmony_ci	wmb();
22308c2ecf20Sopenharmony_ci}
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci/* master command processing */
22338c2ecf20Sopenharmony_civoid mlx4_master_comm_channel(struct work_struct *work)
22348c2ecf20Sopenharmony_ci{
22358c2ecf20Sopenharmony_ci	struct mlx4_mfunc_master_ctx *master =
22368c2ecf20Sopenharmony_ci		container_of(work,
22378c2ecf20Sopenharmony_ci			     struct mlx4_mfunc_master_ctx,
22388c2ecf20Sopenharmony_ci			     comm_work);
22398c2ecf20Sopenharmony_ci	struct mlx4_mfunc *mfunc =
22408c2ecf20Sopenharmony_ci		container_of(master, struct mlx4_mfunc, master);
22418c2ecf20Sopenharmony_ci	struct mlx4_priv *priv =
22428c2ecf20Sopenharmony_ci		container_of(mfunc, struct mlx4_priv, mfunc);
22438c2ecf20Sopenharmony_ci	struct mlx4_dev *dev = &priv->dev;
22448c2ecf20Sopenharmony_ci	__be32 *bit_vec;
22458c2ecf20Sopenharmony_ci	u32 comm_cmd;
22468c2ecf20Sopenharmony_ci	u32 vec;
22478c2ecf20Sopenharmony_ci	int i, j, slave;
22488c2ecf20Sopenharmony_ci	int toggle;
22498c2ecf20Sopenharmony_ci	int served = 0;
22508c2ecf20Sopenharmony_ci	int reported = 0;
22518c2ecf20Sopenharmony_ci	u32 slt;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	bit_vec = master->comm_arm_bit_vector;
22548c2ecf20Sopenharmony_ci	for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) {
22558c2ecf20Sopenharmony_ci		vec = be32_to_cpu(bit_vec[i]);
22568c2ecf20Sopenharmony_ci		for (j = 0; j < 32; j++) {
22578c2ecf20Sopenharmony_ci			if (!(vec & (1 << j)))
22588c2ecf20Sopenharmony_ci				continue;
22598c2ecf20Sopenharmony_ci			++reported;
22608c2ecf20Sopenharmony_ci			slave = (i * 32) + j;
22618c2ecf20Sopenharmony_ci			comm_cmd = swab32(readl(
22628c2ecf20Sopenharmony_ci					  &mfunc->comm[slave].slave_write));
22638c2ecf20Sopenharmony_ci			slt = swab32(readl(&mfunc->comm[slave].slave_read))
22648c2ecf20Sopenharmony_ci				     >> 31;
22658c2ecf20Sopenharmony_ci			toggle = comm_cmd >> 31;
22668c2ecf20Sopenharmony_ci			if (toggle != slt) {
22678c2ecf20Sopenharmony_ci				if (master->slave_state[slave].comm_toggle
22688c2ecf20Sopenharmony_ci				    != slt) {
22698c2ecf20Sopenharmony_ci					pr_info("slave %d out of sync. read toggle %d, state toggle %d. Resynching.\n",
22708c2ecf20Sopenharmony_ci						slave, slt,
22718c2ecf20Sopenharmony_ci						master->slave_state[slave].comm_toggle);
22728c2ecf20Sopenharmony_ci					master->slave_state[slave].comm_toggle =
22738c2ecf20Sopenharmony_ci						slt;
22748c2ecf20Sopenharmony_ci				}
22758c2ecf20Sopenharmony_ci				mlx4_master_do_cmd(dev, slave,
22768c2ecf20Sopenharmony_ci						   comm_cmd >> 16 & 0xff,
22778c2ecf20Sopenharmony_ci						   comm_cmd & 0xffff, toggle);
22788c2ecf20Sopenharmony_ci				++served;
22798c2ecf20Sopenharmony_ci			}
22808c2ecf20Sopenharmony_ci		}
22818c2ecf20Sopenharmony_ci	}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	if (reported && reported != served)
22848c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Got command event with bitmask from %d slaves but %d were served\n",
22858c2ecf20Sopenharmony_ci			  reported, served);
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (mlx4_ARM_COMM_CHANNEL(dev))
22888c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Failed to arm comm channel events\n");
22898c2ecf20Sopenharmony_ci}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_cistatic int sync_toggles(struct mlx4_dev *dev)
22928c2ecf20Sopenharmony_ci{
22938c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
22948c2ecf20Sopenharmony_ci	u32 wr_toggle;
22958c2ecf20Sopenharmony_ci	u32 rd_toggle;
22968c2ecf20Sopenharmony_ci	unsigned long end;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write));
22998c2ecf20Sopenharmony_ci	if (wr_toggle == 0xffffffff)
23008c2ecf20Sopenharmony_ci		end = jiffies + msecs_to_jiffies(30000);
23018c2ecf20Sopenharmony_ci	else
23028c2ecf20Sopenharmony_ci		end = jiffies + msecs_to_jiffies(5000);
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	while (time_before(jiffies, end)) {
23058c2ecf20Sopenharmony_ci		rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read));
23068c2ecf20Sopenharmony_ci		if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) {
23078c2ecf20Sopenharmony_ci			/* PCI might be offline */
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci			/* If device removal has been requested,
23108c2ecf20Sopenharmony_ci			 * do not continue retrying.
23118c2ecf20Sopenharmony_ci			 */
23128c2ecf20Sopenharmony_ci			if (dev->persist->interface_state &
23138c2ecf20Sopenharmony_ci			    MLX4_INTERFACE_STATE_NOWAIT) {
23148c2ecf20Sopenharmony_ci				mlx4_warn(dev,
23158c2ecf20Sopenharmony_ci					  "communication channel is offline\n");
23168c2ecf20Sopenharmony_ci				return -EIO;
23178c2ecf20Sopenharmony_ci			}
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci			msleep(100);
23208c2ecf20Sopenharmony_ci			wr_toggle = swab32(readl(&priv->mfunc.comm->
23218c2ecf20Sopenharmony_ci					   slave_write));
23228c2ecf20Sopenharmony_ci			continue;
23238c2ecf20Sopenharmony_ci		}
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci		if (rd_toggle >> 31 == wr_toggle >> 31) {
23268c2ecf20Sopenharmony_ci			priv->cmd.comm_toggle = rd_toggle >> 31;
23278c2ecf20Sopenharmony_ci			return 0;
23288c2ecf20Sopenharmony_ci		}
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci		cond_resched();
23318c2ecf20Sopenharmony_ci	}
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	/*
23348c2ecf20Sopenharmony_ci	 * we could reach here if for example the previous VM using this
23358c2ecf20Sopenharmony_ci	 * function misbehaved and left the channel with unsynced state. We
23368c2ecf20Sopenharmony_ci	 * should fix this here and give this VM a chance to use a properly
23378c2ecf20Sopenharmony_ci	 * synced channel
23388c2ecf20Sopenharmony_ci	 */
23398c2ecf20Sopenharmony_ci	mlx4_warn(dev, "recovering from previously mis-behaved VM\n");
23408c2ecf20Sopenharmony_ci	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read);
23418c2ecf20Sopenharmony_ci	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write);
23428c2ecf20Sopenharmony_ci	priv->cmd.comm_toggle = 0;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	return 0;
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ciint mlx4_multi_func_init(struct mlx4_dev *dev)
23488c2ecf20Sopenharmony_ci{
23498c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
23508c2ecf20Sopenharmony_ci	struct mlx4_slave_state *s_state;
23518c2ecf20Sopenharmony_ci	int i, j, err, port;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	if (mlx4_is_master(dev))
23548c2ecf20Sopenharmony_ci		priv->mfunc.comm =
23558c2ecf20Sopenharmony_ci		ioremap(pci_resource_start(dev->persist->pdev,
23568c2ecf20Sopenharmony_ci					   priv->fw.comm_bar) +
23578c2ecf20Sopenharmony_ci			priv->fw.comm_base, MLX4_COMM_PAGESIZE);
23588c2ecf20Sopenharmony_ci	else
23598c2ecf20Sopenharmony_ci		priv->mfunc.comm =
23608c2ecf20Sopenharmony_ci		ioremap(pci_resource_start(dev->persist->pdev, 2) +
23618c2ecf20Sopenharmony_ci			MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE);
23628c2ecf20Sopenharmony_ci	if (!priv->mfunc.comm) {
23638c2ecf20Sopenharmony_ci		mlx4_err(dev, "Couldn't map communication vector\n");
23648c2ecf20Sopenharmony_ci		goto err_vhcr;
23658c2ecf20Sopenharmony_ci	}
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	if (mlx4_is_master(dev)) {
23688c2ecf20Sopenharmony_ci		struct mlx4_vf_oper_state *vf_oper;
23698c2ecf20Sopenharmony_ci		struct mlx4_vf_admin_state *vf_admin;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci		priv->mfunc.master.slave_state =
23728c2ecf20Sopenharmony_ci			kcalloc(dev->num_slaves,
23738c2ecf20Sopenharmony_ci				sizeof(struct mlx4_slave_state),
23748c2ecf20Sopenharmony_ci				GFP_KERNEL);
23758c2ecf20Sopenharmony_ci		if (!priv->mfunc.master.slave_state)
23768c2ecf20Sopenharmony_ci			goto err_comm;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci		priv->mfunc.master.vf_admin =
23798c2ecf20Sopenharmony_ci			kcalloc(dev->num_slaves,
23808c2ecf20Sopenharmony_ci				sizeof(struct mlx4_vf_admin_state),
23818c2ecf20Sopenharmony_ci				GFP_KERNEL);
23828c2ecf20Sopenharmony_ci		if (!priv->mfunc.master.vf_admin)
23838c2ecf20Sopenharmony_ci			goto err_comm_admin;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci		priv->mfunc.master.vf_oper =
23868c2ecf20Sopenharmony_ci			kcalloc(dev->num_slaves,
23878c2ecf20Sopenharmony_ci				sizeof(struct mlx4_vf_oper_state),
23888c2ecf20Sopenharmony_ci				GFP_KERNEL);
23898c2ecf20Sopenharmony_ci		if (!priv->mfunc.master.vf_oper)
23908c2ecf20Sopenharmony_ci			goto err_comm_oper;
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci		for (i = 0; i < dev->num_slaves; ++i) {
23938c2ecf20Sopenharmony_ci			vf_admin = &priv->mfunc.master.vf_admin[i];
23948c2ecf20Sopenharmony_ci			vf_oper = &priv->mfunc.master.vf_oper[i];
23958c2ecf20Sopenharmony_ci			s_state = &priv->mfunc.master.slave_state[i];
23968c2ecf20Sopenharmony_ci			s_state->last_cmd = MLX4_COMM_CMD_RESET;
23978c2ecf20Sopenharmony_ci			s_state->vst_qinq_supported = false;
23988c2ecf20Sopenharmony_ci			mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
23998c2ecf20Sopenharmony_ci			for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
24008c2ecf20Sopenharmony_ci				s_state->event_eq[j].eqn = -1;
24018c2ecf20Sopenharmony_ci			__raw_writel((__force u32) 0,
24028c2ecf20Sopenharmony_ci				     &priv->mfunc.comm[i].slave_write);
24038c2ecf20Sopenharmony_ci			__raw_writel((__force u32) 0,
24048c2ecf20Sopenharmony_ci				     &priv->mfunc.comm[i].slave_read);
24058c2ecf20Sopenharmony_ci			for (port = 1; port <= MLX4_MAX_PORTS; port++) {
24068c2ecf20Sopenharmony_ci				struct mlx4_vport_state *admin_vport;
24078c2ecf20Sopenharmony_ci				struct mlx4_vport_state *oper_vport;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci				s_state->vlan_filter[port] =
24108c2ecf20Sopenharmony_ci					kzalloc(sizeof(struct mlx4_vlan_fltr),
24118c2ecf20Sopenharmony_ci						GFP_KERNEL);
24128c2ecf20Sopenharmony_ci				if (!s_state->vlan_filter[port]) {
24138c2ecf20Sopenharmony_ci					if (--port)
24148c2ecf20Sopenharmony_ci						kfree(s_state->vlan_filter[port]);
24158c2ecf20Sopenharmony_ci					goto err_slaves;
24168c2ecf20Sopenharmony_ci				}
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci				admin_vport = &vf_admin->vport[port];
24198c2ecf20Sopenharmony_ci				oper_vport = &vf_oper->vport[port].state;
24208c2ecf20Sopenharmony_ci				INIT_LIST_HEAD(&s_state->mcast_filters[port]);
24218c2ecf20Sopenharmony_ci				admin_vport->default_vlan = MLX4_VGT;
24228c2ecf20Sopenharmony_ci				oper_vport->default_vlan = MLX4_VGT;
24238c2ecf20Sopenharmony_ci				admin_vport->qos_vport =
24248c2ecf20Sopenharmony_ci						MLX4_VPP_DEFAULT_VPORT;
24258c2ecf20Sopenharmony_ci				oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT;
24268c2ecf20Sopenharmony_ci				admin_vport->vlan_proto = htons(ETH_P_8021Q);
24278c2ecf20Sopenharmony_ci				oper_vport->vlan_proto = htons(ETH_P_8021Q);
24288c2ecf20Sopenharmony_ci				vf_oper->vport[port].vlan_idx = NO_INDX;
24298c2ecf20Sopenharmony_ci				vf_oper->vport[port].mac_idx = NO_INDX;
24308c2ecf20Sopenharmony_ci				mlx4_set_random_admin_guid(dev, i, port);
24318c2ecf20Sopenharmony_ci			}
24328c2ecf20Sopenharmony_ci			spin_lock_init(&s_state->lock);
24338c2ecf20Sopenharmony_ci		}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) {
24368c2ecf20Sopenharmony_ci			for (port = 1; port <= dev->caps.num_ports; port++) {
24378c2ecf20Sopenharmony_ci				if (mlx4_is_eth(dev, port)) {
24388c2ecf20Sopenharmony_ci					mlx4_set_default_port_qos(dev, port);
24398c2ecf20Sopenharmony_ci					mlx4_allocate_port_vpps(dev, port);
24408c2ecf20Sopenharmony_ci				}
24418c2ecf20Sopenharmony_ci			}
24428c2ecf20Sopenharmony_ci		}
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci		memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe));
24458c2ecf20Sopenharmony_ci		priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD;
24468c2ecf20Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.comm_work,
24478c2ecf20Sopenharmony_ci			  mlx4_master_comm_channel);
24488c2ecf20Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.slave_event_work,
24498c2ecf20Sopenharmony_ci			  mlx4_gen_slave_eqe);
24508c2ecf20Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.slave_flr_event_work,
24518c2ecf20Sopenharmony_ci			  mlx4_master_handle_slave_flr);
24528c2ecf20Sopenharmony_ci		spin_lock_init(&priv->mfunc.master.slave_state_lock);
24538c2ecf20Sopenharmony_ci		spin_lock_init(&priv->mfunc.master.slave_eq.event_lock);
24548c2ecf20Sopenharmony_ci		priv->mfunc.master.comm_wq =
24558c2ecf20Sopenharmony_ci			create_singlethread_workqueue("mlx4_comm");
24568c2ecf20Sopenharmony_ci		if (!priv->mfunc.master.comm_wq)
24578c2ecf20Sopenharmony_ci			goto err_slaves;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci		if (mlx4_init_resource_tracker(dev))
24608c2ecf20Sopenharmony_ci			goto err_thread;
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	} else {
24638c2ecf20Sopenharmony_ci		err = sync_toggles(dev);
24648c2ecf20Sopenharmony_ci		if (err) {
24658c2ecf20Sopenharmony_ci			mlx4_err(dev, "Couldn't sync toggles\n");
24668c2ecf20Sopenharmony_ci			goto err_comm;
24678c2ecf20Sopenharmony_ci		}
24688c2ecf20Sopenharmony_ci	}
24698c2ecf20Sopenharmony_ci	return 0;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_cierr_thread:
24728c2ecf20Sopenharmony_ci	flush_workqueue(priv->mfunc.master.comm_wq);
24738c2ecf20Sopenharmony_ci	destroy_workqueue(priv->mfunc.master.comm_wq);
24748c2ecf20Sopenharmony_cierr_slaves:
24758c2ecf20Sopenharmony_ci	while (i--) {
24768c2ecf20Sopenharmony_ci		for (port = 1; port <= MLX4_MAX_PORTS; port++)
24778c2ecf20Sopenharmony_ci			kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
24788c2ecf20Sopenharmony_ci	}
24798c2ecf20Sopenharmony_ci	kfree(priv->mfunc.master.vf_oper);
24808c2ecf20Sopenharmony_cierr_comm_oper:
24818c2ecf20Sopenharmony_ci	kfree(priv->mfunc.master.vf_admin);
24828c2ecf20Sopenharmony_cierr_comm_admin:
24838c2ecf20Sopenharmony_ci	kfree(priv->mfunc.master.slave_state);
24848c2ecf20Sopenharmony_cierr_comm:
24858c2ecf20Sopenharmony_ci	iounmap(priv->mfunc.comm);
24868c2ecf20Sopenharmony_ci	priv->mfunc.comm = NULL;
24878c2ecf20Sopenharmony_cierr_vhcr:
24888c2ecf20Sopenharmony_ci	dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
24898c2ecf20Sopenharmony_ci			  priv->mfunc.vhcr,
24908c2ecf20Sopenharmony_ci			  priv->mfunc.vhcr_dma);
24918c2ecf20Sopenharmony_ci	priv->mfunc.vhcr = NULL;
24928c2ecf20Sopenharmony_ci	return -ENOMEM;
24938c2ecf20Sopenharmony_ci}
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ciint mlx4_cmd_init(struct mlx4_dev *dev)
24968c2ecf20Sopenharmony_ci{
24978c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
24988c2ecf20Sopenharmony_ci	int flags = 0;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	if (!priv->cmd.initialized) {
25018c2ecf20Sopenharmony_ci		init_rwsem(&priv->cmd.switch_sem);
25028c2ecf20Sopenharmony_ci		mutex_init(&priv->cmd.slave_cmd_mutex);
25038c2ecf20Sopenharmony_ci		sema_init(&priv->cmd.poll_sem, 1);
25048c2ecf20Sopenharmony_ci		priv->cmd.use_events = 0;
25058c2ecf20Sopenharmony_ci		priv->cmd.toggle     = 1;
25068c2ecf20Sopenharmony_ci		priv->cmd.initialized = 1;
25078c2ecf20Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_STRUCT;
25088c2ecf20Sopenharmony_ci	}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	if (!mlx4_is_slave(dev) && !priv->cmd.hcr) {
25118c2ecf20Sopenharmony_ci		priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev,
25128c2ecf20Sopenharmony_ci					0) + MLX4_HCR_BASE, MLX4_HCR_SIZE);
25138c2ecf20Sopenharmony_ci		if (!priv->cmd.hcr) {
25148c2ecf20Sopenharmony_ci			mlx4_err(dev, "Couldn't map command register\n");
25158c2ecf20Sopenharmony_ci			goto err;
25168c2ecf20Sopenharmony_ci		}
25178c2ecf20Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_HCR;
25188c2ecf20Sopenharmony_ci	}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) {
25218c2ecf20Sopenharmony_ci		priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev,
25228c2ecf20Sopenharmony_ci						      PAGE_SIZE,
25238c2ecf20Sopenharmony_ci						      &priv->mfunc.vhcr_dma,
25248c2ecf20Sopenharmony_ci						      GFP_KERNEL);
25258c2ecf20Sopenharmony_ci		if (!priv->mfunc.vhcr)
25268c2ecf20Sopenharmony_ci			goto err;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_VHCR;
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	if (!priv->cmd.pool) {
25328c2ecf20Sopenharmony_ci		priv->cmd.pool = dma_pool_create("mlx4_cmd",
25338c2ecf20Sopenharmony_ci						 &dev->persist->pdev->dev,
25348c2ecf20Sopenharmony_ci						 MLX4_MAILBOX_SIZE,
25358c2ecf20Sopenharmony_ci						 MLX4_MAILBOX_SIZE, 0);
25368c2ecf20Sopenharmony_ci		if (!priv->cmd.pool)
25378c2ecf20Sopenharmony_ci			goto err;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_POOL;
25408c2ecf20Sopenharmony_ci	}
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	return 0;
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cierr:
25458c2ecf20Sopenharmony_ci	mlx4_cmd_cleanup(dev, flags);
25468c2ecf20Sopenharmony_ci	return -ENOMEM;
25478c2ecf20Sopenharmony_ci}
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_civoid mlx4_report_internal_err_comm_event(struct mlx4_dev *dev)
25508c2ecf20Sopenharmony_ci{
25518c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
25528c2ecf20Sopenharmony_ci	int slave;
25538c2ecf20Sopenharmony_ci	u32 slave_read;
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	/* If the comm channel has not yet been initialized,
25568c2ecf20Sopenharmony_ci	 * skip reporting the internal error event to all
25578c2ecf20Sopenharmony_ci	 * the communication channels.
25588c2ecf20Sopenharmony_ci	 */
25598c2ecf20Sopenharmony_ci	if (!priv->mfunc.comm)
25608c2ecf20Sopenharmony_ci		return;
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	/* Report an internal error event to all
25638c2ecf20Sopenharmony_ci	 * communication channels.
25648c2ecf20Sopenharmony_ci	 */
25658c2ecf20Sopenharmony_ci	for (slave = 0; slave < dev->num_slaves; slave++) {
25668c2ecf20Sopenharmony_ci		slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read));
25678c2ecf20Sopenharmony_ci		slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR;
25688c2ecf20Sopenharmony_ci		__raw_writel((__force u32)cpu_to_be32(slave_read),
25698c2ecf20Sopenharmony_ci			     &priv->mfunc.comm[slave].slave_read);
25708c2ecf20Sopenharmony_ci	}
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_civoid mlx4_multi_func_cleanup(struct mlx4_dev *dev)
25748c2ecf20Sopenharmony_ci{
25758c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
25768c2ecf20Sopenharmony_ci	int i, port;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	if (mlx4_is_master(dev)) {
25798c2ecf20Sopenharmony_ci		flush_workqueue(priv->mfunc.master.comm_wq);
25808c2ecf20Sopenharmony_ci		destroy_workqueue(priv->mfunc.master.comm_wq);
25818c2ecf20Sopenharmony_ci		for (i = 0; i < dev->num_slaves; i++) {
25828c2ecf20Sopenharmony_ci			for (port = 1; port <= MLX4_MAX_PORTS; port++)
25838c2ecf20Sopenharmony_ci				kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
25848c2ecf20Sopenharmony_ci		}
25858c2ecf20Sopenharmony_ci		kfree(priv->mfunc.master.slave_state);
25868c2ecf20Sopenharmony_ci		kfree(priv->mfunc.master.vf_admin);
25878c2ecf20Sopenharmony_ci		kfree(priv->mfunc.master.vf_oper);
25888c2ecf20Sopenharmony_ci		dev->num_slaves = 0;
25898c2ecf20Sopenharmony_ci	}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	iounmap(priv->mfunc.comm);
25928c2ecf20Sopenharmony_ci	priv->mfunc.comm = NULL;
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_civoid mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
25968c2ecf20Sopenharmony_ci{
25978c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	if (priv->cmd.pool && (cleanup_mask & MLX4_CMD_CLEANUP_POOL)) {
26008c2ecf20Sopenharmony_ci		dma_pool_destroy(priv->cmd.pool);
26018c2ecf20Sopenharmony_ci		priv->cmd.pool = NULL;
26028c2ecf20Sopenharmony_ci	}
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	if (!mlx4_is_slave(dev) && priv->cmd.hcr &&
26058c2ecf20Sopenharmony_ci	    (cleanup_mask & MLX4_CMD_CLEANUP_HCR)) {
26068c2ecf20Sopenharmony_ci		iounmap(priv->cmd.hcr);
26078c2ecf20Sopenharmony_ci		priv->cmd.hcr = NULL;
26088c2ecf20Sopenharmony_ci	}
26098c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr &&
26108c2ecf20Sopenharmony_ci	    (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) {
26118c2ecf20Sopenharmony_ci		dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
26128c2ecf20Sopenharmony_ci				  priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
26138c2ecf20Sopenharmony_ci		priv->mfunc.vhcr = NULL;
26148c2ecf20Sopenharmony_ci	}
26158c2ecf20Sopenharmony_ci	if (priv->cmd.initialized && (cleanup_mask & MLX4_CMD_CLEANUP_STRUCT))
26168c2ecf20Sopenharmony_ci		priv->cmd.initialized = 0;
26178c2ecf20Sopenharmony_ci}
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci/*
26208c2ecf20Sopenharmony_ci * Switch to using events to issue FW commands (can only be called
26218c2ecf20Sopenharmony_ci * after event queue for command events has been initialized).
26228c2ecf20Sopenharmony_ci */
26238c2ecf20Sopenharmony_ciint mlx4_cmd_use_events(struct mlx4_dev *dev)
26248c2ecf20Sopenharmony_ci{
26258c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
26268c2ecf20Sopenharmony_ci	int i;
26278c2ecf20Sopenharmony_ci	int err = 0;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	priv->cmd.context = kmalloc_array(priv->cmd.max_cmds,
26308c2ecf20Sopenharmony_ci					  sizeof(struct mlx4_cmd_context),
26318c2ecf20Sopenharmony_ci					  GFP_KERNEL);
26328c2ecf20Sopenharmony_ci	if (!priv->cmd.context)
26338c2ecf20Sopenharmony_ci		return -ENOMEM;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
26368c2ecf20Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
26378c2ecf20Sopenharmony_ci	down_write(&priv->cmd.switch_sem);
26388c2ecf20Sopenharmony_ci	for (i = 0; i < priv->cmd.max_cmds; ++i) {
26398c2ecf20Sopenharmony_ci		priv->cmd.context[i].token = i;
26408c2ecf20Sopenharmony_ci		priv->cmd.context[i].next  = i + 1;
26418c2ecf20Sopenharmony_ci		/* To support fatal error flow, initialize all
26428c2ecf20Sopenharmony_ci		 * cmd contexts to allow simulating completions
26438c2ecf20Sopenharmony_ci		 * with complete() at any time.
26448c2ecf20Sopenharmony_ci		 */
26458c2ecf20Sopenharmony_ci		init_completion(&priv->cmd.context[i].done);
26468c2ecf20Sopenharmony_ci	}
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
26498c2ecf20Sopenharmony_ci	priv->cmd.free_head = 0;
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci	sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	for (priv->cmd.token_mask = 1;
26548c2ecf20Sopenharmony_ci	     priv->cmd.token_mask < priv->cmd.max_cmds;
26558c2ecf20Sopenharmony_ci	     priv->cmd.token_mask <<= 1)
26568c2ecf20Sopenharmony_ci		; /* nothing */
26578c2ecf20Sopenharmony_ci	--priv->cmd.token_mask;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	down(&priv->cmd.poll_sem);
26608c2ecf20Sopenharmony_ci	priv->cmd.use_events = 1;
26618c2ecf20Sopenharmony_ci	up_write(&priv->cmd.switch_sem);
26628c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
26638c2ecf20Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	return err;
26668c2ecf20Sopenharmony_ci}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci/*
26698c2ecf20Sopenharmony_ci * Switch back to polling (used when shutting down the device)
26708c2ecf20Sopenharmony_ci */
26718c2ecf20Sopenharmony_civoid mlx4_cmd_use_polling(struct mlx4_dev *dev)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
26748c2ecf20Sopenharmony_ci	int i;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
26778c2ecf20Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
26788c2ecf20Sopenharmony_ci	down_write(&priv->cmd.switch_sem);
26798c2ecf20Sopenharmony_ci	priv->cmd.use_events = 0;
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ci	for (i = 0; i < priv->cmd.max_cmds; ++i)
26828c2ecf20Sopenharmony_ci		down(&priv->cmd.event_sem);
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	kfree(priv->cmd.context);
26858c2ecf20Sopenharmony_ci	priv->cmd.context = NULL;
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	up(&priv->cmd.poll_sem);
26888c2ecf20Sopenharmony_ci	up_write(&priv->cmd.switch_sem);
26898c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
26908c2ecf20Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
26918c2ecf20Sopenharmony_ci}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_cistruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
26948c2ecf20Sopenharmony_ci{
26958c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL);
26988c2ecf20Sopenharmony_ci	if (!mailbox)
26998c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	mailbox->buf = dma_pool_zalloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL,
27028c2ecf20Sopenharmony_ci				       &mailbox->dma);
27038c2ecf20Sopenharmony_ci	if (!mailbox->buf) {
27048c2ecf20Sopenharmony_ci		kfree(mailbox);
27058c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
27068c2ecf20Sopenharmony_ci	}
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	return mailbox;
27098c2ecf20Sopenharmony_ci}
27108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_civoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev,
27138c2ecf20Sopenharmony_ci			   struct mlx4_cmd_mailbox *mailbox)
27148c2ecf20Sopenharmony_ci{
27158c2ecf20Sopenharmony_ci	if (!mailbox)
27168c2ecf20Sopenharmony_ci		return;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	dma_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma);
27198c2ecf20Sopenharmony_ci	kfree(mailbox);
27208c2ecf20Sopenharmony_ci}
27218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ciu32 mlx4_comm_get_version(void)
27248c2ecf20Sopenharmony_ci{
27258c2ecf20Sopenharmony_ci	 return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
27268c2ecf20Sopenharmony_ci}
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_cistatic int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
27298c2ecf20Sopenharmony_ci{
27308c2ecf20Sopenharmony_ci	if ((vf < 0) || (vf >= dev->persist->num_vfs)) {
27318c2ecf20Sopenharmony_ci		mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n",
27328c2ecf20Sopenharmony_ci			 vf, dev->persist->num_vfs);
27338c2ecf20Sopenharmony_ci		return -EINVAL;
27348c2ecf20Sopenharmony_ci	}
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	return vf+1;
27378c2ecf20Sopenharmony_ci}
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ciint mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
27408c2ecf20Sopenharmony_ci{
27418c2ecf20Sopenharmony_ci	if (slave < 1 || slave > dev->persist->num_vfs) {
27428c2ecf20Sopenharmony_ci		mlx4_err(dev,
27438c2ecf20Sopenharmony_ci			 "Bad slave number:%d (number of activated slaves: %lu)\n",
27448c2ecf20Sopenharmony_ci			 slave, dev->num_slaves);
27458c2ecf20Sopenharmony_ci		return -EINVAL;
27468c2ecf20Sopenharmony_ci	}
27478c2ecf20Sopenharmony_ci	return slave - 1;
27488c2ecf20Sopenharmony_ci}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_civoid mlx4_cmd_wake_completions(struct mlx4_dev *dev)
27518c2ecf20Sopenharmony_ci{
27528c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
27538c2ecf20Sopenharmony_ci	struct mlx4_cmd_context *context;
27548c2ecf20Sopenharmony_ci	int i;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	spin_lock(&priv->cmd.context_lock);
27578c2ecf20Sopenharmony_ci	if (priv->cmd.context) {
27588c2ecf20Sopenharmony_ci		for (i = 0; i < priv->cmd.max_cmds; ++i) {
27598c2ecf20Sopenharmony_ci			context = &priv->cmd.context[i];
27608c2ecf20Sopenharmony_ci			context->fw_status = CMD_STAT_INTERNAL_ERR;
27618c2ecf20Sopenharmony_ci			context->result    =
27628c2ecf20Sopenharmony_ci				mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
27638c2ecf20Sopenharmony_ci			complete(&context->done);
27648c2ecf20Sopenharmony_ci		}
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci	spin_unlock(&priv->cmd.context_lock);
27678c2ecf20Sopenharmony_ci}
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_cistruct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave)
27708c2ecf20Sopenharmony_ci{
27718c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports;
27728c2ecf20Sopenharmony_ci	int vf;
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	if (slave == 0) {
27778c2ecf20Sopenharmony_ci		bitmap_fill(actv_ports.ports, dev->caps.num_ports);
27788c2ecf20Sopenharmony_ci		return actv_ports;
27798c2ecf20Sopenharmony_ci	}
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	vf = mlx4_get_vf_indx(dev, slave);
27828c2ecf20Sopenharmony_ci	if (vf < 0)
27838c2ecf20Sopenharmony_ci		return actv_ports;
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1,
27868c2ecf20Sopenharmony_ci		   min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports,
27878c2ecf20Sopenharmony_ci		   dev->caps.num_ports));
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci	return actv_ports;
27908c2ecf20Sopenharmony_ci}
27918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_active_ports);
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ciint mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port)
27948c2ecf20Sopenharmony_ci{
27958c2ecf20Sopenharmony_ci	unsigned n;
27968c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
27978c2ecf20Sopenharmony_ci	unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	if (port <= 0 || port > m)
28008c2ecf20Sopenharmony_ci		return -EINVAL;
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	n = find_first_bit(actv_ports.ports, dev->caps.num_ports);
28038c2ecf20Sopenharmony_ci	if (port <= n)
28048c2ecf20Sopenharmony_ci		port = n + 1;
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	return port;
28078c2ecf20Sopenharmony_ci}
28088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_slave_convert_port);
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ciint mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port)
28118c2ecf20Sopenharmony_ci{
28128c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
28138c2ecf20Sopenharmony_ci	if (test_bit(port - 1, actv_ports.ports))
28148c2ecf20Sopenharmony_ci		return port -
28158c2ecf20Sopenharmony_ci			find_first_bit(actv_ports.ports, dev->caps.num_ports);
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	return -1;
28188c2ecf20Sopenharmony_ci}
28198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port);
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
28228c2ecf20Sopenharmony_ci						   int port)
28238c2ecf20Sopenharmony_ci{
28248c2ecf20Sopenharmony_ci	unsigned i;
28258c2ecf20Sopenharmony_ci	struct mlx4_slaves_pport slaves_pport;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	if (port <= 0 || port > dev->caps.num_ports)
28308c2ecf20Sopenharmony_ci		return slaves_pport;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	for (i = 0; i < dev->persist->num_vfs + 1; i++) {
28338c2ecf20Sopenharmony_ci		struct mlx4_active_ports actv_ports =
28348c2ecf20Sopenharmony_ci			mlx4_get_active_ports(dev, i);
28358c2ecf20Sopenharmony_ci		if (test_bit(port - 1, actv_ports.ports))
28368c2ecf20Sopenharmony_ci			set_bit(i, slaves_pport.slaves);
28378c2ecf20Sopenharmony_ci	}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	return slaves_pport;
28408c2ecf20Sopenharmony_ci}
28418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
28448c2ecf20Sopenharmony_ci		struct mlx4_dev *dev,
28458c2ecf20Sopenharmony_ci		const struct mlx4_active_ports *crit_ports)
28468c2ecf20Sopenharmony_ci{
28478c2ecf20Sopenharmony_ci	unsigned i;
28488c2ecf20Sopenharmony_ci	struct mlx4_slaves_pport slaves_pport;
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	for (i = 0; i < dev->persist->num_vfs + 1; i++) {
28538c2ecf20Sopenharmony_ci		struct mlx4_active_ports actv_ports =
28548c2ecf20Sopenharmony_ci			mlx4_get_active_ports(dev, i);
28558c2ecf20Sopenharmony_ci		if (bitmap_equal(crit_ports->ports, actv_ports.ports,
28568c2ecf20Sopenharmony_ci				 dev->caps.num_ports))
28578c2ecf20Sopenharmony_ci			set_bit(i, slaves_pport.slaves);
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	return slaves_pport;
28618c2ecf20Sopenharmony_ci}
28628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv);
28638c2ecf20Sopenharmony_ci
28648c2ecf20Sopenharmony_cistatic int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port)
28658c2ecf20Sopenharmony_ci{
28668c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
28678c2ecf20Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports, dev->caps.num_ports)
28688c2ecf20Sopenharmony_ci			+ 1;
28698c2ecf20Sopenharmony_ci	int max_port = min_port +
28708c2ecf20Sopenharmony_ci		bitmap_weight(actv_ports.ports, dev->caps.num_ports);
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	if (port < min_port)
28738c2ecf20Sopenharmony_ci		port = min_port;
28748c2ecf20Sopenharmony_ci	else if (port >= max_port)
28758c2ecf20Sopenharmony_ci		port = max_port - 1;
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	return port;
28788c2ecf20Sopenharmony_ci}
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_cistatic int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port,
28818c2ecf20Sopenharmony_ci			      int max_tx_rate)
28828c2ecf20Sopenharmony_ci{
28838c2ecf20Sopenharmony_ci	int i;
28848c2ecf20Sopenharmony_ci	int err;
28858c2ecf20Sopenharmony_ci	struct mlx4_qos_manager *port_qos;
28868c2ecf20Sopenharmony_ci	struct mlx4_dev *dev = &priv->dev;
28878c2ecf20Sopenharmony_ci	struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP];
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	port_qos = &priv->mfunc.master.qos_ctl[port];
28908c2ecf20Sopenharmony_ci	memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP);
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	if (slave > port_qos->num_of_qos_vfs) {
28938c2ecf20Sopenharmony_ci		mlx4_info(dev, "No available VPP resources for this VF\n");
28948c2ecf20Sopenharmony_ci		return -EINVAL;
28958c2ecf20Sopenharmony_ci	}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci	/* Query for default QoS values from Vport 0 is needed */
28988c2ecf20Sopenharmony_ci	err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos);
28998c2ecf20Sopenharmony_ci	if (err) {
29008c2ecf20Sopenharmony_ci		mlx4_info(dev, "Failed to query Vport 0 QoS values\n");
29018c2ecf20Sopenharmony_ci		return err;
29028c2ecf20Sopenharmony_ci	}
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++) {
29058c2ecf20Sopenharmony_ci		if (test_bit(i, port_qos->priority_bm) && max_tx_rate) {
29068c2ecf20Sopenharmony_ci			vpp_qos[i].max_avg_bw = max_tx_rate;
29078c2ecf20Sopenharmony_ci			vpp_qos[i].enable = 1;
29088c2ecf20Sopenharmony_ci		} else {
29098c2ecf20Sopenharmony_ci			/* if user supplied tx_rate == 0, meaning no rate limit
29108c2ecf20Sopenharmony_ci			 * configuration is required. so we are leaving the
29118c2ecf20Sopenharmony_ci			 * value of max_avg_bw as queried from Vport 0.
29128c2ecf20Sopenharmony_ci			 */
29138c2ecf20Sopenharmony_ci			vpp_qos[i].enable = 0;
29148c2ecf20Sopenharmony_ci		}
29158c2ecf20Sopenharmony_ci	}
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos);
29188c2ecf20Sopenharmony_ci	if (err) {
29198c2ecf20Sopenharmony_ci		mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave);
29208c2ecf20Sopenharmony_ci		return err;
29218c2ecf20Sopenharmony_ci	}
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	return 0;
29248c2ecf20Sopenharmony_ci}
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_cistatic bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port,
29278c2ecf20Sopenharmony_ci					struct mlx4_vport_state *vf_admin)
29288c2ecf20Sopenharmony_ci{
29298c2ecf20Sopenharmony_ci	struct mlx4_qos_manager *info;
29308c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	if (!mlx4_is_master(dev) ||
29338c2ecf20Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
29348c2ecf20Sopenharmony_ci		return false;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	info = &priv->mfunc.master.qos_ctl[port];
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	if (vf_admin->default_vlan != MLX4_VGT &&
29398c2ecf20Sopenharmony_ci	    test_bit(vf_admin->default_qos, info->priority_bm))
29408c2ecf20Sopenharmony_ci		return true;
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci	return false;
29438c2ecf20Sopenharmony_ci}
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_cistatic bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port,
29468c2ecf20Sopenharmony_ci				       struct mlx4_vport_state *vf_admin,
29478c2ecf20Sopenharmony_ci				       int vlan, int qos)
29488c2ecf20Sopenharmony_ci{
29498c2ecf20Sopenharmony_ci	struct mlx4_vport_state dummy_admin = {0};
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) ||
29528c2ecf20Sopenharmony_ci	    !vf_admin->tx_rate)
29538c2ecf20Sopenharmony_ci		return true;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci	dummy_admin.default_qos = qos;
29568c2ecf20Sopenharmony_ci	dummy_admin.default_vlan = vlan;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	/* VF wants to move to other VST state which is valid with current
29598c2ecf20Sopenharmony_ci	 * rate limit. Either differnt default vlan in VST or other
29608c2ecf20Sopenharmony_ci	 * supported QoS priority. Otherwise we don't allow this change when
29618c2ecf20Sopenharmony_ci	 * the TX rate is still configured.
29628c2ecf20Sopenharmony_ci	 */
29638c2ecf20Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin))
29648c2ecf20Sopenharmony_ci		return true;
29658c2ecf20Sopenharmony_ci
29668c2ecf20Sopenharmony_ci	mlx4_info(dev, "Cannot change VF state to %s while rate is set\n",
29678c2ecf20Sopenharmony_ci		  (vlan == MLX4_VGT) ? "VGT" : "VST");
29688c2ecf20Sopenharmony_ci
29698c2ecf20Sopenharmony_ci	if (vlan != MLX4_VGT)
29708c2ecf20Sopenharmony_ci		mlx4_info(dev, "VST priority %d not supported for QoS\n", qos);
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci	mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n");
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	return false;
29758c2ecf20Sopenharmony_ci}
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ciint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac)
29788c2ecf20Sopenharmony_ci{
29798c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
29808c2ecf20Sopenharmony_ci	struct mlx4_vport_state *s_info;
29818c2ecf20Sopenharmony_ci	int slave;
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci	if (!mlx4_is_master(dev))
29848c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	if (is_multicast_ether_addr(mac))
29878c2ecf20Sopenharmony_ci		return -EINVAL;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
29908c2ecf20Sopenharmony_ci	if (slave < 0)
29918c2ecf20Sopenharmony_ci		return -EINVAL;
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
29948c2ecf20Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	if (s_info->spoofchk && is_zero_ether_addr(mac)) {
29978c2ecf20Sopenharmony_ci		mlx4_info(dev, "MAC invalidation is not allowed when spoofchk is on\n");
29988c2ecf20Sopenharmony_ci		return -EPERM;
29998c2ecf20Sopenharmony_ci	}
30008c2ecf20Sopenharmony_ci
30018c2ecf20Sopenharmony_ci	s_info->mac = mlx4_mac_to_u64(mac);
30028c2ecf20Sopenharmony_ci	mlx4_info(dev, "default mac on vf %d port %d to %llX will take effect only after vf restart\n",
30038c2ecf20Sopenharmony_ci		  vf, port, s_info->mac);
30048c2ecf20Sopenharmony_ci	return 0;
30058c2ecf20Sopenharmony_ci}
30068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
30078c2ecf20Sopenharmony_ci
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ciint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos,
30108c2ecf20Sopenharmony_ci		     __be16 proto)
30118c2ecf20Sopenharmony_ci{
30128c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
30138c2ecf20Sopenharmony_ci	struct mlx4_vport_state *vf_admin;
30148c2ecf20Sopenharmony_ci	struct mlx4_slave_state *slave_state;
30158c2ecf20Sopenharmony_ci	struct mlx4_vport_oper_state *vf_oper;
30168c2ecf20Sopenharmony_ci	int slave;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	if ((!mlx4_is_master(dev)) ||
30198c2ecf20Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
30208c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	if ((vlan > 4095) || (qos > 7))
30238c2ecf20Sopenharmony_ci		return -EINVAL;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (proto == htons(ETH_P_8021AD) &&
30268c2ecf20Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP))
30278c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci	if (proto != htons(ETH_P_8021Q) &&
30308c2ecf20Sopenharmony_ci	    proto != htons(ETH_P_8021AD))
30318c2ecf20Sopenharmony_ci		return -EINVAL;
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD)) &&
30348c2ecf20Sopenharmony_ci	    ((vlan == 0) || (vlan == MLX4_VGT)))
30358c2ecf20Sopenharmony_ci		return -EINVAL;
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
30388c2ecf20Sopenharmony_ci	if (slave < 0)
30398c2ecf20Sopenharmony_ci		return -EINVAL;
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci	slave_state = &priv->mfunc.master.slave_state[slave];
30428c2ecf20Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD)) && (slave_state->active) &&
30438c2ecf20Sopenharmony_ci	    (!slave_state->vst_qinq_supported)) {
30448c2ecf20Sopenharmony_ci		mlx4_err(dev, "vf %d does not support VST QinQ mode\n", vf);
30458c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
30468c2ecf20Sopenharmony_ci	}
30478c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
30488c2ecf20Sopenharmony_ci	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
30498c2ecf20Sopenharmony_ci	vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci	if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos))
30528c2ecf20Sopenharmony_ci		return -EPERM;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	if ((0 == vlan) && (0 == qos))
30558c2ecf20Sopenharmony_ci		vf_admin->default_vlan = MLX4_VGT;
30568c2ecf20Sopenharmony_ci	else
30578c2ecf20Sopenharmony_ci		vf_admin->default_vlan = vlan;
30588c2ecf20Sopenharmony_ci	vf_admin->default_qos = qos;
30598c2ecf20Sopenharmony_ci	vf_admin->vlan_proto = proto;
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci	/* If rate was configured prior to VST, we saved the configured rate
30628c2ecf20Sopenharmony_ci	 * in vf_admin->rate and now, if priority supported we enforce the QoS
30638c2ecf20Sopenharmony_ci	 */
30648c2ecf20Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) &&
30658c2ecf20Sopenharmony_ci	    vf_admin->tx_rate)
30668c2ecf20Sopenharmony_ci		vf_admin->qos_vport = slave;
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci	/* Try to activate new vf state without restart,
30698c2ecf20Sopenharmony_ci	 * this option is not supported while moving to VST QinQ mode.
30708c2ecf20Sopenharmony_ci	 */
30718c2ecf20Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD) &&
30728c2ecf20Sopenharmony_ci	     vf_oper->state.vlan_proto != proto) ||
30738c2ecf20Sopenharmony_ci	    mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
30748c2ecf20Sopenharmony_ci		mlx4_info(dev,
30758c2ecf20Sopenharmony_ci			  "updating vf %d port %d config will take effect on next VF restart\n",
30768c2ecf20Sopenharmony_ci			  vf, port);
30778c2ecf20Sopenharmony_ci	return 0;
30788c2ecf20Sopenharmony_ci}
30798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
30808c2ecf20Sopenharmony_ci
30818c2ecf20Sopenharmony_ciint mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate,
30828c2ecf20Sopenharmony_ci		     int max_tx_rate)
30838c2ecf20Sopenharmony_ci{
30848c2ecf20Sopenharmony_ci	int err;
30858c2ecf20Sopenharmony_ci	int slave;
30868c2ecf20Sopenharmony_ci	struct mlx4_vport_state *vf_admin;
30878c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	if (!mlx4_is_master(dev) ||
30908c2ecf20Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
30918c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	if (min_tx_rate) {
30948c2ecf20Sopenharmony_ci		mlx4_info(dev, "Minimum BW share not supported\n");
30958c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
30968c2ecf20Sopenharmony_ci	}
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
30998c2ecf20Sopenharmony_ci	if (slave < 0)
31008c2ecf20Sopenharmony_ci		return -EINVAL;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
31038c2ecf20Sopenharmony_ci	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate);
31068c2ecf20Sopenharmony_ci	if (err) {
31078c2ecf20Sopenharmony_ci		mlx4_info(dev, "vf %d failed to set rate %d\n", vf,
31088c2ecf20Sopenharmony_ci			  max_tx_rate);
31098c2ecf20Sopenharmony_ci		return err;
31108c2ecf20Sopenharmony_ci	}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	vf_admin->tx_rate = max_tx_rate;
31138c2ecf20Sopenharmony_ci	/* if VF is not in supported mode (VST with supported prio),
31148c2ecf20Sopenharmony_ci	 * we do not change vport configuration for its QPs, but save
31158c2ecf20Sopenharmony_ci	 * the rate, so it will be enforced when it moves to supported
31168c2ecf20Sopenharmony_ci	 * mode next time.
31178c2ecf20Sopenharmony_ci	 */
31188c2ecf20Sopenharmony_ci	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) {
31198c2ecf20Sopenharmony_ci		mlx4_info(dev,
31208c2ecf20Sopenharmony_ci			  "rate set for VF %d when not in valid state\n", vf);
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci		if (vf_admin->default_vlan != MLX4_VGT)
31238c2ecf20Sopenharmony_ci			mlx4_info(dev, "VST priority not supported by QoS\n");
31248c2ecf20Sopenharmony_ci		else
31258c2ecf20Sopenharmony_ci			mlx4_info(dev, "VF in VGT mode (needed VST)\n");
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci		mlx4_info(dev,
31288c2ecf20Sopenharmony_ci			  "rate %d take affect when VF moves to valid state\n",
31298c2ecf20Sopenharmony_ci			  max_tx_rate);
31308c2ecf20Sopenharmony_ci		return 0;
31318c2ecf20Sopenharmony_ci	}
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	/* If user sets rate 0 assigning default vport for its QPs */
31348c2ecf20Sopenharmony_ci	vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT;
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci	if (priv->mfunc.master.slave_state[slave].active &&
31378c2ecf20Sopenharmony_ci	    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)
31388c2ecf20Sopenharmony_ci		mlx4_master_immediate_activate_vlan_qos(priv, slave, port);
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	return 0;
31418c2ecf20Sopenharmony_ci}
31428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_rate);
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_ci /* mlx4_get_slave_default_vlan -
31458c2ecf20Sopenharmony_ci * return true if VST ( default vlan)
31468c2ecf20Sopenharmony_ci * if VST, will return vlan & qos (if not NULL)
31478c2ecf20Sopenharmony_ci */
31488c2ecf20Sopenharmony_cibool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
31498c2ecf20Sopenharmony_ci				 u16 *vlan, u8 *qos)
31508c2ecf20Sopenharmony_ci{
31518c2ecf20Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
31528c2ecf20Sopenharmony_ci	struct mlx4_priv *priv;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	priv = mlx4_priv(dev);
31558c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
31568c2ecf20Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
31578c2ecf20Sopenharmony_ci
31588c2ecf20Sopenharmony_ci	if (MLX4_VGT != vp_oper->state.default_vlan) {
31598c2ecf20Sopenharmony_ci		if (vlan)
31608c2ecf20Sopenharmony_ci			*vlan = vp_oper->state.default_vlan;
31618c2ecf20Sopenharmony_ci		if (qos)
31628c2ecf20Sopenharmony_ci			*qos = vp_oper->state.default_qos;
31638c2ecf20Sopenharmony_ci		return true;
31648c2ecf20Sopenharmony_ci	}
31658c2ecf20Sopenharmony_ci	return false;
31668c2ecf20Sopenharmony_ci}
31678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan);
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ciint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
31708c2ecf20Sopenharmony_ci{
31718c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
31728c2ecf20Sopenharmony_ci	struct mlx4_vport_state *s_info;
31738c2ecf20Sopenharmony_ci	int slave;
31748c2ecf20Sopenharmony_ci	u8 mac[ETH_ALEN];
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	if ((!mlx4_is_master(dev)) ||
31778c2ecf20Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM))
31788c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
31818c2ecf20Sopenharmony_ci	if (slave < 0)
31828c2ecf20Sopenharmony_ci		return -EINVAL;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
31858c2ecf20Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_ci	mlx4_u64_to_mac(mac, s_info->mac);
31888c2ecf20Sopenharmony_ci	if (setting && !is_valid_ether_addr(mac)) {
31898c2ecf20Sopenharmony_ci		mlx4_info(dev, "Illegal MAC with spoofchk\n");
31908c2ecf20Sopenharmony_ci		return -EPERM;
31918c2ecf20Sopenharmony_ci	}
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_ci	s_info->spoofchk = setting;
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	return 0;
31968c2ecf20Sopenharmony_ci}
31978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ciint mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf)
32008c2ecf20Sopenharmony_ci{
32018c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
32028c2ecf20Sopenharmony_ci	struct mlx4_vport_state *s_info;
32038c2ecf20Sopenharmony_ci	int slave;
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_ci	if (!mlx4_is_master(dev))
32068c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
32098c2ecf20Sopenharmony_ci	if (slave < 0)
32108c2ecf20Sopenharmony_ci		return -EINVAL;
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
32138c2ecf20Sopenharmony_ci	ivf->vf = vf;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	/* need to convert it to a func */
32168c2ecf20Sopenharmony_ci	ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff);
32178c2ecf20Sopenharmony_ci	ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff);
32188c2ecf20Sopenharmony_ci	ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff);
32198c2ecf20Sopenharmony_ci	ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff);
32208c2ecf20Sopenharmony_ci	ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff);
32218c2ecf20Sopenharmony_ci	ivf->mac[5] = ((s_info->mac)  & 0xff);
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	ivf->vlan		= s_info->default_vlan;
32248c2ecf20Sopenharmony_ci	ivf->qos		= s_info->default_qos;
32258c2ecf20Sopenharmony_ci	ivf->vlan_proto		= s_info->vlan_proto;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info))
32288c2ecf20Sopenharmony_ci		ivf->max_tx_rate = s_info->tx_rate;
32298c2ecf20Sopenharmony_ci	else
32308c2ecf20Sopenharmony_ci		ivf->max_tx_rate = 0;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	ivf->min_tx_rate	= 0;
32338c2ecf20Sopenharmony_ci	ivf->spoofchk		= s_info->spoofchk;
32348c2ecf20Sopenharmony_ci	ivf->linkstate		= s_info->link_state;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	return 0;
32378c2ecf20Sopenharmony_ci}
32388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_config);
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ciint mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state)
32418c2ecf20Sopenharmony_ci{
32428c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
32438c2ecf20Sopenharmony_ci	struct mlx4_vport_state *s_info;
32448c2ecf20Sopenharmony_ci	int slave;
32458c2ecf20Sopenharmony_ci	u8 link_stat_event;
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
32488c2ecf20Sopenharmony_ci	if (slave < 0)
32498c2ecf20Sopenharmony_ci		return -EINVAL;
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
32528c2ecf20Sopenharmony_ci	switch (link_state) {
32538c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
32548c2ecf20Sopenharmony_ci		/* get current link state */
32558c2ecf20Sopenharmony_ci		if (!priv->sense.do_sense_port[port])
32568c2ecf20Sopenharmony_ci			link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
32578c2ecf20Sopenharmony_ci		else
32588c2ecf20Sopenharmony_ci			link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
32598c2ecf20Sopenharmony_ci	    break;
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
32628c2ecf20Sopenharmony_ci		link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
32638c2ecf20Sopenharmony_ci	    break;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
32668c2ecf20Sopenharmony_ci		link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
32678c2ecf20Sopenharmony_ci	    break;
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	default:
32708c2ecf20Sopenharmony_ci		mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n",
32718c2ecf20Sopenharmony_ci			  link_state, slave, port);
32728c2ecf20Sopenharmony_ci		return -EINVAL;
32738c2ecf20Sopenharmony_ci	}
32748c2ecf20Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
32758c2ecf20Sopenharmony_ci	s_info->link_state = link_state;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	/* send event */
32788c2ecf20Sopenharmony_ci	mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event);
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci	if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
32818c2ecf20Sopenharmony_ci		mlx4_dbg(dev,
32828c2ecf20Sopenharmony_ci			 "updating vf %d port %d no link state HW enforcement\n",
32838c2ecf20Sopenharmony_ci			 vf, port);
32848c2ecf20Sopenharmony_ci	return 0;
32858c2ecf20Sopenharmony_ci}
32868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ciint mlx4_get_counter_stats(struct mlx4_dev *dev, int counter_index,
32898c2ecf20Sopenharmony_ci			   struct mlx4_counter *counter_stats, int reset)
32908c2ecf20Sopenharmony_ci{
32918c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox = NULL;
32928c2ecf20Sopenharmony_ci	struct mlx4_counter *tmp_counter;
32938c2ecf20Sopenharmony_ci	int err;
32948c2ecf20Sopenharmony_ci	u32 if_stat_in_mod;
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci	if (!counter_stats)
32978c2ecf20Sopenharmony_ci		return -EINVAL;
32988c2ecf20Sopenharmony_ci
32998c2ecf20Sopenharmony_ci	if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
33008c2ecf20Sopenharmony_ci		return 0;
33018c2ecf20Sopenharmony_ci
33028c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
33038c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
33048c2ecf20Sopenharmony_ci		return PTR_ERR(mailbox);
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	memset(mailbox->buf, 0, sizeof(struct mlx4_counter));
33078c2ecf20Sopenharmony_ci	if_stat_in_mod = counter_index;
33088c2ecf20Sopenharmony_ci	if (reset)
33098c2ecf20Sopenharmony_ci		if_stat_in_mod |= MLX4_QUERY_IF_STAT_RESET;
33108c2ecf20Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma,
33118c2ecf20Sopenharmony_ci			   if_stat_in_mod, 0,
33128c2ecf20Sopenharmony_ci			   MLX4_CMD_QUERY_IF_STAT,
33138c2ecf20Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_C,
33148c2ecf20Sopenharmony_ci			   MLX4_CMD_NATIVE);
33158c2ecf20Sopenharmony_ci	if (err) {
33168c2ecf20Sopenharmony_ci		mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n",
33178c2ecf20Sopenharmony_ci			 __func__, counter_index);
33188c2ecf20Sopenharmony_ci		goto if_stat_out;
33198c2ecf20Sopenharmony_ci	}
33208c2ecf20Sopenharmony_ci	tmp_counter = (struct mlx4_counter *)mailbox->buf;
33218c2ecf20Sopenharmony_ci	counter_stats->counter_mode = tmp_counter->counter_mode;
33228c2ecf20Sopenharmony_ci	if (counter_stats->counter_mode == 0) {
33238c2ecf20Sopenharmony_ci		counter_stats->rx_frames =
33248c2ecf20Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->rx_frames) +
33258c2ecf20Sopenharmony_ci				    be64_to_cpu(tmp_counter->rx_frames));
33268c2ecf20Sopenharmony_ci		counter_stats->tx_frames =
33278c2ecf20Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->tx_frames) +
33288c2ecf20Sopenharmony_ci				    be64_to_cpu(tmp_counter->tx_frames));
33298c2ecf20Sopenharmony_ci		counter_stats->rx_bytes =
33308c2ecf20Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->rx_bytes) +
33318c2ecf20Sopenharmony_ci				    be64_to_cpu(tmp_counter->rx_bytes));
33328c2ecf20Sopenharmony_ci		counter_stats->tx_bytes =
33338c2ecf20Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->tx_bytes) +
33348c2ecf20Sopenharmony_ci				    be64_to_cpu(tmp_counter->tx_bytes));
33358c2ecf20Sopenharmony_ci	}
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ciif_stat_out:
33388c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	return err;
33418c2ecf20Sopenharmony_ci}
33428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_counter_stats);
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_ciint mlx4_get_vf_stats(struct mlx4_dev *dev, int port, int vf_idx,
33458c2ecf20Sopenharmony_ci		      struct ifla_vf_stats *vf_stats)
33468c2ecf20Sopenharmony_ci{
33478c2ecf20Sopenharmony_ci	struct mlx4_counter tmp_vf_stats;
33488c2ecf20Sopenharmony_ci	int slave;
33498c2ecf20Sopenharmony_ci	int err = 0;
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci	if (!vf_stats)
33528c2ecf20Sopenharmony_ci		return -EINVAL;
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci	if (!mlx4_is_master(dev))
33558c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf_idx);
33588c2ecf20Sopenharmony_ci	if (slave < 0)
33598c2ecf20Sopenharmony_ci		return -EINVAL;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
33628c2ecf20Sopenharmony_ci	err = mlx4_calc_vf_counters(dev, slave, port, &tmp_vf_stats);
33638c2ecf20Sopenharmony_ci	if (!err && tmp_vf_stats.counter_mode == 0) {
33648c2ecf20Sopenharmony_ci		vf_stats->rx_packets = be64_to_cpu(tmp_vf_stats.rx_frames);
33658c2ecf20Sopenharmony_ci		vf_stats->tx_packets = be64_to_cpu(tmp_vf_stats.tx_frames);
33668c2ecf20Sopenharmony_ci		vf_stats->rx_bytes = be64_to_cpu(tmp_vf_stats.rx_bytes);
33678c2ecf20Sopenharmony_ci		vf_stats->tx_bytes = be64_to_cpu(tmp_vf_stats.tx_bytes);
33688c2ecf20Sopenharmony_ci	}
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci	return err;
33718c2ecf20Sopenharmony_ci}
33728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_stats);
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ciint mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port)
33758c2ecf20Sopenharmony_ci{
33768c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
33798c2ecf20Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS)
33808c2ecf20Sopenharmony_ci		return 0;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	return priv->mfunc.master.vf_oper[slave].smi_enabled[port] ==
33838c2ecf20Sopenharmony_ci		MLX4_VF_SMI_ENABLED;
33848c2ecf20Sopenharmony_ci}
33858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_smi_enabled);
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ciint mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port)
33888c2ecf20Sopenharmony_ci{
33898c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci	if (slave == mlx4_master_func_num(dev))
33928c2ecf20Sopenharmony_ci		return 1;
33938c2ecf20Sopenharmony_ci
33948c2ecf20Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
33958c2ecf20Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS)
33968c2ecf20Sopenharmony_ci		return 0;
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci	return priv->mfunc.master.vf_admin[slave].enable_smi[port] ==
33998c2ecf20Sopenharmony_ci		MLX4_VF_SMI_ENABLED;
34008c2ecf20Sopenharmony_ci}
34018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_get_enable_smi_admin);
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ciint mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
34048c2ecf20Sopenharmony_ci				 int enabled)
34058c2ecf20Sopenharmony_ci{
34068c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
34078c2ecf20Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
34088c2ecf20Sopenharmony_ci			&priv->dev, slave);
34098c2ecf20Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports,
34108c2ecf20Sopenharmony_ci				      priv->dev.caps.num_ports) + 1;
34118c2ecf20Sopenharmony_ci	int max_port = min_port - 1 +
34128c2ecf20Sopenharmony_ci		bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	if (slave == mlx4_master_func_num(dev))
34158c2ecf20Sopenharmony_ci		return 0;
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
34188c2ecf20Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS ||
34198c2ecf20Sopenharmony_ci	    enabled < 0 || enabled > 1)
34208c2ecf20Sopenharmony_ci		return -EINVAL;
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	if (min_port == max_port && dev->caps.num_ports > 1) {
34238c2ecf20Sopenharmony_ci		mlx4_info(dev, "SMI access disallowed for single ported VFs\n");
34248c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
34258c2ecf20Sopenharmony_ci	}
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci	priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled;
34288c2ecf20Sopenharmony_ci	return 0;
34298c2ecf20Sopenharmony_ci}
34308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_set_enable_smi_admin);
3431