net: aquantia: check rx csum for all packets in LRO session
authorDmitry Bogdanov <dmitry.bogdanov@aquantia.com>
Sat, 25 May 2019 09:58:01 +0000 (09:58 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 May 2019 17:24:14 +0000 (10:24 -0700)
Atlantic hardware does not aggregate nor breaks LRO sessions
with bad csum packets. This means driver should take care of that.

If in LRO session there is a non-first descriptor with invalid
checksum (L2/L3/L4), the driver must account this information
in csum application logic.

Fixes: 018423e90bee8 ("net: ethernet: aquantia: Add ring support code")
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>
drivers/net/ethernet/aquantia/atlantic/aq_ring.c

index 63ed004159042d4ce6fea7cd762a67a73cc85f66..941b0beb87efa156c9698e7ac1a34c240374a256 100644 (file)
@@ -299,35 +299,47 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                unsigned int i = 0U;
                u16 hdr_len;
 
-               if (buff->is_error)
-                       continue;
-
                if (buff->is_cleaned)
                        continue;
 
                if (!buff->is_eop) {
-                       for (next_ = buff->next,
-                            buff_ = &self->buff_ring[next_]; true;
-                            next_ = buff_->next,
-                            buff_ = &self->buff_ring[next_]) {
+                       buff_ = buff;
+                       do {
+                               next_ = buff_->next,
+                               buff_ = &self->buff_ring[next_];
                                is_rsc_completed =
                                        aq_ring_dx_in_range(self->sw_head,
                                                            next_,
                                                            self->hw_head);
 
-                               if (unlikely(!is_rsc_completed)) {
-                                       is_rsc_completed = false;
+                               if (unlikely(!is_rsc_completed))
                                        break;
-                               }
 
-                               if (buff_->is_eop)
-                                       break;
-                       }
+                               buff->is_error |= buff_->is_error;
+
+                       } while (!buff_->is_eop);
 
                        if (!is_rsc_completed) {
                                err = 0;
                                goto err_exit;
                        }
+                       if (buff->is_error) {
+                               buff_ = buff;
+                               do {
+                                       next_ = buff_->next,
+                                       buff_ = &self->buff_ring[next_];
+
+                                       buff_->is_cleaned = true;
+                               } while (!buff_->is_eop);
+
+                               ++self->stats.rx.errors;
+                               continue;
+                       }
+               }
+
+               if (buff->is_error) {
+                       ++self->stats.rx.errors;
+                       continue;
                }
 
                dma_sync_single_range_for_cpu(aq_nic_get_dev(self->aq_nic),
@@ -390,6 +402,12 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
                                                        AQ_CFG_RX_FRAME_MAX);
                                        page_ref_inc(buff_->rxdata.page);
                                        buff_->is_cleaned = 1;
+
+                                       buff->is_ip_cso &= buff_->is_ip_cso;
+                                       buff->is_udp_cso &= buff_->is_udp_cso;
+                                       buff->is_tcp_cso &= buff_->is_tcp_cso;
+                                       buff->is_cso_err |= buff_->is_cso_err;
+
                                } while (!buff_->is_eop);
                        }
                }