Commit 82ebc57e authored by Ido Shamay's avatar Ido Shamay Committed by Kamal Mostafa

net/mlx4_en: Wake TX queues only when there's enough room

[ Upstream commit 488a9b48 ]

Indication of a single completed packet, marked by txbbs_skipped
being bigger then zero, in not enough in order to wake up a
stopped TX queue. The completed packet may contain a single TXBB,
while next packet to be sent (after the wake up) may have multiple
TXBBs (LSO/TSO packets for example), causing overflow in queue followed
by WQE corruption and TX queue timeout.
Instead, wake the stopped queue only when there's enough room for the
worst case (maximum sized WQE) packet that we should need to handle after
the queue is opened again.

Also created an helper routine - mlx4_en_is_tx_ring_full, which checks
if the current TX ring is full or not. It provides better code readability
and removes code duplication.
Signed-off-by: default avatarIdo Shamay <idos@mellanox.com>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 363f6210
...@@ -66,6 +66,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ...@@ -66,6 +66,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
ring->size = size; ring->size = size;
ring->size_mask = size - 1; ring->size_mask = size - 1;
ring->stride = stride; ring->stride = stride;
ring->full_size = ring->size - HEADROOM - MAX_DESC_TXBBS;
tmp = size * sizeof(struct mlx4_en_tx_info); tmp = size * sizeof(struct mlx4_en_tx_info);
ring->tx_info = kmalloc_node(tmp, GFP_KERNEL | __GFP_NOWARN, node); ring->tx_info = kmalloc_node(tmp, GFP_KERNEL | __GFP_NOWARN, node);
...@@ -232,6 +233,11 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, ...@@ -232,6 +233,11 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp); MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp);
} }
static inline bool mlx4_en_is_tx_ring_full(struct mlx4_en_tx_ring *ring)
{
return ring->prod - ring->cons > ring->full_size;
}
static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv, static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring, int index, struct mlx4_en_tx_ring *ring, int index,
u8 owner) u8 owner)
...@@ -474,11 +480,10 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev, ...@@ -474,11 +480,10 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev,
netdev_tx_completed_queue(ring->tx_queue, packets, bytes); netdev_tx_completed_queue(ring->tx_queue, packets, bytes);
/* /* Wakeup Tx queue if this stopped, and ring is not full.
* Wakeup Tx queue if this stopped, and at least 1 packet
* was completed
*/ */
if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) { if (netif_tx_queue_stopped(ring->tx_queue) &&
!mlx4_en_is_tx_ring_full(ring)) {
netif_tx_wake_queue(ring->tx_queue); netif_tx_wake_queue(ring->tx_queue);
ring->wake_queue++; ring->wake_queue++;
} }
...@@ -922,8 +927,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -922,8 +927,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
/* Check available TXBBs And 2K spare for prefetch */ /* Check available TXBBs And 2K spare for prefetch */
stop_queue = (int)(ring->prod - ring_cons) > stop_queue = mlx4_en_is_tx_ring_full(ring);
ring->size - HEADROOM - MAX_DESC_TXBBS;
if (unlikely(stop_queue)) { if (unlikely(stop_queue)) {
netif_tx_stop_queue(ring->tx_queue); netif_tx_stop_queue(ring->tx_queue);
ring->queue_stopped++; ring->queue_stopped++;
...@@ -992,8 +996,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -992,8 +996,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
smp_rmb(); smp_rmb();
ring_cons = ACCESS_ONCE(ring->cons); ring_cons = ACCESS_ONCE(ring->cons);
if (unlikely(((int)(ring->prod - ring_cons)) <= if (unlikely(!mlx4_en_is_tx_ring_full(ring))) {
ring->size - HEADROOM - MAX_DESC_TXBBS)) {
netif_tx_wake_queue(ring->tx_queue); netif_tx_wake_queue(ring->tx_queue);
ring->wake_queue++; ring->wake_queue++;
} }
......
...@@ -280,6 +280,7 @@ struct mlx4_en_tx_ring { ...@@ -280,6 +280,7 @@ struct mlx4_en_tx_ring {
u32 size; /* number of TXBBs */ u32 size; /* number of TXBBs */
u32 size_mask; u32 size_mask;
u16 stride; u16 stride;
u32 full_size;
u16 cqn; /* index of port CQ associated with this ring */ u16 cqn; /* index of port CQ associated with this ring */
u32 buf_size; u32 buf_size;
__be32 doorbell_qpn; __be32 doorbell_qpn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment