aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Bogdanov <dmitry.bogdanov@aquantia.com>2018-11-09 06:54:01 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-09 18:38:10 -0500
commitad703c2b9127f9acdef697ec4755f6da4beaa266 (patch)
tree6413bae24bb34adff365b8fcef9d0e5a27cf683e
parentbfaa9f8553d5c20703781e63f4fc8cb4792f18fd (diff)
net: aquantia: invalid checksumm offload implementation
Packets with marked invalid IP/UDP/TCP checksums were considered as good by the driver. The error was in a logic, processing offload bits in RX descriptor. 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>
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.c35
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c36
2 files changed, 41 insertions, 30 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index 3db91446cc67..74550ccc7a20 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -172,6 +172,27 @@ bool aq_ring_tx_clean(struct aq_ring_s *self)
172 return !!budget; 172 return !!budget;
173} 173}
174 174
175static void aq_rx_checksum(struct aq_ring_s *self,
176 struct aq_ring_buff_s *buff,
177 struct sk_buff *skb)
178{
179 if (!(self->aq_nic->ndev->features & NETIF_F_RXCSUM))
180 return;
181
182 if (unlikely(buff->is_cso_err)) {
183 ++self->stats.rx.errors;
184 skb->ip_summed = CHECKSUM_NONE;
185 return;
186 }
187 if (buff->is_ip_cso) {
188 __skb_incr_checksum_unnecessary(skb);
189 if (buff->is_udp_cso || buff->is_tcp_cso)
190 __skb_incr_checksum_unnecessary(skb);
191 } else {
192 skb->ip_summed = CHECKSUM_NONE;
193 }
194}
195
175#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) 196#define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
176int aq_ring_rx_clean(struct aq_ring_s *self, 197int aq_ring_rx_clean(struct aq_ring_s *self,
177 struct napi_struct *napi, 198 struct napi_struct *napi,
@@ -267,18 +288,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
267 } 288 }
268 289
269 skb->protocol = eth_type_trans(skb, ndev); 290 skb->protocol = eth_type_trans(skb, ndev);
270 if (unlikely(buff->is_cso_err)) { 291
271 ++self->stats.rx.errors; 292 aq_rx_checksum(self, buff, skb);
272 skb->ip_summed = CHECKSUM_NONE;
273 } else {
274 if (buff->is_ip_cso) {
275 __skb_incr_checksum_unnecessary(skb);
276 if (buff->is_udp_cso || buff->is_tcp_cso)
277 __skb_incr_checksum_unnecessary(skb);
278 } else {
279 skb->ip_summed = CHECKSUM_NONE;
280 }
281 }
282 293
283 skb_set_hash(skb, buff->rss_hash, 294 skb_set_hash(skb, buff->rss_hash,
284 buff->is_hash_l4 ? PKT_HASH_TYPE_L4 : 295 buff->is_hash_l4 ? PKT_HASH_TYPE_L4 :
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 3aec56623bf5..179ce12fe4d8 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
@@ -660,9 +660,9 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
660 struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *) 660 struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *)
661 &ring->dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE]; 661 &ring->dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE];
662 662
663 unsigned int is_err = 1U;
664 unsigned int is_rx_check_sum_enabled = 0U; 663 unsigned int is_rx_check_sum_enabled = 0U;
665 unsigned int pkt_type = 0U; 664 unsigned int pkt_type = 0U;
665 u8 rx_stat = 0U;
666 666
667 if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */ 667 if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */
668 break; 668 break;
@@ -670,35 +670,35 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self,
670 670
671 buff = &ring->buff_ring[ring->hw_head]; 671 buff = &ring->buff_ring[ring->hw_head];
672 672
673 is_err = (0x0000003CU & rxd_wb->status); 673 rx_stat = (0x0000003CU & rxd_wb->status) >> 2;
674 674
675 is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19); 675 is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19);
676 is_err &= ~0x20U; /* exclude validity bit */
677 676
678 pkt_type = 0xFFU & (rxd_wb->type >> 4); 677 pkt_type = 0xFFU & (rxd_wb->type >> 4);
679 678
680 if (is_rx_check_sum_enabled) { 679 if (is_rx_check_sum_enabled & BIT(0) &&
681 if (0x0U == (pkt_type & 0x3U)) 680 (0x0U == (pkt_type & 0x3U)))
682 buff->is_ip_cso = (is_err & 0x08U) ? 0U : 1U; 681 buff->is_ip_cso = (rx_stat & BIT(1)) ? 0U : 1U;
683 682
683 if (is_rx_check_sum_enabled & BIT(1)) {
684 if (0x4U == (pkt_type & 0x1CU)) 684 if (0x4U == (pkt_type & 0x1CU))
685 buff->is_udp_cso = buff->is_cso_err ? 0U : 1U; 685 buff->is_udp_cso = (rx_stat & BIT(2)) ? 0U :
686 !!(rx_stat & BIT(3));
686 else if (0x0U == (pkt_type & 0x1CU)) 687 else if (0x0U == (pkt_type & 0x1CU))
687 buff->is_tcp_cso = buff->is_cso_err ? 0U : 1U; 688 buff->is_tcp_cso = (rx_stat & BIT(2)) ? 0U :
688 689 !!(rx_stat & BIT(3));
689 /* Checksum offload workaround for small packets */ 690 }
690 if (rxd_wb->pkt_len <= 60) { 691 buff->is_cso_err = !!(rx_stat & 0x6);
691 buff->is_ip_cso = 0U; 692 /* Checksum offload workaround for small packets */
692 buff->is_cso_err = 0U; 693 if (unlikely(rxd_wb->pkt_len <= 60)) {
693 } 694 buff->is_ip_cso = 0U;
695 buff->is_cso_err = 0U;
694 } 696 }
695
696 is_err &= ~0x18U;
697 697
698 dma_unmap_page(ndev, buff->pa, buff->len, DMA_FROM_DEVICE); 698 dma_unmap_page(ndev, buff->pa, buff->len, DMA_FROM_DEVICE);
699 699
700 if (is_err || rxd_wb->type & 0x1000U) { 700 if ((rx_stat & BIT(0)) || rxd_wb->type & 0x1000U) {
701 /* status error or DMA error */ 701 /* MAC error or DMA error */
702 buff->is_error = 1U; 702 buff->is_error = 1U;
703 } else { 703 } else {
704 if (self->aq_nic_cfg->is_rss) { 704 if (self->aq_nic_cfg->is_rss) {