summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Russkikh <Igor.Russkikh@aquantia.com>2019-05-25 09:57:59 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-06-22 08:15:17 +0200
commit388534d45f04058f19f6f673226b82413bb4c133 (patch)
tree6c48d51f6bd323a6dc0eed6e1d869ed3195ff59e
parentb7ca3f331d5777f0a997e4d3b58ca9248a263705 (diff)
downloadlinux-rpi3-388534d45f04058f19f6f673226b82413bb4c133.tar.gz
linux-rpi3-388534d45f04058f19f6f673226b82413bb4c133.tar.bz2
linux-rpi3-388534d45f04058f19f6f673226b82413bb4c133.zip
net: aquantia: tx clean budget logic error
[ Upstream commit 31bafc49a7736989e4c2d9f7280002c66536e590 ] In case no other traffic happening on the ring, full tx cleanup may not be completed. That may cause socket buffer to overflow and tx traffic to stuck until next activity on the ring happens. This is due to logic error in budget variable decrementor. Variable is compared with zero, and then post decremented, causing it to become MAX_INT. Solution is remove decrementor from the `for` statement and rewrite it in a clear way. Fixes: b647d3980948e ("net: aquantia: Add tx clean budget and valid budget handling logic") Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 6f3312350cac..b3c7994d73eb 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -139,10 +139,10 @@ void aq_ring_queue_stop(struct aq_ring_s *ring)
bool aq_ring_tx_clean(struct aq_ring_s *self)
{
struct device *dev = aq_nic_get_dev(self->aq_nic);
- unsigned int budget = AQ_CFG_TX_CLEAN_BUDGET;
+ unsigned int budget;
- for (; self->sw_head != self->hw_head && budget--;
- self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
+ for (budget = AQ_CFG_TX_CLEAN_BUDGET;
+ budget && self->sw_head != self->hw_head; budget--) {
struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
if (likely(buff->is_mapped)) {
@@ -167,6 +167,7 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
buff->pa = 0U;
buff->eop_index = 0xffffU;
+ self->sw_head = aq_ring_next_dx(self, self->sw_head);
}
return !!budget;