#define GVE_DEALLOCATE_COMPL_TIMEOUT 60
 
 netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
+netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
+                                        struct net_device *dev,
+                                        netdev_features_t features);
 bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
 int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
 int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
 
        return err;
 }
 
+static netdev_features_t gve_features_check(struct sk_buff *skb,
+                                           struct net_device *dev,
+                                           netdev_features_t features)
+{
+       struct gve_priv *priv = netdev_priv(dev);
+
+       if (!gve_is_gqi(priv))
+               return gve_features_check_dqo(skb, dev, features);
+
+       return features;
+}
+
 static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct gve_priv *priv = netdev_priv(dev);
 
 static const struct net_device_ops gve_netdev_ops = {
        .ndo_start_xmit         =       gve_start_xmit,
+       .ndo_features_check     =       gve_features_check,
        .ndo_open               =       gve_open,
        .ndo_stop               =       gve_close,
        .ndo_get_stats64        =       gve_get_stats,
 
        return true;
 }
 
+netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
+                                        struct net_device *dev,
+                                        netdev_features_t features)
+{
+       if (skb_is_gso(skb) && !gve_can_send_tso(skb))
+               return features & ~NETIF_F_GSO_MASK;
+
+       return features;
+}
+
 /* Attempt to transmit specified SKB.
  *
  * Returns 0 if the SKB was transmitted or dropped.
        int num_buffer_descs;
        int total_num_descs;
 
-       if (tx->dqo.qpl) {
-               if (skb_is_gso(skb))
-                       if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
-                               goto drop;
+       if (skb_is_gso(skb) && unlikely(ipv6_hopopt_jumbo_remove(skb)))
+               goto drop;
 
+       if (tx->dqo.qpl) {
                /* We do not need to verify the number of buffers used per
                 * packet or per segment in case of TSO as with 2K size buffers
                 * none of the TX packet rules would be violated.
                 */
                num_buffer_descs = DIV_ROUND_UP(skb->len, GVE_TX_BUF_SIZE_DQO);
        } else {
-               if (skb_is_gso(skb)) {
-                       /* If TSO doesn't meet HW requirements, attempt to linearize the
-                        * packet.
-                        */
-                       if (unlikely(!gve_can_send_tso(skb) &&
-                                    skb_linearize(skb) < 0)) {
-                               net_err_ratelimited("%s: Failed to transmit TSO packet\n",
-                                                   priv->dev->name);
-                               goto drop;
-                       }
-
-                       if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
-                               goto drop;
-
-                       num_buffer_descs = gve_num_buffer_descs_needed(skb);
-               } else {
-                       num_buffer_descs = gve_num_buffer_descs_needed(skb);
-
+               num_buffer_descs = gve_num_buffer_descs_needed(skb);
+               if (!skb_is_gso(skb)) {
                        if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) {
                                if (unlikely(skb_linearize(skb) < 0))
                                        goto drop;