net: aquantia: fix LRO with FCS error [Linux 4.14.129]

net: aquantia: fix LRO with FCS error [Linux 4.14.129]

This Linux kernel change "net: aquantia: fix LRO with FCS error" is included in the Linux 4.14.129 release. This change is authored by Dmitry Bogdanov <dmitry.bogdanov [at] aquantia.com> on Sat May 25 09:58:03 2019 +0000. The commit for this change in Linux stable tree is d704ffa (patch) which is from upstream commit eaeb3b7. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream eaeb3b7.

net: aquantia: fix LRO with FCS error

[ Upstream commit eaeb3b7494ba9159323814a8ce8af06a9277d99b ]

Driver stops producing skbs on ring if a packet with FCS error
was coalesced into LRO session. Ring gets hang forever.

Thats a logical error in driver processing descriptors:
When rx_stat indicates MAC Error, next pointer and eop flags
are not filled. This confuses driver so it waits for descriptor 0
to be filled by HW.

Solution is fill next pointer and eop flag even for packets with FCS error.

Fixes: bab6de8fd180b ("net: ethernet: aquantia: Atlantic A0 and B0 specific functions.")
Signed-off-by: Igor Russkikh <[email protected]>
Signed-off-by: Dmitry Bogdanov <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>

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

 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c  | 61 ++++++++++++----------
 1 file changed, 32 insertions(+), 29 deletions(-)

diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
index f4b3554..236325f 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c
@@ -683,38 +683,41 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
        if (is_err || rxd_wb->type & 0x1000U) {
            /* status error or DMA error */
            buff->is_error = 1U;
-       } else {
-           if (self->aq_nic_cfg->is_rss) {
-               /* last 4 byte */
-               u16 rss_type = rxd_wb->type & 0xFU;
-
-               if (rss_type && rss_type < 0x8U) {
-                   buff->is_hash_l4 = (rss_type == 0x4 ||
-                   rss_type == 0x5);
-                   buff->rss_hash = rxd_wb->rss_hash;
-               }
+       }
+       if (self->aq_nic_cfg->is_rss) {
+           /* last 4 byte */
+           u16 rss_type = rxd_wb->type & 0xFU;
+
+           if (rss_type && rss_type < 0x8U) {
+               buff->is_hash_l4 = (rss_type == 0x4 ||
+               rss_type == 0x5);
+               buff->rss_hash = rxd_wb->rss_hash;
            }
+       }

-           if (HW_ATL_B0_RXD_WB_STAT2_EOP & rxd_wb->status) {
-               buff->len = rxd_wb->pkt_len %
-                   AQ_CFG_RX_FRAME_MAX;
-               buff->len = buff->len ?
-                   buff->len : AQ_CFG_RX_FRAME_MAX;
-               buff->next = 0U;
-               buff->is_eop = 1U;
+       if (HW_ATL_B0_RXD_WB_STAT2_EOP & rxd_wb->status) {
+           buff->len = rxd_wb->pkt_len %
+               AQ_CFG_RX_FRAME_MAX;
+           buff->len = buff->len ?
+               buff->len : AQ_CFG_RX_FRAME_MAX;
+           buff->next = 0U;
+           buff->is_eop = 1U;
+       } else {
+           buff->len =
+               rxd_wb->pkt_len > AQ_CFG_RX_FRAME_MAX ?
+               AQ_CFG_RX_FRAME_MAX : rxd_wb->pkt_len;
+
+           if (HW_ATL_B0_RXD_WB_STAT2_RSCCNT &
+               rxd_wb->status) {
+               /* LRO */
+               buff->next = rxd_wb->next_desc_ptr;
+               ++ring->stats.rx.lro_packets;
            } else {
-               if (HW_ATL_B0_RXD_WB_STAT2_RSCCNT &
-                   rxd_wb->status) {
-                   /* LRO */
-                   buff->next = rxd_wb->next_desc_ptr;
-                   ++ring->stats.rx.lro_packets;
-               } else {
-                   /* jumbo */
-                   buff->next =
-                       aq_ring_next_dx(ring,
-                               ring->hw_head);
-                   ++ring->stats.rx.jumbo_packets;
-               }
+               /* jumbo */
+               buff->next =
+                   aq_ring_next_dx(ring,
+                           ring->hw_head);
+               ++ring->stats.rx.jumbo_packets;
            }
        }
    }

Leave a Reply

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