net: aquantia: fix LRO with FCS error
authorDmitry Bogdanov <dmitry.bogdanov@aquantia.com>
Sat, 25 May 2019 09:58:03 +0000 (09:58 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 Jun 2019 06:16:17 +0000 (08:16 +0200)
[ 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 <igor.russkikh@aquantia.com>
Signed-off-by: Dmitry Bogdanov <dmitry.bogdanov@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c

index f4b3554b0b67bcff2c27318e1ce1c5c1c3fb6032..236325f48ec9befa14da52e41b7b0927014b94d2 100644 (file)
@@ -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;
                        }
                }
        }