DECLARE_BITMAP(qos_used_qids, MLX5E_QOS_MAX_LEAF_NODES);
        struct mlx5e_sq_stats **qos_sq_stats;
        u16 max_qos_sqs;
-       u16 maj_id;
-       u16 defcls;
 };
 
 struct mlx5e_trap;
 
 static u16 mlx5e_qid_from_qos(struct mlx5e_channels *chs, u16 qid)
 {
        /* These channel params are safe to access from the datapath, because:
-        * 1. This function is called only after checking priv->htb.maj_id != 0,
+        * 1. This function is called only after checking selq->htb_maj_id != 0,
         *    and the number of queues can't change while HTB offload is active.
-        * 2. When priv->htb.maj_id becomes 0, synchronize_rcu waits for
+        * 2. When selq->htb_maj_id becomes 0, synchronize_rcu waits for
         *    mlx5e_select_queue to finish while holding priv->state_lock,
         *    preventing other code from changing the number of queues.
         */
        struct mlx5e_qos_node *node = NULL;
        int bkt, err;
 
-       if (!priv->htb.maj_id)
+       if (!mlx5e_selq_is_htb_enabled(&priv->selq))
                return 0;
 
        err = mlx5e_qos_alloc_queues(priv, chs);
                return -EOPNOTSUPP;
        }
 
+       mlx5e_selq_prepare_htb(&priv->selq, htb_maj_id, htb_defcls);
+
        opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
        if (opened) {
-               mlx5e_selq_prepare(&priv->selq, &priv->channels.params, true);
-
                err = mlx5e_qos_alloc_queues(priv, &priv->channels);
                if (err)
                        goto err_cancel_selq;
                goto err_sw_node_delete;
        }
 
-       WRITE_ONCE(priv->htb.defcls, htb_defcls);
-       /* Order maj_id after defcls - pairs with
-        * mlx5e_select_queue/mlx5e_select_htb_queues.
-        */
-       smp_store_release(&priv->htb.maj_id, htb_maj_id);
-
-       if (opened)
-               mlx5e_selq_apply(&priv->selq);
+       mlx5e_selq_apply(&priv->selq);
 
        return 0;
 
         */
        synchronize_net();
 
-       mlx5e_selq_prepare(&priv->selq, &priv->channels.params, false);
+       mlx5e_selq_prepare_htb(&priv->selq, 0, 0);
        mlx5e_selq_apply(&priv->selq);
 
-       WRITE_ONCE(priv->htb.maj_id, 0);
-
        root = mlx5e_sw_node_find(priv, MLX5E_HTB_CLASSID_ROOT);
        if (!root) {
                qos_err(priv->mdev, "Failed to find the root node in the QoS tree\n");
 
                        bool is_ptp : 1;
                };
        };
+       u16 htb_maj_id;
+       u16 htb_defcls;
 };
 
 int mlx5e_selq_init(struct mlx5e_selq *selq, struct mutex *state_lock)
                .num_tcs = 1,
                .is_htb = false,
                .is_ptp = false,
+               .htb_maj_id = 0,
+               .htb_defcls = 0,
        };
        rcu_assign_pointer(selq->active, init_params);
 
        selq->standby = NULL;
 }
 
-void mlx5e_selq_prepare(struct mlx5e_selq *selq, struct mlx5e_params *params, bool htb)
+void mlx5e_selq_prepare_params(struct mlx5e_selq *selq, struct mlx5e_params *params)
 {
+       struct mlx5e_selq_params *selq_active;
+
        lockdep_assert_held(selq->state_lock);
        WARN_ON_ONCE(selq->is_prepared);
 
        selq->is_prepared = true;
 
+       selq_active = rcu_dereference_protected(selq->active,
+                                               lockdep_is_held(selq->state_lock));
+       *selq->standby = *selq_active;
        selq->standby->num_channels = params->num_channels;
        selq->standby->num_tcs = mlx5e_get_dcb_num_tc(params);
        selq->standby->num_regular_queues =
                selq->standby->num_channels * selq->standby->num_tcs;
-       selq->standby->is_htb = htb;
        selq->standby->is_ptp = MLX5E_GET_PFLAG(params, MLX5E_PFLAG_TX_PORT_TS);
 }
 
+bool mlx5e_selq_is_htb_enabled(struct mlx5e_selq *selq)
+{
+       struct mlx5e_selq_params *selq_active =
+               rcu_dereference_protected(selq->active, lockdep_is_held(selq->state_lock));
+
+       return selq_active->htb_maj_id;
+}
+
+void mlx5e_selq_prepare_htb(struct mlx5e_selq *selq, u16 htb_maj_id, u16 htb_defcls)
+{
+       struct mlx5e_selq_params *selq_active;
+
+       lockdep_assert_held(selq->state_lock);
+       WARN_ON_ONCE(selq->is_prepared);
+
+       selq->is_prepared = true;
+
+       selq_active = rcu_dereference_protected(selq->active,
+                                               lockdep_is_held(selq->state_lock));
+       *selq->standby = *selq_active;
+       selq->standby->is_htb = htb_maj_id;
+       selq->standby->htb_maj_id = htb_maj_id;
+       selq->standby->htb_defcls = htb_defcls;
+}
+
 void mlx5e_selq_apply(struct mlx5e_selq *selq)
 {
        struct mlx5e_selq_params *old_params;
        return selq->num_regular_queues + up;
 }
 
-static int mlx5e_select_htb_queue(struct mlx5e_priv *priv, struct sk_buff *skb)
+static int mlx5e_select_htb_queue(struct mlx5e_priv *priv, struct sk_buff *skb,
+                                 struct mlx5e_selq_params *selq)
 {
        u16 classid;
 
        /* Order maj_id before defcls - pairs with mlx5e_htb_root_add. */
-       if ((TC_H_MAJ(skb->priority) >> 16) == smp_load_acquire(&priv->htb.maj_id))
+       if ((TC_H_MAJ(skb->priority) >> 16) == selq->htb_maj_id)
                classid = TC_H_MIN(skb->priority);
        else
-               classid = READ_ONCE(priv->htb.defcls);
+               classid = selq->htb_defcls;
 
        if (!classid)
                return 0;
                        up * selq->num_channels;
        }
 
-       if (unlikely(selq->is_htb)) {
+       if (unlikely(selq->htb_maj_id)) {
                /* num_tcs == 1, shortcut for PTP */
 
-               txq_ix = mlx5e_select_htb_queue(priv, skb);
+               txq_ix = mlx5e_select_htb_queue(priv, skb, selq);
                if (txq_ix > 0)
                        return txq_ix;
 
 
 
 int mlx5e_selq_init(struct mlx5e_selq *selq, struct mutex *state_lock);
 void mlx5e_selq_cleanup(struct mlx5e_selq *selq);
-void mlx5e_selq_prepare(struct mlx5e_selq *selq, struct mlx5e_params *params, bool htb);
+void mlx5e_selq_prepare_params(struct mlx5e_selq *selq, struct mlx5e_params *params);
+void mlx5e_selq_prepare_htb(struct mlx5e_selq *selq, u16 htb_maj_id, u16 htb_defcls);
+bool mlx5e_selq_is_htb_enabled(struct mlx5e_selq *selq);
 void mlx5e_selq_apply(struct mlx5e_selq *selq);
 void mlx5e_selq_cancel(struct mlx5e_selq *selq);
 
 
         * because the numeration of the QoS SQs will change, while per-queue
         * qdiscs are attached.
         */
-       if (priv->htb.maj_id) {
+       if (mlx5e_selq_is_htb_enabled(&priv->selq)) {
                err = -EINVAL;
                netdev_err(priv->netdev, "%s: HTB offload is active, cannot change the number of channels\n",
                           __func__);
         * the numeration of the QoS SQs will change, while per-queue qdiscs are
         * attached.
         */
-       if (priv->htb.maj_id) {
+       if (mlx5e_selq_is_htb_enabled(&priv->selq)) {
                netdev_err(priv->netdev, "%s: HTB offload is active, cannot change the PTP state\n",
                           __func__);
                return -EINVAL;
 
 
        new_chs.params = *params;
 
-       mlx5e_selq_prepare(&priv->selq, &new_chs.params, !!priv->htb.maj_id);
+       mlx5e_selq_prepare_params(&priv->selq, &new_chs.params);
 
        err = mlx5e_open_channels(priv, &new_chs);
        if (err)
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
 
-       mlx5e_selq_prepare(&priv->selq, &priv->channels.params, !!priv->htb.maj_id);
+       mlx5e_selq_prepare_params(&priv->selq, &priv->channels.params);
 
        set_bit(MLX5E_STATE_OPENED, &priv->state);
 
        /* MQPRIO is another toplevel qdisc that can't be attached
         * simultaneously with the offloaded HTB.
         */
-       if (WARN_ON(priv->htb.maj_id))
+       if (WARN_ON(mlx5e_selq_is_htb_enabled(&priv->selq)))
                return -EINVAL;
 
        switch (mqprio->mode) {
 static int set_feature_hw_tc(struct net_device *netdev, bool enable)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
+       int err = 0;
 
 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
        if (!enable && mlx5e_tc_num_filters(priv, MLX5_TC_FLAG(NIC_OFFLOAD))) {
        }
 #endif
 
-       if (!enable && priv->htb.maj_id) {
+       mutex_lock(&priv->state_lock);
+       if (!enable && mlx5e_selq_is_htb_enabled(&priv->selq)) {
                netdev_err(netdev, "Active HTB offload, can't turn hw_tc_offload off\n");
-               return -EINVAL;
+               err = -EINVAL;
        }
+       mutex_unlock(&priv->state_lock);
 
-       return 0;
+       return err;
 }
 
 static int set_feature_rx_all(struct net_device *netdev, bool enable)