* [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf
@ 2016-01-11 17:53 Alexander Duyck
2016-01-11 17:53 ` [next PATCH 1/4] ixgbe: Add support for generic Tx checksums Alexander Duyck
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 17:53 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher; +Cc: tom, netdev
It turns out we were doing far more than we needed to in the Tx checksum
functions for the drivers. As a result it hid the fact that the hardware
is actually much more capable of handling generic offloads then previously
realized.
This patch series enables generic Tx checksum support for igb and ixgbe
based Intel server adapters. In addition it adds a number of other items
such as:
Inner checksum support for MPLS
Encapsulated checksum support for igb, igbvf, and ixgbevf
SCTP CRC offload support for VLAN tunnels, and VFs
IPv6 extension header support for igb and igbvf
---
Alexander Duyck (4):
ixgbe: Add support for generic Tx checksums
ixgbevf: Add support for generic Tx checksums
igb: Add support for generic Tx checksums
igbvf: Add support for generic Tx checksums
drivers/net/ethernet/intel/igb/igb_main.c | 114 ++++++---------
drivers/net/ethernet/intel/igbvf/netdev.c | 142 ++++++++++--------
drivers/net/ethernet/intel/igbvf/vf.h | 1
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 163 ++++++++-------------
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 104 ++++++-------
5 files changed, 231 insertions(+), 293 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [next PATCH 1/4] ixgbe: Add support for generic Tx checksums
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
@ 2016-01-11 17:53 ` Alexander Duyck
2016-01-11 18:11 ` Tom Herbert
2016-01-11 17:54 ` [next PATCH 2/4] ixgbevf: " Alexander Duyck
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 17:53 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher; +Cc: tom, netdev
This patch adds support for generic Tx checksums to the ixgbe driver. It
turns out this is actually pretty easy after going over the datasheet as we
were doing a number of steps we didn't need to.
In order to perform a Tx checksum for an L4 header we need to fill in the
following fields in the Tx descriptor:
MACLEN (maximum of 127), retrieved from:
skb_network_offset()
IPLEN (maximum of 511), retrieved from:
skb_checksum_start_offset() - skb_network_offset()
TUCMD.L4T indicates offset and if checksum or crc32c, based on:
skb->csum_offset
The added advantage to doing this is that we can support inner checksum
offloads for tunnels and MPLS while still being able to transparently insert
VLAN tags.
I also took the opportunity to clean-up many of the feature flag
configuration bits to make them a bit more consistent between drivers.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 163 +++++++++----------------
1 file changed, 59 insertions(+), 104 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 77cdaed6de90..1e3a548cc612 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7207,103 +7207,61 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
return 1;
}
+static inline bool ixgbe_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+ unsigned int offset = 0;
+
+ ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+ return offset == skb_checksum_start_offset(skb);
+}
+
static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
struct ixgbe_tx_buffer *first)
{
struct sk_buff *skb = first->skb;
u32 vlan_macip_lens = 0;
- u32 mss_l4len_idx = 0;
u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) {
- if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
- !(first->tx_flags & IXGBE_TX_FLAGS_CC))
+csum_failed:
+ if (!(first->tx_flags & (IXGBE_TX_FLAGS_HW_VLAN |
+ IXGBE_TX_FLAGS_CC)))
return;
- vlan_macip_lens = skb_network_offset(skb) <<
- IXGBE_ADVTXD_MACLEN_SHIFT;
- } else {
- u8 l4_hdr = 0;
- union {
- struct iphdr *ipv4;
- struct ipv6hdr *ipv6;
- u8 *raw;
- } network_hdr;
- union {
- struct tcphdr *tcphdr;
- u8 *raw;
- } transport_hdr;
- __be16 frag_off;
-
- if (skb->encapsulation) {
- network_hdr.raw = skb_inner_network_header(skb);
- transport_hdr.raw = skb_inner_transport_header(skb);
- vlan_macip_lens = skb_inner_network_offset(skb) <<
- IXGBE_ADVTXD_MACLEN_SHIFT;
- } else {
- network_hdr.raw = skb_network_header(skb);
- transport_hdr.raw = skb_transport_header(skb);
- vlan_macip_lens = skb_network_offset(skb) <<
- IXGBE_ADVTXD_MACLEN_SHIFT;
- }
-
- /* use first 4 bits to determine IP version */
- switch (network_hdr.ipv4->version) {
- case IPVERSION:
- vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
- type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
- l4_hdr = network_hdr.ipv4->protocol;
- break;
- case 6:
- vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
- l4_hdr = network_hdr.ipv6->nexthdr;
- if (likely((transport_hdr.raw - network_hdr.raw) ==
- sizeof(struct ipv6hdr)))
- break;
- ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
- sizeof(struct ipv6hdr),
- &l4_hdr, &frag_off);
- if (unlikely(frag_off))
- l4_hdr = NEXTHDR_FRAGMENT;
- break;
- default:
- break;
- }
+ goto no_csum;
+ }
- switch (l4_hdr) {
- case IPPROTO_TCP:
- type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
- mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_SCTP:
- type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
- mss_l4len_idx = sizeof(struct sctphdr) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_UDP:
- mss_l4len_idx = sizeof(struct udphdr) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
+ switch (skb->csum_offset) {
+ case offsetof(struct tcphdr, check):
+ type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ /* fall through */
+ case offsetof(struct udphdr, check):
+ break;
+ case offsetof(struct sctphdr, checksum):
+ /* validate that this is actually an SCTP request */
+ if (((first->protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+ ((first->protocol == htons(ETH_P_IPV6)) &&
+ ixgbe_ipv6_csum_is_sctp(skb))) {
+ type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
break;
- default:
- if (unlikely(net_ratelimit())) {
- dev_warn(tx_ring->dev,
- "partial checksum, version=%d, l4 proto=%x\n",
- network_hdr.ipv4->version, l4_hdr);
- }
- skb_checksum_help(skb);
- goto no_csum;
}
-
- /* update TX checksum flag */
- first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+ /* fall through */
+ default:
+ skb_checksum_help(skb);
+ goto csum_failed;
}
+ /* update TX checksum flag */
+ first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+ vlan_macip_lens = skb_checksum_start_offset(skb) -
+ skb_network_offset(skb);
no_csum:
/* vlan_macip_lens: MACLEN, VLAN tag */
+ vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
- ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0,
- type_tucmd, mss_l4len_idx);
+ ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0, type_tucmd, 0);
}
#define IXGBE_SET_FLAG(_input, _flag, _result) \
@@ -9012,40 +8970,37 @@ skip_sriov:
#endif
netdev->features = NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
- NETIF_F_HW_VLAN_CTAG_TX |
- NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXHASH |
- NETIF_F_RXCSUM;
-
- netdev->hw_features = netdev->features | NETIF_F_HW_L2FW_DOFFLOAD;
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC |
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
- switch (adapter->hw.mac.type) {
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540:
- case ixgbe_mac_X550:
- case ixgbe_mac_X550EM_x:
+ if (hw->mac.type >= ixgbe_mac_82599EB)
netdev->features |= NETIF_F_SCTP_CRC;
- netdev->hw_features |= NETIF_F_SCTP_CRC |
- NETIF_F_NTUPLE;
- break;
- default:
- break;
- }
- netdev->hw_features |= NETIF_F_RXALL;
+ /* copy netdev features into list of user selectable features */
+ netdev->hw_features |= netdev->features;
+ netdev->hw_features |= NETIF_F_RXALL |
+ NETIF_F_HW_L2FW_DOFFLOAD;
+
+ if (hw->mac.type >= ixgbe_mac_82599EB)
+ netdev->hw_features |= NETIF_F_NTUPLE;
+
+ /* set this bit last since it cannot be part of hw_features */
netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
- netdev->vlan_features |= NETIF_F_TSO;
- netdev->vlan_features |= NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_IP_CSUM;
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
- netdev->vlan_features |= NETIF_F_SG;
+ netdev->vlan_features |= NETIF_F_SG |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
- netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [next PATCH 2/4] ixgbevf: Add support for generic Tx checksums
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
2016-01-11 17:53 ` [next PATCH 1/4] ixgbe: Add support for generic Tx checksums Alexander Duyck
@ 2016-01-11 17:54 ` Alexander Duyck
2016-01-11 17:54 ` [next PATCH 3/4] igb: " Alexander Duyck
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 17:54 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher; +Cc: tom, netdev
This patch adds support for generic Tx checksums to the ixgbevf driver. It
turns out this is actually pretty easy after going over the datasheet as we
were doing a number of steps we didn't need to.
In order to perform a Tx checksum for an L4 header we need to fill in the
following fields in the Tx descriptor:
MACLEN (maximum of 127), retrieved from:
skb_network_offset()
IPLEN (maximum of 511), retrieved from:
skb_checksum_start_offset() - skb_network_offset()
TUCMD.L4T indicates offset and if checksum or crc32c, based on:
skb->csum_offset
The added advantage to doing this is that we can support inner checksum
offloads for tunnels and MPLS while still being able to transparently insert
VLAN tags.
I also took the opportunity to clean-up many of the feature flag
configuration bits to make them a bit more consistent between drivers. In
the case of the VF drivers this meant adding support for SCTP CRCs, and
inner checksum offloads for MPLS and various tunnel types.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 104 +++++++++------------
1 file changed, 43 insertions(+), 61 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 0b451d9eddb0..e58bebf6ea1d 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -3334,76 +3334,55 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
return 1;
}
+static inline bool ixgbevf_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+ unsigned int offset = 0;
+
+ ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+ return offset == skb_checksum_start_offset(skb);
+}
+
static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
struct ixgbevf_tx_buffer *first)
{
struct sk_buff *skb = first->skb;
u32 vlan_macip_lens = 0;
- u32 mss_l4len_idx = 0;
u32 type_tucmd = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- u8 l4_hdr = 0;
- __be16 frag_off;
-
- switch (first->protocol) {
- case htons(ETH_P_IP):
- vlan_macip_lens |= skb_network_header_len(skb);
- type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
- l4_hdr = ip_hdr(skb)->protocol;
- break;
- case htons(ETH_P_IPV6):
- vlan_macip_lens |= skb_network_header_len(skb);
- l4_hdr = ipv6_hdr(skb)->nexthdr;
- if (likely(skb_network_header_len(skb) ==
- sizeof(struct ipv6hdr)))
- break;
- ipv6_skip_exthdr(skb, skb_network_offset(skb) +
- sizeof(struct ipv6hdr),
- &l4_hdr, &frag_off);
- if (unlikely(frag_off))
- l4_hdr = NEXTHDR_FRAGMENT;
- break;
- default:
- break;
- }
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ goto no_csum;
- switch (l4_hdr) {
- case IPPROTO_TCP:
- type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
- mss_l4len_idx = tcp_hdrlen(skb) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_SCTP:
- type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
- mss_l4len_idx = sizeof(struct sctphdr) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_UDP:
- mss_l4len_idx = sizeof(struct udphdr) <<
- IXGBE_ADVTXD_L4LEN_SHIFT;
+ switch (skb->csum_offset) {
+ case offsetof(struct tcphdr, check):
+ type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ /* fall through */
+ case offsetof(struct udphdr, check):
+ break;
+ case offsetof(struct sctphdr, checksum):
+ /* validate that this is actually an SCTP request */
+ if (((first->protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+ ((first->protocol == htons(ETH_P_IPV6)) &&
+ ixgbevf_ipv6_csum_is_sctp(skb))) {
+ type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
break;
- default:
- if (unlikely(net_ratelimit())) {
- dev_warn(tx_ring->dev,
- "partial checksum, l3 proto=%x, l4 proto=%x\n",
- first->protocol, l4_hdr);
- }
- skb_checksum_help(skb);
- goto no_csum;
}
-
- /* update TX checksum flag */
- first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+ /* fall through */
+ default:
+ skb_checksum_help(skb);
+ goto no_csum;
}
-
+ /* update TX checksum flag */
+ first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
+ vlan_macip_lens = skb_checksum_start_offset(skb) -
+ skb_network_offset(skb);
no_csum:
/* vlan_macip_lens: MACLEN, VLAN tag */
vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
- ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens,
- type_tucmd, mss_l4len_idx);
+ ixgbevf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
}
static __le32 ixgbevf_tx_cmd_type(u32 tx_flags)
@@ -4006,22 +3985,25 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
netdev->hw_features = NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
- NETIF_F_RXCSUM;
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
- netdev->vlan_features |= NETIF_F_TSO |
+ netdev->vlan_features |= NETIF_F_SG |
+ NETIF_F_TSO |
NETIF_F_TSO6 |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
- NETIF_F_SG;
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
+
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [next PATCH 3/4] igb: Add support for generic Tx checksums
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
2016-01-11 17:53 ` [next PATCH 1/4] ixgbe: Add support for generic Tx checksums Alexander Duyck
2016-01-11 17:54 ` [next PATCH 2/4] ixgbevf: " Alexander Duyck
@ 2016-01-11 17:54 ` Alexander Duyck
2016-01-11 17:54 ` [next PATCH 4/4] igbvf: " Alexander Duyck
2016-01-12 4:43 ` [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf David Miller
4 siblings, 0 replies; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 17:54 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher; +Cc: tom, netdev
This patch adds support for generic Tx checksums to the igb driver. It
turns out this is actually pretty easy after going over the datasheet as we
were doing a number of steps we didn't need to.
In order to perform a Tx checksum for an L4 header we need to fill in the
following fields in the Tx descriptor:
MACLEN (maximum of 127), retrieved from:
skb_network_offset()
IPLEN (maximum of 511), retrieved from:
skb_checksum_start_offset() - skb_network_offset()
TUCMD.L4T indicates offset and if checksum or crc32c, based on:
skb->csum_offset
The added advantage to doing this is that we can support inner checksum
offloads for tunnels and MPLS while still being able to transparently insert
VLAN tags.
I also took the opportunity to clean-up many of the feature flag
configuration bits to make them a bit more consistent between drivers.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 114 ++++++++++++-----------------
1 file changed, 47 insertions(+), 67 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ade8dee55fb8..8cd71cf39001 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2437,37 +2437,35 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* assignment.
*/
netdev->features |= NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXHASH |
NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_TX;
+ if (hw->mac.type >= e1000_82576)
+ netdev->features |= NETIF_F_SCTP_CRC;
+
/* copy netdev features into list of user selectable features */
netdev->hw_features |= netdev->features;
netdev->hw_features |= NETIF_F_RXALL;
+ if (hw->mac.type >= e1000_i350)
+ netdev->hw_features |= NETIF_F_NTUPLE;
+
/* set this bit last since it cannot be part of hw_features */
netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
- netdev->vlan_features |= NETIF_F_TSO |
+ netdev->vlan_features |= NETIF_F_SG |
+ NETIF_F_TSO |
NETIF_F_TSO6 |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
- NETIF_F_SG;
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
- switch (hw->mac.type) {
- case e1000_i210:
- case e1000_i211:
- case e1000_i350:
- netdev->hw_features |= NETIF_F_NTUPLE;
- break;
- default:
- break;
- }
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
netdev->priv_flags |= IFF_SUPP_NOFCS;
@@ -2476,11 +2474,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->vlan_features |= NETIF_F_HIGHDMA;
}
- if (hw->mac.type >= e1000_82576) {
- netdev->hw_features |= NETIF_F_SCTP_CRC;
- netdev->features |= NETIF_F_SCTP_CRC;
- }
-
netdev->priv_flags |= IFF_UNICAST_FLT;
adapter->en_mng_pt = igb_enable_mng_pass_thru(hw);
@@ -4967,70 +4960,57 @@ static int igb_tso(struct igb_ring *tx_ring,
return 1;
}
+static inline bool igb_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+ unsigned int offset = 0;
+
+ ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+ return offset == skb_checksum_start_offset(skb);
+}
+
static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
{
struct sk_buff *skb = first->skb;
u32 vlan_macip_lens = 0;
- u32 mss_l4len_idx = 0;
u32 type_tucmd = 0;
if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
if (!(first->tx_flags & IGB_TX_FLAGS_VLAN))
return;
- } else {
- u8 l4_hdr = 0;
-
- switch (first->protocol) {
- case htons(ETH_P_IP):
- vlan_macip_lens |= skb_network_header_len(skb);
- type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
- l4_hdr = ip_hdr(skb)->protocol;
- break;
- case htons(ETH_P_IPV6):
- vlan_macip_lens |= skb_network_header_len(skb);
- l4_hdr = ipv6_hdr(skb)->nexthdr;
- break;
- default:
- if (unlikely(net_ratelimit())) {
- dev_warn(tx_ring->dev,
- "partial checksum but proto=%x!\n",
- first->protocol);
- }
- break;
- }
+ goto no_csum;
+ }
- switch (l4_hdr) {
- case IPPROTO_TCP:
- type_tucmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
- mss_l4len_idx = tcp_hdrlen(skb) <<
- E1000_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_SCTP:
- type_tucmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
- mss_l4len_idx = sizeof(struct sctphdr) <<
- E1000_ADVTXD_L4LEN_SHIFT;
- break;
- case IPPROTO_UDP:
- mss_l4len_idx = sizeof(struct udphdr) <<
- E1000_ADVTXD_L4LEN_SHIFT;
- break;
- default:
- if (unlikely(net_ratelimit())) {
- dev_warn(tx_ring->dev,
- "partial checksum but l4 proto=%x!\n",
- l4_hdr);
- }
+ switch (skb->csum_offset) {
+ case offsetof(struct tcphdr, check):
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+ /* fall through */
+ case offsetof(struct udphdr, check):
+ break;
+ case offsetof(struct sctphdr, checksum):
+ /* validate that this is actually an SCTP request */
+ if (((first->protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+ ((first->protocol == htons(ETH_P_IPV6)) &&
+ igb_ipv6_csum_is_sctp(skb))) {
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
break;
}
-
- /* update TX checksum flag */
- first->tx_flags |= IGB_TX_FLAGS_CSUM;
+ default:
+ skb_checksum_help(skb);
+ goto csum_failed;
}
+ /* update TX checksum flag */
+ first->tx_flags |= IGB_TX_FLAGS_CSUM;
+ vlan_macip_lens = skb_checksum_start_offset(skb) -
+ skb_network_offset(skb);
+no_csum:
vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
vlan_macip_lens |= first->tx_flags & IGB_TX_FLAGS_VLAN_MASK;
- igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, mss_l4len_idx);
+ igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
}
#define IGB_SET_FLAG(_input, _flag, _result) \
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [next PATCH 4/4] igbvf: Add support for generic Tx checksums
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
` (2 preceding siblings ...)
2016-01-11 17:54 ` [next PATCH 3/4] igb: " Alexander Duyck
@ 2016-01-11 17:54 ` Alexander Duyck
2016-01-12 4:43 ` [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf David Miller
4 siblings, 0 replies; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 17:54 UTC (permalink / raw)
To: intel-wired-lan, jeffrey.t.kirsher; +Cc: tom, netdev
This patch adds support for generic Tx checksums to the igbvf driver. It
turns out this is actually pretty easy after going over the datasheet as we
were doing a number of steps we didn't need to.
In order to perform a Tx checksum for an L4 header we need to fill in the
following fields in the Tx descriptor:
MACLEN (maximum of 127), retrieved from:
skb_network_offset()
IPLEN (maximum of 511), retrieved from:
skb_checksum_start_offset() - skb_network_offset()
TUCMD.L4T indicates offset and if checksum or crc32c, based on:
skb->csum_offset
The added advantage to doing this is that we can support inner checksum
offloads for tunnels and MPLS while still being able to transparently insert
VLAN tags.
I also took the opportunity to clean-up many of the feature flag
configuration bits to make them a bit more consistent between drivers. In
the case of the VF drivers this meant adding support for SCTP CRCs, and
inner checksum offloads for MPLS and various tunnel types.
Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
---
drivers/net/ethernet/intel/igbvf/netdev.c | 142 +++++++++++++++++------------
drivers/net/ethernet/intel/igbvf/vf.h | 1
2 files changed, 82 insertions(+), 61 deletions(-)
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 297af801f051..ee6a75ee916c 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -43,6 +43,7 @@
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/prefetch.h>
+#include <linux/sctp.h>
#include "igbvf.h"
@@ -1908,6 +1909,31 @@ static void igbvf_watchdog_task(struct work_struct *work)
#define IGBVF_TX_FLAGS_VLAN_MASK 0xffff0000
#define IGBVF_TX_FLAGS_VLAN_SHIFT 16
+static void igbvf_tx_ctxtdesc(struct igbvf_ring *tx_ring, u32 vlan_macip_lens,
+ u32 type_tucmd, u32 mss_l4len_idx)
+{
+ struct e1000_adv_tx_context_desc *context_desc;
+ struct igbvf_buffer *buffer_info;
+ u16 i = tx_ring->next_to_use;
+
+ context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
+
+ i++;
+ tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
+
+ /* set bits to identify this as an advanced context descriptor */
+ type_tucmd |= E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
+
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+ buffer_info->time_stamp = jiffies;
+ buffer_info->dma = 0;
+}
+
static int igbvf_tso(struct igbvf_adapter *adapter,
struct igbvf_ring *tx_ring,
struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
@@ -1987,65 +2013,56 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
return true;
}
-static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
- struct igbvf_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags,
- __be16 protocol)
+static inline bool igbvf_ipv6_csum_is_sctp(struct sk_buff *skb)
{
- struct e1000_adv_tx_context_desc *context_desc;
- unsigned int i;
- struct igbvf_buffer *buffer_info;
- u32 info = 0, tu_cmd = 0;
-
- if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
- (tx_flags & IGBVF_TX_FLAGS_VLAN)) {
- i = tx_ring->next_to_use;
- buffer_info = &tx_ring->buffer_info[i];
- context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+ unsigned int offset = 0;
- if (tx_flags & IGBVF_TX_FLAGS_VLAN)
- info |= (tx_flags & IGBVF_TX_FLAGS_VLAN_MASK);
+ ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
- info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- info |= (skb_transport_header(skb) -
- skb_network_header(skb));
+ return offset == skb_checksum_start_offset(skb);
+}
- context_desc->vlan_macip_lens = cpu_to_le32(info);
+static bool igbvf_tx_csum(struct igbvf_ring *tx_ring, struct sk_buff *skb,
+ u32 tx_flags, __be16 protocol)
+{
+ u32 vlan_macip_lens = 0;
+ u32 type_tucmd = 0;
- tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
+ if (!(tx_flags & IGBVF_TX_FLAGS_VLAN))
+ return false;
+ goto no_csum;
+ }
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- switch (protocol) {
- case htons(ETH_P_IP):
- tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
- break;
- case htons(ETH_P_IPV6):
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
- break;
- default:
- break;
- }
+ switch (skb->csum_offset) {
+ case offsetof(struct tcphdr, check):
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+ /* fall through */
+ case offsetof(struct udphdr, check):
+ break;
+ case offsetof(struct sctphdr, checksum):
+ /* validate that this is actually an SCTP request */
+ if (((protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+ ((protocol == htons(ETH_P_IPV6)) &&
+ igbvf_ipv6_csum_is_sctp(skb))) {
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
+ break;
}
-
- context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
- context_desc->seqnum_seed = 0;
- context_desc->mss_l4len_idx = 0;
-
- buffer_info->time_stamp = jiffies;
- buffer_info->dma = 0;
- i++;
- if (i == tx_ring->count)
- i = 0;
- tx_ring->next_to_use = i;
-
- return true;
+ default:
+ skb_checksum_help(skb);
+ goto csum_failed;
}
- return false;
+ vlan_macip_lens = skb_checksum_start_offset(skb) -
+ skb_network_offset(skb);
+no_csum:
+ vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
+ vlan_macip_lens |= tx_flags & IGBVF_TX_FLAGS_VLAN_MASK;
+
+ igbvf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
+ return true;
}
static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
@@ -2264,7 +2281,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
if (tso)
tx_flags |= IGBVF_TX_FLAGS_TSO;
- else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) &&
+ else if (igbvf_tx_csum(tx_ring, skb, tx_flags, protocol) &&
(skb->ip_summed == CHECKSUM_PARTIAL))
tx_flags |= IGBVF_TX_FLAGS_CSUM;
@@ -2717,11 +2734,11 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->bd_number = cards_found++;
netdev->hw_features = NETIF_F_SG |
- NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM |
- NETIF_F_TSO |
- NETIF_F_TSO6 |
- NETIF_F_RXCSUM;
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
netdev->features = netdev->hw_features |
NETIF_F_HW_VLAN_CTAG_TX |
@@ -2731,11 +2748,14 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->vlan_features |= NETIF_F_TSO;
- netdev->vlan_features |= NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_IP_CSUM;
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
- netdev->vlan_features |= NETIF_F_SG;
+ netdev->vlan_features |= NETIF_F_SG |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM |
+ NETIF_F_SCTP_CRC;
+
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
/*reset the controller to put the device in a known good state */
err = hw->mac.ops.reset_hw(hw);
diff --git a/drivers/net/ethernet/intel/igbvf/vf.h b/drivers/net/ethernet/intel/igbvf/vf.h
index 0f1eca639f68..f00a41d9a1ca 100644
--- a/drivers/net/ethernet/intel/igbvf/vf.h
+++ b/drivers/net/ethernet/intel/igbvf/vf.h
@@ -126,6 +126,7 @@ struct e1000_adv_tx_context_desc {
#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */
#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [next PATCH 1/4] ixgbe: Add support for generic Tx checksums
2016-01-11 17:53 ` [next PATCH 1/4] ixgbe: Add support for generic Tx checksums Alexander Duyck
@ 2016-01-11 18:11 ` Tom Herbert
2016-01-11 20:29 ` [Intel-wired-lan] " Alexander Duyck
0 siblings, 1 reply; 9+ messages in thread
From: Tom Herbert @ 2016-01-11 18:11 UTC (permalink / raw)
To: Alexander Duyck
Cc: intel-wired-lan, Jeff Kirsher, Linux Kernel Network Developers
On Mon, Jan 11, 2016 at 9:53 AM, Alexander Duyck <aduyck@mirantis.com> wrote:
> This patch adds support for generic Tx checksums to the ixgbe driver. It
> turns out this is actually pretty easy after going over the datasheet as we
> were doing a number of steps we didn't need to.
>
> In order to perform a Tx checksum for an L4 header we need to fill in the
> following fields in the Tx descriptor:
> MACLEN (maximum of 127), retrieved from:
> skb_network_offset()
> IPLEN (maximum of 511), retrieved from:
> skb_checksum_start_offset() - skb_network_offset()
> TUCMD.L4T indicates offset and if checksum or crc32c, based on:
> skb->csum_offset
>
> The added advantage to doing this is that we can support inner checksum
> offloads for tunnels and MPLS while still being able to transparently insert
> VLAN tags.
>
> I also took the opportunity to clean-up many of the feature flag
> configuration bits to make them a bit more consistent between drivers.
>
> Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
> ---
> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 163 +++++++++----------------
> 1 file changed, 59 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index 77cdaed6de90..1e3a548cc612 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -7207,103 +7207,61 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
> return 1;
> }
>
> +static inline bool ixgbe_ipv6_csum_is_sctp(struct sk_buff *skb)
> +{
> + unsigned int offset = 0;
> +
> + ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
> +
> + return offset == skb_checksum_start_offset(skb);
> +}
> +
> static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
> struct ixgbe_tx_buffer *first)
> {
> struct sk_buff *skb = first->skb;
> u32 vlan_macip_lens = 0;
> - u32 mss_l4len_idx = 0;
> u32 type_tucmd = 0;
>
> if (skb->ip_summed != CHECKSUM_PARTIAL) {
> - if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
> - !(first->tx_flags & IXGBE_TX_FLAGS_CC))
> +csum_failed:
> + if (!(first->tx_flags & (IXGBE_TX_FLAGS_HW_VLAN |
> + IXGBE_TX_FLAGS_CC)))
> return;
> - vlan_macip_lens = skb_network_offset(skb) <<
> - IXGBE_ADVTXD_MACLEN_SHIFT;
> - } else {
> - u8 l4_hdr = 0;
> - union {
> - struct iphdr *ipv4;
> - struct ipv6hdr *ipv6;
> - u8 *raw;
> - } network_hdr;
> - union {
> - struct tcphdr *tcphdr;
> - u8 *raw;
> - } transport_hdr;
> - __be16 frag_off;
> -
> - if (skb->encapsulation) {
> - network_hdr.raw = skb_inner_network_header(skb);
> - transport_hdr.raw = skb_inner_transport_header(skb);
> - vlan_macip_lens = skb_inner_network_offset(skb) <<
> - IXGBE_ADVTXD_MACLEN_SHIFT;
> - } else {
> - network_hdr.raw = skb_network_header(skb);
> - transport_hdr.raw = skb_transport_header(skb);
> - vlan_macip_lens = skb_network_offset(skb) <<
> - IXGBE_ADVTXD_MACLEN_SHIFT;
> - }
> -
> - /* use first 4 bits to determine IP version */
> - switch (network_hdr.ipv4->version) {
> - case IPVERSION:
> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
> - type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
> - l4_hdr = network_hdr.ipv4->protocol;
> - break;
> - case 6:
> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
> - l4_hdr = network_hdr.ipv6->nexthdr;
> - if (likely((transport_hdr.raw - network_hdr.raw) ==
> - sizeof(struct ipv6hdr)))
> - break;
> - ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
> - sizeof(struct ipv6hdr),
> - &l4_hdr, &frag_off);
> - if (unlikely(frag_off))
> - l4_hdr = NEXTHDR_FRAGMENT;
> - break;
> - default:
> - break;
> - }
> + goto no_csum;
> + }
>
> - switch (l4_hdr) {
> - case IPPROTO_TCP:
> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
> - mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) <<
> - IXGBE_ADVTXD_L4LEN_SHIFT;
> - break;
> - case IPPROTO_SCTP:
> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
> - mss_l4len_idx = sizeof(struct sctphdr) <<
> - IXGBE_ADVTXD_L4LEN_SHIFT;
> - break;
> - case IPPROTO_UDP:
> - mss_l4len_idx = sizeof(struct udphdr) <<
> - IXGBE_ADVTXD_L4LEN_SHIFT;
> + switch (skb->csum_offset) {
> + case offsetof(struct tcphdr, check):
> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
> + /* fall through */
> + case offsetof(struct udphdr, check):
> + break;
> + case offsetof(struct sctphdr, checksum):
> + /* validate that this is actually an SCTP request */
> + if (((first->protocol == htons(ETH_P_IP)) &&
> + (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
> + ((first->protocol == htons(ETH_P_IPV6)) &&
> + ixgbe_ipv6_csum_is_sctp(skb))) {
> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
I think we're going to have to do something different for SCTP CRC
this (and FCOE CRC) is a special case of CHECKSUM_PARTIAL that I don't
think we're always accounting for. For instance, in LCO we are always
assuming that CHECKSUM_PARTIAL refers to an IP checksum. Maybe it's
time to add a bit to ip_summed so we can define CHEKCKSUM_SCTP_CRC and
CHECKSUM_FCOE_CRC?
> break;
> - default:
> - if (unlikely(net_ratelimit())) {
> - dev_warn(tx_ring->dev,
> - "partial checksum, version=%d, l4 proto=%x\n",
> - network_hdr.ipv4->version, l4_hdr);
> - }
> - skb_checksum_help(skb);
> - goto no_csum;
> }
> -
> - /* update TX checksum flag */
> - first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
> + /* fall through */
> + default:
> + skb_checksum_help(skb);
> + goto csum_failed;
> }
>
> + /* update TX checksum flag */
> + first->tx_flags |= IXGBE_TX_FLAGS_CSUM;
> + vlan_macip_lens = skb_checksum_start_offset(skb) -
> + skb_network_offset(skb);
> no_csum:
> /* vlan_macip_lens: MACLEN, VLAN tag */
> + vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT;
> vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK;
>
> - ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0,
> - type_tucmd, mss_l4len_idx);
> + ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0, type_tucmd, 0);
> }
>
> #define IXGBE_SET_FLAG(_input, _flag, _result) \
> @@ -9012,40 +8970,37 @@ skip_sriov:
>
> #endif
> netdev->features = NETIF_F_SG |
> - NETIF_F_IP_CSUM |
> - NETIF_F_IPV6_CSUM |
> - NETIF_F_HW_VLAN_CTAG_TX |
> - NETIF_F_HW_VLAN_CTAG_RX |
> NETIF_F_TSO |
> NETIF_F_TSO6 |
> NETIF_F_RXHASH |
> - NETIF_F_RXCSUM;
> -
> - netdev->hw_features = netdev->features | NETIF_F_HW_L2FW_DOFFLOAD;
> + NETIF_F_RXCSUM |
> + NETIF_F_HW_CSUM |
> + NETIF_F_SCTP_CRC |
> + NETIF_F_HW_VLAN_CTAG_TX |
> + NETIF_F_HW_VLAN_CTAG_RX;
>
> - switch (adapter->hw.mac.type) {
> - case ixgbe_mac_82599EB:
> - case ixgbe_mac_X540:
> - case ixgbe_mac_X550:
> - case ixgbe_mac_X550EM_x:
> + if (hw->mac.type >= ixgbe_mac_82599EB)
> netdev->features |= NETIF_F_SCTP_CRC;
> - netdev->hw_features |= NETIF_F_SCTP_CRC |
> - NETIF_F_NTUPLE;
> - break;
> - default:
> - break;
> - }
>
> - netdev->hw_features |= NETIF_F_RXALL;
> + /* copy netdev features into list of user selectable features */
> + netdev->hw_features |= netdev->features;
> + netdev->hw_features |= NETIF_F_RXALL |
> + NETIF_F_HW_L2FW_DOFFLOAD;
> +
> + if (hw->mac.type >= ixgbe_mac_82599EB)
> + netdev->hw_features |= NETIF_F_NTUPLE;
> +
> + /* set this bit last since it cannot be part of hw_features */
> netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
>
> - netdev->vlan_features |= NETIF_F_TSO;
> - netdev->vlan_features |= NETIF_F_TSO6;
> - netdev->vlan_features |= NETIF_F_IP_CSUM;
> - netdev->vlan_features |= NETIF_F_IPV6_CSUM;
> - netdev->vlan_features |= NETIF_F_SG;
> + netdev->vlan_features |= NETIF_F_SG |
> + NETIF_F_TSO |
> + NETIF_F_TSO6 |
> + NETIF_F_HW_CSUM |
> + NETIF_F_SCTP_CRC;
>
> - netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
> + netdev->mpls_features |= NETIF_F_HW_CSUM;
> + netdev->hw_enc_features |= NETIF_F_HW_CSUM;
>
> netdev->priv_flags |= IFF_UNICAST_FLT;
> netdev->priv_flags |= IFF_SUPP_NOFCS;
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Intel-wired-lan] [next PATCH 1/4] ixgbe: Add support for generic Tx checksums
2016-01-11 18:11 ` Tom Herbert
@ 2016-01-11 20:29 ` Alexander Duyck
2016-01-11 20:49 ` Tom Herbert
0 siblings, 1 reply; 9+ messages in thread
From: Alexander Duyck @ 2016-01-11 20:29 UTC (permalink / raw)
To: Tom Herbert
Cc: Alexander Duyck, Linux Kernel Network Developers, intel-wired-lan
On Mon, Jan 11, 2016 at 10:11 AM, Tom Herbert <tom@herbertland.com> wrote:
> On Mon, Jan 11, 2016 at 9:53 AM, Alexander Duyck <aduyck@mirantis.com> wrote:
>> This patch adds support for generic Tx checksums to the ixgbe driver. It
>> turns out this is actually pretty easy after going over the datasheet as we
>> were doing a number of steps we didn't need to.
>>
>> In order to perform a Tx checksum for an L4 header we need to fill in the
>> following fields in the Tx descriptor:
>> MACLEN (maximum of 127), retrieved from:
>> skb_network_offset()
>> IPLEN (maximum of 511), retrieved from:
>> skb_checksum_start_offset() - skb_network_offset()
>> TUCMD.L4T indicates offset and if checksum or crc32c, based on:
>> skb->csum_offset
>>
>> The added advantage to doing this is that we can support inner checksum
>> offloads for tunnels and MPLS while still being able to transparently insert
>> VLAN tags.
>>
>> I also took the opportunity to clean-up many of the feature flag
>> configuration bits to make them a bit more consistent between drivers.
>>
>> Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
>> ---
>> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 163 +++++++++----------------
>> 1 file changed, 59 insertions(+), 104 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> index 77cdaed6de90..1e3a548cc612 100644
>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>> @@ -7207,103 +7207,61 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
>> return 1;
>> }
>>
>> +static inline bool ixgbe_ipv6_csum_is_sctp(struct sk_buff *skb)
>> +{
>> + unsigned int offset = 0;
>> +
>> + ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
>> +
>> + return offset == skb_checksum_start_offset(skb);
>> +}
>> +
>> static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
>> struct ixgbe_tx_buffer *first)
>> {
>> struct sk_buff *skb = first->skb;
>> u32 vlan_macip_lens = 0;
>> - u32 mss_l4len_idx = 0;
>> u32 type_tucmd = 0;
>>
>> if (skb->ip_summed != CHECKSUM_PARTIAL) {
>> - if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
>> - !(first->tx_flags & IXGBE_TX_FLAGS_CC))
>> +csum_failed:
>> + if (!(first->tx_flags & (IXGBE_TX_FLAGS_HW_VLAN |
>> + IXGBE_TX_FLAGS_CC)))
>> return;
>> - vlan_macip_lens = skb_network_offset(skb) <<
>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>> - } else {
>> - u8 l4_hdr = 0;
>> - union {
>> - struct iphdr *ipv4;
>> - struct ipv6hdr *ipv6;
>> - u8 *raw;
>> - } network_hdr;
>> - union {
>> - struct tcphdr *tcphdr;
>> - u8 *raw;
>> - } transport_hdr;
>> - __be16 frag_off;
>> -
>> - if (skb->encapsulation) {
>> - network_hdr.raw = skb_inner_network_header(skb);
>> - transport_hdr.raw = skb_inner_transport_header(skb);
>> - vlan_macip_lens = skb_inner_network_offset(skb) <<
>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>> - } else {
>> - network_hdr.raw = skb_network_header(skb);
>> - transport_hdr.raw = skb_transport_header(skb);
>> - vlan_macip_lens = skb_network_offset(skb) <<
>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>> - }
>> -
>> - /* use first 4 bits to determine IP version */
>> - switch (network_hdr.ipv4->version) {
>> - case IPVERSION:
>> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
>> - l4_hdr = network_hdr.ipv4->protocol;
>> - break;
>> - case 6:
>> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
>> - l4_hdr = network_hdr.ipv6->nexthdr;
>> - if (likely((transport_hdr.raw - network_hdr.raw) ==
>> - sizeof(struct ipv6hdr)))
>> - break;
>> - ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
>> - sizeof(struct ipv6hdr),
>> - &l4_hdr, &frag_off);
>> - if (unlikely(frag_off))
>> - l4_hdr = NEXTHDR_FRAGMENT;
>> - break;
>> - default:
>> - break;
>> - }
>> + goto no_csum;
>> + }
>>
>> - switch (l4_hdr) {
>> - case IPPROTO_TCP:
>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
>> - mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) <<
>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>> - break;
>> - case IPPROTO_SCTP:
>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
>> - mss_l4len_idx = sizeof(struct sctphdr) <<
>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>> - break;
>> - case IPPROTO_UDP:
>> - mss_l4len_idx = sizeof(struct udphdr) <<
>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>> + switch (skb->csum_offset) {
>> + case offsetof(struct tcphdr, check):
>> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
>> + /* fall through */
>> + case offsetof(struct udphdr, check):
>> + break;
>> + case offsetof(struct sctphdr, checksum):
>> + /* validate that this is actually an SCTP request */
>> + if (((first->protocol == htons(ETH_P_IP)) &&
>> + (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
>> + ((first->protocol == htons(ETH_P_IPV6)) &&
>> + ixgbe_ipv6_csum_is_sctp(skb))) {
>> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
>
> I think we're going to have to do something different for SCTP CRC
> this (and FCOE CRC) is a special case of CHECKSUM_PARTIAL that I don't
> think we're always accounting for. For instance, in LCO we are always
> assuming that CHECKSUM_PARTIAL refers to an IP checksum. Maybe it's
> time to add a bit to ip_summed so we can define CHEKCKSUM_SCTP_CRC and
> CHECKSUM_FCOE_CRC?
I was kind of thinking about that, but for now this is mostly just an
intermediate step. My thought was just to add something signifying
that we are requesting a CRC offload, something like a CRC_PARTIAL
As far as I know the tunnels thing won't be an issue since neither
FCoE or SCTP will even attempt to offload the protocol unless the
underlying device supports it. Since no tunnel supports either of
these it isn't an issue as the CRCs will always be computed by
software before passing the frame off to the tunnel.
- Alex
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Intel-wired-lan] [next PATCH 1/4] ixgbe: Add support for generic Tx checksums
2016-01-11 20:29 ` [Intel-wired-lan] " Alexander Duyck
@ 2016-01-11 20:49 ` Tom Herbert
0 siblings, 0 replies; 9+ messages in thread
From: Tom Herbert @ 2016-01-11 20:49 UTC (permalink / raw)
To: Alexander Duyck
Cc: Alexander Duyck, Linux Kernel Network Developers, intel-wired-lan
On Mon, Jan 11, 2016 at 12:29 PM, Alexander Duyck
<alexander.duyck@gmail.com> wrote:
> On Mon, Jan 11, 2016 at 10:11 AM, Tom Herbert <tom@herbertland.com> wrote:
>> On Mon, Jan 11, 2016 at 9:53 AM, Alexander Duyck <aduyck@mirantis.com> wrote:
>>> This patch adds support for generic Tx checksums to the ixgbe driver. It
>>> turns out this is actually pretty easy after going over the datasheet as we
>>> were doing a number of steps we didn't need to.
>>>
>>> In order to perform a Tx checksum for an L4 header we need to fill in the
>>> following fields in the Tx descriptor:
>>> MACLEN (maximum of 127), retrieved from:
>>> skb_network_offset()
>>> IPLEN (maximum of 511), retrieved from:
>>> skb_checksum_start_offset() - skb_network_offset()
>>> TUCMD.L4T indicates offset and if checksum or crc32c, based on:
>>> skb->csum_offset
>>>
>>> The added advantage to doing this is that we can support inner checksum
>>> offloads for tunnels and MPLS while still being able to transparently insert
>>> VLAN tags.
>>>
>>> I also took the opportunity to clean-up many of the feature flag
>>> configuration bits to make them a bit more consistent between drivers.
>>>
>>> Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
>>> ---
>>> drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 163 +++++++++----------------
>>> 1 file changed, 59 insertions(+), 104 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> index 77cdaed6de90..1e3a548cc612 100644
>>> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
>>> @@ -7207,103 +7207,61 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
>>> return 1;
>>> }
>>>
>>> +static inline bool ixgbe_ipv6_csum_is_sctp(struct sk_buff *skb)
>>> +{
>>> + unsigned int offset = 0;
>>> +
>>> + ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
>>> +
>>> + return offset == skb_checksum_start_offset(skb);
>>> +}
>>> +
>>> static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
>>> struct ixgbe_tx_buffer *first)
>>> {
>>> struct sk_buff *skb = first->skb;
>>> u32 vlan_macip_lens = 0;
>>> - u32 mss_l4len_idx = 0;
>>> u32 type_tucmd = 0;
>>>
>>> if (skb->ip_summed != CHECKSUM_PARTIAL) {
>>> - if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) &&
>>> - !(first->tx_flags & IXGBE_TX_FLAGS_CC))
>>> +csum_failed:
>>> + if (!(first->tx_flags & (IXGBE_TX_FLAGS_HW_VLAN |
>>> + IXGBE_TX_FLAGS_CC)))
>>> return;
>>> - vlan_macip_lens = skb_network_offset(skb) <<
>>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>>> - } else {
>>> - u8 l4_hdr = 0;
>>> - union {
>>> - struct iphdr *ipv4;
>>> - struct ipv6hdr *ipv6;
>>> - u8 *raw;
>>> - } network_hdr;
>>> - union {
>>> - struct tcphdr *tcphdr;
>>> - u8 *raw;
>>> - } transport_hdr;
>>> - __be16 frag_off;
>>> -
>>> - if (skb->encapsulation) {
>>> - network_hdr.raw = skb_inner_network_header(skb);
>>> - transport_hdr.raw = skb_inner_transport_header(skb);
>>> - vlan_macip_lens = skb_inner_network_offset(skb) <<
>>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>>> - } else {
>>> - network_hdr.raw = skb_network_header(skb);
>>> - transport_hdr.raw = skb_transport_header(skb);
>>> - vlan_macip_lens = skb_network_offset(skb) <<
>>> - IXGBE_ADVTXD_MACLEN_SHIFT;
>>> - }
>>> -
>>> - /* use first 4 bits to determine IP version */
>>> - switch (network_hdr.ipv4->version) {
>>> - case IPVERSION:
>>> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
>>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
>>> - l4_hdr = network_hdr.ipv4->protocol;
>>> - break;
>>> - case 6:
>>> - vlan_macip_lens |= transport_hdr.raw - network_hdr.raw;
>>> - l4_hdr = network_hdr.ipv6->nexthdr;
>>> - if (likely((transport_hdr.raw - network_hdr.raw) ==
>>> - sizeof(struct ipv6hdr)))
>>> - break;
>>> - ipv6_skip_exthdr(skb, network_hdr.raw - skb->data +
>>> - sizeof(struct ipv6hdr),
>>> - &l4_hdr, &frag_off);
>>> - if (unlikely(frag_off))
>>> - l4_hdr = NEXTHDR_FRAGMENT;
>>> - break;
>>> - default:
>>> - break;
>>> - }
>>> + goto no_csum;
>>> + }
>>>
>>> - switch (l4_hdr) {
>>> - case IPPROTO_TCP:
>>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
>>> - mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) <<
>>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>>> - break;
>>> - case IPPROTO_SCTP:
>>> - type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_SCTP;
>>> - mss_l4len_idx = sizeof(struct sctphdr) <<
>>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>>> - break;
>>> - case IPPROTO_UDP:
>>> - mss_l4len_idx = sizeof(struct udphdr) <<
>>> - IXGBE_ADVTXD_L4LEN_SHIFT;
>>> + switch (skb->csum_offset) {
>>> + case offsetof(struct tcphdr, check):
>>> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
>>> + /* fall through */
>>> + case offsetof(struct udphdr, check):
>>> + break;
>>> + case offsetof(struct sctphdr, checksum):
>>> + /* validate that this is actually an SCTP request */
>>> + if (((first->protocol == htons(ETH_P_IP)) &&
>>> + (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
>>> + ((first->protocol == htons(ETH_P_IPV6)) &&
>>> + ixgbe_ipv6_csum_is_sctp(skb))) {
>>> + type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_SCTP;
>>
>> I think we're going to have to do something different for SCTP CRC
>> this (and FCOE CRC) is a special case of CHECKSUM_PARTIAL that I don't
>> think we're always accounting for. For instance, in LCO we are always
>> assuming that CHECKSUM_PARTIAL refers to an IP checksum. Maybe it's
>> time to add a bit to ip_summed so we can define CHEKCKSUM_SCTP_CRC and
>> CHECKSUM_FCOE_CRC?
>
> I was kind of thinking about that, but for now this is mostly just an
> intermediate step. My thought was just to add something signifying
> that we are requesting a CRC offload, something like a CRC_PARTIAL
>
> As far as I know the tunnels thing won't be an issue since neither
> FCoE or SCTP will even attempt to offload the protocol unless the
> underlying device supports it. Since no tunnel supports either of
> these it isn't an issue as the CRCs will always be computed by
> software before passing the frame off to the tunnel.
>
Right, we're probably okay in the short term, but this will need to be
addressed. Good news is that it looks like on Intel supports SCTP CRC
offload so this is probably manageable to fix.
> - Alex
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
` (3 preceding siblings ...)
2016-01-11 17:54 ` [next PATCH 4/4] igbvf: " Alexander Duyck
@ 2016-01-12 4:43 ` David Miller
4 siblings, 0 replies; 9+ messages in thread
From: David Miller @ 2016-01-12 4:43 UTC (permalink / raw)
To: aduyck; +Cc: intel-wired-lan, jeffrey.t.kirsher, tom, netdev
From: Alexander Duyck <aduyck@mirantis.com>
Date: Mon, 11 Jan 2016 09:53:50 -0800
> It turns out we were doing far more than we needed to in the Tx checksum
> functions for the drivers. As a result it hid the fact that the hardware
> is actually much more capable of handling generic offloads then previously
> realized.
>
> This patch series enables generic Tx checksum support for igb and ixgbe
> based Intel server adapters. In addition it adds a number of other items
> such as:
> Inner checksum support for MPLS
> Encapsulated checksum support for igb, igbvf, and ixgbevf
> SCTP CRC offload support for VLAN tunnels, and VFs
> IPv6 extension header support for igb and igbvf
I like this series, nice work!
This can go in when net-next opens back up, and I assume I'll get
it via Jeff K.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2016-01-12 4:43 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-11 17:53 [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf Alexander Duyck
2016-01-11 17:53 ` [next PATCH 1/4] ixgbe: Add support for generic Tx checksums Alexander Duyck
2016-01-11 18:11 ` Tom Herbert
2016-01-11 20:29 ` [Intel-wired-lan] " Alexander Duyck
2016-01-11 20:49 ` Tom Herbert
2016-01-11 17:54 ` [next PATCH 2/4] ixgbevf: " Alexander Duyck
2016-01-11 17:54 ` [next PATCH 3/4] igb: " Alexander Duyck
2016-01-11 17:54 ` [next PATCH 4/4] igbvf: " Alexander Duyck
2016-01-12 4:43 ` [next PATCH 0/4] Add support for generic Tx checksums to igb, ixgbe, igbvf, ixgbevf David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).