mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
65 lines
2.5 KiB
Diff
65 lines
2.5 KiB
Diff
|
From d0055b03d9c8d48ad2b971821989b09ba95c39f8 Mon Sep 17 00:00:00 2001
|
||
|
From: Christian Marangi <ansuelsmth@gmail.com>
|
||
|
Date: Sun, 17 Sep 2023 20:18:31 +0200
|
||
|
Subject: [PATCH] net: qualcomm: ipqess: fix TX timeout errors
|
||
|
|
||
|
Currently logic to handle napi tx completion is flawed and on the long
|
||
|
run on loaded condition cause TX timeout error with the queue not being
|
||
|
able to handle any new packet.
|
||
|
|
||
|
There are 2 main cause of this:
|
||
|
- incrementing the packet done value wrongly
|
||
|
- handling 2 times the tx_ring tail
|
||
|
|
||
|
ipqess_tx_unmap_and_free may return 2 kind values:
|
||
|
- 0: we are handling first and middle descriptor for the packet
|
||
|
- packet len: we are at the last descriptor for the packet
|
||
|
|
||
|
Done value was wrongly incremented also for first and intermediate
|
||
|
descriptor for the packet resulting causing panic and TX timeouts by
|
||
|
comunicating to the kernel an inconsistent value of packet handling not
|
||
|
matching the expected ones.
|
||
|
|
||
|
Tx_ring tail was handled twice for ipqess_tx_complete run resulting in
|
||
|
again done value incremented wrongly and also problem with idx handling
|
||
|
by actually skipping descriptor for some packets.
|
||
|
|
||
|
Rework the loop logic to fix these 2 problem and also add some comments
|
||
|
to make sure ipqess_tx_unmap_and_free ret value is better
|
||
|
understandable.
|
||
|
|
||
|
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||
|
---
|
||
|
drivers/net/ethernet/qualcomm/ipqess/ipqess.c | 13 ++++++++++---
|
||
|
1 file changed, 10 insertions(+), 3 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
|
||
|
+++ b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
|
||
|
@@ -453,13 +453,22 @@ static int ipqess_tx_complete(struct ipq
|
||
|
tail >>= IPQESS_TPD_CONS_IDX_SHIFT;
|
||
|
tail &= IPQESS_TPD_CONS_IDX_MASK;
|
||
|
|
||
|
- do {
|
||
|
+ while ((tx_ring->tail != tail) && (done < budget)) {
|
||
|
ret = ipqess_tx_unmap_and_free(&tx_ring->ess->pdev->dev,
|
||
|
&tx_ring->buf[tx_ring->tail]);
|
||
|
- tx_ring->tail = IPQESS_NEXT_IDX(tx_ring->tail, tx_ring->count);
|
||
|
+ /* ipqess_tx_unmap_and_free may return 2 kind values:
|
||
|
+ * - 0: we are handling first and middle descriptor for the packet
|
||
|
+ * - packet len: we are at the last descriptor for the packet
|
||
|
+ * Increment total bytes handled and packet done only if we are
|
||
|
+ * handling the last descriptor for the packet.
|
||
|
+ */
|
||
|
+ if (ret) {
|
||
|
+ total += ret;
|
||
|
+ done++;
|
||
|
+ }
|
||
|
|
||
|
- total += ret;
|
||
|
- } while ((++done < budget) && (tx_ring->tail != tail));
|
||
|
+ tx_ring->tail = IPQESS_NEXT_IDX(tx_ring->tail, tx_ring->count);
|
||
|
+ };
|
||
|
|
||
|
ipqess_w32(tx_ring->ess, IPQESS_REG_TX_SW_CONS_IDX_Q(tx_ring->idx),
|
||
|
tx_ring->tail);
|