|
@@ -158,7 +158,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
|
|
|
[31] = "Modifying loopback source checks using UPDATE_QP support",
|
|
|
[32] = "Loopback source checks support",
|
|
|
[33] = "RoCEv2 support",
|
|
|
- [34] = "DMFS Sniffer support (UC & MC)"
|
|
|
+ [34] = "DMFS Sniffer support (UC & MC)",
|
|
|
+ [35] = "QinQ VST mode support",
|
|
|
};
|
|
|
int i;
|
|
|
|
|
@@ -248,6 +249,72 @@ out:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int mlx4_activate_vst_qinq(struct mlx4_priv *priv, int slave, int port)
|
|
|
+{
|
|
|
+ struct mlx4_vport_oper_state *vp_oper;
|
|
|
+ struct mlx4_vport_state *vp_admin;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
|
|
|
+ vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+
|
|
|
+ if (vp_admin->default_vlan != vp_oper->state.default_vlan) {
|
|
|
+ err = __mlx4_register_vlan(&priv->dev, port,
|
|
|
+ vp_admin->default_vlan,
|
|
|
+ &vp_oper->vlan_idx);
|
|
|
+ if (err) {
|
|
|
+ vp_oper->vlan_idx = NO_INDX;
|
|
|
+ mlx4_warn(&priv->dev,
|
|
|
+ "No vlan resources slave %d, port %d\n",
|
|
|
+ slave, port);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ mlx4_dbg(&priv->dev, "alloc vlan %d idx %d slave %d port %d\n",
|
|
|
+ (int)(vp_oper->state.default_vlan),
|
|
|
+ vp_oper->vlan_idx, slave, port);
|
|
|
+ }
|
|
|
+ vp_oper->state.vlan_proto = vp_admin->vlan_proto;
|
|
|
+ vp_oper->state.default_vlan = vp_admin->default_vlan;
|
|
|
+ vp_oper->state.default_qos = vp_admin->default_qos;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mlx4_handle_vst_qinq(struct mlx4_priv *priv, int slave, int port)
|
|
|
+{
|
|
|
+ struct mlx4_vport_oper_state *vp_oper;
|
|
|
+ struct mlx4_slave_state *slave_state;
|
|
|
+ struct mlx4_vport_state *vp_admin;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
|
|
|
+ vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
|
|
|
+ slave_state = &priv->mfunc.master.slave_state[slave];
|
|
|
+
|
|
|
+ if ((vp_admin->vlan_proto != htons(ETH_P_8021AD)) ||
|
|
|
+ (!slave_state->active))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (vp_oper->state.vlan_proto == vp_admin->vlan_proto &&
|
|
|
+ vp_oper->state.default_vlan == vp_admin->default_vlan &&
|
|
|
+ vp_oper->state.default_qos == vp_admin->default_qos)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (!slave_state->vst_qinq_supported) {
|
|
|
+ /* Warn and revert the request to set vst QinQ mode */
|
|
|
+ vp_admin->vlan_proto = vp_oper->state.vlan_proto;
|
|
|
+ vp_admin->default_vlan = vp_oper->state.default_vlan;
|
|
|
+ vp_admin->default_qos = vp_oper->state.default_qos;
|
|
|
+
|
|
|
+ mlx4_warn(&priv->dev,
|
|
|
+ "Slave %d does not support VST QinQ mode\n", slave);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = mlx4_activate_vst_qinq(priv, slave, port);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|
|
struct mlx4_vhcr *vhcr,
|
|
|
struct mlx4_cmd_mailbox *inbox,
|
|
@@ -311,14 +378,18 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|
|
#define QUERY_FUNC_CAP_VF_ENABLE_QP0 0x08
|
|
|
|
|
|
#define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
|
|
|
-#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31)
|
|
|
#define QUERY_FUNC_CAP_PHV_BIT 0x40
|
|
|
+#define QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE 0x20
|
|
|
+
|
|
|
+#define QUERY_FUNC_CAP_SUPPORTS_VST_QINQ BIT(30)
|
|
|
+#define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS BIT(31)
|
|
|
|
|
|
if (vhcr->op_modifier == 1) {
|
|
|
struct mlx4_active_ports actv_ports =
|
|
|
mlx4_get_active_ports(dev, slave);
|
|
|
int converted_port = mlx4_slave_convert_port(
|
|
|
dev, slave, vhcr->in_modifier);
|
|
|
+ struct mlx4_vport_oper_state *vp_oper;
|
|
|
|
|
|
if (converted_port < 0)
|
|
|
return -EINVAL;
|
|
@@ -357,15 +428,24 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|
|
MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier],
|
|
|
QUERY_FUNC_CAP_PHYS_PORT_ID);
|
|
|
|
|
|
- if (dev->caps.phv_bit[port]) {
|
|
|
- field = QUERY_FUNC_CAP_PHV_BIT;
|
|
|
- MLX4_PUT(outbox->buf, field,
|
|
|
- QUERY_FUNC_CAP_FLAGS0_OFFSET);
|
|
|
- }
|
|
|
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
|
|
|
+ err = mlx4_handle_vst_qinq(priv, slave, port);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ field = 0;
|
|
|
+ if (dev->caps.phv_bit[port])
|
|
|
+ field |= QUERY_FUNC_CAP_PHV_BIT;
|
|
|
+ if (vp_oper->state.vlan_proto == htons(ETH_P_8021AD))
|
|
|
+ field |= QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE;
|
|
|
+ MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS0_OFFSET);
|
|
|
|
|
|
} else if (vhcr->op_modifier == 0) {
|
|
|
struct mlx4_active_ports actv_ports =
|
|
|
mlx4_get_active_ports(dev, slave);
|
|
|
+ struct mlx4_slave_state *slave_state =
|
|
|
+ &priv->mfunc.master.slave_state[slave];
|
|
|
+
|
|
|
/* enable rdma and ethernet interfaces, new quota locations,
|
|
|
* and reserved lkey
|
|
|
*/
|
|
@@ -439,6 +519,10 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
|
|
|
|
|
|
size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00);
|
|
|
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET);
|
|
|
+
|
|
|
+ if (vhcr->in_modifier & QUERY_FUNC_CAP_SUPPORTS_VST_QINQ)
|
|
|
+ slave_state->vst_qinq_supported = true;
|
|
|
+
|
|
|
} else
|
|
|
err = -EINVAL;
|
|
|
|
|
@@ -454,10 +538,12 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
|
|
|
u32 size, qkey;
|
|
|
int err = 0, quotas = 0;
|
|
|
u32 in_modifier;
|
|
|
+ u32 slave_caps;
|
|
|
|
|
|
op_modifier = !!gen_or_port; /* 0 = general, 1 = logical port */
|
|
|
- in_modifier = op_modifier ? gen_or_port :
|
|
|
+ slave_caps = QUERY_FUNC_CAP_SUPPORTS_VST_QINQ |
|
|
|
QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS;
|
|
|
+ in_modifier = op_modifier ? gen_or_port : slave_caps;
|
|
|
|
|
|
mailbox = mlx4_alloc_cmd_mailbox(dev);
|
|
|
if (IS_ERR(mailbox))
|
|
@@ -612,8 +698,7 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
|
|
|
MLX4_GET(func_cap->phys_port_id, outbox,
|
|
|
QUERY_FUNC_CAP_PHYS_PORT_ID);
|
|
|
|
|
|
- MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
|
|
|
- func_cap->flags |= (field & QUERY_FUNC_CAP_PHV_BIT);
|
|
|
+ MLX4_GET(func_cap->flags0, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET);
|
|
|
|
|
|
/* All other resources are allocated by the master, but we still report
|
|
|
* 'num' and 'reserved' capabilities as follows:
|
|
@@ -690,6 +775,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|
|
#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52
|
|
|
#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55
|
|
|
#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56
|
|
|
+#define QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET 0x5D
|
|
|
#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61
|
|
|
#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62
|
|
|
#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63
|
|
@@ -857,6 +943,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
|
|
|
MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET);
|
|
|
dev_cap->max_sq_desc_sz = size;
|
|
|
|
|
|
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_SVLAN_BY_QP_OFFSET);
|
|
|
+ if (field & 0x1)
|
|
|
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SVLAN_BY_QP;
|
|
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET);
|
|
|
dev_cap->max_qp_per_mcg = 1 << field;
|
|
|
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET);
|
|
@@ -2914,7 +3003,7 @@ int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv)
|
|
|
memset(&func_cap, 0, sizeof(func_cap));
|
|
|
err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap);
|
|
|
if (!err)
|
|
|
- *phv = func_cap.flags & QUERY_FUNC_CAP_PHV_BIT;
|
|
|
+ *phv = func_cap.flags0 & QUERY_FUNC_CAP_PHV_BIT;
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(get_phv_bit);
|
|
@@ -2938,6 +3027,22 @@ int set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val)
|
|
|
}
|
|
|
EXPORT_SYMBOL(set_phv_bit);
|
|
|
|
|
|
+int mlx4_get_is_vlan_offload_disabled(struct mlx4_dev *dev, u8 port,
|
|
|
+ bool *vlan_offload_disabled)
|
|
|
+{
|
|
|
+ struct mlx4_func_cap func_cap;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ memset(&func_cap, 0, sizeof(func_cap));
|
|
|
+ err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap);
|
|
|
+ if (!err)
|
|
|
+ *vlan_offload_disabled =
|
|
|
+ !!(func_cap.flags0 &
|
|
|
+ QUERY_FUNC_CAP_VLAN_OFFLOAD_DISABLE);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(mlx4_get_is_vlan_offload_disabled);
|
|
|
+
|
|
|
void mlx4_replace_zero_macs(struct mlx4_dev *dev)
|
|
|
{
|
|
|
int i;
|