diff options
author | Jesse Brandeburg <jesse.brandeburg@intel.com> | 2014-05-20 04:01:43 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-06-09 03:39:58 -0400 |
commit | 8a3c91cce3d32d3fa1e3b64d41b241103a62fd62 (patch) | |
tree | 385692000534fb57c95dcfac5eb95ae11ffa15f2 | |
parent | 9aa7e9355db342fda17d716bcf5ce62df7a02e61 (diff) |
i40e/i40evf: add PPRS bit to error bits and fix bug in Rx checksum
The driver was not marking packets with bad checksums
correctly, especially IPv6 packets with a bad checksum.
To do this correctly we need a define that may be set by
hardware in rare cases.
Change-ID: I1a997b72b491ded27a78ac3bce1197b2d2611130
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.c | 74 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_type.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 74 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_type.h | 3 |
5 files changed, 115 insertions, 40 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index df3917b68c99..b16c25111552 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c | |||
@@ -119,6 +119,7 @@ static struct i40e_stats i40e_gstrings_stats[] = { | |||
119 | I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), | 119 | I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), |
120 | I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), | 120 | I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), |
121 | I40E_PF_STAT("tx_timeout", tx_timeout_count), | 121 | I40E_PF_STAT("tx_timeout", tx_timeout_count), |
122 | I40E_PF_STAT("rx_csum_bad", hw_csum_rx_error), | ||
122 | I40E_PF_STAT("rx_length_errors", stats.rx_length_errors), | 123 | I40E_PF_STAT("rx_length_errors", stats.rx_length_errors), |
123 | I40E_PF_STAT("link_xon_rx", stats.link_xon_rx), | 124 | I40E_PF_STAT("link_xon_rx", stats.link_xon_rx), |
124 | I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx), | 125 | I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx), |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 2622a86de64b..d84f4275f470 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c | |||
@@ -1193,10 +1193,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
1193 | u32 rx_error, | 1193 | u32 rx_error, |
1194 | u16 rx_ptype) | 1194 | u16 rx_ptype) |
1195 | { | 1195 | { |
1196 | struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype); | ||
1197 | bool ipv4 = false, ipv6 = false; | ||
1196 | bool ipv4_tunnel, ipv6_tunnel; | 1198 | bool ipv4_tunnel, ipv6_tunnel; |
1197 | __wsum rx_udp_csum; | 1199 | __wsum rx_udp_csum; |
1198 | __sum16 csum; | ||
1199 | struct iphdr *iph; | 1200 | struct iphdr *iph; |
1201 | __sum16 csum; | ||
1200 | 1202 | ||
1201 | ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && | 1203 | ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && |
1202 | (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); | 1204 | (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); |
@@ -1207,29 +1209,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
1207 | skb->ip_summed = CHECKSUM_NONE; | 1209 | skb->ip_summed = CHECKSUM_NONE; |
1208 | 1210 | ||
1209 | /* Rx csum enabled and ip headers found? */ | 1211 | /* Rx csum enabled and ip headers found? */ |
1210 | if (!(vsi->netdev->features & NETIF_F_RXCSUM && | 1212 | if (!(vsi->netdev->features & NETIF_F_RXCSUM)) |
1211 | rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) | 1213 | return; |
1214 | |||
1215 | /* did the hardware decode the packet and checksum? */ | ||
1216 | if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) | ||
1217 | return; | ||
1218 | |||
1219 | /* both known and outer_ip must be set for the below code to work */ | ||
1220 | if (!(decoded.known && decoded.outer_ip)) | ||
1212 | return; | 1221 | return; |
1213 | 1222 | ||
1223 | if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && | ||
1224 | decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) | ||
1225 | ipv4 = true; | ||
1226 | else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && | ||
1227 | decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) | ||
1228 | ipv6 = true; | ||
1229 | |||
1230 | if (ipv4 && | ||
1231 | (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | | ||
1232 | (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) | ||
1233 | goto checksum_fail; | ||
1234 | |||
1214 | /* likely incorrect csum if alternate IP extension headers found */ | 1235 | /* likely incorrect csum if alternate IP extension headers found */ |
1215 | if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) | 1236 | if (ipv6 && |
1237 | decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP && | ||
1238 | rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) && | ||
1239 | rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) | ||
1240 | /* don't increment checksum err here, non-fatal err */ | ||
1216 | return; | 1241 | return; |
1217 | 1242 | ||
1218 | /* IP or L4 or outmost IP checksum error */ | 1243 | /* there was some L4 error, count error and punt packet to the stack */ |
1219 | if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | | 1244 | if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) |
1220 | (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) | | 1245 | goto checksum_fail; |
1221 | (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) { | 1246 | |
1222 | vsi->back->hw_csum_rx_error++; | 1247 | /* handle packets that were not able to be checksummed due |
1248 | * to arrival speed, in this case the stack can compute | ||
1249 | * the csum. | ||
1250 | */ | ||
1251 | if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) | ||
1223 | return; | 1252 | return; |
1224 | } | ||
1225 | 1253 | ||
1254 | /* If VXLAN traffic has an outer UDPv4 checksum we need to check | ||
1255 | * it in the driver, hardware does not do it for us. | ||
1256 | * Since L3L4P bit was set we assume a valid IHL value (>=5) | ||
1257 | * so the total length of IPv4 header is IHL*4 bytes | ||
1258 | * The UDP_0 bit *may* bet set if the *inner* header is UDP | ||
1259 | */ | ||
1226 | if (ipv4_tunnel && | 1260 | if (ipv4_tunnel && |
1261 | (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) && | ||
1227 | !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { | 1262 | !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { |
1228 | /* If VXLAN traffic has an outer UDPv4 checksum we need to check | ||
1229 | * it in the driver, hardware does not do it for us. | ||
1230 | * Since L3L4P bit was set we assume a valid IHL value (>=5) | ||
1231 | * so the total length of IPv4 header is IHL*4 bytes | ||
1232 | */ | ||
1233 | skb->transport_header = skb->mac_header + | 1263 | skb->transport_header = skb->mac_header + |
1234 | sizeof(struct ethhdr) + | 1264 | sizeof(struct ethhdr) + |
1235 | (ip_hdr(skb)->ihl * 4); | 1265 | (ip_hdr(skb)->ihl * 4); |
@@ -1246,13 +1276,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
1246 | (skb->len - skb_transport_offset(skb)), | 1276 | (skb->len - skb_transport_offset(skb)), |
1247 | IPPROTO_UDP, rx_udp_csum); | 1277 | IPPROTO_UDP, rx_udp_csum); |
1248 | 1278 | ||
1249 | if (udp_hdr(skb)->check != csum) { | 1279 | if (udp_hdr(skb)->check != csum) |
1250 | vsi->back->hw_csum_rx_error++; | 1280 | goto checksum_fail; |
1251 | return; | ||
1252 | } | ||
1253 | } | 1281 | } |
1254 | 1282 | ||
1255 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1283 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1284 | |||
1285 | return; | ||
1286 | |||
1287 | checksum_fail: | ||
1288 | vsi->back->hw_csum_rx_error++; | ||
1256 | } | 1289 | } |
1257 | 1290 | ||
1258 | /** | 1291 | /** |
@@ -1429,6 +1462,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) | |||
1429 | /* ERR_MASK will only have valid bits if EOP set */ | 1462 | /* ERR_MASK will only have valid bits if EOP set */ |
1430 | if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { | 1463 | if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { |
1431 | dev_kfree_skb_any(skb); | 1464 | dev_kfree_skb_any(skb); |
1465 | /* TODO: shouldn't we increment a counter indicating the | ||
1466 | * drop? | ||
1467 | */ | ||
1432 | goto next_desc; | 1468 | goto next_desc; |
1433 | } | 1469 | } |
1434 | 1470 | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 6c977d2d48e4..42bfb2aed765 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h | |||
@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits { | |||
541 | I40E_RX_DESC_ERROR_IPE_SHIFT = 3, | 541 | I40E_RX_DESC_ERROR_IPE_SHIFT = 3, |
542 | I40E_RX_DESC_ERROR_L4E_SHIFT = 4, | 542 | I40E_RX_DESC_ERROR_L4E_SHIFT = 4, |
543 | I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, | 543 | I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, |
544 | I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6 | 544 | I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6, |
545 | I40E_RX_DESC_ERROR_PPRS_SHIFT = 7 | ||
545 | }; | 546 | }; |
546 | 547 | ||
547 | enum i40e_rx_desc_error_l3l4e_fcoe_masks { | 548 | enum i40e_rx_desc_error_l3l4e_fcoe_masks { |
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index ae089df7df19..48ebb6cd69f2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c | |||
@@ -728,10 +728,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
728 | u32 rx_error, | 728 | u32 rx_error, |
729 | u16 rx_ptype) | 729 | u16 rx_ptype) |
730 | { | 730 | { |
731 | struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype); | ||
732 | bool ipv4 = false, ipv6 = false; | ||
731 | bool ipv4_tunnel, ipv6_tunnel; | 733 | bool ipv4_tunnel, ipv6_tunnel; |
732 | __wsum rx_udp_csum; | 734 | __wsum rx_udp_csum; |
733 | __sum16 csum; | ||
734 | struct iphdr *iph; | 735 | struct iphdr *iph; |
736 | __sum16 csum; | ||
735 | 737 | ||
736 | ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && | 738 | ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && |
737 | (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); | 739 | (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); |
@@ -742,29 +744,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
742 | skb->ip_summed = CHECKSUM_NONE; | 744 | skb->ip_summed = CHECKSUM_NONE; |
743 | 745 | ||
744 | /* Rx csum enabled and ip headers found? */ | 746 | /* Rx csum enabled and ip headers found? */ |
745 | if (!(vsi->netdev->features & NETIF_F_RXCSUM && | 747 | if (!(vsi->netdev->features & NETIF_F_RXCSUM)) |
746 | rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) | 748 | return; |
749 | |||
750 | /* did the hardware decode the packet and checksum? */ | ||
751 | if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) | ||
752 | return; | ||
753 | |||
754 | /* both known and outer_ip must be set for the below code to work */ | ||
755 | if (!(decoded.known && decoded.outer_ip)) | ||
747 | return; | 756 | return; |
748 | 757 | ||
758 | if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && | ||
759 | decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) | ||
760 | ipv4 = true; | ||
761 | else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && | ||
762 | decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) | ||
763 | ipv6 = true; | ||
764 | |||
765 | if (ipv4 && | ||
766 | (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | | ||
767 | (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) | ||
768 | goto checksum_fail; | ||
769 | |||
749 | /* likely incorrect csum if alternate IP extension headers found */ | 770 | /* likely incorrect csum if alternate IP extension headers found */ |
750 | if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) | 771 | if (ipv6 && |
772 | decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP && | ||
773 | rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) && | ||
774 | rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) | ||
775 | /* don't increment checksum err here, non-fatal err */ | ||
751 | return; | 776 | return; |
752 | 777 | ||
753 | /* IP or L4 or outmost IP checksum error */ | 778 | /* there was some L4 error, count error and punt packet to the stack */ |
754 | if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | | 779 | if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) |
755 | (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) | | 780 | goto checksum_fail; |
756 | (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) { | 781 | |
757 | vsi->back->hw_csum_rx_error++; | 782 | /* handle packets that were not able to be checksummed due |
783 | * to arrival speed, in this case the stack can compute | ||
784 | * the csum. | ||
785 | */ | ||
786 | if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) | ||
758 | return; | 787 | return; |
759 | } | ||
760 | 788 | ||
789 | /* If VXLAN traffic has an outer UDPv4 checksum we need to check | ||
790 | * it in the driver, hardware does not do it for us. | ||
791 | * Since L3L4P bit was set we assume a valid IHL value (>=5) | ||
792 | * so the total length of IPv4 header is IHL*4 bytes | ||
793 | * The UDP_0 bit *may* bet set if the *inner* header is UDP | ||
794 | */ | ||
761 | if (ipv4_tunnel && | 795 | if (ipv4_tunnel && |
796 | (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) && | ||
762 | !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { | 797 | !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { |
763 | /* If VXLAN traffic has an outer UDPv4 checksum we need to check | ||
764 | * it in the driver, hardware does not do it for us. | ||
765 | * Since L3L4P bit was set we assume a valid IHL value (>=5) | ||
766 | * so the total length of IPv4 header is IHL*4 bytes | ||
767 | */ | ||
768 | skb->transport_header = skb->mac_header + | 798 | skb->transport_header = skb->mac_header + |
769 | sizeof(struct ethhdr) + | 799 | sizeof(struct ethhdr) + |
770 | (ip_hdr(skb)->ihl * 4); | 800 | (ip_hdr(skb)->ihl * 4); |
@@ -781,13 +811,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, | |||
781 | (skb->len - skb_transport_offset(skb)), | 811 | (skb->len - skb_transport_offset(skb)), |
782 | IPPROTO_UDP, rx_udp_csum); | 812 | IPPROTO_UDP, rx_udp_csum); |
783 | 813 | ||
784 | if (udp_hdr(skb)->check != csum) { | 814 | if (udp_hdr(skb)->check != csum) |
785 | vsi->back->hw_csum_rx_error++; | 815 | goto checksum_fail; |
786 | return; | ||
787 | } | ||
788 | } | 816 | } |
789 | 817 | ||
790 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 818 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
819 | |||
820 | return; | ||
821 | |||
822 | checksum_fail: | ||
823 | vsi->back->hw_csum_rx_error++; | ||
791 | } | 824 | } |
792 | 825 | ||
793 | /** | 826 | /** |
@@ -956,6 +989,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) | |||
956 | /* ERR_MASK will only have valid bits if EOP set */ | 989 | /* ERR_MASK will only have valid bits if EOP set */ |
957 | if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { | 990 | if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { |
958 | dev_kfree_skb_any(skb); | 991 | dev_kfree_skb_any(skb); |
992 | /* TODO: shouldn't we increment a counter indicating the | ||
993 | * drop? | ||
994 | */ | ||
959 | goto next_desc; | 995 | goto next_desc; |
960 | } | 996 | } |
961 | 997 | ||
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index e3c9ebbe7ca2..0a7914d11b6a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h | |||
@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits { | |||
541 | I40E_RX_DESC_ERROR_IPE_SHIFT = 3, | 541 | I40E_RX_DESC_ERROR_IPE_SHIFT = 3, |
542 | I40E_RX_DESC_ERROR_L4E_SHIFT = 4, | 542 | I40E_RX_DESC_ERROR_L4E_SHIFT = 4, |
543 | I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, | 543 | I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, |
544 | I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6 | 544 | I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6, |
545 | I40E_RX_DESC_ERROR_PPRS_SHIFT = 7 | ||
545 | }; | 546 | }; |
546 | 547 | ||
547 | enum i40e_rx_desc_error_l3l4e_fcoe_masks { | 548 | enum i40e_rx_desc_error_l3l4e_fcoe_masks { |