net/mlx5e: Support RX multi-packet WQE (Striding RQ)
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_ethtool.c
index 5abeb00..4077856 100644 (file)
@@ -165,6 +165,8 @@ static const struct {
        },
 };
 
+#define MLX5E_NUM_Q_CNTRS(priv) (NUM_Q_COUNTERS * (!!priv->q_counter))
+
 static int mlx5e_get_sset_count(struct net_device *dev, int sset)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
@@ -172,6 +174,7 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset)
        switch (sset) {
        case ETH_SS_STATS:
                return NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS +
+                      MLX5E_NUM_Q_CNTRS(priv) +
                       priv->params.num_channels * NUM_RQ_STATS +
                       priv->params.num_channels * priv->params.num_tc *
                                                   NUM_SQ_STATS;
@@ -200,6 +203,11 @@ static void mlx5e_get_strings(struct net_device *dev,
                        strcpy(data + (idx++) * ETH_GSTRING_LEN,
                               vport_strings[i]);
 
+               /* Q counters */
+               for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
+                       strcpy(data + (idx++) * ETH_GSTRING_LEN,
+                              qcounter_stats_strings[i]);
+
                /* PPORT counters */
                for (i = 0; i < NUM_PPORT_COUNTERS; i++)
                        strcpy(data + (idx++) * ETH_GSTRING_LEN,
@@ -211,13 +219,14 @@ static void mlx5e_get_strings(struct net_device *dev,
                                sprintf(data + (idx++) * ETH_GSTRING_LEN,
                                        "rx%d_%s", i, rq_stats_strings[j]);
 
-               for (i = 0; i < priv->params.num_channels; i++)
-                       for (tc = 0; tc < priv->params.num_tc; tc++)
+               for (tc = 0; tc < priv->params.num_tc; tc++)
+                       for (i = 0; i < priv->params.num_channels; i++)
                                for (j = 0; j < NUM_SQ_STATS; j++)
                                        sprintf(data +
-                                               (idx++) * ETH_GSTRING_LEN,
-                                               "tx%d_%d_%s", i, tc,
-                                               sq_stats_strings[j]);
+                                             (idx++) * ETH_GSTRING_LEN,
+                                             "tx%d_%s",
+                                             priv->channeltc_to_txq_map[i][tc],
+                                             sq_stats_strings[j]);
                break;
        }
 }
@@ -239,6 +248,9 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
        for (i = 0; i < NUM_VPORT_COUNTERS; i++)
                data[idx++] = ((u64 *)&priv->stats.vport)[i];
 
+       for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
+               data[idx++] = ((u32 *)&priv->stats.qcnt)[i];
+
        for (i = 0; i < NUM_PPORT_COUNTERS; i++)
                data[idx++] = be64_to_cpu(((__be64 *)&priv->stats.pport)[i]);
 
@@ -249,8 +261,8 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
                                                &priv->state) ? 0 :
                                       ((u64 *)&priv->channel[i]->rq.stats)[j];
 
-       for (i = 0; i < priv->params.num_channels; i++)
-               for (tc = 0; tc < priv->params.num_tc; tc++)
+       for (tc = 0; tc < priv->params.num_tc; tc++)
+               for (i = 0; i < priv->params.num_channels; i++)
                        for (j = 0; j < NUM_SQ_STATS; j++)
                                data[idx++] = !test_bit(MLX5E_STATE_OPENED,
                                                        &priv->state) ? 0 :
@@ -261,8 +273,9 @@ static void mlx5e_get_ringparam(struct net_device *dev,
                                struct ethtool_ringparam *param)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
+       int rq_wq_type = priv->params.rq_wq_type;
 
-       param->rx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
+       param->rx_max_pending = 1 << mlx5_max_log_rq_size(rq_wq_type);
        param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
        param->rx_pending     = 1 << priv->params.log_rq_size;
        param->tx_pending     = 1 << priv->params.log_sq_size;
@@ -273,6 +286,7 @@ static int mlx5e_set_ringparam(struct net_device *dev,
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
        bool was_opened;
+       int rq_wq_type = priv->params.rq_wq_type;
        u16 min_rx_wqes;
        u8 log_rq_size;
        u8 log_sq_size;
@@ -288,16 +302,16 @@ static int mlx5e_set_ringparam(struct net_device *dev,
                            __func__);
                return -EINVAL;
        }
-       if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
+       if (param->rx_pending < (1 << mlx5_min_log_rq_size(rq_wq_type))) {
                netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n",
                            __func__, param->rx_pending,
-                           1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
+                           1 << mlx5_min_log_rq_size(rq_wq_type));
                return -EINVAL;
        }
-       if (param->rx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE)) {
+       if (param->rx_pending > (1 << mlx5_max_log_rq_size(rq_wq_type))) {
                netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n",
                            __func__, param->rx_pending,
-                           1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE);
+                           1 << mlx5_max_log_rq_size(rq_wq_type));
                return -EINVAL;
        }
        if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
@@ -315,8 +329,7 @@ static int mlx5e_set_ringparam(struct net_device *dev,
 
        log_rq_size = order_base_2(param->rx_pending);
        log_sq_size = order_base_2(param->tx_pending);
-       min_rx_wqes = min_t(u16, param->rx_pending - 1,
-                           MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
+       min_rx_wqes = mlx5_min_rx_wqes(rq_wq_type, param->rx_pending);
 
        if (log_rq_size == priv->params.log_rq_size &&
            log_sq_size == priv->params.log_sq_size &&
@@ -385,7 +398,7 @@ static int mlx5e_set_channels(struct net_device *dev,
                mlx5e_close_locked(dev);
 
        priv->params.num_channels = count;
-       mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+       mlx5e_build_default_indir_rqt(priv->mdev, priv->params.indirection_rqt,
                                      MLX5E_INDIR_RQT_SIZE, count);
 
        if (was_opened)
@@ -401,6 +414,9 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
+               return -ENOTSUPP;
+
        coal->rx_coalesce_usecs       = priv->params.rx_cq_moderation_usec;
        coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
        coal->tx_coalesce_usecs       = priv->params.tx_cq_moderation_usec;
@@ -418,11 +434,18 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
        int tc;
        int i;
 
+       if (!MLX5_CAP_GEN(mdev, cq_moderation))
+               return -ENOTSUPP;
+
+       mutex_lock(&priv->state_lock);
        priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
        priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
        priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
        priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
 
+       if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+               goto out;
+
        for (i = 0; i < priv->params.num_channels; ++i) {
                c = priv->channel[i];
 
@@ -438,6 +461,8 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
                                               coal->rx_max_coalesced_frames);
        }
 
+out:
+       mutex_unlock(&priv->state_lock);
        return 0;
 }
 
@@ -900,6 +925,129 @@ static int mlx5e_get_ts_info(struct net_device *dev,
        return 0;
 }
 
+static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev)
+{
+       __u32 ret = 0;
+
+       if (MLX5_CAP_GEN(mdev, wol_g))
+               ret |= WAKE_MAGIC;
+
+       if (MLX5_CAP_GEN(mdev, wol_s))
+               ret |= WAKE_MAGICSECURE;
+
+       if (MLX5_CAP_GEN(mdev, wol_a))
+               ret |= WAKE_ARP;
+
+       if (MLX5_CAP_GEN(mdev, wol_b))
+               ret |= WAKE_BCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_m))
+               ret |= WAKE_MCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_u))
+               ret |= WAKE_UCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_p))
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode)
+{
+       __u32 ret = 0;
+
+       if (mode & MLX5_WOL_MAGIC)
+               ret |= WAKE_MAGIC;
+
+       if (mode & MLX5_WOL_SECURED_MAGIC)
+               ret |= WAKE_MAGICSECURE;
+
+       if (mode & MLX5_WOL_ARP)
+               ret |= WAKE_ARP;
+
+       if (mode & MLX5_WOL_BROADCAST)
+               ret |= WAKE_BCAST;
+
+       if (mode & MLX5_WOL_MULTICAST)
+               ret |= WAKE_MCAST;
+
+       if (mode & MLX5_WOL_UNICAST)
+               ret |= WAKE_UCAST;
+
+       if (mode & MLX5_WOL_PHY_ACTIVITY)
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode)
+{
+       u8 ret = 0;
+
+       if (mode & WAKE_MAGIC)
+               ret |= MLX5_WOL_MAGIC;
+
+       if (mode & WAKE_MAGICSECURE)
+               ret |= MLX5_WOL_SECURED_MAGIC;
+
+       if (mode & WAKE_ARP)
+               ret |= MLX5_WOL_ARP;
+
+       if (mode & WAKE_BCAST)
+               ret |= MLX5_WOL_BROADCAST;
+
+       if (mode & WAKE_MCAST)
+               ret |= MLX5_WOL_MULTICAST;
+
+       if (mode & WAKE_UCAST)
+               ret |= MLX5_WOL_UNICAST;
+
+       if (mode & WAKE_PHY)
+               ret |= MLX5_WOL_PHY_ACTIVITY;
+
+       return ret;
+}
+
+static void mlx5e_get_wol(struct net_device *netdev,
+                         struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 mlx5_wol_mode;
+       int err;
+
+       memset(wol, 0, sizeof(*wol));
+
+       wol->supported = mlx5e_get_wol_supported(mdev);
+       if (!wol->supported)
+               return;
+
+       err = mlx5_query_port_wol(mdev, &mlx5_wol_mode);
+       if (err)
+               return;
+
+       wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode);
+}
+
+static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       __u32 wol_supported = mlx5e_get_wol_supported(mdev);
+       u32 mlx5_wol_mode;
+
+       if (!wol_supported)
+               return -ENOTSUPP;
+
+       if (wol->wolopts & ~wol_supported)
+               return -EINVAL;
+
+       mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts);
+
+       return mlx5_set_port_wol(mdev, mlx5_wol_mode);
+}
+
 const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
@@ -924,4 +1072,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_pauseparam    = mlx5e_get_pauseparam,
        .set_pauseparam    = mlx5e_set_pauseparam,
        .get_ts_info       = mlx5e_get_ts_info,
+       .get_wol           = mlx5e_get_wol,
+       .set_wol           = mlx5e_set_wol,
 };