net/mlx5e: Added self loopback prevention
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_main.c
index 59874d6..df00175 100644 (file)
@@ -442,12 +442,12 @@ static void mlx5e_disable_rq(struct mlx5e_rq *rq)
 
 static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq)
 {
+       unsigned long exp_time = jiffies + msecs_to_jiffies(20000);
        struct mlx5e_channel *c = rq->channel;
        struct mlx5e_priv *priv = c->priv;
        struct mlx5_wq_ll *wq = &rq->wq;
-       int i;
 
-       for (i = 0; i < 1000; i++) {
+       while (time_before(jiffies, exp_time)) {
                if (wq->cur_sz >= priv->params.min_rx_wqes)
                        return 0;
 
@@ -1332,6 +1332,42 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
        return err;
 }
 
+static int mlx5e_refresh_tir_self_loopback_enable(struct mlx5_core_dev *mdev,
+                                                 u32 tirn)
+{
+       void *in;
+       int inlen;
+       int err;
+
+       inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
+
+       err = mlx5_core_modify_tir(mdev, tirn, in, inlen);
+
+       kvfree(in);
+
+       return err;
+}
+
+static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv)
+{
+       int err;
+       int i;
+
+       for (i = 0; i < MLX5E_NUM_TT; i++) {
+               err = mlx5e_refresh_tir_self_loopback_enable(priv->mdev,
+                                                            priv->tirn[i]);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1367,13 +1403,20 @@ int mlx5e_open_locked(struct net_device *netdev)
 
        err = mlx5e_set_dev_port_mtu(netdev);
        if (err)
-               return err;
+               goto err_clear_state_opened_flag;
 
        err = mlx5e_open_channels(priv);
        if (err) {
                netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n",
                           __func__, err);
-               return err;
+               goto err_clear_state_opened_flag;
+       }
+
+       err = mlx5e_refresh_tirs_self_loopback_enable(priv);
+       if (err) {
+               netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
+                          __func__, err);
+               goto err_close_channels;
        }
 
        mlx5e_update_carrier(priv);
@@ -1382,6 +1425,12 @@ int mlx5e_open_locked(struct net_device *netdev)
        schedule_delayed_work(&priv->update_stats_work, 0);
 
        return 0;
+
+err_close_channels:
+       mlx5e_close_channels(priv);
+err_clear_state_opened_flag:
+       clear_bit(MLX5E_STATE_OPENED, &priv->state);
+       return err;
 }
 
 static int mlx5e_open(struct net_device *netdev)
@@ -1400,6 +1449,12 @@ int mlx5e_close_locked(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       /* May already be CLOSED in case a previous configuration operation
+        * (e.g RX/TX queue size change) that involves close&open failed.
+        */
+       if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+               return 0;
+
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
 
        mlx5e_redirect_rqts(priv);
@@ -1833,7 +1888,7 @@ static int mlx5e_set_features(struct net_device *netdev,
                        mlx5e_disable_vlan_filter(priv);
        }
 
-       return 0;
+       return err;
 }
 
 static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
@@ -1899,6 +1954,9 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
                               "Not creating net device, some required device capabilities are missing\n");
                return -ENOTSUPP;
        }
+       if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
+               mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+
        return 0;
 }
 
@@ -1994,6 +2052,7 @@ static void mlx5e_build_netdev(struct net_device *netdev)
                netdev->vlan_features    |= NETIF_F_LRO;
 
        netdev->hw_features       = netdev->vlan_features;
+       netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_TX;
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_RX;
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
@@ -2037,8 +2096,7 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
 {
        struct net_device *netdev;
        struct mlx5e_priv *priv;
-       int nch = min_t(int, mdev->priv.eq_table.num_comp_vectors,
-                       MLX5E_MAX_NUM_CHANNELS);
+       int nch = mlx5e_get_max_num_channels(mdev);
        int err;
 
        if (mlx5e_check_required_hca_cap(mdev))