lan743x: Fix TX Stall Issue [Linux 5.0]

lan743x: Fix TX Stall Issue [Linux 5.0]

This Linux kernel change "lan743x: Fix TX Stall Issue" is included in the Linux 5.0 release. This change is authored by Bryan Whitehead <Bryan.Whitehead [at] microchip.com> on Tue Feb 26 14:06:26 2019 -0500. The commit for this change in Linux stable tree is 90490ef (patch).

lan743x: Fix TX Stall Issue

It has been observed that tx queue stalls while downloading
from certain web sites (example www.speedtest.net)

The cause has been tracked down to a corner case where
dma descriptors where not setup properly. And there for a tx
completion interrupt was not signaled.

This fix corrects the problem by properly marking the end of
a multi descriptor transmission.

Fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver")
Signed-off-by: Bryan Whitehead <[email protected]>
Signed-off-by: David S. Miller <[email protected]>

There are 16 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/ethernet/microchip/lan743x_main.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 310807e..4d1b4a2 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1400,7 +1400,8 @@ static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 }

 static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
-                    unsigned int frame_length)
+                    unsigned int frame_length,
+                    int nr_frags)
 {
    /* called only from within lan743x_tx_xmit_frame.
     * assuming tx->ring_lock has already been acquired.
@@ -1410,6 +1411,10 @@ static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,

    /* wrap up previous descriptor */
    tx->frame_data0 |= TX_DESC_DATA0_EXT_;
+   if (nr_frags <= 0) {
+       tx->frame_data0 |= TX_DESC_DATA0_LS_;
+       tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+   }
    tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
    tx_descriptor->data0 = tx->frame_data0;

@@ -1514,8 +1519,11 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx,
    u32 tx_tail_flags = 0;

    /* wrap up previous descriptor */
-   tx->frame_data0 |= TX_DESC_DATA0_LS_;
-   tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+   if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) ==
+       TX_DESC_DATA0_DTYPE_DATA_) {
+       tx->frame_data0 |= TX_DESC_DATA0_LS_;
+       tx->frame_data0 |= TX_DESC_DATA0_IOC_;
+   }

    tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
    buffer_info = &tx->buffer_info[tx->frame_tail];
@@ -1600,7 +1608,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
    }

    if (gso)
-       lan743x_tx_frame_add_lso(tx, frame_length);
+       lan743x_tx_frame_add_lso(tx, frame_length, nr_frags);

    if (nr_frags <= 0)
        goto finish;

Leave a Reply

Your email address will not be published. Required fields are marked *