Commit 0ce8df66 authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: implement encapsulated TSO on EF10

>From the 8000 series onwards, EF10 NICs with suitable firmware are able
 to perform TSO within VXLAN or NVGRE encapsulation.
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1679c72c
...@@ -2179,10 +2179,11 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb, ...@@ -2179,10 +2179,11 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
bool *data_mapped) bool *data_mapped)
{ {
struct efx_tx_buffer *buffer; struct efx_tx_buffer *buffer;
u16 inner_ipv4_id = 0;
u16 outer_ipv4_id = 0;
struct tcphdr *tcp; struct tcphdr *tcp;
struct iphdr *ip; struct iphdr *ip;
u16 ip_tot_len;
u16 ipv4_id;
u32 seqnum; u32 seqnum;
u32 mss; u32 mss;
...@@ -2195,21 +2196,43 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb, ...@@ -2195,21 +2196,43 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
return -EINVAL; return -EINVAL;
} }
if (skb->encapsulation) {
if (!tx_queue->tso_encap)
return -EINVAL;
ip = ip_hdr(skb); ip = ip_hdr(skb);
if (ip->version == 4)
outer_ipv4_id = ntohs(ip->id);
ip = inner_ip_hdr(skb);
tcp = inner_tcp_hdr(skb);
} else {
ip = ip_hdr(skb);
tcp = tcp_hdr(skb);
}
/* 8000-series EF10 hardware requires that IP Total Length be
* greater than or equal to the value it will have in each segment
* (which is at most mss + 208 + TCP header length), but also less
* than (0x10000 - inner_network_header). Otherwise the TCP
* checksum calculation will be broken for encapsulated packets.
* We fill in ip->tot_len with 0xff30, which should satisfy the
* first requirement unless the MSS is ridiculously large (which
* should be impossible as the driver max MTU is 9216); it is
* guaranteed to satisfy the second as we only attempt TSO if
* inner_network_header <= 208.
*/
ip_tot_len = -EFX_TSO2_MAX_HDRLEN;
EFX_WARN_ON_ONCE_PARANOID(mss + EFX_TSO2_MAX_HDRLEN +
(tcp->doff << 2u) > ip_tot_len);
if (ip->version == 4) { if (ip->version == 4) {
/* Modify IPv4 header if needed. */ ip->tot_len = htons(ip_tot_len);
ip->tot_len = 0;
ip->check = 0; ip->check = 0;
ipv4_id = ntohs(ip->id); inner_ipv4_id = ntohs(ip->id);
} else { } else {
/* Modify IPv6 header if needed. */ ((struct ipv6hdr *)ip)->payload_len = htons(ip_tot_len);
struct ipv6hdr *ipv6 = ipv6_hdr(skb);
ipv6->payload_len = 0;
ipv4_id = 0;
} }
tcp = tcp_hdr(skb);
seqnum = ntohl(tcp->seq); seqnum = ntohl(tcp->seq);
buffer = efx_tx_queue_get_insert_buffer(tx_queue); buffer = efx_tx_queue_get_insert_buffer(tx_queue);
...@@ -2222,7 +2245,7 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb, ...@@ -2222,7 +2245,7 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO, ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO,
ESF_DZ_TX_TSO_OPTION_TYPE, ESF_DZ_TX_TSO_OPTION_TYPE,
ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A, ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A,
ESF_DZ_TX_TSO_IP_ID, ipv4_id, ESF_DZ_TX_TSO_IP_ID, inner_ipv4_id,
ESF_DZ_TX_TSO_TCP_SEQNO, seqnum ESF_DZ_TX_TSO_TCP_SEQNO, seqnum
); );
++tx_queue->insert_count; ++tx_queue->insert_count;
...@@ -2232,11 +2255,12 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb, ...@@ -2232,11 +2255,12 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
buffer->flags = EFX_TX_BUF_OPTION; buffer->flags = EFX_TX_BUF_OPTION;
buffer->len = 0; buffer->len = 0;
buffer->unmap_len = 0; buffer->unmap_len = 0;
EFX_POPULATE_QWORD_4(buffer->option, EFX_POPULATE_QWORD_5(buffer->option,
ESF_DZ_TX_DESC_IS_OPT, 1, ESF_DZ_TX_DESC_IS_OPT, 1,
ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO, ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO,
ESF_DZ_TX_TSO_OPTION_TYPE, ESF_DZ_TX_TSO_OPTION_TYPE,
ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B, ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B,
ESF_DZ_TX_TSO_OUTER_IPID, outer_ipv4_id,
ESF_DZ_TX_TSO_TCP_MSS, mss ESF_DZ_TX_TSO_TCP_MSS, mss
); );
++tx_queue->insert_count; ++tx_queue->insert_count;
...@@ -2322,6 +2346,9 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) ...@@ -2322,6 +2346,9 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
ESF_DZ_TX_TIMESTAMP, tx_queue->timestamping); ESF_DZ_TX_TIMESTAMP, tx_queue->timestamping);
tx_queue->write_count = 1; tx_queue->write_count = 1;
if (tx_queue->tso_version == 2 && efx_has_cap(efx, TX_TSO_V2_ENCAP))
tx_queue->tso_encap = true;
wmb(); wmb();
efx_ef10_push_tx_desc(tx_queue, txd); efx_ef10_push_tx_desc(tx_queue, txd);
......
...@@ -77,6 +77,9 @@ ...@@ -77,6 +77,9 @@
/* Minimum MTU, from RFC791 (IP) */ /* Minimum MTU, from RFC791 (IP) */
#define EFX_MIN_MTU 68 #define EFX_MIN_MTU 68
/* Maximum total header length for TSOv2 */
#define EFX_TSO2_MAX_HDRLEN 208
/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page, /* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page,
* and should be a multiple of the cache line size. * and should be a multiple of the cache line size.
*/ */
...@@ -195,6 +198,7 @@ struct efx_tx_buffer { ...@@ -195,6 +198,7 @@ struct efx_tx_buffer {
* Is our index within @channel->tx_queue array. * Is our index within @channel->tx_queue array.
* @type: configuration type of this TX queue. A bitmask of %EFX_TXQ_TYPE_* flags. * @type: configuration type of this TX queue. A bitmask of %EFX_TXQ_TYPE_* flags.
* @tso_version: Version of TSO in use for this queue. * @tso_version: Version of TSO in use for this queue.
* @tso_encap: Is encapsulated TSO supported? Supported in TSOv2 on 8000 series.
* @channel: The associated channel * @channel: The associated channel
* @core_txq: The networking core TX queue structure * @core_txq: The networking core TX queue structure
* @buffer: The software buffer ring * @buffer: The software buffer ring
...@@ -258,6 +262,7 @@ struct efx_tx_queue { ...@@ -258,6 +262,7 @@ struct efx_tx_queue {
unsigned int label; unsigned int label;
unsigned int type; unsigned int type;
unsigned int tso_version; unsigned int tso_version;
bool tso_encap;
struct efx_channel *channel; struct efx_channel *channel;
struct netdev_queue *core_txq; struct netdev_queue *core_txq;
struct efx_tx_buffer *buffer; struct efx_tx_buffer *buffer;
......
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