#include <linux/dim.h>
 #include <linux/ethtool_netlink.h>
+#include <net/netdev_queues.h>
 
 #include "en.h"
 #include "en/channels.h"
        param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
        param->rx_pending     = 1 << priv->channels.params.log_rq_mtu_frames;
        param->tx_pending     = 1 << priv->channels.params.log_sq_size;
-
-       kernel_param->tcp_data_split =
-               (priv->channels.params.packet_merge.type == MLX5E_PACKET_MERGE_SHAMPO) ?
-               ETHTOOL_TCP_DATA_SPLIT_ENABLED :
-               ETHTOOL_TCP_DATA_SPLIT_DISABLED;
 }
 
 static void mlx5e_get_ringparam(struct net_device *dev,
        mlx5e_ethtool_get_ringparam(priv, param, kernel_param);
 }
 
+static bool mlx5e_ethtool_set_tcp_data_split(struct mlx5e_priv *priv,
+                                            u8 tcp_data_split,
+                                            struct netlink_ext_ack *extack)
+{
+       struct net_device *dev = priv->netdev;
+
+       if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
+           !(dev->features & NETIF_F_GRO_HW)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "TCP-data-split is not supported when GRO HW is disabled");
+               return false;
+       }
+
+       /* Might need to disable HW-GRO if it was kept on due to hds. */
+       if (tcp_data_split == ETHTOOL_TCP_DATA_SPLIT_DISABLED &&
+           dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED)
+               netdev_update_features(priv->netdev);
+
+       return true;
+}
+
 int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv,
                                struct ethtool_ringparam *param,
                                struct netlink_ext_ack *extack)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
 
+       if (!mlx5e_ethtool_set_tcp_data_split(priv,
+                                             kernel_param->tcp_data_split,
+                                             extack))
+               return -EINVAL;
+
        return mlx5e_ethtool_set_ringparam(priv, param, extack);
 }
 
                                     ETHTOOL_COALESCE_USE_ADAPTIVE |
                                     ETHTOOL_COALESCE_USE_CQE,
        .supported_input_xfrm = RXH_XFRM_SYM_OR_XOR,
+       .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT,
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
        .get_link_ext_state  = mlx5e_get_link_ext_state,
 
 static netdev_features_t mlx5e_fix_features(struct net_device *netdev,
                                            netdev_features_t features)
 {
+       struct netdev_config *cfg = netdev->cfg_pending;
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5e_vlan_table *vlan;
        struct mlx5e_params *params;
                }
        }
 
+       /* The header-data split ring param requires HW GRO to stay enabled. */
+       if (cfg && cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_ENABLED &&
+           !(features & NETIF_F_GRO_HW)) {
+               netdev_warn(netdev, "Keeping HW-GRO enabled, TCP header-data split depends on it\n");
+               features |= NETIF_F_GRO_HW;
+       }
+
        if (mlx5e_is_uplink_rep(priv)) {
                features = mlx5e_fix_uplink_rep_features(netdev, features);
                netdev->netns_immutable = true;