aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Brandeburg <jesse.brandeburg@intel.com>2014-05-20 04:01:43 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2014-06-09 03:39:58 -0400
commit8a3c91cce3d32d3fa1e3b64d41b241103a62fd62 (patch)
tree385692000534fb57c95dcfac5eb95ae11ffa15f2
parent9aa7e9355db342fda17d716bcf5ce62df7a02e61 (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.c1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c74
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h3
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c74
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h3
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
1287checksum_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
547enum i40e_rx_desc_error_l3l4e_fcoe_masks { 548enum 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
822checksum_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
547enum i40e_rx_desc_error_l3l4e_fcoe_masks { 548enum i40e_rx_desc_error_l3l4e_fcoe_masks {