sfc: implement encapsulated TSO on EF10
authorEdward Cree <ecree@solarflare.com>
Fri, 11 Sep 2020 22:40:14 +0000 (23:40 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 12 Sep 2020 00:15:22 +0000 (17:15 -0700)
>From the 8000 series onwards, EF10 NICs with suitable firmware are able
 to perform TSO within VXLAN or NVGRE encapsulation.

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/net_driver.h

index c6507d1..4775b82 100644 (file)
@@ -2179,10 +2179,11 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
                         bool *data_mapped)
 {
        struct efx_tx_buffer *buffer;
+       u16 inner_ipv4_id = 0;
+       u16 outer_ipv4_id = 0;
        struct tcphdr *tcp;
        struct iphdr *ip;
-
-       u16 ipv4_id;
+       u16 ip_tot_len;
        u32 seqnum;
        u32 mss;
 
@@ -2195,21 +2196,43 @@ int efx_ef10_tx_tso_desc(struct efx_tx_queue *tx_queue, struct sk_buff *skb,
                return -EINVAL;
        }
 
-       ip = ip_hdr(skb);
+       if (skb->encapsulation) {
+               if (!tx_queue->tso_encap)
+                       return -EINVAL;
+               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) {
-               /* Modify IPv4 header if needed. */
-               ip->tot_len = 0;
+               ip->tot_len = htons(ip_tot_len);
                ip->check = 0;
-               ipv4_id = ntohs(ip->id);
+               inner_ipv4_id = ntohs(ip->id);
        } else {
-               /* Modify IPv6 header if needed. */
-               struct ipv6hdr *ipv6 = ipv6_hdr(skb);
-
-               ipv6->payload_len = 0;
-               ipv4_id = 0;
+               ((struct ipv6hdr *)ip)->payload_len = htons(ip_tot_len);
        }
 
-       tcp = tcp_hdr(skb);
        seqnum = ntohl(tcp->seq);
 
        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,
                        ESF_DZ_TX_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO,
                        ESF_DZ_TX_TSO_OPTION_TYPE,
                        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
                        );
        ++tx_queue->insert_count;
@@ -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->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_OPTION_TYPE, ESE_DZ_TX_OPTION_DESC_TSO,
                        ESF_DZ_TX_TSO_OPTION_TYPE,
                        ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B,
+                       ESF_DZ_TX_TSO_OUTER_IPID, outer_ipv4_id,
                        ESF_DZ_TX_TSO_TCP_MSS, mss
                        );
        ++tx_queue->insert_count;
@@ -2322,6 +2346,9 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
                             ESF_DZ_TX_TIMESTAMP, tx_queue->timestamping);
        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();
        efx_ef10_push_tx_desc(tx_queue, txd);
 
index ddcd1c4..a4c0445 100644 (file)
@@ -77,6 +77,9 @@
 /* Minimum MTU, from RFC791 (IP) */
 #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,
  * and should be a multiple of the cache line size.
  */
@@ -195,6 +198,7 @@ struct efx_tx_buffer {
  *     Is our index within @channel->tx_queue array.
  * @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_encap: Is encapsulated TSO supported? Supported in TSOv2 on 8000 series.
  * @channel: The associated channel
  * @core_txq: The networking core TX queue structure
  * @buffer: The software buffer ring
@@ -258,6 +262,7 @@ struct efx_tx_queue {
        unsigned int label;
        unsigned int type;
        unsigned int tso_version;
+       bool tso_encap;
        struct efx_channel *channel;
        struct netdev_queue *core_txq;
        struct efx_tx_buffer *buffer;