Skip to content

Commit

Permalink
Merge branch 'sfc-ef100-tso-enhancements'
Browse files Browse the repository at this point in the history
Edward Cree says:

====================
sfc: EF100 TSO enhancements

Support TSO over encapsulation (with GSO_PARTIAL), and over VLANs
 (which the code already handled but we didn't advertise).  Also
 correct our handling of IPID mangling.

I couldn't find documentation of exactly what shaped SKBs we can
 get given, so patch #2 is slightly guesswork, but when I tested
 TSO over both underlay and (VxLAN) overlay, the checksums came
 out correctly, so at least in those cases the edits we're making
 must be the right ones.
Similarly, I'm not 100% sure I've correctly understood how FIXEDID
 and MANGLEID are supposed to work in patch #3.
====================

Link: https://lore.kernel.org/r/6e1ea05f-faeb-18df-91ef-572445691d89@solarflare.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Oct 31, 2020
2 parents dc95658 + b61e810 commit 8ece853
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 33 deletions.
42 changes: 37 additions & 5 deletions drivers/net/ethernet/sfc/bitfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,11 @@ typedef union efx_oword {
field10, value10, \
field11, value11, \
field12, value12, \
field13, value13) \
field13, value13, \
field14, value14, \
field15, value15, \
field16, value16, \
field17, value17) \
(EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
Expand All @@ -298,7 +302,11 @@ typedef union efx_oword {
EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field11, (value11)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field12, (value12)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field13, (value13)))
EFX_INSERT_FIELD_NATIVE((min), (max), field13, (value13)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field14, (value14)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field15, (value15)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field16, (value16)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field17, (value17)))

#define EFX_INSERT_FIELDS64(...) \
cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
Expand Down Expand Up @@ -340,7 +348,15 @@ typedef union efx_oword {
#endif

/* Populate an octword field with various numbers of arguments */
#define EFX_POPULATE_OWORD_13 EFX_POPULATE_OWORD
#define EFX_POPULATE_OWORD_17 EFX_POPULATE_OWORD
#define EFX_POPULATE_OWORD_16(oword, ...) \
EFX_POPULATE_OWORD_17(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_15(oword, ...) \
EFX_POPULATE_OWORD_16(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_14(oword, ...) \
EFX_POPULATE_OWORD_15(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_13(oword, ...) \
EFX_POPULATE_OWORD_14(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_12(oword, ...) \
EFX_POPULATE_OWORD_13(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_11(oword, ...) \
Expand Down Expand Up @@ -375,7 +391,15 @@ typedef union efx_oword {
EFX_DWORD_3, 0xffffffff)

/* Populate a quadword field with various numbers of arguments */
#define EFX_POPULATE_QWORD_13 EFX_POPULATE_QWORD
#define EFX_POPULATE_QWORD_17 EFX_POPULATE_QWORD
#define EFX_POPULATE_QWORD_16(qword, ...) \
EFX_POPULATE_QWORD_17(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_15(qword, ...) \
EFX_POPULATE_QWORD_16(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_14(qword, ...) \
EFX_POPULATE_QWORD_15(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_13(qword, ...) \
EFX_POPULATE_QWORD_14(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_12(qword, ...) \
EFX_POPULATE_QWORD_13(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_11(qword, ...) \
Expand Down Expand Up @@ -408,7 +432,15 @@ typedef union efx_oword {
EFX_DWORD_1, 0xffffffff)

/* Populate a dword field with various numbers of arguments */
#define EFX_POPULATE_DWORD_13 EFX_POPULATE_DWORD
#define EFX_POPULATE_DWORD_17 EFX_POPULATE_DWORD
#define EFX_POPULATE_DWORD_16(dword, ...) \
EFX_POPULATE_DWORD_17(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_15(dword, ...) \
EFX_POPULATE_DWORD_16(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_14(dword, ...) \
EFX_POPULATE_DWORD_15(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_13(dword, ...) \
EFX_POPULATE_DWORD_14(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_12(dword, ...) \
EFX_POPULATE_DWORD_13(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_11(dword, ...) \
Expand Down
17 changes: 14 additions & 3 deletions drivers/net/ethernet/sfc/ef100_nic.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,16 @@ static int efx_ef100_init_datapath_caps(struct efx_nic *efx)
if (rc)
return rc;

if (efx_ef100_has_cap(nic_data->datapath_caps2, TX_TSO_V3))
efx->net_dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
if (efx_ef100_has_cap(nic_data->datapath_caps2, TX_TSO_V3)) {
struct net_device *net_dev = efx->net_dev;
netdev_features_t tso = NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_PARTIAL |
NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM;

net_dev->features |= tso;
net_dev->hw_features |= tso;
net_dev->hw_enc_features |= tso;
net_dev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM;
}
efx->num_mac_stats = MCDI_WORD(outbuf,
GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS);
netif_dbg(efx, probe, efx->net_dev,
Expand Down Expand Up @@ -686,7 +694,7 @@ static unsigned int ef100_check_caps(const struct efx_nic *efx,
#define EF100_OFFLOAD_FEATURES (NETIF_F_HW_CSUM | NETIF_F_RXCSUM | \
NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_NTUPLE | \
NETIF_F_RXHASH | NETIF_F_RXFCS | NETIF_F_TSO_ECN | NETIF_F_RXALL | \
NETIF_F_TSO_MANGLEID | NETIF_F_HW_VLAN_CTAG_TX)
NETIF_F_HW_VLAN_CTAG_TX)

const struct efx_nic_type ef100_pf_nic_type = {
.revision = EFX_REV_EF100,
Expand Down Expand Up @@ -1101,6 +1109,9 @@ static int ef100_probe_main(struct efx_nic *efx)
nic_data->efx = efx;
net_dev->features |= efx->type->offload_features;
net_dev->hw_features |= efx->type->offload_features;
net_dev->hw_enc_features |= efx->type->offload_features;
net_dev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_ALL_TSO;

/* Populate design-parameter defaults */
nic_data->tso_max_hdr_len = ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT;
Expand Down
58 changes: 33 additions & 25 deletions drivers/net/ethernet/sfc/ef100_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ static bool ef100_tx_can_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
struct efx_nic *efx = tx_queue->efx;
struct ef100_nic_data *nic_data;
struct efx_tx_buffer *buffer;
struct tcphdr *tcphdr;
struct iphdr *iphdr;
size_t header_len;
u32 mss;

Expand Down Expand Up @@ -98,20 +96,6 @@ static bool ef100_tx_can_tso(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
buffer->unmap_len = 0;
buffer->skb = skb;
++tx_queue->insert_count;

/* Adjust the TCP checksum to exclude the total length, since we set
* ED_INNER_IP_LEN in the descriptor.
*/
tcphdr = tcp_hdr(skb);
if (skb_is_gso_v6(skb)) {
tcphdr->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
0, IPPROTO_TCP, 0);
} else {
iphdr = ip_hdr(skb);
tcphdr->check = ~csum_tcpudp_magic(iphdr->saddr, iphdr->daddr,
0, IPPROTO_TCP, 0);
}
return true;
}

Expand Down Expand Up @@ -203,23 +187,42 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
struct efx_tx_buffer *buffer, efx_oword_t *txd,
unsigned int segment_count)
{
u32 mangleid = (efx->net_dev->features & NETIF_F_TSO_MANGLEID) ||
skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID ?
ESE_GZ_TX_DESC_IP4_ID_NO_OP :
ESE_GZ_TX_DESC_IP4_ID_INC_MOD16;
u16 vlan_enable = efx->net_dev->features & NETIF_F_HW_VLAN_CTAG_TX ?
skb_vlan_tag_present(skb) : 0;
bool gso_partial = skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL;
unsigned int len, ip_offset, tcp_offset, payload_segs;
u32 mangleid = ESE_GZ_TX_DESC_IP4_ID_INC_MOD16;
unsigned int outer_ip_offset, outer_l4_offset;
u16 vlan_tci = skb_vlan_tag_get(skb);
u32 mss = skb_shinfo(skb)->gso_size;
bool encap = skb->encapsulation;
u16 vlan_enable = 0;
struct tcphdr *tcp;
u32 paylen;

if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID)
mangleid = ESE_GZ_TX_DESC_IP4_ID_NO_OP;
if (efx->net_dev->features & NETIF_F_HW_VLAN_CTAG_TX)
vlan_enable = skb_vlan_tag_present(skb);

len = skb->len - buffer->len;
/* We use 1 for the TSO descriptor and 1 for the header */
payload_segs = segment_count - 2;
ip_offset = skb_network_offset(skb);
tcp_offset = skb_transport_offset(skb);
if (encap) {
outer_ip_offset = skb_network_offset(skb);
outer_l4_offset = skb_transport_offset(skb);
ip_offset = skb_inner_network_offset(skb);
tcp_offset = skb_inner_transport_offset(skb);
} else {
ip_offset = skb_network_offset(skb);
tcp_offset = skb_transport_offset(skb);
outer_ip_offset = outer_l4_offset = 0;
}

/* subtract TCP payload length from inner checksum */
tcp = (void *)skb->data + tcp_offset;
paylen = skb->len - tcp_offset;
csum_replace_by_diff(&tcp->check, (__force __wsum)htonl(paylen));

EFX_POPULATE_OWORD_13(*txd,
EFX_POPULATE_OWORD_17(*txd,
ESF_GZ_TX_DESC_TYPE, ESE_GZ_TX_DESC_TYPE_TSO,
ESF_GZ_TX_TSO_MSS, mss,
ESF_GZ_TX_TSO_HDR_NUM_SEGS, 1,
Expand All @@ -231,6 +234,11 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
ESF_GZ_TX_TSO_INNER_L4_OFF_W, tcp_offset >> 1,
ESF_GZ_TX_TSO_ED_INNER_IP4_ID, mangleid,
ESF_GZ_TX_TSO_ED_INNER_IP_LEN, 1,
ESF_GZ_TX_TSO_OUTER_L3_OFF_W, outer_ip_offset >> 1,
ESF_GZ_TX_TSO_OUTER_L4_OFF_W, outer_l4_offset >> 1,
ESF_GZ_TX_TSO_ED_OUTER_UDP_LEN, encap && !gso_partial,
ESF_GZ_TX_TSO_ED_OUTER_IP4_ID, encap ? mangleid :
ESE_GZ_TX_DESC_IP4_ID_NO_OP,
ESF_GZ_TX_TSO_VLAN_INSERT_EN, vlan_enable,
ESF_GZ_TX_TSO_VLAN_INSERT_TCI, vlan_tci
);
Expand Down

0 comments on commit 8ece853

Please sign in to comment.