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/etherdevice.h>
3662306a36Sopenharmony_ci#include <linux/mlx4/cmd.h>
3762306a36Sopenharmony_ci#include <linux/module.h>
3862306a36Sopenharmony_ci#include <linux/cache.h>
3962306a36Sopenharmony_ci#include <linux/kernel.h>
4062306a36Sopenharmony_ci#include <uapi/rdma/mlx4-abi.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include "fw.h"
4362306a36Sopenharmony_ci#include "icm.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cienum {
4662306a36Sopenharmony_ci	MLX4_COMMAND_INTERFACE_MIN_REV		= 2,
4762306a36Sopenharmony_ci	MLX4_COMMAND_INTERFACE_MAX_REV		= 3,
4862306a36Sopenharmony_ci	MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS	= 3,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciextern void __buggy_use_of_MLX4_GET(void);
5262306a36Sopenharmony_ciextern void __buggy_use_of_MLX4_PUT(void);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic bool enable_qos;
5562306a36Sopenharmony_cimodule_param(enable_qos, bool, 0444);
5662306a36Sopenharmony_ciMODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: off)");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define MLX4_GET(dest, source, offset)				      \
5962306a36Sopenharmony_ci	do {							      \
6062306a36Sopenharmony_ci		void *__p = (char *) (source) + (offset);	      \
6162306a36Sopenharmony_ci		__be64 val;                                           \
6262306a36Sopenharmony_ci		switch (sizeof(dest)) {				      \
6362306a36Sopenharmony_ci		case 1: (dest) = *(u8 *) __p;	    break;	      \
6462306a36Sopenharmony_ci		case 2: (dest) = be16_to_cpup(__p); break;	      \
6562306a36Sopenharmony_ci		case 4: (dest) = be32_to_cpup(__p); break;	      \
6662306a36Sopenharmony_ci		case 8: val = get_unaligned((__be64 *)__p);           \
6762306a36Sopenharmony_ci			(dest) = be64_to_cpu(val);  break;            \
6862306a36Sopenharmony_ci		default: __buggy_use_of_MLX4_GET();		      \
6962306a36Sopenharmony_ci		}						      \
7062306a36Sopenharmony_ci	} while (0)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define MLX4_PUT(dest, source, offset)				      \
7362306a36Sopenharmony_ci	do {							      \
7462306a36Sopenharmony_ci		void *__d = ((char *) (dest) + (offset));	      \
7562306a36Sopenharmony_ci		switch (sizeof(source)) {			      \
7662306a36Sopenharmony_ci		case 1: *(u8 *) __d = (source);		       break; \
7762306a36Sopenharmony_ci		case 2:	*(__be16 *) __d = cpu_to_be16(source); break; \
7862306a36Sopenharmony_ci		case 4:	*(__be32 *) __d = cpu_to_be32(source); break; \
7962306a36Sopenharmony_ci		case 8:	*(__be64 *) __d = cpu_to_be64(source); break; \
8062306a36Sopenharmony_ci		default: __buggy_use_of_MLX4_PUT();		      \
8162306a36Sopenharmony_ci		}						      \
8262306a36Sopenharmony_ci	} while (0)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	static const char *fname[] = {
8762306a36Sopenharmony_ci		[ 0] = "RC transport",
8862306a36Sopenharmony_ci		[ 1] = "UC transport",
8962306a36Sopenharmony_ci		[ 2] = "UD transport",
9062306a36Sopenharmony_ci		[ 3] = "XRC transport",
9162306a36Sopenharmony_ci		[ 6] = "SRQ support",
9262306a36Sopenharmony_ci		[ 7] = "IPoIB checksum offload",
9362306a36Sopenharmony_ci		[ 8] = "P_Key violation counter",
9462306a36Sopenharmony_ci		[ 9] = "Q_Key violation counter",
9562306a36Sopenharmony_ci		[12] = "Dual Port Different Protocol (DPDP) support",
9662306a36Sopenharmony_ci		[15] = "Big LSO headers",
9762306a36Sopenharmony_ci		[16] = "MW support",
9862306a36Sopenharmony_ci		[17] = "APM support",
9962306a36Sopenharmony_ci		[18] = "Atomic ops support",
10062306a36Sopenharmony_ci		[19] = "Raw multicast support",
10162306a36Sopenharmony_ci		[20] = "Address vector port checking support",
10262306a36Sopenharmony_ci		[21] = "UD multicast support",
10362306a36Sopenharmony_ci		[30] = "IBoE support",
10462306a36Sopenharmony_ci		[32] = "Unicast loopback support",
10562306a36Sopenharmony_ci		[34] = "FCS header control",
10662306a36Sopenharmony_ci		[37] = "Wake On LAN (port1) support",
10762306a36Sopenharmony_ci		[38] = "Wake On LAN (port2) support",
10862306a36Sopenharmony_ci		[40] = "UDP RSS support",
10962306a36Sopenharmony_ci		[41] = "Unicast VEP steering support",
11062306a36Sopenharmony_ci		[42] = "Multicast VEP steering support",
11162306a36Sopenharmony_ci		[48] = "Counters support",
11262306a36Sopenharmony_ci		[52] = "RSS IP fragments support",
11362306a36Sopenharmony_ci		[53] = "Port ETS Scheduler support",
11462306a36Sopenharmony_ci		[55] = "Port link type sensing support",
11562306a36Sopenharmony_ci		[59] = "Port management change event support",
11662306a36Sopenharmony_ci		[61] = "64 byte EQE support",
11762306a36Sopenharmony_ci		[62] = "64 byte CQE support",
11862306a36Sopenharmony_ci	};
11962306a36Sopenharmony_ci	int i;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	mlx4_dbg(dev, "DEV_CAP flags:\n");
12262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fname); ++i)
12362306a36Sopenharmony_ci		if (fname[i] && (flags & (1LL << i)))
12462306a36Sopenharmony_ci			mlx4_dbg(dev, "    %s\n", fname[i]);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	static const char * const fname[] = {
13062306a36Sopenharmony_ci		[0] = "RSS support",
13162306a36Sopenharmony_ci		[1] = "RSS Toeplitz Hash Function support",
13262306a36Sopenharmony_ci		[2] = "RSS XOR Hash Function support",
13362306a36Sopenharmony_ci		[3] = "Device managed flow steering support",
13462306a36Sopenharmony_ci		[4] = "Automatic MAC reassignment support",
13562306a36Sopenharmony_ci		[5] = "Time stamping support",
13662306a36Sopenharmony_ci		[6] = "VST (control vlan insertion/stripping) support",
13762306a36Sopenharmony_ci		[7] = "FSM (MAC anti-spoofing) support",
13862306a36Sopenharmony_ci		[8] = "Dynamic QP updates support",
13962306a36Sopenharmony_ci		[9] = "Device managed flow steering IPoIB support",
14062306a36Sopenharmony_ci		[10] = "TCP/IP offloads/flow-steering for VXLAN support",
14162306a36Sopenharmony_ci		[11] = "MAD DEMUX (Secure-Host) support",
14262306a36Sopenharmony_ci		[12] = "Large cache line (>64B) CQE stride support",
14362306a36Sopenharmony_ci		[13] = "Large cache line (>64B) EQE stride support",
14462306a36Sopenharmony_ci		[14] = "Ethernet protocol control support",
14562306a36Sopenharmony_ci		[15] = "Ethernet Backplane autoneg support",
14662306a36Sopenharmony_ci		[16] = "CONFIG DEV support",
14762306a36Sopenharmony_ci		[17] = "Asymmetric EQs support",
14862306a36Sopenharmony_ci		[18] = "More than 80 VFs support",
14962306a36Sopenharmony_ci		[19] = "Performance optimized for limited rule configuration flow steering support",
15062306a36Sopenharmony_ci		[20] = "Recoverable error events support",
15162306a36Sopenharmony_ci		[21] = "Port Remap support",
15262306a36Sopenharmony_ci		[22] = "QCN support",
15362306a36Sopenharmony_ci		[23] = "QP rate limiting support",
15462306a36Sopenharmony_ci		[24] = "Ethernet Flow control statistics support",
15562306a36Sopenharmony_ci		[25] = "Granular QoS per VF support",
15662306a36Sopenharmony_ci		[26] = "Port ETS Scheduler support",
15762306a36Sopenharmony_ci		[27] = "Port beacon support",
15862306a36Sopenharmony_ci		[28] = "RX-ALL support",
15962306a36Sopenharmony_ci		[29] = "802.1ad offload support",
16062306a36Sopenharmony_ci		[31] = "Modifying loopback source checks using UPDATE_QP support",
16162306a36Sopenharmony_ci		[32] = "Loopback source checks support",
16262306a36Sopenharmony_ci		[33] = "RoCEv2 support",
16362306a36Sopenharmony_ci		[34] = "DMFS Sniffer support (UC & MC)",
16462306a36Sopenharmony_ci		[35] = "Diag counters per port",
16562306a36Sopenharmony_ci		[36] = "QinQ VST mode support",
16662306a36Sopenharmony_ci		[37] = "sl to vl mapping table change event support",
16762306a36Sopenharmony_ci		[38] = "user MAC support",
16862306a36Sopenharmony_ci		[39] = "Report driver version to FW support",
16962306a36Sopenharmony_ci		[40] = "SW CQ initialization support",
17062306a36Sopenharmony_ci	};
17162306a36Sopenharmony_ci	int i;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(fname); ++i)
17462306a36Sopenharmony_ci		if (fname[i] && (flags & (1LL << i)))
17562306a36Sopenharmony_ci			mlx4_dbg(dev, "    %s\n", fname[i]);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciint mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
18162306a36Sopenharmony_ci	u32 *inbox;
18262306a36Sopenharmony_ci	int err = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#define MOD_STAT_CFG_IN_SIZE		0x100
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define MOD_STAT_CFG_PG_SZ_M_OFFSET	0x002
18762306a36Sopenharmony_ci#define MOD_STAT_CFG_PG_SZ_OFFSET	0x003
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
19062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
19162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
19262306a36Sopenharmony_ci	inbox = mailbox->buf;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET);
19562306a36Sopenharmony_ci	MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG,
19862306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
20162306a36Sopenharmony_ci	return err;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciint mlx4_QUERY_FUNC(struct mlx4_dev *dev, struct mlx4_func *func, int slave)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
20762306a36Sopenharmony_ci	u32 *outbox;
20862306a36Sopenharmony_ci	u8 in_modifier;
20962306a36Sopenharmony_ci	u8 field;
21062306a36Sopenharmony_ci	u16 field16;
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#define QUERY_FUNC_BUS_OFFSET			0x00
21462306a36Sopenharmony_ci#define QUERY_FUNC_DEVICE_OFFSET		0x01
21562306a36Sopenharmony_ci#define QUERY_FUNC_FUNCTION_OFFSET		0x01
21662306a36Sopenharmony_ci#define QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET	0x03
21762306a36Sopenharmony_ci#define QUERY_FUNC_RSVD_EQS_OFFSET		0x04
21862306a36Sopenharmony_ci#define QUERY_FUNC_MAX_EQ_OFFSET		0x06
21962306a36Sopenharmony_ci#define QUERY_FUNC_RSVD_UARS_OFFSET		0x0b
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
22262306a36Sopenharmony_ci	if (IS_ERR(mailbox))
22362306a36Sopenharmony_ci		return PTR_ERR(mailbox);
22462306a36Sopenharmony_ci	outbox = mailbox->buf;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	in_modifier = slave;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, 0,
22962306a36Sopenharmony_ci			   MLX4_CMD_QUERY_FUNC,
23062306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A,
23162306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
23262306a36Sopenharmony_ci	if (err)
23362306a36Sopenharmony_ci		goto out;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_BUS_OFFSET);
23662306a36Sopenharmony_ci	func->bus = field & 0xf;
23762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_DEVICE_OFFSET);
23862306a36Sopenharmony_ci	func->device = field & 0xf1;
23962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_FUNCTION_OFFSET);
24062306a36Sopenharmony_ci	func->function = field & 0x7;
24162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_PHYSICAL_FUNCTION_OFFSET);
24262306a36Sopenharmony_ci	func->physical_function = field & 0xf;
24362306a36Sopenharmony_ci	MLX4_GET(field16, outbox, QUERY_FUNC_RSVD_EQS_OFFSET);
24462306a36Sopenharmony_ci	func->rsvd_eqs = field16 & 0xffff;
24562306a36Sopenharmony_ci	MLX4_GET(field16, outbox, QUERY_FUNC_MAX_EQ_OFFSET);
24662306a36Sopenharmony_ci	func->max_eq = field16 & 0xffff;
24762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_RSVD_UARS_OFFSET);
24862306a36Sopenharmony_ci	func->rsvd_uars = field & 0x0f;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	mlx4_dbg(dev, "Bus: %d, Device: %d, Function: %d, Physical function: %d, Max EQs: %d, Reserved EQs: %d, Reserved UARs: %d\n",
25162306a36Sopenharmony_ci		 func->bus, func->device, func->function, func->physical_function,
25262306a36Sopenharmony_ci		 func->max_eq, func->rsvd_eqs, func->rsvd_uars);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciout:
25562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
25662306a36Sopenharmony_ci	return err;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int mlx4_activate_vst_qinq(struct mlx4_priv *priv, int slave, int port)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
26262306a36Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
26362306a36Sopenharmony_ci	int err;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
26662306a36Sopenharmony_ci	vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (vp_admin->default_vlan != vp_oper->state.default_vlan) {
26962306a36Sopenharmony_ci		err = __mlx4_register_vlan(&priv->dev, port,
27062306a36Sopenharmony_ci					   vp_admin->default_vlan,
27162306a36Sopenharmony_ci					   &vp_oper->vlan_idx);
27262306a36Sopenharmony_ci		if (err) {
27362306a36Sopenharmony_ci			vp_oper->vlan_idx = NO_INDX;
27462306a36Sopenharmony_ci			mlx4_warn(&priv->dev,
27562306a36Sopenharmony_ci				  "No vlan resources slave %d, port %d\n",
27662306a36Sopenharmony_ci				  slave, port);
27762306a36Sopenharmony_ci			return err;
27862306a36Sopenharmony_ci		}
27962306a36Sopenharmony_ci		mlx4_dbg(&priv->dev, "alloc vlan %d idx  %d slave %d port %d\n",
28062306a36Sopenharmony_ci			 (int)(vp_oper->state.default_vlan),
28162306a36Sopenharmony_ci			 vp_oper->vlan_idx, slave, port);
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci	vp_oper->state.vlan_proto   = vp_admin->vlan_proto;
28462306a36Sopenharmony_ci	vp_oper->state.default_vlan = vp_admin->default_vlan;
28562306a36Sopenharmony_ci	vp_oper->state.default_qos  = vp_admin->default_qos;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int mlx4_handle_vst_qinq(struct mlx4_priv *priv, int slave, int port)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct mlx4_vport_oper_state *vp_oper;
29362306a36Sopenharmony_ci	struct mlx4_slave_state *slave_state;
29462306a36Sopenharmony_ci	struct mlx4_vport_state *vp_admin;
29562306a36Sopenharmony_ci	int err;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
29862306a36Sopenharmony_ci	vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
29962306a36Sopenharmony_ci	slave_state = &priv->mfunc.master.slave_state[slave];
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if ((vp_admin->vlan_proto != htons(ETH_P_8021AD)) ||
30262306a36Sopenharmony_ci	    (!slave_state->active))
30362306a36Sopenharmony_ci		return 0;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (vp_oper->state.vlan_proto == vp_admin->vlan_proto &&
30662306a36Sopenharmony_ci	    vp_oper->state.default_vlan == vp_admin->default_vlan &&
30762306a36Sopenharmony_ci	    vp_oper->state.default_qos == vp_admin->default_qos)
30862306a36Sopenharmony_ci		return 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (!slave_state->vst_qinq_supported) {
31162306a36Sopenharmony_ci		/* Warn and revert the request to set vst QinQ mode */
31262306a36Sopenharmony_ci		vp_admin->vlan_proto   = vp_oper->state.vlan_proto;
31362306a36Sopenharmony_ci		vp_admin->default_vlan = vp_oper->state.default_vlan;
31462306a36Sopenharmony_ci		vp_admin->default_qos  = vp_oper->state.default_qos;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		mlx4_warn(&priv->dev,
31762306a36Sopenharmony_ci			  "Slave %d does not support VST QinQ mode\n", slave);
31862306a36Sopenharmony_ci		return 0;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	err = mlx4_activate_vst_qinq(priv, slave, port);
32262306a36Sopenharmony_ci	return err;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ciint mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
32662306a36Sopenharmony_ci				struct mlx4_vhcr *vhcr,
32762306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *inbox,
32862306a36Sopenharmony_ci				struct mlx4_cmd_mailbox *outbox,
32962306a36Sopenharmony_ci				struct mlx4_cmd_info *cmd)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
33262306a36Sopenharmony_ci	u8	field, port;
33362306a36Sopenharmony_ci	u32	size, proxy_qp, qkey;
33462306a36Sopenharmony_ci	int	err = 0;
33562306a36Sopenharmony_ci	struct mlx4_func func;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS_OFFSET		0x0
33862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_NUM_PORTS_OFFSET		0x1
33962306a36Sopenharmony_ci#define QUERY_FUNC_CAP_PF_BHVR_OFFSET		0x4
34062306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FMR_OFFSET		0x8
34162306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP	0x10
34262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP	0x14
34362306a36Sopenharmony_ci#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP	0x18
34462306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP	0x20
34562306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP	0x24
34662306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP	0x28
34762306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MAX_EQ_OFFSET		0x2c
34862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET	0x30
34962306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET	0x48
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET		0x50
35262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET		0x54
35362306a36Sopenharmony_ci#define QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET		0x58
35462306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MPT_QUOTA_OFFSET		0x60
35562306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MTT_QUOTA_OFFSET		0x64
35662306a36Sopenharmony_ci#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET		0x68
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET	0x6c
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FMR_FLAG			0x80
36162306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAG_RDMA		0x40
36262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAG_ETH			0x80
36362306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAG_QUOTAS		0x10
36462306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAG_RESD_LKEY		0x08
36562306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX	0x04
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG	(1UL << 31)
36862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG	(1UL << 30)
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci/* when opcode modifier = 1 */
37162306a36Sopenharmony_ci#define QUERY_FUNC_CAP_PHYS_PORT_OFFSET		0x3
37262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET	0x4
37362306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS0_OFFSET		0x8
37462306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS1_OFFSET		0xc
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP0_TUNNEL		0x10
37762306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP0_PROXY		0x14
37862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP1_TUNNEL		0x18
37962306a36Sopenharmony_ci#define QUERY_FUNC_CAP_QP1_PROXY		0x1c
38062306a36Sopenharmony_ci#define QUERY_FUNC_CAP_PHYS_PORT_ID		0x28
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC		0x40
38362306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN	0x80
38462306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS1_NIC_INFO			0x10
38562306a36Sopenharmony_ci#define QUERY_FUNC_CAP_VF_ENABLE_QP0		0x08
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
38862306a36Sopenharmony_ci#define QUERY_FUNC_CAP_PHV_BIT			0x40
38962306a36Sopenharmony_ci#define QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE	0x20
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci#define QUERY_FUNC_CAP_SUPPORTS_VST_QINQ	BIT(30)
39262306a36Sopenharmony_ci#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS BIT(31)
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (vhcr->op_modifier == 1) {
39562306a36Sopenharmony_ci		struct mlx4_active_ports actv_ports =
39662306a36Sopenharmony_ci			mlx4_get_active_ports(dev, slave);
39762306a36Sopenharmony_ci		int converted_port = mlx4_slave_convert_port(
39862306a36Sopenharmony_ci				dev, slave, vhcr->in_modifier);
39962306a36Sopenharmony_ci		struct mlx4_vport_oper_state *vp_oper;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		if (converted_port < 0)
40262306a36Sopenharmony_ci			return -EINVAL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		vhcr->in_modifier = converted_port;
40562306a36Sopenharmony_ci		/* phys-port = logical-port */
40662306a36Sopenharmony_ci		field = vhcr->in_modifier -
40762306a36Sopenharmony_ci			find_first_bit(actv_ports.ports, dev->caps.num_ports);
40862306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		port = vhcr->in_modifier;
41162306a36Sopenharmony_ci		proxy_qp = dev->phys_caps.base_proxy_sqpn + 8 * slave + port - 1;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* Set nic_info bit to mark new fields support */
41462306a36Sopenharmony_ci		field  = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		if (mlx4_vf_smi_enabled(dev, slave, port) &&
41762306a36Sopenharmony_ci		    !mlx4_get_parav_qkey(dev, proxy_qp, &qkey)) {
41862306a36Sopenharmony_ci			field |= QUERY_FUNC_CAP_VF_ENABLE_QP0;
41962306a36Sopenharmony_ci			MLX4_PUT(outbox->buf, qkey,
42062306a36Sopenharmony_ci				 QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		/* size is now the QP number */
42562306a36Sopenharmony_ci		size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + port - 1;
42662306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		size += 2;
42962306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_TUNNEL);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP0_PROXY);
43262306a36Sopenharmony_ci		proxy_qp += 2;
43362306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, proxy_qp, QUERY_FUNC_CAP_QP1_PROXY);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier],
43662306a36Sopenharmony_ci			 QUERY_FUNC_CAP_PHYS_PORT_ID);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
43962306a36Sopenharmony_ci		err = mlx4_handle_vst_qinq(priv, slave, port);
44062306a36Sopenharmony_ci		if (err)
44162306a36Sopenharmony_ci			return err;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		field = 0;
44462306a36Sopenharmony_ci		if (dev->caps.phv_bit[port])
44562306a36Sopenharmony_ci			field |= QUERY_FUNC_CAP_PHV_BIT;
44662306a36Sopenharmony_ci		if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))
44762306a36Sopenharmony_ci			field |= QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE;
44862306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	} else if (vhcr->op_modifier == 0) {
45162306a36Sopenharmony_ci		struct mlx4_active_ports actv_ports =
45262306a36Sopenharmony_ci			mlx4_get_active_ports(dev, slave);
45362306a36Sopenharmony_ci		struct mlx4_slave_state *slave_state =
45462306a36Sopenharmony_ci			&priv->mfunc.master.slave_state[slave];
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		/* enable rdma and ethernet interfaces, new quota locations,
45762306a36Sopenharmony_ci		 * and reserved lkey
45862306a36Sopenharmony_ci		 */
45962306a36Sopenharmony_ci		field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
46062306a36Sopenharmony_ci			 QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX |
46162306a36Sopenharmony_ci			 QUERY_FUNC_CAP_FLAG_RESD_LKEY);
46262306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		field = min(
46562306a36Sopenharmony_ci			bitmap_weight(actv_ports.ports, dev->caps.num_ports),
46662306a36Sopenharmony_ci			(unsigned int) dev->caps.num_ports);
46762306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		size = dev->caps.function_caps; /* set PF behaviours */
47062306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_PF_BHVR_OFFSET);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		field = 0; /* protected FMR support not available as yet */
47362306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FMR_OFFSET);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		size = priv->mfunc.master.res_tracker.res_alloc[RES_QP].quota[slave];
47662306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET);
47762306a36Sopenharmony_ci		size = dev->caps.num_qps;
47862306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		size = priv->mfunc.master.res_tracker.res_alloc[RES_SRQ].quota[slave];
48162306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET);
48262306a36Sopenharmony_ci		size = dev->caps.num_srqs;
48362306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		size = priv->mfunc.master.res_tracker.res_alloc[RES_CQ].quota[slave];
48662306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET);
48762306a36Sopenharmony_ci		size = dev->caps.num_cqs;
48862306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS) ||
49162306a36Sopenharmony_ci		    mlx4_QUERY_FUNC(dev, &func, slave)) {
49262306a36Sopenharmony_ci			size = vhcr->in_modifier &
49362306a36Sopenharmony_ci				QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
49462306a36Sopenharmony_ci				dev->caps.num_eqs :
49562306a36Sopenharmony_ci				rounddown_pow_of_two(dev->caps.num_eqs);
49662306a36Sopenharmony_ci			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
49762306a36Sopenharmony_ci			size = dev->caps.reserved_eqs;
49862306a36Sopenharmony_ci			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
49962306a36Sopenharmony_ci		} else {
50062306a36Sopenharmony_ci			size = vhcr->in_modifier &
50162306a36Sopenharmony_ci				QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS ?
50262306a36Sopenharmony_ci				func.max_eq :
50362306a36Sopenharmony_ci				rounddown_pow_of_two(func.max_eq);
50462306a36Sopenharmony_ci			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
50562306a36Sopenharmony_ci			size = func.rsvd_eqs;
50662306a36Sopenharmony_ci			MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		size = priv->mfunc.master.res_tracker.res_alloc[RES_MPT].quota[slave];
51062306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
51162306a36Sopenharmony_ci		size = dev->caps.num_mpts;
51262306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		size = priv->mfunc.master.res_tracker.res_alloc[RES_MTT].quota[slave];
51562306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET);
51662306a36Sopenharmony_ci		size = dev->caps.num_mtts;
51762306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		size = dev->caps.num_mgms + dev->caps.num_amgms;
52062306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
52162306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG |
52462306a36Sopenharmony_ci			QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG;
52562306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00);
52862306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		if (vhcr->in_modifier & QUERY_FUNC_CAP_SUPPORTS_VST_QINQ)
53162306a36Sopenharmony_ci			slave_state->vst_qinq_supported = true;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	} else
53462306a36Sopenharmony_ci		err = -EINVAL;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return err;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ciint mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
54062306a36Sopenharmony_ci			struct mlx4_func_cap *func_cap)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
54362306a36Sopenharmony_ci	u32			*outbox;
54462306a36Sopenharmony_ci	u8			field, op_modifier;
54562306a36Sopenharmony_ci	u32			size, qkey;
54662306a36Sopenharmony_ci	int			err = 0, quotas = 0;
54762306a36Sopenharmony_ci	u32                     in_modifier;
54862306a36Sopenharmony_ci	u32			slave_caps;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
55162306a36Sopenharmony_ci	slave_caps = QUERY_FUNC_CAP_SUPPORTS_VST_QINQ |
55262306a36Sopenharmony_ci		QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS;
55362306a36Sopenharmony_ci	in_modifier = op_modifier ? gen_or_port : slave_caps;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
55662306a36Sopenharmony_ci	if (IS_ERR(mailbox))
55762306a36Sopenharmony_ci		return PTR_ERR(mailbox);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, in_modifier, op_modifier,
56062306a36Sopenharmony_ci			   MLX4_CMD_QUERY_FUNC_CAP,
56162306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
56262306a36Sopenharmony_ci	if (err)
56362306a36Sopenharmony_ci		goto out;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	outbox = mailbox->buf;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (!op_modifier) {
56862306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS_OFFSET);
56962306a36Sopenharmony_ci		if (!(field & (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA))) {
57062306a36Sopenharmony_ci			mlx4_err(dev, "The host supports neither eth nor rdma interfaces\n");
57162306a36Sopenharmony_ci			err = -EPROTONOSUPPORT;
57262306a36Sopenharmony_ci			goto out;
57362306a36Sopenharmony_ci		}
57462306a36Sopenharmony_ci		func_cap->flags = field;
57562306a36Sopenharmony_ci		quotas = !!(func_cap->flags & QUERY_FUNC_CAP_FLAG_QUOTAS);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
57862306a36Sopenharmony_ci		func_cap->num_ports = field;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		MLX4_GET(size, outbox, QUERY_FUNC_CAP_PF_BHVR_OFFSET);
58162306a36Sopenharmony_ci		func_cap->pf_context_behaviour = size;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		if (quotas) {
58462306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET);
58562306a36Sopenharmony_ci			func_cap->qp_quota = size & 0xFFFFFF;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET);
58862306a36Sopenharmony_ci			func_cap->srq_quota = size & 0xFFFFFF;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET);
59162306a36Sopenharmony_ci			func_cap->cq_quota = size & 0xFFFFFF;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET);
59462306a36Sopenharmony_ci			func_cap->mpt_quota = size & 0xFFFFFF;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET);
59762306a36Sopenharmony_ci			func_cap->mtt_quota = size & 0xFFFFFF;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET);
60062306a36Sopenharmony_ci			func_cap->mcg_quota = size & 0xFFFFFF;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		} else {
60362306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_QUOTA_OFFSET_DEP);
60462306a36Sopenharmony_ci			func_cap->qp_quota = size & 0xFFFFFF;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_SRQ_QUOTA_OFFSET_DEP);
60762306a36Sopenharmony_ci			func_cap->srq_quota = size & 0xFFFFFF;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_CQ_QUOTA_OFFSET_DEP);
61062306a36Sopenharmony_ci			func_cap->cq_quota = size & 0xFFFFFF;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MPT_QUOTA_OFFSET_DEP);
61362306a36Sopenharmony_ci			func_cap->mpt_quota = size & 0xFFFFFF;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MTT_QUOTA_OFFSET_DEP);
61662306a36Sopenharmony_ci			func_cap->mtt_quota = size & 0xFFFFFF;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP);
61962306a36Sopenharmony_ci			func_cap->mcg_quota = size & 0xFFFFFF;
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci		MLX4_GET(size, outbox, QUERY_FUNC_CAP_MAX_EQ_OFFSET);
62262306a36Sopenharmony_ci		func_cap->max_eq = size & 0xFFFFFF;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
62562306a36Sopenharmony_ci		func_cap->reserved_eq = size & 0xFFFFFF;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		if (func_cap->flags & QUERY_FUNC_CAP_FLAG_RESD_LKEY) {
62862306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET);
62962306a36Sopenharmony_ci			func_cap->reserved_lkey = size;
63062306a36Sopenharmony_ci		} else {
63162306a36Sopenharmony_ci			func_cap->reserved_lkey = 0;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		func_cap->extra_flags = 0;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci		/* Mailbox data from 0x6c and onward should only be treated if
63762306a36Sopenharmony_ci		 * QUERY_FUNC_CAP_FLAG_VALID_MAILBOX is set in func_cap->flags
63862306a36Sopenharmony_ci		 */
63962306a36Sopenharmony_ci		if (func_cap->flags & QUERY_FUNC_CAP_FLAG_VALID_MAILBOX) {
64062306a36Sopenharmony_ci			MLX4_GET(size, outbox, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
64162306a36Sopenharmony_ci			if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG)
64262306a36Sopenharmony_ci				func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_BF_RES_QP;
64362306a36Sopenharmony_ci			if (size & QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG)
64462306a36Sopenharmony_ci				func_cap->extra_flags |= MLX4_QUERY_FUNC_FLAGS_A0_RES_QP;
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		goto out;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* logical port query */
65162306a36Sopenharmony_ci	if (gen_or_port > dev->caps.num_ports) {
65262306a36Sopenharmony_ci		err = -EINVAL;
65362306a36Sopenharmony_ci		goto out;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	MLX4_GET(func_cap->flags1, outbox, QUERY_FUNC_CAP_FLAGS1_OFFSET);
65762306a36Sopenharmony_ci	if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_ETH) {
65862306a36Sopenharmony_ci		if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN) {
65962306a36Sopenharmony_ci			mlx4_err(dev, "VLAN is enforced on this port\n");
66062306a36Sopenharmony_ci			err = -EPROTONOSUPPORT;
66162306a36Sopenharmony_ci			goto out;
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_FORCE_MAC) {
66562306a36Sopenharmony_ci			mlx4_err(dev, "Force mac is enabled on this port\n");
66662306a36Sopenharmony_ci			err = -EPROTONOSUPPORT;
66762306a36Sopenharmony_ci			goto out;
66862306a36Sopenharmony_ci		}
66962306a36Sopenharmony_ci	} else if (dev->caps.port_type[gen_or_port] == MLX4_PORT_TYPE_IB) {
67062306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
67162306a36Sopenharmony_ci		if (field & QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID) {
67262306a36Sopenharmony_ci			mlx4_err(dev, "phy_wqe_gid is enforced on this ib port\n");
67362306a36Sopenharmony_ci			err = -EPROTONOSUPPORT;
67462306a36Sopenharmony_ci			goto out;
67562306a36Sopenharmony_ci		}
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
67962306a36Sopenharmony_ci	func_cap->physical_port = field;
68062306a36Sopenharmony_ci	if (func_cap->physical_port != gen_or_port) {
68162306a36Sopenharmony_ci		err = -EINVAL;
68262306a36Sopenharmony_ci		goto out;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (func_cap->flags1 & QUERY_FUNC_CAP_VF_ENABLE_QP0) {
68662306a36Sopenharmony_ci		MLX4_GET(qkey, outbox, QUERY_FUNC_CAP_PRIV_VF_QKEY_OFFSET);
68762306a36Sopenharmony_ci		func_cap->spec_qps.qp0_qkey = qkey;
68862306a36Sopenharmony_ci	} else {
68962306a36Sopenharmony_ci		func_cap->spec_qps.qp0_qkey = 0;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_TUNNEL);
69362306a36Sopenharmony_ci	func_cap->spec_qps.qp0_tunnel = size & 0xFFFFFF;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP0_PROXY);
69662306a36Sopenharmony_ci	func_cap->spec_qps.qp0_proxy = size & 0xFFFFFF;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_TUNNEL);
69962306a36Sopenharmony_ci	func_cap->spec_qps.qp1_tunnel = size & 0xFFFFFF;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY);
70262306a36Sopenharmony_ci	func_cap->spec_qps.qp1_proxy = size & 0xFFFFFF;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_NIC_INFO)
70562306a36Sopenharmony_ci		MLX4_GET(func_cap->phys_port_id, outbox,
70662306a36Sopenharmony_ci			 QUERY_FUNC_CAP_PHYS_PORT_ID);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	MLX4_GET(func_cap->flags0, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/* All other resources are allocated by the master, but we still report
71162306a36Sopenharmony_ci	 * 'num' and 'reserved' capabilities as follows:
71262306a36Sopenharmony_ci	 * - num remains the maximum resource index
71362306a36Sopenharmony_ci	 * - 'num - reserved' is the total available objects of a resource, but
71462306a36Sopenharmony_ci	 *   resource indices may be less than 'reserved'
71562306a36Sopenharmony_ci	 * TODO: set per-resource quotas */
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ciout:
71862306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return err;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic void disable_unsupported_roce_caps(void *buf);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ciint mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
72862306a36Sopenharmony_ci	u32 *outbox;
72962306a36Sopenharmony_ci	u8 field;
73062306a36Sopenharmony_ci	u32 field32, flags, ext_flags;
73162306a36Sopenharmony_ci	u16 size;
73262306a36Sopenharmony_ci	u16 stat_rate;
73362306a36Sopenharmony_ci	int err;
73462306a36Sopenharmony_ci	int i;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci#define QUERY_DEV_CAP_OUT_SIZE		       0x100
73762306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET		0x10
73862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET		0x11
73962306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_QP_OFFSET		0x12
74062306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_QP_OFFSET		0x13
74162306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET		0x14
74262306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_SRQ_OFFSET		0x15
74362306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_EEC_OFFSET		0x16
74462306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_EEC_OFFSET		0x17
74562306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET		0x19
74662306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_CQ_OFFSET		0x1a
74762306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_CQ_OFFSET		0x1b
74862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_MPT_OFFSET		0x1d
74962306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_EQ_OFFSET		0x1e
75062306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_EQ_OFFSET		0x1f
75162306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_MTT_OFFSET		0x20
75262306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET		0x21
75362306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_MRW_OFFSET		0x22
75462306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET	0x23
75562306a36Sopenharmony_ci#define QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET		0x26
75662306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_AV_OFFSET		0x27
75762306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET		0x29
75862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET		0x2b
75962306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_GSO_OFFSET		0x2d
76062306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSS_OFFSET		0x2e
76162306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_RDMA_OFFSET		0x2f
76262306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET		0x33
76362306a36Sopenharmony_ci#define QUERY_DEV_CAP_PORT_BEACON_OFFSET	0x34
76462306a36Sopenharmony_ci#define QUERY_DEV_CAP_ACK_DELAY_OFFSET		0x35
76562306a36Sopenharmony_ci#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET		0x36
76662306a36Sopenharmony_ci#define QUERY_DEV_CAP_VL_PORT_OFFSET		0x37
76762306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET		0x38
76862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_GID_OFFSET		0x3b
76962306a36Sopenharmony_ci#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET	0x3c
77062306a36Sopenharmony_ci#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET	0x3e
77162306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_PKEY_OFFSET		0x3f
77262306a36Sopenharmony_ci#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET		0x40
77362306a36Sopenharmony_ci#define QUERY_DEV_CAP_WOL_OFFSET		0x43
77462306a36Sopenharmony_ci#define QUERY_DEV_CAP_FLAGS_OFFSET		0x44
77562306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_UAR_OFFSET		0x48
77662306a36Sopenharmony_ci#define QUERY_DEV_CAP_UAR_SZ_OFFSET		0x49
77762306a36Sopenharmony_ci#define QUERY_DEV_CAP_PAGE_SZ_OFFSET		0x4b
77862306a36Sopenharmony_ci#define QUERY_DEV_CAP_BF_OFFSET			0x4c
77962306a36Sopenharmony_ci#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET	0x4d
78062306a36Sopenharmony_ci#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET	0x4e
78162306a36Sopenharmony_ci#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET	0x4f
78262306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET		0x51
78362306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET	0x52
78462306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET		0x55
78562306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET	0x56
78662306a36Sopenharmony_ci#define QUERY_DEV_CAP_USER_MAC_EN_OFFSET	0x5C
78762306a36Sopenharmony_ci#define QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET	0x5D
78862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET		0x61
78962306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_MCG_OFFSET		0x62
79062306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_MCG_OFFSET		0x63
79162306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_PD_OFFSET		0x64
79262306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_PD_OFFSET		0x65
79362306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_XRC_OFFSET		0x66
79462306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_XRC_OFFSET		0x67
79562306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET	0x68
79662306a36Sopenharmony_ci#define QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET	0x70
79762306a36Sopenharmony_ci#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET	0x70
79862306a36Sopenharmony_ci#define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET	0x74
79962306a36Sopenharmony_ci#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET	0x76
80062306a36Sopenharmony_ci#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET	0x77
80162306a36Sopenharmony_ci#define QUERY_DEV_CAP_SL2VL_EVENT_OFFSET	0x78
80262306a36Sopenharmony_ci#define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE	0x7a
80362306a36Sopenharmony_ci#define QUERY_DEV_CAP_ECN_QCN_VER_OFFSET	0x7b
80462306a36Sopenharmony_ci#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET	0x80
80562306a36Sopenharmony_ci#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET	0x82
80662306a36Sopenharmony_ci#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET	0x84
80762306a36Sopenharmony_ci#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET	0x86
80862306a36Sopenharmony_ci#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET	0x88
80962306a36Sopenharmony_ci#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET	0x8a
81062306a36Sopenharmony_ci#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET	0x8c
81162306a36Sopenharmony_ci#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET	0x8e
81262306a36Sopenharmony_ci#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET	0x90
81362306a36Sopenharmony_ci#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET	0x92
81462306a36Sopenharmony_ci#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET		0x94
81562306a36Sopenharmony_ci#define QUERY_DEV_CAP_CONFIG_DEV_OFFSET		0x94
81662306a36Sopenharmony_ci#define QUERY_DEV_CAP_PHV_EN_OFFSET		0x96
81762306a36Sopenharmony_ci#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET		0x98
81862306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET		0xa0
81962306a36Sopenharmony_ci#define QUERY_DEV_CAP_ETH_BACKPL_OFFSET		0x9c
82062306a36Sopenharmony_ci#define QUERY_DEV_CAP_DIAG_RPRT_PER_PORT	0x9c
82162306a36Sopenharmony_ci#define QUERY_DEV_CAP_FW_REASSIGN_MAC		0x9d
82262306a36Sopenharmony_ci#define QUERY_DEV_CAP_VXLAN			0x9e
82362306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAD_DEMUX_OFFSET		0xb0
82462306a36Sopenharmony_ci#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET	0xa8
82562306a36Sopenharmony_ci#define QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET	0xac
82662306a36Sopenharmony_ci#define QUERY_DEV_CAP_MAP_CLOCK_TO_USER 0xc1
82762306a36Sopenharmony_ci#define QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET	0xcc
82862306a36Sopenharmony_ci#define QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET	0xd0
82962306a36Sopenharmony_ci#define QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET	0xd2
83062306a36Sopenharmony_ci#define QUERY_DEV_CAP_HEALTH_BUFFER_ADDRESS_OFFSET	0xe4
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	dev_cap->flags2 = 0;
83362306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
83462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
83562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
83662306a36Sopenharmony_ci	outbox = mailbox->buf;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
83962306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
84062306a36Sopenharmony_ci	if (err)
84162306a36Sopenharmony_ci		goto out;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev))
84462306a36Sopenharmony_ci		disable_unsupported_roce_caps(outbox);
84562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAP_CLOCK_TO_USER);
84662306a36Sopenharmony_ci	dev_cap->map_clock_to_user = field & 0x80;
84762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);
84862306a36Sopenharmony_ci	dev_cap->reserved_qps = 1 << (field & 0xf);
84962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET);
85062306a36Sopenharmony_ci	dev_cap->max_qps = 1 << (field & 0x1f);
85162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET);
85262306a36Sopenharmony_ci	dev_cap->reserved_srqs = 1 << (field >> 4);
85362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET);
85462306a36Sopenharmony_ci	dev_cap->max_srqs = 1 << (field & 0x1f);
85562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET);
85662306a36Sopenharmony_ci	dev_cap->max_cq_sz = 1 << field;
85762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET);
85862306a36Sopenharmony_ci	dev_cap->reserved_cqs = 1 << (field & 0xf);
85962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET);
86062306a36Sopenharmony_ci	dev_cap->max_cqs = 1 << (field & 0x1f);
86162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
86262306a36Sopenharmony_ci	dev_cap->max_mpts = 1 << (field & 0x3f);
86362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
86462306a36Sopenharmony_ci	dev_cap->reserved_eqs = 1 << (field & 0xf);
86562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
86662306a36Sopenharmony_ci	dev_cap->max_eqs = 1 << (field & 0xf);
86762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
86862306a36Sopenharmony_ci	dev_cap->reserved_mtts = 1 << (field >> 4);
86962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET);
87062306a36Sopenharmony_ci	dev_cap->reserved_mrws = 1 << (field & 0xf);
87162306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET);
87262306a36Sopenharmony_ci	dev_cap->num_sys_eqs = size & 0xfff;
87362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
87462306a36Sopenharmony_ci	dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
87562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
87662306a36Sopenharmony_ci	dev_cap->max_responder_per_qp = 1 << (field & 0x3f);
87762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET);
87862306a36Sopenharmony_ci	field &= 0x1f;
87962306a36Sopenharmony_ci	if (!field)
88062306a36Sopenharmony_ci		dev_cap->max_gso_sz = 0;
88162306a36Sopenharmony_ci	else
88262306a36Sopenharmony_ci		dev_cap->max_gso_sz = 1 << field;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET);
88562306a36Sopenharmony_ci	if (field & 0x20)
88662306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR;
88762306a36Sopenharmony_ci	if (field & 0x10)
88862306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP;
88962306a36Sopenharmony_ci	field &= 0xf;
89062306a36Sopenharmony_ci	if (field) {
89162306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS;
89262306a36Sopenharmony_ci		dev_cap->max_rss_tbl_sz = 1 << field;
89362306a36Sopenharmony_ci	} else
89462306a36Sopenharmony_ci		dev_cap->max_rss_tbl_sz = 0;
89562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
89662306a36Sopenharmony_ci	dev_cap->max_rdma_global = 1 << (field & 0x3f);
89762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
89862306a36Sopenharmony_ci	dev_cap->local_ca_ack_delay = field & 0x1f;
89962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
90062306a36Sopenharmony_ci	dev_cap->num_ports = field & 0xf;
90162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
90262306a36Sopenharmony_ci	dev_cap->max_msg_sz = 1 << (field & 0x1f);
90362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_FLOWSTATS_COUNTERS_OFFSET);
90462306a36Sopenharmony_ci	if (field & 0x10)
90562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN;
90662306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
90762306a36Sopenharmony_ci	if (field & 0x80)
90862306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN;
90962306a36Sopenharmony_ci	dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f;
91062306a36Sopenharmony_ci	if (field & 0x20)
91162306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER;
91262306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_BEACON_OFFSET);
91362306a36Sopenharmony_ci	if (field & 0x80)
91462306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_BEACON;
91562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
91662306a36Sopenharmony_ci	if (field & 0x80)
91762306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB;
91862306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET);
91962306a36Sopenharmony_ci	dev_cap->fs_max_num_qp_per_entry = field;
92062306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_SL2VL_EVENT_OFFSET);
92162306a36Sopenharmony_ci	if (field & (1 << 5))
92262306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT;
92362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
92462306a36Sopenharmony_ci	if (field & 0x1)
92562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QCN;
92662306a36Sopenharmony_ci	MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
92762306a36Sopenharmony_ci	dev_cap->stat_rate_support = stat_rate;
92862306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
92962306a36Sopenharmony_ci	if (field & 0x80)
93062306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS;
93162306a36Sopenharmony_ci	MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
93262306a36Sopenharmony_ci	MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
93362306a36Sopenharmony_ci	dev_cap->flags = flags | (u64)ext_flags << 32;
93462306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_WOL_OFFSET);
93562306a36Sopenharmony_ci	dev_cap->wol_port[1] = !!(field & 0x20);
93662306a36Sopenharmony_ci	dev_cap->wol_port[2] = !!(field & 0x40);
93762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
93862306a36Sopenharmony_ci	dev_cap->reserved_uars = field >> 4;
93962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET);
94062306a36Sopenharmony_ci	dev_cap->uar_size = 1 << ((field & 0x3f) + 20);
94162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET);
94262306a36Sopenharmony_ci	dev_cap->min_page_sz = 1 << field;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET);
94562306a36Sopenharmony_ci	if (field & 0x80) {
94662306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
94762306a36Sopenharmony_ci		dev_cap->bf_reg_size = 1 << (field & 0x1f);
94862306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
94962306a36Sopenharmony_ci		if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size))
95062306a36Sopenharmony_ci			field = 3;
95162306a36Sopenharmony_ci		dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
95262306a36Sopenharmony_ci	} else {
95362306a36Sopenharmony_ci		dev_cap->bf_reg_size = 0;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET);
95762306a36Sopenharmony_ci	dev_cap->max_sq_sg = field;
95862306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET);
95962306a36Sopenharmony_ci	dev_cap->max_sq_desc_sz = size;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_USER_MAC_EN_OFFSET);
96262306a36Sopenharmony_ci	if (field & (1 << 2))
96362306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_USER_MAC_EN;
96462306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET);
96562306a36Sopenharmony_ci	if (field & 0x1)
96662306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP;
96762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET);
96862306a36Sopenharmony_ci	dev_cap->max_qp_per_mcg = 1 << field;
96962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET);
97062306a36Sopenharmony_ci	dev_cap->reserved_mgms = field & 0xf;
97162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET);
97262306a36Sopenharmony_ci	dev_cap->max_mcgs = 1 << field;
97362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET);
97462306a36Sopenharmony_ci	dev_cap->reserved_pds = field >> 4;
97562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET);
97662306a36Sopenharmony_ci	dev_cap->max_pds = 1 << (field & 0x3f);
97762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET);
97862306a36Sopenharmony_ci	dev_cap->reserved_xrcds = field >> 4;
97962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET);
98062306a36Sopenharmony_ci	dev_cap->max_xrcds = 1 << (field & 0x1f);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET);
98362306a36Sopenharmony_ci	dev_cap->rdmarc_entry_sz = size;
98462306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET);
98562306a36Sopenharmony_ci	dev_cap->qpc_entry_sz = size;
98662306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET);
98762306a36Sopenharmony_ci	dev_cap->aux_entry_sz = size;
98862306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET);
98962306a36Sopenharmony_ci	dev_cap->altc_entry_sz = size;
99062306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET);
99162306a36Sopenharmony_ci	dev_cap->eqc_entry_sz = size;
99262306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET);
99362306a36Sopenharmony_ci	dev_cap->cqc_entry_sz = size;
99462306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET);
99562306a36Sopenharmony_ci	dev_cap->srq_entry_sz = size;
99662306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET);
99762306a36Sopenharmony_ci	dev_cap->cmpt_entry_sz = size;
99862306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET);
99962306a36Sopenharmony_ci	dev_cap->mtt_entry_sz = size;
100062306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET);
100162306a36Sopenharmony_ci	dev_cap->dmpt_entry_sz = size;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET);
100462306a36Sopenharmony_ci	dev_cap->max_srq_sz = 1 << field;
100562306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET);
100662306a36Sopenharmony_ci	dev_cap->max_qp_sz = 1 << field;
100762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET);
100862306a36Sopenharmony_ci	dev_cap->resize_srq = field & 1;
100962306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET);
101062306a36Sopenharmony_ci	dev_cap->max_rq_sg = field;
101162306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
101262306a36Sopenharmony_ci	dev_cap->max_rq_desc_sz = size;
101362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
101462306a36Sopenharmony_ci	if (field & (1 << 4))
101562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QOS_VPP;
101662306a36Sopenharmony_ci	if (field & (1 << 5))
101762306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL;
101862306a36Sopenharmony_ci	if (field & (1 << 6))
101962306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CQE_STRIDE;
102062306a36Sopenharmony_ci	if (field & (1 << 7))
102162306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE;
102262306a36Sopenharmony_ci	MLX4_GET(dev_cap->bmme_flags, outbox,
102362306a36Sopenharmony_ci		 QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
102462306a36Sopenharmony_ci	if (dev_cap->bmme_flags & MLX4_FLAG_ROCE_V1_V2)
102562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ROCE_V1_V2;
102662306a36Sopenharmony_ci	if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP)
102762306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP;
102862306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
102962306a36Sopenharmony_ci	if (field & 0x20)
103062306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV;
103162306a36Sopenharmony_ci	if (field & (1 << 2))
103262306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_IGNORE_FCS;
103362306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_PHV_EN_OFFSET);
103462306a36Sopenharmony_ci	if (field & 0x80)
103562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PHV_EN;
103662306a36Sopenharmony_ci	if (field & 0x40)
103762306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	MLX4_GET(dev_cap->reserved_lkey, outbox,
104062306a36Sopenharmony_ci		 QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
104162306a36Sopenharmony_ci	MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET);
104262306a36Sopenharmony_ci	if (field32 & (1 << 0))
104362306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
104462306a36Sopenharmony_ci	if (field32 & (1 << 7))
104562306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT;
104662306a36Sopenharmony_ci	if (field32 & (1 << 8))
104762306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW;
104862306a36Sopenharmony_ci	MLX4_GET(field32, outbox, QUERY_DEV_CAP_DIAG_RPRT_PER_PORT);
104962306a36Sopenharmony_ci	if (field32 & (1 << 17))
105062306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT;
105162306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
105262306a36Sopenharmony_ci	if (field & 1<<6)
105362306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
105462306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
105562306a36Sopenharmony_ci	if (field & 1<<3)
105662306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS;
105762306a36Sopenharmony_ci	if (field & (1 << 5))
105862306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG;
105962306a36Sopenharmony_ci	MLX4_GET(dev_cap->max_icm_sz, outbox,
106062306a36Sopenharmony_ci		 QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
106162306a36Sopenharmony_ci	if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS)
106262306a36Sopenharmony_ci		MLX4_GET(dev_cap->max_counters, outbox,
106362306a36Sopenharmony_ci			 QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	MLX4_GET(field32, outbox,
106662306a36Sopenharmony_ci		 QUERY_DEV_CAP_MAD_DEMUX_OFFSET);
106762306a36Sopenharmony_ci	if (field32 & (1 << 0))
106862306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_MAD_DEMUX;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	MLX4_GET(dev_cap->dmfs_high_rate_qpn_base, outbox,
107162306a36Sopenharmony_ci		 QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_BASE_OFFSET);
107262306a36Sopenharmony_ci	dev_cap->dmfs_high_rate_qpn_base &= MGM_QPN_MASK;
107362306a36Sopenharmony_ci	MLX4_GET(dev_cap->dmfs_high_rate_qpn_range, outbox,
107462306a36Sopenharmony_ci		 QUERY_DEV_CAP_DMFS_HIGH_RATE_QPN_RANGE_OFFSET);
107562306a36Sopenharmony_ci	dev_cap->dmfs_high_rate_qpn_range &= MGM_QPN_MASK;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET);
107862306a36Sopenharmony_ci	dev_cap->rl_caps.num_rates = size;
107962306a36Sopenharmony_ci	if (dev_cap->rl_caps.num_rates) {
108062306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT;
108162306a36Sopenharmony_ci		MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MAX_OFFSET);
108262306a36Sopenharmony_ci		dev_cap->rl_caps.max_val  = size & 0xfff;
108362306a36Sopenharmony_ci		dev_cap->rl_caps.max_unit = size >> 14;
108462306a36Sopenharmony_ci		MLX4_GET(size, outbox, QUERY_DEV_CAP_QP_RATE_LIMIT_MIN_OFFSET);
108562306a36Sopenharmony_ci		dev_cap->rl_caps.min_val  = size & 0xfff;
108662306a36Sopenharmony_ci		dev_cap->rl_caps.min_unit = size >> 14;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	MLX4_GET(dev_cap->health_buffer_addrs, outbox,
109062306a36Sopenharmony_ci		 QUERY_DEV_CAP_HEALTH_BUFFER_ADDRESS_OFFSET);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
109362306a36Sopenharmony_ci	if (field32 & (1 << 16))
109462306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP;
109562306a36Sopenharmony_ci	if (field32 & (1 << 18))
109662306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP_SRC_CHECK_LB;
109762306a36Sopenharmony_ci	if (field32 & (1 << 19))
109862306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_LB_SRC_CHK;
109962306a36Sopenharmony_ci	if (field32 & (1 << 26))
110062306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
110162306a36Sopenharmony_ci	if (field32 & (1 << 20))
110262306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
110362306a36Sopenharmony_ci	if (field32 & (1 << 21))
110462306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_80_VFS;
110562306a36Sopenharmony_ci	if (field32 & (1 << 23))
110662306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SW_CQ_INIT;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	for (i = 1; i <= dev_cap->num_ports; i++) {
110962306a36Sopenharmony_ci		err = mlx4_QUERY_PORT(dev, i, dev_cap->port_cap + i);
111062306a36Sopenharmony_ci		if (err)
111162306a36Sopenharmony_ci			goto out;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	/*
111562306a36Sopenharmony_ci	 * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then
111662306a36Sopenharmony_ci	 * we can't use any EQs whose doorbell falls on that page,
111762306a36Sopenharmony_ci	 * even if the EQ itself isn't reserved.
111862306a36Sopenharmony_ci	 */
111962306a36Sopenharmony_ci	if (dev_cap->num_sys_eqs == 0)
112062306a36Sopenharmony_ci		dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
112162306a36Sopenharmony_ci					    dev_cap->reserved_eqs);
112262306a36Sopenharmony_ci	else
112362306a36Sopenharmony_ci		dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ciout:
112662306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
112762306a36Sopenharmony_ci	return err;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_civoid mlx4_dev_cap_dump(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	if (dev_cap->bf_reg_size > 0)
113362306a36Sopenharmony_ci		mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
113462306a36Sopenharmony_ci			 dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
113562306a36Sopenharmony_ci	else
113662306a36Sopenharmony_ci		mlx4_dbg(dev, "BlueFlame not available\n");
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
113962306a36Sopenharmony_ci		 dev_cap->bmme_flags, dev_cap->reserved_lkey);
114062306a36Sopenharmony_ci	mlx4_dbg(dev, "Max ICM size %lld MB\n",
114162306a36Sopenharmony_ci		 (unsigned long long) dev_cap->max_icm_sz >> 20);
114262306a36Sopenharmony_ci	mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
114362306a36Sopenharmony_ci		 dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz);
114462306a36Sopenharmony_ci	mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
114562306a36Sopenharmony_ci		 dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
114662306a36Sopenharmony_ci	mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
114762306a36Sopenharmony_ci		 dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
114862306a36Sopenharmony_ci	mlx4_dbg(dev, "Num sys EQs: %d, max EQs: %d, reserved EQs: %d, entry size: %d\n",
114962306a36Sopenharmony_ci		 dev_cap->num_sys_eqs, dev_cap->max_eqs, dev_cap->reserved_eqs,
115062306a36Sopenharmony_ci		 dev_cap->eqc_entry_sz);
115162306a36Sopenharmony_ci	mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
115262306a36Sopenharmony_ci		 dev_cap->reserved_mrws, dev_cap->reserved_mtts);
115362306a36Sopenharmony_ci	mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
115462306a36Sopenharmony_ci		 dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars);
115562306a36Sopenharmony_ci	mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n",
115662306a36Sopenharmony_ci		 dev_cap->max_pds, dev_cap->reserved_mgms);
115762306a36Sopenharmony_ci	mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
115862306a36Sopenharmony_ci		 dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
115962306a36Sopenharmony_ci	mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
116062306a36Sopenharmony_ci		 dev_cap->local_ca_ack_delay, 128 << dev_cap->port_cap[1].ib_mtu,
116162306a36Sopenharmony_ci		 dev_cap->port_cap[1].max_port_width);
116262306a36Sopenharmony_ci	mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
116362306a36Sopenharmony_ci		 dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
116462306a36Sopenharmony_ci	mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
116562306a36Sopenharmony_ci		 dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
116662306a36Sopenharmony_ci	mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
116762306a36Sopenharmony_ci	mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
116862306a36Sopenharmony_ci	mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
116962306a36Sopenharmony_ci	mlx4_dbg(dev, "DMFS high rate steer QPn base: %d\n",
117062306a36Sopenharmony_ci		 dev_cap->dmfs_high_rate_qpn_base);
117162306a36Sopenharmony_ci	mlx4_dbg(dev, "DMFS high rate steer QPn range: %d\n",
117262306a36Sopenharmony_ci		 dev_cap->dmfs_high_rate_qpn_range);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT) {
117562306a36Sopenharmony_ci		struct mlx4_rate_limit_caps *rl_caps = &dev_cap->rl_caps;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		mlx4_dbg(dev, "QP Rate-Limit: #rates %d, unit/val max %d/%d, min %d/%d\n",
117862306a36Sopenharmony_ci			 rl_caps->num_rates, rl_caps->max_unit, rl_caps->max_val,
117962306a36Sopenharmony_ci			 rl_caps->min_unit, rl_caps->min_val);
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	dump_dev_cap_flags(dev, dev_cap->flags);
118362306a36Sopenharmony_ci	dump_dev_cap_flags2(dev, dev_cap->flags2);
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ciint mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
118962306a36Sopenharmony_ci	u32 *outbox;
119062306a36Sopenharmony_ci	u8 field;
119162306a36Sopenharmony_ci	u32 field32;
119262306a36Sopenharmony_ci	int err;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
119562306a36Sopenharmony_ci	if (IS_ERR(mailbox))
119662306a36Sopenharmony_ci		return PTR_ERR(mailbox);
119762306a36Sopenharmony_ci	outbox = mailbox->buf;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
120062306a36Sopenharmony_ci		err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
120162306a36Sopenharmony_ci				   MLX4_CMD_TIME_CLASS_A,
120262306a36Sopenharmony_ci				   MLX4_CMD_NATIVE);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		if (err)
120562306a36Sopenharmony_ci			goto out;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
120862306a36Sopenharmony_ci		port_cap->max_vl	   = field >> 4;
120962306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
121062306a36Sopenharmony_ci		port_cap->ib_mtu	   = field >> 4;
121162306a36Sopenharmony_ci		port_cap->max_port_width = field & 0xf;
121262306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
121362306a36Sopenharmony_ci		port_cap->max_gids	   = 1 << (field & 0xf);
121462306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
121562306a36Sopenharmony_ci		port_cap->max_pkeys	   = 1 << (field & 0xf);
121662306a36Sopenharmony_ci	} else {
121762306a36Sopenharmony_ci#define QUERY_PORT_SUPPORTED_TYPE_OFFSET	0x00
121862306a36Sopenharmony_ci#define QUERY_PORT_MTU_OFFSET			0x01
121962306a36Sopenharmony_ci#define QUERY_PORT_ETH_MTU_OFFSET		0x02
122062306a36Sopenharmony_ci#define QUERY_PORT_WIDTH_OFFSET			0x06
122162306a36Sopenharmony_ci#define QUERY_PORT_MAX_GID_PKEY_OFFSET		0x07
122262306a36Sopenharmony_ci#define QUERY_PORT_MAX_MACVLAN_OFFSET		0x0a
122362306a36Sopenharmony_ci#define QUERY_PORT_MAX_VL_OFFSET		0x0b
122462306a36Sopenharmony_ci#define QUERY_PORT_MAC_OFFSET			0x10
122562306a36Sopenharmony_ci#define QUERY_PORT_TRANS_VENDOR_OFFSET		0x18
122662306a36Sopenharmony_ci#define QUERY_PORT_WAVELENGTH_OFFSET		0x1c
122762306a36Sopenharmony_ci#define QUERY_PORT_TRANS_CODE_OFFSET		0x20
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci		err = mlx4_cmd_box(dev, 0, mailbox->dma, port, 0, MLX4_CMD_QUERY_PORT,
123062306a36Sopenharmony_ci				   MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
123162306a36Sopenharmony_ci		if (err)
123262306a36Sopenharmony_ci			goto out;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
123562306a36Sopenharmony_ci		port_cap->link_state = (field & 0x80) >> 7;
123662306a36Sopenharmony_ci		port_cap->supported_port_types = field & 3;
123762306a36Sopenharmony_ci		port_cap->suggested_type = (field >> 3) & 1;
123862306a36Sopenharmony_ci		port_cap->default_sense = (field >> 4) & 1;
123962306a36Sopenharmony_ci		port_cap->dmfs_optimized_state = (field >> 5) & 1;
124062306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
124162306a36Sopenharmony_ci		port_cap->ib_mtu	   = field & 0xf;
124262306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
124362306a36Sopenharmony_ci		port_cap->max_port_width = field & 0xf;
124462306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET);
124562306a36Sopenharmony_ci		port_cap->max_gids	   = 1 << (field >> 4);
124662306a36Sopenharmony_ci		port_cap->max_pkeys	   = 1 << (field & 0xf);
124762306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET);
124862306a36Sopenharmony_ci		port_cap->max_vl	   = field & 0xf;
124962306a36Sopenharmony_ci		port_cap->max_tc_eth	   = field >> 4;
125062306a36Sopenharmony_ci		MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET);
125162306a36Sopenharmony_ci		port_cap->log_max_macs  = field & 0xf;
125262306a36Sopenharmony_ci		port_cap->log_max_vlans = field >> 4;
125362306a36Sopenharmony_ci		MLX4_GET(port_cap->eth_mtu, outbox, QUERY_PORT_ETH_MTU_OFFSET);
125462306a36Sopenharmony_ci		MLX4_GET(port_cap->def_mac, outbox, QUERY_PORT_MAC_OFFSET);
125562306a36Sopenharmony_ci		MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET);
125662306a36Sopenharmony_ci		port_cap->trans_type = field32 >> 24;
125762306a36Sopenharmony_ci		port_cap->vendor_oui = field32 & 0xffffff;
125862306a36Sopenharmony_ci		MLX4_GET(port_cap->wavelength, outbox, QUERY_PORT_WAVELENGTH_OFFSET);
125962306a36Sopenharmony_ci		MLX4_GET(port_cap->trans_code, outbox, QUERY_PORT_TRANS_CODE_OFFSET);
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ciout:
126362306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
126462306a36Sopenharmony_ci	return err;
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci#define DEV_CAP_EXT_2_FLAG_PFC_COUNTERS	(1 << 28)
126862306a36Sopenharmony_ci#define DEV_CAP_EXT_2_FLAG_VLAN_CONTROL (1 << 26)
126962306a36Sopenharmony_ci#define DEV_CAP_EXT_2_FLAG_80_VFS	(1 << 21)
127062306a36Sopenharmony_ci#define DEV_CAP_EXT_2_FLAG_FSM		(1 << 20)
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ciint mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
127362306a36Sopenharmony_ci			       struct mlx4_vhcr *vhcr,
127462306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *inbox,
127562306a36Sopenharmony_ci			       struct mlx4_cmd_mailbox *outbox,
127662306a36Sopenharmony_ci			       struct mlx4_cmd_info *cmd)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	u64	flags;
127962306a36Sopenharmony_ci	int	err = 0;
128062306a36Sopenharmony_ci	u8	field;
128162306a36Sopenharmony_ci	u16	field16;
128262306a36Sopenharmony_ci	u32	bmme_flags, field32;
128362306a36Sopenharmony_ci	int	real_port;
128462306a36Sopenharmony_ci	int	slave_port;
128562306a36Sopenharmony_ci	int	first_port;
128662306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
128962306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
129062306a36Sopenharmony_ci	if (err)
129162306a36Sopenharmony_ci		return err;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	disable_unsupported_roce_caps(outbox->buf);
129462306a36Sopenharmony_ci	/* add port mng change event capability and disable mw type 1
129562306a36Sopenharmony_ci	 * unconditionally to slaves
129662306a36Sopenharmony_ci	 */
129762306a36Sopenharmony_ci	MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
129862306a36Sopenharmony_ci	flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV;
129962306a36Sopenharmony_ci	flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
130062306a36Sopenharmony_ci	actv_ports = mlx4_get_active_ports(dev, slave);
130162306a36Sopenharmony_ci	first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
130262306a36Sopenharmony_ci	for (slave_port = 0, real_port = first_port;
130362306a36Sopenharmony_ci	     real_port < first_port +
130462306a36Sopenharmony_ci	     bitmap_weight(actv_ports.ports, dev->caps.num_ports);
130562306a36Sopenharmony_ci	     ++real_port, ++slave_port) {
130662306a36Sopenharmony_ci		if (flags & (MLX4_DEV_CAP_FLAG_WOL_PORT1 << real_port))
130762306a36Sopenharmony_ci			flags |= MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port;
130862306a36Sopenharmony_ci		else
130962306a36Sopenharmony_ci			flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci	for (; slave_port < dev->caps.num_ports; ++slave_port)
131262306a36Sopenharmony_ci		flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	/* Not exposing RSS IP fragments to guests */
131562306a36Sopenharmony_ci	flags &= ~MLX4_DEV_CAP_FLAG_RSS_IP_FRAG;
131662306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET);
131962306a36Sopenharmony_ci	field &= ~0x0F;
132062306a36Sopenharmony_ci	field |= bitmap_weight(actv_ports.ports, dev->caps.num_ports) & 0x0F;
132162306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VL_PORT_OFFSET);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	/* For guests, disable timestamp */
132462306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
132562306a36Sopenharmony_ci	field &= 0x7f;
132662306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	/* For guests, disable vxlan tunneling and QoS support */
132962306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
133062306a36Sopenharmony_ci	field &= 0xd7;
133162306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	/* For guests, disable port BEACON */
133462306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_PORT_BEACON_OFFSET);
133562306a36Sopenharmony_ci	field &= 0x7f;
133662306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_PORT_BEACON_OFFSET);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* For guests, report Blueflame disabled */
133962306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET);
134062306a36Sopenharmony_ci	field &= 0x7f;
134162306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	/* For guests, disable mw type 2 and port remap*/
134462306a36Sopenharmony_ci	MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
134562306a36Sopenharmony_ci	bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
134662306a36Sopenharmony_ci	bmme_flags &= ~MLX4_FLAG_PORT_REMAP;
134762306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* turn off device-managed steering capability if not enabled */
135062306a36Sopenharmony_ci	if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
135162306a36Sopenharmony_ci		MLX4_GET(field, outbox->buf,
135262306a36Sopenharmony_ci			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
135362306a36Sopenharmony_ci		field &= 0x7f;
135462306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, field,
135562306a36Sopenharmony_ci			 QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	/* turn off ipoib managed steering for guests */
135962306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
136062306a36Sopenharmony_ci	field &= ~0x80;
136162306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	/* turn off host side virt features (VST, FSM, etc) for guests */
136462306a36Sopenharmony_ci	MLX4_GET(field32, outbox->buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
136562306a36Sopenharmony_ci	field32 &= ~(DEV_CAP_EXT_2_FLAG_VLAN_CONTROL | DEV_CAP_EXT_2_FLAG_80_VFS |
136662306a36Sopenharmony_ci		     DEV_CAP_EXT_2_FLAG_FSM | DEV_CAP_EXT_2_FLAG_PFC_COUNTERS);
136762306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field32, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	/* turn off QCN for guests */
137062306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
137162306a36Sopenharmony_ci	field &= 0xfe;
137262306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/* turn off QP max-rate limiting for guests */
137562306a36Sopenharmony_ci	field16 = 0;
137662306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field16, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	/* turn off QoS per VF support for guests */
137962306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
138062306a36Sopenharmony_ci	field &= 0xef;
138162306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	/* turn off ignore FCS feature for guests */
138462306a36Sopenharmony_ci	MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
138562306a36Sopenharmony_ci	field &= 0xfb;
138662306a36Sopenharmony_ci	MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	return 0;
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_cistatic void disable_unsupported_roce_caps(void *buf)
139262306a36Sopenharmony_ci{
139362306a36Sopenharmony_ci	u32 flags;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
139662306a36Sopenharmony_ci	flags &= ~(1UL << 31);
139762306a36Sopenharmony_ci	MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
139862306a36Sopenharmony_ci	MLX4_GET(flags, buf, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
139962306a36Sopenharmony_ci	flags &= ~(1UL << 24);
140062306a36Sopenharmony_ci	MLX4_PUT(buf, flags, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
140162306a36Sopenharmony_ci	MLX4_GET(flags, buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
140262306a36Sopenharmony_ci	flags &= ~(MLX4_FLAG_ROCE_V1_V2);
140362306a36Sopenharmony_ci	MLX4_PUT(buf, flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ciint mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
140762306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
140862306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
140962306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
141062306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
141362306a36Sopenharmony_ci	u64 def_mac;
141462306a36Sopenharmony_ci	u8 port_type;
141562306a36Sopenharmony_ci	u16 short_field;
141662306a36Sopenharmony_ci	int err;
141762306a36Sopenharmony_ci	int admin_link_state;
141862306a36Sopenharmony_ci	int port = mlx4_slave_convert_port(dev, slave,
141962306a36Sopenharmony_ci					   vhcr->in_modifier & 0xFF);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci#define MLX4_VF_PORT_NO_LINK_SENSE_MASK	0xE0
142262306a36Sopenharmony_ci#define MLX4_PORT_LINK_UP_MASK		0x80
142362306a36Sopenharmony_ci#define QUERY_PORT_CUR_MAX_PKEY_OFFSET	0x0c
142462306a36Sopenharmony_ci#define QUERY_PORT_CUR_MAX_GID_OFFSET	0x0e
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (port < 0)
142762306a36Sopenharmony_ci		return -EINVAL;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/* Protect against untrusted guests: enforce that this is the
143062306a36Sopenharmony_ci	 * QUERY_PORT general query.
143162306a36Sopenharmony_ci	 */
143262306a36Sopenharmony_ci	if (vhcr->op_modifier || vhcr->in_modifier & ~0xFF)
143362306a36Sopenharmony_ci		return -EINVAL;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	vhcr->in_modifier = port;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0,
143862306a36Sopenharmony_ci			   MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
143962306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	if (!err && dev->caps.function != slave) {
144262306a36Sopenharmony_ci		def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
144362306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci		/* get port type - currently only eth is enabled */
144662306a36Sopenharmony_ci		MLX4_GET(port_type, outbox->buf,
144762306a36Sopenharmony_ci			 QUERY_PORT_SUPPORTED_TYPE_OFFSET);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		/* No link sensing allowed */
145062306a36Sopenharmony_ci		port_type &= MLX4_VF_PORT_NO_LINK_SENSE_MASK;
145162306a36Sopenharmony_ci		/* set port type to currently operating port type */
145262306a36Sopenharmony_ci		port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		admin_link_state = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.link_state;
145562306a36Sopenharmony_ci		if (IFLA_VF_LINK_STATE_ENABLE == admin_link_state)
145662306a36Sopenharmony_ci			port_type |= MLX4_PORT_LINK_UP_MASK;
145762306a36Sopenharmony_ci		else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state)
145862306a36Sopenharmony_ci			port_type &= ~MLX4_PORT_LINK_UP_MASK;
145962306a36Sopenharmony_ci		else if (IFLA_VF_LINK_STATE_AUTO == admin_link_state && mlx4_is_bonded(dev)) {
146062306a36Sopenharmony_ci			int other_port = (port == 1) ? 2 : 1;
146162306a36Sopenharmony_ci			struct mlx4_port_cap port_cap;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci			err = mlx4_QUERY_PORT(dev, other_port, &port_cap);
146462306a36Sopenharmony_ci			if (err)
146562306a36Sopenharmony_ci				goto out;
146662306a36Sopenharmony_ci			port_type |= (port_cap.link_state << 7);
146762306a36Sopenharmony_ci		}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, port_type,
147062306a36Sopenharmony_ci			 QUERY_PORT_SUPPORTED_TYPE_OFFSET);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
147362306a36Sopenharmony_ci			short_field = mlx4_get_slave_num_gids(dev, slave, port);
147462306a36Sopenharmony_ci		else
147562306a36Sopenharmony_ci			short_field = 1; /* slave max gids */
147662306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, short_field,
147762306a36Sopenharmony_ci			 QUERY_PORT_CUR_MAX_GID_OFFSET);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		short_field = dev->caps.pkey_table_len[vhcr->in_modifier];
148062306a36Sopenharmony_ci		MLX4_PUT(outbox->buf, short_field,
148162306a36Sopenharmony_ci			 QUERY_PORT_CUR_MAX_PKEY_OFFSET);
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ciout:
148462306a36Sopenharmony_ci	return err;
148562306a36Sopenharmony_ci}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ciint mlx4_get_slave_pkey_gid_tbl_len(struct mlx4_dev *dev, u8 port,
148862306a36Sopenharmony_ci				    int *gid_tbl_len, int *pkey_tbl_len)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
149162306a36Sopenharmony_ci	u32			*outbox;
149262306a36Sopenharmony_ci	u16			field;
149362306a36Sopenharmony_ci	int			err;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
149662306a36Sopenharmony_ci	if (IS_ERR(mailbox))
149762306a36Sopenharmony_ci		return PTR_ERR(mailbox);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	err =  mlx4_cmd_box(dev, 0, mailbox->dma, port, 0,
150062306a36Sopenharmony_ci			    MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
150162306a36Sopenharmony_ci			    MLX4_CMD_WRAPPED);
150262306a36Sopenharmony_ci	if (err)
150362306a36Sopenharmony_ci		goto out;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	outbox = mailbox->buf;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_GID_OFFSET);
150862306a36Sopenharmony_ci	*gid_tbl_len = field;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	MLX4_GET(field, outbox, QUERY_PORT_CUR_MAX_PKEY_OFFSET);
151162306a36Sopenharmony_ci	*pkey_tbl_len = field;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ciout:
151462306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
151562306a36Sopenharmony_ci	return err;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ciEXPORT_SYMBOL(mlx4_get_slave_pkey_gid_tbl_len);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ciint mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
152262306a36Sopenharmony_ci	struct mlx4_icm_iter iter;
152362306a36Sopenharmony_ci	__be64 *pages;
152462306a36Sopenharmony_ci	int lg;
152562306a36Sopenharmony_ci	int nent = 0;
152662306a36Sopenharmony_ci	int i;
152762306a36Sopenharmony_ci	int err = 0;
152862306a36Sopenharmony_ci	int ts = 0, tc = 0;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
153162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
153262306a36Sopenharmony_ci		return PTR_ERR(mailbox);
153362306a36Sopenharmony_ci	pages = mailbox->buf;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	for (mlx4_icm_first(icm, &iter);
153662306a36Sopenharmony_ci	     !mlx4_icm_last(&iter);
153762306a36Sopenharmony_ci	     mlx4_icm_next(&iter)) {
153862306a36Sopenharmony_ci		/*
153962306a36Sopenharmony_ci		 * We have to pass pages that are aligned to their
154062306a36Sopenharmony_ci		 * size, so find the least significant 1 in the
154162306a36Sopenharmony_ci		 * address or size and use that as our log2 size.
154262306a36Sopenharmony_ci		 */
154362306a36Sopenharmony_ci		lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1;
154462306a36Sopenharmony_ci		if (lg < MLX4_ICM_PAGE_SHIFT) {
154562306a36Sopenharmony_ci			mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx)\n",
154662306a36Sopenharmony_ci				  MLX4_ICM_PAGE_SIZE,
154762306a36Sopenharmony_ci				  (unsigned long long) mlx4_icm_addr(&iter),
154862306a36Sopenharmony_ci				  mlx4_icm_size(&iter));
154962306a36Sopenharmony_ci			err = -EINVAL;
155062306a36Sopenharmony_ci			goto out;
155162306a36Sopenharmony_ci		}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) {
155462306a36Sopenharmony_ci			if (virt != -1) {
155562306a36Sopenharmony_ci				pages[nent * 2] = cpu_to_be64(virt);
155662306a36Sopenharmony_ci				virt += 1ULL << lg;
155762306a36Sopenharmony_ci			}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci			pages[nent * 2 + 1] =
156062306a36Sopenharmony_ci				cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) |
156162306a36Sopenharmony_ci					    (lg - MLX4_ICM_PAGE_SHIFT));
156262306a36Sopenharmony_ci			ts += 1 << (lg - 10);
156362306a36Sopenharmony_ci			++tc;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci			if (++nent == MLX4_MAILBOX_SIZE / 16) {
156662306a36Sopenharmony_ci				err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
156762306a36Sopenharmony_ci						MLX4_CMD_TIME_CLASS_B,
156862306a36Sopenharmony_ci						MLX4_CMD_NATIVE);
156962306a36Sopenharmony_ci				if (err)
157062306a36Sopenharmony_ci					goto out;
157162306a36Sopenharmony_ci				nent = 0;
157262306a36Sopenharmony_ci			}
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (nent)
157762306a36Sopenharmony_ci		err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
157862306a36Sopenharmony_ci			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
157962306a36Sopenharmony_ci	if (err)
158062306a36Sopenharmony_ci		goto out;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	switch (op) {
158362306a36Sopenharmony_ci	case MLX4_CMD_MAP_FA:
158462306a36Sopenharmony_ci		mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW\n", tc, ts);
158562306a36Sopenharmony_ci		break;
158662306a36Sopenharmony_ci	case MLX4_CMD_MAP_ICM_AUX:
158762306a36Sopenharmony_ci		mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux\n", tc, ts);
158862306a36Sopenharmony_ci		break;
158962306a36Sopenharmony_ci	case MLX4_CMD_MAP_ICM:
159062306a36Sopenharmony_ci		mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM\n",
159162306a36Sopenharmony_ci			 tc, ts, (unsigned long long) virt - (ts << 10));
159262306a36Sopenharmony_ci		break;
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ciout:
159662306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
159762306a36Sopenharmony_ci	return err;
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ciint mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1);
160362306a36Sopenharmony_ci}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ciint mlx4_UNMAP_FA(struct mlx4_dev *dev)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA,
160862306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
160962306a36Sopenharmony_ci}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ciint mlx4_RUN_FW(struct mlx4_dev *dev)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW,
161562306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ciint mlx4_QUERY_FW(struct mlx4_dev *dev)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	struct mlx4_fw  *fw  = &mlx4_priv(dev)->fw;
162162306a36Sopenharmony_ci	struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
162262306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
162362306a36Sopenharmony_ci	u32 *outbox;
162462306a36Sopenharmony_ci	int err = 0;
162562306a36Sopenharmony_ci	u64 fw_ver;
162662306a36Sopenharmony_ci	u16 cmd_if_rev;
162762306a36Sopenharmony_ci	u8 lg;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci#define QUERY_FW_OUT_SIZE             0x100
163062306a36Sopenharmony_ci#define QUERY_FW_VER_OFFSET            0x00
163162306a36Sopenharmony_ci#define QUERY_FW_PPF_ID		       0x09
163262306a36Sopenharmony_ci#define QUERY_FW_CMD_IF_REV_OFFSET     0x0a
163362306a36Sopenharmony_ci#define QUERY_FW_MAX_CMD_OFFSET        0x0f
163462306a36Sopenharmony_ci#define QUERY_FW_ERR_START_OFFSET      0x30
163562306a36Sopenharmony_ci#define QUERY_FW_ERR_SIZE_OFFSET       0x38
163662306a36Sopenharmony_ci#define QUERY_FW_ERR_BAR_OFFSET        0x3c
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci#define QUERY_FW_SIZE_OFFSET           0x00
163962306a36Sopenharmony_ci#define QUERY_FW_CLR_INT_BASE_OFFSET   0x20
164062306a36Sopenharmony_ci#define QUERY_FW_CLR_INT_BAR_OFFSET    0x28
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci#define QUERY_FW_COMM_BASE_OFFSET      0x40
164362306a36Sopenharmony_ci#define QUERY_FW_COMM_BAR_OFFSET       0x48
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci#define QUERY_FW_CLOCK_OFFSET	       0x50
164662306a36Sopenharmony_ci#define QUERY_FW_CLOCK_BAR	       0x58
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
164962306a36Sopenharmony_ci	if (IS_ERR(mailbox))
165062306a36Sopenharmony_ci		return PTR_ERR(mailbox);
165162306a36Sopenharmony_ci	outbox = mailbox->buf;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
165462306a36Sopenharmony_ci			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
165562306a36Sopenharmony_ci	if (err)
165662306a36Sopenharmony_ci		goto out;
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET);
165962306a36Sopenharmony_ci	/*
166062306a36Sopenharmony_ci	 * FW subminor version is at more significant bits than minor
166162306a36Sopenharmony_ci	 * version, so swap here.
166262306a36Sopenharmony_ci	 */
166362306a36Sopenharmony_ci	dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) |
166462306a36Sopenharmony_ci		((fw_ver & 0xffff0000ull) >> 16) |
166562306a36Sopenharmony_ci		((fw_ver & 0x0000ffffull) << 16);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	MLX4_GET(lg, outbox, QUERY_FW_PPF_ID);
166862306a36Sopenharmony_ci	dev->caps.function = lg;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	if (mlx4_is_slave(dev))
167162306a36Sopenharmony_ci		goto out;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET);
167562306a36Sopenharmony_ci	if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV ||
167662306a36Sopenharmony_ci	    cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) {
167762306a36Sopenharmony_ci		mlx4_err(dev, "Installed FW has unsupported command interface revision %d\n",
167862306a36Sopenharmony_ci			 cmd_if_rev);
167962306a36Sopenharmony_ci		mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n",
168062306a36Sopenharmony_ci			 (int) (dev->caps.fw_ver >> 32),
168162306a36Sopenharmony_ci			 (int) (dev->caps.fw_ver >> 16) & 0xffff,
168262306a36Sopenharmony_ci			 (int) dev->caps.fw_ver & 0xffff);
168362306a36Sopenharmony_ci		mlx4_err(dev, "This driver version supports only revisions %d to %d\n",
168462306a36Sopenharmony_ci			 MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV);
168562306a36Sopenharmony_ci		err = -ENODEV;
168662306a36Sopenharmony_ci		goto out;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS)
169062306a36Sopenharmony_ci		dev->flags |= MLX4_FLAG_OLD_PORT_CMDS;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
169362306a36Sopenharmony_ci	cmd->max_cmds = 1 << lg;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n",
169662306a36Sopenharmony_ci		 (int) (dev->caps.fw_ver >> 32),
169762306a36Sopenharmony_ci		 (int) (dev->caps.fw_ver >> 16) & 0xffff,
169862306a36Sopenharmony_ci		 (int) dev->caps.fw_ver & 0xffff,
169962306a36Sopenharmony_ci		 cmd_if_rev, cmd->max_cmds);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET);
170262306a36Sopenharmony_ci	MLX4_GET(fw->catas_size,   outbox, QUERY_FW_ERR_SIZE_OFFSET);
170362306a36Sopenharmony_ci	MLX4_GET(fw->catas_bar,    outbox, QUERY_FW_ERR_BAR_OFFSET);
170462306a36Sopenharmony_ci	fw->catas_bar = (fw->catas_bar >> 6) * 2;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n",
170762306a36Sopenharmony_ci		 (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	MLX4_GET(fw->fw_pages,     outbox, QUERY_FW_SIZE_OFFSET);
171062306a36Sopenharmony_ci	MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
171162306a36Sopenharmony_ci	MLX4_GET(fw->clr_int_bar,  outbox, QUERY_FW_CLR_INT_BAR_OFFSET);
171262306a36Sopenharmony_ci	fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	MLX4_GET(fw->comm_base, outbox, QUERY_FW_COMM_BASE_OFFSET);
171562306a36Sopenharmony_ci	MLX4_GET(fw->comm_bar,  outbox, QUERY_FW_COMM_BAR_OFFSET);
171662306a36Sopenharmony_ci	fw->comm_bar = (fw->comm_bar >> 6) * 2;
171762306a36Sopenharmony_ci	mlx4_dbg(dev, "Communication vector bar:%d offset:0x%llx\n",
171862306a36Sopenharmony_ci		 fw->comm_bar, fw->comm_base);
171962306a36Sopenharmony_ci	mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET);
172262306a36Sopenharmony_ci	MLX4_GET(fw->clock_bar,    outbox, QUERY_FW_CLOCK_BAR);
172362306a36Sopenharmony_ci	fw->clock_bar = (fw->clock_bar >> 6) * 2;
172462306a36Sopenharmony_ci	mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n",
172562306a36Sopenharmony_ci		 fw->clock_bar, fw->clock_offset);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/*
172862306a36Sopenharmony_ci	 * Round up number of system pages needed in case
172962306a36Sopenharmony_ci	 * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
173062306a36Sopenharmony_ci	 */
173162306a36Sopenharmony_ci	fw->fw_pages =
173262306a36Sopenharmony_ci		ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
173362306a36Sopenharmony_ci		(PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n",
173662306a36Sopenharmony_ci		 (unsigned long long) fw->clr_int_base, fw->clr_int_bar);
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ciout:
173962306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
174062306a36Sopenharmony_ci	return err;
174162306a36Sopenharmony_ci}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ciint mlx4_QUERY_FW_wrapper(struct mlx4_dev *dev, int slave,
174462306a36Sopenharmony_ci			  struct mlx4_vhcr *vhcr,
174562306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *inbox,
174662306a36Sopenharmony_ci			  struct mlx4_cmd_mailbox *outbox,
174762306a36Sopenharmony_ci			  struct mlx4_cmd_info *cmd)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	u8 *outbuf;
175062306a36Sopenharmony_ci	int err;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	outbuf = outbox->buf;
175362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
175462306a36Sopenharmony_ci			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
175562306a36Sopenharmony_ci	if (err)
175662306a36Sopenharmony_ci		return err;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	/* for slaves, set pci PPF ID to invalid and zero out everything
175962306a36Sopenharmony_ci	 * else except FW version */
176062306a36Sopenharmony_ci	outbuf[0] = outbuf[1] = 0;
176162306a36Sopenharmony_ci	memset(&outbuf[8], 0, QUERY_FW_OUT_SIZE - 8);
176262306a36Sopenharmony_ci	outbuf[QUERY_FW_PPF_ID] = MLX4_INVALID_SLAVE_ID;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	return 0;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic void get_board_id(void *vsd, char *board_id)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	int i;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci#define VSD_OFFSET_SIG1		0x00
177262306a36Sopenharmony_ci#define VSD_OFFSET_SIG2		0xde
177362306a36Sopenharmony_ci#define VSD_OFFSET_MLX_BOARD_ID	0xd0
177462306a36Sopenharmony_ci#define VSD_OFFSET_TS_BOARD_ID	0x20
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci#define VSD_SIGNATURE_TOPSPIN	0x5ad
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	memset(board_id, 0, MLX4_BOARD_ID_LEN);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
178162306a36Sopenharmony_ci	    be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
178262306a36Sopenharmony_ci		strscpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN);
178362306a36Sopenharmony_ci	} else {
178462306a36Sopenharmony_ci		/*
178562306a36Sopenharmony_ci		 * The board ID is a string but the firmware byte
178662306a36Sopenharmony_ci		 * swaps each 4-byte word before passing it back to
178762306a36Sopenharmony_ci		 * us.  Therefore we need to swab it before printing.
178862306a36Sopenharmony_ci		 */
178962306a36Sopenharmony_ci		u32 *bid_u32 = (u32 *)board_id;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci		for (i = 0; i < 4; ++i) {
179262306a36Sopenharmony_ci			u32 *addr;
179362306a36Sopenharmony_ci			u32 val;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci			addr = (u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4);
179662306a36Sopenharmony_ci			val = get_unaligned(addr);
179762306a36Sopenharmony_ci			val = swab32(val);
179862306a36Sopenharmony_ci			put_unaligned(val, &bid_u32[i]);
179962306a36Sopenharmony_ci		}
180062306a36Sopenharmony_ci	}
180162306a36Sopenharmony_ci}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ciint mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
180662306a36Sopenharmony_ci	u32 *outbox;
180762306a36Sopenharmony_ci	int err;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci#define QUERY_ADAPTER_OUT_SIZE             0x100
181062306a36Sopenharmony_ci#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
181162306a36Sopenharmony_ci#define QUERY_ADAPTER_VSD_OFFSET           0x20
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
181462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
181562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
181662306a36Sopenharmony_ci	outbox = mailbox->buf;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER,
181962306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
182062306a36Sopenharmony_ci	if (err)
182162306a36Sopenharmony_ci		goto out;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	MLX4_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
182662306a36Sopenharmony_ci		     adapter->board_id);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ciout:
182962306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
183062306a36Sopenharmony_ci	return err;
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ciint mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
183662306a36Sopenharmony_ci	__be32 *inbox;
183762306a36Sopenharmony_ci	int err;
183862306a36Sopenharmony_ci	static const u8 a0_dmfs_hw_steering[] =  {
183962306a36Sopenharmony_ci		[MLX4_STEERING_DMFS_A0_DEFAULT]		= 0,
184062306a36Sopenharmony_ci		[MLX4_STEERING_DMFS_A0_DYNAMIC]		= 1,
184162306a36Sopenharmony_ci		[MLX4_STEERING_DMFS_A0_STATIC]		= 2,
184262306a36Sopenharmony_ci		[MLX4_STEERING_DMFS_A0_DISABLE]		= 3
184362306a36Sopenharmony_ci	};
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci#define INIT_HCA_IN_SIZE		 0x200
184662306a36Sopenharmony_ci#define INIT_HCA_VERSION_OFFSET		 0x000
184762306a36Sopenharmony_ci#define	 INIT_HCA_VERSION		 2
184862306a36Sopenharmony_ci#define INIT_HCA_VXLAN_OFFSET		 0x0c
184962306a36Sopenharmony_ci#define INIT_HCA_CACHELINE_SZ_OFFSET	 0x0e
185062306a36Sopenharmony_ci#define INIT_HCA_FLAGS_OFFSET		 0x014
185162306a36Sopenharmony_ci#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018
185262306a36Sopenharmony_ci#define INIT_HCA_QPC_OFFSET		 0x020
185362306a36Sopenharmony_ci#define	 INIT_HCA_QPC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x10)
185462306a36Sopenharmony_ci#define	 INIT_HCA_LOG_QP_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x17)
185562306a36Sopenharmony_ci#define	 INIT_HCA_SRQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x28)
185662306a36Sopenharmony_ci#define	 INIT_HCA_LOG_SRQ_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x2f)
185762306a36Sopenharmony_ci#define	 INIT_HCA_CQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x30)
185862306a36Sopenharmony_ci#define	 INIT_HCA_LOG_CQ_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x37)
185962306a36Sopenharmony_ci#define	 INIT_HCA_EQE_CQE_OFFSETS	 (INIT_HCA_QPC_OFFSET + 0x38)
186062306a36Sopenharmony_ci#define	 INIT_HCA_EQE_CQE_STRIDE_OFFSET  (INIT_HCA_QPC_OFFSET + 0x3b)
186162306a36Sopenharmony_ci#define	 INIT_HCA_ALTC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x40)
186262306a36Sopenharmony_ci#define	 INIT_HCA_AUXC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x50)
186362306a36Sopenharmony_ci#define	 INIT_HCA_EQC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x60)
186462306a36Sopenharmony_ci#define	 INIT_HCA_LOG_EQ_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x67)
186562306a36Sopenharmony_ci#define	INIT_HCA_NUM_SYS_EQS_OFFSET	(INIT_HCA_QPC_OFFSET + 0x6a)
186662306a36Sopenharmony_ci#define	 INIT_HCA_RDMARC_BASE_OFFSET	 (INIT_HCA_QPC_OFFSET + 0x70)
186762306a36Sopenharmony_ci#define	 INIT_HCA_LOG_RD_OFFSET		 (INIT_HCA_QPC_OFFSET + 0x77)
186862306a36Sopenharmony_ci#define INIT_HCA_MCAST_OFFSET		 0x0c0
186962306a36Sopenharmony_ci#define	 INIT_HCA_MC_BASE_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x00)
187062306a36Sopenharmony_ci#define	 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x13)
187162306a36Sopenharmony_ci#define	 INIT_HCA_LOG_MC_HASH_SZ_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x17)
187262306a36Sopenharmony_ci#define  INIT_HCA_UC_STEERING_OFFSET	 (INIT_HCA_MCAST_OFFSET + 0x18)
187362306a36Sopenharmony_ci#define	 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
187462306a36Sopenharmony_ci#define  INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN	0x6
187562306a36Sopenharmony_ci#define  INIT_HCA_DRIVER_VERSION_OFFSET   0x140
187662306a36Sopenharmony_ci#define  INIT_HCA_DRIVER_VERSION_SZ       0x40
187762306a36Sopenharmony_ci#define  INIT_HCA_FS_PARAM_OFFSET         0x1d0
187862306a36Sopenharmony_ci#define  INIT_HCA_FS_BASE_OFFSET          (INIT_HCA_FS_PARAM_OFFSET + 0x00)
187962306a36Sopenharmony_ci#define  INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x13)
188062306a36Sopenharmony_ci#define  INIT_HCA_FS_A0_OFFSET		  (INIT_HCA_FS_PARAM_OFFSET + 0x18)
188162306a36Sopenharmony_ci#define  INIT_HCA_FS_LOG_TABLE_SZ_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x1b)
188262306a36Sopenharmony_ci#define  INIT_HCA_FS_ETH_BITS_OFFSET      (INIT_HCA_FS_PARAM_OFFSET + 0x21)
188362306a36Sopenharmony_ci#define  INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET (INIT_HCA_FS_PARAM_OFFSET + 0x22)
188462306a36Sopenharmony_ci#define  INIT_HCA_FS_IB_BITS_OFFSET       (INIT_HCA_FS_PARAM_OFFSET + 0x25)
188562306a36Sopenharmony_ci#define  INIT_HCA_FS_IB_NUM_ADDRS_OFFSET  (INIT_HCA_FS_PARAM_OFFSET + 0x26)
188662306a36Sopenharmony_ci#define INIT_HCA_TPT_OFFSET		 0x0f0
188762306a36Sopenharmony_ci#define	 INIT_HCA_DMPT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x00)
188862306a36Sopenharmony_ci#define  INIT_HCA_TPT_MW_OFFSET		 (INIT_HCA_TPT_OFFSET + 0x08)
188962306a36Sopenharmony_ci#define	 INIT_HCA_LOG_MPT_SZ_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x0b)
189062306a36Sopenharmony_ci#define	 INIT_HCA_MTT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x10)
189162306a36Sopenharmony_ci#define	 INIT_HCA_CMPT_BASE_OFFSET	 (INIT_HCA_TPT_OFFSET + 0x18)
189262306a36Sopenharmony_ci#define INIT_HCA_UAR_OFFSET		 0x120
189362306a36Sopenharmony_ci#define	 INIT_HCA_LOG_UAR_SZ_OFFSET	 (INIT_HCA_UAR_OFFSET + 0x0a)
189462306a36Sopenharmony_ci#define  INIT_HCA_UAR_PAGE_SZ_OFFSET     (INIT_HCA_UAR_OFFSET + 0x0b)
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
189762306a36Sopenharmony_ci	if (IS_ERR(mailbox))
189862306a36Sopenharmony_ci		return PTR_ERR(mailbox);
189962306a36Sopenharmony_ci	inbox = mailbox->buf;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	*((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	*((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) =
190462306a36Sopenharmony_ci		((ilog2(cache_line_size()) - 4) << 5) | (1 << 4);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN)
190762306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
190862306a36Sopenharmony_ci#elif defined(__BIG_ENDIAN)
190962306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
191062306a36Sopenharmony_ci#else
191162306a36Sopenharmony_ci#error Host endianness not defined
191262306a36Sopenharmony_ci#endif
191362306a36Sopenharmony_ci	/* Check port for UD address vector: */
191462306a36Sopenharmony_ci	*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/* Enable IPoIB checksumming if we can: */
191762306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM)
191862306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3);
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	/* Enable QoS support if module parameter set */
192162306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG && enable_qos)
192262306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	/* enable counters */
192562306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS)
192662306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4);
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	/* Enable RSS spread to fragmented IP packets when supported */
192962306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_RSS_IP_FRAG)
193062306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 13);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	/* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */
193362306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) {
193462306a36Sopenharmony_ci		*(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29);
193562306a36Sopenharmony_ci		dev->caps.eqe_size   = 64;
193662306a36Sopenharmony_ci		dev->caps.eqe_factor = 1;
193762306a36Sopenharmony_ci	} else {
193862306a36Sopenharmony_ci		dev->caps.eqe_size   = 32;
193962306a36Sopenharmony_ci		dev->caps.eqe_factor = 0;
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_CQE) {
194362306a36Sopenharmony_ci		*(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 30);
194462306a36Sopenharmony_ci		dev->caps.cqe_size   = 64;
194562306a36Sopenharmony_ci		dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
194662306a36Sopenharmony_ci	} else {
194762306a36Sopenharmony_ci		dev->caps.cqe_size   = 32;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	/* CX3 is capable of extending CQEs\EQEs to strides larger than 64B */
195162306a36Sopenharmony_ci	if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_EQE_STRIDE) &&
195262306a36Sopenharmony_ci	    (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CQE_STRIDE)) {
195362306a36Sopenharmony_ci		dev->caps.eqe_size = cache_line_size();
195462306a36Sopenharmony_ci		dev->caps.cqe_size = cache_line_size();
195562306a36Sopenharmony_ci		dev->caps.eqe_factor = 0;
195662306a36Sopenharmony_ci		MLX4_PUT(inbox, (u8)((ilog2(dev->caps.eqe_size) - 5) << 4 |
195762306a36Sopenharmony_ci				      (ilog2(dev->caps.eqe_size) - 5)),
195862306a36Sopenharmony_ci			 INIT_HCA_EQE_CQE_STRIDE_OFFSET);
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		/* User still need to know to support CQE > 32B */
196162306a36Sopenharmony_ci		dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT)
196562306a36Sopenharmony_ci		*(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DRIVER_VERSION_TO_FW) {
196862306a36Sopenharmony_ci		u8 *dst = (u8 *)(inbox + INIT_HCA_DRIVER_VERSION_OFFSET / 4);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		strncpy(dst, DRV_NAME_FOR_FW, INIT_HCA_DRIVER_VERSION_SZ - 1);
197162306a36Sopenharmony_ci		mlx4_dbg(dev, "Reporting Driver Version to FW: %s\n", dst);
197262306a36Sopenharmony_ci	}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	/* QPC/EEC/CQC/EQC/RDMARC attributes */
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	MLX4_PUT(inbox, param->qpc_base,      INIT_HCA_QPC_BASE_OFFSET);
197762306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_num_qps,   INIT_HCA_LOG_QP_OFFSET);
197862306a36Sopenharmony_ci	MLX4_PUT(inbox, param->srqc_base,     INIT_HCA_SRQC_BASE_OFFSET);
197962306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_num_srqs,  INIT_HCA_LOG_SRQ_OFFSET);
198062306a36Sopenharmony_ci	MLX4_PUT(inbox, param->cqc_base,      INIT_HCA_CQC_BASE_OFFSET);
198162306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_num_cqs,   INIT_HCA_LOG_CQ_OFFSET);
198262306a36Sopenharmony_ci	MLX4_PUT(inbox, param->altc_base,     INIT_HCA_ALTC_BASE_OFFSET);
198362306a36Sopenharmony_ci	MLX4_PUT(inbox, param->auxc_base,     INIT_HCA_AUXC_BASE_OFFSET);
198462306a36Sopenharmony_ci	MLX4_PUT(inbox, param->eqc_base,      INIT_HCA_EQC_BASE_OFFSET);
198562306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_num_eqs,   INIT_HCA_LOG_EQ_OFFSET);
198662306a36Sopenharmony_ci	MLX4_PUT(inbox, param->num_sys_eqs,   INIT_HCA_NUM_SYS_EQS_OFFSET);
198762306a36Sopenharmony_ci	MLX4_PUT(inbox, param->rdmarc_base,   INIT_HCA_RDMARC_BASE_OFFSET);
198862306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	/* steering attributes */
199162306a36Sopenharmony_ci	if (dev->caps.steering_mode ==
199262306a36Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
199362306a36Sopenharmony_ci		*(inbox + INIT_HCA_FLAGS_OFFSET / 4) |=
199462306a36Sopenharmony_ci			cpu_to_be32(1 <<
199562306a36Sopenharmony_ci				    INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci		MLX4_PUT(inbox, param->mc_base, INIT_HCA_FS_BASE_OFFSET);
199862306a36Sopenharmony_ci		MLX4_PUT(inbox, param->log_mc_entry_sz,
199962306a36Sopenharmony_ci			 INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
200062306a36Sopenharmony_ci		MLX4_PUT(inbox, param->log_mc_table_sz,
200162306a36Sopenharmony_ci			 INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
200262306a36Sopenharmony_ci		/* Enable Ethernet flow steering
200362306a36Sopenharmony_ci		 * with udp unicast and tcp unicast
200462306a36Sopenharmony_ci		 */
200562306a36Sopenharmony_ci		if (dev->caps.dmfs_high_steer_mode !=
200662306a36Sopenharmony_ci		    MLX4_STEERING_DMFS_A0_STATIC)
200762306a36Sopenharmony_ci			MLX4_PUT(inbox,
200862306a36Sopenharmony_ci				 (u8)(MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
200962306a36Sopenharmony_ci				 INIT_HCA_FS_ETH_BITS_OFFSET);
201062306a36Sopenharmony_ci		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
201162306a36Sopenharmony_ci			 INIT_HCA_FS_ETH_NUM_ADDRS_OFFSET);
201262306a36Sopenharmony_ci		/* Enable IPoIB flow steering
201362306a36Sopenharmony_ci		 * with udp unicast and tcp unicast
201462306a36Sopenharmony_ci		 */
201562306a36Sopenharmony_ci		MLX4_PUT(inbox, (u8) (MLX4_FS_UDP_UC_EN | MLX4_FS_TCP_UC_EN),
201662306a36Sopenharmony_ci			 INIT_HCA_FS_IB_BITS_OFFSET);
201762306a36Sopenharmony_ci		MLX4_PUT(inbox, (u16) MLX4_FS_NUM_OF_L2_ADDR,
201862306a36Sopenharmony_ci			 INIT_HCA_FS_IB_NUM_ADDRS_OFFSET);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		if (dev->caps.dmfs_high_steer_mode !=
202162306a36Sopenharmony_ci		    MLX4_STEERING_DMFS_A0_NOT_SUPPORTED)
202262306a36Sopenharmony_ci			MLX4_PUT(inbox,
202362306a36Sopenharmony_ci				 ((u8)(a0_dmfs_hw_steering[dev->caps.dmfs_high_steer_mode]
202462306a36Sopenharmony_ci				       << 6)),
202562306a36Sopenharmony_ci				 INIT_HCA_FS_A0_OFFSET);
202662306a36Sopenharmony_ci	} else {
202762306a36Sopenharmony_ci		MLX4_PUT(inbox, param->mc_base,	INIT_HCA_MC_BASE_OFFSET);
202862306a36Sopenharmony_ci		MLX4_PUT(inbox, param->log_mc_entry_sz,
202962306a36Sopenharmony_ci			 INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
203062306a36Sopenharmony_ci		MLX4_PUT(inbox, param->log_mc_hash_sz,
203162306a36Sopenharmony_ci			 INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
203262306a36Sopenharmony_ci		MLX4_PUT(inbox, param->log_mc_table_sz,
203362306a36Sopenharmony_ci			 INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
203462306a36Sopenharmony_ci		if (dev->caps.steering_mode == MLX4_STEERING_MODE_B0)
203562306a36Sopenharmony_ci			MLX4_PUT(inbox, (u8) (1 << 3),
203662306a36Sopenharmony_ci				 INIT_HCA_UC_STEERING_OFFSET);
203762306a36Sopenharmony_ci	}
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	/* TPT attributes */
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	MLX4_PUT(inbox, param->dmpt_base,  INIT_HCA_DMPT_BASE_OFFSET);
204262306a36Sopenharmony_ci	MLX4_PUT(inbox, param->mw_enabled, INIT_HCA_TPT_MW_OFFSET);
204362306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
204462306a36Sopenharmony_ci	MLX4_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
204562306a36Sopenharmony_ci	MLX4_PUT(inbox, param->cmpt_base,  INIT_HCA_CMPT_BASE_OFFSET);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	/* UAR attributes */
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	MLX4_PUT(inbox, param->uar_page_sz,	INIT_HCA_UAR_PAGE_SZ_OFFSET);
205062306a36Sopenharmony_ci	MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	/* set parser VXLAN attributes */
205362306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS) {
205462306a36Sopenharmony_ci		u8 parser_params = 0;
205562306a36Sopenharmony_ci		MLX4_PUT(inbox, parser_params,	INIT_HCA_VXLAN_OFFSET);
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA,
205962306a36Sopenharmony_ci		       MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	if (err)
206262306a36Sopenharmony_ci		mlx4_err(dev, "INIT_HCA returns %d\n", err);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
206562306a36Sopenharmony_ci	return err;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ciint mlx4_QUERY_HCA(struct mlx4_dev *dev,
206962306a36Sopenharmony_ci		   struct mlx4_init_hca_param *param)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
207262306a36Sopenharmony_ci	__be32 *outbox;
207362306a36Sopenharmony_ci	u64 qword_field;
207462306a36Sopenharmony_ci	u32 dword_field;
207562306a36Sopenharmony_ci	u16 word_field;
207662306a36Sopenharmony_ci	u8 byte_field;
207762306a36Sopenharmony_ci	int err;
207862306a36Sopenharmony_ci	static const u8 a0_dmfs_query_hw_steering[] =  {
207962306a36Sopenharmony_ci		[0] = MLX4_STEERING_DMFS_A0_DEFAULT,
208062306a36Sopenharmony_ci		[1] = MLX4_STEERING_DMFS_A0_DYNAMIC,
208162306a36Sopenharmony_ci		[2] = MLX4_STEERING_DMFS_A0_STATIC,
208262306a36Sopenharmony_ci		[3] = MLX4_STEERING_DMFS_A0_DISABLE
208362306a36Sopenharmony_ci	};
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci#define QUERY_HCA_GLOBAL_CAPS_OFFSET	0x04
208662306a36Sopenharmony_ci#define QUERY_HCA_CORE_CLOCK_OFFSET	0x0c
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
208962306a36Sopenharmony_ci	if (IS_ERR(mailbox))
209062306a36Sopenharmony_ci		return PTR_ERR(mailbox);
209162306a36Sopenharmony_ci	outbox = mailbox->buf;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
209462306a36Sopenharmony_ci			   MLX4_CMD_QUERY_HCA,
209562306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_B,
209662306a36Sopenharmony_ci			   !mlx4_is_slave(dev));
209762306a36Sopenharmony_ci	if (err)
209862306a36Sopenharmony_ci		goto out;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET);
210162306a36Sopenharmony_ci	MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	/* QPC/EEC/CQC/EQC/RDMARC attributes */
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_QPC_BASE_OFFSET);
210662306a36Sopenharmony_ci	param->qpc_base = qword_field & ~((u64)0x1f);
210762306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_QP_OFFSET);
210862306a36Sopenharmony_ci	param->log_num_qps = byte_field & 0x1f;
210962306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_SRQC_BASE_OFFSET);
211062306a36Sopenharmony_ci	param->srqc_base = qword_field & ~((u64)0x1f);
211162306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_SRQ_OFFSET);
211262306a36Sopenharmony_ci	param->log_num_srqs = byte_field & 0x1f;
211362306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_CQC_BASE_OFFSET);
211462306a36Sopenharmony_ci	param->cqc_base = qword_field & ~((u64)0x1f);
211562306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_CQ_OFFSET);
211662306a36Sopenharmony_ci	param->log_num_cqs = byte_field & 0x1f;
211762306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_ALTC_BASE_OFFSET);
211862306a36Sopenharmony_ci	param->altc_base = qword_field;
211962306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_AUXC_BASE_OFFSET);
212062306a36Sopenharmony_ci	param->auxc_base = qword_field;
212162306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_EQC_BASE_OFFSET);
212262306a36Sopenharmony_ci	param->eqc_base = qword_field & ~((u64)0x1f);
212362306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_EQ_OFFSET);
212462306a36Sopenharmony_ci	param->log_num_eqs = byte_field & 0x1f;
212562306a36Sopenharmony_ci	MLX4_GET(word_field, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET);
212662306a36Sopenharmony_ci	param->num_sys_eqs = word_field & 0xfff;
212762306a36Sopenharmony_ci	MLX4_GET(qword_field, outbox, INIT_HCA_RDMARC_BASE_OFFSET);
212862306a36Sopenharmony_ci	param->rdmarc_base = qword_field & ~((u64)0x1f);
212962306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_RD_OFFSET);
213062306a36Sopenharmony_ci	param->log_rd_per_qp = byte_field & 0x7;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET);
213362306a36Sopenharmony_ci	if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) {
213462306a36Sopenharmony_ci		param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED;
213562306a36Sopenharmony_ci	} else {
213662306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET);
213762306a36Sopenharmony_ci		if (byte_field & 0x8)
213862306a36Sopenharmony_ci			param->steering_mode = MLX4_STEERING_MODE_B0;
213962306a36Sopenharmony_ci		else
214062306a36Sopenharmony_ci			param->steering_mode = MLX4_STEERING_MODE_A0;
214162306a36Sopenharmony_ci	}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	if (dword_field & (1 << 13))
214462306a36Sopenharmony_ci		param->rss_ip_frags = 1;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	/* steering attributes */
214762306a36Sopenharmony_ci	if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
214862306a36Sopenharmony_ci		MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET);
214962306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
215062306a36Sopenharmony_ci		param->log_mc_entry_sz = byte_field & 0x1f;
215162306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_TABLE_SZ_OFFSET);
215262306a36Sopenharmony_ci		param->log_mc_table_sz = byte_field & 0x1f;
215362306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_FS_A0_OFFSET);
215462306a36Sopenharmony_ci		param->dmfs_high_steer_mode =
215562306a36Sopenharmony_ci			a0_dmfs_query_hw_steering[(byte_field >> 6) & 3];
215662306a36Sopenharmony_ci	} else {
215762306a36Sopenharmony_ci		MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET);
215862306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
215962306a36Sopenharmony_ci		param->log_mc_entry_sz = byte_field & 0x1f;
216062306a36Sopenharmony_ci		MLX4_GET(byte_field,  outbox, INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
216162306a36Sopenharmony_ci		param->log_mc_hash_sz = byte_field & 0x1f;
216262306a36Sopenharmony_ci		MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
216362306a36Sopenharmony_ci		param->log_mc_table_sz = byte_field & 0x1f;
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	/* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */
216762306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_OFFSETS);
216862306a36Sopenharmony_ci	if (byte_field & 0x20) /* 64-bytes eqe enabled */
216962306a36Sopenharmony_ci		param->dev_cap_enabled |= MLX4_DEV_CAP_64B_EQE_ENABLED;
217062306a36Sopenharmony_ci	if (byte_field & 0x40) /* 64-bytes cqe enabled */
217162306a36Sopenharmony_ci		param->dev_cap_enabled |= MLX4_DEV_CAP_64B_CQE_ENABLED;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	/* CX3 is capable of extending CQEs\EQEs to strides larger than 64B */
217462306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_EQE_CQE_STRIDE_OFFSET);
217562306a36Sopenharmony_ci	if (byte_field) {
217662306a36Sopenharmony_ci		param->dev_cap_enabled |= MLX4_DEV_CAP_EQE_STRIDE_ENABLED;
217762306a36Sopenharmony_ci		param->dev_cap_enabled |= MLX4_DEV_CAP_CQE_STRIDE_ENABLED;
217862306a36Sopenharmony_ci		param->cqe_size = 1 << ((byte_field &
217962306a36Sopenharmony_ci					 MLX4_CQE_SIZE_MASK_STRIDE) + 5);
218062306a36Sopenharmony_ci		param->eqe_size = 1 << (((byte_field &
218162306a36Sopenharmony_ci					  MLX4_EQE_SIZE_MASK_STRIDE) >> 4) + 5);
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	/* TPT attributes */
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	MLX4_GET(param->dmpt_base,  outbox, INIT_HCA_DMPT_BASE_OFFSET);
218762306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_TPT_MW_OFFSET);
218862306a36Sopenharmony_ci	param->mw_enabled = byte_field >> 7;
218962306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET);
219062306a36Sopenharmony_ci	param->log_mpt_sz = byte_field & 0x3f;
219162306a36Sopenharmony_ci	MLX4_GET(param->mtt_base,   outbox, INIT_HCA_MTT_BASE_OFFSET);
219262306a36Sopenharmony_ci	MLX4_GET(param->cmpt_base,  outbox, INIT_HCA_CMPT_BASE_OFFSET);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	/* UAR attributes */
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET);
219762306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET);
219862306a36Sopenharmony_ci	param->log_uar_sz = byte_field & 0xf;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	/* phv_check enable */
220162306a36Sopenharmony_ci	MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET);
220262306a36Sopenharmony_ci	if (byte_field & 0x2)
220362306a36Sopenharmony_ci		param->phv_check_en = 1;
220462306a36Sopenharmony_ciout:
220562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	return err;
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic int mlx4_hca_core_clock_update(struct mlx4_dev *dev)
221162306a36Sopenharmony_ci{
221262306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
221362306a36Sopenharmony_ci	__be32 *outbox;
221462306a36Sopenharmony_ci	int err;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
221762306a36Sopenharmony_ci	if (IS_ERR(mailbox)) {
221862306a36Sopenharmony_ci		mlx4_warn(dev, "hca_core_clock mailbox allocation failed\n");
221962306a36Sopenharmony_ci		return PTR_ERR(mailbox);
222062306a36Sopenharmony_ci	}
222162306a36Sopenharmony_ci	outbox = mailbox->buf;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
222462306a36Sopenharmony_ci			   MLX4_CMD_QUERY_HCA,
222562306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_B,
222662306a36Sopenharmony_ci			   !mlx4_is_slave(dev));
222762306a36Sopenharmony_ci	if (err) {
222862306a36Sopenharmony_ci		mlx4_warn(dev, "hca_core_clock update failed\n");
222962306a36Sopenharmony_ci		goto out;
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	MLX4_GET(dev->caps.hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ciout:
223562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	return err;
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0
224162306a36Sopenharmony_ci * and real QP0 are active, so that the paravirtualized QP0 is ready
224262306a36Sopenharmony_ci * to operate */
224362306a36Sopenharmony_cistatic int check_qp0_state(struct mlx4_dev *dev, int function, int port)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
224662306a36Sopenharmony_ci	/* irrelevant if not infiniband */
224762306a36Sopenharmony_ci	if (priv->mfunc.master.qp0_state[port].proxy_qp0_active &&
224862306a36Sopenharmony_ci	    priv->mfunc.master.qp0_state[port].qp0_active)
224962306a36Sopenharmony_ci		return 1;
225062306a36Sopenharmony_ci	return 0;
225162306a36Sopenharmony_ci}
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ciint mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave,
225462306a36Sopenharmony_ci			   struct mlx4_vhcr *vhcr,
225562306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *inbox,
225662306a36Sopenharmony_ci			   struct mlx4_cmd_mailbox *outbox,
225762306a36Sopenharmony_ci			   struct mlx4_cmd_info *cmd)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
226062306a36Sopenharmony_ci	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
226162306a36Sopenharmony_ci	int err;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	if (port < 0)
226462306a36Sopenharmony_ci		return -EINVAL;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port))
226762306a36Sopenharmony_ci		return 0;
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) {
227062306a36Sopenharmony_ci		/* Enable port only if it was previously disabled */
227162306a36Sopenharmony_ci		if (!priv->mfunc.master.init_port_ref[port]) {
227262306a36Sopenharmony_ci			err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
227362306a36Sopenharmony_ci				       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
227462306a36Sopenharmony_ci			if (err)
227562306a36Sopenharmony_ci				return err;
227662306a36Sopenharmony_ci		}
227762306a36Sopenharmony_ci		priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
227862306a36Sopenharmony_ci	} else {
227962306a36Sopenharmony_ci		if (slave == mlx4_master_func_num(dev)) {
228062306a36Sopenharmony_ci			if (check_qp0_state(dev, slave, port) &&
228162306a36Sopenharmony_ci			    !priv->mfunc.master.qp0_state[port].port_active) {
228262306a36Sopenharmony_ci				err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
228362306a36Sopenharmony_ci					       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
228462306a36Sopenharmony_ci				if (err)
228562306a36Sopenharmony_ci					return err;
228662306a36Sopenharmony_ci				priv->mfunc.master.qp0_state[port].port_active = 1;
228762306a36Sopenharmony_ci				priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
228862306a36Sopenharmony_ci			}
228962306a36Sopenharmony_ci		} else
229062306a36Sopenharmony_ci			priv->mfunc.master.slave_state[slave].init_port_mask |= (1 << port);
229162306a36Sopenharmony_ci	}
229262306a36Sopenharmony_ci	++priv->mfunc.master.init_port_ref[port];
229362306a36Sopenharmony_ci	return 0;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ciint mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
229762306a36Sopenharmony_ci{
229862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
229962306a36Sopenharmony_ci	u32 *inbox;
230062306a36Sopenharmony_ci	int err;
230162306a36Sopenharmony_ci	u32 flags;
230262306a36Sopenharmony_ci	u16 field;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
230562306a36Sopenharmony_ci#define INIT_PORT_IN_SIZE          256
230662306a36Sopenharmony_ci#define INIT_PORT_FLAGS_OFFSET     0x00
230762306a36Sopenharmony_ci#define INIT_PORT_FLAG_SIG         (1 << 18)
230862306a36Sopenharmony_ci#define INIT_PORT_FLAG_NG          (1 << 17)
230962306a36Sopenharmony_ci#define INIT_PORT_FLAG_G0          (1 << 16)
231062306a36Sopenharmony_ci#define INIT_PORT_VL_SHIFT         4
231162306a36Sopenharmony_ci#define INIT_PORT_PORT_WIDTH_SHIFT 8
231262306a36Sopenharmony_ci#define INIT_PORT_MTU_OFFSET       0x04
231362306a36Sopenharmony_ci#define INIT_PORT_MAX_GID_OFFSET   0x06
231462306a36Sopenharmony_ci#define INIT_PORT_MAX_PKEY_OFFSET  0x0a
231562306a36Sopenharmony_ci#define INIT_PORT_GUID0_OFFSET     0x10
231662306a36Sopenharmony_ci#define INIT_PORT_NODE_GUID_OFFSET 0x18
231762306a36Sopenharmony_ci#define INIT_PORT_SI_GUID_OFFSET   0x20
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci		mailbox = mlx4_alloc_cmd_mailbox(dev);
232062306a36Sopenharmony_ci		if (IS_ERR(mailbox))
232162306a36Sopenharmony_ci			return PTR_ERR(mailbox);
232262306a36Sopenharmony_ci		inbox = mailbox->buf;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci		flags = 0;
232562306a36Sopenharmony_ci		flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT;
232662306a36Sopenharmony_ci		flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
232762306a36Sopenharmony_ci		MLX4_PUT(inbox, flags,		  INIT_PORT_FLAGS_OFFSET);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		field = 128 << dev->caps.ib_mtu_cap[port];
233062306a36Sopenharmony_ci		MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET);
233162306a36Sopenharmony_ci		field = dev->caps.gid_table_len[port];
233262306a36Sopenharmony_ci		MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET);
233362306a36Sopenharmony_ci		field = dev->caps.pkey_table_len[port];
233462306a36Sopenharmony_ci		MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci		err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT,
233762306a36Sopenharmony_ci			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci		mlx4_free_cmd_mailbox(dev, mailbox);
234062306a36Sopenharmony_ci	} else
234162306a36Sopenharmony_ci		err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
234262306a36Sopenharmony_ci			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	if (!err)
234562306a36Sopenharmony_ci		mlx4_hca_core_clock_update(dev);
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	return err;
234862306a36Sopenharmony_ci}
234962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_INIT_PORT);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ciint mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
235262306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
235362306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
235462306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
235562306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
235862306a36Sopenharmony_ci	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
235962306a36Sopenharmony_ci	int err;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci	if (port < 0)
236262306a36Sopenharmony_ci		return -EINVAL;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	if (!(priv->mfunc.master.slave_state[slave].init_port_mask &
236562306a36Sopenharmony_ci	    (1 << port)))
236662306a36Sopenharmony_ci		return 0;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) {
236962306a36Sopenharmony_ci		if (priv->mfunc.master.init_port_ref[port] == 1) {
237062306a36Sopenharmony_ci			err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
237162306a36Sopenharmony_ci				       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
237262306a36Sopenharmony_ci			if (err)
237362306a36Sopenharmony_ci				return err;
237462306a36Sopenharmony_ci		}
237562306a36Sopenharmony_ci		priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
237662306a36Sopenharmony_ci	} else {
237762306a36Sopenharmony_ci		/* infiniband port */
237862306a36Sopenharmony_ci		if (slave == mlx4_master_func_num(dev)) {
237962306a36Sopenharmony_ci			if (!priv->mfunc.master.qp0_state[port].qp0_active &&
238062306a36Sopenharmony_ci			    priv->mfunc.master.qp0_state[port].port_active) {
238162306a36Sopenharmony_ci				err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
238262306a36Sopenharmony_ci					       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
238362306a36Sopenharmony_ci				if (err)
238462306a36Sopenharmony_ci					return err;
238562306a36Sopenharmony_ci				priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
238662306a36Sopenharmony_ci				priv->mfunc.master.qp0_state[port].port_active = 0;
238762306a36Sopenharmony_ci			}
238862306a36Sopenharmony_ci		} else
238962306a36Sopenharmony_ci			priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci	--priv->mfunc.master.init_port_ref[port];
239262306a36Sopenharmony_ci	return 0;
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ciint mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port)
239662306a36Sopenharmony_ci{
239762306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
239862306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
239962306a36Sopenharmony_ci}
240062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ciint mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
240362306a36Sopenharmony_ci{
240462306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA,
240562306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
240662306a36Sopenharmony_ci}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_cistruct mlx4_config_dev {
240962306a36Sopenharmony_ci	__be32	update_flags;
241062306a36Sopenharmony_ci	__be32	rsvd1[3];
241162306a36Sopenharmony_ci	__be16	vxlan_udp_dport;
241262306a36Sopenharmony_ci	__be16	rsvd2;
241362306a36Sopenharmony_ci	__be16  roce_v2_entropy;
241462306a36Sopenharmony_ci	__be16  roce_v2_udp_dport;
241562306a36Sopenharmony_ci	__be32	roce_flags;
241662306a36Sopenharmony_ci	__be32	rsvd4[25];
241762306a36Sopenharmony_ci	__be16	rsvd5;
241862306a36Sopenharmony_ci	u8	rsvd6;
241962306a36Sopenharmony_ci	u8	rx_checksum_val;
242062306a36Sopenharmony_ci};
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci#define MLX4_VXLAN_UDP_DPORT (1 << 0)
242362306a36Sopenharmony_ci#define MLX4_ROCE_V2_UDP_DPORT BIT(3)
242462306a36Sopenharmony_ci#define MLX4_DISABLE_RX_PORT BIT(18)
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_cistatic int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
242762306a36Sopenharmony_ci{
242862306a36Sopenharmony_ci	int err;
242962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
243262306a36Sopenharmony_ci	if (IS_ERR(mailbox))
243362306a36Sopenharmony_ci		return PTR_ERR(mailbox);
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	memcpy(mailbox->buf, config_dev, sizeof(*config_dev));
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_CONFIG_DEV,
243862306a36Sopenharmony_ci		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
244162306a36Sopenharmony_ci	return err;
244262306a36Sopenharmony_ci}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_cistatic int mlx4_CONFIG_DEV_get(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
244562306a36Sopenharmony_ci{
244662306a36Sopenharmony_ci	int err;
244762306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
245062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
245162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 1, MLX4_CMD_CONFIG_DEV,
245462306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	if (!err)
245762306a36Sopenharmony_ci		memcpy(config_dev, mailbox->buf, sizeof(*config_dev));
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
246062306a36Sopenharmony_ci	return err;
246162306a36Sopenharmony_ci}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci/* Conversion between the HW values and the actual functionality.
246462306a36Sopenharmony_ci * The value represented by the array index,
246562306a36Sopenharmony_ci * and the functionality determined by the flags.
246662306a36Sopenharmony_ci */
246762306a36Sopenharmony_cistatic const u8 config_dev_csum_flags[] = {
246862306a36Sopenharmony_ci	[0] =	0,
246962306a36Sopenharmony_ci	[1] =	MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP,
247062306a36Sopenharmony_ci	[2] =	MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP	|
247162306a36Sopenharmony_ci		MLX4_RX_CSUM_MODE_L4,
247262306a36Sopenharmony_ci	[3] =	MLX4_RX_CSUM_MODE_L4			|
247362306a36Sopenharmony_ci		MLX4_RX_CSUM_MODE_IP_OK_IP_NON_TCP_UDP	|
247462306a36Sopenharmony_ci		MLX4_RX_CSUM_MODE_MULTI_VLAN
247562306a36Sopenharmony_ci};
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ciint mlx4_config_dev_retrieval(struct mlx4_dev *dev,
247862306a36Sopenharmony_ci			      struct mlx4_config_dev_params *params)
247962306a36Sopenharmony_ci{
248062306a36Sopenharmony_ci	struct mlx4_config_dev config_dev = {0};
248162306a36Sopenharmony_ci	int err;
248262306a36Sopenharmony_ci	u8 csum_mask;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci#define CONFIG_DEV_RX_CSUM_MODE_MASK			0x7
248562306a36Sopenharmony_ci#define CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET	0
248662306a36Sopenharmony_ci#define CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET	4
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_CONFIG_DEV))
248962306a36Sopenharmony_ci		return -EOPNOTSUPP;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	err = mlx4_CONFIG_DEV_get(dev, &config_dev);
249262306a36Sopenharmony_ci	if (err)
249362306a36Sopenharmony_ci		return err;
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT1_BIT_OFFSET) &
249662306a36Sopenharmony_ci			CONFIG_DEV_RX_CSUM_MODE_MASK;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (csum_mask >= ARRAY_SIZE(config_dev_csum_flags))
249962306a36Sopenharmony_ci		return -EINVAL;
250062306a36Sopenharmony_ci	params->rx_csum_flags_port_1 = config_dev_csum_flags[csum_mask];
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	csum_mask = (config_dev.rx_checksum_val >> CONFIG_DEV_RX_CSUM_MODE_PORT2_BIT_OFFSET) &
250362306a36Sopenharmony_ci			CONFIG_DEV_RX_CSUM_MODE_MASK;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	if (csum_mask >= ARRAY_SIZE(config_dev_csum_flags))
250662306a36Sopenharmony_ci		return -EINVAL;
250762306a36Sopenharmony_ci	params->rx_csum_flags_port_2 = config_dev_csum_flags[csum_mask];
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	params->vxlan_udp_dport = be16_to_cpu(config_dev.vxlan_udp_dport);
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	return 0;
251262306a36Sopenharmony_ci}
251362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_config_dev_retrieval);
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ciint mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	struct mlx4_config_dev config_dev;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	memset(&config_dev, 0, sizeof(config_dev));
252062306a36Sopenharmony_ci	config_dev.update_flags    = cpu_to_be32(MLX4_VXLAN_UDP_DPORT);
252162306a36Sopenharmony_ci	config_dev.vxlan_udp_dport = udp_port;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	return mlx4_CONFIG_DEV_set(dev, &config_dev);
252462306a36Sopenharmony_ci}
252562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci#define CONFIG_DISABLE_RX_PORT BIT(15)
252862306a36Sopenharmony_ciint mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	struct mlx4_config_dev config_dev;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	memset(&config_dev, 0, sizeof(config_dev));
253362306a36Sopenharmony_ci	config_dev.update_flags = cpu_to_be32(MLX4_DISABLE_RX_PORT);
253462306a36Sopenharmony_ci	if (dis)
253562306a36Sopenharmony_ci		config_dev.roce_flags =
253662306a36Sopenharmony_ci			cpu_to_be32(CONFIG_DISABLE_RX_PORT);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	return mlx4_CONFIG_DEV_set(dev, &config_dev);
253962306a36Sopenharmony_ci}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ciint mlx4_config_roce_v2_port(struct mlx4_dev *dev, u16 udp_port)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	struct mlx4_config_dev config_dev;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	memset(&config_dev, 0, sizeof(config_dev));
254662306a36Sopenharmony_ci	config_dev.update_flags    = cpu_to_be32(MLX4_ROCE_V2_UDP_DPORT);
254762306a36Sopenharmony_ci	config_dev.roce_v2_udp_dport = cpu_to_be16(udp_port);
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	return mlx4_CONFIG_DEV_set(dev, &config_dev);
255062306a36Sopenharmony_ci}
255162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_config_roce_v2_port);
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ciint mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2)
255462306a36Sopenharmony_ci{
255562306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
255662306a36Sopenharmony_ci	struct {
255762306a36Sopenharmony_ci		__be32 v_port1;
255862306a36Sopenharmony_ci		__be32 v_port2;
255962306a36Sopenharmony_ci	} *v2p;
256062306a36Sopenharmony_ci	int err;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
256362306a36Sopenharmony_ci	if (IS_ERR(mailbox))
256462306a36Sopenharmony_ci		return -ENOMEM;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	v2p = mailbox->buf;
256762306a36Sopenharmony_ci	v2p->v_port1 = cpu_to_be32(port1);
256862306a36Sopenharmony_ci	v2p->v_port2 = cpu_to_be32(port2);
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, 0,
257162306a36Sopenharmony_ci		       MLX4_SET_PORT_VIRT2PHY, MLX4_CMD_VIRT_PORT_MAP,
257262306a36Sopenharmony_ci		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
257562306a36Sopenharmony_ci	return err;
257662306a36Sopenharmony_ci}
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ciint mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
258262306a36Sopenharmony_ci			       MLX4_CMD_SET_ICM_SIZE,
258362306a36Sopenharmony_ci			       MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
258462306a36Sopenharmony_ci	if (ret)
258562306a36Sopenharmony_ci		return ret;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	/*
258862306a36Sopenharmony_ci	 * Round up number of system pages needed in case
258962306a36Sopenharmony_ci	 * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
259062306a36Sopenharmony_ci	 */
259162306a36Sopenharmony_ci	*aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
259262306a36Sopenharmony_ci		(PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	return 0;
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ciint mlx4_NOP(struct mlx4_dev *dev)
259862306a36Sopenharmony_ci{
259962306a36Sopenharmony_ci	/* Input modifier of 0x1f means "finish as soon as possible." */
260062306a36Sopenharmony_ci	return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A,
260162306a36Sopenharmony_ci			MLX4_CMD_NATIVE);
260262306a36Sopenharmony_ci}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ciint mlx4_query_diag_counters(struct mlx4_dev *dev, u8 op_modifier,
260562306a36Sopenharmony_ci			     const u32 offset[],
260662306a36Sopenharmony_ci			     u32 value[], size_t array_len, u8 port)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
260962306a36Sopenharmony_ci	u32 *outbox;
261062306a36Sopenharmony_ci	size_t i;
261162306a36Sopenharmony_ci	int ret;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
261462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
261562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	outbox = mailbox->buf;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	ret = mlx4_cmd_box(dev, 0, mailbox->dma, port, op_modifier,
262062306a36Sopenharmony_ci			   MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A,
262162306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
262262306a36Sopenharmony_ci	if (ret)
262362306a36Sopenharmony_ci		goto out;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	for (i = 0; i < array_len; i++) {
262662306a36Sopenharmony_ci		if (offset[i] > MLX4_MAILBOX_SIZE) {
262762306a36Sopenharmony_ci			ret = -EINVAL;
262862306a36Sopenharmony_ci			goto out;
262962306a36Sopenharmony_ci		}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci		MLX4_GET(value[i], outbox, offset[i]);
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ciout:
263562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
263662306a36Sopenharmony_ci	return ret;
263762306a36Sopenharmony_ci}
263862306a36Sopenharmony_ciEXPORT_SYMBOL(mlx4_query_diag_counters);
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ciint mlx4_get_phys_port_id(struct mlx4_dev *dev)
264162306a36Sopenharmony_ci{
264262306a36Sopenharmony_ci	u8 port;
264362306a36Sopenharmony_ci	u32 *outbox;
264462306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
264562306a36Sopenharmony_ci	u32 in_mod;
264662306a36Sopenharmony_ci	u32 guid_hi, guid_lo;
264762306a36Sopenharmony_ci	int err, ret = 0;
264862306a36Sopenharmony_ci#define MOD_STAT_CFG_PORT_OFFSET 8
264962306a36Sopenharmony_ci#define MOD_STAT_CFG_GUID_H	 0X14
265062306a36Sopenharmony_ci#define MOD_STAT_CFG_GUID_L	 0X1c
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
265362306a36Sopenharmony_ci	if (IS_ERR(mailbox))
265462306a36Sopenharmony_ci		return PTR_ERR(mailbox);
265562306a36Sopenharmony_ci	outbox = mailbox->buf;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	for (port = 1; port <= dev->caps.num_ports; port++) {
265862306a36Sopenharmony_ci		in_mod = port << MOD_STAT_CFG_PORT_OFFSET;
265962306a36Sopenharmony_ci		err = mlx4_cmd_box(dev, 0, mailbox->dma, in_mod, 0x2,
266062306a36Sopenharmony_ci				   MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A,
266162306a36Sopenharmony_ci				   MLX4_CMD_NATIVE);
266262306a36Sopenharmony_ci		if (err) {
266362306a36Sopenharmony_ci			mlx4_err(dev, "Fail to get port %d uplink guid\n",
266462306a36Sopenharmony_ci				 port);
266562306a36Sopenharmony_ci			ret = err;
266662306a36Sopenharmony_ci		} else {
266762306a36Sopenharmony_ci			MLX4_GET(guid_hi, outbox, MOD_STAT_CFG_GUID_H);
266862306a36Sopenharmony_ci			MLX4_GET(guid_lo, outbox, MOD_STAT_CFG_GUID_L);
266962306a36Sopenharmony_ci			dev->caps.phys_port_id[port] = (u64)guid_lo |
267062306a36Sopenharmony_ci						       (u64)guid_hi << 32;
267162306a36Sopenharmony_ci		}
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
267462306a36Sopenharmony_ci	return ret;
267562306a36Sopenharmony_ci}
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci#define MLX4_WOL_SETUP_MODE (5 << 28)
267862306a36Sopenharmony_ciint mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port)
267962306a36Sopenharmony_ci{
268062306a36Sopenharmony_ci	u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3,
268362306a36Sopenharmony_ci			    MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A,
268462306a36Sopenharmony_ci			    MLX4_CMD_NATIVE);
268562306a36Sopenharmony_ci}
268662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_wol_read);
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ciint mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port)
268962306a36Sopenharmony_ci{
269062306a36Sopenharmony_ci	u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG,
269362306a36Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
269462306a36Sopenharmony_ci}
269562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_wol_write);
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_cienum {
269862306a36Sopenharmony_ci	ADD_TO_MCG = 0x26,
269962306a36Sopenharmony_ci};
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_civoid mlx4_opreq_action(struct work_struct *work)
270362306a36Sopenharmony_ci{
270462306a36Sopenharmony_ci	struct mlx4_priv *priv = container_of(work, struct mlx4_priv,
270562306a36Sopenharmony_ci					      opreq_task);
270662306a36Sopenharmony_ci	struct mlx4_dev *dev = &priv->dev;
270762306a36Sopenharmony_ci	int num_tasks = atomic_read(&priv->opreq_count);
270862306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
270962306a36Sopenharmony_ci	struct mlx4_mgm *mgm;
271062306a36Sopenharmony_ci	u32 *outbox;
271162306a36Sopenharmony_ci	u32 modifier;
271262306a36Sopenharmony_ci	u16 token;
271362306a36Sopenharmony_ci	u16 type;
271462306a36Sopenharmony_ci	int err;
271562306a36Sopenharmony_ci	u32 num_qps;
271662306a36Sopenharmony_ci	struct mlx4_qp qp;
271762306a36Sopenharmony_ci	int i;
271862306a36Sopenharmony_ci	u8 rem_mcg;
271962306a36Sopenharmony_ci	u8 prot;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci#define GET_OP_REQ_MODIFIER_OFFSET	0x08
272262306a36Sopenharmony_ci#define GET_OP_REQ_TOKEN_OFFSET		0x14
272362306a36Sopenharmony_ci#define GET_OP_REQ_TYPE_OFFSET		0x1a
272462306a36Sopenharmony_ci#define GET_OP_REQ_DATA_OFFSET		0x20
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
272762306a36Sopenharmony_ci	if (IS_ERR(mailbox)) {
272862306a36Sopenharmony_ci		mlx4_err(dev, "Failed to allocate mailbox for GET_OP_REQ\n");
272962306a36Sopenharmony_ci		return;
273062306a36Sopenharmony_ci	}
273162306a36Sopenharmony_ci	outbox = mailbox->buf;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	while (num_tasks) {
273462306a36Sopenharmony_ci		err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
273562306a36Sopenharmony_ci				   MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
273662306a36Sopenharmony_ci				   MLX4_CMD_NATIVE);
273762306a36Sopenharmony_ci		if (err) {
273862306a36Sopenharmony_ci			mlx4_err(dev, "Failed to retrieve required operation: %d\n",
273962306a36Sopenharmony_ci				 err);
274062306a36Sopenharmony_ci			goto out;
274162306a36Sopenharmony_ci		}
274262306a36Sopenharmony_ci		MLX4_GET(modifier, outbox, GET_OP_REQ_MODIFIER_OFFSET);
274362306a36Sopenharmony_ci		MLX4_GET(token, outbox, GET_OP_REQ_TOKEN_OFFSET);
274462306a36Sopenharmony_ci		MLX4_GET(type, outbox, GET_OP_REQ_TYPE_OFFSET);
274562306a36Sopenharmony_ci		type &= 0xfff;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci		switch (type) {
274862306a36Sopenharmony_ci		case ADD_TO_MCG:
274962306a36Sopenharmony_ci			if (dev->caps.steering_mode ==
275062306a36Sopenharmony_ci			    MLX4_STEERING_MODE_DEVICE_MANAGED) {
275162306a36Sopenharmony_ci				mlx4_warn(dev, "ADD MCG operation is not supported in DEVICE_MANAGED steering mode\n");
275262306a36Sopenharmony_ci				err = EPERM;
275362306a36Sopenharmony_ci				break;
275462306a36Sopenharmony_ci			}
275562306a36Sopenharmony_ci			mgm = (struct mlx4_mgm *)((u8 *)(outbox) +
275662306a36Sopenharmony_ci						  GET_OP_REQ_DATA_OFFSET);
275762306a36Sopenharmony_ci			num_qps = be32_to_cpu(mgm->members_count) &
275862306a36Sopenharmony_ci				  MGM_QPN_MASK;
275962306a36Sopenharmony_ci			rem_mcg = ((u8 *)(&mgm->members_count))[0] & 1;
276062306a36Sopenharmony_ci			prot = ((u8 *)(&mgm->members_count))[0] >> 6;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci			for (i = 0; i < num_qps; i++) {
276362306a36Sopenharmony_ci				qp.qpn = be32_to_cpu(mgm->qp[i]);
276462306a36Sopenharmony_ci				if (rem_mcg)
276562306a36Sopenharmony_ci					err = mlx4_multicast_detach(dev, &qp,
276662306a36Sopenharmony_ci								    mgm->gid,
276762306a36Sopenharmony_ci								    prot, 0);
276862306a36Sopenharmony_ci				else
276962306a36Sopenharmony_ci					err = mlx4_multicast_attach(dev, &qp,
277062306a36Sopenharmony_ci								    mgm->gid,
277162306a36Sopenharmony_ci								    mgm->gid[5]
277262306a36Sopenharmony_ci								    , 0, prot,
277362306a36Sopenharmony_ci								    NULL);
277462306a36Sopenharmony_ci				if (err)
277562306a36Sopenharmony_ci					break;
277662306a36Sopenharmony_ci			}
277762306a36Sopenharmony_ci			break;
277862306a36Sopenharmony_ci		default:
277962306a36Sopenharmony_ci			mlx4_warn(dev, "Bad type for required operation\n");
278062306a36Sopenharmony_ci			err = EINVAL;
278162306a36Sopenharmony_ci			break;
278262306a36Sopenharmony_ci		}
278362306a36Sopenharmony_ci		err = mlx4_cmd(dev, 0, ((u32) err |
278462306a36Sopenharmony_ci					(__force u32)cpu_to_be32(token) << 16),
278562306a36Sopenharmony_ci			       1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
278662306a36Sopenharmony_ci			       MLX4_CMD_NATIVE);
278762306a36Sopenharmony_ci		if (err) {
278862306a36Sopenharmony_ci			mlx4_err(dev, "Failed to acknowledge required request: %d\n",
278962306a36Sopenharmony_ci				 err);
279062306a36Sopenharmony_ci			goto out;
279162306a36Sopenharmony_ci		}
279262306a36Sopenharmony_ci		memset(outbox, 0, 0xffc);
279362306a36Sopenharmony_ci		num_tasks = atomic_dec_return(&priv->opreq_count);
279462306a36Sopenharmony_ci	}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ciout:
279762306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
279862306a36Sopenharmony_ci}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_cistatic int mlx4_check_smp_firewall_active(struct mlx4_dev *dev,
280162306a36Sopenharmony_ci					  struct mlx4_cmd_mailbox *mailbox)
280262306a36Sopenharmony_ci{
280362306a36Sopenharmony_ci#define MLX4_CMD_MAD_DEMUX_SET_ATTR_OFFSET		0x10
280462306a36Sopenharmony_ci#define MLX4_CMD_MAD_DEMUX_GETRESP_ATTR_OFFSET		0x20
280562306a36Sopenharmony_ci#define MLX4_CMD_MAD_DEMUX_TRAP_ATTR_OFFSET		0x40
280662306a36Sopenharmony_ci#define MLX4_CMD_MAD_DEMUX_TRAP_REPRESS_ATTR_OFFSET	0x70
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	u32 set_attr_mask, getresp_attr_mask;
280962306a36Sopenharmony_ci	u32 trap_attr_mask, traprepress_attr_mask;
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	MLX4_GET(set_attr_mask, mailbox->buf,
281262306a36Sopenharmony_ci		 MLX4_CMD_MAD_DEMUX_SET_ATTR_OFFSET);
281362306a36Sopenharmony_ci	mlx4_dbg(dev, "SMP firewall set_attribute_mask = 0x%x\n",
281462306a36Sopenharmony_ci		 set_attr_mask);
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	MLX4_GET(getresp_attr_mask, mailbox->buf,
281762306a36Sopenharmony_ci		 MLX4_CMD_MAD_DEMUX_GETRESP_ATTR_OFFSET);
281862306a36Sopenharmony_ci	mlx4_dbg(dev, "SMP firewall getresp_attribute_mask = 0x%x\n",
281962306a36Sopenharmony_ci		 getresp_attr_mask);
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	MLX4_GET(trap_attr_mask, mailbox->buf,
282262306a36Sopenharmony_ci		 MLX4_CMD_MAD_DEMUX_TRAP_ATTR_OFFSET);
282362306a36Sopenharmony_ci	mlx4_dbg(dev, "SMP firewall trap_attribute_mask = 0x%x\n",
282462306a36Sopenharmony_ci		 trap_attr_mask);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	MLX4_GET(traprepress_attr_mask, mailbox->buf,
282762306a36Sopenharmony_ci		 MLX4_CMD_MAD_DEMUX_TRAP_REPRESS_ATTR_OFFSET);
282862306a36Sopenharmony_ci	mlx4_dbg(dev, "SMP firewall traprepress_attribute_mask = 0x%x\n",
282962306a36Sopenharmony_ci		 traprepress_attr_mask);
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (set_attr_mask && getresp_attr_mask && trap_attr_mask &&
283262306a36Sopenharmony_ci	    traprepress_attr_mask)
283362306a36Sopenharmony_ci		return 1;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return 0;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ciint mlx4_config_mad_demux(struct mlx4_dev *dev)
283962306a36Sopenharmony_ci{
284062306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
284162306a36Sopenharmony_ci	int err;
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	/* Check if mad_demux is supported */
284462306a36Sopenharmony_ci	if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_MAD_DEMUX))
284562306a36Sopenharmony_ci		return 0;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
284862306a36Sopenharmony_ci	if (IS_ERR(mailbox)) {
284962306a36Sopenharmony_ci		mlx4_warn(dev, "Failed to allocate mailbox for cmd MAD_DEMUX");
285062306a36Sopenharmony_ci		return -ENOMEM;
285162306a36Sopenharmony_ci	}
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	/* Query mad_demux to find out which MADs are handled by internal sma */
285462306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, 0, mailbox->dma, 0x01 /* subn mgmt class */,
285562306a36Sopenharmony_ci			   MLX4_CMD_MAD_DEMUX_QUERY_RESTR, MLX4_CMD_MAD_DEMUX,
285662306a36Sopenharmony_ci			   MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
285762306a36Sopenharmony_ci	if (err) {
285862306a36Sopenharmony_ci		mlx4_warn(dev, "MLX4_CMD_MAD_DEMUX: query restrictions failed (%d)\n",
285962306a36Sopenharmony_ci			  err);
286062306a36Sopenharmony_ci		goto out;
286162306a36Sopenharmony_ci	}
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	if (mlx4_check_smp_firewall_active(dev, mailbox))
286462306a36Sopenharmony_ci		dev->flags |= MLX4_FLAG_SECURE_HOST;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	/* Config mad_demux to handle all MADs returned by the query above */
286762306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, 0x01 /* subn mgmt class */,
286862306a36Sopenharmony_ci		       MLX4_CMD_MAD_DEMUX_CONFIG, MLX4_CMD_MAD_DEMUX,
286962306a36Sopenharmony_ci		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
287062306a36Sopenharmony_ci	if (err) {
287162306a36Sopenharmony_ci		mlx4_warn(dev, "MLX4_CMD_MAD_DEMUX: configure failed (%d)\n", err);
287262306a36Sopenharmony_ci		goto out;
287362306a36Sopenharmony_ci	}
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci	if (dev->flags & MLX4_FLAG_SECURE_HOST)
287662306a36Sopenharmony_ci		mlx4_warn(dev, "HCA operating in secure-host mode. SMP firewall activated.\n");
287762306a36Sopenharmony_ciout:
287862306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
287962306a36Sopenharmony_ci	return err;
288062306a36Sopenharmony_ci}
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci/* Access Reg commands */
288362306a36Sopenharmony_cienum mlx4_access_reg_masks {
288462306a36Sopenharmony_ci	MLX4_ACCESS_REG_STATUS_MASK = 0x7f,
288562306a36Sopenharmony_ci	MLX4_ACCESS_REG_METHOD_MASK = 0x7f,
288662306a36Sopenharmony_ci	MLX4_ACCESS_REG_LEN_MASK = 0x7ff
288762306a36Sopenharmony_ci};
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_cistruct mlx4_access_reg {
289062306a36Sopenharmony_ci	__be16 constant1;
289162306a36Sopenharmony_ci	u8 status;
289262306a36Sopenharmony_ci	u8 resrvd1;
289362306a36Sopenharmony_ci	__be16 reg_id;
289462306a36Sopenharmony_ci	u8 method;
289562306a36Sopenharmony_ci	u8 constant2;
289662306a36Sopenharmony_ci	__be32 resrvd2[2];
289762306a36Sopenharmony_ci	__be16 len_const;
289862306a36Sopenharmony_ci	__be16 resrvd3;
289962306a36Sopenharmony_ci#define MLX4_ACCESS_REG_HEADER_SIZE (20)
290062306a36Sopenharmony_ci	u8 reg_data[MLX4_MAILBOX_SIZE-MLX4_ACCESS_REG_HEADER_SIZE];
290162306a36Sopenharmony_ci} __attribute__((__packed__));
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci/**
290462306a36Sopenharmony_ci * mlx4_ACCESS_REG - Generic access reg command.
290562306a36Sopenharmony_ci * @dev: mlx4_dev.
290662306a36Sopenharmony_ci * @reg_id: register ID to access.
290762306a36Sopenharmony_ci * @method: Access method Read/Write.
290862306a36Sopenharmony_ci * @reg_len: register length to Read/Write in bytes.
290962306a36Sopenharmony_ci * @reg_data: reg_data pointer to Read/Write From/To.
291062306a36Sopenharmony_ci *
291162306a36Sopenharmony_ci * Access ConnectX registers FW command.
291262306a36Sopenharmony_ci * Returns 0 on success and copies outbox mlx4_access_reg data
291362306a36Sopenharmony_ci * field into reg_data or a negative error code.
291462306a36Sopenharmony_ci */
291562306a36Sopenharmony_cistatic int mlx4_ACCESS_REG(struct mlx4_dev *dev, u16 reg_id,
291662306a36Sopenharmony_ci			   enum mlx4_access_reg_method method,
291762306a36Sopenharmony_ci			   u16 reg_len, void *reg_data)
291862306a36Sopenharmony_ci{
291962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *inbox, *outbox;
292062306a36Sopenharmony_ci	struct mlx4_access_reg *inbuf, *outbuf;
292162306a36Sopenharmony_ci	int err;
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	inbox = mlx4_alloc_cmd_mailbox(dev);
292462306a36Sopenharmony_ci	if (IS_ERR(inbox))
292562306a36Sopenharmony_ci		return PTR_ERR(inbox);
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	outbox = mlx4_alloc_cmd_mailbox(dev);
292862306a36Sopenharmony_ci	if (IS_ERR(outbox)) {
292962306a36Sopenharmony_ci		mlx4_free_cmd_mailbox(dev, inbox);
293062306a36Sopenharmony_ci		return PTR_ERR(outbox);
293162306a36Sopenharmony_ci	}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	inbuf = inbox->buf;
293462306a36Sopenharmony_ci	outbuf = outbox->buf;
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	inbuf->constant1 = cpu_to_be16(0x1<<11 | 0x4);
293762306a36Sopenharmony_ci	inbuf->constant2 = 0x1;
293862306a36Sopenharmony_ci	inbuf->reg_id = cpu_to_be16(reg_id);
293962306a36Sopenharmony_ci	inbuf->method = method & MLX4_ACCESS_REG_METHOD_MASK;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	reg_len = min(reg_len, (u16)(sizeof(inbuf->reg_data)));
294262306a36Sopenharmony_ci	inbuf->len_const =
294362306a36Sopenharmony_ci		cpu_to_be16(((reg_len/4 + 1) & MLX4_ACCESS_REG_LEN_MASK) |
294462306a36Sopenharmony_ci			    ((0x3) << 12));
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	memcpy(inbuf->reg_data, reg_data, reg_len);
294762306a36Sopenharmony_ci	err = mlx4_cmd_box(dev, inbox->dma, outbox->dma, 0, 0,
294862306a36Sopenharmony_ci			   MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
294962306a36Sopenharmony_ci			   MLX4_CMD_WRAPPED);
295062306a36Sopenharmony_ci	if (err)
295162306a36Sopenharmony_ci		goto out;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	if (outbuf->status & MLX4_ACCESS_REG_STATUS_MASK) {
295462306a36Sopenharmony_ci		err = outbuf->status & MLX4_ACCESS_REG_STATUS_MASK;
295562306a36Sopenharmony_ci		mlx4_err(dev,
295662306a36Sopenharmony_ci			 "MLX4_CMD_ACCESS_REG(%x) returned REG status (%x)\n",
295762306a36Sopenharmony_ci			 reg_id, err);
295862306a36Sopenharmony_ci		goto out;
295962306a36Sopenharmony_ci	}
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	memcpy(reg_data, outbuf->reg_data, reg_len);
296262306a36Sopenharmony_ciout:
296362306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, inbox);
296462306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, outbox);
296562306a36Sopenharmony_ci	return err;
296662306a36Sopenharmony_ci}
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci/* ConnectX registers IDs */
296962306a36Sopenharmony_cienum mlx4_reg_id {
297062306a36Sopenharmony_ci	MLX4_REG_ID_PTYS = 0x5004,
297162306a36Sopenharmony_ci};
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci/**
297462306a36Sopenharmony_ci * mlx4_ACCESS_PTYS_REG - Access PTYs (Port Type and Speed)
297562306a36Sopenharmony_ci * register
297662306a36Sopenharmony_ci * @dev: mlx4_dev.
297762306a36Sopenharmony_ci * @method: Access method Read/Write.
297862306a36Sopenharmony_ci * @ptys_reg: PTYS register data pointer.
297962306a36Sopenharmony_ci *
298062306a36Sopenharmony_ci * Access ConnectX PTYS register, to Read/Write Port Type/Speed
298162306a36Sopenharmony_ci * configuration
298262306a36Sopenharmony_ci * Returns 0 on success or a negative error code.
298362306a36Sopenharmony_ci */
298462306a36Sopenharmony_ciint mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev,
298562306a36Sopenharmony_ci			 enum mlx4_access_reg_method method,
298662306a36Sopenharmony_ci			 struct mlx4_ptys_reg *ptys_reg)
298762306a36Sopenharmony_ci{
298862306a36Sopenharmony_ci	return mlx4_ACCESS_REG(dev, MLX4_REG_ID_PTYS,
298962306a36Sopenharmony_ci			       method, sizeof(*ptys_reg), ptys_reg);
299062306a36Sopenharmony_ci}
299162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_ACCESS_PTYS_REG);
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ciint mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave,
299462306a36Sopenharmony_ci			    struct mlx4_vhcr *vhcr,
299562306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *inbox,
299662306a36Sopenharmony_ci			    struct mlx4_cmd_mailbox *outbox,
299762306a36Sopenharmony_ci			    struct mlx4_cmd_info *cmd)
299862306a36Sopenharmony_ci{
299962306a36Sopenharmony_ci	struct mlx4_access_reg *inbuf = inbox->buf;
300062306a36Sopenharmony_ci	u8 method = inbuf->method & MLX4_ACCESS_REG_METHOD_MASK;
300162306a36Sopenharmony_ci	u16 reg_id = be16_to_cpu(inbuf->reg_id);
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	if (slave != mlx4_master_func_num(dev) &&
300462306a36Sopenharmony_ci	    method == MLX4_ACCESS_REG_WRITE)
300562306a36Sopenharmony_ci		return -EPERM;
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	if (reg_id == MLX4_REG_ID_PTYS) {
300862306a36Sopenharmony_ci		struct mlx4_ptys_reg *ptys_reg =
300962306a36Sopenharmony_ci			(struct mlx4_ptys_reg *)inbuf->reg_data;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		ptys_reg->local_port =
301262306a36Sopenharmony_ci			mlx4_slave_convert_port(dev, slave,
301362306a36Sopenharmony_ci						ptys_reg->local_port);
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	return mlx4_cmd_box(dev, inbox->dma, outbox->dma, vhcr->in_modifier,
301762306a36Sopenharmony_ci			    0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C,
301862306a36Sopenharmony_ci			    MLX4_CMD_NATIVE);
301962306a36Sopenharmony_ci}
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_cistatic int mlx4_SET_PORT_phv_bit(struct mlx4_dev *dev, u8 port, u8 phv_bit)
302262306a36Sopenharmony_ci{
302362306a36Sopenharmony_ci#define SET_PORT_GEN_PHV_VALID	0x10
302462306a36Sopenharmony_ci#define SET_PORT_GEN_PHV_EN	0x80
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
302762306a36Sopenharmony_ci	struct mlx4_set_port_general_context *context;
302862306a36Sopenharmony_ci	u32 in_mod;
302962306a36Sopenharmony_ci	int err;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
303262306a36Sopenharmony_ci	if (IS_ERR(mailbox))
303362306a36Sopenharmony_ci		return PTR_ERR(mailbox);
303462306a36Sopenharmony_ci	context = mailbox->buf;
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	context->flags2 |=  SET_PORT_GEN_PHV_VALID;
303762306a36Sopenharmony_ci	if (phv_bit)
303862306a36Sopenharmony_ci		context->phv_en |=  SET_PORT_GEN_PHV_EN;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
304162306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
304262306a36Sopenharmony_ci		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
304362306a36Sopenharmony_ci		       MLX4_CMD_NATIVE);
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
304662306a36Sopenharmony_ci	return err;
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ciint get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv)
305062306a36Sopenharmony_ci{
305162306a36Sopenharmony_ci	int err;
305262306a36Sopenharmony_ci	struct mlx4_func_cap func_cap;
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci	memset(&func_cap, 0, sizeof(func_cap));
305562306a36Sopenharmony_ci	err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap);
305662306a36Sopenharmony_ci	if (!err)
305762306a36Sopenharmony_ci		*phv = func_cap.flags0 & QUERY_FUNC_CAP_PHV_BIT;
305862306a36Sopenharmony_ci	return err;
305962306a36Sopenharmony_ci}
306062306a36Sopenharmony_ciEXPORT_SYMBOL(get_phv_bit);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ciint set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val)
306362306a36Sopenharmony_ci{
306462306a36Sopenharmony_ci	int ret;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	if (mlx4_is_slave(dev))
306762306a36Sopenharmony_ci		return -EPERM;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN &&
307062306a36Sopenharmony_ci	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) {
307162306a36Sopenharmony_ci		ret = mlx4_SET_PORT_phv_bit(dev, port, new_val);
307262306a36Sopenharmony_ci		if (!ret)
307362306a36Sopenharmony_ci			dev->caps.phv_bit[port] = new_val;
307462306a36Sopenharmony_ci		return ret;
307562306a36Sopenharmony_ci	}
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	return -EOPNOTSUPP;
307862306a36Sopenharmony_ci}
307962306a36Sopenharmony_ciEXPORT_SYMBOL(set_phv_bit);
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ciint mlx4_get_is_vlan_offload_disabled(struct mlx4_dev *dev, u8 port,
308262306a36Sopenharmony_ci				      bool *vlan_offload_disabled)
308362306a36Sopenharmony_ci{
308462306a36Sopenharmony_ci	struct mlx4_func_cap func_cap;
308562306a36Sopenharmony_ci	int err;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci	memset(&func_cap, 0, sizeof(func_cap));
308862306a36Sopenharmony_ci	err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap);
308962306a36Sopenharmony_ci	if (!err)
309062306a36Sopenharmony_ci		*vlan_offload_disabled =
309162306a36Sopenharmony_ci			!!(func_cap.flags0 &
309262306a36Sopenharmony_ci			   QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE);
309362306a36Sopenharmony_ci	return err;
309462306a36Sopenharmony_ci}
309562306a36Sopenharmony_ciEXPORT_SYMBOL(mlx4_get_is_vlan_offload_disabled);
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_civoid mlx4_replace_zero_macs(struct mlx4_dev *dev)
309862306a36Sopenharmony_ci{
309962306a36Sopenharmony_ci	int i;
310062306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	dev->port_random_macs = 0;
310362306a36Sopenharmony_ci	for (i = 1; i <= dev->caps.num_ports; ++i)
310462306a36Sopenharmony_ci		if (!dev->caps.def_mac[i] &&
310562306a36Sopenharmony_ci		    dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) {
310662306a36Sopenharmony_ci			eth_random_addr(mac_addr);
310762306a36Sopenharmony_ci			dev->port_random_macs |= 1 << i;
310862306a36Sopenharmony_ci			dev->caps.def_mac[i] = ether_addr_to_u64(mac_addr);
310962306a36Sopenharmony_ci		}
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_replace_zero_macs);
3112