18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * Driver for Solarflare network controllers and boards 48c2ecf20Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 58c2ecf20Sopenharmony_ci * Copyright 2005-2015 Solarflare Communications Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/tcp.h> 108c2ecf20Sopenharmony_ci#include <linux/ip.h> 118c2ecf20Sopenharmony_ci#include <linux/in.h> 128c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <net/ipv6.h> 158c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 168c2ecf20Sopenharmony_ci#include <linux/highmem.h> 178c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 188c2ecf20Sopenharmony_ci#include <linux/cache.h> 198c2ecf20Sopenharmony_ci#include "net_driver.h" 208c2ecf20Sopenharmony_ci#include "efx.h" 218c2ecf20Sopenharmony_ci#include "io.h" 228c2ecf20Sopenharmony_ci#include "nic.h" 238c2ecf20Sopenharmony_ci#include "tx.h" 248c2ecf20Sopenharmony_ci#include "workarounds.h" 258c2ecf20Sopenharmony_ci#include "ef10_regs.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Efx legacy TCP segmentation acceleration. 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Utilises firmware support to go faster than GSO (but not as fast as TSOv2). 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Requires TX checksum offload support. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define PTR_DIFF(p1, p2) ((u8 *)(p1) - (u8 *)(p2)) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/** 378c2ecf20Sopenharmony_ci * struct tso_state - TSO state for an SKB 388c2ecf20Sopenharmony_ci * @out_len: Remaining length in current segment 398c2ecf20Sopenharmony_ci * @seqnum: Current sequence number 408c2ecf20Sopenharmony_ci * @ipv4_id: Current IPv4 ID, host endian 418c2ecf20Sopenharmony_ci * @packet_space: Remaining space in current packet 428c2ecf20Sopenharmony_ci * @dma_addr: DMA address of current position 438c2ecf20Sopenharmony_ci * @in_len: Remaining length in current SKB fragment 448c2ecf20Sopenharmony_ci * @unmap_len: Length of SKB fragment 458c2ecf20Sopenharmony_ci * @unmap_addr: DMA address of SKB fragment 468c2ecf20Sopenharmony_ci * @protocol: Network protocol (after any VLAN header) 478c2ecf20Sopenharmony_ci * @ip_off: Offset of IP header 488c2ecf20Sopenharmony_ci * @tcp_off: Offset of TCP header 498c2ecf20Sopenharmony_ci * @header_len: Number of bytes of header 508c2ecf20Sopenharmony_ci * @ip_base_len: IPv4 tot_len or IPv6 payload_len, before TCP payload 518c2ecf20Sopenharmony_ci * @header_dma_addr: Header DMA address 528c2ecf20Sopenharmony_ci * @header_unmap_len: Header DMA mapped length 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * The state used during segmentation. It is put into this data structure 558c2ecf20Sopenharmony_ci * just to make it easy to pass into inline functions. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistruct tso_state { 588c2ecf20Sopenharmony_ci /* Output position */ 598c2ecf20Sopenharmony_ci unsigned int out_len; 608c2ecf20Sopenharmony_ci unsigned int seqnum; 618c2ecf20Sopenharmony_ci u16 ipv4_id; 628c2ecf20Sopenharmony_ci unsigned int packet_space; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Input position */ 658c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 668c2ecf20Sopenharmony_ci unsigned int in_len; 678c2ecf20Sopenharmony_ci unsigned int unmap_len; 688c2ecf20Sopenharmony_ci dma_addr_t unmap_addr; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci __be16 protocol; 718c2ecf20Sopenharmony_ci unsigned int ip_off; 728c2ecf20Sopenharmony_ci unsigned int tcp_off; 738c2ecf20Sopenharmony_ci unsigned int header_len; 748c2ecf20Sopenharmony_ci unsigned int ip_base_len; 758c2ecf20Sopenharmony_ci dma_addr_t header_dma_addr; 768c2ecf20Sopenharmony_ci unsigned int header_unmap_len; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline void prefetch_ptr(struct efx_tx_queue *tx_queue) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned int insert_ptr = efx_tx_queue_get_insert_index(tx_queue); 828c2ecf20Sopenharmony_ci char *ptr; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ptr = (char *) (tx_queue->buffer + insert_ptr); 858c2ecf20Sopenharmony_ci prefetch(ptr); 868c2ecf20Sopenharmony_ci prefetch(ptr + 0x80); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ptr = (char *) (((efx_qword_t *)tx_queue->txd.buf.addr) + insert_ptr); 898c2ecf20Sopenharmony_ci prefetch(ptr); 908c2ecf20Sopenharmony_ci prefetch(ptr + 0x80); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * efx_tx_queue_insert - push descriptors onto the TX queue 958c2ecf20Sopenharmony_ci * @tx_queue: Efx TX queue 968c2ecf20Sopenharmony_ci * @dma_addr: DMA address of fragment 978c2ecf20Sopenharmony_ci * @len: Length of fragment 988c2ecf20Sopenharmony_ci * @final_buffer: The final buffer inserted into the queue 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Push descriptors onto the TX queue. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic void efx_tx_queue_insert(struct efx_tx_queue *tx_queue, 1038c2ecf20Sopenharmony_ci dma_addr_t dma_addr, unsigned int len, 1048c2ecf20Sopenharmony_ci struct efx_tx_buffer **final_buffer) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct efx_tx_buffer *buffer; 1078c2ecf20Sopenharmony_ci unsigned int dma_len; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(len <= 0); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci while (1) { 1128c2ecf20Sopenharmony_ci buffer = efx_tx_queue_get_insert_buffer(tx_queue); 1138c2ecf20Sopenharmony_ci ++tx_queue->insert_count; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(tx_queue->insert_count - 1168c2ecf20Sopenharmony_ci tx_queue->read_count >= 1178c2ecf20Sopenharmony_ci tx_queue->efx->txq_entries); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci buffer->dma_addr = dma_addr; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci dma_len = tx_queue->efx->type->tx_limit_len(tx_queue, 1228c2ecf20Sopenharmony_ci dma_addr, len); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* If there's space for everything this is our last buffer. */ 1258c2ecf20Sopenharmony_ci if (dma_len >= len) 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci buffer->len = dma_len; 1298c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_CONT; 1308c2ecf20Sopenharmony_ci dma_addr += dma_len; 1318c2ecf20Sopenharmony_ci len -= dma_len; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(!len); 1358c2ecf20Sopenharmony_ci buffer->len = len; 1368c2ecf20Sopenharmony_ci *final_buffer = buffer; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * Verify that our various assumptions about sk_buffs and the conditions 1418c2ecf20Sopenharmony_ci * under which TSO will be attempted hold true. Return the protocol number. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic __be16 efx_tso_check_protocol(struct sk_buff *skb) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci __be16 protocol = skb->protocol; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(((struct ethhdr *)skb->data)->h_proto != 1488c2ecf20Sopenharmony_ci protocol); 1498c2ecf20Sopenharmony_ci if (protocol == htons(ETH_P_8021Q)) { 1508c2ecf20Sopenharmony_ci struct vlan_ethhdr *veh = skb_vlan_eth_hdr(skb); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci protocol = veh->h_vlan_encapsulated_proto; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (protocol == htons(ETH_P_IP)) { 1568c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); 1578c2ecf20Sopenharmony_ci } else { 1588c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(protocol != htons(ETH_P_IPV6)); 1598c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) + 1628c2ecf20Sopenharmony_ci (tcp_hdr(skb)->doff << 2u)) > 1638c2ecf20Sopenharmony_ci skb_headlen(skb)); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return protocol; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* Parse the SKB header and initialise state. */ 1698c2ecf20Sopenharmony_cistatic int tso_start(struct tso_state *st, struct efx_nic *efx, 1708c2ecf20Sopenharmony_ci struct efx_tx_queue *tx_queue, 1718c2ecf20Sopenharmony_ci const struct sk_buff *skb) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct device *dma_dev = &efx->pci_dev->dev; 1748c2ecf20Sopenharmony_ci unsigned int header_len, in_len; 1758c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci st->ip_off = skb_network_header(skb) - skb->data; 1788c2ecf20Sopenharmony_ci st->tcp_off = skb_transport_header(skb) - skb->data; 1798c2ecf20Sopenharmony_ci header_len = st->tcp_off + (tcp_hdr(skb)->doff << 2u); 1808c2ecf20Sopenharmony_ci in_len = skb_headlen(skb) - header_len; 1818c2ecf20Sopenharmony_ci st->header_len = header_len; 1828c2ecf20Sopenharmony_ci st->in_len = in_len; 1838c2ecf20Sopenharmony_ci if (st->protocol == htons(ETH_P_IP)) { 1848c2ecf20Sopenharmony_ci st->ip_base_len = st->header_len - st->ip_off; 1858c2ecf20Sopenharmony_ci st->ipv4_id = ntohs(ip_hdr(skb)->id); 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci st->ip_base_len = st->header_len - st->tcp_off; 1888c2ecf20Sopenharmony_ci st->ipv4_id = 0; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci st->seqnum = ntohl(tcp_hdr(skb)->seq); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(tcp_hdr(skb)->urg); 1938c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(tcp_hdr(skb)->syn); 1948c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(tcp_hdr(skb)->rst); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci st->out_len = skb->len - header_len; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci dma_addr = dma_map_single(dma_dev, skb->data, 1998c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 2008c2ecf20Sopenharmony_ci st->header_dma_addr = dma_addr; 2018c2ecf20Sopenharmony_ci st->header_unmap_len = skb_headlen(skb); 2028c2ecf20Sopenharmony_ci st->dma_addr = dma_addr + header_len; 2038c2ecf20Sopenharmony_ci st->unmap_len = 0; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return unlikely(dma_mapping_error(dma_dev, dma_addr)) ? -ENOMEM : 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int tso_get_fragment(struct tso_state *st, struct efx_nic *efx, 2098c2ecf20Sopenharmony_ci skb_frag_t *frag) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci st->unmap_addr = skb_frag_dma_map(&efx->pci_dev->dev, frag, 0, 2128c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 2138c2ecf20Sopenharmony_ci if (likely(!dma_mapping_error(&efx->pci_dev->dev, st->unmap_addr))) { 2148c2ecf20Sopenharmony_ci st->unmap_len = skb_frag_size(frag); 2158c2ecf20Sopenharmony_ci st->in_len = skb_frag_size(frag); 2168c2ecf20Sopenharmony_ci st->dma_addr = st->unmap_addr; 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci return -ENOMEM; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * tso_fill_packet_with_fragment - form descriptors for the current fragment 2258c2ecf20Sopenharmony_ci * @tx_queue: Efx TX queue 2268c2ecf20Sopenharmony_ci * @skb: Socket buffer 2278c2ecf20Sopenharmony_ci * @st: TSO state 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * Form descriptors for the current fragment, until we reach the end 2308c2ecf20Sopenharmony_ci * of fragment or end-of-packet. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic void tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue, 2338c2ecf20Sopenharmony_ci const struct sk_buff *skb, 2348c2ecf20Sopenharmony_ci struct tso_state *st) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct efx_tx_buffer *buffer; 2378c2ecf20Sopenharmony_ci int n; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (st->in_len == 0) 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_ci if (st->packet_space == 0) 2428c2ecf20Sopenharmony_ci return; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(st->in_len <= 0); 2458c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(st->packet_space <= 0); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci n = min(st->in_len, st->packet_space); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci st->packet_space -= n; 2508c2ecf20Sopenharmony_ci st->out_len -= n; 2518c2ecf20Sopenharmony_ci st->in_len -= n; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci efx_tx_queue_insert(tx_queue, st->dma_addr, n, &buffer); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (st->out_len == 0) { 2568c2ecf20Sopenharmony_ci /* Transfer ownership of the skb */ 2578c2ecf20Sopenharmony_ci buffer->skb = skb; 2588c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_SKB; 2598c2ecf20Sopenharmony_ci } else if (st->packet_space != 0) { 2608c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_CONT; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (st->in_len == 0) { 2648c2ecf20Sopenharmony_ci /* Transfer ownership of the DMA mapping */ 2658c2ecf20Sopenharmony_ci buffer->unmap_len = st->unmap_len; 2668c2ecf20Sopenharmony_ci buffer->dma_offset = buffer->unmap_len - buffer->len; 2678c2ecf20Sopenharmony_ci st->unmap_len = 0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci st->dma_addr += n; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define TCP_FLAGS_OFFSET 13 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/** 2778c2ecf20Sopenharmony_ci * tso_start_new_packet - generate a new header and prepare for the new packet 2788c2ecf20Sopenharmony_ci * @tx_queue: Efx TX queue 2798c2ecf20Sopenharmony_ci * @skb: Socket buffer 2808c2ecf20Sopenharmony_ci * @st: TSO state 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Generate a new header and prepare for the new packet. Return 0 on 2838c2ecf20Sopenharmony_ci * success, or -%ENOMEM if failed to alloc header, or other negative error. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic int tso_start_new_packet(struct efx_tx_queue *tx_queue, 2868c2ecf20Sopenharmony_ci const struct sk_buff *skb, 2878c2ecf20Sopenharmony_ci struct tso_state *st) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct efx_tx_buffer *buffer = 2908c2ecf20Sopenharmony_ci efx_tx_queue_get_insert_buffer(tx_queue); 2918c2ecf20Sopenharmony_ci bool is_last = st->out_len <= skb_shinfo(skb)->gso_size; 2928c2ecf20Sopenharmony_ci u8 tcp_flags_mask, tcp_flags; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!is_last) { 2958c2ecf20Sopenharmony_ci st->packet_space = skb_shinfo(skb)->gso_size; 2968c2ecf20Sopenharmony_ci tcp_flags_mask = 0x09; /* mask out FIN and PSH */ 2978c2ecf20Sopenharmony_ci } else { 2988c2ecf20Sopenharmony_ci st->packet_space = st->out_len; 2998c2ecf20Sopenharmony_ci tcp_flags_mask = 0x00; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (WARN_ON(!st->header_unmap_len)) 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci /* Send the original headers with a TSO option descriptor 3058c2ecf20Sopenharmony_ci * in front 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci tcp_flags = ((u8 *)tcp_hdr(skb))[TCP_FLAGS_OFFSET] & ~tcp_flags_mask; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_OPTION; 3108c2ecf20Sopenharmony_ci buffer->len = 0; 3118c2ecf20Sopenharmony_ci buffer->unmap_len = 0; 3128c2ecf20Sopenharmony_ci EFX_POPULATE_QWORD_5(buffer->option, 3138c2ecf20Sopenharmony_ci ESF_DZ_TX_DESC_IS_OPT, 1, 3148c2ecf20Sopenharmony_ci ESF_DZ_TX_OPTION_TYPE, 3158c2ecf20Sopenharmony_ci ESE_DZ_TX_OPTION_DESC_TSO, 3168c2ecf20Sopenharmony_ci ESF_DZ_TX_TSO_TCP_FLAGS, tcp_flags, 3178c2ecf20Sopenharmony_ci ESF_DZ_TX_TSO_IP_ID, st->ipv4_id, 3188c2ecf20Sopenharmony_ci ESF_DZ_TX_TSO_TCP_SEQNO, st->seqnum); 3198c2ecf20Sopenharmony_ci ++tx_queue->insert_count; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* We mapped the headers in tso_start(). Unmap them 3228c2ecf20Sopenharmony_ci * when the last segment is completed. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci buffer = efx_tx_queue_get_insert_buffer(tx_queue); 3258c2ecf20Sopenharmony_ci buffer->dma_addr = st->header_dma_addr; 3268c2ecf20Sopenharmony_ci buffer->len = st->header_len; 3278c2ecf20Sopenharmony_ci if (is_last) { 3288c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_MAP_SINGLE; 3298c2ecf20Sopenharmony_ci buffer->unmap_len = st->header_unmap_len; 3308c2ecf20Sopenharmony_ci buffer->dma_offset = 0; 3318c2ecf20Sopenharmony_ci /* Ensure we only unmap them once in case of a 3328c2ecf20Sopenharmony_ci * later DMA mapping error and rollback 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci st->header_unmap_len = 0; 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci buffer->flags = EFX_TX_BUF_CONT; 3378c2ecf20Sopenharmony_ci buffer->unmap_len = 0; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci ++tx_queue->insert_count; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci st->seqnum += skb_shinfo(skb)->gso_size; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Linux leaves suitable gaps in the IP ID space for us to fill. */ 3448c2ecf20Sopenharmony_ci ++st->ipv4_id; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/** 3508c2ecf20Sopenharmony_ci * efx_enqueue_skb_tso - segment and transmit a TSO socket buffer 3518c2ecf20Sopenharmony_ci * @tx_queue: Efx TX queue 3528c2ecf20Sopenharmony_ci * @skb: Socket buffer 3538c2ecf20Sopenharmony_ci * @data_mapped: Did we map the data? Always set to true 3548c2ecf20Sopenharmony_ci * by this on success. 3558c2ecf20Sopenharmony_ci * 3568c2ecf20Sopenharmony_ci * Context: You must hold netif_tx_lock() to call this function. 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * Add socket buffer @skb to @tx_queue, doing TSO or return != 0 if 3598c2ecf20Sopenharmony_ci * @skb was not enqueued. @skb is consumed unless return value is 3608c2ecf20Sopenharmony_ci * %EINVAL. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ciint efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, 3638c2ecf20Sopenharmony_ci struct sk_buff *skb, 3648c2ecf20Sopenharmony_ci bool *data_mapped) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct efx_nic *efx = tx_queue->efx; 3678c2ecf20Sopenharmony_ci int frag_i, rc; 3688c2ecf20Sopenharmony_ci struct tso_state state; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (tx_queue->tso_version != 1) 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci prefetch(skb->data); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Find the packet protocol and sanity-check it */ 3768c2ecf20Sopenharmony_ci state.protocol = efx_tso_check_protocol(skb); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(tx_queue->write_count != tx_queue->insert_count); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci rc = tso_start(&state, efx, tx_queue, skb); 3818c2ecf20Sopenharmony_ci if (rc) 3828c2ecf20Sopenharmony_ci goto fail; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (likely(state.in_len == 0)) { 3858c2ecf20Sopenharmony_ci /* Grab the first payload fragment. */ 3868c2ecf20Sopenharmony_ci EFX_WARN_ON_ONCE_PARANOID(skb_shinfo(skb)->nr_frags < 1); 3878c2ecf20Sopenharmony_ci frag_i = 0; 3888c2ecf20Sopenharmony_ci rc = tso_get_fragment(&state, efx, 3898c2ecf20Sopenharmony_ci skb_shinfo(skb)->frags + frag_i); 3908c2ecf20Sopenharmony_ci if (rc) 3918c2ecf20Sopenharmony_ci goto fail; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci /* Payload starts in the header area. */ 3948c2ecf20Sopenharmony_ci frag_i = -1; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci rc = tso_start_new_packet(tx_queue, skb, &state); 3988c2ecf20Sopenharmony_ci if (rc) 3998c2ecf20Sopenharmony_ci goto fail; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci prefetch_ptr(tx_queue); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci while (1) { 4048c2ecf20Sopenharmony_ci tso_fill_packet_with_fragment(tx_queue, skb, &state); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Move onto the next fragment? */ 4078c2ecf20Sopenharmony_ci if (state.in_len == 0) { 4088c2ecf20Sopenharmony_ci if (++frag_i >= skb_shinfo(skb)->nr_frags) 4098c2ecf20Sopenharmony_ci /* End of payload reached. */ 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci rc = tso_get_fragment(&state, efx, 4128c2ecf20Sopenharmony_ci skb_shinfo(skb)->frags + frag_i); 4138c2ecf20Sopenharmony_ci if (rc) 4148c2ecf20Sopenharmony_ci goto fail; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Start at new packet? */ 4188c2ecf20Sopenharmony_ci if (state.packet_space == 0) { 4198c2ecf20Sopenharmony_ci rc = tso_start_new_packet(tx_queue, skb, &state); 4208c2ecf20Sopenharmony_ci if (rc) 4218c2ecf20Sopenharmony_ci goto fail; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci *data_mapped = true; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cifail: 4308c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 4318c2ecf20Sopenharmony_ci netif_err(efx, tx_err, efx->net_dev, 4328c2ecf20Sopenharmony_ci "Out of memory for TSO headers, or DMA mapping error\n"); 4338c2ecf20Sopenharmony_ci else 4348c2ecf20Sopenharmony_ci netif_err(efx, tx_err, efx->net_dev, "TSO failed, rc = %d\n", rc); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Free the DMA mapping we were in the process of writing out */ 4378c2ecf20Sopenharmony_ci if (state.unmap_len) { 4388c2ecf20Sopenharmony_ci dma_unmap_page(&efx->pci_dev->dev, state.unmap_addr, 4398c2ecf20Sopenharmony_ci state.unmap_len, DMA_TO_DEVICE); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* Free the header DMA mapping */ 4438c2ecf20Sopenharmony_ci if (state.header_unmap_len) 4448c2ecf20Sopenharmony_ci dma_unmap_single(&efx->pci_dev->dev, state.header_dma_addr, 4458c2ecf20Sopenharmony_ci state.header_unmap_len, DMA_TO_DEVICE); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return rc; 4488c2ecf20Sopenharmony_ci} 449