]>
Commit | Line | Data |
---|---|---|
a15a8890 SL |
1 | From 5122b5d03f515f5cec1429414a7a3b66c8f83027 Mon Sep 17 00:00:00 2001 |
2 | From: Igor Russkikh <Igor.Russkikh@aquantia.com> | |
3 | Date: Sat, 25 May 2019 09:57:59 +0000 | |
4 | Subject: net: aquantia: tx clean budget logic error | |
5 | ||
6 | [ Upstream commit 31bafc49a7736989e4c2d9f7280002c66536e590 ] | |
7 | ||
8 | In case no other traffic happening on the ring, full tx cleanup | |
9 | may not be completed. That may cause socket buffer to overflow | |
10 | and tx traffic to stuck until next activity on the ring happens. | |
11 | ||
12 | This is due to logic error in budget variable decrementor. | |
13 | Variable is compared with zero, and then post decremented, | |
14 | causing it to become MAX_INT. Solution is remove decrementor | |
15 | from the `for` statement and rewrite it in a clear way. | |
16 | ||
17 | Fixes: b647d3980948e ("net: aquantia: Add tx clean budget and valid budget handling logic") | |
18 | Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> | |
19 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
20 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
21 | --- | |
22 | drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 7 ++++--- | |
23 | 1 file changed, 4 insertions(+), 3 deletions(-) | |
24 | ||
25 | diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c | |
26 | index 6f3312350cac..b3c7994d73eb 100644 | |
27 | --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c | |
28 | +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c | |
29 | @@ -139,10 +139,10 @@ void aq_ring_queue_stop(struct aq_ring_s *ring) | |
30 | bool aq_ring_tx_clean(struct aq_ring_s *self) | |
31 | { | |
32 | struct device *dev = aq_nic_get_dev(self->aq_nic); | |
33 | - unsigned int budget = AQ_CFG_TX_CLEAN_BUDGET; | |
34 | + unsigned int budget; | |
35 | ||
36 | - for (; self->sw_head != self->hw_head && budget--; | |
37 | - self->sw_head = aq_ring_next_dx(self, self->sw_head)) { | |
38 | + for (budget = AQ_CFG_TX_CLEAN_BUDGET; | |
39 | + budget && self->sw_head != self->hw_head; budget--) { | |
40 | struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; | |
41 | ||
42 | if (likely(buff->is_mapped)) { | |
43 | @@ -167,6 +167,7 @@ bool aq_ring_tx_clean(struct aq_ring_s *self) | |
44 | ||
45 | buff->pa = 0U; | |
46 | buff->eop_index = 0xffffU; | |
47 | + self->sw_head = aq_ring_next_dx(self, self->sw_head); | |
48 | } | |
49 | ||
50 | return !!budget; | |
51 | -- | |
52 | 2.20.1 | |
53 |