Commit 806f9f23 authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski

sfc: implement encap TSO on EF100

The NIC only needs to know where the headers it has to edit (TCP and
 inner and outer IPv4) are, which fits GSO_PARTIAL nicely.
It also supports non-PARTIAL offload of UDP tunnels, again just
 needing to be told the outer transport offset so that it can edit
 the UDP length field.
(It's not clear to me whether the stack will ever use the non-PARTIAL
 version with the netdev feature flags we're setting here.)
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a7a375ca
......@@ -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,
......@@ -1101,6 +1109,7 @@ 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;
/* Populate design-parameter defaults */
nic_data->tso_max_hdr_len = ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT;
......
......@@ -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;
......@@ -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;
}
......@@ -209,17 +193,35 @@ static void ef100_make_tso_desc(struct efx_nic *efx,
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;
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;
struct tcphdr *tcp;
u32 paylen;
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,
......@@ -231,6 +233,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
);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment