int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset)
 {
+       int i, num_stats = 0;
+
        switch (sset) {
        case ETH_SS_STATS:
-               return NUM_SW_COUNTERS +
+               for (i = 0; i < mlx5e_num_stats_grps; i++)
+                       num_stats += mlx5e_stats_grps[i].get_num_stats(priv);
+               return num_stats +
                       MLX5E_NUM_Q_CNTRS(priv) +
                       NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS(priv) +
                       NUM_PCIE_COUNTERS(priv) +
        int i, j, tc, prio, idx = 0;
        unsigned long pfc_combined;
 
-       /* SW counters */
-       for (i = 0; i < NUM_SW_COUNTERS; i++)
-               strcpy(data + (idx++) * ETH_GSTRING_LEN, sw_stats_desc[i].format);
+       for (i = 0; i < mlx5e_num_stats_grps; i++)
+               idx = mlx5e_stats_grps[i].fill_strings(priv, data, idx);
 
        /* Q counters */
        for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
        channels = &priv->channels;
        mutex_unlock(&priv->state_lock);
 
-       for (i = 0; i < NUM_SW_COUNTERS; i++)
-               data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.sw,
-                                                  sw_stats_desc, i);
+       for (i = 0; i < mlx5e_num_stats_grps; i++)
+               idx = mlx5e_stats_grps[i].fill_stats(priv, data, idx);
 
        for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++)
                data[idx++] = MLX5E_READ_CTR32_CPU(&priv->stats.qcnt,
 
--- /dev/null
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "en.h"
+
+static const struct counter_desc sw_stats_desc[] = {
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_packets) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_packets) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_packets) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_packets) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_complete) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary_inner) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_drop) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_full) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_none) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial_inner) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_stopped) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_wake) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_dropped) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xmit_more) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_wqe_err) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_buff_alloc_err) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_page_reuse) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_reuse) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_full) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_empty) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_busy) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_waive) },
+       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, link_down_events_phy) },
+};
+
+#define NUM_SW_COUNTERS                        ARRAY_SIZE(sw_stats_desc)
+
+static int mlx5e_grp_sw_get_num_stats(struct mlx5e_priv *priv)
+{
+       return NUM_SW_COUNTERS;
+}
+
+static int mlx5e_grp_sw_fill_strings(struct mlx5e_priv *priv, u8 *data, int idx)
+{
+       int i;
+
+       for (i = 0; i < NUM_SW_COUNTERS; i++)
+               strcpy(data + (idx++) * ETH_GSTRING_LEN, sw_stats_desc[i].format);
+       return idx;
+}
+
+static int mlx5e_grp_sw_fill_stats(struct mlx5e_priv *priv, u64 *data, int idx)
+{
+       int i;
+
+       for (i = 0; i < NUM_SW_COUNTERS; i++)
+               data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.sw, sw_stats_desc, i);
+       return idx;
+}
+
+const struct mlx5e_stats_grp mlx5e_stats_grps[] = {
+       {
+               .get_num_stats = mlx5e_grp_sw_get_num_stats,
+               .fill_strings = mlx5e_grp_sw_fill_strings,
+               .fill_stats = mlx5e_grp_sw_fill_stats,
+       }
+};
+
+const int mlx5e_num_stats_grps = ARRAY_SIZE(mlx5e_stats_grps);
 
        u64 link_down_events_phy;
 };
 
-static const struct counter_desc sw_stats_desc[] = {
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_packets) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_bytes) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_packets) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_bytes) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_packets) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_bytes) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_packets) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tso_inner_bytes) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_bytes) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_none) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_complete) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_csum_unnecessary_inner) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_drop) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_xdp_tx_full) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_none) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_csum_partial_inner) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_stopped) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_wake) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_queue_dropped) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_xmit_more) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_wqe_err) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_mpwqe_filler) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_buff_alloc_err) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_blks) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cqe_compress_pkts) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_page_reuse) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_reuse) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_full) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_empty) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_busy) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_cache_waive) },
-       { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, link_down_events_phy) },
-};
-
 struct mlx5e_qcounter_stats {
        u32 rx_out_of_buffer;
 };
        { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, xmit_more) },
 };
 
-#define NUM_SW_COUNTERS                        ARRAY_SIZE(sw_stats_desc)
 #define NUM_Q_COUNTERS                 ARRAY_SIZE(q_stats_desc)
 #define NUM_VPORT_COUNTERS             ARRAY_SIZE(vport_stats_desc)
 #define NUM_PPORT_802_3_COUNTERS       ARRAY_SIZE(pport_802_3_stats_desc)
        struct mlx5e_pcie_stats pcie;
 };
 
+struct mlx5e_priv;
+struct mlx5e_stats_grp {
+       int (*get_num_stats)(struct mlx5e_priv *priv);
+       int (*fill_strings)(struct mlx5e_priv *priv, u8 *data, int idx);
+       int (*fill_stats)(struct mlx5e_priv *priv, u64 *data, int idx);
+};
+
+extern const struct mlx5e_stats_grp mlx5e_stats_grps[];
+extern const int mlx5e_num_stats_grps;
+
 static const struct counter_desc mlx5e_pme_status_desc[] = {
        { "module_unplug", 8 },
 };