enum mlx5e_rq_group {
        MLX5E_RQ_GROUP_REGULAR,
        MLX5E_RQ_GROUP_XSK,
-       MLX5E_NUM_RQ_GROUPS /* Keep last. */
+#define MLX5E_NUM_RQ_GROUPS(g) (1 + MLX5E_RQ_GROUP_##g)
 };
 
 static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
                min_t(int, mlx5_comp_vectors_count(mdev), MLX5E_MAX_NUM_CHANNELS);
 }
 
-/* Use this function to get max num channels after netdev was created */
-static inline int mlx5e_get_netdev_max_channels(struct net_device *netdev)
-{
-       return min_t(unsigned int,
-                    netdev->num_rx_queues / MLX5E_NUM_RQ_GROUPS,
-                    netdev->num_tx_queues);
-}
-
 struct mlx5e_tx_wqe {
        struct mlx5_wqe_ctrl_seg ctrl;
        struct mlx5_wqe_eth_seg  eth;
        struct net_device         *netdev;
        struct mlx5e_stats         stats;
        struct mlx5e_channel_stats channel_stats[MLX5E_MAX_NUM_CHANNELS];
+       u16                        max_nch;
        u8                         max_opened_tc;
        struct hwtstamp_config     tstamp;
        u16                        q_counter;
                mlx5e_fp_handle_rx_cqe handle_rx_cqe_mpwqe;
        } rx_handlers;
        int     max_tc;
+       u8      rq_groups;
 };
 
 void mlx5e_build_ptys2ethtool_map(void);
 
                          struct mlx5e_channel_param *cparam)
 {
        struct mlx5e_priv *priv = c->priv;
-       int err, tc, max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+       int err, tc;
 
        for (tc = 0; tc < params->num_tc; tc++) {
-               int txq_ix = c->ix + tc * max_nch;
+               int txq_ix = c->ix + tc * priv->max_nch;
 
                err = mlx5e_open_txqsq(c, c->priv->tisn[tc], txq_ix,
                                       params, &cparam->sq, &c->sq[tc], tc);
 
 int mlx5e_create_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int err;
        int ix;
 
-       for (ix = 0; ix < max_nch; ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                err = mlx5e_create_rqt(priv, 1 /*size */, &tirs[ix].rqt);
                if (unlikely(err))
                        goto err_destroy_rqts;
 
 void mlx5e_destroy_direct_rqts(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                mlx5e_destroy_rqt(priv, &tirs[i].rqt);
 }
 
                mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp);
        }
 
-       for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                struct mlx5e_redirect_rqt_param direct_rrp = {
                        .is_rss = false,
                        {
                        goto free_in;
        }
 
-       for (ix = 0; ix < mlx5e_get_netdev_max_channels(priv->netdev); ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn,
                                           in, inlen);
                if (err)
 
 static void mlx5e_build_tc2txq_maps(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i, tc;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                for (tc = 0; tc < priv->profile->max_tc; tc++)
-                       priv->channel_tc2txq[i][tc] = i + tc * max_nch;
+                       priv->channel_tc2txq[i][tc] = i + tc * priv->max_nch;
 }
 
 static void mlx5e_build_tx2sq_maps(struct mlx5e_priv *priv)
 void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)
 {
        int num_txqs = priv->channels.num * priv->channels.params.num_tc;
-       int num_rxqs = priv->channels.num * MLX5E_NUM_RQ_GROUPS;
+       int num_rxqs = priv->channels.num * priv->profile->rq_groups;
        struct net_device *netdev = priv->netdev;
 
        mlx5e_netdev_set_tcs(netdev);
 
 int mlx5e_create_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        struct mlx5e_tir *tir;
        void *tirc;
        int inlen;
        if (!in)
                return -ENOMEM;
 
-       for (ix = 0; ix < max_nch; ix++) {
+       for (ix = 0; ix < priv->max_nch; ix++) {
                memset(in, 0, inlen);
                tir = &tirs[ix];
                tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
 
 void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv, struct mlx5e_tir *tirs)
 {
-       const int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        int i;
 
-       for (i = 0; i < max_nch; i++)
+       for (i = 0; i < priv->max_nch; i++)
                mlx5e_destroy_tir(priv->mdev, &tirs[i]);
 }
 
 {
        int i;
 
-       for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats = &priv->channel_stats[i];
                struct mlx5e_rq_stats *xskrq_stats = &channel_stats->xskrq;
                struct mlx5e_rq_stats *rq_stats = &channel_stats->rq;
                return err;
 
        mlx5e_build_nic_params(mdev, &priv->xsk, rss, &priv->channels.params,
-                              mlx5e_get_netdev_max_channels(netdev),
-                              netdev->mtu);
+                              priv->max_nch, netdev->mtu);
 
        mlx5e_timestamp_init(priv);
 
        .rx_handlers.handle_rx_cqe       = mlx5e_handle_rx_cqe,
        .rx_handlers.handle_rx_cqe_mpwqe = mlx5e_handle_rx_cqe_mpwrq,
        .max_tc            = MLX5E_MAX_NUM_TC,
+       .rq_groups         = MLX5E_NUM_RQ_GROUPS(XSK),
 };
 
 /* mlx5e generic netdev management API (move to en_common.c) */
        priv->profile     = profile;
        priv->ppriv       = ppriv;
        priv->msglevel    = MLX5E_MSG_LEVEL;
+       priv->max_nch     = netdev->num_rx_queues / max_t(u8, profile->rq_groups, 1);
        priv->max_opened_tc = 1;
 
        mutex_init(&priv->state_lock);
 
        netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
                                    nch * profile->max_tc,
-                                   nch * MLX5E_NUM_RQ_GROUPS);
+                                   nch * profile->rq_groups);
        if (!netdev) {
                mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
                return NULL;
 
 
        memset(s, 0, sizeof(*s));
 
-       for (i = 0; i < mlx5e_get_netdev_max_channels(priv->netdev); i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats =
                        &priv->channel_stats[i];
                struct mlx5e_xdpsq_stats *xdpsq_red_stats = &channel_stats->xdpsq;
 
 static int mlx5e_grp_channels_get_num_stats(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
+       int max_nch = priv->max_nch;
 
        return (NUM_RQ_STATS * max_nch) +
               (NUM_CH_STATS * max_nch) +
 static int mlx5e_grp_channels_fill_strings(struct mlx5e_priv *priv, u8 *data,
                                           int idx)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        bool is_xsk = priv->xsk.ever_used;
+       int max_nch = priv->max_nch;
        int i, j, tc;
 
        for (i = 0; i < max_nch; i++)
 static int mlx5e_grp_channels_fill_stats(struct mlx5e_priv *priv, u64 *data,
                                         int idx)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        bool is_xsk = priv->xsk.ever_used;
+       int max_nch = priv->max_nch;
        int i, j, tc;
 
        for (i = 0; i < max_nch; i++)
 
        netdev->mtu = netdev->max_mtu;
 
        mlx5e_build_nic_params(mdev, NULL, &priv->rss_params, &priv->channels.params,
-                              mlx5e_get_netdev_max_channels(netdev),
-                              netdev->mtu);
+                              priv->max_nch, netdev->mtu);
        mlx5i_build_nic_params(mdev, &priv->channels.params);
 
        mlx5e_timestamp_init(priv);
 
 static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv)
 {
-       int max_nch = mlx5e_get_netdev_max_channels(priv->netdev);
        struct mlx5e_sw_stats s = { 0 };
        int i, j;
 
-       for (i = 0; i < max_nch; i++) {
+       for (i = 0; i < priv->max_nch; i++) {
                struct mlx5e_channel_stats *channel_stats;
                struct mlx5e_rq_stats *rq_stats;
 
        .rx_handlers.handle_rx_cqe       = mlx5i_handle_rx_cqe,
        .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */
        .max_tc            = MLX5I_MAX_NUM_TC,
+       .rq_groups         = MLX5E_NUM_RQ_GROUPS(REGULAR),
 };
 
 /* mlx5i netdev NDos */