Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / fw.c
index d87bbe6..c41ab31 100644 (file)
@@ -159,6 +159,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [32] = "Loopback source checks support",
                [33] = "RoCEv2 support",
                [34] = "DMFS Sniffer support (UC & MC)",
+               [35] = "QinQ VST mode support",
                [36] = "sl to vl mapping table change event support"
        };
        int i;
@@ -249,6 +250,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,
@@ -312,14 +379,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;
@@ -358,15 +429,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
                 */
@@ -440,6 +520,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;
 
@@ -455,10 +539,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))
@@ -613,8 +699,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:
@@ -691,6 +776,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
@@ -769,12 +855,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev_cap->max_eqs = 1 << (field & 0xf);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
        dev_cap->reserved_mtts = 1 << (field >> 4);
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
-       dev_cap->max_mrw_sz = 1 << field;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET);
        dev_cap->reserved_mrws = 1 << (field & 0xf);
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
-       dev_cap->max_mtt_seg = 1 << (field & 0x3f);
        MLX4_GET(size, outbox, QUERY_DEV_CAP_NUM_SYS_EQ_OFFSET);
        dev_cap->num_sys_eqs = size & 0xfff;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
@@ -862,6 +944,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);
@@ -2919,7 +3004,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);
@@ -2943,6 +3028,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;