net/mlx5e: Fix checksum handling for non-stripped vlan packets
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_main.c
index 0c53236..5bad17d 100644 (file)
@@ -109,6 +109,7 @@ static void mlx5e_update_sw_counters(struct mlx5e_priv *priv)
                s->lro_bytes    += rq_stats->lro_bytes;
                s->rx_csum_none += rq_stats->csum_none;
                s->rx_csum_sw   += rq_stats->csum_sw;
+               s->rx_csum_inner += rq_stats->csum_inner;
                s->rx_wqe_err   += rq_stats->wqe_err;
                s->rx_mpwqe_filler += rq_stats->mpwqe_filler;
                s->rx_mpwqe_frag   += rq_stats->mpwqe_frag;
@@ -135,6 +136,10 @@ static void mlx5e_update_sw_counters(struct mlx5e_priv *priv)
        s->tx_csum_offload = s->tx_packets - tx_offload_none - s->tx_csum_inner;
        s->rx_csum_good    = s->rx_packets - s->rx_csum_none -
                             s->rx_csum_sw;
+
+       s->link_down_events = MLX5_GET(ppcnt_reg,
+                               priv->stats.pport.phy_counters,
+                               counter_set.phys_layer_cntrs.link_down_events);
 }
 
 static void mlx5e_update_vport_counters(struct mlx5e_priv *priv)
@@ -161,6 +166,7 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv)
        struct mlx5e_pport_stats *pstats = &priv->stats.pport;
        struct mlx5_core_dev *mdev = priv->mdev;
        int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
+       int prio;
        void *out;
        u32 *in;
 
@@ -182,6 +188,18 @@ static void mlx5e_update_pport_counters(struct mlx5e_priv *priv)
        MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2819_COUNTERS_GROUP);
        mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
 
+       out = pstats->phy_counters;
+       MLX5_SET(ppcnt_reg, in, grp, MLX5_PHYSICAL_LAYER_COUNTERS_GROUP);
+       mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
+
+       MLX5_SET(ppcnt_reg, in, grp, MLX5_PER_PRIORITY_COUNTERS_GROUP);
+       for (prio = 0; prio < NUM_PPORT_PRIO; prio++) {
+               out = pstats->per_prio_counters[prio];
+               MLX5_SET(ppcnt_reg, in, prio_tc, prio);
+               mlx5_core_access_reg(mdev, in, sz, out, sz,
+                                    MLX5_REG_PPCNT, 0, 0);
+       }
+
 free_out:
        kvfree(in);
 }
@@ -199,10 +217,10 @@ static void mlx5e_update_q_counter(struct mlx5e_priv *priv)
 
 void mlx5e_update_stats(struct mlx5e_priv *priv)
 {
-       mlx5e_update_sw_counters(priv);
        mlx5e_update_q_counter(priv);
        mlx5e_update_vport_counters(priv);
        mlx5e_update_pport_counters(priv);
+       mlx5e_update_sw_counters(priv);
 }
 
 static void mlx5e_update_stats_work(struct work_struct *work)
@@ -371,6 +389,7 @@ static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param)
        MLX5_SET(rqc,  rqc, cqn,                rq->cq.mcq.cqn);
        MLX5_SET(rqc,  rqc, state,              MLX5_RQC_STATE_RST);
        MLX5_SET(rqc,  rqc, flush_in_error_en,  1);
+       MLX5_SET(rqc,  rqc, vsd, priv->params.vlan_strip_disable);
        MLX5_SET(wq,   wq,  log_wq_pg_sz,       rq->wq_ctrl.buf.page_shift -
                                                MLX5_ADAPTER_PAGE_SHIFT);
        MLX5_SET64(wq, wq,  dbr_addr,           rq->wq_ctrl.db.dma);
@@ -385,7 +404,8 @@ static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param)
        return err;
 }
 
-static int mlx5e_modify_rq(struct mlx5e_rq *rq, int curr_state, int next_state)
+static int mlx5e_modify_rq_state(struct mlx5e_rq *rq, int curr_state,
+                                int next_state)
 {
        struct mlx5e_channel *c = rq->channel;
        struct mlx5e_priv *priv = c->priv;
@@ -413,6 +433,36 @@ static int mlx5e_modify_rq(struct mlx5e_rq *rq, int curr_state, int next_state)
        return err;
 }
 
+static int mlx5e_modify_rq_vsd(struct mlx5e_rq *rq, bool vsd)
+{
+       struct mlx5e_channel *c = rq->channel;
+       struct mlx5e_priv *priv = c->priv;
+       struct mlx5_core_dev *mdev = priv->mdev;
+
+       void *in;
+       void *rqc;
+       int inlen;
+       int err;
+
+       inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
+       rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
+
+       MLX5_SET(modify_rq_in, in, rq_state, MLX5_RQC_STATE_RDY);
+       MLX5_SET64(modify_rq_in, in, modify_bitmask, MLX5_RQ_BITMASK_VSD);
+       MLX5_SET(rqc, rqc, vsd, vsd);
+       MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RDY);
+
+       err = mlx5_core_modify_rq(mdev, rq->rqn, in, inlen);
+
+       kvfree(in);
+
+       return err;
+}
+
 static void mlx5e_disable_rq(struct mlx5e_rq *rq)
 {
        mlx5_core_destroy_rq(rq->priv->mdev, rq->rqn);
@@ -451,7 +501,7 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_rq;
 
-       err = mlx5e_modify_rq(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
+       err = mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY);
        if (err)
                goto err_disable_rq;
 
@@ -476,7 +526,7 @@ static void mlx5e_close_rq(struct mlx5e_rq *rq)
        clear_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
        napi_synchronize(&rq->channel->napi); /* prevent mlx5e_post_rx_wqes */
 
-       mlx5e_modify_rq(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR);
+       mlx5e_modify_rq_state(rq, MLX5_RQC_STATE_RDY, MLX5_RQC_STATE_ERR);
        while (!mlx5_wq_ll_is_empty(&rq->wq))
                msleep(20);
 
@@ -1946,6 +1996,23 @@ static void mlx5e_destroy_tirs(struct mlx5e_priv *priv)
                mlx5e_destroy_tir(priv, i);
 }
 
+int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd)
+{
+       int err = 0;
+       int i;
+
+       if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+               return 0;
+
+       for (i = 0; i < priv->params.num_channels; i++) {
+               err = mlx5e_modify_rq_vsd(&priv->channel[i]->rq, vsd);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int mlx5e_setup_tc(struct net_device *netdev, u8 tc)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -2061,52 +2128,135 @@ static int mlx5e_set_mac(struct net_device *netdev, void *addr)
        return 0;
 }
 
-static int mlx5e_set_features(struct net_device *netdev,
-                             netdev_features_t features)
+#define MLX5E_SET_FEATURE(netdev, feature, enable)     \
+       do {                                            \
+               if (enable)                             \
+                       netdev->features |= feature;    \
+               else                                    \
+                       netdev->features &= ~feature;   \
+       } while (0)
+
+typedef int (*mlx5e_feature_handler)(struct net_device *netdev, bool enable);
+
+static int set_feature_lro(struct net_device *netdev, bool enable)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
-       int err = 0;
-       netdev_features_t changes = features ^ netdev->features;
+       bool was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
+       int err;
 
        mutex_lock(&priv->state_lock);
 
-       if (changes & NETIF_F_LRO) {
-               bool was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
-
-               if (was_opened && (priv->params.rq_wq_type ==
-                                  MLX5_WQ_TYPE_LINKED_LIST))
-                       mlx5e_close_locked(priv->netdev);
-
-               priv->params.lro_en = !!(features & NETIF_F_LRO);
-               err = mlx5e_modify_tirs_lro(priv);
-               if (err)
-                       mlx5_core_warn(priv->mdev, "lro modify failed, %d\n",
-                                      err);
+       if (was_opened && (priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST))
+               mlx5e_close_locked(priv->netdev);
 
-               if (was_opened && (priv->params.rq_wq_type ==
-                                  MLX5_WQ_TYPE_LINKED_LIST))
-                       err = mlx5e_open_locked(priv->netdev);
+       priv->params.lro_en = enable;
+       err = mlx5e_modify_tirs_lro(priv);
+       if (err) {
+               netdev_err(netdev, "lro modify failed, %d\n", err);
+               priv->params.lro_en = !enable;
        }
 
+       if (was_opened && (priv->params.rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST))
+               mlx5e_open_locked(priv->netdev);
+
        mutex_unlock(&priv->state_lock);
 
-       if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) {
-               if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
-                       mlx5e_enable_vlan_filter(priv);
-               else
-                       mlx5e_disable_vlan_filter(priv);
-       }
+       return err;
+}
+
+static int set_feature_vlan_filter(struct net_device *netdev, bool enable)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (enable)
+               mlx5e_enable_vlan_filter(priv);
+       else
+               mlx5e_disable_vlan_filter(priv);
+
+       return 0;
+}
+
+static int set_feature_tc_num_filters(struct net_device *netdev, bool enable)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
 
-       if ((changes & NETIF_F_HW_TC) && !(features & NETIF_F_HW_TC) &&
-           mlx5e_tc_num_filters(priv)) {
+       if (!enable && mlx5e_tc_num_filters(priv)) {
                netdev_err(netdev,
                           "Active offloaded tc filters, can't turn hw_tc_offload off\n");
                return -EINVAL;
        }
 
+       return 0;
+}
+
+static int set_feature_rx_all(struct net_device *netdev, bool enable)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+
+       return mlx5_set_port_fcs(mdev, !enable);
+}
+
+static int set_feature_rx_vlan(struct net_device *netdev, bool enable)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int err;
+
+       mutex_lock(&priv->state_lock);
+
+       priv->params.vlan_strip_disable = !enable;
+       err = mlx5e_modify_rqs_vsd(priv, !enable);
+       if (err)
+               priv->params.vlan_strip_disable = enable;
+
+       mutex_unlock(&priv->state_lock);
+
        return err;
 }
 
+static int mlx5e_handle_feature(struct net_device *netdev,
+                               netdev_features_t wanted_features,
+                               netdev_features_t feature,
+                               mlx5e_feature_handler feature_handler)
+{
+       netdev_features_t changes = wanted_features ^ netdev->features;
+       bool enable = !!(wanted_features & feature);
+       int err;
+
+       if (!(changes & feature))
+               return 0;
+
+       err = feature_handler(netdev, enable);
+       if (err) {
+               netdev_err(netdev, "%s feature 0x%llx failed err %d\n",
+                          enable ? "Enable" : "Disable", feature, err);
+               return err;
+       }
+
+       MLX5E_SET_FEATURE(netdev, feature, enable);
+       return 0;
+}
+
+static int mlx5e_set_features(struct net_device *netdev,
+                             netdev_features_t features)
+{
+       int err;
+
+       err  = mlx5e_handle_feature(netdev, features, NETIF_F_LRO,
+                                   set_feature_lro);
+       err |= mlx5e_handle_feature(netdev, features,
+                                   NETIF_F_HW_VLAN_CTAG_FILTER,
+                                   set_feature_vlan_filter);
+       err |= mlx5e_handle_feature(netdev, features, NETIF_F_HW_TC,
+                                   set_feature_tc_num_filters);
+       err |= mlx5e_handle_feature(netdev, features, NETIF_F_RXALL,
+                                   set_feature_rx_all);
+       err |= mlx5e_handle_feature(netdev, features, NETIF_F_HW_VLAN_CTAG_RX,
+                                   set_feature_rx_vlan);
+
+       return err ? -EINVAL : 0;
+}
+
 static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -2493,6 +2643,8 @@ static void mlx5e_build_netdev(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
+       bool fcs_supported;
+       bool fcs_enabled;
 
        SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
 
@@ -2536,10 +2688,18 @@ static void mlx5e_build_netdev(struct net_device *netdev)
                netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
        }
 
+       mlx5_query_port_fcs(mdev, &fcs_supported, &fcs_enabled);
+
+       if (fcs_supported)
+               netdev->hw_features |= NETIF_F_RXALL;
+
        netdev->features          = netdev->hw_features;
        if (!priv->params.lro_en)
                netdev->features  &= ~NETIF_F_LRO;
 
+       if (fcs_enabled)
+               netdev->features  &= ~NETIF_F_RXALL;
+
 #define FT_CAP(f) MLX5_CAP_FLOWTABLE(mdev, flow_table_properties_nic_receive.f)
        if (FT_CAP(flow_modify_en) &&
            FT_CAP(modify_root) &&