162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This software is available to you under a choice of one of two
762306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
1062306a36Sopenharmony_ci * OpenIB.org BSD license below:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1362306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1462306a36Sopenharmony_ci *     conditions are met:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1762306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1862306a36Sopenharmony_ci *        disclaimer.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2162306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2262306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2362306a36Sopenharmony_ci *        provided with the distribution.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3262306a36Sopenharmony_ci * SOFTWARE.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/sched.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <linux/export.h>
3862306a36Sopenharmony_ci#include <linux/pci.h>
3962306a36Sopenharmony_ci#include <linux/errno.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include <linux/mlx4/cmd.h>
4262306a36Sopenharmony_ci#include <linux/mlx4/device.h>
4362306a36Sopenharmony_ci#include <linux/semaphore.h>
4462306a36Sopenharmony_ci#include <rdma/ib_smi.h>
4562306a36Sopenharmony_ci#include <linux/delay.h>
4662306a36Sopenharmony_ci#include <linux/etherdevice.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <asm/io.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include "mlx4.h"
5162306a36Sopenharmony_ci#include "fw.h"
5262306a36Sopenharmony_ci#include "fw_qos.h"
5362306a36Sopenharmony_ci#include "mlx4_stats.h"
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define CMD_POLL_TOKEN 0xffff
5662306a36Sopenharmony_ci#define INBOX_MASK	0xffffffffffffff00ULL
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define CMD_CHAN_VER 1
5962306a36Sopenharmony_ci#define CMD_CHAN_IF_REV 1
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cienum {
6262306a36Sopenharmony_ci	/* command completed successfully: */
6362306a36Sopenharmony_ci	CMD_STAT_OK		= 0x00,
6462306a36Sopenharmony_ci	/* Internal error (such as a bus error) occurred while processing command: */
6562306a36Sopenharmony_ci	CMD_STAT_INTERNAL_ERR	= 0x01,
6662306a36Sopenharmony_ci	/* Operation/command not supported or opcode modifier not supported: */
6762306a36Sopenharmony_ci	CMD_STAT_BAD_OP		= 0x02,
6862306a36Sopenharmony_ci	/* Parameter not supported or parameter out of range: */
6962306a36Sopenharmony_ci	CMD_STAT_BAD_PARAM	= 0x03,
7062306a36Sopenharmony_ci	/* System not enabled or bad system state: */
7162306a36Sopenharmony_ci	CMD_STAT_BAD_SYS_STATE	= 0x04,
7262306a36Sopenharmony_ci	/* Attempt to access reserved or unallocaterd resource: */
7362306a36Sopenharmony_ci	CMD_STAT_BAD_RESOURCE	= 0x05,
7462306a36Sopenharmony_ci	/* Requested resource is currently executing a command, or is otherwise busy: */
7562306a36Sopenharmony_ci	CMD_STAT_RESOURCE_BUSY	= 0x06,
7662306a36Sopenharmony_ci	/* Required capability exceeds device limits: */
7762306a36Sopenharmony_ci	CMD_STAT_EXCEED_LIM	= 0x08,
7862306a36Sopenharmony_ci	/* Resource is not in the appropriate state or ownership: */
7962306a36Sopenharmony_ci	CMD_STAT_BAD_RES_STATE	= 0x09,
8062306a36Sopenharmony_ci	/* Index out of range: */
8162306a36Sopenharmony_ci	CMD_STAT_BAD_INDEX	= 0x0a,
8262306a36Sopenharmony_ci	/* FW image corrupted: */
8362306a36Sopenharmony_ci	CMD_STAT_BAD_NVMEM	= 0x0b,
8462306a36Sopenharmony_ci	/* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */
8562306a36Sopenharmony_ci	CMD_STAT_ICM_ERROR	= 0x0c,
8662306a36Sopenharmony_ci	/* Attempt to modify a QP/EE which is not in the presumed state: */
8762306a36Sopenharmony_ci	CMD_STAT_BAD_QP_STATE   = 0x10,
8862306a36Sopenharmony_ci	/* Bad segment parameters (Address/Size): */
8962306a36Sopenharmony_ci	CMD_STAT_BAD_SEG_PARAM	= 0x20,
9062306a36Sopenharmony_ci	/* Memory Region has Memory Windows bound to: */
9162306a36Sopenharmony_ci	CMD_STAT_REG_BOUND	= 0x21,
9262306a36Sopenharmony_ci	/* HCA local attached memory not present: */
9362306a36Sopenharmony_ci	CMD_STAT_LAM_NOT_PRE	= 0x22,
9462306a36Sopenharmony_ci	/* Bad management packet (silently discarded): */
9562306a36Sopenharmony_ci	CMD_STAT_BAD_PKT	= 0x30,
9662306a36Sopenharmony_ci	/* More outstanding CQEs in CQ than new CQ size: */
9762306a36Sopenharmony_ci	CMD_STAT_BAD_SIZE	= 0x40,
9862306a36Sopenharmony_ci	/* Multi Function device support required: */
9962306a36Sopenharmony_ci	CMD_STAT_MULTI_FUNC_REQ	= 0x50,
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cienum {
10362306a36Sopenharmony_ci	HCR_IN_PARAM_OFFSET	= 0x00,
10462306a36Sopenharmony_ci	HCR_IN_MODIFIER_OFFSET	= 0x08,
10562306a36Sopenharmony_ci	HCR_OUT_PARAM_OFFSET	= 0x0c,
10662306a36Sopenharmony_ci	HCR_TOKEN_OFFSET	= 0x14,
10762306a36Sopenharmony_ci	HCR_STATUS_OFFSET	= 0x18,
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	HCR_OPMOD_SHIFT		= 12,
11062306a36Sopenharmony_ci	HCR_T_BIT		= 21,
11162306a36Sopenharmony_ci	HCR_E_BIT		= 22,
11262306a36Sopenharmony_ci	HCR_GO_BIT		= 23
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cienum {
11662306a36Sopenharmony_ci	GO_BIT_TIMEOUT_MSECS	= 10000
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cienum mlx4_vlan_transition {
12062306a36Sopenharmony_ci	MLX4_VLAN_TRANSITION_VST_VST = 0,
12162306a36Sopenharmony_ci	MLX4_VLAN_TRANSITION_VST_VGT = 1,
12262306a36Sopenharmony_ci	MLX4_VLAN_TRANSITION_VGT_VST = 2,
12362306a36Sopenharmony_ci	MLX4_VLAN_TRANSITION_VGT_VGT = 3,
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct mlx4_cmd_context {
12862306a36Sopenharmony_ci	struct completion	done;
12962306a36Sopenharmony_ci	int			result;
13062306a36Sopenharmony_ci	int			next;
13162306a36Sopenharmony_ci	u64			out_param;
13262306a36Sopenharmony_ci	u16			token;
13362306a36Sopenharmony_ci	u8			fw_status;
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
13762306a36Sopenharmony_ci				    struct mlx4_vhcr_cmd *in_vhcr);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic int mlx4_status_to_errno(u8 status)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	static const int trans_table[] = {
14262306a36Sopenharmony_ci		[CMD_STAT_INTERNAL_ERR]	  = -EIO,
14362306a36Sopenharmony_ci		[CMD_STAT_BAD_OP]	  = -EPERM,
14462306a36Sopenharmony_ci		[CMD_STAT_BAD_PARAM]	  = -EINVAL,
14562306a36Sopenharmony_ci		[CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
14662306a36Sopenharmony_ci		[CMD_STAT_BAD_RESOURCE]	  = -EBADF,
14762306a36Sopenharmony_ci		[CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
14862306a36Sopenharmony_ci		[CMD_STAT_EXCEED_LIM]	  = -ENOMEM,
14962306a36Sopenharmony_ci		[CMD_STAT_BAD_RES_STATE]  = -EBADF,
15062306a36Sopenharmony_ci		[CMD_STAT_BAD_INDEX]	  = -EBADF,
15162306a36Sopenharmony_ci		[CMD_STAT_BAD_NVMEM]	  = -EFAULT,
15262306a36Sopenharmony_ci		[CMD_STAT_ICM_ERROR]	  = -ENFILE,
15362306a36Sopenharmony_ci		[CMD_STAT_BAD_QP_STATE]   = -EINVAL,
15462306a36Sopenharmony_ci		[CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
15562306a36Sopenharmony_ci		[CMD_STAT_REG_BOUND]	  = -EBUSY,
15662306a36Sopenharmony_ci		[CMD_STAT_LAM_NOT_PRE]	  = -EAGAIN,
15762306a36Sopenharmony_ci		[CMD_STAT_BAD_PKT]	  = -EINVAL,
15862306a36Sopenharmony_ci		[CMD_STAT_BAD_SIZE]	  = -ENOMEM,
15962306a36Sopenharmony_ci		[CMD_STAT_MULTI_FUNC_REQ] = -EACCES,
16062306a36Sopenharmony_ci	};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (status >= ARRAY_SIZE(trans_table) ||
16362306a36Sopenharmony_ci	    (status != CMD_STAT_OK && trans_table[status] == 0))
16462306a36Sopenharmony_ci		return -EIO;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return trans_table[status];
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic u8 mlx4_errno_to_status(int errno)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	switch (errno) {
17262306a36Sopenharmony_ci	case -EPERM:
17362306a36Sopenharmony_ci		return CMD_STAT_BAD_OP;
17462306a36Sopenharmony_ci	case -EINVAL:
17562306a36Sopenharmony_ci		return CMD_STAT_BAD_PARAM;
17662306a36Sopenharmony_ci	case -ENXIO:
17762306a36Sopenharmony_ci		return CMD_STAT_BAD_SYS_STATE;
17862306a36Sopenharmony_ci	case -EBUSY:
17962306a36Sopenharmony_ci		return CMD_STAT_RESOURCE_BUSY;
18062306a36Sopenharmony_ci	case -ENOMEM:
18162306a36Sopenharmony_ci		return CMD_STAT_EXCEED_LIM;
18262306a36Sopenharmony_ci	case -ENFILE:
18362306a36Sopenharmony_ci		return CMD_STAT_ICM_ERROR;
18462306a36Sopenharmony_ci	default:
18562306a36Sopenharmony_ci		return CMD_STAT_INTERNAL_ERR;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op,
19062306a36Sopenharmony_ci				       u8 op_modifier)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	switch (op) {
19362306a36Sopenharmony_ci	case MLX4_CMD_UNMAP_ICM:
19462306a36Sopenharmony_ci	case MLX4_CMD_UNMAP_ICM_AUX:
19562306a36Sopenharmony_ci	case MLX4_CMD_UNMAP_FA:
19662306a36Sopenharmony_ci	case MLX4_CMD_2RST_QP:
19762306a36Sopenharmony_ci	case MLX4_CMD_HW2SW_EQ:
19862306a36Sopenharmony_ci	case MLX4_CMD_HW2SW_CQ:
19962306a36Sopenharmony_ci	case MLX4_CMD_HW2SW_SRQ:
20062306a36Sopenharmony_ci	case MLX4_CMD_HW2SW_MPT:
20162306a36Sopenharmony_ci	case MLX4_CMD_CLOSE_HCA:
20262306a36Sopenharmony_ci	case MLX4_QP_FLOW_STEERING_DETACH:
20362306a36Sopenharmony_ci	case MLX4_CMD_FREE_RES:
20462306a36Sopenharmony_ci	case MLX4_CMD_CLOSE_PORT:
20562306a36Sopenharmony_ci		return CMD_STAT_OK;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	case MLX4_CMD_QP_ATTACH:
20862306a36Sopenharmony_ci		/* On Detach case return success */
20962306a36Sopenharmony_ci		if (op_modifier == 0)
21062306a36Sopenharmony_ci			return CMD_STAT_OK;
21162306a36Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	default:
21462306a36Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	/* Any error during the closing commands below is considered fatal */
22162306a36Sopenharmony_ci	if (op == MLX4_CMD_CLOSE_HCA ||
22262306a36Sopenharmony_ci	    op == MLX4_CMD_HW2SW_EQ ||
22362306a36Sopenharmony_ci	    op == MLX4_CMD_HW2SW_CQ ||
22462306a36Sopenharmony_ci	    op == MLX4_CMD_2RST_QP ||
22562306a36Sopenharmony_ci	    op == MLX4_CMD_HW2SW_SRQ ||
22662306a36Sopenharmony_ci	    op == MLX4_CMD_SYNC_TPT ||
22762306a36Sopenharmony_ci	    op == MLX4_CMD_UNMAP_ICM ||
22862306a36Sopenharmony_ci	    op == MLX4_CMD_UNMAP_ICM_AUX ||
22962306a36Sopenharmony_ci	    op == MLX4_CMD_UNMAP_FA)
23062306a36Sopenharmony_ci		return 1;
23162306a36Sopenharmony_ci	/* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals
23262306a36Sopenharmony_ci	  * CMD_STAT_REG_BOUND.
23362306a36Sopenharmony_ci	  * This status indicates that memory region has memory windows bound to it
23462306a36Sopenharmony_ci	  * which may result from invalid user space usage and is not fatal.
23562306a36Sopenharmony_ci	  */
23662306a36Sopenharmony_ci	if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND)
23762306a36Sopenharmony_ci		return 1;
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier,
24262306a36Sopenharmony_ci			       int err)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	/* Only if reset flow is really active return code is based on
24562306a36Sopenharmony_ci	  * command, otherwise current error code is returned.
24662306a36Sopenharmony_ci	  */
24762306a36Sopenharmony_ci	if (mlx4_internal_err_reset) {
24862306a36Sopenharmony_ci		mlx4_enter_error_state(dev->persist);
24962306a36Sopenharmony_ci		err = mlx4_internal_err_ret_value(dev, op, op_modifier);
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return err;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int comm_pending(struct mlx4_dev *dev)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
25862306a36Sopenharmony_ci	u32 status = readl(&priv->mfunc.comm->slave_read);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return (swab32(status) >> 31) != priv->cmd.comm_toggle;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
26662306a36Sopenharmony_ci	u32 val;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* To avoid writing to unknown addresses after the device state was
26962306a36Sopenharmony_ci	 * changed to internal error and the function was rest,
27062306a36Sopenharmony_ci	 * check the INTERNAL_ERROR flag which is updated under
27162306a36Sopenharmony_ci	 * device_state_mutex lock.
27262306a36Sopenharmony_ci	 */
27362306a36Sopenharmony_ci	mutex_lock(&dev->persist->device_state_mutex);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
27662306a36Sopenharmony_ci		mutex_unlock(&dev->persist->device_state_mutex);
27762306a36Sopenharmony_ci		return -EIO;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	priv->cmd.comm_toggle ^= 1;
28162306a36Sopenharmony_ci	val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31);
28262306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(val),
28362306a36Sopenharmony_ci		     &priv->mfunc.comm->slave_write);
28462306a36Sopenharmony_ci	mutex_unlock(&dev->persist->device_state_mutex);
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
28962306a36Sopenharmony_ci		       unsigned long timeout)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
29262306a36Sopenharmony_ci	unsigned long end;
29362306a36Sopenharmony_ci	int err = 0;
29462306a36Sopenharmony_ci	int ret_from_pending = 0;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* First, verify that the master reports correct status */
29762306a36Sopenharmony_ci	if (comm_pending(dev)) {
29862306a36Sopenharmony_ci		mlx4_warn(dev, "Communication channel is not idle - my toggle is %d (cmd:0x%x)\n",
29962306a36Sopenharmony_ci			  priv->cmd.comm_toggle, cmd);
30062306a36Sopenharmony_ci		return -EAGAIN;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* Write command */
30462306a36Sopenharmony_ci	down(&priv->cmd.poll_sem);
30562306a36Sopenharmony_ci	if (mlx4_comm_cmd_post(dev, cmd, param)) {
30662306a36Sopenharmony_ci		/* Only in case the device state is INTERNAL_ERROR,
30762306a36Sopenharmony_ci		 * mlx4_comm_cmd_post returns with an error
30862306a36Sopenharmony_ci		 */
30962306a36Sopenharmony_ci		err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
31062306a36Sopenharmony_ci		goto out;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	end = msecs_to_jiffies(timeout) + jiffies;
31462306a36Sopenharmony_ci	while (comm_pending(dev) && time_before(jiffies, end))
31562306a36Sopenharmony_ci		cond_resched();
31662306a36Sopenharmony_ci	ret_from_pending = comm_pending(dev);
31762306a36Sopenharmony_ci	if (ret_from_pending) {
31862306a36Sopenharmony_ci		/* check if the slave is trying to boot in the middle of
31962306a36Sopenharmony_ci		 * FLR process. The only non-zero result in the RESET command
32062306a36Sopenharmony_ci		 * is MLX4_DELAY_RESET_SLAVE*/
32162306a36Sopenharmony_ci		if ((MLX4_COMM_CMD_RESET == cmd)) {
32262306a36Sopenharmony_ci			err = MLX4_DELAY_RESET_SLAVE;
32362306a36Sopenharmony_ci			goto out;
32462306a36Sopenharmony_ci		} else {
32562306a36Sopenharmony_ci			mlx4_warn(dev, "Communication channel command 0x%x timed out\n",
32662306a36Sopenharmony_ci				  cmd);
32762306a36Sopenharmony_ci			err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (err)
33262306a36Sopenharmony_ci		mlx4_enter_error_state(dev->persist);
33362306a36Sopenharmony_ciout:
33462306a36Sopenharmony_ci	up(&priv->cmd.poll_sem);
33562306a36Sopenharmony_ci	return err;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd,
33962306a36Sopenharmony_ci			      u16 param, u16 op, unsigned long timeout)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
34262306a36Sopenharmony_ci	struct mlx4_cmd_context *context;
34362306a36Sopenharmony_ci	unsigned long end;
34462306a36Sopenharmony_ci	int err = 0;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	down(&cmd->event_sem);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	spin_lock(&cmd->context_lock);
34962306a36Sopenharmony_ci	BUG_ON(cmd->free_head < 0);
35062306a36Sopenharmony_ci	context = &cmd->context[cmd->free_head];
35162306a36Sopenharmony_ci	context->token += cmd->token_mask + 1;
35262306a36Sopenharmony_ci	cmd->free_head = context->next;
35362306a36Sopenharmony_ci	spin_unlock(&cmd->context_lock);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	reinit_completion(&context->done);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) {
35862306a36Sopenharmony_ci		/* Only in case the device state is INTERNAL_ERROR,
35962306a36Sopenharmony_ci		 * mlx4_comm_cmd_post returns with an error
36062306a36Sopenharmony_ci		 */
36162306a36Sopenharmony_ci		err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
36262306a36Sopenharmony_ci		goto out;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&context->done,
36662306a36Sopenharmony_ci					 msecs_to_jiffies(timeout))) {
36762306a36Sopenharmony_ci		mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n",
36862306a36Sopenharmony_ci			  vhcr_cmd, op);
36962306a36Sopenharmony_ci		goto out_reset;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	err = context->result;
37362306a36Sopenharmony_ci	if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) {
37462306a36Sopenharmony_ci		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
37562306a36Sopenharmony_ci			 vhcr_cmd, context->fw_status);
37662306a36Sopenharmony_ci		if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
37762306a36Sopenharmony_ci			goto out_reset;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/* wait for comm channel ready
38162306a36Sopenharmony_ci	 * this is necessary for prevention the race
38262306a36Sopenharmony_ci	 * when switching between event to polling mode
38362306a36Sopenharmony_ci	 * Skipping this section in case the device is in FATAL_ERROR state,
38462306a36Sopenharmony_ci	 * In this state, no commands are sent via the comm channel until
38562306a36Sopenharmony_ci	 * the device has returned from reset.
38662306a36Sopenharmony_ci	 */
38762306a36Sopenharmony_ci	if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
38862306a36Sopenharmony_ci		end = msecs_to_jiffies(timeout) + jiffies;
38962306a36Sopenharmony_ci		while (comm_pending(dev) && time_before(jiffies, end))
39062306a36Sopenharmony_ci			cond_resched();
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	goto out;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ciout_reset:
39562306a36Sopenharmony_ci	err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
39662306a36Sopenharmony_ci	mlx4_enter_error_state(dev->persist);
39762306a36Sopenharmony_ciout:
39862306a36Sopenharmony_ci	spin_lock(&cmd->context_lock);
39962306a36Sopenharmony_ci	context->next = cmd->free_head;
40062306a36Sopenharmony_ci	cmd->free_head = context - cmd->context;
40162306a36Sopenharmony_ci	spin_unlock(&cmd->context_lock);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	up(&cmd->event_sem);
40462306a36Sopenharmony_ci	return err;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ciint mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
40862306a36Sopenharmony_ci		  u16 op, unsigned long timeout)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
41162306a36Sopenharmony_ci		return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (mlx4_priv(dev)->cmd.use_events)
41462306a36Sopenharmony_ci		return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout);
41562306a36Sopenharmony_ci	return mlx4_comm_cmd_poll(dev, cmd, param, timeout);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic int cmd_pending(struct mlx4_dev *dev)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	u32 status;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev))
42362306a36Sopenharmony_ci		return -EIO;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return (status & swab32(1 << HCR_GO_BIT)) ||
42862306a36Sopenharmony_ci		(mlx4_priv(dev)->cmd.toggle ==
42962306a36Sopenharmony_ci		 !!(status & swab32(1 << HCR_T_BIT)));
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
43362306a36Sopenharmony_ci			 u32 in_modifier, u8 op_modifier, u16 op, u16 token,
43462306a36Sopenharmony_ci			 int event)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
43762306a36Sopenharmony_ci	u32 __iomem *hcr = cmd->hcr;
43862306a36Sopenharmony_ci	int ret = -EIO;
43962306a36Sopenharmony_ci	unsigned long end;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	mutex_lock(&dev->persist->device_state_mutex);
44262306a36Sopenharmony_ci	/* To avoid writing to unknown addresses after the device state was
44362306a36Sopenharmony_ci	  * changed to internal error and the chip was reset,
44462306a36Sopenharmony_ci	  * check the INTERNAL_ERROR flag which is updated under
44562306a36Sopenharmony_ci	  * device_state_mutex lock.
44662306a36Sopenharmony_ci	  */
44762306a36Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev) ||
44862306a36Sopenharmony_ci	    (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
44962306a36Sopenharmony_ci		/*
45062306a36Sopenharmony_ci		 * Device is going through error recovery
45162306a36Sopenharmony_ci		 * and cannot accept commands.
45262306a36Sopenharmony_ci		 */
45362306a36Sopenharmony_ci		goto out;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	end = jiffies;
45762306a36Sopenharmony_ci	if (event)
45862306a36Sopenharmony_ci		end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	while (cmd_pending(dev)) {
46162306a36Sopenharmony_ci		if (pci_channel_offline(dev->persist->pdev)) {
46262306a36Sopenharmony_ci			/*
46362306a36Sopenharmony_ci			 * Device is going through error recovery
46462306a36Sopenharmony_ci			 * and cannot accept commands.
46562306a36Sopenharmony_ci			 */
46662306a36Sopenharmony_ci			goto out;
46762306a36Sopenharmony_ci		}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		if (time_after_eq(jiffies, end)) {
47062306a36Sopenharmony_ci			mlx4_err(dev, "%s:cmd_pending failed\n", __func__);
47162306a36Sopenharmony_ci			goto out;
47262306a36Sopenharmony_ci		}
47362306a36Sopenharmony_ci		cond_resched();
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/*
47762306a36Sopenharmony_ci	 * We use writel (instead of something like memcpy_toio)
47862306a36Sopenharmony_ci	 * because writes of less than 32 bits to the HCR don't work
47962306a36Sopenharmony_ci	 * (and some architectures such as ia64 implement memcpy_toio
48062306a36Sopenharmony_ci	 * in terms of writeb).
48162306a36Sopenharmony_ci	 */
48262306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param >> 32),		  hcr + 0);
48362306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  hcr + 1);
48462306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(in_modifier),		  hcr + 2);
48562306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param >> 32),	  hcr + 3);
48662306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4);
48762306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(token << 16),		  hcr + 5);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* __raw_writel may not order writes. */
49062306a36Sopenharmony_ci	wmb();
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)		|
49362306a36Sopenharmony_ci					       (cmd->toggle << HCR_T_BIT)	|
49462306a36Sopenharmony_ci					       (event ? (1 << HCR_E_BIT) : 0)	|
49562306a36Sopenharmony_ci					       (op_modifier << HCR_OPMOD_SHIFT) |
49662306a36Sopenharmony_ci					       op), hcr + 6);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	cmd->toggle = cmd->toggle ^ 1;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	ret = 0;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ciout:
50362306a36Sopenharmony_ci	if (ret)
50462306a36Sopenharmony_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",
50562306a36Sopenharmony_ci			  op, ret, in_param, in_modifier, op_modifier);
50662306a36Sopenharmony_ci	mutex_unlock(&dev->persist->device_state_mutex);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return ret;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
51262306a36Sopenharmony_ci			  int out_is_imm, u32 in_modifier, u8 op_modifier,
51362306a36Sopenharmony_ci			  u16 op, unsigned long timeout)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
51662306a36Sopenharmony_ci	struct mlx4_vhcr_cmd *vhcr = priv->mfunc.vhcr;
51762306a36Sopenharmony_ci	int ret;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	mutex_lock(&priv->cmd.slave_cmd_mutex);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	vhcr->in_param = cpu_to_be64(in_param);
52262306a36Sopenharmony_ci	vhcr->out_param = out_param ? cpu_to_be64(*out_param) : 0;
52362306a36Sopenharmony_ci	vhcr->in_modifier = cpu_to_be32(in_modifier);
52462306a36Sopenharmony_ci	vhcr->opcode = cpu_to_be16((((u16) op_modifier) << 12) | (op & 0xfff));
52562306a36Sopenharmony_ci	vhcr->token = cpu_to_be16(CMD_POLL_TOKEN);
52662306a36Sopenharmony_ci	vhcr->status = 0;
52762306a36Sopenharmony_ci	vhcr->flags = !!(priv->cmd.use_events) << 6;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (mlx4_is_master(dev)) {
53062306a36Sopenharmony_ci		ret = mlx4_master_process_vhcr(dev, dev->caps.function, vhcr);
53162306a36Sopenharmony_ci		if (!ret) {
53262306a36Sopenharmony_ci			if (out_is_imm) {
53362306a36Sopenharmony_ci				if (out_param)
53462306a36Sopenharmony_ci					*out_param =
53562306a36Sopenharmony_ci						be64_to_cpu(vhcr->out_param);
53662306a36Sopenharmony_ci				else {
53762306a36Sopenharmony_ci					mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
53862306a36Sopenharmony_ci						 op);
53962306a36Sopenharmony_ci					vhcr->status = CMD_STAT_BAD_PARAM;
54062306a36Sopenharmony_ci				}
54162306a36Sopenharmony_ci			}
54262306a36Sopenharmony_ci			ret = mlx4_status_to_errno(vhcr->status);
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci		if (ret &&
54562306a36Sopenharmony_ci		    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
54662306a36Sopenharmony_ci			ret = mlx4_internal_err_ret_value(dev, op, op_modifier);
54762306a36Sopenharmony_ci	} else {
54862306a36Sopenharmony_ci		ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op,
54962306a36Sopenharmony_ci				    MLX4_COMM_TIME + timeout);
55062306a36Sopenharmony_ci		if (!ret) {
55162306a36Sopenharmony_ci			if (out_is_imm) {
55262306a36Sopenharmony_ci				if (out_param)
55362306a36Sopenharmony_ci					*out_param =
55462306a36Sopenharmony_ci						be64_to_cpu(vhcr->out_param);
55562306a36Sopenharmony_ci				else {
55662306a36Sopenharmony_ci					mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
55762306a36Sopenharmony_ci						 op);
55862306a36Sopenharmony_ci					vhcr->status = CMD_STAT_BAD_PARAM;
55962306a36Sopenharmony_ci				}
56062306a36Sopenharmony_ci			}
56162306a36Sopenharmony_ci			ret = mlx4_status_to_errno(vhcr->status);
56262306a36Sopenharmony_ci		} else {
56362306a36Sopenharmony_ci			if (dev->persist->state &
56462306a36Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR)
56562306a36Sopenharmony_ci				ret = mlx4_internal_err_ret_value(dev, op,
56662306a36Sopenharmony_ci								  op_modifier);
56762306a36Sopenharmony_ci			else
56862306a36Sopenharmony_ci				mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op);
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	mutex_unlock(&priv->cmd.slave_cmd_mutex);
57362306a36Sopenharmony_ci	return ret;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
57762306a36Sopenharmony_ci			 int out_is_imm, u32 in_modifier, u8 op_modifier,
57862306a36Sopenharmony_ci			 u16 op, unsigned long timeout)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
58162306a36Sopenharmony_ci	void __iomem *hcr = priv->cmd.hcr;
58262306a36Sopenharmony_ci	int err = 0;
58362306a36Sopenharmony_ci	unsigned long end;
58462306a36Sopenharmony_ci	u32 stat;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	down(&priv->cmd.poll_sem);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
58962306a36Sopenharmony_ci		/*
59062306a36Sopenharmony_ci		 * Device is going through error recovery
59162306a36Sopenharmony_ci		 * and cannot accept commands.
59262306a36Sopenharmony_ci		 */
59362306a36Sopenharmony_ci		err = mlx4_internal_err_ret_value(dev, op, op_modifier);
59462306a36Sopenharmony_ci		goto out;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (out_is_imm && !out_param) {
59862306a36Sopenharmony_ci		mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
59962306a36Sopenharmony_ci			 op);
60062306a36Sopenharmony_ci		err = -EINVAL;
60162306a36Sopenharmony_ci		goto out;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
60562306a36Sopenharmony_ci			    in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
60662306a36Sopenharmony_ci	if (err)
60762306a36Sopenharmony_ci		goto out_reset;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	end = msecs_to_jiffies(timeout) + jiffies;
61062306a36Sopenharmony_ci	while (cmd_pending(dev) && time_before(jiffies, end)) {
61162306a36Sopenharmony_ci		if (pci_channel_offline(dev->persist->pdev)) {
61262306a36Sopenharmony_ci			/*
61362306a36Sopenharmony_ci			 * Device is going through error recovery
61462306a36Sopenharmony_ci			 * and cannot accept commands.
61562306a36Sopenharmony_ci			 */
61662306a36Sopenharmony_ci			err = -EIO;
61762306a36Sopenharmony_ci			goto out_reset;
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
62162306a36Sopenharmony_ci			err = mlx4_internal_err_ret_value(dev, op, op_modifier);
62262306a36Sopenharmony_ci			goto out;
62362306a36Sopenharmony_ci		}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		cond_resched();
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (cmd_pending(dev)) {
62962306a36Sopenharmony_ci		mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
63062306a36Sopenharmony_ci			  op);
63162306a36Sopenharmony_ci		err = -EIO;
63262306a36Sopenharmony_ci		goto out_reset;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if (out_is_imm)
63662306a36Sopenharmony_ci		*out_param =
63762306a36Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
63862306a36Sopenharmony_ci					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
63962306a36Sopenharmony_ci			(u64) be32_to_cpu((__force __be32)
64062306a36Sopenharmony_ci					  __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
64162306a36Sopenharmony_ci	stat = be32_to_cpu((__force __be32)
64262306a36Sopenharmony_ci			   __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24;
64362306a36Sopenharmony_ci	err = mlx4_status_to_errno(stat);
64462306a36Sopenharmony_ci	if (err) {
64562306a36Sopenharmony_ci		mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
64662306a36Sopenharmony_ci			 op, stat);
64762306a36Sopenharmony_ci		if (mlx4_closing_cmd_fatal_error(op, stat))
64862306a36Sopenharmony_ci			goto out_reset;
64962306a36Sopenharmony_ci		goto out;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciout_reset:
65362306a36Sopenharmony_ci	if (err)
65462306a36Sopenharmony_ci		err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
65562306a36Sopenharmony_ciout:
65662306a36Sopenharmony_ci	up(&priv->cmd.poll_sem);
65762306a36Sopenharmony_ci	return err;
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_civoid mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
66362306a36Sopenharmony_ci	struct mlx4_cmd_context *context =
66462306a36Sopenharmony_ci		&priv->cmd.context[token & priv->cmd.token_mask];
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* previously timed out command completing at long last */
66762306a36Sopenharmony_ci	if (token != context->token)
66862306a36Sopenharmony_ci		return;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	context->fw_status = status;
67162306a36Sopenharmony_ci	context->result    = mlx4_status_to_errno(status);
67262306a36Sopenharmony_ci	context->out_param = out_param;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	complete(&context->done);
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
67862306a36Sopenharmony_ci			 int out_is_imm, u32 in_modifier, u8 op_modifier,
67962306a36Sopenharmony_ci			 u16 op, unsigned long timeout)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
68262306a36Sopenharmony_ci	struct mlx4_cmd_context *context;
68362306a36Sopenharmony_ci	long ret_wait;
68462306a36Sopenharmony_ci	int err = 0;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	down(&cmd->event_sem);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	spin_lock(&cmd->context_lock);
68962306a36Sopenharmony_ci	BUG_ON(cmd->free_head < 0);
69062306a36Sopenharmony_ci	context = &cmd->context[cmd->free_head];
69162306a36Sopenharmony_ci	context->token += cmd->token_mask + 1;
69262306a36Sopenharmony_ci	cmd->free_head = context->next;
69362306a36Sopenharmony_ci	spin_unlock(&cmd->context_lock);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (out_is_imm && !out_param) {
69662306a36Sopenharmony_ci		mlx4_err(dev, "response expected while output mailbox is NULL for command 0x%x\n",
69762306a36Sopenharmony_ci			 op);
69862306a36Sopenharmony_ci		err = -EINVAL;
69962306a36Sopenharmony_ci		goto out;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	reinit_completion(&context->done);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
70562306a36Sopenharmony_ci			    in_modifier, op_modifier, op, context->token, 1);
70662306a36Sopenharmony_ci	if (err)
70762306a36Sopenharmony_ci		goto out_reset;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (op == MLX4_CMD_SENSE_PORT) {
71062306a36Sopenharmony_ci		ret_wait =
71162306a36Sopenharmony_ci			wait_for_completion_interruptible_timeout(&context->done,
71262306a36Sopenharmony_ci								  msecs_to_jiffies(timeout));
71362306a36Sopenharmony_ci		if (ret_wait < 0) {
71462306a36Sopenharmony_ci			context->fw_status = 0;
71562306a36Sopenharmony_ci			context->out_param = 0;
71662306a36Sopenharmony_ci			context->result = 0;
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci	} else {
71962306a36Sopenharmony_ci		ret_wait = (long)wait_for_completion_timeout(&context->done,
72062306a36Sopenharmony_ci							     msecs_to_jiffies(timeout));
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	if (!ret_wait) {
72362306a36Sopenharmony_ci		mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
72462306a36Sopenharmony_ci			  op);
72562306a36Sopenharmony_ci		if (op == MLX4_CMD_NOP) {
72662306a36Sopenharmony_ci			err = -EBUSY;
72762306a36Sopenharmony_ci			goto out;
72862306a36Sopenharmony_ci		} else {
72962306a36Sopenharmony_ci			err = -EIO;
73062306a36Sopenharmony_ci			goto out_reset;
73162306a36Sopenharmony_ci		}
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	err = context->result;
73562306a36Sopenharmony_ci	if (err) {
73662306a36Sopenharmony_ci		/* Since we do not want to have this error message always
73762306a36Sopenharmony_ci		 * displayed at driver start when there are ConnectX2 HCAs
73862306a36Sopenharmony_ci		 * on the host, we deprecate the error message for this
73962306a36Sopenharmony_ci		 * specific command/input_mod/opcode_mod/fw-status to be debug.
74062306a36Sopenharmony_ci		 */
74162306a36Sopenharmony_ci		if (op == MLX4_CMD_SET_PORT &&
74262306a36Sopenharmony_ci		    (in_modifier == 1 || in_modifier == 2) &&
74362306a36Sopenharmony_ci		    op_modifier == MLX4_SET_PORT_IB_OPCODE &&
74462306a36Sopenharmony_ci		    context->fw_status == CMD_STAT_BAD_SIZE)
74562306a36Sopenharmony_ci			mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
74662306a36Sopenharmony_ci				 op, context->fw_status);
74762306a36Sopenharmony_ci		else
74862306a36Sopenharmony_ci			mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
74962306a36Sopenharmony_ci				 op, context->fw_status);
75062306a36Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
75162306a36Sopenharmony_ci			err = mlx4_internal_err_ret_value(dev, op, op_modifier);
75262306a36Sopenharmony_ci		else if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
75362306a36Sopenharmony_ci			goto out_reset;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		goto out;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (out_is_imm)
75962306a36Sopenharmony_ci		*out_param = context->out_param;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ciout_reset:
76262306a36Sopenharmony_ci	if (err)
76362306a36Sopenharmony_ci		err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
76462306a36Sopenharmony_ciout:
76562306a36Sopenharmony_ci	spin_lock(&cmd->context_lock);
76662306a36Sopenharmony_ci	context->next = cmd->free_head;
76762306a36Sopenharmony_ci	cmd->free_head = context - cmd->context;
76862306a36Sopenharmony_ci	spin_unlock(&cmd->context_lock);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	up(&cmd->event_sem);
77162306a36Sopenharmony_ci	return err;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ciint __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
77562306a36Sopenharmony_ci	       int out_is_imm, u32 in_modifier, u8 op_modifier,
77662306a36Sopenharmony_ci	       u16 op, unsigned long timeout, int native)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	if (pci_channel_offline(dev->persist->pdev))
77962306a36Sopenharmony_ci		return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
78262306a36Sopenharmony_ci		int ret;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
78562306a36Sopenharmony_ci			return mlx4_internal_err_ret_value(dev, op,
78662306a36Sopenharmony_ci							  op_modifier);
78762306a36Sopenharmony_ci		down_read(&mlx4_priv(dev)->cmd.switch_sem);
78862306a36Sopenharmony_ci		if (mlx4_priv(dev)->cmd.use_events)
78962306a36Sopenharmony_ci			ret = mlx4_cmd_wait(dev, in_param, out_param,
79062306a36Sopenharmony_ci					    out_is_imm, in_modifier,
79162306a36Sopenharmony_ci					    op_modifier, op, timeout);
79262306a36Sopenharmony_ci		else
79362306a36Sopenharmony_ci			ret = mlx4_cmd_poll(dev, in_param, out_param,
79462306a36Sopenharmony_ci					    out_is_imm, in_modifier,
79562306a36Sopenharmony_ci					    op_modifier, op, timeout);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		up_read(&mlx4_priv(dev)->cmd.switch_sem);
79862306a36Sopenharmony_ci		return ret;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci	return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm,
80162306a36Sopenharmony_ci			      in_modifier, op_modifier, op, timeout);
80262306a36Sopenharmony_ci}
80362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__mlx4_cmd);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ciint mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL,
80962306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr,
81362306a36Sopenharmony_ci			   int slave, u64 slave_addr,
81462306a36Sopenharmony_ci			   int size, int is_read)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	u64 in_param;
81762306a36Sopenharmony_ci	u64 out_param;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	if ((slave_addr & 0xfff) | (master_addr & 0xfff) |
82062306a36Sopenharmony_ci	    (slave & ~0x7f) | (size & 0xff)) {
82162306a36Sopenharmony_ci		mlx4_err(dev, "Bad access mem params - slave_addr:0x%llx master_addr:0x%llx slave_id:%d size:%d\n",
82262306a36Sopenharmony_ci			 slave_addr, master_addr, slave, size);
82362306a36Sopenharmony_ci		return -EINVAL;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (is_read) {
82762306a36Sopenharmony_ci		in_param = (u64) slave | slave_addr;
82862306a36Sopenharmony_ci		out_param = (u64) dev->caps.function | master_addr;
82962306a36Sopenharmony_ci	} else {
83062306a36Sopenharmony_ci		in_param = (u64) dev->caps.function | master_addr;
83162306a36Sopenharmony_ci		out_param = (u64) slave | slave_addr;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return mlx4_cmd_imm(dev, in_param, &out_param, size, 0,
83562306a36Sopenharmony_ci			    MLX4_CMD_ACCESS_MEM,
83662306a36Sopenharmony_ci			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int query_pkey_block(struct mlx4_dev *dev, u8 port, u16 index, u16 *pkey,
84062306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
84162306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct ib_smp *in_mad = (struct ib_smp *)(inbox->buf);
84462306a36Sopenharmony_ci	struct ib_smp *out_mad = (struct ib_smp *)(outbox->buf);
84562306a36Sopenharmony_ci	int err;
84662306a36Sopenharmony_ci	int i;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (index & 0x1f)
84962306a36Sopenharmony_ci		return -EINVAL;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(index / 32);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
85462306a36Sopenharmony_ci			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
85562306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
85662306a36Sopenharmony_ci	if (err)
85762306a36Sopenharmony_ci		return err;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	for (i = 0; i < 32; ++i)
86062306a36Sopenharmony_ci		pkey[i] = be16_to_cpu(((__be16 *) out_mad->data)[i]);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	return err;
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic int get_full_pkey_table(struct mlx4_dev *dev, u8 port, u16 *table,
86662306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
86762306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	int i;
87062306a36Sopenharmony_ci	int err;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	for (i = 0; i < dev->caps.pkey_table_len[port]; i += 32) {
87362306a36Sopenharmony_ci		err = query_pkey_block(dev, port, i, table + i, inbox, outbox);
87462306a36Sopenharmony_ci		if (err)
87562306a36Sopenharmony_ci			return err;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	return 0;
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci#define PORT_CAPABILITY_LOCATION_IN_SMP 20
88162306a36Sopenharmony_ci#define PORT_STATE_OFFSET 32
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic enum ib_port_state vf_port_state(struct mlx4_dev *dev, int port, int vf)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	if (mlx4_get_slave_port_state(dev, vf, port) == SLAVE_PORT_UP)
88662306a36Sopenharmony_ci		return IB_PORT_ACTIVE;
88762306a36Sopenharmony_ci	else
88862306a36Sopenharmony_ci		return IB_PORT_DOWN;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
89262306a36Sopenharmony_ci				struct mlx4_vhcr *vhcr,
89362306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *inbox,
89462306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *outbox,
89562306a36Sopenharmony_ci				struct mlx4_cmd_info *cmd)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct ib_smp *smp = inbox->buf;
89862306a36Sopenharmony_ci	u32 index;
89962306a36Sopenharmony_ci	u8 port, slave_port;
90062306a36Sopenharmony_ci	u8 opcode_modifier;
90162306a36Sopenharmony_ci	u16 *table;
90262306a36Sopenharmony_ci	int err;
90362306a36Sopenharmony_ci	int vidx, pidx;
90462306a36Sopenharmony_ci	int network_view;
90562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
90662306a36Sopenharmony_ci	struct ib_smp *outsmp = outbox->buf;
90762306a36Sopenharmony_ci	__be16 *outtab = (__be16 *)(outsmp->data);
90862306a36Sopenharmony_ci	__be32 slave_cap_mask;
90962306a36Sopenharmony_ci	__be64 slave_node_guid;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	slave_port = vhcr->in_modifier;
91262306a36Sopenharmony_ci	port = mlx4_slave_convert_port(dev, slave, slave_port);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* network-view bit is for driver use only, and should not be passed to FW */
91562306a36Sopenharmony_ci	opcode_modifier = vhcr->op_modifier & ~0x8; /* clear netw view bit */
91662306a36Sopenharmony_ci	network_view = !!(vhcr->op_modifier & 0x8);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (smp->base_version == 1 &&
91962306a36Sopenharmony_ci	    smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
92062306a36Sopenharmony_ci	    smp->class_version == 1) {
92162306a36Sopenharmony_ci		/* host view is paravirtualized */
92262306a36Sopenharmony_ci		if (!network_view && smp->method == IB_MGMT_METHOD_GET) {
92362306a36Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_PKEY_TABLE) {
92462306a36Sopenharmony_ci				index = be32_to_cpu(smp->attr_mod);
92562306a36Sopenharmony_ci				if (port < 1 || port > dev->caps.num_ports)
92662306a36Sopenharmony_ci					return -EINVAL;
92762306a36Sopenharmony_ci				table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1,
92862306a36Sopenharmony_ci						sizeof(*table) * 32, GFP_KERNEL);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci				if (!table)
93162306a36Sopenharmony_ci					return -ENOMEM;
93262306a36Sopenharmony_ci				/* need to get the full pkey table because the paravirtualized
93362306a36Sopenharmony_ci				 * pkeys may be scattered among several pkey blocks.
93462306a36Sopenharmony_ci				 */
93562306a36Sopenharmony_ci				err = get_full_pkey_table(dev, port, table, inbox, outbox);
93662306a36Sopenharmony_ci				if (!err) {
93762306a36Sopenharmony_ci					for (vidx = index * 32; vidx < (index + 1) * 32; ++vidx) {
93862306a36Sopenharmony_ci						pidx = priv->virt2phys_pkey[slave][port - 1][vidx];
93962306a36Sopenharmony_ci						outtab[vidx % 32] = cpu_to_be16(table[pidx]);
94062306a36Sopenharmony_ci					}
94162306a36Sopenharmony_ci				}
94262306a36Sopenharmony_ci				kfree(table);
94362306a36Sopenharmony_ci				return err;
94462306a36Sopenharmony_ci			}
94562306a36Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_PORT_INFO) {
94662306a36Sopenharmony_ci				/*get the slave specific caps:*/
94762306a36Sopenharmony_ci				/*do the command */
94862306a36Sopenharmony_ci				smp->attr_mod = cpu_to_be32(port);
94962306a36Sopenharmony_ci				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
95062306a36Sopenharmony_ci					    port, opcode_modifier,
95162306a36Sopenharmony_ci					    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
95262306a36Sopenharmony_ci				/* modify the response for slaves */
95362306a36Sopenharmony_ci				if (!err && slave != mlx4_master_func_num(dev)) {
95462306a36Sopenharmony_ci					u8 *state = outsmp->data + PORT_STATE_OFFSET;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci					*state = (*state & 0xf0) | vf_port_state(dev, port, slave);
95762306a36Sopenharmony_ci					slave_cap_mask = priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
95862306a36Sopenharmony_ci					memcpy(outsmp->data + PORT_CAPABILITY_LOCATION_IN_SMP, &slave_cap_mask, 4);
95962306a36Sopenharmony_ci				}
96062306a36Sopenharmony_ci				return err;
96162306a36Sopenharmony_ci			}
96262306a36Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_GUID_INFO) {
96362306a36Sopenharmony_ci				__be64 guid = mlx4_get_admin_guid(dev, slave,
96462306a36Sopenharmony_ci								  port);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci				/* set the PF admin guid to the FW/HW burned
96762306a36Sopenharmony_ci				 * GUID, if it wasn't yet set
96862306a36Sopenharmony_ci				 */
96962306a36Sopenharmony_ci				if (slave == 0 && guid == 0) {
97062306a36Sopenharmony_ci					smp->attr_mod = 0;
97162306a36Sopenharmony_ci					err = mlx4_cmd_box(dev,
97262306a36Sopenharmony_ci							   inbox->dma,
97362306a36Sopenharmony_ci							   outbox->dma,
97462306a36Sopenharmony_ci							   vhcr->in_modifier,
97562306a36Sopenharmony_ci							   opcode_modifier,
97662306a36Sopenharmony_ci							   vhcr->op,
97762306a36Sopenharmony_ci							   MLX4_CMD_TIME_CLASS_C,
97862306a36Sopenharmony_ci							   MLX4_CMD_NATIVE);
97962306a36Sopenharmony_ci					if (err)
98062306a36Sopenharmony_ci						return err;
98162306a36Sopenharmony_ci					mlx4_set_admin_guid(dev,
98262306a36Sopenharmony_ci							    *(__be64 *)outsmp->
98362306a36Sopenharmony_ci							    data, slave, port);
98462306a36Sopenharmony_ci				} else {
98562306a36Sopenharmony_ci					memcpy(outsmp->data, &guid, 8);
98662306a36Sopenharmony_ci				}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci				/* clean all other gids */
98962306a36Sopenharmony_ci				memset(outsmp->data + 8, 0, 56);
99062306a36Sopenharmony_ci				return 0;
99162306a36Sopenharmony_ci			}
99262306a36Sopenharmony_ci			if (smp->attr_id == IB_SMP_ATTR_NODE_INFO) {
99362306a36Sopenharmony_ci				err = mlx4_cmd_box(dev, inbox->dma, outbox->dma,
99462306a36Sopenharmony_ci					     port, opcode_modifier,
99562306a36Sopenharmony_ci					     vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
99662306a36Sopenharmony_ci				if (!err) {
99762306a36Sopenharmony_ci					slave_node_guid =  mlx4_get_slave_node_guid(dev, slave);
99862306a36Sopenharmony_ci					memcpy(outsmp->data + 12, &slave_node_guid, 8);
99962306a36Sopenharmony_ci				}
100062306a36Sopenharmony_ci				return err;
100162306a36Sopenharmony_ci			}
100262306a36Sopenharmony_ci		}
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* Non-privileged VFs are only allowed "host" view LID-routed 'Get' MADs.
100662306a36Sopenharmony_ci	 * These are the MADs used by ib verbs (such as ib_query_gids).
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	if (slave != mlx4_master_func_num(dev) &&
100962306a36Sopenharmony_ci	    !mlx4_vf_smi_enabled(dev, slave, port)) {
101062306a36Sopenharmony_ci		if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
101162306a36Sopenharmony_ci		      smp->method == IB_MGMT_METHOD_GET) || network_view) {
101262306a36Sopenharmony_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",
101362306a36Sopenharmony_ci				 slave, smp->mgmt_class, smp->method,
101462306a36Sopenharmony_ci				 network_view ? "Network" : "Host",
101562306a36Sopenharmony_ci				 be16_to_cpu(smp->attr_id));
101662306a36Sopenharmony_ci			return -EPERM;
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	return mlx4_cmd_box(dev, inbox->dma, outbox->dma,
102162306a36Sopenharmony_ci				    vhcr->in_modifier, opcode_modifier,
102262306a36Sopenharmony_ci				    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave,
102662306a36Sopenharmony_ci		     struct mlx4_vhcr *vhcr,
102762306a36Sopenharmony_ci		     struct mlx4_cmd_mailbox *inbox,
102862306a36Sopenharmony_ci		     struct mlx4_cmd_mailbox *outbox,
102962306a36Sopenharmony_ci		     struct mlx4_cmd_info *cmd)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	return -EPERM;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ciint mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave,
103562306a36Sopenharmony_ci		     struct mlx4_vhcr *vhcr,
103662306a36Sopenharmony_ci		     struct mlx4_cmd_mailbox *inbox,
103762306a36Sopenharmony_ci		     struct mlx4_cmd_mailbox *outbox,
103862306a36Sopenharmony_ci		     struct mlx4_cmd_info *cmd)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	u64 in_param;
104162306a36Sopenharmony_ci	u64 out_param;
104262306a36Sopenharmony_ci	int err;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	in_param = cmd->has_inbox ? (u64) inbox->dma : vhcr->in_param;
104562306a36Sopenharmony_ci	out_param = cmd->has_outbox ? (u64) outbox->dma : vhcr->out_param;
104662306a36Sopenharmony_ci	if (cmd->encode_slave_id) {
104762306a36Sopenharmony_ci		in_param &= 0xffffffffffffff00ll;
104862306a36Sopenharmony_ci		in_param |= slave;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	err = __mlx4_cmd(dev, in_param, &out_param, cmd->out_is_imm,
105262306a36Sopenharmony_ci			 vhcr->in_modifier, vhcr->op_modifier, vhcr->op,
105362306a36Sopenharmony_ci			 MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	if (cmd->out_is_imm)
105662306a36Sopenharmony_ci		vhcr->out_param = out_param;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return err;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic struct mlx4_cmd_info cmd_info[] = {
106262306a36Sopenharmony_ci	{
106362306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_FW,
106462306a36Sopenharmony_ci		.has_inbox = false,
106562306a36Sopenharmony_ci		.has_outbox = true,
106662306a36Sopenharmony_ci		.out_is_imm = false,
106762306a36Sopenharmony_ci		.encode_slave_id = false,
106862306a36Sopenharmony_ci		.verify = NULL,
106962306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_FW_wrapper
107062306a36Sopenharmony_ci	},
107162306a36Sopenharmony_ci	{
107262306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_HCA,
107362306a36Sopenharmony_ci		.has_inbox = false,
107462306a36Sopenharmony_ci		.has_outbox = true,
107562306a36Sopenharmony_ci		.out_is_imm = false,
107662306a36Sopenharmony_ci		.encode_slave_id = false,
107762306a36Sopenharmony_ci		.verify = NULL,
107862306a36Sopenharmony_ci		.wrapper = NULL
107962306a36Sopenharmony_ci	},
108062306a36Sopenharmony_ci	{
108162306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_DEV_CAP,
108262306a36Sopenharmony_ci		.has_inbox = false,
108362306a36Sopenharmony_ci		.has_outbox = true,
108462306a36Sopenharmony_ci		.out_is_imm = false,
108562306a36Sopenharmony_ci		.encode_slave_id = false,
108662306a36Sopenharmony_ci		.verify = NULL,
108762306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_DEV_CAP_wrapper
108862306a36Sopenharmony_ci	},
108962306a36Sopenharmony_ci	{
109062306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_FUNC_CAP,
109162306a36Sopenharmony_ci		.has_inbox = false,
109262306a36Sopenharmony_ci		.has_outbox = true,
109362306a36Sopenharmony_ci		.out_is_imm = false,
109462306a36Sopenharmony_ci		.encode_slave_id = false,
109562306a36Sopenharmony_ci		.verify = NULL,
109662306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_FUNC_CAP_wrapper
109762306a36Sopenharmony_ci	},
109862306a36Sopenharmony_ci	{
109962306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_ADAPTER,
110062306a36Sopenharmony_ci		.has_inbox = false,
110162306a36Sopenharmony_ci		.has_outbox = true,
110262306a36Sopenharmony_ci		.out_is_imm = false,
110362306a36Sopenharmony_ci		.encode_slave_id = false,
110462306a36Sopenharmony_ci		.verify = NULL,
110562306a36Sopenharmony_ci		.wrapper = NULL
110662306a36Sopenharmony_ci	},
110762306a36Sopenharmony_ci	{
110862306a36Sopenharmony_ci		.opcode = MLX4_CMD_INIT_PORT,
110962306a36Sopenharmony_ci		.has_inbox = false,
111062306a36Sopenharmony_ci		.has_outbox = false,
111162306a36Sopenharmony_ci		.out_is_imm = false,
111262306a36Sopenharmony_ci		.encode_slave_id = false,
111362306a36Sopenharmony_ci		.verify = NULL,
111462306a36Sopenharmony_ci		.wrapper = mlx4_INIT_PORT_wrapper
111562306a36Sopenharmony_ci	},
111662306a36Sopenharmony_ci	{
111762306a36Sopenharmony_ci		.opcode = MLX4_CMD_CLOSE_PORT,
111862306a36Sopenharmony_ci		.has_inbox = false,
111962306a36Sopenharmony_ci		.has_outbox = false,
112062306a36Sopenharmony_ci		.out_is_imm  = false,
112162306a36Sopenharmony_ci		.encode_slave_id = false,
112262306a36Sopenharmony_ci		.verify = NULL,
112362306a36Sopenharmony_ci		.wrapper = mlx4_CLOSE_PORT_wrapper
112462306a36Sopenharmony_ci	},
112562306a36Sopenharmony_ci	{
112662306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_PORT,
112762306a36Sopenharmony_ci		.has_inbox = false,
112862306a36Sopenharmony_ci		.has_outbox = true,
112962306a36Sopenharmony_ci		.out_is_imm = false,
113062306a36Sopenharmony_ci		.encode_slave_id = false,
113162306a36Sopenharmony_ci		.verify = NULL,
113262306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_PORT_wrapper
113362306a36Sopenharmony_ci	},
113462306a36Sopenharmony_ci	{
113562306a36Sopenharmony_ci		.opcode = MLX4_CMD_SET_PORT,
113662306a36Sopenharmony_ci		.has_inbox = true,
113762306a36Sopenharmony_ci		.has_outbox = false,
113862306a36Sopenharmony_ci		.out_is_imm = false,
113962306a36Sopenharmony_ci		.encode_slave_id = false,
114062306a36Sopenharmony_ci		.verify = NULL,
114162306a36Sopenharmony_ci		.wrapper = mlx4_SET_PORT_wrapper
114262306a36Sopenharmony_ci	},
114362306a36Sopenharmony_ci	{
114462306a36Sopenharmony_ci		.opcode = MLX4_CMD_MAP_EQ,
114562306a36Sopenharmony_ci		.has_inbox = false,
114662306a36Sopenharmony_ci		.has_outbox = false,
114762306a36Sopenharmony_ci		.out_is_imm = false,
114862306a36Sopenharmony_ci		.encode_slave_id = false,
114962306a36Sopenharmony_ci		.verify = NULL,
115062306a36Sopenharmony_ci		.wrapper = mlx4_MAP_EQ_wrapper
115162306a36Sopenharmony_ci	},
115262306a36Sopenharmony_ci	{
115362306a36Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_EQ,
115462306a36Sopenharmony_ci		.has_inbox = true,
115562306a36Sopenharmony_ci		.has_outbox = false,
115662306a36Sopenharmony_ci		.out_is_imm = false,
115762306a36Sopenharmony_ci		.encode_slave_id = true,
115862306a36Sopenharmony_ci		.verify = NULL,
115962306a36Sopenharmony_ci		.wrapper = mlx4_SW2HW_EQ_wrapper
116062306a36Sopenharmony_ci	},
116162306a36Sopenharmony_ci	{
116262306a36Sopenharmony_ci		.opcode = MLX4_CMD_HW_HEALTH_CHECK,
116362306a36Sopenharmony_ci		.has_inbox = false,
116462306a36Sopenharmony_ci		.has_outbox = false,
116562306a36Sopenharmony_ci		.out_is_imm = false,
116662306a36Sopenharmony_ci		.encode_slave_id = false,
116762306a36Sopenharmony_ci		.verify = NULL,
116862306a36Sopenharmony_ci		.wrapper = NULL
116962306a36Sopenharmony_ci	},
117062306a36Sopenharmony_ci	{
117162306a36Sopenharmony_ci		.opcode = MLX4_CMD_NOP,
117262306a36Sopenharmony_ci		.has_inbox = false,
117362306a36Sopenharmony_ci		.has_outbox = false,
117462306a36Sopenharmony_ci		.out_is_imm = false,
117562306a36Sopenharmony_ci		.encode_slave_id = false,
117662306a36Sopenharmony_ci		.verify = NULL,
117762306a36Sopenharmony_ci		.wrapper = NULL
117862306a36Sopenharmony_ci	},
117962306a36Sopenharmony_ci	{
118062306a36Sopenharmony_ci		.opcode = MLX4_CMD_CONFIG_DEV,
118162306a36Sopenharmony_ci		.has_inbox = false,
118262306a36Sopenharmony_ci		.has_outbox = true,
118362306a36Sopenharmony_ci		.out_is_imm = false,
118462306a36Sopenharmony_ci		.encode_slave_id = false,
118562306a36Sopenharmony_ci		.verify = NULL,
118662306a36Sopenharmony_ci		.wrapper = mlx4_CONFIG_DEV_wrapper
118762306a36Sopenharmony_ci	},
118862306a36Sopenharmony_ci	{
118962306a36Sopenharmony_ci		.opcode = MLX4_CMD_ALLOC_RES,
119062306a36Sopenharmony_ci		.has_inbox = false,
119162306a36Sopenharmony_ci		.has_outbox = false,
119262306a36Sopenharmony_ci		.out_is_imm = true,
119362306a36Sopenharmony_ci		.encode_slave_id = false,
119462306a36Sopenharmony_ci		.verify = NULL,
119562306a36Sopenharmony_ci		.wrapper = mlx4_ALLOC_RES_wrapper
119662306a36Sopenharmony_ci	},
119762306a36Sopenharmony_ci	{
119862306a36Sopenharmony_ci		.opcode = MLX4_CMD_FREE_RES,
119962306a36Sopenharmony_ci		.has_inbox = false,
120062306a36Sopenharmony_ci		.has_outbox = false,
120162306a36Sopenharmony_ci		.out_is_imm = false,
120262306a36Sopenharmony_ci		.encode_slave_id = false,
120362306a36Sopenharmony_ci		.verify = NULL,
120462306a36Sopenharmony_ci		.wrapper = mlx4_FREE_RES_wrapper
120562306a36Sopenharmony_ci	},
120662306a36Sopenharmony_ci	{
120762306a36Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_MPT,
120862306a36Sopenharmony_ci		.has_inbox = true,
120962306a36Sopenharmony_ci		.has_outbox = false,
121062306a36Sopenharmony_ci		.out_is_imm = false,
121162306a36Sopenharmony_ci		.encode_slave_id = true,
121262306a36Sopenharmony_ci		.verify = NULL,
121362306a36Sopenharmony_ci		.wrapper = mlx4_SW2HW_MPT_wrapper
121462306a36Sopenharmony_ci	},
121562306a36Sopenharmony_ci	{
121662306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_MPT,
121762306a36Sopenharmony_ci		.has_inbox = false,
121862306a36Sopenharmony_ci		.has_outbox = true,
121962306a36Sopenharmony_ci		.out_is_imm = false,
122062306a36Sopenharmony_ci		.encode_slave_id = false,
122162306a36Sopenharmony_ci		.verify = NULL,
122262306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_MPT_wrapper
122362306a36Sopenharmony_ci	},
122462306a36Sopenharmony_ci	{
122562306a36Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_MPT,
122662306a36Sopenharmony_ci		.has_inbox = false,
122762306a36Sopenharmony_ci		.has_outbox = false,
122862306a36Sopenharmony_ci		.out_is_imm = false,
122962306a36Sopenharmony_ci		.encode_slave_id = false,
123062306a36Sopenharmony_ci		.verify = NULL,
123162306a36Sopenharmony_ci		.wrapper = mlx4_HW2SW_MPT_wrapper
123262306a36Sopenharmony_ci	},
123362306a36Sopenharmony_ci	{
123462306a36Sopenharmony_ci		.opcode = MLX4_CMD_READ_MTT,
123562306a36Sopenharmony_ci		.has_inbox = false,
123662306a36Sopenharmony_ci		.has_outbox = true,
123762306a36Sopenharmony_ci		.out_is_imm = false,
123862306a36Sopenharmony_ci		.encode_slave_id = false,
123962306a36Sopenharmony_ci		.verify = NULL,
124062306a36Sopenharmony_ci		.wrapper = NULL
124162306a36Sopenharmony_ci	},
124262306a36Sopenharmony_ci	{
124362306a36Sopenharmony_ci		.opcode = MLX4_CMD_WRITE_MTT,
124462306a36Sopenharmony_ci		.has_inbox = true,
124562306a36Sopenharmony_ci		.has_outbox = false,
124662306a36Sopenharmony_ci		.out_is_imm = false,
124762306a36Sopenharmony_ci		.encode_slave_id = false,
124862306a36Sopenharmony_ci		.verify = NULL,
124962306a36Sopenharmony_ci		.wrapper = mlx4_WRITE_MTT_wrapper
125062306a36Sopenharmony_ci	},
125162306a36Sopenharmony_ci	{
125262306a36Sopenharmony_ci		.opcode = MLX4_CMD_SYNC_TPT,
125362306a36Sopenharmony_ci		.has_inbox = true,
125462306a36Sopenharmony_ci		.has_outbox = false,
125562306a36Sopenharmony_ci		.out_is_imm = false,
125662306a36Sopenharmony_ci		.encode_slave_id = false,
125762306a36Sopenharmony_ci		.verify = NULL,
125862306a36Sopenharmony_ci		.wrapper = NULL
125962306a36Sopenharmony_ci	},
126062306a36Sopenharmony_ci	{
126162306a36Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_EQ,
126262306a36Sopenharmony_ci		.has_inbox = false,
126362306a36Sopenharmony_ci		.has_outbox = false,
126462306a36Sopenharmony_ci		.out_is_imm = false,
126562306a36Sopenharmony_ci		.encode_slave_id = true,
126662306a36Sopenharmony_ci		.verify = NULL,
126762306a36Sopenharmony_ci		.wrapper = mlx4_HW2SW_EQ_wrapper
126862306a36Sopenharmony_ci	},
126962306a36Sopenharmony_ci	{
127062306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_EQ,
127162306a36Sopenharmony_ci		.has_inbox = false,
127262306a36Sopenharmony_ci		.has_outbox = true,
127362306a36Sopenharmony_ci		.out_is_imm = false,
127462306a36Sopenharmony_ci		.encode_slave_id = true,
127562306a36Sopenharmony_ci		.verify = NULL,
127662306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_EQ_wrapper
127762306a36Sopenharmony_ci	},
127862306a36Sopenharmony_ci	{
127962306a36Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_CQ,
128062306a36Sopenharmony_ci		.has_inbox = true,
128162306a36Sopenharmony_ci		.has_outbox = false,
128262306a36Sopenharmony_ci		.out_is_imm = false,
128362306a36Sopenharmony_ci		.encode_slave_id = true,
128462306a36Sopenharmony_ci		.verify = NULL,
128562306a36Sopenharmony_ci		.wrapper = mlx4_SW2HW_CQ_wrapper
128662306a36Sopenharmony_ci	},
128762306a36Sopenharmony_ci	{
128862306a36Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_CQ,
128962306a36Sopenharmony_ci		.has_inbox = false,
129062306a36Sopenharmony_ci		.has_outbox = false,
129162306a36Sopenharmony_ci		.out_is_imm = false,
129262306a36Sopenharmony_ci		.encode_slave_id = false,
129362306a36Sopenharmony_ci		.verify = NULL,
129462306a36Sopenharmony_ci		.wrapper = mlx4_HW2SW_CQ_wrapper
129562306a36Sopenharmony_ci	},
129662306a36Sopenharmony_ci	{
129762306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_CQ,
129862306a36Sopenharmony_ci		.has_inbox = false,
129962306a36Sopenharmony_ci		.has_outbox = true,
130062306a36Sopenharmony_ci		.out_is_imm = false,
130162306a36Sopenharmony_ci		.encode_slave_id = false,
130262306a36Sopenharmony_ci		.verify = NULL,
130362306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_CQ_wrapper
130462306a36Sopenharmony_ci	},
130562306a36Sopenharmony_ci	{
130662306a36Sopenharmony_ci		.opcode = MLX4_CMD_MODIFY_CQ,
130762306a36Sopenharmony_ci		.has_inbox = true,
130862306a36Sopenharmony_ci		.has_outbox = false,
130962306a36Sopenharmony_ci		.out_is_imm = true,
131062306a36Sopenharmony_ci		.encode_slave_id = false,
131162306a36Sopenharmony_ci		.verify = NULL,
131262306a36Sopenharmony_ci		.wrapper = mlx4_MODIFY_CQ_wrapper
131362306a36Sopenharmony_ci	},
131462306a36Sopenharmony_ci	{
131562306a36Sopenharmony_ci		.opcode = MLX4_CMD_SW2HW_SRQ,
131662306a36Sopenharmony_ci		.has_inbox = true,
131762306a36Sopenharmony_ci		.has_outbox = false,
131862306a36Sopenharmony_ci		.out_is_imm = false,
131962306a36Sopenharmony_ci		.encode_slave_id = true,
132062306a36Sopenharmony_ci		.verify = NULL,
132162306a36Sopenharmony_ci		.wrapper = mlx4_SW2HW_SRQ_wrapper
132262306a36Sopenharmony_ci	},
132362306a36Sopenharmony_ci	{
132462306a36Sopenharmony_ci		.opcode = MLX4_CMD_HW2SW_SRQ,
132562306a36Sopenharmony_ci		.has_inbox = false,
132662306a36Sopenharmony_ci		.has_outbox = false,
132762306a36Sopenharmony_ci		.out_is_imm = false,
132862306a36Sopenharmony_ci		.encode_slave_id = false,
132962306a36Sopenharmony_ci		.verify = NULL,
133062306a36Sopenharmony_ci		.wrapper = mlx4_HW2SW_SRQ_wrapper
133162306a36Sopenharmony_ci	},
133262306a36Sopenharmony_ci	{
133362306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_SRQ,
133462306a36Sopenharmony_ci		.has_inbox = false,
133562306a36Sopenharmony_ci		.has_outbox = true,
133662306a36Sopenharmony_ci		.out_is_imm = false,
133762306a36Sopenharmony_ci		.encode_slave_id = false,
133862306a36Sopenharmony_ci		.verify = NULL,
133962306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_SRQ_wrapper
134062306a36Sopenharmony_ci	},
134162306a36Sopenharmony_ci	{
134262306a36Sopenharmony_ci		.opcode = MLX4_CMD_ARM_SRQ,
134362306a36Sopenharmony_ci		.has_inbox = false,
134462306a36Sopenharmony_ci		.has_outbox = false,
134562306a36Sopenharmony_ci		.out_is_imm = false,
134662306a36Sopenharmony_ci		.encode_slave_id = false,
134762306a36Sopenharmony_ci		.verify = NULL,
134862306a36Sopenharmony_ci		.wrapper = mlx4_ARM_SRQ_wrapper
134962306a36Sopenharmony_ci	},
135062306a36Sopenharmony_ci	{
135162306a36Sopenharmony_ci		.opcode = MLX4_CMD_RST2INIT_QP,
135262306a36Sopenharmony_ci		.has_inbox = true,
135362306a36Sopenharmony_ci		.has_outbox = false,
135462306a36Sopenharmony_ci		.out_is_imm = false,
135562306a36Sopenharmony_ci		.encode_slave_id = true,
135662306a36Sopenharmony_ci		.verify = NULL,
135762306a36Sopenharmony_ci		.wrapper = mlx4_RST2INIT_QP_wrapper
135862306a36Sopenharmony_ci	},
135962306a36Sopenharmony_ci	{
136062306a36Sopenharmony_ci		.opcode = MLX4_CMD_INIT2INIT_QP,
136162306a36Sopenharmony_ci		.has_inbox = true,
136262306a36Sopenharmony_ci		.has_outbox = false,
136362306a36Sopenharmony_ci		.out_is_imm = false,
136462306a36Sopenharmony_ci		.encode_slave_id = false,
136562306a36Sopenharmony_ci		.verify = NULL,
136662306a36Sopenharmony_ci		.wrapper = mlx4_INIT2INIT_QP_wrapper
136762306a36Sopenharmony_ci	},
136862306a36Sopenharmony_ci	{
136962306a36Sopenharmony_ci		.opcode = MLX4_CMD_INIT2RTR_QP,
137062306a36Sopenharmony_ci		.has_inbox = true,
137162306a36Sopenharmony_ci		.has_outbox = false,
137262306a36Sopenharmony_ci		.out_is_imm = false,
137362306a36Sopenharmony_ci		.encode_slave_id = false,
137462306a36Sopenharmony_ci		.verify = NULL,
137562306a36Sopenharmony_ci		.wrapper = mlx4_INIT2RTR_QP_wrapper
137662306a36Sopenharmony_ci	},
137762306a36Sopenharmony_ci	{
137862306a36Sopenharmony_ci		.opcode = MLX4_CMD_RTR2RTS_QP,
137962306a36Sopenharmony_ci		.has_inbox = true,
138062306a36Sopenharmony_ci		.has_outbox = false,
138162306a36Sopenharmony_ci		.out_is_imm = false,
138262306a36Sopenharmony_ci		.encode_slave_id = false,
138362306a36Sopenharmony_ci		.verify = NULL,
138462306a36Sopenharmony_ci		.wrapper = mlx4_RTR2RTS_QP_wrapper
138562306a36Sopenharmony_ci	},
138662306a36Sopenharmony_ci	{
138762306a36Sopenharmony_ci		.opcode = MLX4_CMD_RTS2RTS_QP,
138862306a36Sopenharmony_ci		.has_inbox = true,
138962306a36Sopenharmony_ci		.has_outbox = false,
139062306a36Sopenharmony_ci		.out_is_imm = false,
139162306a36Sopenharmony_ci		.encode_slave_id = false,
139262306a36Sopenharmony_ci		.verify = NULL,
139362306a36Sopenharmony_ci		.wrapper = mlx4_RTS2RTS_QP_wrapper
139462306a36Sopenharmony_ci	},
139562306a36Sopenharmony_ci	{
139662306a36Sopenharmony_ci		.opcode = MLX4_CMD_SQERR2RTS_QP,
139762306a36Sopenharmony_ci		.has_inbox = true,
139862306a36Sopenharmony_ci		.has_outbox = false,
139962306a36Sopenharmony_ci		.out_is_imm = false,
140062306a36Sopenharmony_ci		.encode_slave_id = false,
140162306a36Sopenharmony_ci		.verify = NULL,
140262306a36Sopenharmony_ci		.wrapper = mlx4_SQERR2RTS_QP_wrapper
140362306a36Sopenharmony_ci	},
140462306a36Sopenharmony_ci	{
140562306a36Sopenharmony_ci		.opcode = MLX4_CMD_2ERR_QP,
140662306a36Sopenharmony_ci		.has_inbox = false,
140762306a36Sopenharmony_ci		.has_outbox = false,
140862306a36Sopenharmony_ci		.out_is_imm = false,
140962306a36Sopenharmony_ci		.encode_slave_id = false,
141062306a36Sopenharmony_ci		.verify = NULL,
141162306a36Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
141262306a36Sopenharmony_ci	},
141362306a36Sopenharmony_ci	{
141462306a36Sopenharmony_ci		.opcode = MLX4_CMD_RTS2SQD_QP,
141562306a36Sopenharmony_ci		.has_inbox = false,
141662306a36Sopenharmony_ci		.has_outbox = false,
141762306a36Sopenharmony_ci		.out_is_imm = false,
141862306a36Sopenharmony_ci		.encode_slave_id = false,
141962306a36Sopenharmony_ci		.verify = NULL,
142062306a36Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
142162306a36Sopenharmony_ci	},
142262306a36Sopenharmony_ci	{
142362306a36Sopenharmony_ci		.opcode = MLX4_CMD_SQD2SQD_QP,
142462306a36Sopenharmony_ci		.has_inbox = true,
142562306a36Sopenharmony_ci		.has_outbox = false,
142662306a36Sopenharmony_ci		.out_is_imm = false,
142762306a36Sopenharmony_ci		.encode_slave_id = false,
142862306a36Sopenharmony_ci		.verify = NULL,
142962306a36Sopenharmony_ci		.wrapper = mlx4_SQD2SQD_QP_wrapper
143062306a36Sopenharmony_ci	},
143162306a36Sopenharmony_ci	{
143262306a36Sopenharmony_ci		.opcode = MLX4_CMD_SQD2RTS_QP,
143362306a36Sopenharmony_ci		.has_inbox = true,
143462306a36Sopenharmony_ci		.has_outbox = false,
143562306a36Sopenharmony_ci		.out_is_imm = false,
143662306a36Sopenharmony_ci		.encode_slave_id = false,
143762306a36Sopenharmony_ci		.verify = NULL,
143862306a36Sopenharmony_ci		.wrapper = mlx4_SQD2RTS_QP_wrapper
143962306a36Sopenharmony_ci	},
144062306a36Sopenharmony_ci	{
144162306a36Sopenharmony_ci		.opcode = MLX4_CMD_2RST_QP,
144262306a36Sopenharmony_ci		.has_inbox = false,
144362306a36Sopenharmony_ci		.has_outbox = false,
144462306a36Sopenharmony_ci		.out_is_imm = false,
144562306a36Sopenharmony_ci		.encode_slave_id = false,
144662306a36Sopenharmony_ci		.verify = NULL,
144762306a36Sopenharmony_ci		.wrapper = mlx4_2RST_QP_wrapper
144862306a36Sopenharmony_ci	},
144962306a36Sopenharmony_ci	{
145062306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_QP,
145162306a36Sopenharmony_ci		.has_inbox = false,
145262306a36Sopenharmony_ci		.has_outbox = true,
145362306a36Sopenharmony_ci		.out_is_imm = false,
145462306a36Sopenharmony_ci		.encode_slave_id = false,
145562306a36Sopenharmony_ci		.verify = NULL,
145662306a36Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
145762306a36Sopenharmony_ci	},
145862306a36Sopenharmony_ci	{
145962306a36Sopenharmony_ci		.opcode = MLX4_CMD_SUSPEND_QP,
146062306a36Sopenharmony_ci		.has_inbox = false,
146162306a36Sopenharmony_ci		.has_outbox = false,
146262306a36Sopenharmony_ci		.out_is_imm = false,
146362306a36Sopenharmony_ci		.encode_slave_id = false,
146462306a36Sopenharmony_ci		.verify = NULL,
146562306a36Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
146662306a36Sopenharmony_ci	},
146762306a36Sopenharmony_ci	{
146862306a36Sopenharmony_ci		.opcode = MLX4_CMD_UNSUSPEND_QP,
146962306a36Sopenharmony_ci		.has_inbox = false,
147062306a36Sopenharmony_ci		.has_outbox = false,
147162306a36Sopenharmony_ci		.out_is_imm = false,
147262306a36Sopenharmony_ci		.encode_slave_id = false,
147362306a36Sopenharmony_ci		.verify = NULL,
147462306a36Sopenharmony_ci		.wrapper = mlx4_GEN_QP_wrapper
147562306a36Sopenharmony_ci	},
147662306a36Sopenharmony_ci	{
147762306a36Sopenharmony_ci		.opcode = MLX4_CMD_UPDATE_QP,
147862306a36Sopenharmony_ci		.has_inbox = true,
147962306a36Sopenharmony_ci		.has_outbox = false,
148062306a36Sopenharmony_ci		.out_is_imm = false,
148162306a36Sopenharmony_ci		.encode_slave_id = false,
148262306a36Sopenharmony_ci		.verify = NULL,
148362306a36Sopenharmony_ci		.wrapper = mlx4_UPDATE_QP_wrapper
148462306a36Sopenharmony_ci	},
148562306a36Sopenharmony_ci	{
148662306a36Sopenharmony_ci		.opcode = MLX4_CMD_GET_OP_REQ,
148762306a36Sopenharmony_ci		.has_inbox = false,
148862306a36Sopenharmony_ci		.has_outbox = false,
148962306a36Sopenharmony_ci		.out_is_imm = false,
149062306a36Sopenharmony_ci		.encode_slave_id = false,
149162306a36Sopenharmony_ci		.verify = NULL,
149262306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
149362306a36Sopenharmony_ci	},
149462306a36Sopenharmony_ci	{
149562306a36Sopenharmony_ci		.opcode = MLX4_CMD_ALLOCATE_VPP,
149662306a36Sopenharmony_ci		.has_inbox = false,
149762306a36Sopenharmony_ci		.has_outbox = true,
149862306a36Sopenharmony_ci		.out_is_imm = false,
149962306a36Sopenharmony_ci		.encode_slave_id = false,
150062306a36Sopenharmony_ci		.verify = NULL,
150162306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
150262306a36Sopenharmony_ci	},
150362306a36Sopenharmony_ci	{
150462306a36Sopenharmony_ci		.opcode = MLX4_CMD_SET_VPORT_QOS,
150562306a36Sopenharmony_ci		.has_inbox = false,
150662306a36Sopenharmony_ci		.has_outbox = true,
150762306a36Sopenharmony_ci		.out_is_imm = false,
150862306a36Sopenharmony_ci		.encode_slave_id = false,
150962306a36Sopenharmony_ci		.verify = NULL,
151062306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
151162306a36Sopenharmony_ci	},
151262306a36Sopenharmony_ci	{
151362306a36Sopenharmony_ci		.opcode = MLX4_CMD_CONF_SPECIAL_QP,
151462306a36Sopenharmony_ci		.has_inbox = false,
151562306a36Sopenharmony_ci		.has_outbox = false,
151662306a36Sopenharmony_ci		.out_is_imm = false,
151762306a36Sopenharmony_ci		.encode_slave_id = false,
151862306a36Sopenharmony_ci		.verify = NULL, /* XXX verify: only demux can do this */
151962306a36Sopenharmony_ci		.wrapper = NULL
152062306a36Sopenharmony_ci	},
152162306a36Sopenharmony_ci	{
152262306a36Sopenharmony_ci		.opcode = MLX4_CMD_MAD_IFC,
152362306a36Sopenharmony_ci		.has_inbox = true,
152462306a36Sopenharmony_ci		.has_outbox = true,
152562306a36Sopenharmony_ci		.out_is_imm = false,
152662306a36Sopenharmony_ci		.encode_slave_id = false,
152762306a36Sopenharmony_ci		.verify = NULL,
152862306a36Sopenharmony_ci		.wrapper = mlx4_MAD_IFC_wrapper
152962306a36Sopenharmony_ci	},
153062306a36Sopenharmony_ci	{
153162306a36Sopenharmony_ci		.opcode = MLX4_CMD_MAD_DEMUX,
153262306a36Sopenharmony_ci		.has_inbox = false,
153362306a36Sopenharmony_ci		.has_outbox = false,
153462306a36Sopenharmony_ci		.out_is_imm = false,
153562306a36Sopenharmony_ci		.encode_slave_id = false,
153662306a36Sopenharmony_ci		.verify = NULL,
153762306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
153862306a36Sopenharmony_ci	},
153962306a36Sopenharmony_ci	{
154062306a36Sopenharmony_ci		.opcode = MLX4_CMD_QUERY_IF_STAT,
154162306a36Sopenharmony_ci		.has_inbox = false,
154262306a36Sopenharmony_ci		.has_outbox = true,
154362306a36Sopenharmony_ci		.out_is_imm = false,
154462306a36Sopenharmony_ci		.encode_slave_id = false,
154562306a36Sopenharmony_ci		.verify = NULL,
154662306a36Sopenharmony_ci		.wrapper = mlx4_QUERY_IF_STAT_wrapper
154762306a36Sopenharmony_ci	},
154862306a36Sopenharmony_ci	{
154962306a36Sopenharmony_ci		.opcode = MLX4_CMD_ACCESS_REG,
155062306a36Sopenharmony_ci		.has_inbox = true,
155162306a36Sopenharmony_ci		.has_outbox = true,
155262306a36Sopenharmony_ci		.out_is_imm = false,
155362306a36Sopenharmony_ci		.encode_slave_id = false,
155462306a36Sopenharmony_ci		.verify = NULL,
155562306a36Sopenharmony_ci		.wrapper = mlx4_ACCESS_REG_wrapper,
155662306a36Sopenharmony_ci	},
155762306a36Sopenharmony_ci	{
155862306a36Sopenharmony_ci		.opcode = MLX4_CMD_CONGESTION_CTRL_OPCODE,
155962306a36Sopenharmony_ci		.has_inbox = false,
156062306a36Sopenharmony_ci		.has_outbox = false,
156162306a36Sopenharmony_ci		.out_is_imm = false,
156262306a36Sopenharmony_ci		.encode_slave_id = false,
156362306a36Sopenharmony_ci		.verify = NULL,
156462306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper,
156562306a36Sopenharmony_ci	},
156662306a36Sopenharmony_ci	/* Native multicast commands are not available for guests */
156762306a36Sopenharmony_ci	{
156862306a36Sopenharmony_ci		.opcode = MLX4_CMD_QP_ATTACH,
156962306a36Sopenharmony_ci		.has_inbox = true,
157062306a36Sopenharmony_ci		.has_outbox = false,
157162306a36Sopenharmony_ci		.out_is_imm = false,
157262306a36Sopenharmony_ci		.encode_slave_id = false,
157362306a36Sopenharmony_ci		.verify = NULL,
157462306a36Sopenharmony_ci		.wrapper = mlx4_QP_ATTACH_wrapper
157562306a36Sopenharmony_ci	},
157662306a36Sopenharmony_ci	{
157762306a36Sopenharmony_ci		.opcode = MLX4_CMD_PROMISC,
157862306a36Sopenharmony_ci		.has_inbox = false,
157962306a36Sopenharmony_ci		.has_outbox = false,
158062306a36Sopenharmony_ci		.out_is_imm = false,
158162306a36Sopenharmony_ci		.encode_slave_id = false,
158262306a36Sopenharmony_ci		.verify = NULL,
158362306a36Sopenharmony_ci		.wrapper = mlx4_PROMISC_wrapper
158462306a36Sopenharmony_ci	},
158562306a36Sopenharmony_ci	/* Ethernet specific commands */
158662306a36Sopenharmony_ci	{
158762306a36Sopenharmony_ci		.opcode = MLX4_CMD_SET_VLAN_FLTR,
158862306a36Sopenharmony_ci		.has_inbox = true,
158962306a36Sopenharmony_ci		.has_outbox = false,
159062306a36Sopenharmony_ci		.out_is_imm = false,
159162306a36Sopenharmony_ci		.encode_slave_id = false,
159262306a36Sopenharmony_ci		.verify = NULL,
159362306a36Sopenharmony_ci		.wrapper = mlx4_SET_VLAN_FLTR_wrapper
159462306a36Sopenharmony_ci	},
159562306a36Sopenharmony_ci	{
159662306a36Sopenharmony_ci		.opcode = MLX4_CMD_SET_MCAST_FLTR,
159762306a36Sopenharmony_ci		.has_inbox = false,
159862306a36Sopenharmony_ci		.has_outbox = false,
159962306a36Sopenharmony_ci		.out_is_imm = false,
160062306a36Sopenharmony_ci		.encode_slave_id = false,
160162306a36Sopenharmony_ci		.verify = NULL,
160262306a36Sopenharmony_ci		.wrapper = mlx4_SET_MCAST_FLTR_wrapper
160362306a36Sopenharmony_ci	},
160462306a36Sopenharmony_ci	{
160562306a36Sopenharmony_ci		.opcode = MLX4_CMD_DUMP_ETH_STATS,
160662306a36Sopenharmony_ci		.has_inbox = false,
160762306a36Sopenharmony_ci		.has_outbox = true,
160862306a36Sopenharmony_ci		.out_is_imm = false,
160962306a36Sopenharmony_ci		.encode_slave_id = false,
161062306a36Sopenharmony_ci		.verify = NULL,
161162306a36Sopenharmony_ci		.wrapper = mlx4_DUMP_ETH_STATS_wrapper
161262306a36Sopenharmony_ci	},
161362306a36Sopenharmony_ci	{
161462306a36Sopenharmony_ci		.opcode = MLX4_CMD_INFORM_FLR_DONE,
161562306a36Sopenharmony_ci		.has_inbox = false,
161662306a36Sopenharmony_ci		.has_outbox = false,
161762306a36Sopenharmony_ci		.out_is_imm = false,
161862306a36Sopenharmony_ci		.encode_slave_id = false,
161962306a36Sopenharmony_ci		.verify = NULL,
162062306a36Sopenharmony_ci		.wrapper = NULL
162162306a36Sopenharmony_ci	},
162262306a36Sopenharmony_ci	/* flow steering commands */
162362306a36Sopenharmony_ci	{
162462306a36Sopenharmony_ci		.opcode = MLX4_QP_FLOW_STEERING_ATTACH,
162562306a36Sopenharmony_ci		.has_inbox = true,
162662306a36Sopenharmony_ci		.has_outbox = false,
162762306a36Sopenharmony_ci		.out_is_imm = true,
162862306a36Sopenharmony_ci		.encode_slave_id = false,
162962306a36Sopenharmony_ci		.verify = NULL,
163062306a36Sopenharmony_ci		.wrapper = mlx4_QP_FLOW_STEERING_ATTACH_wrapper
163162306a36Sopenharmony_ci	},
163262306a36Sopenharmony_ci	{
163362306a36Sopenharmony_ci		.opcode = MLX4_QP_FLOW_STEERING_DETACH,
163462306a36Sopenharmony_ci		.has_inbox = false,
163562306a36Sopenharmony_ci		.has_outbox = false,
163662306a36Sopenharmony_ci		.out_is_imm = false,
163762306a36Sopenharmony_ci		.encode_slave_id = false,
163862306a36Sopenharmony_ci		.verify = NULL,
163962306a36Sopenharmony_ci		.wrapper = mlx4_QP_FLOW_STEERING_DETACH_wrapper
164062306a36Sopenharmony_ci	},
164162306a36Sopenharmony_ci	{
164262306a36Sopenharmony_ci		.opcode = MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
164362306a36Sopenharmony_ci		.has_inbox = false,
164462306a36Sopenharmony_ci		.has_outbox = false,
164562306a36Sopenharmony_ci		.out_is_imm = false,
164662306a36Sopenharmony_ci		.encode_slave_id = false,
164762306a36Sopenharmony_ci		.verify = NULL,
164862306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
164962306a36Sopenharmony_ci	},
165062306a36Sopenharmony_ci	{
165162306a36Sopenharmony_ci		.opcode = MLX4_CMD_VIRT_PORT_MAP,
165262306a36Sopenharmony_ci		.has_inbox = false,
165362306a36Sopenharmony_ci		.has_outbox = false,
165462306a36Sopenharmony_ci		.out_is_imm = false,
165562306a36Sopenharmony_ci		.encode_slave_id = false,
165662306a36Sopenharmony_ci		.verify = NULL,
165762306a36Sopenharmony_ci		.wrapper = mlx4_CMD_EPERM_wrapper
165862306a36Sopenharmony_ci	},
165962306a36Sopenharmony_ci};
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
166262306a36Sopenharmony_ci				    struct mlx4_vhcr_cmd *in_vhcr)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
166562306a36Sopenharmony_ci	struct mlx4_cmd_info *cmd = NULL;
166662306a36Sopenharmony_ci	struct mlx4_vhcr_cmd *vhcr_cmd = in_vhcr ? in_vhcr : priv->mfunc.vhcr;
166762306a36Sopenharmony_ci	struct mlx4_vhcr *vhcr;
166862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *inbox = NULL;
166962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *outbox = NULL;
167062306a36Sopenharmony_ci	u64 in_param;
167162306a36Sopenharmony_ci	u64 out_param;
167262306a36Sopenharmony_ci	int ret = 0;
167362306a36Sopenharmony_ci	int i;
167462306a36Sopenharmony_ci	int err = 0;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	/* Create sw representation of Virtual HCR */
167762306a36Sopenharmony_ci	vhcr = kzalloc(sizeof(struct mlx4_vhcr), GFP_KERNEL);
167862306a36Sopenharmony_ci	if (!vhcr)
167962306a36Sopenharmony_ci		return -ENOMEM;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* DMA in the vHCR */
168262306a36Sopenharmony_ci	if (!in_vhcr) {
168362306a36Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
168462306a36Sopenharmony_ci				      priv->mfunc.master.slave_state[slave].vhcr_dma,
168562306a36Sopenharmony_ci				      ALIGN(sizeof(struct mlx4_vhcr_cmd),
168662306a36Sopenharmony_ci					    MLX4_ACCESS_MEM_ALIGN), 1);
168762306a36Sopenharmony_ci		if (ret) {
168862306a36Sopenharmony_ci			if (!(dev->persist->state &
168962306a36Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
169062306a36Sopenharmony_ci				mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n",
169162306a36Sopenharmony_ci					 __func__, ret);
169262306a36Sopenharmony_ci			kfree(vhcr);
169362306a36Sopenharmony_ci			return ret;
169462306a36Sopenharmony_ci		}
169562306a36Sopenharmony_ci	}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	/* Fill SW VHCR fields */
169862306a36Sopenharmony_ci	vhcr->in_param = be64_to_cpu(vhcr_cmd->in_param);
169962306a36Sopenharmony_ci	vhcr->out_param = be64_to_cpu(vhcr_cmd->out_param);
170062306a36Sopenharmony_ci	vhcr->in_modifier = be32_to_cpu(vhcr_cmd->in_modifier);
170162306a36Sopenharmony_ci	vhcr->token = be16_to_cpu(vhcr_cmd->token);
170262306a36Sopenharmony_ci	vhcr->op = be16_to_cpu(vhcr_cmd->opcode) & 0xfff;
170362306a36Sopenharmony_ci	vhcr->op_modifier = (u8) (be16_to_cpu(vhcr_cmd->opcode) >> 12);
170462306a36Sopenharmony_ci	vhcr->e_bit = vhcr_cmd->flags & (1 << 6);
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	/* Lookup command */
170762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cmd_info); ++i) {
170862306a36Sopenharmony_ci		if (vhcr->op == cmd_info[i].opcode) {
170962306a36Sopenharmony_ci			cmd = &cmd_info[i];
171062306a36Sopenharmony_ci			break;
171162306a36Sopenharmony_ci		}
171262306a36Sopenharmony_ci	}
171362306a36Sopenharmony_ci	if (!cmd) {
171462306a36Sopenharmony_ci		mlx4_err(dev, "Unknown command:0x%x accepted from slave:%d\n",
171562306a36Sopenharmony_ci			 vhcr->op, slave);
171662306a36Sopenharmony_ci		vhcr_cmd->status = CMD_STAT_BAD_PARAM;
171762306a36Sopenharmony_ci		goto out_status;
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	/* Read inbox */
172162306a36Sopenharmony_ci	if (cmd->has_inbox) {
172262306a36Sopenharmony_ci		vhcr->in_param &= INBOX_MASK;
172362306a36Sopenharmony_ci		inbox = mlx4_alloc_cmd_mailbox(dev);
172462306a36Sopenharmony_ci		if (IS_ERR(inbox)) {
172562306a36Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
172662306a36Sopenharmony_ci			inbox = NULL;
172762306a36Sopenharmony_ci			goto out_status;
172862306a36Sopenharmony_ci		}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave,
173162306a36Sopenharmony_ci				      vhcr->in_param,
173262306a36Sopenharmony_ci				      MLX4_MAILBOX_SIZE, 1);
173362306a36Sopenharmony_ci		if (ret) {
173462306a36Sopenharmony_ci			if (!(dev->persist->state &
173562306a36Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
173662306a36Sopenharmony_ci				mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
173762306a36Sopenharmony_ci					 __func__, cmd->opcode);
173862306a36Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_INTERNAL_ERR;
173962306a36Sopenharmony_ci			goto out_status;
174062306a36Sopenharmony_ci		}
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Apply permission and bound checks if applicable */
174462306a36Sopenharmony_ci	if (cmd->verify && cmd->verify(dev, slave, vhcr, inbox)) {
174562306a36Sopenharmony_ci		mlx4_warn(dev, "Command:0x%x from slave: %d failed protection checks for resource_id:%d\n",
174662306a36Sopenharmony_ci			  vhcr->op, slave, vhcr->in_modifier);
174762306a36Sopenharmony_ci		vhcr_cmd->status = CMD_STAT_BAD_OP;
174862306a36Sopenharmony_ci		goto out_status;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	/* Allocate outbox */
175262306a36Sopenharmony_ci	if (cmd->has_outbox) {
175362306a36Sopenharmony_ci		outbox = mlx4_alloc_cmd_mailbox(dev);
175462306a36Sopenharmony_ci		if (IS_ERR(outbox)) {
175562306a36Sopenharmony_ci			vhcr_cmd->status = CMD_STAT_BAD_SIZE;
175662306a36Sopenharmony_ci			outbox = NULL;
175762306a36Sopenharmony_ci			goto out_status;
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	/* Execute the command! */
176262306a36Sopenharmony_ci	if (cmd->wrapper) {
176362306a36Sopenharmony_ci		err = cmd->wrapper(dev, slave, vhcr, inbox, outbox,
176462306a36Sopenharmony_ci				   cmd);
176562306a36Sopenharmony_ci		if (cmd->out_is_imm)
176662306a36Sopenharmony_ci			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
176762306a36Sopenharmony_ci	} else {
176862306a36Sopenharmony_ci		in_param = cmd->has_inbox ? (u64) inbox->dma :
176962306a36Sopenharmony_ci			vhcr->in_param;
177062306a36Sopenharmony_ci		out_param = cmd->has_outbox ? (u64) outbox->dma :
177162306a36Sopenharmony_ci			vhcr->out_param;
177262306a36Sopenharmony_ci		err = __mlx4_cmd(dev, in_param, &out_param,
177362306a36Sopenharmony_ci				 cmd->out_is_imm, vhcr->in_modifier,
177462306a36Sopenharmony_ci				 vhcr->op_modifier, vhcr->op,
177562306a36Sopenharmony_ci				 MLX4_CMD_TIME_CLASS_A,
177662306a36Sopenharmony_ci				 MLX4_CMD_NATIVE);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		if (cmd->out_is_imm) {
177962306a36Sopenharmony_ci			vhcr->out_param = out_param;
178062306a36Sopenharmony_ci			vhcr_cmd->out_param = cpu_to_be64(vhcr->out_param);
178162306a36Sopenharmony_ci		}
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	if (err) {
178562306a36Sopenharmony_ci		if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
178662306a36Sopenharmony_ci			if (vhcr->op == MLX4_CMD_ALLOC_RES &&
178762306a36Sopenharmony_ci			    (vhcr->in_modifier & 0xff) == RES_COUNTER &&
178862306a36Sopenharmony_ci			    err == -EDQUOT)
178962306a36Sopenharmony_ci				mlx4_dbg(dev,
179062306a36Sopenharmony_ci					 "Unable to allocate counter for slave %d (%d)\n",
179162306a36Sopenharmony_ci					 slave, err);
179262306a36Sopenharmony_ci			else
179362306a36Sopenharmony_ci				mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n",
179462306a36Sopenharmony_ci					  vhcr->op, slave, vhcr->errno, err);
179562306a36Sopenharmony_ci		}
179662306a36Sopenharmony_ci		vhcr_cmd->status = mlx4_errno_to_status(err);
179762306a36Sopenharmony_ci		goto out_status;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	/* Write outbox if command completed successfully */
180262306a36Sopenharmony_ci	if (cmd->has_outbox && !vhcr_cmd->status) {
180362306a36Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, outbox->dma, slave,
180462306a36Sopenharmony_ci				      vhcr->out_param,
180562306a36Sopenharmony_ci				      MLX4_MAILBOX_SIZE, MLX4_CMD_WRAPPED);
180662306a36Sopenharmony_ci		if (ret) {
180762306a36Sopenharmony_ci			/* If we failed to write back the outbox after the
180862306a36Sopenharmony_ci			 *command was successfully executed, we must fail this
180962306a36Sopenharmony_ci			 * slave, as it is now in undefined state */
181062306a36Sopenharmony_ci			if (!(dev->persist->state &
181162306a36Sopenharmony_ci			    MLX4_DEVICE_STATE_INTERNAL_ERROR))
181262306a36Sopenharmony_ci				mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
181362306a36Sopenharmony_ci			goto out;
181462306a36Sopenharmony_ci		}
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ciout_status:
181862306a36Sopenharmony_ci	/* DMA back vhcr result */
181962306a36Sopenharmony_ci	if (!in_vhcr) {
182062306a36Sopenharmony_ci		ret = mlx4_ACCESS_MEM(dev, priv->mfunc.vhcr_dma, slave,
182162306a36Sopenharmony_ci				      priv->mfunc.master.slave_state[slave].vhcr_dma,
182262306a36Sopenharmony_ci				      ALIGN(sizeof(struct mlx4_vhcr),
182362306a36Sopenharmony_ci					    MLX4_ACCESS_MEM_ALIGN),
182462306a36Sopenharmony_ci				      MLX4_CMD_WRAPPED);
182562306a36Sopenharmony_ci		if (ret)
182662306a36Sopenharmony_ci			mlx4_err(dev, "%s:Failed writing vhcr result\n",
182762306a36Sopenharmony_ci				 __func__);
182862306a36Sopenharmony_ci		else if (vhcr->e_bit &&
182962306a36Sopenharmony_ci			 mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe))
183062306a36Sopenharmony_ci				mlx4_warn(dev, "Failed to generate command completion eqe for slave %d\n",
183162306a36Sopenharmony_ci					  slave);
183262306a36Sopenharmony_ci	}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ciout:
183562306a36Sopenharmony_ci	kfree(vhcr);
183662306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, inbox);
183762306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, outbox);
183862306a36Sopenharmony_ci	return ret;
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_cistatic int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
184262306a36Sopenharmony_ci					    int slave, int port)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
184562306a36Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
184662306a36Sopenharmony_ci	struct mlx4_vf_immed_vlan_work *work;
184762306a36Sopenharmony_ci	struct mlx4_dev *dev = &(priv->dev);
184862306a36Sopenharmony_ci	int err;
184962306a36Sopenharmony_ci	int admin_vlan_ix = NO_INDX;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
185262306a36Sopenharmony_ci	vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	if (vp_oper->state.default_vlan == vp_admin->default_vlan &&
185562306a36Sopenharmony_ci	    vp_oper->state.default_qos == vp_admin->default_qos &&
185662306a36Sopenharmony_ci	    vp_oper->state.vlan_proto == vp_admin->vlan_proto &&
185762306a36Sopenharmony_ci	    vp_oper->state.link_state == vp_admin->link_state &&
185862306a36Sopenharmony_ci	    vp_oper->state.qos_vport == vp_admin->qos_vport)
185962306a36Sopenharmony_ci		return 0;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (!(priv->mfunc.master.slave_state[slave].active &&
186262306a36Sopenharmony_ci	      dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)) {
186362306a36Sopenharmony_ci		/* even if the UPDATE_QP command isn't supported, we still want
186462306a36Sopenharmony_ci		 * to set this VF link according to the admin directive
186562306a36Sopenharmony_ci		 */
186662306a36Sopenharmony_ci		vp_oper->state.link_state = vp_admin->link_state;
186762306a36Sopenharmony_ci		return -1;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n",
187162306a36Sopenharmony_ci		 slave, port);
187262306a36Sopenharmony_ci	mlx4_dbg(dev, "vlan %d QoS %d link down %d\n",
187362306a36Sopenharmony_ci		 vp_admin->default_vlan, vp_admin->default_qos,
187462306a36Sopenharmony_ci		 vp_admin->link_state);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	work = kzalloc(sizeof(*work), GFP_KERNEL);
187762306a36Sopenharmony_ci	if (!work)
187862306a36Sopenharmony_ci		return -ENOMEM;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	if (vp_oper->state.default_vlan != vp_admin->default_vlan) {
188162306a36Sopenharmony_ci		if (MLX4_VGT != vp_admin->default_vlan) {
188262306a36Sopenharmony_ci			err = __mlx4_register_vlan(&priv->dev, port,
188362306a36Sopenharmony_ci						   vp_admin->default_vlan,
188462306a36Sopenharmony_ci						   &admin_vlan_ix);
188562306a36Sopenharmony_ci			if (err) {
188662306a36Sopenharmony_ci				kfree(work);
188762306a36Sopenharmony_ci				mlx4_warn(&priv->dev,
188862306a36Sopenharmony_ci					  "No vlan resources slave %d, port %d\n",
188962306a36Sopenharmony_ci					  slave, port);
189062306a36Sopenharmony_ci				return err;
189162306a36Sopenharmony_ci			}
189262306a36Sopenharmony_ci		} else {
189362306a36Sopenharmony_ci			admin_vlan_ix = NO_INDX;
189462306a36Sopenharmony_ci		}
189562306a36Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN;
189662306a36Sopenharmony_ci		mlx4_dbg(&priv->dev,
189762306a36Sopenharmony_ci			 "alloc vlan %d idx  %d slave %d port %d\n",
189862306a36Sopenharmony_ci			 (int)(vp_admin->default_vlan),
189962306a36Sopenharmony_ci			 admin_vlan_ix, slave, port);
190062306a36Sopenharmony_ci	}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	/* save original vlan ix and vlan id */
190362306a36Sopenharmony_ci	work->orig_vlan_id = vp_oper->state.default_vlan;
190462306a36Sopenharmony_ci	work->orig_vlan_ix = vp_oper->vlan_idx;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	/* handle new qos */
190762306a36Sopenharmony_ci	if (vp_oper->state.default_qos != vp_admin->default_qos)
190862306a36Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN)
191162306a36Sopenharmony_ci		vp_oper->vlan_idx = admin_vlan_ix;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	vp_oper->state.default_vlan = vp_admin->default_vlan;
191462306a36Sopenharmony_ci	vp_oper->state.default_qos = vp_admin->default_qos;
191562306a36Sopenharmony_ci	vp_oper->state.vlan_proto = vp_admin->vlan_proto;
191662306a36Sopenharmony_ci	vp_oper->state.link_state = vp_admin->link_state;
191762306a36Sopenharmony_ci	vp_oper->state.qos_vport = vp_admin->qos_vport;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE)
192062306a36Sopenharmony_ci		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* iterate over QPs owned by this slave, using UPDATE_QP */
192362306a36Sopenharmony_ci	work->port = port;
192462306a36Sopenharmony_ci	work->slave = slave;
192562306a36Sopenharmony_ci	work->qos = vp_oper->state.default_qos;
192662306a36Sopenharmony_ci	work->qos_vport = vp_oper->state.qos_vport;
192762306a36Sopenharmony_ci	work->vlan_id = vp_oper->state.default_vlan;
192862306a36Sopenharmony_ci	work->vlan_ix = vp_oper->vlan_idx;
192962306a36Sopenharmony_ci	work->vlan_proto = vp_oper->state.vlan_proto;
193062306a36Sopenharmony_ci	work->priv = priv;
193162306a36Sopenharmony_ci	INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler);
193262306a36Sopenharmony_ci	queue_work(priv->mfunc.master.comm_wq, &work->work);
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	return 0;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	struct mlx4_qos_manager *port_qos_ctl;
194062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	port_qos_ctl = &priv->mfunc.master.qos_ctl[port];
194362306a36Sopenharmony_ci	bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	/* Enable only default prio at PF init routine */
194662306a36Sopenharmony_ci	set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm);
194762306a36Sopenharmony_ci}
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_cistatic void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	int i;
195262306a36Sopenharmony_ci	int err;
195362306a36Sopenharmony_ci	int num_vfs;
195462306a36Sopenharmony_ci	u16 available_vpp;
195562306a36Sopenharmony_ci	u8 vpp_param[MLX4_NUM_UP];
195662306a36Sopenharmony_ci	struct mlx4_qos_manager *port_qos;
195762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param);
196062306a36Sopenharmony_ci	if (err) {
196162306a36Sopenharmony_ci		mlx4_info(dev, "Failed query available VPPs\n");
196262306a36Sopenharmony_ci		return;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	port_qos = &priv->mfunc.master.qos_ctl[port];
196662306a36Sopenharmony_ci	num_vfs = (available_vpp /
196762306a36Sopenharmony_ci		   bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP));
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++) {
197062306a36Sopenharmony_ci		if (test_bit(i, port_qos->priority_bm))
197162306a36Sopenharmony_ci			vpp_param[i] = num_vfs;
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param);
197562306a36Sopenharmony_ci	if (err) {
197662306a36Sopenharmony_ci		mlx4_info(dev, "Failed allocating VPPs\n");
197762306a36Sopenharmony_ci		return;
197862306a36Sopenharmony_ci	}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	/* Query actual allocated VPP, just to make sure */
198162306a36Sopenharmony_ci	err = mlx4_ALLOCATE_VPP_get(dev, port, &available_vpp, vpp_param);
198262306a36Sopenharmony_ci	if (err) {
198362306a36Sopenharmony_ci		mlx4_info(dev, "Failed query available VPPs\n");
198462306a36Sopenharmony_ci		return;
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	port_qos->num_of_qos_vfs = num_vfs;
198862306a36Sopenharmony_ci	mlx4_dbg(dev, "Port %d Available VPPs %d\n", port, available_vpp);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++)
199162306a36Sopenharmony_ci		mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i,
199262306a36Sopenharmony_ci			 vpp_param[i]);
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
199662306a36Sopenharmony_ci{
199762306a36Sopenharmony_ci	int p, port, err;
199862306a36Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
199962306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
200062306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state =
200162306a36Sopenharmony_ci		&priv->mfunc.master.slave_state[slave];
200262306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
200362306a36Sopenharmony_ci			&priv->dev, slave);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	for_each_set_bit(p, actv_ports.ports, priv->dev.caps.num_ports) {
200662306a36Sopenharmony_ci		port = p + 1;
200762306a36Sopenharmony_ci		priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
200862306a36Sopenharmony_ci			priv->mfunc.master.vf_admin[slave].enable_smi[port];
200962306a36Sopenharmony_ci		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
201062306a36Sopenharmony_ci		vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
201162306a36Sopenharmony_ci		if (vp_admin->vlan_proto != htons(ETH_P_8021AD) ||
201262306a36Sopenharmony_ci		    slave_state->vst_qinq_supported) {
201362306a36Sopenharmony_ci			vp_oper->state.vlan_proto   = vp_admin->vlan_proto;
201462306a36Sopenharmony_ci			vp_oper->state.default_vlan = vp_admin->default_vlan;
201562306a36Sopenharmony_ci			vp_oper->state.default_qos  = vp_admin->default_qos;
201662306a36Sopenharmony_ci		}
201762306a36Sopenharmony_ci		vp_oper->state.link_state = vp_admin->link_state;
201862306a36Sopenharmony_ci		vp_oper->state.mac        = vp_admin->mac;
201962306a36Sopenharmony_ci		vp_oper->state.spoofchk   = vp_admin->spoofchk;
202062306a36Sopenharmony_ci		vp_oper->state.tx_rate    = vp_admin->tx_rate;
202162306a36Sopenharmony_ci		vp_oper->state.qos_vport  = vp_admin->qos_vport;
202262306a36Sopenharmony_ci		vp_oper->state.guid       = vp_admin->guid;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci		if (MLX4_VGT != vp_admin->default_vlan) {
202562306a36Sopenharmony_ci			err = __mlx4_register_vlan(&priv->dev, port,
202662306a36Sopenharmony_ci						   vp_admin->default_vlan, &(vp_oper->vlan_idx));
202762306a36Sopenharmony_ci			if (err) {
202862306a36Sopenharmony_ci				vp_oper->vlan_idx = NO_INDX;
202962306a36Sopenharmony_ci				vp_oper->state.default_vlan = MLX4_VGT;
203062306a36Sopenharmony_ci				vp_oper->state.vlan_proto = htons(ETH_P_8021Q);
203162306a36Sopenharmony_ci				mlx4_warn(&priv->dev,
203262306a36Sopenharmony_ci					  "No vlan resources slave %d, port %d\n",
203362306a36Sopenharmony_ci					  slave, port);
203462306a36Sopenharmony_ci				return err;
203562306a36Sopenharmony_ci			}
203662306a36Sopenharmony_ci			mlx4_dbg(&priv->dev, "alloc vlan %d idx  %d slave %d port %d\n",
203762306a36Sopenharmony_ci				 (int)(vp_oper->state.default_vlan),
203862306a36Sopenharmony_ci				 vp_oper->vlan_idx, slave, port);
203962306a36Sopenharmony_ci		}
204062306a36Sopenharmony_ci		if (vp_admin->spoofchk) {
204162306a36Sopenharmony_ci			vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
204262306a36Sopenharmony_ci							       port,
204362306a36Sopenharmony_ci							       vp_admin->mac);
204462306a36Sopenharmony_ci			if (0 > vp_oper->mac_idx) {
204562306a36Sopenharmony_ci				err = vp_oper->mac_idx;
204662306a36Sopenharmony_ci				vp_oper->mac_idx = NO_INDX;
204762306a36Sopenharmony_ci				mlx4_warn(&priv->dev,
204862306a36Sopenharmony_ci					  "No mac resources slave %d, port %d\n",
204962306a36Sopenharmony_ci					  slave, port);
205062306a36Sopenharmony_ci				return err;
205162306a36Sopenharmony_ci			}
205262306a36Sopenharmony_ci			mlx4_dbg(&priv->dev, "alloc mac %llx idx  %d slave %d port %d\n",
205362306a36Sopenharmony_ci				 vp_oper->state.mac, vp_oper->mac_idx, slave, port);
205462306a36Sopenharmony_ci		}
205562306a36Sopenharmony_ci	}
205662306a36Sopenharmony_ci	return 0;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	int p, port;
206262306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
206362306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
206462306a36Sopenharmony_ci			&priv->dev, slave);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	for_each_set_bit(p, actv_ports.ports, priv->dev.caps.num_ports) {
206762306a36Sopenharmony_ci		port = p + 1;
206862306a36Sopenharmony_ci		priv->mfunc.master.vf_oper[slave].smi_enabled[port] =
206962306a36Sopenharmony_ci			MLX4_VF_SMI_DISABLED;
207062306a36Sopenharmony_ci		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
207162306a36Sopenharmony_ci		if (NO_INDX != vp_oper->vlan_idx) {
207262306a36Sopenharmony_ci			__mlx4_unregister_vlan(&priv->dev,
207362306a36Sopenharmony_ci					       port, vp_oper->state.default_vlan);
207462306a36Sopenharmony_ci			vp_oper->vlan_idx = NO_INDX;
207562306a36Sopenharmony_ci		}
207662306a36Sopenharmony_ci		if (NO_INDX != vp_oper->mac_idx) {
207762306a36Sopenharmony_ci			__mlx4_unregister_mac(&priv->dev, port, vp_oper->state.mac);
207862306a36Sopenharmony_ci			vp_oper->mac_idx = NO_INDX;
207962306a36Sopenharmony_ci		}
208062306a36Sopenharmony_ci	}
208162306a36Sopenharmony_ci	return;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
208562306a36Sopenharmony_ci			       u16 param, u8 toggle)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
208862306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
208962306a36Sopenharmony_ci	u32 reply;
209062306a36Sopenharmony_ci	u8 is_going_down = 0;
209162306a36Sopenharmony_ci	int i;
209262306a36Sopenharmony_ci	unsigned long flags;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	slave_state[slave].comm_toggle ^= 1;
209562306a36Sopenharmony_ci	reply = (u32) slave_state[slave].comm_toggle << 31;
209662306a36Sopenharmony_ci	if (toggle != slave_state[slave].comm_toggle) {
209762306a36Sopenharmony_ci		mlx4_warn(dev, "Incorrect toggle %d from slave %d. *** MASTER STATE COMPROMISED ***\n",
209862306a36Sopenharmony_ci			  toggle, slave);
209962306a36Sopenharmony_ci		goto reset_slave;
210062306a36Sopenharmony_ci	}
210162306a36Sopenharmony_ci	if (cmd == MLX4_COMM_CMD_RESET) {
210262306a36Sopenharmony_ci		mlx4_warn(dev, "Received reset from slave:%d\n", slave);
210362306a36Sopenharmony_ci		slave_state[slave].active = false;
210462306a36Sopenharmony_ci		slave_state[slave].old_vlan_api = false;
210562306a36Sopenharmony_ci		slave_state[slave].vst_qinq_supported = false;
210662306a36Sopenharmony_ci		mlx4_master_deactivate_admin_state(priv, slave);
210762306a36Sopenharmony_ci		for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
210862306a36Sopenharmony_ci				slave_state[slave].event_eq[i].eqn = -1;
210962306a36Sopenharmony_ci				slave_state[slave].event_eq[i].token = 0;
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci		/*check if we are in the middle of FLR process,
211262306a36Sopenharmony_ci		if so return "retry" status to the slave*/
211362306a36Sopenharmony_ci		if (MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd)
211462306a36Sopenharmony_ci			goto inform_slave_state;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_SHUTDOWN, &slave);
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci		/* write the version in the event field */
211962306a36Sopenharmony_ci		reply |= mlx4_comm_get_version();
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci		goto reset_slave;
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci	/*command from slave in the middle of FLR*/
212462306a36Sopenharmony_ci	if (cmd != MLX4_COMM_CMD_RESET &&
212562306a36Sopenharmony_ci	    MLX4_COMM_CMD_FLR == slave_state[slave].last_cmd) {
212662306a36Sopenharmony_ci		mlx4_warn(dev, "slave:%d is Trying to run cmd(0x%x) in the middle of FLR\n",
212762306a36Sopenharmony_ci			  slave, cmd);
212862306a36Sopenharmony_ci		return;
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	switch (cmd) {
213262306a36Sopenharmony_ci	case MLX4_COMM_CMD_VHCR0:
213362306a36Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_RESET)
213462306a36Sopenharmony_ci			goto reset_slave;
213562306a36Sopenharmony_ci		slave_state[slave].vhcr_dma = ((u64) param) << 48;
213662306a36Sopenharmony_ci		priv->mfunc.master.slave_state[slave].cookie = 0;
213762306a36Sopenharmony_ci		break;
213862306a36Sopenharmony_ci	case MLX4_COMM_CMD_VHCR1:
213962306a36Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0)
214062306a36Sopenharmony_ci			goto reset_slave;
214162306a36Sopenharmony_ci		slave_state[slave].vhcr_dma |= ((u64) param) << 32;
214262306a36Sopenharmony_ci		break;
214362306a36Sopenharmony_ci	case MLX4_COMM_CMD_VHCR2:
214462306a36Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR1)
214562306a36Sopenharmony_ci			goto reset_slave;
214662306a36Sopenharmony_ci		slave_state[slave].vhcr_dma |= ((u64) param) << 16;
214762306a36Sopenharmony_ci		break;
214862306a36Sopenharmony_ci	case MLX4_COMM_CMD_VHCR_EN:
214962306a36Sopenharmony_ci		if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
215062306a36Sopenharmony_ci			goto reset_slave;
215162306a36Sopenharmony_ci		slave_state[slave].vhcr_dma |= param;
215262306a36Sopenharmony_ci		if (mlx4_master_activate_admin_state(priv, slave))
215362306a36Sopenharmony_ci				goto reset_slave;
215462306a36Sopenharmony_ci		slave_state[slave].active = true;
215562306a36Sopenharmony_ci		mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, &slave);
215662306a36Sopenharmony_ci		break;
215762306a36Sopenharmony_ci	case MLX4_COMM_CMD_VHCR_POST:
215862306a36Sopenharmony_ci		if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
215962306a36Sopenharmony_ci		    (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) {
216062306a36Sopenharmony_ci			mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n",
216162306a36Sopenharmony_ci				  slave, cmd, slave_state[slave].last_cmd);
216262306a36Sopenharmony_ci			goto reset_slave;
216362306a36Sopenharmony_ci		}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
216662306a36Sopenharmony_ci		if (mlx4_master_process_vhcr(dev, slave, NULL)) {
216762306a36Sopenharmony_ci			mlx4_err(dev, "Failed processing vhcr for slave:%d, resetting slave\n",
216862306a36Sopenharmony_ci				 slave);
216962306a36Sopenharmony_ci			mutex_unlock(&priv->cmd.slave_cmd_mutex);
217062306a36Sopenharmony_ci			goto reset_slave;
217162306a36Sopenharmony_ci		}
217262306a36Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
217362306a36Sopenharmony_ci		break;
217462306a36Sopenharmony_ci	default:
217562306a36Sopenharmony_ci		mlx4_warn(dev, "Bad comm cmd:%d from slave:%d\n", cmd, slave);
217662306a36Sopenharmony_ci		goto reset_slave;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
217962306a36Sopenharmony_ci	if (!slave_state[slave].is_slave_going_down)
218062306a36Sopenharmony_ci		slave_state[slave].last_cmd = cmd;
218162306a36Sopenharmony_ci	else
218262306a36Sopenharmony_ci		is_going_down = 1;
218362306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
218462306a36Sopenharmony_ci	if (is_going_down) {
218562306a36Sopenharmony_ci		mlx4_warn(dev, "Slave is going down aborting command(%d) executing from slave:%d\n",
218662306a36Sopenharmony_ci			  cmd, slave);
218762306a36Sopenharmony_ci		return;
218862306a36Sopenharmony_ci	}
218962306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(reply),
219062306a36Sopenharmony_ci		     &priv->mfunc.comm[slave].slave_read);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	return;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_cireset_slave:
219562306a36Sopenharmony_ci	/* cleanup any slave resources */
219662306a36Sopenharmony_ci	if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP)
219762306a36Sopenharmony_ci		mlx4_delete_all_resources_for_slave(dev, slave);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	if (cmd != MLX4_COMM_CMD_RESET) {
220062306a36Sopenharmony_ci		mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n",
220162306a36Sopenharmony_ci			  slave, cmd);
220262306a36Sopenharmony_ci		/* Turn on internal error letting slave reset itself immeditaly,
220362306a36Sopenharmony_ci		 * otherwise it might take till timeout on command is passed
220462306a36Sopenharmony_ci		 */
220562306a36Sopenharmony_ci		reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR);
220662306a36Sopenharmony_ci	}
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
220962306a36Sopenharmony_ci	if (!slave_state[slave].is_slave_going_down)
221062306a36Sopenharmony_ci		slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET;
221162306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags);
221262306a36Sopenharmony_ci	/*with slave in the middle of flr, no need to clean resources again.*/
221362306a36Sopenharmony_ciinform_slave_state:
221462306a36Sopenharmony_ci	memset(&slave_state[slave].event_eq, 0,
221562306a36Sopenharmony_ci	       sizeof(struct mlx4_slave_event_eq_info));
221662306a36Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(reply),
221762306a36Sopenharmony_ci		     &priv->mfunc.comm[slave].slave_read);
221862306a36Sopenharmony_ci	wmb();
221962306a36Sopenharmony_ci}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci/* master command processing */
222262306a36Sopenharmony_civoid mlx4_master_comm_channel(struct work_struct *work)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	struct mlx4_mfunc_master_ctx *master =
222562306a36Sopenharmony_ci		container_of(work,
222662306a36Sopenharmony_ci			     struct mlx4_mfunc_master_ctx,
222762306a36Sopenharmony_ci			     comm_work);
222862306a36Sopenharmony_ci	struct mlx4_mfunc *mfunc =
222962306a36Sopenharmony_ci		container_of(master, struct mlx4_mfunc, master);
223062306a36Sopenharmony_ci	struct mlx4_priv *priv =
223162306a36Sopenharmony_ci		container_of(mfunc, struct mlx4_priv, mfunc);
223262306a36Sopenharmony_ci	struct mlx4_dev *dev = &priv->dev;
223362306a36Sopenharmony_ci	u32 lbit_vec[COMM_CHANNEL_BIT_ARRAY_SIZE];
223462306a36Sopenharmony_ci	u32 nmbr_bits;
223562306a36Sopenharmony_ci	u32 comm_cmd;
223662306a36Sopenharmony_ci	int i, slave;
223762306a36Sopenharmony_ci	int toggle;
223862306a36Sopenharmony_ci	bool first = true;
223962306a36Sopenharmony_ci	int served = 0;
224062306a36Sopenharmony_ci	int reported = 0;
224162306a36Sopenharmony_ci	u32 slt;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++)
224462306a36Sopenharmony_ci		lbit_vec[i] = be32_to_cpu(master->comm_arm_bit_vector[i]);
224562306a36Sopenharmony_ci	nmbr_bits = dev->persist->num_vfs + 1;
224662306a36Sopenharmony_ci	if (++master->next_slave >= nmbr_bits)
224762306a36Sopenharmony_ci		master->next_slave = 0;
224862306a36Sopenharmony_ci	slave = master->next_slave;
224962306a36Sopenharmony_ci	while (true) {
225062306a36Sopenharmony_ci		slave = find_next_bit((const unsigned long *)&lbit_vec, nmbr_bits, slave);
225162306a36Sopenharmony_ci		if  (!first && slave >= master->next_slave)
225262306a36Sopenharmony_ci			break;
225362306a36Sopenharmony_ci		if (slave == nmbr_bits) {
225462306a36Sopenharmony_ci			if (!first)
225562306a36Sopenharmony_ci				break;
225662306a36Sopenharmony_ci			first = false;
225762306a36Sopenharmony_ci			slave = 0;
225862306a36Sopenharmony_ci			continue;
225962306a36Sopenharmony_ci		}
226062306a36Sopenharmony_ci		++reported;
226162306a36Sopenharmony_ci		comm_cmd = swab32(readl(&mfunc->comm[slave].slave_write));
226262306a36Sopenharmony_ci		slt = swab32(readl(&mfunc->comm[slave].slave_read)) >> 31;
226362306a36Sopenharmony_ci		toggle = comm_cmd >> 31;
226462306a36Sopenharmony_ci		if (toggle != slt) {
226562306a36Sopenharmony_ci			if (master->slave_state[slave].comm_toggle
226662306a36Sopenharmony_ci			    != slt) {
226762306a36Sopenharmony_ci				pr_info("slave %d out of sync. read toggle %d, state toggle %d. Resynching.\n",
226862306a36Sopenharmony_ci					slave, slt,
226962306a36Sopenharmony_ci					master->slave_state[slave].comm_toggle);
227062306a36Sopenharmony_ci				master->slave_state[slave].comm_toggle =
227162306a36Sopenharmony_ci					slt;
227262306a36Sopenharmony_ci			}
227362306a36Sopenharmony_ci			mlx4_master_do_cmd(dev, slave,
227462306a36Sopenharmony_ci					   comm_cmd >> 16 & 0xff,
227562306a36Sopenharmony_ci					   comm_cmd & 0xffff, toggle);
227662306a36Sopenharmony_ci			++served;
227762306a36Sopenharmony_ci		}
227862306a36Sopenharmony_ci		slave++;
227962306a36Sopenharmony_ci	}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	if (reported && reported != served)
228262306a36Sopenharmony_ci		mlx4_warn(dev, "Got command event with bitmask from %d slaves but %d were served\n",
228362306a36Sopenharmony_ci			  reported, served);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	if (mlx4_ARM_COMM_CHANNEL(dev))
228662306a36Sopenharmony_ci		mlx4_warn(dev, "Failed to arm comm channel events\n");
228762306a36Sopenharmony_ci}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_cistatic int sync_toggles(struct mlx4_dev *dev)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
229262306a36Sopenharmony_ci	u32 wr_toggle;
229362306a36Sopenharmony_ci	u32 rd_toggle;
229462306a36Sopenharmony_ci	unsigned long end;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write));
229762306a36Sopenharmony_ci	if (wr_toggle == 0xffffffff)
229862306a36Sopenharmony_ci		end = jiffies + msecs_to_jiffies(30000);
229962306a36Sopenharmony_ci	else
230062306a36Sopenharmony_ci		end = jiffies + msecs_to_jiffies(5000);
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	while (time_before(jiffies, end)) {
230362306a36Sopenharmony_ci		rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read));
230462306a36Sopenharmony_ci		if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) {
230562306a36Sopenharmony_ci			/* PCI might be offline */
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci			/* If device removal has been requested,
230862306a36Sopenharmony_ci			 * do not continue retrying.
230962306a36Sopenharmony_ci			 */
231062306a36Sopenharmony_ci			if (dev->persist->interface_state &
231162306a36Sopenharmony_ci			    MLX4_INTERFACE_STATE_NOWAIT) {
231262306a36Sopenharmony_ci				mlx4_warn(dev,
231362306a36Sopenharmony_ci					  "communication channel is offline\n");
231462306a36Sopenharmony_ci				return -EIO;
231562306a36Sopenharmony_ci			}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci			msleep(100);
231862306a36Sopenharmony_ci			wr_toggle = swab32(readl(&priv->mfunc.comm->
231962306a36Sopenharmony_ci					   slave_write));
232062306a36Sopenharmony_ci			continue;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		if (rd_toggle >> 31 == wr_toggle >> 31) {
232462306a36Sopenharmony_ci			priv->cmd.comm_toggle = rd_toggle >> 31;
232562306a36Sopenharmony_ci			return 0;
232662306a36Sopenharmony_ci		}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci		cond_resched();
232962306a36Sopenharmony_ci	}
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci	/*
233262306a36Sopenharmony_ci	 * we could reach here if for example the previous VM using this
233362306a36Sopenharmony_ci	 * function misbehaved and left the channel with unsynced state. We
233462306a36Sopenharmony_ci	 * should fix this here and give this VM a chance to use a properly
233562306a36Sopenharmony_ci	 * synced channel
233662306a36Sopenharmony_ci	 */
233762306a36Sopenharmony_ci	mlx4_warn(dev, "recovering from previously mis-behaved VM\n");
233862306a36Sopenharmony_ci	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_read);
233962306a36Sopenharmony_ci	__raw_writel((__force u32) 0, &priv->mfunc.comm->slave_write);
234062306a36Sopenharmony_ci	priv->cmd.comm_toggle = 0;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	return 0;
234362306a36Sopenharmony_ci}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ciint mlx4_multi_func_init(struct mlx4_dev *dev)
234662306a36Sopenharmony_ci{
234762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
234862306a36Sopenharmony_ci	struct mlx4_slave_state *s_state;
234962306a36Sopenharmony_ci	int i, j, err, port;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (mlx4_is_master(dev))
235262306a36Sopenharmony_ci		priv->mfunc.comm =
235362306a36Sopenharmony_ci		ioremap(pci_resource_start(dev->persist->pdev,
235462306a36Sopenharmony_ci					   priv->fw.comm_bar) +
235562306a36Sopenharmony_ci			priv->fw.comm_base, MLX4_COMM_PAGESIZE);
235662306a36Sopenharmony_ci	else
235762306a36Sopenharmony_ci		priv->mfunc.comm =
235862306a36Sopenharmony_ci		ioremap(pci_resource_start(dev->persist->pdev, 2) +
235962306a36Sopenharmony_ci			MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE);
236062306a36Sopenharmony_ci	if (!priv->mfunc.comm) {
236162306a36Sopenharmony_ci		mlx4_err(dev, "Couldn't map communication vector\n");
236262306a36Sopenharmony_ci		goto err_vhcr;
236362306a36Sopenharmony_ci	}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	if (mlx4_is_master(dev)) {
236662306a36Sopenharmony_ci		struct mlx4_vf_oper_state *vf_oper;
236762306a36Sopenharmony_ci		struct mlx4_vf_admin_state *vf_admin;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci		priv->mfunc.master.slave_state =
237062306a36Sopenharmony_ci			kcalloc(dev->num_slaves,
237162306a36Sopenharmony_ci				sizeof(struct mlx4_slave_state),
237262306a36Sopenharmony_ci				GFP_KERNEL);
237362306a36Sopenharmony_ci		if (!priv->mfunc.master.slave_state)
237462306a36Sopenharmony_ci			goto err_comm;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci		priv->mfunc.master.vf_admin =
237762306a36Sopenharmony_ci			kcalloc(dev->num_slaves,
237862306a36Sopenharmony_ci				sizeof(struct mlx4_vf_admin_state),
237962306a36Sopenharmony_ci				GFP_KERNEL);
238062306a36Sopenharmony_ci		if (!priv->mfunc.master.vf_admin)
238162306a36Sopenharmony_ci			goto err_comm_admin;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci		priv->mfunc.master.vf_oper =
238462306a36Sopenharmony_ci			kcalloc(dev->num_slaves,
238562306a36Sopenharmony_ci				sizeof(struct mlx4_vf_oper_state),
238662306a36Sopenharmony_ci				GFP_KERNEL);
238762306a36Sopenharmony_ci		if (!priv->mfunc.master.vf_oper)
238862306a36Sopenharmony_ci			goto err_comm_oper;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci		priv->mfunc.master.next_slave = 0;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci		for (i = 0; i < dev->num_slaves; ++i) {
239362306a36Sopenharmony_ci			vf_admin = &priv->mfunc.master.vf_admin[i];
239462306a36Sopenharmony_ci			vf_oper = &priv->mfunc.master.vf_oper[i];
239562306a36Sopenharmony_ci			s_state = &priv->mfunc.master.slave_state[i];
239662306a36Sopenharmony_ci			s_state->last_cmd = MLX4_COMM_CMD_RESET;
239762306a36Sopenharmony_ci			s_state->vst_qinq_supported = false;
239862306a36Sopenharmony_ci			mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
239962306a36Sopenharmony_ci			for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j)
240062306a36Sopenharmony_ci				s_state->event_eq[j].eqn = -1;
240162306a36Sopenharmony_ci			__raw_writel((__force u32) 0,
240262306a36Sopenharmony_ci				     &priv->mfunc.comm[i].slave_write);
240362306a36Sopenharmony_ci			__raw_writel((__force u32) 0,
240462306a36Sopenharmony_ci				     &priv->mfunc.comm[i].slave_read);
240562306a36Sopenharmony_ci			for (port = 1; port <= MLX4_MAX_PORTS; port++) {
240662306a36Sopenharmony_ci				struct mlx4_vport_state *admin_vport;
240762306a36Sopenharmony_ci				struct mlx4_vport_state *oper_vport;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci				s_state->vlan_filter[port] =
241062306a36Sopenharmony_ci					kzalloc(sizeof(struct mlx4_vlan_fltr),
241162306a36Sopenharmony_ci						GFP_KERNEL);
241262306a36Sopenharmony_ci				if (!s_state->vlan_filter[port]) {
241362306a36Sopenharmony_ci					if (--port)
241462306a36Sopenharmony_ci						kfree(s_state->vlan_filter[port]);
241562306a36Sopenharmony_ci					goto err_slaves;
241662306a36Sopenharmony_ci				}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci				admin_vport = &vf_admin->vport[port];
241962306a36Sopenharmony_ci				oper_vport = &vf_oper->vport[port].state;
242062306a36Sopenharmony_ci				INIT_LIST_HEAD(&s_state->mcast_filters[port]);
242162306a36Sopenharmony_ci				admin_vport->default_vlan = MLX4_VGT;
242262306a36Sopenharmony_ci				oper_vport->default_vlan = MLX4_VGT;
242362306a36Sopenharmony_ci				admin_vport->qos_vport =
242462306a36Sopenharmony_ci						MLX4_VPP_DEFAULT_VPORT;
242562306a36Sopenharmony_ci				oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT;
242662306a36Sopenharmony_ci				admin_vport->vlan_proto = htons(ETH_P_8021Q);
242762306a36Sopenharmony_ci				oper_vport->vlan_proto = htons(ETH_P_8021Q);
242862306a36Sopenharmony_ci				vf_oper->vport[port].vlan_idx = NO_INDX;
242962306a36Sopenharmony_ci				vf_oper->vport[port].mac_idx = NO_INDX;
243062306a36Sopenharmony_ci				mlx4_set_random_admin_guid(dev, i, port);
243162306a36Sopenharmony_ci			}
243262306a36Sopenharmony_ci			spin_lock_init(&s_state->lock);
243362306a36Sopenharmony_ci		}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) {
243662306a36Sopenharmony_ci			for (port = 1; port <= dev->caps.num_ports; port++) {
243762306a36Sopenharmony_ci				if (mlx4_is_eth(dev, port)) {
243862306a36Sopenharmony_ci					mlx4_set_default_port_qos(dev, port);
243962306a36Sopenharmony_ci					mlx4_allocate_port_vpps(dev, port);
244062306a36Sopenharmony_ci				}
244162306a36Sopenharmony_ci			}
244262306a36Sopenharmony_ci		}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci		memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe));
244562306a36Sopenharmony_ci		priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD;
244662306a36Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.comm_work,
244762306a36Sopenharmony_ci			  mlx4_master_comm_channel);
244862306a36Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.slave_event_work,
244962306a36Sopenharmony_ci			  mlx4_gen_slave_eqe);
245062306a36Sopenharmony_ci		INIT_WORK(&priv->mfunc.master.slave_flr_event_work,
245162306a36Sopenharmony_ci			  mlx4_master_handle_slave_flr);
245262306a36Sopenharmony_ci		spin_lock_init(&priv->mfunc.master.slave_state_lock);
245362306a36Sopenharmony_ci		spin_lock_init(&priv->mfunc.master.slave_eq.event_lock);
245462306a36Sopenharmony_ci		priv->mfunc.master.comm_wq =
245562306a36Sopenharmony_ci			create_singlethread_workqueue("mlx4_comm");
245662306a36Sopenharmony_ci		if (!priv->mfunc.master.comm_wq)
245762306a36Sopenharmony_ci			goto err_slaves;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci		if (mlx4_init_resource_tracker(dev))
246062306a36Sopenharmony_ci			goto err_thread;
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	} else {
246362306a36Sopenharmony_ci		err = sync_toggles(dev);
246462306a36Sopenharmony_ci		if (err) {
246562306a36Sopenharmony_ci			mlx4_err(dev, "Couldn't sync toggles\n");
246662306a36Sopenharmony_ci			goto err_comm;
246762306a36Sopenharmony_ci		}
246862306a36Sopenharmony_ci	}
246962306a36Sopenharmony_ci	return 0;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_cierr_thread:
247262306a36Sopenharmony_ci	destroy_workqueue(priv->mfunc.master.comm_wq);
247362306a36Sopenharmony_cierr_slaves:
247462306a36Sopenharmony_ci	while (i--) {
247562306a36Sopenharmony_ci		for (port = 1; port <= MLX4_MAX_PORTS; port++)
247662306a36Sopenharmony_ci			kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
247762306a36Sopenharmony_ci	}
247862306a36Sopenharmony_ci	kfree(priv->mfunc.master.vf_oper);
247962306a36Sopenharmony_cierr_comm_oper:
248062306a36Sopenharmony_ci	kfree(priv->mfunc.master.vf_admin);
248162306a36Sopenharmony_cierr_comm_admin:
248262306a36Sopenharmony_ci	kfree(priv->mfunc.master.slave_state);
248362306a36Sopenharmony_cierr_comm:
248462306a36Sopenharmony_ci	iounmap(priv->mfunc.comm);
248562306a36Sopenharmony_ci	priv->mfunc.comm = NULL;
248662306a36Sopenharmony_cierr_vhcr:
248762306a36Sopenharmony_ci	dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
248862306a36Sopenharmony_ci			  priv->mfunc.vhcr,
248962306a36Sopenharmony_ci			  priv->mfunc.vhcr_dma);
249062306a36Sopenharmony_ci	priv->mfunc.vhcr = NULL;
249162306a36Sopenharmony_ci	return -ENOMEM;
249262306a36Sopenharmony_ci}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ciint mlx4_cmd_init(struct mlx4_dev *dev)
249562306a36Sopenharmony_ci{
249662306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
249762306a36Sopenharmony_ci	int flags = 0;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	if (!priv->cmd.initialized) {
250062306a36Sopenharmony_ci		init_rwsem(&priv->cmd.switch_sem);
250162306a36Sopenharmony_ci		mutex_init(&priv->cmd.slave_cmd_mutex);
250262306a36Sopenharmony_ci		sema_init(&priv->cmd.poll_sem, 1);
250362306a36Sopenharmony_ci		priv->cmd.use_events = 0;
250462306a36Sopenharmony_ci		priv->cmd.toggle     = 1;
250562306a36Sopenharmony_ci		priv->cmd.initialized = 1;
250662306a36Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_STRUCT;
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	if (!mlx4_is_slave(dev) && !priv->cmd.hcr) {
251062306a36Sopenharmony_ci		priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev,
251162306a36Sopenharmony_ci					0) + MLX4_HCR_BASE, MLX4_HCR_SIZE);
251262306a36Sopenharmony_ci		if (!priv->cmd.hcr) {
251362306a36Sopenharmony_ci			mlx4_err(dev, "Couldn't map command register\n");
251462306a36Sopenharmony_ci			goto err;
251562306a36Sopenharmony_ci		}
251662306a36Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_HCR;
251762306a36Sopenharmony_ci	}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) {
252062306a36Sopenharmony_ci		priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev,
252162306a36Sopenharmony_ci						      PAGE_SIZE,
252262306a36Sopenharmony_ci						      &priv->mfunc.vhcr_dma,
252362306a36Sopenharmony_ci						      GFP_KERNEL);
252462306a36Sopenharmony_ci		if (!priv->mfunc.vhcr)
252562306a36Sopenharmony_ci			goto err;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_VHCR;
252862306a36Sopenharmony_ci	}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	if (!priv->cmd.pool) {
253162306a36Sopenharmony_ci		priv->cmd.pool = dma_pool_create("mlx4_cmd",
253262306a36Sopenharmony_ci						 &dev->persist->pdev->dev,
253362306a36Sopenharmony_ci						 MLX4_MAILBOX_SIZE,
253462306a36Sopenharmony_ci						 MLX4_MAILBOX_SIZE, 0);
253562306a36Sopenharmony_ci		if (!priv->cmd.pool)
253662306a36Sopenharmony_ci			goto err;
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci		flags |= MLX4_CMD_CLEANUP_POOL;
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	return 0;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_cierr:
254462306a36Sopenharmony_ci	mlx4_cmd_cleanup(dev, flags);
254562306a36Sopenharmony_ci	return -ENOMEM;
254662306a36Sopenharmony_ci}
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_civoid mlx4_report_internal_err_comm_event(struct mlx4_dev *dev)
254962306a36Sopenharmony_ci{
255062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
255162306a36Sopenharmony_ci	int slave;
255262306a36Sopenharmony_ci	u32 slave_read;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	/* If the comm channel has not yet been initialized,
255562306a36Sopenharmony_ci	 * skip reporting the internal error event to all
255662306a36Sopenharmony_ci	 * the communication channels.
255762306a36Sopenharmony_ci	 */
255862306a36Sopenharmony_ci	if (!priv->mfunc.comm)
255962306a36Sopenharmony_ci		return;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	/* Report an internal error event to all
256262306a36Sopenharmony_ci	 * communication channels.
256362306a36Sopenharmony_ci	 */
256462306a36Sopenharmony_ci	for (slave = 0; slave < dev->num_slaves; slave++) {
256562306a36Sopenharmony_ci		slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read));
256662306a36Sopenharmony_ci		slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR;
256762306a36Sopenharmony_ci		__raw_writel((__force u32)cpu_to_be32(slave_read),
256862306a36Sopenharmony_ci			     &priv->mfunc.comm[slave].slave_read);
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_civoid mlx4_multi_func_cleanup(struct mlx4_dev *dev)
257362306a36Sopenharmony_ci{
257462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
257562306a36Sopenharmony_ci	int i, port;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	if (mlx4_is_master(dev)) {
257862306a36Sopenharmony_ci		destroy_workqueue(priv->mfunc.master.comm_wq);
257962306a36Sopenharmony_ci		for (i = 0; i < dev->num_slaves; i++) {
258062306a36Sopenharmony_ci			for (port = 1; port <= MLX4_MAX_PORTS; port++)
258162306a36Sopenharmony_ci				kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
258262306a36Sopenharmony_ci		}
258362306a36Sopenharmony_ci		kfree(priv->mfunc.master.slave_state);
258462306a36Sopenharmony_ci		kfree(priv->mfunc.master.vf_admin);
258562306a36Sopenharmony_ci		kfree(priv->mfunc.master.vf_oper);
258662306a36Sopenharmony_ci		dev->num_slaves = 0;
258762306a36Sopenharmony_ci	}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	iounmap(priv->mfunc.comm);
259062306a36Sopenharmony_ci	priv->mfunc.comm = NULL;
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_civoid mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
259462306a36Sopenharmony_ci{
259562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	if (priv->cmd.pool && (cleanup_mask & MLX4_CMD_CLEANUP_POOL)) {
259862306a36Sopenharmony_ci		dma_pool_destroy(priv->cmd.pool);
259962306a36Sopenharmony_ci		priv->cmd.pool = NULL;
260062306a36Sopenharmony_ci	}
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	if (!mlx4_is_slave(dev) && priv->cmd.hcr &&
260362306a36Sopenharmony_ci	    (cleanup_mask & MLX4_CMD_CLEANUP_HCR)) {
260462306a36Sopenharmony_ci		iounmap(priv->cmd.hcr);
260562306a36Sopenharmony_ci		priv->cmd.hcr = NULL;
260662306a36Sopenharmony_ci	}
260762306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr &&
260862306a36Sopenharmony_ci	    (cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) {
260962306a36Sopenharmony_ci		dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
261062306a36Sopenharmony_ci				  priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
261162306a36Sopenharmony_ci		priv->mfunc.vhcr = NULL;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci	if (priv->cmd.initialized && (cleanup_mask & MLX4_CMD_CLEANUP_STRUCT))
261462306a36Sopenharmony_ci		priv->cmd.initialized = 0;
261562306a36Sopenharmony_ci}
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci/*
261862306a36Sopenharmony_ci * Switch to using events to issue FW commands (can only be called
261962306a36Sopenharmony_ci * after event queue for command events has been initialized).
262062306a36Sopenharmony_ci */
262162306a36Sopenharmony_ciint mlx4_cmd_use_events(struct mlx4_dev *dev)
262262306a36Sopenharmony_ci{
262362306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
262462306a36Sopenharmony_ci	int i;
262562306a36Sopenharmony_ci	int err = 0;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	priv->cmd.context = kmalloc_array(priv->cmd.max_cmds,
262862306a36Sopenharmony_ci					  sizeof(struct mlx4_cmd_context),
262962306a36Sopenharmony_ci					  GFP_KERNEL);
263062306a36Sopenharmony_ci	if (!priv->cmd.context)
263162306a36Sopenharmony_ci		return -ENOMEM;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev))
263462306a36Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
263562306a36Sopenharmony_ci	down_write(&priv->cmd.switch_sem);
263662306a36Sopenharmony_ci	for (i = 0; i < priv->cmd.max_cmds; ++i) {
263762306a36Sopenharmony_ci		priv->cmd.context[i].token = i;
263862306a36Sopenharmony_ci		priv->cmd.context[i].next  = i + 1;
263962306a36Sopenharmony_ci		/* To support fatal error flow, initialize all
264062306a36Sopenharmony_ci		 * cmd contexts to allow simulating completions
264162306a36Sopenharmony_ci		 * with complete() at any time.
264262306a36Sopenharmony_ci		 */
264362306a36Sopenharmony_ci		init_completion(&priv->cmd.context[i].done);
264462306a36Sopenharmony_ci	}
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
264762306a36Sopenharmony_ci	priv->cmd.free_head = 0;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	for (priv->cmd.token_mask = 1;
265262306a36Sopenharmony_ci	     priv->cmd.token_mask < priv->cmd.max_cmds;
265362306a36Sopenharmony_ci	     priv->cmd.token_mask <<= 1)
265462306a36Sopenharmony_ci		; /* nothing */
265562306a36Sopenharmony_ci	--priv->cmd.token_mask;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	down(&priv->cmd.poll_sem);
265862306a36Sopenharmony_ci	priv->cmd.use_events = 1;
265962306a36Sopenharmony_ci	up_write(&priv->cmd.switch_sem);
266062306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev))
266162306a36Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	return err;
266462306a36Sopenharmony_ci}
266562306a36Sopenharmony_ci
266662306a36Sopenharmony_ci/*
266762306a36Sopenharmony_ci * Switch back to polling (used when shutting down the device)
266862306a36Sopenharmony_ci */
266962306a36Sopenharmony_civoid mlx4_cmd_use_polling(struct mlx4_dev *dev)
267062306a36Sopenharmony_ci{
267162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
267262306a36Sopenharmony_ci	int i;
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev))
267562306a36Sopenharmony_ci		mutex_lock(&priv->cmd.slave_cmd_mutex);
267662306a36Sopenharmony_ci	down_write(&priv->cmd.switch_sem);
267762306a36Sopenharmony_ci	priv->cmd.use_events = 0;
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	for (i = 0; i < priv->cmd.max_cmds; ++i)
268062306a36Sopenharmony_ci		down(&priv->cmd.event_sem);
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	kfree(priv->cmd.context);
268362306a36Sopenharmony_ci	priv->cmd.context = NULL;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	up(&priv->cmd.poll_sem);
268662306a36Sopenharmony_ci	up_write(&priv->cmd.switch_sem);
268762306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev))
268862306a36Sopenharmony_ci		mutex_unlock(&priv->cmd.slave_cmd_mutex);
268962306a36Sopenharmony_ci}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_cistruct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
269262306a36Sopenharmony_ci{
269362306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL);
269662306a36Sopenharmony_ci	if (!mailbox)
269762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	mailbox->buf = dma_pool_zalloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL,
270062306a36Sopenharmony_ci				       &mailbox->dma);
270162306a36Sopenharmony_ci	if (!mailbox->buf) {
270262306a36Sopenharmony_ci		kfree(mailbox);
270362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
270462306a36Sopenharmony_ci	}
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	return mailbox;
270762306a36Sopenharmony_ci}
270862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_civoid mlx4_free_cmd_mailbox(struct mlx4_dev *dev,
271162306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *mailbox)
271262306a36Sopenharmony_ci{
271362306a36Sopenharmony_ci	if (!mailbox)
271462306a36Sopenharmony_ci		return;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	dma_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma);
271762306a36Sopenharmony_ci	kfree(mailbox);
271862306a36Sopenharmony_ci}
271962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ciu32 mlx4_comm_get_version(void)
272262306a36Sopenharmony_ci{
272362306a36Sopenharmony_ci	 return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
272462306a36Sopenharmony_ci}
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_cistatic int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
272762306a36Sopenharmony_ci{
272862306a36Sopenharmony_ci	if ((vf < 0) || (vf >= dev->persist->num_vfs)) {
272962306a36Sopenharmony_ci		mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n",
273062306a36Sopenharmony_ci			 vf, dev->persist->num_vfs);
273162306a36Sopenharmony_ci		return -EINVAL;
273262306a36Sopenharmony_ci	}
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	return vf+1;
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ciint mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
273862306a36Sopenharmony_ci{
273962306a36Sopenharmony_ci	if (slave < 1 || slave > dev->persist->num_vfs) {
274062306a36Sopenharmony_ci		mlx4_err(dev,
274162306a36Sopenharmony_ci			 "Bad slave number:%d (number of activated slaves: %lu)\n",
274262306a36Sopenharmony_ci			 slave, dev->num_slaves);
274362306a36Sopenharmony_ci		return -EINVAL;
274462306a36Sopenharmony_ci	}
274562306a36Sopenharmony_ci	return slave - 1;
274662306a36Sopenharmony_ci}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_civoid mlx4_cmd_wake_completions(struct mlx4_dev *dev)
274962306a36Sopenharmony_ci{
275062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
275162306a36Sopenharmony_ci	struct mlx4_cmd_context *context;
275262306a36Sopenharmony_ci	int i;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	spin_lock(&priv->cmd.context_lock);
275562306a36Sopenharmony_ci	if (priv->cmd.context) {
275662306a36Sopenharmony_ci		for (i = 0; i < priv->cmd.max_cmds; ++i) {
275762306a36Sopenharmony_ci			context = &priv->cmd.context[i];
275862306a36Sopenharmony_ci			context->fw_status = CMD_STAT_INTERNAL_ERR;
275962306a36Sopenharmony_ci			context->result    =
276062306a36Sopenharmony_ci				mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
276162306a36Sopenharmony_ci			complete(&context->done);
276262306a36Sopenharmony_ci		}
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci	spin_unlock(&priv->cmd.context_lock);
276562306a36Sopenharmony_ci}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_cistruct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave)
276862306a36Sopenharmony_ci{
276962306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports;
277062306a36Sopenharmony_ci	int vf;
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	if (slave == 0) {
277562306a36Sopenharmony_ci		bitmap_fill(actv_ports.ports, dev->caps.num_ports);
277662306a36Sopenharmony_ci		return actv_ports;
277762306a36Sopenharmony_ci	}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	vf = mlx4_get_vf_indx(dev, slave);
278062306a36Sopenharmony_ci	if (vf < 0)
278162306a36Sopenharmony_ci		return actv_ports;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1,
278462306a36Sopenharmony_ci		   min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports,
278562306a36Sopenharmony_ci		   dev->caps.num_ports));
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	return actv_ports;
278862306a36Sopenharmony_ci}
278962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_active_ports);
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ciint mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port)
279262306a36Sopenharmony_ci{
279362306a36Sopenharmony_ci	unsigned n;
279462306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
279562306a36Sopenharmony_ci	unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	if (port <= 0 || port > m)
279862306a36Sopenharmony_ci		return -EINVAL;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	n = find_first_bit(actv_ports.ports, dev->caps.num_ports);
280162306a36Sopenharmony_ci	if (port <= n)
280262306a36Sopenharmony_ci		port = n + 1;
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	return port;
280562306a36Sopenharmony_ci}
280662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_slave_convert_port);
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ciint mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port)
280962306a36Sopenharmony_ci{
281062306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
281162306a36Sopenharmony_ci	if (test_bit(port - 1, actv_ports.ports))
281262306a36Sopenharmony_ci		return port -
281362306a36Sopenharmony_ci			find_first_bit(actv_ports.ports, dev->caps.num_ports);
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	return -1;
281662306a36Sopenharmony_ci}
281762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port);
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
282062306a36Sopenharmony_ci						   int port)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	unsigned i;
282362306a36Sopenharmony_ci	struct mlx4_slaves_pport slaves_pport;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci	bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	if (port <= 0 || port > dev->caps.num_ports)
282862306a36Sopenharmony_ci		return slaves_pport;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	for (i = 0; i < dev->persist->num_vfs + 1; i++) {
283162306a36Sopenharmony_ci		struct mlx4_active_ports actv_ports =
283262306a36Sopenharmony_ci			mlx4_get_active_ports(dev, i);
283362306a36Sopenharmony_ci		if (test_bit(port - 1, actv_ports.ports))
283462306a36Sopenharmony_ci			set_bit(i, slaves_pport.slaves);
283562306a36Sopenharmony_ci	}
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	return slaves_pport;
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport);
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_cistruct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
284262306a36Sopenharmony_ci		struct mlx4_dev *dev,
284362306a36Sopenharmony_ci		const struct mlx4_active_ports *crit_ports)
284462306a36Sopenharmony_ci{
284562306a36Sopenharmony_ci	unsigned i;
284662306a36Sopenharmony_ci	struct mlx4_slaves_pport slaves_pport;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	for (i = 0; i < dev->persist->num_vfs + 1; i++) {
285162306a36Sopenharmony_ci		struct mlx4_active_ports actv_ports =
285262306a36Sopenharmony_ci			mlx4_get_active_ports(dev, i);
285362306a36Sopenharmony_ci		if (bitmap_equal(crit_ports->ports, actv_ports.ports,
285462306a36Sopenharmony_ci				 dev->caps.num_ports))
285562306a36Sopenharmony_ci			set_bit(i, slaves_pport.slaves);
285662306a36Sopenharmony_ci	}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	return slaves_pport;
285962306a36Sopenharmony_ci}
286062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_cistatic int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port)
286362306a36Sopenharmony_ci{
286462306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
286562306a36Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports, dev->caps.num_ports)
286662306a36Sopenharmony_ci			+ 1;
286762306a36Sopenharmony_ci	int max_port = min_port +
286862306a36Sopenharmony_ci		bitmap_weight(actv_ports.ports, dev->caps.num_ports);
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	if (port < min_port)
287162306a36Sopenharmony_ci		port = min_port;
287262306a36Sopenharmony_ci	else if (port >= max_port)
287362306a36Sopenharmony_ci		port = max_port - 1;
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	return port;
287662306a36Sopenharmony_ci}
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_cistatic int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port,
287962306a36Sopenharmony_ci			      int max_tx_rate)
288062306a36Sopenharmony_ci{
288162306a36Sopenharmony_ci	int i;
288262306a36Sopenharmony_ci	int err;
288362306a36Sopenharmony_ci	struct mlx4_qos_manager *port_qos;
288462306a36Sopenharmony_ci	struct mlx4_dev *dev = &priv->dev;
288562306a36Sopenharmony_ci	struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP];
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	port_qos = &priv->mfunc.master.qos_ctl[port];
288862306a36Sopenharmony_ci	memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	if (slave > port_qos->num_of_qos_vfs) {
289162306a36Sopenharmony_ci		mlx4_info(dev, "No available VPP resources for this VF\n");
289262306a36Sopenharmony_ci		return -EINVAL;
289362306a36Sopenharmony_ci	}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_ci	/* Query for default QoS values from Vport 0 is needed */
289662306a36Sopenharmony_ci	err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos);
289762306a36Sopenharmony_ci	if (err) {
289862306a36Sopenharmony_ci		mlx4_info(dev, "Failed to query Vport 0 QoS values\n");
289962306a36Sopenharmony_ci		return err;
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	for (i = 0; i < MLX4_NUM_UP; i++) {
290362306a36Sopenharmony_ci		if (test_bit(i, port_qos->priority_bm) && max_tx_rate) {
290462306a36Sopenharmony_ci			vpp_qos[i].max_avg_bw = max_tx_rate;
290562306a36Sopenharmony_ci			vpp_qos[i].enable = 1;
290662306a36Sopenharmony_ci		} else {
290762306a36Sopenharmony_ci			/* if user supplied tx_rate == 0, meaning no rate limit
290862306a36Sopenharmony_ci			 * configuration is required. so we are leaving the
290962306a36Sopenharmony_ci			 * value of max_avg_bw as queried from Vport 0.
291062306a36Sopenharmony_ci			 */
291162306a36Sopenharmony_ci			vpp_qos[i].enable = 0;
291262306a36Sopenharmony_ci		}
291362306a36Sopenharmony_ci	}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos);
291662306a36Sopenharmony_ci	if (err) {
291762306a36Sopenharmony_ci		mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave);
291862306a36Sopenharmony_ci		return err;
291962306a36Sopenharmony_ci	}
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	return 0;
292262306a36Sopenharmony_ci}
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_cistatic bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port,
292562306a36Sopenharmony_ci					struct mlx4_vport_state *vf_admin)
292662306a36Sopenharmony_ci{
292762306a36Sopenharmony_ci	struct mlx4_qos_manager *info;
292862306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	if (!mlx4_is_master(dev) ||
293162306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
293262306a36Sopenharmony_ci		return false;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	info = &priv->mfunc.master.qos_ctl[port];
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	if (vf_admin->default_vlan != MLX4_VGT &&
293762306a36Sopenharmony_ci	    test_bit(vf_admin->default_qos, info->priority_bm))
293862306a36Sopenharmony_ci		return true;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	return false;
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_cistatic bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port,
294462306a36Sopenharmony_ci				       struct mlx4_vport_state *vf_admin,
294562306a36Sopenharmony_ci				       int vlan, int qos)
294662306a36Sopenharmony_ci{
294762306a36Sopenharmony_ci	struct mlx4_vport_state dummy_admin = {0};
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) ||
295062306a36Sopenharmony_ci	    !vf_admin->tx_rate)
295162306a36Sopenharmony_ci		return true;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	dummy_admin.default_qos = qos;
295462306a36Sopenharmony_ci	dummy_admin.default_vlan = vlan;
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	/* VF wants to move to other VST state which is valid with current
295762306a36Sopenharmony_ci	 * rate limit. Either differnt default vlan in VST or other
295862306a36Sopenharmony_ci	 * supported QoS priority. Otherwise we don't allow this change when
295962306a36Sopenharmony_ci	 * the TX rate is still configured.
296062306a36Sopenharmony_ci	 */
296162306a36Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin))
296262306a36Sopenharmony_ci		return true;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	mlx4_info(dev, "Cannot change VF state to %s while rate is set\n",
296562306a36Sopenharmony_ci		  (vlan == MLX4_VGT) ? "VGT" : "VST");
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	if (vlan != MLX4_VGT)
296862306a36Sopenharmony_ci		mlx4_info(dev, "VST priority %d not supported for QoS\n", qos);
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci	mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n");
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	return false;
297362306a36Sopenharmony_ci}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ciint mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u8 *mac)
297662306a36Sopenharmony_ci{
297762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
297862306a36Sopenharmony_ci	struct mlx4_vport_state *s_info;
297962306a36Sopenharmony_ci	int slave;
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	if (!mlx4_is_master(dev))
298262306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	if (is_multicast_ether_addr(mac))
298562306a36Sopenharmony_ci		return -EINVAL;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
298862306a36Sopenharmony_ci	if (slave < 0)
298962306a36Sopenharmony_ci		return -EINVAL;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
299262306a36Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	if (s_info->spoofchk && is_zero_ether_addr(mac)) {
299562306a36Sopenharmony_ci		mlx4_info(dev, "MAC invalidation is not allowed when spoofchk is on\n");
299662306a36Sopenharmony_ci		return -EPERM;
299762306a36Sopenharmony_ci	}
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	s_info->mac = ether_addr_to_u64(mac);
300062306a36Sopenharmony_ci	mlx4_info(dev, "default mac on vf %d port %d to %llX will take effect only after vf restart\n",
300162306a36Sopenharmony_ci		  vf, port, s_info->mac);
300262306a36Sopenharmony_ci	return 0;
300362306a36Sopenharmony_ci}
300462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ciint mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos,
300862306a36Sopenharmony_ci		     __be16 proto)
300962306a36Sopenharmony_ci{
301062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
301162306a36Sopenharmony_ci	struct mlx4_vport_state *vf_admin;
301262306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state;
301362306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vf_oper;
301462306a36Sopenharmony_ci	int slave;
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	if ((!mlx4_is_master(dev)) ||
301762306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
301862306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	if ((vlan > 4095) || (qos > 7))
302162306a36Sopenharmony_ci		return -EINVAL;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	if (proto == htons(ETH_P_8021AD) &&
302462306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP))
302562306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci	if (proto != htons(ETH_P_8021Q) &&
302862306a36Sopenharmony_ci	    proto != htons(ETH_P_8021AD))
302962306a36Sopenharmony_ci		return -EINVAL;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD)) &&
303262306a36Sopenharmony_ci	    ((vlan == 0) || (vlan == MLX4_VGT)))
303362306a36Sopenharmony_ci		return -EINVAL;
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
303662306a36Sopenharmony_ci	if (slave < 0)
303762306a36Sopenharmony_ci		return -EINVAL;
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	slave_state = &priv->mfunc.master.slave_state[slave];
304062306a36Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD)) && (slave_state->active) &&
304162306a36Sopenharmony_ci	    (!slave_state->vst_qinq_supported)) {
304262306a36Sopenharmony_ci		mlx4_err(dev, "vf %d does not support VST QinQ mode\n", vf);
304362306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
304662306a36Sopenharmony_ci	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
304762306a36Sopenharmony_ci	vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos))
305062306a36Sopenharmony_ci		return -EPERM;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	if ((0 == vlan) && (0 == qos))
305362306a36Sopenharmony_ci		vf_admin->default_vlan = MLX4_VGT;
305462306a36Sopenharmony_ci	else
305562306a36Sopenharmony_ci		vf_admin->default_vlan = vlan;
305662306a36Sopenharmony_ci	vf_admin->default_qos = qos;
305762306a36Sopenharmony_ci	vf_admin->vlan_proto = proto;
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	/* If rate was configured prior to VST, we saved the configured rate
306062306a36Sopenharmony_ci	 * in vf_admin->rate and now, if priority supported we enforce the QoS
306162306a36Sopenharmony_ci	 */
306262306a36Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) &&
306362306a36Sopenharmony_ci	    vf_admin->tx_rate)
306462306a36Sopenharmony_ci		vf_admin->qos_vport = slave;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	/* Try to activate new vf state without restart,
306762306a36Sopenharmony_ci	 * this option is not supported while moving to VST QinQ mode.
306862306a36Sopenharmony_ci	 */
306962306a36Sopenharmony_ci	if ((proto == htons(ETH_P_8021AD) &&
307062306a36Sopenharmony_ci	     vf_oper->state.vlan_proto != proto) ||
307162306a36Sopenharmony_ci	    mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
307262306a36Sopenharmony_ci		mlx4_info(dev,
307362306a36Sopenharmony_ci			  "updating vf %d port %d config will take effect on next VF restart\n",
307462306a36Sopenharmony_ci			  vf, port);
307562306a36Sopenharmony_ci	return 0;
307662306a36Sopenharmony_ci}
307762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ciint mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate,
308062306a36Sopenharmony_ci		     int max_tx_rate)
308162306a36Sopenharmony_ci{
308262306a36Sopenharmony_ci	int err;
308362306a36Sopenharmony_ci	int slave;
308462306a36Sopenharmony_ci	struct mlx4_vport_state *vf_admin;
308562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	if (!mlx4_is_master(dev) ||
308862306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
308962306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci	if (min_tx_rate) {
309262306a36Sopenharmony_ci		mlx4_info(dev, "Minimum BW share not supported\n");
309362306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
309462306a36Sopenharmony_ci	}
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
309762306a36Sopenharmony_ci	if (slave < 0)
309862306a36Sopenharmony_ci		return -EINVAL;
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
310162306a36Sopenharmony_ci	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate);
310462306a36Sopenharmony_ci	if (err) {
310562306a36Sopenharmony_ci		mlx4_info(dev, "vf %d failed to set rate %d\n", vf,
310662306a36Sopenharmony_ci			  max_tx_rate);
310762306a36Sopenharmony_ci		return err;
310862306a36Sopenharmony_ci	}
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	vf_admin->tx_rate = max_tx_rate;
311162306a36Sopenharmony_ci	/* if VF is not in supported mode (VST with supported prio),
311262306a36Sopenharmony_ci	 * we do not change vport configuration for its QPs, but save
311362306a36Sopenharmony_ci	 * the rate, so it will be enforced when it moves to supported
311462306a36Sopenharmony_ci	 * mode next time.
311562306a36Sopenharmony_ci	 */
311662306a36Sopenharmony_ci	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) {
311762306a36Sopenharmony_ci		mlx4_info(dev,
311862306a36Sopenharmony_ci			  "rate set for VF %d when not in valid state\n", vf);
311962306a36Sopenharmony_ci
312062306a36Sopenharmony_ci		if (vf_admin->default_vlan != MLX4_VGT)
312162306a36Sopenharmony_ci			mlx4_info(dev, "VST priority not supported by QoS\n");
312262306a36Sopenharmony_ci		else
312362306a36Sopenharmony_ci			mlx4_info(dev, "VF in VGT mode (needed VST)\n");
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci		mlx4_info(dev,
312662306a36Sopenharmony_ci			  "rate %d take affect when VF moves to valid state\n",
312762306a36Sopenharmony_ci			  max_tx_rate);
312862306a36Sopenharmony_ci		return 0;
312962306a36Sopenharmony_ci	}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	/* If user sets rate 0 assigning default vport for its QPs */
313262306a36Sopenharmony_ci	vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT;
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	if (priv->mfunc.master.slave_state[slave].active &&
313562306a36Sopenharmony_ci	    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)
313662306a36Sopenharmony_ci		mlx4_master_immediate_activate_vlan_qos(priv, slave, port);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	return 0;
313962306a36Sopenharmony_ci}
314062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_rate);
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci /* mlx4_get_slave_default_vlan -
314362306a36Sopenharmony_ci * return true if VST ( default vlan)
314462306a36Sopenharmony_ci * if VST, will return vlan & qos (if not NULL)
314562306a36Sopenharmony_ci */
314662306a36Sopenharmony_cibool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
314762306a36Sopenharmony_ci				 u16 *vlan, u8 *qos)
314862306a36Sopenharmony_ci{
314962306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
315062306a36Sopenharmony_ci	struct mlx4_priv *priv;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	priv = mlx4_priv(dev);
315362306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
315462306a36Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	if (MLX4_VGT != vp_oper->state.default_vlan) {
315762306a36Sopenharmony_ci		if (vlan)
315862306a36Sopenharmony_ci			*vlan = vp_oper->state.default_vlan;
315962306a36Sopenharmony_ci		if (qos)
316062306a36Sopenharmony_ci			*qos = vp_oper->state.default_qos;
316162306a36Sopenharmony_ci		return true;
316262306a36Sopenharmony_ci	}
316362306a36Sopenharmony_ci	return false;
316462306a36Sopenharmony_ci}
316562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan);
316662306a36Sopenharmony_ci
316762306a36Sopenharmony_ciint mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
316862306a36Sopenharmony_ci{
316962306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
317062306a36Sopenharmony_ci	struct mlx4_vport_state *s_info;
317162306a36Sopenharmony_ci	int slave;
317262306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	if ((!mlx4_is_master(dev)) ||
317562306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM))
317662306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
317962306a36Sopenharmony_ci	if (slave < 0)
318062306a36Sopenharmony_ci		return -EINVAL;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
318362306a36Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	u64_to_ether_addr(s_info->mac, mac);
318662306a36Sopenharmony_ci	if (setting && !is_valid_ether_addr(mac)) {
318762306a36Sopenharmony_ci		mlx4_info(dev, "Illegal MAC with spoofchk\n");
318862306a36Sopenharmony_ci		return -EPERM;
318962306a36Sopenharmony_ci	}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	s_info->spoofchk = setting;
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	return 0;
319462306a36Sopenharmony_ci}
319562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ciint mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf)
319862306a36Sopenharmony_ci{
319962306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
320062306a36Sopenharmony_ci	struct mlx4_vport_state *s_info;
320162306a36Sopenharmony_ci	int slave;
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	if (!mlx4_is_master(dev))
320462306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
320762306a36Sopenharmony_ci	if (slave < 0)
320862306a36Sopenharmony_ci		return -EINVAL;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
321162306a36Sopenharmony_ci	ivf->vf = vf;
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	/* need to convert it to a func */
321462306a36Sopenharmony_ci	ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff);
321562306a36Sopenharmony_ci	ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff);
321662306a36Sopenharmony_ci	ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff);
321762306a36Sopenharmony_ci	ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff);
321862306a36Sopenharmony_ci	ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff);
321962306a36Sopenharmony_ci	ivf->mac[5] = ((s_info->mac)  & 0xff);
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	ivf->vlan		= s_info->default_vlan;
322262306a36Sopenharmony_ci	ivf->qos		= s_info->default_qos;
322362306a36Sopenharmony_ci	ivf->vlan_proto		= s_info->vlan_proto;
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci	if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info))
322662306a36Sopenharmony_ci		ivf->max_tx_rate = s_info->tx_rate;
322762306a36Sopenharmony_ci	else
322862306a36Sopenharmony_ci		ivf->max_tx_rate = 0;
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	ivf->min_tx_rate	= 0;
323162306a36Sopenharmony_ci	ivf->spoofchk		= s_info->spoofchk;
323262306a36Sopenharmony_ci	ivf->linkstate		= s_info->link_state;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	return 0;
323562306a36Sopenharmony_ci}
323662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_config);
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ciint mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state)
323962306a36Sopenharmony_ci{
324062306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
324162306a36Sopenharmony_ci	struct mlx4_vport_state *s_info;
324262306a36Sopenharmony_ci	int slave;
324362306a36Sopenharmony_ci	u8 link_stat_event;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf);
324662306a36Sopenharmony_ci	if (slave < 0)
324762306a36Sopenharmony_ci		return -EINVAL;
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
325062306a36Sopenharmony_ci	switch (link_state) {
325162306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
325262306a36Sopenharmony_ci		/* get current link state */
325362306a36Sopenharmony_ci		if (!priv->sense.do_sense_port[port])
325462306a36Sopenharmony_ci			link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
325562306a36Sopenharmony_ci		else
325662306a36Sopenharmony_ci			link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
325762306a36Sopenharmony_ci	    break;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
326062306a36Sopenharmony_ci		link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
326162306a36Sopenharmony_ci	    break;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
326462306a36Sopenharmony_ci		link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
326562306a36Sopenharmony_ci	    break;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	default:
326862306a36Sopenharmony_ci		mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n",
326962306a36Sopenharmony_ci			  link_state, slave, port);
327062306a36Sopenharmony_ci		return -EINVAL;
327162306a36Sopenharmony_ci	}
327262306a36Sopenharmony_ci	s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
327362306a36Sopenharmony_ci	s_info->link_state = link_state;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	/* send event */
327662306a36Sopenharmony_ci	mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
327962306a36Sopenharmony_ci		mlx4_dbg(dev,
328062306a36Sopenharmony_ci			 "updating vf %d port %d no link state HW enforcement\n",
328162306a36Sopenharmony_ci			 vf, port);
328262306a36Sopenharmony_ci	return 0;
328362306a36Sopenharmony_ci}
328462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ciint mlx4_get_counter_stats(struct mlx4_dev *dev, int counter_index,
328762306a36Sopenharmony_ci			   struct mlx4_counter *counter_stats, int reset)
328862306a36Sopenharmony_ci{
328962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox = NULL;
329062306a36Sopenharmony_ci	struct mlx4_counter *tmp_counter;
329162306a36Sopenharmony_ci	int err;
329262306a36Sopenharmony_ci	u32 if_stat_in_mod;
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ci	if (!counter_stats)
329562306a36Sopenharmony_ci		return -EINVAL;
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	if (counter_index == MLX4_SINK_COUNTER_INDEX(dev))
329862306a36Sopenharmony_ci		return 0;
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
330162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
330262306a36Sopenharmony_ci		return PTR_ERR(mailbox);
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	memset(mailbox->buf, 0, sizeof(struct mlx4_counter));
330562306a36Sopenharmony_ci	if_stat_in_mod = counter_index;
330662306a36Sopenharmony_ci	if (reset)
330762306a36Sopenharmony_ci		if_stat_in_mod |= MLX4_QUERY_IF_STAT_RESET;
330862306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma,
330962306a36Sopenharmony_ci			   if_stat_in_mod, 0,
331062306a36Sopenharmony_ci			   MLX4_CMD_QUERY_IF_STAT,
331162306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_C,
331262306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
331362306a36Sopenharmony_ci	if (err) {
331462306a36Sopenharmony_ci		mlx4_dbg(dev, "%s: failed to read statistics for counter index %d\n",
331562306a36Sopenharmony_ci			 __func__, counter_index);
331662306a36Sopenharmony_ci		goto if_stat_out;
331762306a36Sopenharmony_ci	}
331862306a36Sopenharmony_ci	tmp_counter = (struct mlx4_counter *)mailbox->buf;
331962306a36Sopenharmony_ci	counter_stats->counter_mode = tmp_counter->counter_mode;
332062306a36Sopenharmony_ci	if (counter_stats->counter_mode == 0) {
332162306a36Sopenharmony_ci		counter_stats->rx_frames =
332262306a36Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->rx_frames) +
332362306a36Sopenharmony_ci				    be64_to_cpu(tmp_counter->rx_frames));
332462306a36Sopenharmony_ci		counter_stats->tx_frames =
332562306a36Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->tx_frames) +
332662306a36Sopenharmony_ci				    be64_to_cpu(tmp_counter->tx_frames));
332762306a36Sopenharmony_ci		counter_stats->rx_bytes =
332862306a36Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->rx_bytes) +
332962306a36Sopenharmony_ci				    be64_to_cpu(tmp_counter->rx_bytes));
333062306a36Sopenharmony_ci		counter_stats->tx_bytes =
333162306a36Sopenharmony_ci			cpu_to_be64(be64_to_cpu(counter_stats->tx_bytes) +
333262306a36Sopenharmony_ci				    be64_to_cpu(tmp_counter->tx_bytes));
333362306a36Sopenharmony_ci	}
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ciif_stat_out:
333662306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	return err;
333962306a36Sopenharmony_ci}
334062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_counter_stats);
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ciint mlx4_get_vf_stats(struct mlx4_dev *dev, int port, int vf_idx,
334362306a36Sopenharmony_ci		      struct ifla_vf_stats *vf_stats)
334462306a36Sopenharmony_ci{
334562306a36Sopenharmony_ci	struct mlx4_counter tmp_vf_stats;
334662306a36Sopenharmony_ci	int slave;
334762306a36Sopenharmony_ci	int err = 0;
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	if (!vf_stats)
335062306a36Sopenharmony_ci		return -EINVAL;
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	if (!mlx4_is_master(dev))
335362306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	slave = mlx4_get_slave_indx(dev, vf_idx);
335662306a36Sopenharmony_ci	if (slave < 0)
335762306a36Sopenharmony_ci		return -EINVAL;
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	port = mlx4_slaves_closest_port(dev, slave, port);
336062306a36Sopenharmony_ci	err = mlx4_calc_vf_counters(dev, slave, port, &tmp_vf_stats);
336162306a36Sopenharmony_ci	if (!err && tmp_vf_stats.counter_mode == 0) {
336262306a36Sopenharmony_ci		vf_stats->rx_packets = be64_to_cpu(tmp_vf_stats.rx_frames);
336362306a36Sopenharmony_ci		vf_stats->tx_packets = be64_to_cpu(tmp_vf_stats.tx_frames);
336462306a36Sopenharmony_ci		vf_stats->rx_bytes = be64_to_cpu(tmp_vf_stats.rx_bytes);
336562306a36Sopenharmony_ci		vf_stats->tx_bytes = be64_to_cpu(tmp_vf_stats.tx_bytes);
336662306a36Sopenharmony_ci	}
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	return err;
336962306a36Sopenharmony_ci}
337062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_get_vf_stats);
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ciint mlx4_vf_smi_enabled(struct mlx4_dev *dev, int slave, int port)
337362306a36Sopenharmony_ci{
337462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
337762306a36Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS)
337862306a36Sopenharmony_ci		return 0;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	return priv->mfunc.master.vf_oper[slave].smi_enabled[port] ==
338162306a36Sopenharmony_ci		MLX4_VF_SMI_ENABLED;
338262306a36Sopenharmony_ci}
338362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_smi_enabled);
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ciint mlx4_vf_get_enable_smi_admin(struct mlx4_dev *dev, int slave, int port)
338662306a36Sopenharmony_ci{
338762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	if (slave == mlx4_master_func_num(dev))
339062306a36Sopenharmony_ci		return 1;
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
339362306a36Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS)
339462306a36Sopenharmony_ci		return 0;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	return priv->mfunc.master.vf_admin[slave].enable_smi[port] ==
339762306a36Sopenharmony_ci		MLX4_VF_SMI_ENABLED;
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_get_enable_smi_admin);
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ciint mlx4_vf_set_enable_smi_admin(struct mlx4_dev *dev, int slave, int port,
340262306a36Sopenharmony_ci				 int enabled)
340362306a36Sopenharmony_ci{
340462306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
340562306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
340662306a36Sopenharmony_ci			&priv->dev, slave);
340762306a36Sopenharmony_ci	int min_port = find_first_bit(actv_ports.ports,
340862306a36Sopenharmony_ci				      priv->dev.caps.num_ports) + 1;
340962306a36Sopenharmony_ci	int max_port = min_port - 1 +
341062306a36Sopenharmony_ci		bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	if (slave == mlx4_master_func_num(dev))
341362306a36Sopenharmony_ci		return 0;
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	if (slave < 1 || slave >= dev->num_slaves ||
341662306a36Sopenharmony_ci	    port < 1 || port > MLX4_MAX_PORTS ||
341762306a36Sopenharmony_ci	    enabled < 0 || enabled > 1)
341862306a36Sopenharmony_ci		return -EINVAL;
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	if (min_port == max_port && dev->caps.num_ports > 1) {
342162306a36Sopenharmony_ci		mlx4_info(dev, "SMI access disallowed for single ported VFs\n");
342262306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
342362306a36Sopenharmony_ci	}
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	priv->mfunc.master.vf_admin[slave].enable_smi[port] = enabled;
342662306a36Sopenharmony_ci	return 0;
342762306a36Sopenharmony_ci}
342862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_vf_set_enable_smi_admin);
3429