It is recommended that TX work not count against the quota.
The cost of TX packet liberation is a minute percentage of what it costs to
process an RX frame. Furthermore, that SKB freeing makes memory available for
other paths in the stack.
Give the TX a larger budget and be more aggressive about cleaning up the Tx
descriptors this budget could be changed using ethtool:
$ ethtool -C eth1 tx-frames-irq <budget>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
 
        coal->tx_coalesce_usecs = priv->tx_usecs;
        coal->tx_max_coalesced_frames = priv->tx_frames;
+       coal->tx_max_coalesced_frames_irq = priv->tx_work_limit;
+
        coal->rx_coalesce_usecs = priv->rx_usecs;
        coal->rx_max_coalesced_frames = priv->rx_frames;
 
        coal->rx_coalesce_usecs_high = priv->rx_usecs_high;
        coal->rate_sample_interval = priv->sample_interval;
        coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal;
+
        return 0;
 }
 
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
 
+       if (!coal->tx_max_coalesced_frames_irq)
+               return -EINVAL;
+
        priv->rx_frames = (coal->rx_max_coalesced_frames ==
                           MLX4_EN_AUTO_CONF) ?
                                MLX4_EN_RX_COAL_TARGET :
        priv->rx_usecs_high = coal->rx_coalesce_usecs_high;
        priv->sample_interval = coal->rate_sample_interval;
        priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce;
+       priv->tx_work_limit = coal->tx_max_coalesced_frames_irq;
 
        return mlx4_en_moderation_update(priv);
 }
 
                        MLX4_WQE_CTRL_SOLICITED);
        priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up;
        priv->tx_ring_num = prof->tx_ring_num;
+       priv->tx_work_limit = MLX4_EN_DEFAULT_TX_WORK;
 
        priv->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring *) * MAX_TX_RINGS,
                                GFP_KERNEL);
 
        return cnt;
 }
 
-static int mlx4_en_process_tx_cq(struct net_device *dev,
-                                struct mlx4_en_cq *cq,
-                                int budget)
+static bool mlx4_en_process_tx_cq(struct net_device *dev,
+                                struct mlx4_en_cq *cq)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_cq *mcq = &cq->mcq;
        int factor = priv->cqe_factor;
        u64 timestamp = 0;
        int done = 0;
+       int budget = priv->tx_work_limit;
 
        if (!priv->port_up)
-               return 0;
+               return true;
 
        index = cons_index & size_mask;
        cqe = &buf[(index << factor) + factor];
                netif_tx_wake_queue(ring->tx_queue);
                ring->wake_queue++;
        }
-       return done;
+       return done < budget;
 }
 
 void mlx4_en_tx_irq(struct mlx4_cq *mcq)
        struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
        struct net_device *dev = cq->dev;
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       int done;
+       int clean_complete;
 
-       done = mlx4_en_process_tx_cq(dev, cq, budget);
+       clean_complete = mlx4_en_process_tx_cq(dev, cq);
+       if (!clean_complete)
+               return budget;
 
-       /* If we used up all the quota - we're probably not done yet... */
-       if (done < budget) {
-               /* Done for now */
-               napi_complete(napi);
-               mlx4_en_arm_cq(priv, cq);
-               return done;
-       }
-       return budget;
+       napi_complete(napi);
+       mlx4_en_arm_cq(priv, cq);
+
+       return 0;
 }
 
 static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
 
 #define MAX_TX_RINGS                   (MLX4_EN_MAX_TX_RING_P_UP * \
                                         MLX4_EN_NUM_UP)
 
+#define MLX4_EN_DEFAULT_TX_WORK                256
+
 /* Target number of packets to coalesce with interrupt moderation */
 #define MLX4_EN_RX_COAL_TARGET 44
 #define MLX4_EN_RX_COAL_TIME   0x10
        __be32 ctrl_flags;
        u32 flags;
        u8 num_tx_rings_p_up;
+       u32 tx_work_limit;
        u32 tx_ring_num;
        u32 rx_ring_num;
        u32 rx_skb_size;