net/mlx4: Add set VF default vlan ID and priority support
authorRony Efraim <ronye@mellanox.com>
Thu, 25 Apr 2013 05:22:28 +0000 (05:22 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 27 Apr 2013 03:29:13 +0000 (23:29 -0400)
Add support to ndo_set_vf_vlan in the driver. Once this call is used the vport
is considered to be in VST mode. In this mode, the PPF driver configures
Ethernet QPs created by this VF to use this vlan id and priority. Currently
RoCE isn't supported on that mode.

The special values of VID=4095 or VID=0,UP=0 are considered as VGT.

Signed-off-by: Rony Efraim <ronye@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h

index a029124fe2f8eb6e92b539fd851f331ae8d4bebf..aad6f8dbfb4c95ff651a06c8d10dd0ec660c4a02 100644 (file)
@@ -1492,14 +1492,48 @@ out:
 
 static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
 {
-       int port;
+       int port, err;
+       struct mlx4_vport_state *vp_admin;
+       struct mlx4_vport_oper_state *vp_oper;
+
        for (port = 1; port <= MLX4_MAX_PORTS; port++) {
-               priv->mfunc.master.vf_oper[slave].vport[port].state =
-                               priv->mfunc.master.vf_admin[slave].vport[port];
+               vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+               vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
+               vp_oper->state = *vp_admin;
+               if (MLX4_VGT != vp_admin->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 resorces 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);
+               }
        }
        return 0;
 }
 
+static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
+{
+       int port;
+       struct mlx4_vport_oper_state *vp_oper;
+
+       for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+               vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+               if (NO_INDX != vp_oper->vlan_idx) {
+                       __mlx4_unregister_vlan(&priv->dev,
+                                              port, vp_oper->vlan_idx);
+                       vp_oper->vlan_idx = NO_INDX;
+               }
+       }
+       return;
+}
+
 static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
                               u16 param, u8 toggle)
 {
@@ -1520,6 +1554,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
        if (cmd == MLX4_COMM_CMD_RESET) {
                mlx4_warn(dev, "Received reset from slave:%d\n", slave);
                slave_state[slave].active = false;
+               mlx4_master_deactivate_admin_state(priv, slave);
                for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
                                slave_state[slave].event_eq[i].eqn = -1;
                                slave_state[slave].event_eq[i].token = 0;
@@ -1566,7 +1601,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
                if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
                        goto reset_slave;
                slave_state[slave].vhcr_dma |= param;
-               mlx4_master_activate_admin_state(priv, slave);
+               if (mlx4_master_activate_admin_state(priv, slave))
+                               goto reset_slave;
                slave_state[slave].active = true;
                mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
                break;
@@ -1776,6 +1812,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
                                }
                                INIT_LIST_HEAD(&s_state->mcast_filters[port]);
                                priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
+                               priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
                                priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
                                priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
                        }
@@ -2047,3 +2084,30 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
        return 0;
 }
 EXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
+
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_vport_state *s_info;
+       int slave;
+
+       if ((!mlx4_is_master(dev)) ||
+           !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
+               return -EPROTONOSUPPORT;
+
+       if ((vlan > 4095) || (qos > 7))
+               return -EINVAL;
+
+       slave = mlx4_get_slave_indx(dev, vf);
+       if (slave < 0)
+               return -EINVAL;
+
+       s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+       if ((0 == vlan) && (0 == qos))
+               s_info->default_vlan = MLX4_VGT;
+       else
+               s_info->default_vlan = vlan;
+       s_info->default_qos = qos;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
index 8293a92bf151f3091d65b0655c92413d7e6da1c0..c1f2c5b34d9586ecde65cbe0037518b16269ccb4 100644 (file)
@@ -2036,6 +2036,14 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
        return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
 }
 
+static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
+{
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
+
+       return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos);
+}
+
 
 static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_open               = mlx4_en_open,
@@ -2075,6 +2083,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
        .ndo_vlan_rx_add_vid    = mlx4_en_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = mlx4_en_vlan_rx_kill_vid,
        .ndo_set_vf_mac         = mlx4_en_set_vf_mac,
+       .ndo_set_vf_vlan        = mlx4_en_set_vf_vlan,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = mlx4_en_netpoll,
 #endif
index 70d44adddc399885fa6cd181c28858a61e703c3a..d2d30c940790cf1271445454d7e641d145d481ba 100644 (file)
@@ -468,6 +468,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_RSVD_XRC_OFFSET          0x66
 #define QUERY_DEV_CAP_MAX_XRC_OFFSET           0x67
 #define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET      0x68
+#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET       0x70
 #define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET    0x76
 #define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET      0x77
 #define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET   0x80
@@ -655,6 +656,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                MLX4_GET(dev_cap->max_counters, outbox,
                         QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
 
+       MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
+       if (field32 & (1 << 26))
+               dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
+
        if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
                for (i = 1; i <= dev_cap->num_ports; ++i) {
                        MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
index 7e1d10059eda673ad33348edd9aba0c8b7ea58b9..eac3dae10efe4170d7ed7c276eaccca1ff2434fa 100644 (file)
@@ -1157,6 +1157,8 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
 
 void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
 void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
 
 int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz);
 /* resource tracker functions*/
index d3408add8742851f564202625dcf841f229a4d1a..946e0af5faef28b2e89bc677510e1032c24e9eef 100644 (file)
@@ -310,7 +310,7 @@ int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
 }
 EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
 
-static int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
                                int *index)
 {
        struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -384,7 +384,7 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
 }
 EXPORT_SYMBOL_GPL(mlx4_register_vlan);
 
-static void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
 {
        struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 
index f2d64435d8ef8f8de55b58fd1e2d2b97bdab16c1..5083d4babfe32a1822ac2bbb81e8e2fbfd386ac3 100644 (file)
@@ -353,6 +353,39 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
        }
 }
 
+static int update_vport_qp_param(struct mlx4_dev *dev,
+                                struct mlx4_cmd_mailbox *inbox,
+                                u8 slave)
+{
+       struct mlx4_qp_context  *qpc = inbox->buf + 8;
+       struct mlx4_vport_oper_state *vp_oper;
+       struct mlx4_priv *priv;
+       u32 qp_type;
+       int port;
+
+       port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
+       priv = mlx4_priv(dev);
+       vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+       if (MLX4_VGT != vp_oper->state.default_vlan) {
+               qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+               if (MLX4_QP_ST_RC == qp_type)
+                       return -EINVAL;
+
+               qpc->pri_path.vlan_index = vp_oper->vlan_idx;
+               qpc->pri_path.fl = (1 << 6) | (1 << 2); /* set cv bit and hide_cqe_vlan bit*/
+               qpc->pri_path.feup |= 1 << 3; /* set fvl bit */
+               qpc->pri_path.sched_queue &= 0xC7;
+               qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
+               mlx4_dbg(dev, "qp %d  port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n",
+                        be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+                        (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan,
+                        vp_oper->vlan_idx, (int)(qpc->pri_path.feup),
+                        (int)(qpc->pri_path.fl));
+       }
+       return 0;
+}
+
 static int mpt_mask(struct mlx4_dev *dev)
 {
        return dev->caps.num_mpts - 1;
@@ -2798,6 +2831,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        update_pkey_index(dev, slave, inbox);
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
+       err = update_vport_qp_param(dev, inbox, slave);
+       if (err)
+               return err;
 
        return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 }
index f21ddc6203bdf9b323f7d52d79848a63396da746..7daead75a6f525e719010f0c88b941ebdcbcfa9b 100644 (file)
@@ -233,6 +233,8 @@ void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbo
 
 u32 mlx4_comm_get_version(void);
 int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac);
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos);
+
 
 #define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8)
 
index 2fbc1464b53beae24231b3bc630a05030df78366..6606d8f5862a2dd03727afbdee3cb77212cfaaed 100644 (file)
@@ -155,7 +155,8 @@ enum {
        MLX4_DEV_CAP_FLAG2_RSS_XOR              = 1LL <<  2,
        MLX4_DEV_CAP_FLAG2_FS_EN                = 1LL <<  3,
        MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN     = 1LL <<  4,
-       MLX4_DEV_CAP_FLAG2_TS                   = 1LL <<  5
+       MLX4_DEV_CAP_FLAG2_TS                   = 1LL <<  5,
+       MLX4_DEV_CAP_FLAG2_VLAN_CONTROL         = 1LL <<  6
 };
 
 enum {