162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/prefetch.h> 562306a36Sopenharmony_ci#include <linux/bpf_trace.h> 662306a36Sopenharmony_ci#include <net/mpls.h> 762306a36Sopenharmony_ci#include <net/xdp.h> 862306a36Sopenharmony_ci#include "i40e.h" 962306a36Sopenharmony_ci#include "i40e_trace.h" 1062306a36Sopenharmony_ci#include "i40e_prototype.h" 1162306a36Sopenharmony_ci#include "i40e_txrx_common.h" 1262306a36Sopenharmony_ci#include "i40e_xsk.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) 1562306a36Sopenharmony_ci/** 1662306a36Sopenharmony_ci * i40e_fdir - Generate a Flow Director descriptor based on fdata 1762306a36Sopenharmony_ci * @tx_ring: Tx ring to send buffer on 1862306a36Sopenharmony_ci * @fdata: Flow director filter data 1962306a36Sopenharmony_ci * @add: Indicate if we are adding a rule or deleting one 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci **/ 2262306a36Sopenharmony_cistatic void i40e_fdir(struct i40e_ring *tx_ring, 2362306a36Sopenharmony_ci struct i40e_fdir_filter *fdata, bool add) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct i40e_filter_program_desc *fdir_desc; 2662306a36Sopenharmony_ci struct i40e_pf *pf = tx_ring->vsi->back; 2762306a36Sopenharmony_ci u32 flex_ptype, dtype_cmd; 2862306a36Sopenharmony_ci u16 i; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* grab the next descriptor */ 3162306a36Sopenharmony_ci i = tx_ring->next_to_use; 3262306a36Sopenharmony_ci fdir_desc = I40E_TX_FDIRDESC(tx_ring, i); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci i++; 3562306a36Sopenharmony_ci tx_ring->next_to_use = (i < tx_ring->count) ? i : 0; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci flex_ptype = I40E_TXD_FLTR_QW0_QINDEX_MASK & 3862306a36Sopenharmony_ci (fdata->q_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci flex_ptype |= I40E_TXD_FLTR_QW0_FLEXOFF_MASK & 4162306a36Sopenharmony_ci (fdata->flex_off << I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK & 4462306a36Sopenharmony_ci (fdata->pctype << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* Use LAN VSI Id if not programmed by user */ 4762306a36Sopenharmony_ci flex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK & 4862306a36Sopenharmony_ci ((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) << 4962306a36Sopenharmony_ci I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci dtype_cmd |= add ? 5462306a36Sopenharmony_ci I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 5562306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_PCMD_SHIFT : 5662306a36Sopenharmony_ci I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 5762306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_PCMD_SHIFT; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_DEST_MASK & 6062306a36Sopenharmony_ci (fdata->dest_ctl << I40E_TXD_FLTR_QW1_DEST_SHIFT); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_FD_STATUS_MASK & 6362306a36Sopenharmony_ci (fdata->fd_status << I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (fdata->cnt_index) { 6662306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK; 6762306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_CNTINDEX_MASK & 6862306a36Sopenharmony_ci ((u32)fdata->cnt_index << 6962306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); 7362306a36Sopenharmony_ci fdir_desc->rsvd = cpu_to_le32(0); 7462306a36Sopenharmony_ci fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd); 7562306a36Sopenharmony_ci fdir_desc->fd_id = cpu_to_le32(fdata->fd_id); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define I40E_FD_CLEAN_DELAY 10 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * i40e_program_fdir_filter - Program a Flow Director filter 8162306a36Sopenharmony_ci * @fdir_data: Packet data that will be filter parameters 8262306a36Sopenharmony_ci * @raw_packet: the pre-allocated packet buffer for FDir 8362306a36Sopenharmony_ci * @pf: The PF pointer 8462306a36Sopenharmony_ci * @add: True for add/update, False for remove 8562306a36Sopenharmony_ci **/ 8662306a36Sopenharmony_cistatic int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, 8762306a36Sopenharmony_ci u8 *raw_packet, struct i40e_pf *pf, 8862306a36Sopenharmony_ci bool add) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct i40e_tx_buffer *tx_buf, *first; 9162306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 9262306a36Sopenharmony_ci struct i40e_ring *tx_ring; 9362306a36Sopenharmony_ci struct i40e_vsi *vsi; 9462306a36Sopenharmony_ci struct device *dev; 9562306a36Sopenharmony_ci dma_addr_t dma; 9662306a36Sopenharmony_ci u32 td_cmd = 0; 9762306a36Sopenharmony_ci u16 i; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* find existing FDIR VSI */ 10062306a36Sopenharmony_ci vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR); 10162306a36Sopenharmony_ci if (!vsi) 10262306a36Sopenharmony_ci return -ENOENT; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci tx_ring = vsi->tx_rings[0]; 10562306a36Sopenharmony_ci dev = tx_ring->dev; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* we need two descriptors to add/del a filter and we can wait */ 10862306a36Sopenharmony_ci for (i = I40E_FD_CLEAN_DELAY; I40E_DESC_UNUSED(tx_ring) < 2; i--) { 10962306a36Sopenharmony_ci if (!i) 11062306a36Sopenharmony_ci return -EAGAIN; 11162306a36Sopenharmony_ci msleep_interruptible(1); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci dma = dma_map_single(dev, raw_packet, 11562306a36Sopenharmony_ci I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE); 11662306a36Sopenharmony_ci if (dma_mapping_error(dev, dma)) 11762306a36Sopenharmony_ci goto dma_fail; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* grab the next descriptor */ 12062306a36Sopenharmony_ci i = tx_ring->next_to_use; 12162306a36Sopenharmony_ci first = &tx_ring->tx_bi[i]; 12262306a36Sopenharmony_ci i40e_fdir(tx_ring, fdir_data, add); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Now program a dummy descriptor */ 12562306a36Sopenharmony_ci i = tx_ring->next_to_use; 12662306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, i); 12762306a36Sopenharmony_ci tx_buf = &tx_ring->tx_bi[i]; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci tx_ring->next_to_use = ((i + 1) < tx_ring->count) ? i + 1 : 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci memset(tx_buf, 0, sizeof(struct i40e_tx_buffer)); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* record length, and DMA address */ 13462306a36Sopenharmony_ci dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE); 13562306a36Sopenharmony_ci dma_unmap_addr_set(tx_buf, dma, dma); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 13862306a36Sopenharmony_ci td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci tx_buf->tx_flags = I40E_TX_FLAGS_FD_SB; 14162306a36Sopenharmony_ci tx_buf->raw_buf = (void *)raw_packet; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = 14462306a36Sopenharmony_ci build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* Force memory writes to complete before letting h/w 14762306a36Sopenharmony_ci * know there are new descriptors to fetch. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci wmb(); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Mark the data descriptor to be watched */ 15262306a36Sopenharmony_ci first->next_to_watch = tx_desc; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci writel(tx_ring->next_to_use, tx_ring->tail); 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cidma_fail: 15862306a36Sopenharmony_ci return -1; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/** 16262306a36Sopenharmony_ci * i40e_create_dummy_packet - Constructs dummy packet for HW 16362306a36Sopenharmony_ci * @dummy_packet: preallocated space for dummy packet 16462306a36Sopenharmony_ci * @ipv4: is layer 3 packet of version 4 or 6 16562306a36Sopenharmony_ci * @l4proto: next level protocol used in data portion of l3 16662306a36Sopenharmony_ci * @data: filter data 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Returns address of layer 4 protocol dummy packet. 16962306a36Sopenharmony_ci **/ 17062306a36Sopenharmony_cistatic char *i40e_create_dummy_packet(u8 *dummy_packet, bool ipv4, u8 l4proto, 17162306a36Sopenharmony_ci struct i40e_fdir_filter *data) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci bool is_vlan = !!data->vlan_tag; 17462306a36Sopenharmony_ci struct vlan_hdr vlan = {}; 17562306a36Sopenharmony_ci struct ipv6hdr ipv6 = {}; 17662306a36Sopenharmony_ci struct ethhdr eth = {}; 17762306a36Sopenharmony_ci struct iphdr ip = {}; 17862306a36Sopenharmony_ci u8 *tmp; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (ipv4) { 18162306a36Sopenharmony_ci eth.h_proto = cpu_to_be16(ETH_P_IP); 18262306a36Sopenharmony_ci ip.protocol = l4proto; 18362306a36Sopenharmony_ci ip.version = 0x4; 18462306a36Sopenharmony_ci ip.ihl = 0x5; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ip.daddr = data->dst_ip; 18762306a36Sopenharmony_ci ip.saddr = data->src_ip; 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci eth.h_proto = cpu_to_be16(ETH_P_IPV6); 19062306a36Sopenharmony_ci ipv6.nexthdr = l4proto; 19162306a36Sopenharmony_ci ipv6.version = 0x6; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci memcpy(&ipv6.saddr.in6_u.u6_addr32, data->src_ip6, 19462306a36Sopenharmony_ci sizeof(__be32) * 4); 19562306a36Sopenharmony_ci memcpy(&ipv6.daddr.in6_u.u6_addr32, data->dst_ip6, 19662306a36Sopenharmony_ci sizeof(__be32) * 4); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (is_vlan) { 20062306a36Sopenharmony_ci vlan.h_vlan_TCI = data->vlan_tag; 20162306a36Sopenharmony_ci vlan.h_vlan_encapsulated_proto = eth.h_proto; 20262306a36Sopenharmony_ci eth.h_proto = data->vlan_etype; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci tmp = dummy_packet; 20662306a36Sopenharmony_ci memcpy(tmp, ð, sizeof(eth)); 20762306a36Sopenharmony_ci tmp += sizeof(eth); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (is_vlan) { 21062306a36Sopenharmony_ci memcpy(tmp, &vlan, sizeof(vlan)); 21162306a36Sopenharmony_ci tmp += sizeof(vlan); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (ipv4) { 21562306a36Sopenharmony_ci memcpy(tmp, &ip, sizeof(ip)); 21662306a36Sopenharmony_ci tmp += sizeof(ip); 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci memcpy(tmp, &ipv6, sizeof(ipv6)); 21962306a36Sopenharmony_ci tmp += sizeof(ipv6); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return tmp; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * i40e_create_dummy_udp_packet - helper function to create UDP packet 22762306a36Sopenharmony_ci * @raw_packet: preallocated space for dummy packet 22862306a36Sopenharmony_ci * @ipv4: is layer 3 packet of version 4 or 6 22962306a36Sopenharmony_ci * @l4proto: next level protocol used in data portion of l3 23062306a36Sopenharmony_ci * @data: filter data 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * Helper function to populate udp fields. 23362306a36Sopenharmony_ci **/ 23462306a36Sopenharmony_cistatic void i40e_create_dummy_udp_packet(u8 *raw_packet, bool ipv4, u8 l4proto, 23562306a36Sopenharmony_ci struct i40e_fdir_filter *data) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct udphdr *udp; 23862306a36Sopenharmony_ci u8 *tmp; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci tmp = i40e_create_dummy_packet(raw_packet, ipv4, IPPROTO_UDP, data); 24162306a36Sopenharmony_ci udp = (struct udphdr *)(tmp); 24262306a36Sopenharmony_ci udp->dest = data->dst_port; 24362306a36Sopenharmony_ci udp->source = data->src_port; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/** 24762306a36Sopenharmony_ci * i40e_create_dummy_tcp_packet - helper function to create TCP packet 24862306a36Sopenharmony_ci * @raw_packet: preallocated space for dummy packet 24962306a36Sopenharmony_ci * @ipv4: is layer 3 packet of version 4 or 6 25062306a36Sopenharmony_ci * @l4proto: next level protocol used in data portion of l3 25162306a36Sopenharmony_ci * @data: filter data 25262306a36Sopenharmony_ci * 25362306a36Sopenharmony_ci * Helper function to populate tcp fields. 25462306a36Sopenharmony_ci **/ 25562306a36Sopenharmony_cistatic void i40e_create_dummy_tcp_packet(u8 *raw_packet, bool ipv4, u8 l4proto, 25662306a36Sopenharmony_ci struct i40e_fdir_filter *data) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct tcphdr *tcp; 25962306a36Sopenharmony_ci u8 *tmp; 26062306a36Sopenharmony_ci /* Dummy tcp packet */ 26162306a36Sopenharmony_ci static const char tcp_packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26262306a36Sopenharmony_ci 0x50, 0x11, 0x0, 0x72, 0, 0, 0, 0}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci tmp = i40e_create_dummy_packet(raw_packet, ipv4, IPPROTO_TCP, data); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci tcp = (struct tcphdr *)tmp; 26762306a36Sopenharmony_ci memcpy(tcp, tcp_packet, sizeof(tcp_packet)); 26862306a36Sopenharmony_ci tcp->dest = data->dst_port; 26962306a36Sopenharmony_ci tcp->source = data->src_port; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * i40e_create_dummy_sctp_packet - helper function to create SCTP packet 27462306a36Sopenharmony_ci * @raw_packet: preallocated space for dummy packet 27562306a36Sopenharmony_ci * @ipv4: is layer 3 packet of version 4 or 6 27662306a36Sopenharmony_ci * @l4proto: next level protocol used in data portion of l3 27762306a36Sopenharmony_ci * @data: filter data 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Helper function to populate sctp fields. 28062306a36Sopenharmony_ci **/ 28162306a36Sopenharmony_cistatic void i40e_create_dummy_sctp_packet(u8 *raw_packet, bool ipv4, 28262306a36Sopenharmony_ci u8 l4proto, 28362306a36Sopenharmony_ci struct i40e_fdir_filter *data) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct sctphdr *sctp; 28662306a36Sopenharmony_ci u8 *tmp; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci tmp = i40e_create_dummy_packet(raw_packet, ipv4, IPPROTO_SCTP, data); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci sctp = (struct sctphdr *)tmp; 29162306a36Sopenharmony_ci sctp->dest = data->dst_port; 29262306a36Sopenharmony_ci sctp->source = data->src_port; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/** 29662306a36Sopenharmony_ci * i40e_prepare_fdir_filter - Prepare and program fdir filter 29762306a36Sopenharmony_ci * @pf: physical function to attach filter to 29862306a36Sopenharmony_ci * @fd_data: filter data 29962306a36Sopenharmony_ci * @add: add or delete filter 30062306a36Sopenharmony_ci * @packet_addr: address of dummy packet, used in filtering 30162306a36Sopenharmony_ci * @payload_offset: offset from dummy packet address to user defined data 30262306a36Sopenharmony_ci * @pctype: Packet type for which filter is used 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * Helper function to offset data of dummy packet, program it and 30562306a36Sopenharmony_ci * handle errors. 30662306a36Sopenharmony_ci **/ 30762306a36Sopenharmony_cistatic int i40e_prepare_fdir_filter(struct i40e_pf *pf, 30862306a36Sopenharmony_ci struct i40e_fdir_filter *fd_data, 30962306a36Sopenharmony_ci bool add, char *packet_addr, 31062306a36Sopenharmony_ci int payload_offset, u8 pctype) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci int ret; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (fd_data->flex_filter) { 31562306a36Sopenharmony_ci u8 *payload; 31662306a36Sopenharmony_ci __be16 pattern = fd_data->flex_word; 31762306a36Sopenharmony_ci u16 off = fd_data->flex_offset; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci payload = packet_addr + payload_offset; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* If user provided vlan, offset payload by vlan header length */ 32262306a36Sopenharmony_ci if (!!fd_data->vlan_tag) 32362306a36Sopenharmony_ci payload += VLAN_HLEN; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci *((__force __be16 *)(payload + off)) = pattern; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci fd_data->pctype = pctype; 32962306a36Sopenharmony_ci ret = i40e_program_fdir_filter(fd_data, packet_addr, pf, add); 33062306a36Sopenharmony_ci if (ret) { 33162306a36Sopenharmony_ci dev_info(&pf->pdev->dev, 33262306a36Sopenharmony_ci "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n", 33362306a36Sopenharmony_ci fd_data->pctype, fd_data->fd_id, ret); 33462306a36Sopenharmony_ci /* Free the packet buffer since it wasn't added to the ring */ 33562306a36Sopenharmony_ci return -EOPNOTSUPP; 33662306a36Sopenharmony_ci } else if (I40E_DEBUG_FD & pf->hw.debug_mask) { 33762306a36Sopenharmony_ci if (add) 33862306a36Sopenharmony_ci dev_info(&pf->pdev->dev, 33962306a36Sopenharmony_ci "Filter OK for PCTYPE %d loc = %d\n", 34062306a36Sopenharmony_ci fd_data->pctype, fd_data->fd_id); 34162306a36Sopenharmony_ci else 34262306a36Sopenharmony_ci dev_info(&pf->pdev->dev, 34362306a36Sopenharmony_ci "Filter deleted for PCTYPE %d loc = %d\n", 34462306a36Sopenharmony_ci fd_data->pctype, fd_data->fd_id); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/** 35162306a36Sopenharmony_ci * i40e_change_filter_num - Prepare and program fdir filter 35262306a36Sopenharmony_ci * @ipv4: is layer 3 packet of version 4 or 6 35362306a36Sopenharmony_ci * @add: add or delete filter 35462306a36Sopenharmony_ci * @ipv4_filter_num: field to update 35562306a36Sopenharmony_ci * @ipv6_filter_num: field to update 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * Update filter number field for pf. 35862306a36Sopenharmony_ci **/ 35962306a36Sopenharmony_cistatic void i40e_change_filter_num(bool ipv4, bool add, u16 *ipv4_filter_num, 36062306a36Sopenharmony_ci u16 *ipv6_filter_num) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci if (add) { 36362306a36Sopenharmony_ci if (ipv4) 36462306a36Sopenharmony_ci (*ipv4_filter_num)++; 36562306a36Sopenharmony_ci else 36662306a36Sopenharmony_ci (*ipv6_filter_num)++; 36762306a36Sopenharmony_ci } else { 36862306a36Sopenharmony_ci if (ipv4) 36962306a36Sopenharmony_ci (*ipv4_filter_num)--; 37062306a36Sopenharmony_ci else 37162306a36Sopenharmony_ci (*ipv6_filter_num)--; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci#define I40E_UDPIP_DUMMY_PACKET_LEN 42 37662306a36Sopenharmony_ci#define I40E_UDPIP6_DUMMY_PACKET_LEN 62 37762306a36Sopenharmony_ci/** 37862306a36Sopenharmony_ci * i40e_add_del_fdir_udp - Add/Remove UDP filters 37962306a36Sopenharmony_ci * @vsi: pointer to the targeted VSI 38062306a36Sopenharmony_ci * @fd_data: the flow director data required for the FDir descriptor 38162306a36Sopenharmony_ci * @add: true adds a filter, false removes it 38262306a36Sopenharmony_ci * @ipv4: true is v4, false is v6 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * Returns 0 if the filters were successfully added or removed 38562306a36Sopenharmony_ci **/ 38662306a36Sopenharmony_cistatic int i40e_add_del_fdir_udp(struct i40e_vsi *vsi, 38762306a36Sopenharmony_ci struct i40e_fdir_filter *fd_data, 38862306a36Sopenharmony_ci bool add, 38962306a36Sopenharmony_ci bool ipv4) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 39262306a36Sopenharmony_ci u8 *raw_packet; 39362306a36Sopenharmony_ci int ret; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); 39662306a36Sopenharmony_ci if (!raw_packet) 39762306a36Sopenharmony_ci return -ENOMEM; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci i40e_create_dummy_udp_packet(raw_packet, ipv4, IPPROTO_UDP, fd_data); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (ipv4) 40262306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 40362306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 40462306a36Sopenharmony_ci I40E_UDPIP_DUMMY_PACKET_LEN, 40562306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV4_UDP); 40662306a36Sopenharmony_ci else 40762306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 40862306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 40962306a36Sopenharmony_ci I40E_UDPIP6_DUMMY_PACKET_LEN, 41062306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV6_UDP); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (ret) { 41362306a36Sopenharmony_ci kfree(raw_packet); 41462306a36Sopenharmony_ci return ret; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci i40e_change_filter_num(ipv4, add, &pf->fd_udp4_filter_cnt, 41862306a36Sopenharmony_ci &pf->fd_udp6_filter_cnt); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci#define I40E_TCPIP_DUMMY_PACKET_LEN 54 42462306a36Sopenharmony_ci#define I40E_TCPIP6_DUMMY_PACKET_LEN 74 42562306a36Sopenharmony_ci/** 42662306a36Sopenharmony_ci * i40e_add_del_fdir_tcp - Add/Remove TCPv4 filters 42762306a36Sopenharmony_ci * @vsi: pointer to the targeted VSI 42862306a36Sopenharmony_ci * @fd_data: the flow director data required for the FDir descriptor 42962306a36Sopenharmony_ci * @add: true adds a filter, false removes it 43062306a36Sopenharmony_ci * @ipv4: true is v4, false is v6 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Returns 0 if the filters were successfully added or removed 43362306a36Sopenharmony_ci **/ 43462306a36Sopenharmony_cistatic int i40e_add_del_fdir_tcp(struct i40e_vsi *vsi, 43562306a36Sopenharmony_ci struct i40e_fdir_filter *fd_data, 43662306a36Sopenharmony_ci bool add, 43762306a36Sopenharmony_ci bool ipv4) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 44062306a36Sopenharmony_ci u8 *raw_packet; 44162306a36Sopenharmony_ci int ret; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); 44462306a36Sopenharmony_ci if (!raw_packet) 44562306a36Sopenharmony_ci return -ENOMEM; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci i40e_create_dummy_tcp_packet(raw_packet, ipv4, IPPROTO_TCP, fd_data); 44862306a36Sopenharmony_ci if (ipv4) 44962306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 45062306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 45162306a36Sopenharmony_ci I40E_TCPIP_DUMMY_PACKET_LEN, 45262306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV4_TCP); 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 45562306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 45662306a36Sopenharmony_ci I40E_TCPIP6_DUMMY_PACKET_LEN, 45762306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV6_TCP); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (ret) { 46062306a36Sopenharmony_ci kfree(raw_packet); 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci i40e_change_filter_num(ipv4, add, &pf->fd_tcp4_filter_cnt, 46562306a36Sopenharmony_ci &pf->fd_tcp6_filter_cnt); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (add) { 46862306a36Sopenharmony_ci if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) && 46962306a36Sopenharmony_ci I40E_DEBUG_FD & pf->hw.debug_mask) 47062306a36Sopenharmony_ci dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); 47162306a36Sopenharmony_ci set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci#define I40E_SCTPIP_DUMMY_PACKET_LEN 46 47762306a36Sopenharmony_ci#define I40E_SCTPIP6_DUMMY_PACKET_LEN 66 47862306a36Sopenharmony_ci/** 47962306a36Sopenharmony_ci * i40e_add_del_fdir_sctp - Add/Remove SCTPv4 Flow Director filters for 48062306a36Sopenharmony_ci * a specific flow spec 48162306a36Sopenharmony_ci * @vsi: pointer to the targeted VSI 48262306a36Sopenharmony_ci * @fd_data: the flow director data required for the FDir descriptor 48362306a36Sopenharmony_ci * @add: true adds a filter, false removes it 48462306a36Sopenharmony_ci * @ipv4: true is v4, false is v6 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * Returns 0 if the filters were successfully added or removed 48762306a36Sopenharmony_ci **/ 48862306a36Sopenharmony_cistatic int i40e_add_del_fdir_sctp(struct i40e_vsi *vsi, 48962306a36Sopenharmony_ci struct i40e_fdir_filter *fd_data, 49062306a36Sopenharmony_ci bool add, 49162306a36Sopenharmony_ci bool ipv4) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 49462306a36Sopenharmony_ci u8 *raw_packet; 49562306a36Sopenharmony_ci int ret; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); 49862306a36Sopenharmony_ci if (!raw_packet) 49962306a36Sopenharmony_ci return -ENOMEM; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci i40e_create_dummy_sctp_packet(raw_packet, ipv4, IPPROTO_SCTP, fd_data); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (ipv4) 50462306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 50562306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 50662306a36Sopenharmony_ci I40E_SCTPIP_DUMMY_PACKET_LEN, 50762306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV4_SCTP); 50862306a36Sopenharmony_ci else 50962306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter 51062306a36Sopenharmony_ci (pf, fd_data, add, raw_packet, 51162306a36Sopenharmony_ci I40E_SCTPIP6_DUMMY_PACKET_LEN, 51262306a36Sopenharmony_ci I40E_FILTER_PCTYPE_NONF_IPV6_SCTP); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (ret) { 51562306a36Sopenharmony_ci kfree(raw_packet); 51662306a36Sopenharmony_ci return ret; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci i40e_change_filter_num(ipv4, add, &pf->fd_sctp4_filter_cnt, 52062306a36Sopenharmony_ci &pf->fd_sctp6_filter_cnt); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci#define I40E_IP_DUMMY_PACKET_LEN 34 52662306a36Sopenharmony_ci#define I40E_IP6_DUMMY_PACKET_LEN 54 52762306a36Sopenharmony_ci/** 52862306a36Sopenharmony_ci * i40e_add_del_fdir_ip - Add/Remove IPv4 Flow Director filters for 52962306a36Sopenharmony_ci * a specific flow spec 53062306a36Sopenharmony_ci * @vsi: pointer to the targeted VSI 53162306a36Sopenharmony_ci * @fd_data: the flow director data required for the FDir descriptor 53262306a36Sopenharmony_ci * @add: true adds a filter, false removes it 53362306a36Sopenharmony_ci * @ipv4: true is v4, false is v6 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * Returns 0 if the filters were successfully added or removed 53662306a36Sopenharmony_ci **/ 53762306a36Sopenharmony_cistatic int i40e_add_del_fdir_ip(struct i40e_vsi *vsi, 53862306a36Sopenharmony_ci struct i40e_fdir_filter *fd_data, 53962306a36Sopenharmony_ci bool add, 54062306a36Sopenharmony_ci bool ipv4) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 54362306a36Sopenharmony_ci int payload_offset; 54462306a36Sopenharmony_ci u8 *raw_packet; 54562306a36Sopenharmony_ci int iter_start; 54662306a36Sopenharmony_ci int iter_end; 54762306a36Sopenharmony_ci int ret; 54862306a36Sopenharmony_ci int i; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (ipv4) { 55162306a36Sopenharmony_ci iter_start = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; 55262306a36Sopenharmony_ci iter_end = I40E_FILTER_PCTYPE_FRAG_IPV4; 55362306a36Sopenharmony_ci } else { 55462306a36Sopenharmony_ci iter_start = I40E_FILTER_PCTYPE_NONF_IPV6_OTHER; 55562306a36Sopenharmony_ci iter_end = I40E_FILTER_PCTYPE_FRAG_IPV6; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = iter_start; i <= iter_end; i++) { 55962306a36Sopenharmony_ci raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); 56062306a36Sopenharmony_ci if (!raw_packet) 56162306a36Sopenharmony_ci return -ENOMEM; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* IPv6 no header option differs from IPv4 */ 56462306a36Sopenharmony_ci (void)i40e_create_dummy_packet 56562306a36Sopenharmony_ci (raw_packet, ipv4, (ipv4) ? IPPROTO_IP : IPPROTO_NONE, 56662306a36Sopenharmony_ci fd_data); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci payload_offset = (ipv4) ? I40E_IP_DUMMY_PACKET_LEN : 56962306a36Sopenharmony_ci I40E_IP6_DUMMY_PACKET_LEN; 57062306a36Sopenharmony_ci ret = i40e_prepare_fdir_filter(pf, fd_data, add, raw_packet, 57162306a36Sopenharmony_ci payload_offset, i); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci goto err; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci i40e_change_filter_num(ipv4, add, &pf->fd_ip4_filter_cnt, 57762306a36Sopenharmony_ci &pf->fd_ip6_filter_cnt); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_cierr: 58162306a36Sopenharmony_ci kfree(raw_packet); 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/** 58662306a36Sopenharmony_ci * i40e_add_del_fdir - Build raw packets to add/del fdir filter 58762306a36Sopenharmony_ci * @vsi: pointer to the targeted VSI 58862306a36Sopenharmony_ci * @input: filter to add or delete 58962306a36Sopenharmony_ci * @add: true adds a filter, false removes it 59062306a36Sopenharmony_ci * 59162306a36Sopenharmony_ci **/ 59262306a36Sopenharmony_ciint i40e_add_del_fdir(struct i40e_vsi *vsi, 59362306a36Sopenharmony_ci struct i40e_fdir_filter *input, bool add) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci enum ip_ver { ipv6 = 0, ipv4 = 1 }; 59662306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 59762306a36Sopenharmony_ci int ret; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci switch (input->flow_type & ~FLOW_EXT) { 60062306a36Sopenharmony_ci case TCP_V4_FLOW: 60162306a36Sopenharmony_ci ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4); 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci case UDP_V4_FLOW: 60462306a36Sopenharmony_ci ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4); 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case SCTP_V4_FLOW: 60762306a36Sopenharmony_ci ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv4); 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case TCP_V6_FLOW: 61062306a36Sopenharmony_ci ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv6); 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case UDP_V6_FLOW: 61362306a36Sopenharmony_ci ret = i40e_add_del_fdir_udp(vsi, input, add, ipv6); 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case SCTP_V6_FLOW: 61662306a36Sopenharmony_ci ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv6); 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case IP_USER_FLOW: 61962306a36Sopenharmony_ci switch (input->ipl4_proto) { 62062306a36Sopenharmony_ci case IPPROTO_TCP: 62162306a36Sopenharmony_ci ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv4); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case IPPROTO_UDP: 62462306a36Sopenharmony_ci ret = i40e_add_del_fdir_udp(vsi, input, add, ipv4); 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci case IPPROTO_SCTP: 62762306a36Sopenharmony_ci ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv4); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case IPPROTO_IP: 63062306a36Sopenharmony_ci ret = i40e_add_del_fdir_ip(vsi, input, add, ipv4); 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci default: 63362306a36Sopenharmony_ci /* We cannot support masking based on protocol */ 63462306a36Sopenharmony_ci dev_info(&pf->pdev->dev, "Unsupported IPv4 protocol 0x%02x\n", 63562306a36Sopenharmony_ci input->ipl4_proto); 63662306a36Sopenharmony_ci return -EINVAL; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci case IPV6_USER_FLOW: 64062306a36Sopenharmony_ci switch (input->ipl4_proto) { 64162306a36Sopenharmony_ci case IPPROTO_TCP: 64262306a36Sopenharmony_ci ret = i40e_add_del_fdir_tcp(vsi, input, add, ipv6); 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci case IPPROTO_UDP: 64562306a36Sopenharmony_ci ret = i40e_add_del_fdir_udp(vsi, input, add, ipv6); 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci case IPPROTO_SCTP: 64862306a36Sopenharmony_ci ret = i40e_add_del_fdir_sctp(vsi, input, add, ipv6); 64962306a36Sopenharmony_ci break; 65062306a36Sopenharmony_ci case IPPROTO_IP: 65162306a36Sopenharmony_ci ret = i40e_add_del_fdir_ip(vsi, input, add, ipv6); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci default: 65462306a36Sopenharmony_ci /* We cannot support masking based on protocol */ 65562306a36Sopenharmony_ci dev_info(&pf->pdev->dev, "Unsupported IPv6 protocol 0x%02x\n", 65662306a36Sopenharmony_ci input->ipl4_proto); 65762306a36Sopenharmony_ci return -EINVAL; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci default: 66162306a36Sopenharmony_ci dev_info(&pf->pdev->dev, "Unsupported flow type 0x%02x\n", 66262306a36Sopenharmony_ci input->flow_type); 66362306a36Sopenharmony_ci return -EINVAL; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* The buffer allocated here will be normally be freed by 66762306a36Sopenharmony_ci * i40e_clean_fdir_tx_irq() as it reclaims resources after transmit 66862306a36Sopenharmony_ci * completion. In the event of an error adding the buffer to the FDIR 66962306a36Sopenharmony_ci * ring, it will immediately be freed. It may also be freed by 67062306a36Sopenharmony_ci * i40e_clean_tx_ring() when closing the VSI. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci return ret; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci/** 67662306a36Sopenharmony_ci * i40e_fd_handle_status - check the Programming Status for FD 67762306a36Sopenharmony_ci * @rx_ring: the Rx ring for this descriptor 67862306a36Sopenharmony_ci * @qword0_raw: qword0 67962306a36Sopenharmony_ci * @qword1: qword1 after le_to_cpu 68062306a36Sopenharmony_ci * @prog_id: the id originally used for programming 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * This is used to verify if the FD programming or invalidation 68362306a36Sopenharmony_ci * requested by SW to the HW is successful or not and take actions accordingly. 68462306a36Sopenharmony_ci **/ 68562306a36Sopenharmony_cistatic void i40e_fd_handle_status(struct i40e_ring *rx_ring, u64 qword0_raw, 68662306a36Sopenharmony_ci u64 qword1, u8 prog_id) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct i40e_pf *pf = rx_ring->vsi->back; 68962306a36Sopenharmony_ci struct pci_dev *pdev = pf->pdev; 69062306a36Sopenharmony_ci struct i40e_16b_rx_wb_qw0 *qw0; 69162306a36Sopenharmony_ci u32 fcnt_prog, fcnt_avail; 69262306a36Sopenharmony_ci u32 error; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci qw0 = (struct i40e_16b_rx_wb_qw0 *)&qword0_raw; 69562306a36Sopenharmony_ci error = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> 69662306a36Sopenharmony_ci I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (error == BIT(I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { 69962306a36Sopenharmony_ci pf->fd_inv = le32_to_cpu(qw0->hi_dword.fd_id); 70062306a36Sopenharmony_ci if (qw0->hi_dword.fd_id != 0 || 70162306a36Sopenharmony_ci (I40E_DEBUG_FD & pf->hw.debug_mask)) 70262306a36Sopenharmony_ci dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n", 70362306a36Sopenharmony_ci pf->fd_inv); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Check if the programming error is for ATR. 70662306a36Sopenharmony_ci * If so, auto disable ATR and set a state for 70762306a36Sopenharmony_ci * flush in progress. Next time we come here if flush is in 70862306a36Sopenharmony_ci * progress do nothing, once flush is complete the state will 70962306a36Sopenharmony_ci * be cleared. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci if (test_bit(__I40E_FD_FLUSH_REQUESTED, pf->state)) 71262306a36Sopenharmony_ci return; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci pf->fd_add_err++; 71562306a36Sopenharmony_ci /* store the current atr filter count */ 71662306a36Sopenharmony_ci pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (qw0->hi_dword.fd_id == 0 && 71962306a36Sopenharmony_ci test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) { 72062306a36Sopenharmony_ci /* These set_bit() calls aren't atomic with the 72162306a36Sopenharmony_ci * test_bit() here, but worse case we potentially 72262306a36Sopenharmony_ci * disable ATR and queue a flush right after SB 72362306a36Sopenharmony_ci * support is re-enabled. That shouldn't cause an 72462306a36Sopenharmony_ci * issue in practice 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state); 72762306a36Sopenharmony_ci set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* filter programming failed most likely due to table full */ 73162306a36Sopenharmony_ci fcnt_prog = i40e_get_global_fd_count(pf); 73262306a36Sopenharmony_ci fcnt_avail = pf->fdir_pf_filter_count; 73362306a36Sopenharmony_ci /* If ATR is running fcnt_prog can quickly change, 73462306a36Sopenharmony_ci * if we are very close to full, it makes sense to disable 73562306a36Sopenharmony_ci * FD ATR/SB and then re-enable it when there is room. 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ci if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) { 73862306a36Sopenharmony_ci if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) && 73962306a36Sopenharmony_ci !test_and_set_bit(__I40E_FD_SB_AUTO_DISABLED, 74062306a36Sopenharmony_ci pf->state)) 74162306a36Sopenharmony_ci if (I40E_DEBUG_FD & pf->hw.debug_mask) 74262306a36Sopenharmony_ci dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n"); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci } else if (error == BIT(I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { 74562306a36Sopenharmony_ci if (I40E_DEBUG_FD & pf->hw.debug_mask) 74662306a36Sopenharmony_ci dev_info(&pdev->dev, "ntuple filter fd_id = %d, could not be removed\n", 74762306a36Sopenharmony_ci qw0->hi_dword.fd_id); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/** 75262306a36Sopenharmony_ci * i40e_unmap_and_free_tx_resource - Release a Tx buffer 75362306a36Sopenharmony_ci * @ring: the ring that owns the buffer 75462306a36Sopenharmony_ci * @tx_buffer: the buffer to free 75562306a36Sopenharmony_ci **/ 75662306a36Sopenharmony_cistatic void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, 75762306a36Sopenharmony_ci struct i40e_tx_buffer *tx_buffer) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci if (tx_buffer->skb) { 76062306a36Sopenharmony_ci if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB) 76162306a36Sopenharmony_ci kfree(tx_buffer->raw_buf); 76262306a36Sopenharmony_ci else if (ring_is_xdp(ring)) 76362306a36Sopenharmony_ci xdp_return_frame(tx_buffer->xdpf); 76462306a36Sopenharmony_ci else 76562306a36Sopenharmony_ci dev_kfree_skb_any(tx_buffer->skb); 76662306a36Sopenharmony_ci if (dma_unmap_len(tx_buffer, len)) 76762306a36Sopenharmony_ci dma_unmap_single(ring->dev, 76862306a36Sopenharmony_ci dma_unmap_addr(tx_buffer, dma), 76962306a36Sopenharmony_ci dma_unmap_len(tx_buffer, len), 77062306a36Sopenharmony_ci DMA_TO_DEVICE); 77162306a36Sopenharmony_ci } else if (dma_unmap_len(tx_buffer, len)) { 77262306a36Sopenharmony_ci dma_unmap_page(ring->dev, 77362306a36Sopenharmony_ci dma_unmap_addr(tx_buffer, dma), 77462306a36Sopenharmony_ci dma_unmap_len(tx_buffer, len), 77562306a36Sopenharmony_ci DMA_TO_DEVICE); 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci tx_buffer->next_to_watch = NULL; 77962306a36Sopenharmony_ci tx_buffer->skb = NULL; 78062306a36Sopenharmony_ci dma_unmap_len_set(tx_buffer, len, 0); 78162306a36Sopenharmony_ci /* tx_buffer must be completely set up in the transmit path */ 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/** 78562306a36Sopenharmony_ci * i40e_clean_tx_ring - Free any empty Tx buffers 78662306a36Sopenharmony_ci * @tx_ring: ring to be cleaned 78762306a36Sopenharmony_ci **/ 78862306a36Sopenharmony_civoid i40e_clean_tx_ring(struct i40e_ring *tx_ring) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci unsigned long bi_size; 79162306a36Sopenharmony_ci u16 i; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (ring_is_xdp(tx_ring) && tx_ring->xsk_pool) { 79462306a36Sopenharmony_ci i40e_xsk_clean_tx_ring(tx_ring); 79562306a36Sopenharmony_ci } else { 79662306a36Sopenharmony_ci /* ring already cleared, nothing to do */ 79762306a36Sopenharmony_ci if (!tx_ring->tx_bi) 79862306a36Sopenharmony_ci return; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Free all the Tx ring sk_buffs */ 80162306a36Sopenharmony_ci for (i = 0; i < tx_ring->count; i++) 80262306a36Sopenharmony_ci i40e_unmap_and_free_tx_resource(tx_ring, 80362306a36Sopenharmony_ci &tx_ring->tx_bi[i]); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; 80762306a36Sopenharmony_ci memset(tx_ring->tx_bi, 0, bi_size); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* Zero out the descriptor ring */ 81062306a36Sopenharmony_ci memset(tx_ring->desc, 0, tx_ring->size); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci tx_ring->next_to_use = 0; 81362306a36Sopenharmony_ci tx_ring->next_to_clean = 0; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (!tx_ring->netdev) 81662306a36Sopenharmony_ci return; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* cleanup Tx queue statistics */ 81962306a36Sopenharmony_ci netdev_tx_reset_queue(txring_txq(tx_ring)); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/** 82362306a36Sopenharmony_ci * i40e_free_tx_resources - Free Tx resources per queue 82462306a36Sopenharmony_ci * @tx_ring: Tx descriptor ring for a specific queue 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Free all transmit software resources 82762306a36Sopenharmony_ci **/ 82862306a36Sopenharmony_civoid i40e_free_tx_resources(struct i40e_ring *tx_ring) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci i40e_clean_tx_ring(tx_ring); 83162306a36Sopenharmony_ci kfree(tx_ring->tx_bi); 83262306a36Sopenharmony_ci tx_ring->tx_bi = NULL; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (tx_ring->desc) { 83562306a36Sopenharmony_ci dma_free_coherent(tx_ring->dev, tx_ring->size, 83662306a36Sopenharmony_ci tx_ring->desc, tx_ring->dma); 83762306a36Sopenharmony_ci tx_ring->desc = NULL; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/** 84262306a36Sopenharmony_ci * i40e_get_tx_pending - how many tx descriptors not processed 84362306a36Sopenharmony_ci * @ring: the ring of descriptors 84462306a36Sopenharmony_ci * @in_sw: use SW variables 84562306a36Sopenharmony_ci * 84662306a36Sopenharmony_ci * Since there is no access to the ring head register 84762306a36Sopenharmony_ci * in XL710, we need to use our local copies 84862306a36Sopenharmony_ci **/ 84962306a36Sopenharmony_ciu32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci u32 head, tail; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (!in_sw) { 85462306a36Sopenharmony_ci head = i40e_get_head(ring); 85562306a36Sopenharmony_ci tail = readl(ring->tail); 85662306a36Sopenharmony_ci } else { 85762306a36Sopenharmony_ci head = ring->next_to_clean; 85862306a36Sopenharmony_ci tail = ring->next_to_use; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (head != tail) 86262306a36Sopenharmony_ci return (head < tail) ? 86362306a36Sopenharmony_ci tail - head : (tail + ring->count - head); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return 0; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/** 86962306a36Sopenharmony_ci * i40e_detect_recover_hung - Function to detect and recover hung_queues 87062306a36Sopenharmony_ci * @vsi: pointer to vsi struct with tx queues 87162306a36Sopenharmony_ci * 87262306a36Sopenharmony_ci * VSI has netdev and netdev has TX queues. This function is to check each of 87362306a36Sopenharmony_ci * those TX queues if they are hung, trigger recovery by issuing SW interrupt. 87462306a36Sopenharmony_ci **/ 87562306a36Sopenharmony_civoid i40e_detect_recover_hung(struct i40e_vsi *vsi) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci struct i40e_ring *tx_ring = NULL; 87862306a36Sopenharmony_ci struct net_device *netdev; 87962306a36Sopenharmony_ci unsigned int i; 88062306a36Sopenharmony_ci int packets; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (!vsi) 88362306a36Sopenharmony_ci return; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (test_bit(__I40E_VSI_DOWN, vsi->state)) 88662306a36Sopenharmony_ci return; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci netdev = vsi->netdev; 88962306a36Sopenharmony_ci if (!netdev) 89062306a36Sopenharmony_ci return; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!netif_carrier_ok(netdev)) 89362306a36Sopenharmony_ci return; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci for (i = 0; i < vsi->num_queue_pairs; i++) { 89662306a36Sopenharmony_ci tx_ring = vsi->tx_rings[i]; 89762306a36Sopenharmony_ci if (tx_ring && tx_ring->desc) { 89862306a36Sopenharmony_ci /* If packet counter has not changed the queue is 89962306a36Sopenharmony_ci * likely stalled, so force an interrupt for this 90062306a36Sopenharmony_ci * queue. 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * prev_pkt_ctr would be negative if there was no 90362306a36Sopenharmony_ci * pending work. 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_ci packets = tx_ring->stats.packets & INT_MAX; 90662306a36Sopenharmony_ci if (tx_ring->tx_stats.prev_pkt_ctr == packets) { 90762306a36Sopenharmony_ci i40e_force_wb(vsi, tx_ring->q_vector); 90862306a36Sopenharmony_ci continue; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* Memory barrier between read of packet count and call 91262306a36Sopenharmony_ci * to i40e_get_tx_pending() 91362306a36Sopenharmony_ci */ 91462306a36Sopenharmony_ci smp_rmb(); 91562306a36Sopenharmony_ci tx_ring->tx_stats.prev_pkt_ctr = 91662306a36Sopenharmony_ci i40e_get_tx_pending(tx_ring, true) ? packets : -1; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci/** 92262306a36Sopenharmony_ci * i40e_clean_tx_irq - Reclaim resources after transmit completes 92362306a36Sopenharmony_ci * @vsi: the VSI we care about 92462306a36Sopenharmony_ci * @tx_ring: Tx ring to clean 92562306a36Sopenharmony_ci * @napi_budget: Used to determine if we are in netpoll 92662306a36Sopenharmony_ci * @tx_cleaned: Out parameter set to the number of TXes cleaned 92762306a36Sopenharmony_ci * 92862306a36Sopenharmony_ci * Returns true if there's any budget left (e.g. the clean is finished) 92962306a36Sopenharmony_ci **/ 93062306a36Sopenharmony_cistatic bool i40e_clean_tx_irq(struct i40e_vsi *vsi, 93162306a36Sopenharmony_ci struct i40e_ring *tx_ring, int napi_budget, 93262306a36Sopenharmony_ci unsigned int *tx_cleaned) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci int i = tx_ring->next_to_clean; 93562306a36Sopenharmony_ci struct i40e_tx_buffer *tx_buf; 93662306a36Sopenharmony_ci struct i40e_tx_desc *tx_head; 93762306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 93862306a36Sopenharmony_ci unsigned int total_bytes = 0, total_packets = 0; 93962306a36Sopenharmony_ci unsigned int budget = vsi->work_limit; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci tx_buf = &tx_ring->tx_bi[i]; 94262306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, i); 94362306a36Sopenharmony_ci i -= tx_ring->count; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring)); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci do { 94862306a36Sopenharmony_ci struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci /* if next_to_watch is not set then there is no work pending */ 95162306a36Sopenharmony_ci if (!eop_desc) 95262306a36Sopenharmony_ci break; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* prevent any other reads prior to eop_desc */ 95562306a36Sopenharmony_ci smp_rmb(); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci i40e_trace(clean_tx_irq, tx_ring, tx_desc, tx_buf); 95862306a36Sopenharmony_ci /* we have caught up to head, no work left to do */ 95962306a36Sopenharmony_ci if (tx_head == tx_desc) 96062306a36Sopenharmony_ci break; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* clear next_to_watch to prevent false hangs */ 96362306a36Sopenharmony_ci tx_buf->next_to_watch = NULL; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* update the statistics for this packet */ 96662306a36Sopenharmony_ci total_bytes += tx_buf->bytecount; 96762306a36Sopenharmony_ci total_packets += tx_buf->gso_segs; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* free the skb/XDP data */ 97062306a36Sopenharmony_ci if (ring_is_xdp(tx_ring)) 97162306a36Sopenharmony_ci xdp_return_frame(tx_buf->xdpf); 97262306a36Sopenharmony_ci else 97362306a36Sopenharmony_ci napi_consume_skb(tx_buf->skb, napi_budget); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* unmap skb header data */ 97662306a36Sopenharmony_ci dma_unmap_single(tx_ring->dev, 97762306a36Sopenharmony_ci dma_unmap_addr(tx_buf, dma), 97862306a36Sopenharmony_ci dma_unmap_len(tx_buf, len), 97962306a36Sopenharmony_ci DMA_TO_DEVICE); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* clear tx_buffer data */ 98262306a36Sopenharmony_ci tx_buf->skb = NULL; 98362306a36Sopenharmony_ci dma_unmap_len_set(tx_buf, len, 0); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* unmap remaining buffers */ 98662306a36Sopenharmony_ci while (tx_desc != eop_desc) { 98762306a36Sopenharmony_ci i40e_trace(clean_tx_irq_unmap, 98862306a36Sopenharmony_ci tx_ring, tx_desc, tx_buf); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci tx_buf++; 99162306a36Sopenharmony_ci tx_desc++; 99262306a36Sopenharmony_ci i++; 99362306a36Sopenharmony_ci if (unlikely(!i)) { 99462306a36Sopenharmony_ci i -= tx_ring->count; 99562306a36Sopenharmony_ci tx_buf = tx_ring->tx_bi; 99662306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, 0); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* unmap any remaining paged data */ 100062306a36Sopenharmony_ci if (dma_unmap_len(tx_buf, len)) { 100162306a36Sopenharmony_ci dma_unmap_page(tx_ring->dev, 100262306a36Sopenharmony_ci dma_unmap_addr(tx_buf, dma), 100362306a36Sopenharmony_ci dma_unmap_len(tx_buf, len), 100462306a36Sopenharmony_ci DMA_TO_DEVICE); 100562306a36Sopenharmony_ci dma_unmap_len_set(tx_buf, len, 0); 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* move us one more past the eop_desc for start of next pkt */ 101062306a36Sopenharmony_ci tx_buf++; 101162306a36Sopenharmony_ci tx_desc++; 101262306a36Sopenharmony_ci i++; 101362306a36Sopenharmony_ci if (unlikely(!i)) { 101462306a36Sopenharmony_ci i -= tx_ring->count; 101562306a36Sopenharmony_ci tx_buf = tx_ring->tx_bi; 101662306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, 0); 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci prefetch(tx_desc); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* update budget accounting */ 102262306a36Sopenharmony_ci budget--; 102362306a36Sopenharmony_ci } while (likely(budget)); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci i += tx_ring->count; 102662306a36Sopenharmony_ci tx_ring->next_to_clean = i; 102762306a36Sopenharmony_ci i40e_update_tx_stats(tx_ring, total_packets, total_bytes); 102862306a36Sopenharmony_ci i40e_arm_wb(tx_ring, vsi, budget); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (ring_is_xdp(tx_ring)) 103162306a36Sopenharmony_ci return !!budget; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* notify netdev of completed buffers */ 103462306a36Sopenharmony_ci netdev_tx_completed_queue(txring_txq(tx_ring), 103562306a36Sopenharmony_ci total_packets, total_bytes); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci#define TX_WAKE_THRESHOLD ((s16)(DESC_NEEDED * 2)) 103862306a36Sopenharmony_ci if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) && 103962306a36Sopenharmony_ci (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) { 104062306a36Sopenharmony_ci /* Make sure that anybody stopping the queue after this 104162306a36Sopenharmony_ci * sees the new next_to_clean. 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_ci smp_mb(); 104462306a36Sopenharmony_ci if (__netif_subqueue_stopped(tx_ring->netdev, 104562306a36Sopenharmony_ci tx_ring->queue_index) && 104662306a36Sopenharmony_ci !test_bit(__I40E_VSI_DOWN, vsi->state)) { 104762306a36Sopenharmony_ci netif_wake_subqueue(tx_ring->netdev, 104862306a36Sopenharmony_ci tx_ring->queue_index); 104962306a36Sopenharmony_ci ++tx_ring->tx_stats.restart_queue; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci *tx_cleaned = total_packets; 105462306a36Sopenharmony_ci return !!budget; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/** 105862306a36Sopenharmony_ci * i40e_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled 105962306a36Sopenharmony_ci * @vsi: the VSI we care about 106062306a36Sopenharmony_ci * @q_vector: the vector on which to enable writeback 106162306a36Sopenharmony_ci * 106262306a36Sopenharmony_ci **/ 106362306a36Sopenharmony_cistatic void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, 106462306a36Sopenharmony_ci struct i40e_q_vector *q_vector) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci u16 flags = q_vector->tx.ring[0].flags; 106762306a36Sopenharmony_ci u32 val; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR)) 107062306a36Sopenharmony_ci return; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (q_vector->arm_wb_state) 107362306a36Sopenharmony_ci return; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { 107662306a36Sopenharmony_ci val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK | 107762306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */ 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci wr32(&vsi->back->hw, 108062306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN(q_vector->reg_idx), 108162306a36Sopenharmony_ci val); 108262306a36Sopenharmony_ci } else { 108362306a36Sopenharmony_ci val = I40E_PFINT_DYN_CTL0_WB_ON_ITR_MASK | 108462306a36Sopenharmony_ci I40E_PFINT_DYN_CTL0_ITR_INDX_MASK; /* set noitr */ 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0, val); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci q_vector->arm_wb_state = true; 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci/** 109262306a36Sopenharmony_ci * i40e_force_wb - Issue SW Interrupt so HW does a wb 109362306a36Sopenharmony_ci * @vsi: the VSI we care about 109462306a36Sopenharmony_ci * @q_vector: the vector on which to force writeback 109562306a36Sopenharmony_ci * 109662306a36Sopenharmony_ci **/ 109762306a36Sopenharmony_civoid i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { 110062306a36Sopenharmony_ci u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | 110162306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */ 110262306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | 110362306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; 110462306a36Sopenharmony_ci /* allow 00 to be written to the index */ 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci wr32(&vsi->back->hw, 110762306a36Sopenharmony_ci I40E_PFINT_DYN_CTLN(q_vector->reg_idx), val); 110862306a36Sopenharmony_ci } else { 110962306a36Sopenharmony_ci u32 val = I40E_PFINT_DYN_CTL0_INTENA_MASK | 111062306a36Sopenharmony_ci I40E_PFINT_DYN_CTL0_ITR_INDX_MASK | /* set noitr */ 111162306a36Sopenharmony_ci I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK | 111262306a36Sopenharmony_ci I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK; 111362306a36Sopenharmony_ci /* allow 00 to be written to the index */ 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0, val); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic inline bool i40e_container_is_rx(struct i40e_q_vector *q_vector, 112062306a36Sopenharmony_ci struct i40e_ring_container *rc) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci return &q_vector->rx == rc; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic inline unsigned int i40e_itr_divisor(struct i40e_q_vector *q_vector) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci unsigned int divisor; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci switch (q_vector->vsi->back->hw.phy.link_info.link_speed) { 113062306a36Sopenharmony_ci case I40E_LINK_SPEED_40GB: 113162306a36Sopenharmony_ci divisor = I40E_ITR_ADAPTIVE_MIN_INC * 1024; 113262306a36Sopenharmony_ci break; 113362306a36Sopenharmony_ci case I40E_LINK_SPEED_25GB: 113462306a36Sopenharmony_ci case I40E_LINK_SPEED_20GB: 113562306a36Sopenharmony_ci divisor = I40E_ITR_ADAPTIVE_MIN_INC * 512; 113662306a36Sopenharmony_ci break; 113762306a36Sopenharmony_ci default: 113862306a36Sopenharmony_ci case I40E_LINK_SPEED_10GB: 113962306a36Sopenharmony_ci divisor = I40E_ITR_ADAPTIVE_MIN_INC * 256; 114062306a36Sopenharmony_ci break; 114162306a36Sopenharmony_ci case I40E_LINK_SPEED_1GB: 114262306a36Sopenharmony_ci case I40E_LINK_SPEED_100MB: 114362306a36Sopenharmony_ci divisor = I40E_ITR_ADAPTIVE_MIN_INC * 32; 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return divisor; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci/** 115162306a36Sopenharmony_ci * i40e_update_itr - update the dynamic ITR value based on statistics 115262306a36Sopenharmony_ci * @q_vector: structure containing interrupt and ring information 115362306a36Sopenharmony_ci * @rc: structure containing ring performance data 115462306a36Sopenharmony_ci * 115562306a36Sopenharmony_ci * Stores a new ITR value based on packets and byte 115662306a36Sopenharmony_ci * counts during the last interrupt. The advantage of per interrupt 115762306a36Sopenharmony_ci * computation is faster updates and more accurate ITR for the current 115862306a36Sopenharmony_ci * traffic pattern. Constants in this function were computed 115962306a36Sopenharmony_ci * based on theoretical maximum wire speed and thresholds were set based 116062306a36Sopenharmony_ci * on testing data as well as attempting to minimize response time 116162306a36Sopenharmony_ci * while increasing bulk throughput. 116262306a36Sopenharmony_ci **/ 116362306a36Sopenharmony_cistatic void i40e_update_itr(struct i40e_q_vector *q_vector, 116462306a36Sopenharmony_ci struct i40e_ring_container *rc) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci unsigned int avg_wire_size, packets, bytes, itr; 116762306a36Sopenharmony_ci unsigned long next_update = jiffies; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* If we don't have any rings just leave ourselves set for maximum 117062306a36Sopenharmony_ci * possible latency so we take ourselves out of the equation. 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_ci if (!rc->ring || !ITR_IS_DYNAMIC(rc->ring->itr_setting)) 117362306a36Sopenharmony_ci return; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* For Rx we want to push the delay up and default to low latency. 117662306a36Sopenharmony_ci * for Tx we want to pull the delay down and default to high latency. 117762306a36Sopenharmony_ci */ 117862306a36Sopenharmony_ci itr = i40e_container_is_rx(q_vector, rc) ? 117962306a36Sopenharmony_ci I40E_ITR_ADAPTIVE_MIN_USECS | I40E_ITR_ADAPTIVE_LATENCY : 118062306a36Sopenharmony_ci I40E_ITR_ADAPTIVE_MAX_USECS | I40E_ITR_ADAPTIVE_LATENCY; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* If we didn't update within up to 1 - 2 jiffies we can assume 118362306a36Sopenharmony_ci * that either packets are coming in so slow there hasn't been 118462306a36Sopenharmony_ci * any work, or that there is so much work that NAPI is dealing 118562306a36Sopenharmony_ci * with interrupt moderation and we don't need to do anything. 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci if (time_after(next_update, rc->next_update)) 118862306a36Sopenharmony_ci goto clear_counts; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* If itr_countdown is set it means we programmed an ITR within 119162306a36Sopenharmony_ci * the last 4 interrupt cycles. This has a side effect of us 119262306a36Sopenharmony_ci * potentially firing an early interrupt. In order to work around 119362306a36Sopenharmony_ci * this we need to throw out any data received for a few 119462306a36Sopenharmony_ci * interrupts following the update. 119562306a36Sopenharmony_ci */ 119662306a36Sopenharmony_ci if (q_vector->itr_countdown) { 119762306a36Sopenharmony_ci itr = rc->target_itr; 119862306a36Sopenharmony_ci goto clear_counts; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci packets = rc->total_packets; 120262306a36Sopenharmony_ci bytes = rc->total_bytes; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci if (i40e_container_is_rx(q_vector, rc)) { 120562306a36Sopenharmony_ci /* If Rx there are 1 to 4 packets and bytes are less than 120662306a36Sopenharmony_ci * 9000 assume insufficient data to use bulk rate limiting 120762306a36Sopenharmony_ci * approach unless Tx is already in bulk rate limiting. We 120862306a36Sopenharmony_ci * are likely latency driven. 120962306a36Sopenharmony_ci */ 121062306a36Sopenharmony_ci if (packets && packets < 4 && bytes < 9000 && 121162306a36Sopenharmony_ci (q_vector->tx.target_itr & I40E_ITR_ADAPTIVE_LATENCY)) { 121262306a36Sopenharmony_ci itr = I40E_ITR_ADAPTIVE_LATENCY; 121362306a36Sopenharmony_ci goto adjust_by_size; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci } else if (packets < 4) { 121662306a36Sopenharmony_ci /* If we have Tx and Rx ITR maxed and Tx ITR is running in 121762306a36Sopenharmony_ci * bulk mode and we are receiving 4 or fewer packets just 121862306a36Sopenharmony_ci * reset the ITR_ADAPTIVE_LATENCY bit for latency mode so 121962306a36Sopenharmony_ci * that the Rx can relax. 122062306a36Sopenharmony_ci */ 122162306a36Sopenharmony_ci if (rc->target_itr == I40E_ITR_ADAPTIVE_MAX_USECS && 122262306a36Sopenharmony_ci (q_vector->rx.target_itr & I40E_ITR_MASK) == 122362306a36Sopenharmony_ci I40E_ITR_ADAPTIVE_MAX_USECS) 122462306a36Sopenharmony_ci goto clear_counts; 122562306a36Sopenharmony_ci } else if (packets > 32) { 122662306a36Sopenharmony_ci /* If we have processed over 32 packets in a single interrupt 122762306a36Sopenharmony_ci * for Tx assume we need to switch over to "bulk" mode. 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci rc->target_itr &= ~I40E_ITR_ADAPTIVE_LATENCY; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci /* We have no packets to actually measure against. This means 123362306a36Sopenharmony_ci * either one of the other queues on this vector is active or 123462306a36Sopenharmony_ci * we are a Tx queue doing TSO with too high of an interrupt rate. 123562306a36Sopenharmony_ci * 123662306a36Sopenharmony_ci * Between 4 and 56 we can assume that our current interrupt delay 123762306a36Sopenharmony_ci * is only slightly too low. As such we should increase it by a small 123862306a36Sopenharmony_ci * fixed amount. 123962306a36Sopenharmony_ci */ 124062306a36Sopenharmony_ci if (packets < 56) { 124162306a36Sopenharmony_ci itr = rc->target_itr + I40E_ITR_ADAPTIVE_MIN_INC; 124262306a36Sopenharmony_ci if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) { 124362306a36Sopenharmony_ci itr &= I40E_ITR_ADAPTIVE_LATENCY; 124462306a36Sopenharmony_ci itr += I40E_ITR_ADAPTIVE_MAX_USECS; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci goto clear_counts; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (packets <= 256) { 125062306a36Sopenharmony_ci itr = min(q_vector->tx.current_itr, q_vector->rx.current_itr); 125162306a36Sopenharmony_ci itr &= I40E_ITR_MASK; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* Between 56 and 112 is our "goldilocks" zone where we are 125462306a36Sopenharmony_ci * working out "just right". Just report that our current 125562306a36Sopenharmony_ci * ITR is good for us. 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_ci if (packets <= 112) 125862306a36Sopenharmony_ci goto clear_counts; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci /* If packet count is 128 or greater we are likely looking 126162306a36Sopenharmony_ci * at a slight overrun of the delay we want. Try halving 126262306a36Sopenharmony_ci * our delay to see if that will cut the number of packets 126362306a36Sopenharmony_ci * in half per interrupt. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci itr /= 2; 126662306a36Sopenharmony_ci itr &= I40E_ITR_MASK; 126762306a36Sopenharmony_ci if (itr < I40E_ITR_ADAPTIVE_MIN_USECS) 126862306a36Sopenharmony_ci itr = I40E_ITR_ADAPTIVE_MIN_USECS; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci goto clear_counts; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* The paths below assume we are dealing with a bulk ITR since 127462306a36Sopenharmony_ci * number of packets is greater than 256. We are just going to have 127562306a36Sopenharmony_ci * to compute a value and try to bring the count under control, 127662306a36Sopenharmony_ci * though for smaller packet sizes there isn't much we can do as 127762306a36Sopenharmony_ci * NAPI polling will likely be kicking in sooner rather than later. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci itr = I40E_ITR_ADAPTIVE_BULK; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ciadjust_by_size: 128262306a36Sopenharmony_ci /* If packet counts are 256 or greater we can assume we have a gross 128362306a36Sopenharmony_ci * overestimation of what the rate should be. Instead of trying to fine 128462306a36Sopenharmony_ci * tune it just use the formula below to try and dial in an exact value 128562306a36Sopenharmony_ci * give the current packet size of the frame. 128662306a36Sopenharmony_ci */ 128762306a36Sopenharmony_ci avg_wire_size = bytes / packets; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* The following is a crude approximation of: 129062306a36Sopenharmony_ci * wmem_default / (size + overhead) = desired_pkts_per_int 129162306a36Sopenharmony_ci * rate / bits_per_byte / (size + ethernet overhead) = pkt_rate 129262306a36Sopenharmony_ci * (desired_pkt_rate / pkt_rate) * usecs_per_sec = ITR value 129362306a36Sopenharmony_ci * 129462306a36Sopenharmony_ci * Assuming wmem_default is 212992 and overhead is 640 bytes per 129562306a36Sopenharmony_ci * packet, (256 skb, 64 headroom, 320 shared info), we can reduce the 129662306a36Sopenharmony_ci * formula down to 129762306a36Sopenharmony_ci * 129862306a36Sopenharmony_ci * (170 * (size + 24)) / (size + 640) = ITR 129962306a36Sopenharmony_ci * 130062306a36Sopenharmony_ci * We first do some math on the packet size and then finally bitshift 130162306a36Sopenharmony_ci * by 8 after rounding up. We also have to account for PCIe link speed 130262306a36Sopenharmony_ci * difference as ITR scales based on this. 130362306a36Sopenharmony_ci */ 130462306a36Sopenharmony_ci if (avg_wire_size <= 60) { 130562306a36Sopenharmony_ci /* Start at 250k ints/sec */ 130662306a36Sopenharmony_ci avg_wire_size = 4096; 130762306a36Sopenharmony_ci } else if (avg_wire_size <= 380) { 130862306a36Sopenharmony_ci /* 250K ints/sec to 60K ints/sec */ 130962306a36Sopenharmony_ci avg_wire_size *= 40; 131062306a36Sopenharmony_ci avg_wire_size += 1696; 131162306a36Sopenharmony_ci } else if (avg_wire_size <= 1084) { 131262306a36Sopenharmony_ci /* 60K ints/sec to 36K ints/sec */ 131362306a36Sopenharmony_ci avg_wire_size *= 15; 131462306a36Sopenharmony_ci avg_wire_size += 11452; 131562306a36Sopenharmony_ci } else if (avg_wire_size <= 1980) { 131662306a36Sopenharmony_ci /* 36K ints/sec to 30K ints/sec */ 131762306a36Sopenharmony_ci avg_wire_size *= 5; 131862306a36Sopenharmony_ci avg_wire_size += 22420; 131962306a36Sopenharmony_ci } else { 132062306a36Sopenharmony_ci /* plateau at a limit of 30K ints/sec */ 132162306a36Sopenharmony_ci avg_wire_size = 32256; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* If we are in low latency mode halve our delay which doubles the 132562306a36Sopenharmony_ci * rate to somewhere between 100K to 16K ints/sec 132662306a36Sopenharmony_ci */ 132762306a36Sopenharmony_ci if (itr & I40E_ITR_ADAPTIVE_LATENCY) 132862306a36Sopenharmony_ci avg_wire_size /= 2; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* Resultant value is 256 times larger than it needs to be. This 133162306a36Sopenharmony_ci * gives us room to adjust the value as needed to either increase 133262306a36Sopenharmony_ci * or decrease the value based on link speeds of 10G, 2.5G, 1G, etc. 133362306a36Sopenharmony_ci * 133462306a36Sopenharmony_ci * Use addition as we have already recorded the new latency flag 133562306a36Sopenharmony_ci * for the ITR value. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_ci itr += DIV_ROUND_UP(avg_wire_size, i40e_itr_divisor(q_vector)) * 133862306a36Sopenharmony_ci I40E_ITR_ADAPTIVE_MIN_INC; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci if ((itr & I40E_ITR_MASK) > I40E_ITR_ADAPTIVE_MAX_USECS) { 134162306a36Sopenharmony_ci itr &= I40E_ITR_ADAPTIVE_LATENCY; 134262306a36Sopenharmony_ci itr += I40E_ITR_ADAPTIVE_MAX_USECS; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ciclear_counts: 134662306a36Sopenharmony_ci /* write back value */ 134762306a36Sopenharmony_ci rc->target_itr = itr; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* next update should occur within next jiffy */ 135062306a36Sopenharmony_ci rc->next_update = next_update + 1; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci rc->total_bytes = 0; 135362306a36Sopenharmony_ci rc->total_packets = 0; 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic struct i40e_rx_buffer *i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx) 135762306a36Sopenharmony_ci{ 135862306a36Sopenharmony_ci return &rx_ring->rx_bi[idx]; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci/** 136262306a36Sopenharmony_ci * i40e_reuse_rx_page - page flip buffer and store it back on the ring 136362306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to store buffers on 136462306a36Sopenharmony_ci * @old_buff: donor buffer to have page reused 136562306a36Sopenharmony_ci * 136662306a36Sopenharmony_ci * Synchronizes page for reuse by the adapter 136762306a36Sopenharmony_ci **/ 136862306a36Sopenharmony_cistatic void i40e_reuse_rx_page(struct i40e_ring *rx_ring, 136962306a36Sopenharmony_ci struct i40e_rx_buffer *old_buff) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci struct i40e_rx_buffer *new_buff; 137262306a36Sopenharmony_ci u16 nta = rx_ring->next_to_alloc; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci new_buff = i40e_rx_bi(rx_ring, nta); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* update, and store next to alloc */ 137762306a36Sopenharmony_ci nta++; 137862306a36Sopenharmony_ci rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* transfer page from old buffer to new buffer */ 138162306a36Sopenharmony_ci new_buff->dma = old_buff->dma; 138262306a36Sopenharmony_ci new_buff->page = old_buff->page; 138362306a36Sopenharmony_ci new_buff->page_offset = old_buff->page_offset; 138462306a36Sopenharmony_ci new_buff->pagecnt_bias = old_buff->pagecnt_bias; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* clear contents of buffer_info */ 138762306a36Sopenharmony_ci old_buff->page = NULL; 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci/** 139162306a36Sopenharmony_ci * i40e_clean_programming_status - clean the programming status descriptor 139262306a36Sopenharmony_ci * @rx_ring: the rx ring that has this descriptor 139362306a36Sopenharmony_ci * @qword0_raw: qword0 139462306a36Sopenharmony_ci * @qword1: qword1 representing status_error_len in CPU ordering 139562306a36Sopenharmony_ci * 139662306a36Sopenharmony_ci * Flow director should handle FD_FILTER_STATUS to check its filter programming 139762306a36Sopenharmony_ci * status being successful or not and take actions accordingly. FCoE should 139862306a36Sopenharmony_ci * handle its context/filter programming/invalidation status and take actions. 139962306a36Sopenharmony_ci * 140062306a36Sopenharmony_ci * Returns an i40e_rx_buffer to reuse if the cleanup occurred, otherwise NULL. 140162306a36Sopenharmony_ci **/ 140262306a36Sopenharmony_civoid i40e_clean_programming_status(struct i40e_ring *rx_ring, u64 qword0_raw, 140362306a36Sopenharmony_ci u64 qword1) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci u8 id; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci id = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >> 140862306a36Sopenharmony_ci I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) 141162306a36Sopenharmony_ci i40e_fd_handle_status(rx_ring, qword0_raw, qword1, id); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci/** 141562306a36Sopenharmony_ci * i40e_setup_tx_descriptors - Allocate the Tx descriptors 141662306a36Sopenharmony_ci * @tx_ring: the tx ring to set up 141762306a36Sopenharmony_ci * 141862306a36Sopenharmony_ci * Return 0 on success, negative on error 141962306a36Sopenharmony_ci **/ 142062306a36Sopenharmony_ciint i40e_setup_tx_descriptors(struct i40e_ring *tx_ring) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci struct device *dev = tx_ring->dev; 142362306a36Sopenharmony_ci int bi_size; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (!dev) 142662306a36Sopenharmony_ci return -ENOMEM; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* warn if we are about to overwrite the pointer */ 142962306a36Sopenharmony_ci WARN_ON(tx_ring->tx_bi); 143062306a36Sopenharmony_ci bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; 143162306a36Sopenharmony_ci tx_ring->tx_bi = kzalloc(bi_size, GFP_KERNEL); 143262306a36Sopenharmony_ci if (!tx_ring->tx_bi) 143362306a36Sopenharmony_ci goto err; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci u64_stats_init(&tx_ring->syncp); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* round up to nearest 4K */ 143862306a36Sopenharmony_ci tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc); 143962306a36Sopenharmony_ci /* add u32 for head writeback, align after this takes care of 144062306a36Sopenharmony_ci * guaranteeing this is at least one cache line in size 144162306a36Sopenharmony_ci */ 144262306a36Sopenharmony_ci tx_ring->size += sizeof(u32); 144362306a36Sopenharmony_ci tx_ring->size = ALIGN(tx_ring->size, 4096); 144462306a36Sopenharmony_ci tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size, 144562306a36Sopenharmony_ci &tx_ring->dma, GFP_KERNEL); 144662306a36Sopenharmony_ci if (!tx_ring->desc) { 144762306a36Sopenharmony_ci dev_info(dev, "Unable to allocate memory for the Tx descriptor ring, size=%d\n", 144862306a36Sopenharmony_ci tx_ring->size); 144962306a36Sopenharmony_ci goto err; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci tx_ring->next_to_use = 0; 145362306a36Sopenharmony_ci tx_ring->next_to_clean = 0; 145462306a36Sopenharmony_ci tx_ring->tx_stats.prev_pkt_ctr = -1; 145562306a36Sopenharmony_ci return 0; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_cierr: 145862306a36Sopenharmony_ci kfree(tx_ring->tx_bi); 145962306a36Sopenharmony_ci tx_ring->tx_bi = NULL; 146062306a36Sopenharmony_ci return -ENOMEM; 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_cistatic void i40e_clear_rx_bi(struct i40e_ring *rx_ring) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci memset(rx_ring->rx_bi, 0, sizeof(*rx_ring->rx_bi) * rx_ring->count); 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci/** 146962306a36Sopenharmony_ci * i40e_clean_rx_ring - Free Rx buffers 147062306a36Sopenharmony_ci * @rx_ring: ring to be cleaned 147162306a36Sopenharmony_ci **/ 147262306a36Sopenharmony_civoid i40e_clean_rx_ring(struct i40e_ring *rx_ring) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci u16 i; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* ring already cleared, nothing to do */ 147762306a36Sopenharmony_ci if (!rx_ring->rx_bi) 147862306a36Sopenharmony_ci return; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (rx_ring->xsk_pool) { 148162306a36Sopenharmony_ci i40e_xsk_clean_rx_ring(rx_ring); 148262306a36Sopenharmony_ci goto skip_free; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* Free all the Rx ring sk_buffs */ 148662306a36Sopenharmony_ci for (i = 0; i < rx_ring->count; i++) { 148762306a36Sopenharmony_ci struct i40e_rx_buffer *rx_bi = i40e_rx_bi(rx_ring, i); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (!rx_bi->page) 149062306a36Sopenharmony_ci continue; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* Invalidate cache lines that may have been written to by 149362306a36Sopenharmony_ci * device so that we avoid corrupting memory. 149462306a36Sopenharmony_ci */ 149562306a36Sopenharmony_ci dma_sync_single_range_for_cpu(rx_ring->dev, 149662306a36Sopenharmony_ci rx_bi->dma, 149762306a36Sopenharmony_ci rx_bi->page_offset, 149862306a36Sopenharmony_ci rx_ring->rx_buf_len, 149962306a36Sopenharmony_ci DMA_FROM_DEVICE); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci /* free resources associated with mapping */ 150262306a36Sopenharmony_ci dma_unmap_page_attrs(rx_ring->dev, rx_bi->dma, 150362306a36Sopenharmony_ci i40e_rx_pg_size(rx_ring), 150462306a36Sopenharmony_ci DMA_FROM_DEVICE, 150562306a36Sopenharmony_ci I40E_RX_DMA_ATTR); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci __page_frag_cache_drain(rx_bi->page, rx_bi->pagecnt_bias); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci rx_bi->page = NULL; 151062306a36Sopenharmony_ci rx_bi->page_offset = 0; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ciskip_free: 151462306a36Sopenharmony_ci if (rx_ring->xsk_pool) 151562306a36Sopenharmony_ci i40e_clear_rx_bi_zc(rx_ring); 151662306a36Sopenharmony_ci else 151762306a36Sopenharmony_ci i40e_clear_rx_bi(rx_ring); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci /* Zero out the descriptor ring */ 152062306a36Sopenharmony_ci memset(rx_ring->desc, 0, rx_ring->size); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci rx_ring->next_to_alloc = 0; 152362306a36Sopenharmony_ci rx_ring->next_to_clean = 0; 152462306a36Sopenharmony_ci rx_ring->next_to_process = 0; 152562306a36Sopenharmony_ci rx_ring->next_to_use = 0; 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci/** 152962306a36Sopenharmony_ci * i40e_free_rx_resources - Free Rx resources 153062306a36Sopenharmony_ci * @rx_ring: ring to clean the resources from 153162306a36Sopenharmony_ci * 153262306a36Sopenharmony_ci * Free all receive software resources 153362306a36Sopenharmony_ci **/ 153462306a36Sopenharmony_civoid i40e_free_rx_resources(struct i40e_ring *rx_ring) 153562306a36Sopenharmony_ci{ 153662306a36Sopenharmony_ci i40e_clean_rx_ring(rx_ring); 153762306a36Sopenharmony_ci if (rx_ring->vsi->type == I40E_VSI_MAIN) 153862306a36Sopenharmony_ci xdp_rxq_info_unreg(&rx_ring->xdp_rxq); 153962306a36Sopenharmony_ci rx_ring->xdp_prog = NULL; 154062306a36Sopenharmony_ci kfree(rx_ring->rx_bi); 154162306a36Sopenharmony_ci rx_ring->rx_bi = NULL; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (rx_ring->desc) { 154462306a36Sopenharmony_ci dma_free_coherent(rx_ring->dev, rx_ring->size, 154562306a36Sopenharmony_ci rx_ring->desc, rx_ring->dma); 154662306a36Sopenharmony_ci rx_ring->desc = NULL; 154762306a36Sopenharmony_ci } 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci/** 155162306a36Sopenharmony_ci * i40e_setup_rx_descriptors - Allocate Rx descriptors 155262306a36Sopenharmony_ci * @rx_ring: Rx descriptor ring (for a specific queue) to setup 155362306a36Sopenharmony_ci * 155462306a36Sopenharmony_ci * Returns 0 on success, negative on failure 155562306a36Sopenharmony_ci **/ 155662306a36Sopenharmony_ciint i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci struct device *dev = rx_ring->dev; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci u64_stats_init(&rx_ring->syncp); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* Round up to nearest 4K */ 156362306a36Sopenharmony_ci rx_ring->size = rx_ring->count * sizeof(union i40e_rx_desc); 156462306a36Sopenharmony_ci rx_ring->size = ALIGN(rx_ring->size, 4096); 156562306a36Sopenharmony_ci rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size, 156662306a36Sopenharmony_ci &rx_ring->dma, GFP_KERNEL); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (!rx_ring->desc) { 156962306a36Sopenharmony_ci dev_info(dev, "Unable to allocate memory for the Rx descriptor ring, size=%d\n", 157062306a36Sopenharmony_ci rx_ring->size); 157162306a36Sopenharmony_ci return -ENOMEM; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci rx_ring->next_to_alloc = 0; 157562306a36Sopenharmony_ci rx_ring->next_to_clean = 0; 157662306a36Sopenharmony_ci rx_ring->next_to_process = 0; 157762306a36Sopenharmony_ci rx_ring->next_to_use = 0; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci rx_ring->xdp_prog = rx_ring->vsi->xdp_prog; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci rx_ring->rx_bi = 158262306a36Sopenharmony_ci kcalloc(rx_ring->count, sizeof(*rx_ring->rx_bi), GFP_KERNEL); 158362306a36Sopenharmony_ci if (!rx_ring->rx_bi) 158462306a36Sopenharmony_ci return -ENOMEM; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci return 0; 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci/** 159062306a36Sopenharmony_ci * i40e_release_rx_desc - Store the new tail and head values 159162306a36Sopenharmony_ci * @rx_ring: ring to bump 159262306a36Sopenharmony_ci * @val: new head index 159362306a36Sopenharmony_ci **/ 159462306a36Sopenharmony_civoid i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci rx_ring->next_to_use = val; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* update next to alloc since we have filled the ring */ 159962306a36Sopenharmony_ci rx_ring->next_to_alloc = val; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Force memory writes to complete before letting h/w 160262306a36Sopenharmony_ci * know there are new descriptors to fetch. (Only 160362306a36Sopenharmony_ci * applicable for weak-ordered memory model archs, 160462306a36Sopenharmony_ci * such as IA-64). 160562306a36Sopenharmony_ci */ 160662306a36Sopenharmony_ci wmb(); 160762306a36Sopenharmony_ci writel(val, rx_ring->tail); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci#if (PAGE_SIZE >= 8192) 161162306a36Sopenharmony_cistatic unsigned int i40e_rx_frame_truesize(struct i40e_ring *rx_ring, 161262306a36Sopenharmony_ci unsigned int size) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci unsigned int truesize; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci truesize = rx_ring->rx_offset ? 161762306a36Sopenharmony_ci SKB_DATA_ALIGN(size + rx_ring->rx_offset) + 161862306a36Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : 161962306a36Sopenharmony_ci SKB_DATA_ALIGN(size); 162062306a36Sopenharmony_ci return truesize; 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci#endif 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/** 162562306a36Sopenharmony_ci * i40e_alloc_mapped_page - recycle or make a new page 162662306a36Sopenharmony_ci * @rx_ring: ring to use 162762306a36Sopenharmony_ci * @bi: rx_buffer struct to modify 162862306a36Sopenharmony_ci * 162962306a36Sopenharmony_ci * Returns true if the page was successfully allocated or 163062306a36Sopenharmony_ci * reused. 163162306a36Sopenharmony_ci **/ 163262306a36Sopenharmony_cistatic bool i40e_alloc_mapped_page(struct i40e_ring *rx_ring, 163362306a36Sopenharmony_ci struct i40e_rx_buffer *bi) 163462306a36Sopenharmony_ci{ 163562306a36Sopenharmony_ci struct page *page = bi->page; 163662306a36Sopenharmony_ci dma_addr_t dma; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* since we are recycling buffers we should seldom need to alloc */ 163962306a36Sopenharmony_ci if (likely(page)) { 164062306a36Sopenharmony_ci rx_ring->rx_stats.page_reuse_count++; 164162306a36Sopenharmony_ci return true; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci /* alloc new page for storage */ 164562306a36Sopenharmony_ci page = dev_alloc_pages(i40e_rx_pg_order(rx_ring)); 164662306a36Sopenharmony_ci if (unlikely(!page)) { 164762306a36Sopenharmony_ci rx_ring->rx_stats.alloc_page_failed++; 164862306a36Sopenharmony_ci return false; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci rx_ring->rx_stats.page_alloc_count++; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* map page for use */ 165462306a36Sopenharmony_ci dma = dma_map_page_attrs(rx_ring->dev, page, 0, 165562306a36Sopenharmony_ci i40e_rx_pg_size(rx_ring), 165662306a36Sopenharmony_ci DMA_FROM_DEVICE, 165762306a36Sopenharmony_ci I40E_RX_DMA_ATTR); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* if mapping failed free memory back to system since 166062306a36Sopenharmony_ci * there isn't much point in holding memory we can't use 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci if (dma_mapping_error(rx_ring->dev, dma)) { 166362306a36Sopenharmony_ci __free_pages(page, i40e_rx_pg_order(rx_ring)); 166462306a36Sopenharmony_ci rx_ring->rx_stats.alloc_page_failed++; 166562306a36Sopenharmony_ci return false; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci bi->dma = dma; 166962306a36Sopenharmony_ci bi->page = page; 167062306a36Sopenharmony_ci bi->page_offset = rx_ring->rx_offset; 167162306a36Sopenharmony_ci page_ref_add(page, USHRT_MAX - 1); 167262306a36Sopenharmony_ci bi->pagecnt_bias = USHRT_MAX; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci return true; 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci/** 167862306a36Sopenharmony_ci * i40e_alloc_rx_buffers - Replace used receive buffers 167962306a36Sopenharmony_ci * @rx_ring: ring to place buffers on 168062306a36Sopenharmony_ci * @cleaned_count: number of buffers to replace 168162306a36Sopenharmony_ci * 168262306a36Sopenharmony_ci * Returns false if all allocations were successful, true if any fail 168362306a36Sopenharmony_ci **/ 168462306a36Sopenharmony_cibool i40e_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count) 168562306a36Sopenharmony_ci{ 168662306a36Sopenharmony_ci u16 ntu = rx_ring->next_to_use; 168762306a36Sopenharmony_ci union i40e_rx_desc *rx_desc; 168862306a36Sopenharmony_ci struct i40e_rx_buffer *bi; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* do nothing if no valid netdev defined */ 169162306a36Sopenharmony_ci if (!rx_ring->netdev || !cleaned_count) 169262306a36Sopenharmony_ci return false; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, ntu); 169562306a36Sopenharmony_ci bi = i40e_rx_bi(rx_ring, ntu); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci do { 169862306a36Sopenharmony_ci if (!i40e_alloc_mapped_page(rx_ring, bi)) 169962306a36Sopenharmony_ci goto no_buffers; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci /* sync the buffer for use by the device */ 170262306a36Sopenharmony_ci dma_sync_single_range_for_device(rx_ring->dev, bi->dma, 170362306a36Sopenharmony_ci bi->page_offset, 170462306a36Sopenharmony_ci rx_ring->rx_buf_len, 170562306a36Sopenharmony_ci DMA_FROM_DEVICE); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* Refresh the desc even if buffer_addrs didn't change 170862306a36Sopenharmony_ci * because each write-back erases this info. 170962306a36Sopenharmony_ci */ 171062306a36Sopenharmony_ci rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci rx_desc++; 171362306a36Sopenharmony_ci bi++; 171462306a36Sopenharmony_ci ntu++; 171562306a36Sopenharmony_ci if (unlikely(ntu == rx_ring->count)) { 171662306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, 0); 171762306a36Sopenharmony_ci bi = i40e_rx_bi(rx_ring, 0); 171862306a36Sopenharmony_ci ntu = 0; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci /* clear the status bits for the next_to_use descriptor */ 172262306a36Sopenharmony_ci rx_desc->wb.qword1.status_error_len = 0; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci cleaned_count--; 172562306a36Sopenharmony_ci } while (cleaned_count); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci if (rx_ring->next_to_use != ntu) 172862306a36Sopenharmony_ci i40e_release_rx_desc(rx_ring, ntu); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci return false; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_cino_buffers: 173362306a36Sopenharmony_ci if (rx_ring->next_to_use != ntu) 173462306a36Sopenharmony_ci i40e_release_rx_desc(rx_ring, ntu); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* make sure to come back via polling to try again after 173762306a36Sopenharmony_ci * allocation failure 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci return true; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci/** 174362306a36Sopenharmony_ci * i40e_rx_checksum - Indicate in skb if hw indicated a good cksum 174462306a36Sopenharmony_ci * @vsi: the VSI we care about 174562306a36Sopenharmony_ci * @skb: skb currently being received and modified 174662306a36Sopenharmony_ci * @rx_desc: the receive descriptor 174762306a36Sopenharmony_ci **/ 174862306a36Sopenharmony_cistatic inline void i40e_rx_checksum(struct i40e_vsi *vsi, 174962306a36Sopenharmony_ci struct sk_buff *skb, 175062306a36Sopenharmony_ci union i40e_rx_desc *rx_desc) 175162306a36Sopenharmony_ci{ 175262306a36Sopenharmony_ci struct i40e_rx_ptype_decoded decoded; 175362306a36Sopenharmony_ci u32 rx_error, rx_status; 175462306a36Sopenharmony_ci bool ipv4, ipv6; 175562306a36Sopenharmony_ci u8 ptype; 175662306a36Sopenharmony_ci u64 qword; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); 175962306a36Sopenharmony_ci ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; 176062306a36Sopenharmony_ci rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> 176162306a36Sopenharmony_ci I40E_RXD_QW1_ERROR_SHIFT; 176262306a36Sopenharmony_ci rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> 176362306a36Sopenharmony_ci I40E_RXD_QW1_STATUS_SHIFT; 176462306a36Sopenharmony_ci decoded = decode_rx_desc_ptype(ptype); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci skb_checksum_none_assert(skb); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci /* Rx csum enabled and ip headers found? */ 177162306a36Sopenharmony_ci if (!(vsi->netdev->features & NETIF_F_RXCSUM)) 177262306a36Sopenharmony_ci return; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* did the hardware decode the packet and checksum? */ 177562306a36Sopenharmony_ci if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) 177662306a36Sopenharmony_ci return; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci /* both known and outer_ip must be set for the below code to work */ 177962306a36Sopenharmony_ci if (!(decoded.known && decoded.outer_ip)) 178062306a36Sopenharmony_ci return; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) && 178362306a36Sopenharmony_ci (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4); 178462306a36Sopenharmony_ci ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) && 178562306a36Sopenharmony_ci (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (ipv4 && 178862306a36Sopenharmony_ci (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | 178962306a36Sopenharmony_ci BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) 179062306a36Sopenharmony_ci goto checksum_fail; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci /* likely incorrect csum if alternate IP extension headers found */ 179362306a36Sopenharmony_ci if (ipv6 && 179462306a36Sopenharmony_ci rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) 179562306a36Sopenharmony_ci /* don't increment checksum err here, non-fatal err */ 179662306a36Sopenharmony_ci return; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci /* there was some L4 error, count error and punt packet to the stack */ 179962306a36Sopenharmony_ci if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) 180062306a36Sopenharmony_ci goto checksum_fail; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci /* handle packets that were not able to be checksummed due 180362306a36Sopenharmony_ci * to arrival speed, in this case the stack can compute 180462306a36Sopenharmony_ci * the csum. 180562306a36Sopenharmony_ci */ 180662306a36Sopenharmony_ci if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) 180762306a36Sopenharmony_ci return; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci /* If there is an outer header present that might contain a checksum 181062306a36Sopenharmony_ci * we need to bump the checksum level by 1 to reflect the fact that 181162306a36Sopenharmony_ci * we are indicating we validated the inner checksum. 181262306a36Sopenharmony_ci */ 181362306a36Sopenharmony_ci if (decoded.tunnel_type >= I40E_RX_PTYPE_TUNNEL_IP_GRENAT) 181462306a36Sopenharmony_ci skb->csum_level = 1; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci /* Only report checksum unnecessary for TCP, UDP, or SCTP */ 181762306a36Sopenharmony_ci switch (decoded.inner_prot) { 181862306a36Sopenharmony_ci case I40E_RX_PTYPE_INNER_PROT_TCP: 181962306a36Sopenharmony_ci case I40E_RX_PTYPE_INNER_PROT_UDP: 182062306a36Sopenharmony_ci case I40E_RX_PTYPE_INNER_PROT_SCTP: 182162306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 182262306a36Sopenharmony_ci fallthrough; 182362306a36Sopenharmony_ci default: 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci return; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cichecksum_fail: 183062306a36Sopenharmony_ci vsi->back->hw_csum_rx_error++; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci/** 183462306a36Sopenharmony_ci * i40e_ptype_to_htype - get a hash type 183562306a36Sopenharmony_ci * @ptype: the ptype value from the descriptor 183662306a36Sopenharmony_ci * 183762306a36Sopenharmony_ci * Returns a hash type to be used by skb_set_hash 183862306a36Sopenharmony_ci **/ 183962306a36Sopenharmony_cistatic inline int i40e_ptype_to_htype(u8 ptype) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci if (!decoded.known) 184462306a36Sopenharmony_ci return PKT_HASH_TYPE_NONE; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && 184762306a36Sopenharmony_ci decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) 184862306a36Sopenharmony_ci return PKT_HASH_TYPE_L4; 184962306a36Sopenharmony_ci else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && 185062306a36Sopenharmony_ci decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) 185162306a36Sopenharmony_ci return PKT_HASH_TYPE_L3; 185262306a36Sopenharmony_ci else 185362306a36Sopenharmony_ci return PKT_HASH_TYPE_L2; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci/** 185762306a36Sopenharmony_ci * i40e_rx_hash - set the hash value in the skb 185862306a36Sopenharmony_ci * @ring: descriptor ring 185962306a36Sopenharmony_ci * @rx_desc: specific descriptor 186062306a36Sopenharmony_ci * @skb: skb currently being received and modified 186162306a36Sopenharmony_ci * @rx_ptype: Rx packet type 186262306a36Sopenharmony_ci **/ 186362306a36Sopenharmony_cistatic inline void i40e_rx_hash(struct i40e_ring *ring, 186462306a36Sopenharmony_ci union i40e_rx_desc *rx_desc, 186562306a36Sopenharmony_ci struct sk_buff *skb, 186662306a36Sopenharmony_ci u8 rx_ptype) 186762306a36Sopenharmony_ci{ 186862306a36Sopenharmony_ci u32 hash; 186962306a36Sopenharmony_ci const __le64 rss_mask = 187062306a36Sopenharmony_ci cpu_to_le64((u64)I40E_RX_DESC_FLTSTAT_RSS_HASH << 187162306a36Sopenharmony_ci I40E_RX_DESC_STATUS_FLTSTAT_SHIFT); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (!(ring->netdev->features & NETIF_F_RXHASH)) 187462306a36Sopenharmony_ci return; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci if ((rx_desc->wb.qword1.status_error_len & rss_mask) == rss_mask) { 187762306a36Sopenharmony_ci hash = le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss); 187862306a36Sopenharmony_ci skb_set_hash(skb, hash, i40e_ptype_to_htype(rx_ptype)); 187962306a36Sopenharmony_ci } 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci/** 188362306a36Sopenharmony_ci * i40e_process_skb_fields - Populate skb header fields from Rx descriptor 188462306a36Sopenharmony_ci * @rx_ring: rx descriptor ring packet is being transacted on 188562306a36Sopenharmony_ci * @rx_desc: pointer to the EOP Rx descriptor 188662306a36Sopenharmony_ci * @skb: pointer to current skb being populated 188762306a36Sopenharmony_ci * 188862306a36Sopenharmony_ci * This function checks the ring, descriptor, and packet information in 188962306a36Sopenharmony_ci * order to populate the hash, checksum, VLAN, protocol, and 189062306a36Sopenharmony_ci * other fields within the skb. 189162306a36Sopenharmony_ci **/ 189262306a36Sopenharmony_civoid i40e_process_skb_fields(struct i40e_ring *rx_ring, 189362306a36Sopenharmony_ci union i40e_rx_desc *rx_desc, struct sk_buff *skb) 189462306a36Sopenharmony_ci{ 189562306a36Sopenharmony_ci u64 qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); 189662306a36Sopenharmony_ci u32 rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> 189762306a36Sopenharmony_ci I40E_RXD_QW1_STATUS_SHIFT; 189862306a36Sopenharmony_ci u32 tsynvalid = rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK; 189962306a36Sopenharmony_ci u32 tsyn = (rx_status & I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >> 190062306a36Sopenharmony_ci I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT; 190162306a36Sopenharmony_ci u8 rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> 190262306a36Sopenharmony_ci I40E_RXD_QW1_PTYPE_SHIFT; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci if (unlikely(tsynvalid)) 190562306a36Sopenharmony_ci i40e_ptp_rx_hwtstamp(rx_ring->vsi->back, skb, tsyn); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci i40e_rx_hash(rx_ring, rx_desc, skb, rx_ptype); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci i40e_rx_checksum(rx_ring->vsi, skb, rx_desc); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci skb_record_rx_queue(skb, rx_ring->queue_index); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (qword & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) { 191462306a36Sopenharmony_ci __le16 vlan_tag = rx_desc->wb.qword0.lo_dword.l2tag1; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 191762306a36Sopenharmony_ci le16_to_cpu(vlan_tag)); 191862306a36Sopenharmony_ci } 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci /* modifies the skb - consumes the enet header */ 192162306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, rx_ring->netdev); 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci/** 192562306a36Sopenharmony_ci * i40e_cleanup_headers - Correct empty headers 192662306a36Sopenharmony_ci * @rx_ring: rx descriptor ring packet is being transacted on 192762306a36Sopenharmony_ci * @skb: pointer to current skb being fixed 192862306a36Sopenharmony_ci * @rx_desc: pointer to the EOP Rx descriptor 192962306a36Sopenharmony_ci * 193062306a36Sopenharmony_ci * In addition if skb is not at least 60 bytes we need to pad it so that 193162306a36Sopenharmony_ci * it is large enough to qualify as a valid Ethernet frame. 193262306a36Sopenharmony_ci * 193362306a36Sopenharmony_ci * Returns true if an error was encountered and skb was freed. 193462306a36Sopenharmony_ci **/ 193562306a36Sopenharmony_cistatic bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb, 193662306a36Sopenharmony_ci union i40e_rx_desc *rx_desc) 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci /* ERR_MASK will only have valid bits if EOP set, and 194062306a36Sopenharmony_ci * what we are doing here is actually checking 194162306a36Sopenharmony_ci * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in 194262306a36Sopenharmony_ci * the error field 194362306a36Sopenharmony_ci */ 194462306a36Sopenharmony_ci if (unlikely(i40e_test_staterr(rx_desc, 194562306a36Sopenharmony_ci BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { 194662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 194762306a36Sopenharmony_ci return true; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* if eth_skb_pad returns an error the skb was freed */ 195162306a36Sopenharmony_ci if (eth_skb_pad(skb)) 195262306a36Sopenharmony_ci return true; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return false; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci/** 195862306a36Sopenharmony_ci * i40e_can_reuse_rx_page - Determine if page can be reused for another Rx 195962306a36Sopenharmony_ci * @rx_buffer: buffer containing the page 196062306a36Sopenharmony_ci * @rx_stats: rx stats structure for the rx ring 196162306a36Sopenharmony_ci * 196262306a36Sopenharmony_ci * If page is reusable, we have a green light for calling i40e_reuse_rx_page, 196362306a36Sopenharmony_ci * which will assign the current buffer to the buffer that next_to_alloc is 196462306a36Sopenharmony_ci * pointing to; otherwise, the DMA mapping needs to be destroyed and 196562306a36Sopenharmony_ci * page freed. 196662306a36Sopenharmony_ci * 196762306a36Sopenharmony_ci * rx_stats will be updated to indicate whether the page was waived 196862306a36Sopenharmony_ci * or busy if it could not be reused. 196962306a36Sopenharmony_ci */ 197062306a36Sopenharmony_cistatic bool i40e_can_reuse_rx_page(struct i40e_rx_buffer *rx_buffer, 197162306a36Sopenharmony_ci struct i40e_rx_queue_stats *rx_stats) 197262306a36Sopenharmony_ci{ 197362306a36Sopenharmony_ci unsigned int pagecnt_bias = rx_buffer->pagecnt_bias; 197462306a36Sopenharmony_ci struct page *page = rx_buffer->page; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci /* Is any reuse possible? */ 197762306a36Sopenharmony_ci if (!dev_page_is_reusable(page)) { 197862306a36Sopenharmony_ci rx_stats->page_waive_count++; 197962306a36Sopenharmony_ci return false; 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci#if (PAGE_SIZE < 8192) 198362306a36Sopenharmony_ci /* if we are only owner of page we can reuse it */ 198462306a36Sopenharmony_ci if (unlikely((rx_buffer->page_count - pagecnt_bias) > 1)) { 198562306a36Sopenharmony_ci rx_stats->page_busy_count++; 198662306a36Sopenharmony_ci return false; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci#else 198962306a36Sopenharmony_ci#define I40E_LAST_OFFSET \ 199062306a36Sopenharmony_ci (SKB_WITH_OVERHEAD(PAGE_SIZE) - I40E_RXBUFFER_2048) 199162306a36Sopenharmony_ci if (rx_buffer->page_offset > I40E_LAST_OFFSET) { 199262306a36Sopenharmony_ci rx_stats->page_busy_count++; 199362306a36Sopenharmony_ci return false; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci#endif 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* If we have drained the page fragment pool we need to update 199862306a36Sopenharmony_ci * the pagecnt_bias and page count so that we fully restock the 199962306a36Sopenharmony_ci * number of references the driver holds. 200062306a36Sopenharmony_ci */ 200162306a36Sopenharmony_ci if (unlikely(pagecnt_bias == 1)) { 200262306a36Sopenharmony_ci page_ref_add(page, USHRT_MAX - 1); 200362306a36Sopenharmony_ci rx_buffer->pagecnt_bias = USHRT_MAX; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci return true; 200762306a36Sopenharmony_ci} 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci/** 201062306a36Sopenharmony_ci * i40e_rx_buffer_flip - adjusted rx_buffer to point to an unused region 201162306a36Sopenharmony_ci * @rx_buffer: Rx buffer to adjust 201262306a36Sopenharmony_ci * @truesize: Size of adjustment 201362306a36Sopenharmony_ci **/ 201462306a36Sopenharmony_cistatic void i40e_rx_buffer_flip(struct i40e_rx_buffer *rx_buffer, 201562306a36Sopenharmony_ci unsigned int truesize) 201662306a36Sopenharmony_ci{ 201762306a36Sopenharmony_ci#if (PAGE_SIZE < 8192) 201862306a36Sopenharmony_ci rx_buffer->page_offset ^= truesize; 201962306a36Sopenharmony_ci#else 202062306a36Sopenharmony_ci rx_buffer->page_offset += truesize; 202162306a36Sopenharmony_ci#endif 202262306a36Sopenharmony_ci} 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci/** 202562306a36Sopenharmony_ci * i40e_get_rx_buffer - Fetch Rx buffer and synchronize data for use 202662306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to transact packets on 202762306a36Sopenharmony_ci * @size: size of buffer to add to skb 202862306a36Sopenharmony_ci * 202962306a36Sopenharmony_ci * This function will pull an Rx buffer from the ring and synchronize it 203062306a36Sopenharmony_ci * for use by the CPU. 203162306a36Sopenharmony_ci */ 203262306a36Sopenharmony_cistatic struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring, 203362306a36Sopenharmony_ci const unsigned int size) 203462306a36Sopenharmony_ci{ 203562306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci rx_buffer = i40e_rx_bi(rx_ring, rx_ring->next_to_process); 203862306a36Sopenharmony_ci rx_buffer->page_count = 203962306a36Sopenharmony_ci#if (PAGE_SIZE < 8192) 204062306a36Sopenharmony_ci page_count(rx_buffer->page); 204162306a36Sopenharmony_ci#else 204262306a36Sopenharmony_ci 0; 204362306a36Sopenharmony_ci#endif 204462306a36Sopenharmony_ci prefetch_page_address(rx_buffer->page); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* we are reusing so sync this buffer for CPU use */ 204762306a36Sopenharmony_ci dma_sync_single_range_for_cpu(rx_ring->dev, 204862306a36Sopenharmony_ci rx_buffer->dma, 204962306a36Sopenharmony_ci rx_buffer->page_offset, 205062306a36Sopenharmony_ci size, 205162306a36Sopenharmony_ci DMA_FROM_DEVICE); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci /* We have pulled a buffer for use, so decrement pagecnt_bias */ 205462306a36Sopenharmony_ci rx_buffer->pagecnt_bias--; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci return rx_buffer; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci/** 206062306a36Sopenharmony_ci * i40e_put_rx_buffer - Clean up used buffer and either recycle or free 206162306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to transact packets on 206262306a36Sopenharmony_ci * @rx_buffer: rx buffer to pull data from 206362306a36Sopenharmony_ci * 206462306a36Sopenharmony_ci * This function will clean up the contents of the rx_buffer. It will 206562306a36Sopenharmony_ci * either recycle the buffer or unmap it and free the associated resources. 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_cistatic void i40e_put_rx_buffer(struct i40e_ring *rx_ring, 206862306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer) 206962306a36Sopenharmony_ci{ 207062306a36Sopenharmony_ci if (i40e_can_reuse_rx_page(rx_buffer, &rx_ring->rx_stats)) { 207162306a36Sopenharmony_ci /* hand second half of page back to the ring */ 207262306a36Sopenharmony_ci i40e_reuse_rx_page(rx_ring, rx_buffer); 207362306a36Sopenharmony_ci } else { 207462306a36Sopenharmony_ci /* we are not reusing the buffer so unmap it */ 207562306a36Sopenharmony_ci dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, 207662306a36Sopenharmony_ci i40e_rx_pg_size(rx_ring), 207762306a36Sopenharmony_ci DMA_FROM_DEVICE, I40E_RX_DMA_ATTR); 207862306a36Sopenharmony_ci __page_frag_cache_drain(rx_buffer->page, 207962306a36Sopenharmony_ci rx_buffer->pagecnt_bias); 208062306a36Sopenharmony_ci /* clear contents of buffer_info */ 208162306a36Sopenharmony_ci rx_buffer->page = NULL; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci/** 208662306a36Sopenharmony_ci * i40e_process_rx_buffs- Processing of buffers post XDP prog or on error 208762306a36Sopenharmony_ci * @rx_ring: Rx descriptor ring to transact packets on 208862306a36Sopenharmony_ci * @xdp_res: Result of the XDP program 208962306a36Sopenharmony_ci * @xdp: xdp_buff pointing to the data 209062306a36Sopenharmony_ci **/ 209162306a36Sopenharmony_cistatic void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res, 209262306a36Sopenharmony_ci struct xdp_buff *xdp) 209362306a36Sopenharmony_ci{ 209462306a36Sopenharmony_ci u32 nr_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; 209562306a36Sopenharmony_ci u32 next = rx_ring->next_to_clean, i = 0; 209662306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci xdp->flags = 0; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci while (1) { 210162306a36Sopenharmony_ci rx_buffer = i40e_rx_bi(rx_ring, next); 210262306a36Sopenharmony_ci if (++next == rx_ring->count) 210362306a36Sopenharmony_ci next = 0; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (!rx_buffer->page) 210662306a36Sopenharmony_ci continue; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (xdp_res != I40E_XDP_CONSUMED) 210962306a36Sopenharmony_ci i40e_rx_buffer_flip(rx_buffer, xdp->frame_sz); 211062306a36Sopenharmony_ci else if (i++ <= nr_frags) 211162306a36Sopenharmony_ci rx_buffer->pagecnt_bias++; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci /* EOP buffer will be put in i40e_clean_rx_irq() */ 211462306a36Sopenharmony_ci if (next == rx_ring->next_to_process) 211562306a36Sopenharmony_ci return; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci i40e_put_rx_buffer(rx_ring, rx_buffer); 211862306a36Sopenharmony_ci } 211962306a36Sopenharmony_ci} 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci/** 212262306a36Sopenharmony_ci * i40e_construct_skb - Allocate skb and populate it 212362306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to transact packets on 212462306a36Sopenharmony_ci * @xdp: xdp_buff pointing to the data 212562306a36Sopenharmony_ci * 212662306a36Sopenharmony_ci * This function allocates an skb. It then populates it with the page 212762306a36Sopenharmony_ci * data from the current receive descriptor, taking care to set up the 212862306a36Sopenharmony_ci * skb correctly. 212962306a36Sopenharmony_ci */ 213062306a36Sopenharmony_cistatic struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, 213162306a36Sopenharmony_ci struct xdp_buff *xdp) 213262306a36Sopenharmony_ci{ 213362306a36Sopenharmony_ci unsigned int size = xdp->data_end - xdp->data; 213462306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer; 213562306a36Sopenharmony_ci struct skb_shared_info *sinfo; 213662306a36Sopenharmony_ci unsigned int headlen; 213762306a36Sopenharmony_ci struct sk_buff *skb; 213862306a36Sopenharmony_ci u32 nr_frags = 0; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci /* prefetch first cache line of first page */ 214162306a36Sopenharmony_ci net_prefetch(xdp->data); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci /* Note, we get here by enabling legacy-rx via: 214462306a36Sopenharmony_ci * 214562306a36Sopenharmony_ci * ethtool --set-priv-flags <dev> legacy-rx on 214662306a36Sopenharmony_ci * 214762306a36Sopenharmony_ci * In this mode, we currently get 0 extra XDP headroom as 214862306a36Sopenharmony_ci * opposed to having legacy-rx off, where we process XDP 214962306a36Sopenharmony_ci * packets going to stack via i40e_build_skb(). The latter 215062306a36Sopenharmony_ci * provides us currently with 192 bytes of headroom. 215162306a36Sopenharmony_ci * 215262306a36Sopenharmony_ci * For i40e_construct_skb() mode it means that the 215362306a36Sopenharmony_ci * xdp->data_meta will always point to xdp->data, since 215462306a36Sopenharmony_ci * the helper cannot expand the head. Should this ever 215562306a36Sopenharmony_ci * change in future for legacy-rx mode on, then lets also 215662306a36Sopenharmony_ci * add xdp->data_meta handling here. 215762306a36Sopenharmony_ci */ 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci /* allocate a skb to store the frags */ 216062306a36Sopenharmony_ci skb = __napi_alloc_skb(&rx_ring->q_vector->napi, 216162306a36Sopenharmony_ci I40E_RX_HDR_SIZE, 216262306a36Sopenharmony_ci GFP_ATOMIC | __GFP_NOWARN); 216362306a36Sopenharmony_ci if (unlikely(!skb)) 216462306a36Sopenharmony_ci return NULL; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci /* Determine available headroom for copy */ 216762306a36Sopenharmony_ci headlen = size; 216862306a36Sopenharmony_ci if (headlen > I40E_RX_HDR_SIZE) 216962306a36Sopenharmony_ci headlen = eth_get_headlen(skb->dev, xdp->data, 217062306a36Sopenharmony_ci I40E_RX_HDR_SIZE); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* align pull length to size of long to optimize memcpy performance */ 217362306a36Sopenharmony_ci memcpy(__skb_put(skb, headlen), xdp->data, 217462306a36Sopenharmony_ci ALIGN(headlen, sizeof(long))); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 217762306a36Sopenharmony_ci sinfo = xdp_get_shared_info_from_buff(xdp); 217862306a36Sopenharmony_ci nr_frags = sinfo->nr_frags; 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci rx_buffer = i40e_rx_bi(rx_ring, rx_ring->next_to_clean); 218162306a36Sopenharmony_ci /* update all of the pointers */ 218262306a36Sopenharmony_ci size -= headlen; 218362306a36Sopenharmony_ci if (size) { 218462306a36Sopenharmony_ci if (unlikely(nr_frags >= MAX_SKB_FRAGS)) { 218562306a36Sopenharmony_ci dev_kfree_skb(skb); 218662306a36Sopenharmony_ci return NULL; 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci skb_add_rx_frag(skb, 0, rx_buffer->page, 218962306a36Sopenharmony_ci rx_buffer->page_offset + headlen, 219062306a36Sopenharmony_ci size, xdp->frame_sz); 219162306a36Sopenharmony_ci /* buffer is used by skb, update page_offset */ 219262306a36Sopenharmony_ci i40e_rx_buffer_flip(rx_buffer, xdp->frame_sz); 219362306a36Sopenharmony_ci } else { 219462306a36Sopenharmony_ci /* buffer is unused, reset bias back to rx_buffer */ 219562306a36Sopenharmony_ci rx_buffer->pagecnt_bias++; 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 219962306a36Sopenharmony_ci struct skb_shared_info *skinfo = skb_shinfo(skb); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci memcpy(&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0], 220262306a36Sopenharmony_ci sizeof(skb_frag_t) * nr_frags); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci xdp_update_skb_shared_info(skb, skinfo->nr_frags + nr_frags, 220562306a36Sopenharmony_ci sinfo->xdp_frags_size, 220662306a36Sopenharmony_ci nr_frags * xdp->frame_sz, 220762306a36Sopenharmony_ci xdp_buff_is_frag_pfmemalloc(xdp)); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci /* First buffer has already been processed, so bump ntc */ 221062306a36Sopenharmony_ci if (++rx_ring->next_to_clean == rx_ring->count) 221162306a36Sopenharmony_ci rx_ring->next_to_clean = 0; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci i40e_process_rx_buffs(rx_ring, I40E_XDP_PASS, xdp); 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci return skb; 221762306a36Sopenharmony_ci} 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci/** 222062306a36Sopenharmony_ci * i40e_build_skb - Build skb around an existing buffer 222162306a36Sopenharmony_ci * @rx_ring: Rx descriptor ring to transact packets on 222262306a36Sopenharmony_ci * @xdp: xdp_buff pointing to the data 222362306a36Sopenharmony_ci * 222462306a36Sopenharmony_ci * This function builds an skb around an existing Rx buffer, taking care 222562306a36Sopenharmony_ci * to set up the skb correctly and avoid any memcpy overhead. 222662306a36Sopenharmony_ci */ 222762306a36Sopenharmony_cistatic struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring, 222862306a36Sopenharmony_ci struct xdp_buff *xdp) 222962306a36Sopenharmony_ci{ 223062306a36Sopenharmony_ci unsigned int metasize = xdp->data - xdp->data_meta; 223162306a36Sopenharmony_ci struct skb_shared_info *sinfo; 223262306a36Sopenharmony_ci struct sk_buff *skb; 223362306a36Sopenharmony_ci u32 nr_frags; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci /* Prefetch first cache line of first page. If xdp->data_meta 223662306a36Sopenharmony_ci * is unused, this points exactly as xdp->data, otherwise we 223762306a36Sopenharmony_ci * likely have a consumer accessing first few bytes of meta 223862306a36Sopenharmony_ci * data, and then actual data. 223962306a36Sopenharmony_ci */ 224062306a36Sopenharmony_ci net_prefetch(xdp->data_meta); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 224362306a36Sopenharmony_ci sinfo = xdp_get_shared_info_from_buff(xdp); 224462306a36Sopenharmony_ci nr_frags = sinfo->nr_frags; 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci /* build an skb around the page buffer */ 224862306a36Sopenharmony_ci skb = napi_build_skb(xdp->data_hard_start, xdp->frame_sz); 224962306a36Sopenharmony_ci if (unlikely(!skb)) 225062306a36Sopenharmony_ci return NULL; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci /* update pointers within the skb to store the data */ 225362306a36Sopenharmony_ci skb_reserve(skb, xdp->data - xdp->data_hard_start); 225462306a36Sopenharmony_ci __skb_put(skb, xdp->data_end - xdp->data); 225562306a36Sopenharmony_ci if (metasize) 225662306a36Sopenharmony_ci skb_metadata_set(skb, metasize); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 225962306a36Sopenharmony_ci xdp_update_skb_shared_info(skb, nr_frags, 226062306a36Sopenharmony_ci sinfo->xdp_frags_size, 226162306a36Sopenharmony_ci nr_frags * xdp->frame_sz, 226262306a36Sopenharmony_ci xdp_buff_is_frag_pfmemalloc(xdp)); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci i40e_process_rx_buffs(rx_ring, I40E_XDP_PASS, xdp); 226562306a36Sopenharmony_ci } else { 226662306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci rx_buffer = i40e_rx_bi(rx_ring, rx_ring->next_to_clean); 226962306a36Sopenharmony_ci /* buffer is used by skb, update page_offset */ 227062306a36Sopenharmony_ci i40e_rx_buffer_flip(rx_buffer, xdp->frame_sz); 227162306a36Sopenharmony_ci } 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci return skb; 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci/** 227762306a36Sopenharmony_ci * i40e_is_non_eop - process handling of non-EOP buffers 227862306a36Sopenharmony_ci * @rx_ring: Rx ring being processed 227962306a36Sopenharmony_ci * @rx_desc: Rx descriptor for current buffer 228062306a36Sopenharmony_ci * 228162306a36Sopenharmony_ci * If the buffer is an EOP buffer, this function exits returning false, 228262306a36Sopenharmony_ci * otherwise return true indicating that this is in fact a non-EOP buffer. 228362306a36Sopenharmony_ci */ 228462306a36Sopenharmony_cibool i40e_is_non_eop(struct i40e_ring *rx_ring, 228562306a36Sopenharmony_ci union i40e_rx_desc *rx_desc) 228662306a36Sopenharmony_ci{ 228762306a36Sopenharmony_ci /* if we are the last buffer then there is nothing else to do */ 228862306a36Sopenharmony_ci#define I40E_RXD_EOF BIT(I40E_RX_DESC_STATUS_EOF_SHIFT) 228962306a36Sopenharmony_ci if (likely(i40e_test_staterr(rx_desc, I40E_RXD_EOF))) 229062306a36Sopenharmony_ci return false; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci rx_ring->rx_stats.non_eop_descs++; 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci return true; 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_cistatic int i40e_xmit_xdp_ring(struct xdp_frame *xdpf, 229862306a36Sopenharmony_ci struct i40e_ring *xdp_ring); 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ciint i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring) 230162306a36Sopenharmony_ci{ 230262306a36Sopenharmony_ci struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci if (unlikely(!xdpf)) 230562306a36Sopenharmony_ci return I40E_XDP_CONSUMED; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci return i40e_xmit_xdp_ring(xdpf, xdp_ring); 230862306a36Sopenharmony_ci} 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci/** 231162306a36Sopenharmony_ci * i40e_run_xdp - run an XDP program 231262306a36Sopenharmony_ci * @rx_ring: Rx ring being processed 231362306a36Sopenharmony_ci * @xdp: XDP buffer containing the frame 231462306a36Sopenharmony_ci * @xdp_prog: XDP program to run 231562306a36Sopenharmony_ci **/ 231662306a36Sopenharmony_cistatic int i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp, struct bpf_prog *xdp_prog) 231762306a36Sopenharmony_ci{ 231862306a36Sopenharmony_ci int err, result = I40E_XDP_PASS; 231962306a36Sopenharmony_ci struct i40e_ring *xdp_ring; 232062306a36Sopenharmony_ci u32 act; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci if (!xdp_prog) 232362306a36Sopenharmony_ci goto xdp_out; 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci prefetchw(xdp->data_hard_start); /* xdp_frame write */ 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci act = bpf_prog_run_xdp(xdp_prog, xdp); 232862306a36Sopenharmony_ci switch (act) { 232962306a36Sopenharmony_ci case XDP_PASS: 233062306a36Sopenharmony_ci break; 233162306a36Sopenharmony_ci case XDP_TX: 233262306a36Sopenharmony_ci xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index]; 233362306a36Sopenharmony_ci result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring); 233462306a36Sopenharmony_ci if (result == I40E_XDP_CONSUMED) 233562306a36Sopenharmony_ci goto out_failure; 233662306a36Sopenharmony_ci break; 233762306a36Sopenharmony_ci case XDP_REDIRECT: 233862306a36Sopenharmony_ci err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); 233962306a36Sopenharmony_ci if (err) 234062306a36Sopenharmony_ci goto out_failure; 234162306a36Sopenharmony_ci result = I40E_XDP_REDIR; 234262306a36Sopenharmony_ci break; 234362306a36Sopenharmony_ci default: 234462306a36Sopenharmony_ci bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, act); 234562306a36Sopenharmony_ci fallthrough; 234662306a36Sopenharmony_ci case XDP_ABORTED: 234762306a36Sopenharmony_ciout_failure: 234862306a36Sopenharmony_ci trace_xdp_exception(rx_ring->netdev, xdp_prog, act); 234962306a36Sopenharmony_ci fallthrough; /* handle aborts by dropping packet */ 235062306a36Sopenharmony_ci case XDP_DROP: 235162306a36Sopenharmony_ci result = I40E_XDP_CONSUMED; 235262306a36Sopenharmony_ci break; 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_cixdp_out: 235562306a36Sopenharmony_ci return result; 235662306a36Sopenharmony_ci} 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci/** 235962306a36Sopenharmony_ci * i40e_xdp_ring_update_tail - Updates the XDP Tx ring tail register 236062306a36Sopenharmony_ci * @xdp_ring: XDP Tx ring 236162306a36Sopenharmony_ci * 236262306a36Sopenharmony_ci * This function updates the XDP Tx ring tail register. 236362306a36Sopenharmony_ci **/ 236462306a36Sopenharmony_civoid i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring) 236562306a36Sopenharmony_ci{ 236662306a36Sopenharmony_ci /* Force memory writes to complete before letting h/w 236762306a36Sopenharmony_ci * know there are new descriptors to fetch. 236862306a36Sopenharmony_ci */ 236962306a36Sopenharmony_ci wmb(); 237062306a36Sopenharmony_ci writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci/** 237462306a36Sopenharmony_ci * i40e_update_rx_stats - Update Rx ring statistics 237562306a36Sopenharmony_ci * @rx_ring: rx descriptor ring 237662306a36Sopenharmony_ci * @total_rx_bytes: number of bytes received 237762306a36Sopenharmony_ci * @total_rx_packets: number of packets received 237862306a36Sopenharmony_ci * 237962306a36Sopenharmony_ci * This function updates the Rx ring statistics. 238062306a36Sopenharmony_ci **/ 238162306a36Sopenharmony_civoid i40e_update_rx_stats(struct i40e_ring *rx_ring, 238262306a36Sopenharmony_ci unsigned int total_rx_bytes, 238362306a36Sopenharmony_ci unsigned int total_rx_packets) 238462306a36Sopenharmony_ci{ 238562306a36Sopenharmony_ci u64_stats_update_begin(&rx_ring->syncp); 238662306a36Sopenharmony_ci rx_ring->stats.packets += total_rx_packets; 238762306a36Sopenharmony_ci rx_ring->stats.bytes += total_rx_bytes; 238862306a36Sopenharmony_ci u64_stats_update_end(&rx_ring->syncp); 238962306a36Sopenharmony_ci rx_ring->q_vector->rx.total_packets += total_rx_packets; 239062306a36Sopenharmony_ci rx_ring->q_vector->rx.total_bytes += total_rx_bytes; 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci/** 239462306a36Sopenharmony_ci * i40e_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map 239562306a36Sopenharmony_ci * @rx_ring: Rx ring 239662306a36Sopenharmony_ci * @xdp_res: Result of the receive batch 239762306a36Sopenharmony_ci * 239862306a36Sopenharmony_ci * This function bumps XDP Tx tail and/or flush redirect map, and 239962306a36Sopenharmony_ci * should be called when a batch of packets has been processed in the 240062306a36Sopenharmony_ci * napi loop. 240162306a36Sopenharmony_ci **/ 240262306a36Sopenharmony_civoid i40e_finalize_xdp_rx(struct i40e_ring *rx_ring, unsigned int xdp_res) 240362306a36Sopenharmony_ci{ 240462306a36Sopenharmony_ci if (xdp_res & I40E_XDP_REDIR) 240562306a36Sopenharmony_ci xdp_do_flush_map(); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci if (xdp_res & I40E_XDP_TX) { 240862306a36Sopenharmony_ci struct i40e_ring *xdp_ring = 240962306a36Sopenharmony_ci rx_ring->vsi->xdp_rings[rx_ring->queue_index]; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci i40e_xdp_ring_update_tail(xdp_ring); 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci} 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci/** 241662306a36Sopenharmony_ci * i40e_inc_ntp: Advance the next_to_process index 241762306a36Sopenharmony_ci * @rx_ring: Rx ring 241862306a36Sopenharmony_ci **/ 241962306a36Sopenharmony_cistatic void i40e_inc_ntp(struct i40e_ring *rx_ring) 242062306a36Sopenharmony_ci{ 242162306a36Sopenharmony_ci u32 ntp = rx_ring->next_to_process + 1; 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci ntp = (ntp < rx_ring->count) ? ntp : 0; 242462306a36Sopenharmony_ci rx_ring->next_to_process = ntp; 242562306a36Sopenharmony_ci prefetch(I40E_RX_DESC(rx_ring, ntp)); 242662306a36Sopenharmony_ci} 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci/** 242962306a36Sopenharmony_ci * i40e_add_xdp_frag: Add a frag to xdp_buff 243062306a36Sopenharmony_ci * @xdp: xdp_buff pointing to the data 243162306a36Sopenharmony_ci * @nr_frags: return number of buffers for the packet 243262306a36Sopenharmony_ci * @rx_buffer: rx_buffer holding data of the current frag 243362306a36Sopenharmony_ci * @size: size of data of current frag 243462306a36Sopenharmony_ci */ 243562306a36Sopenharmony_cistatic int i40e_add_xdp_frag(struct xdp_buff *xdp, u32 *nr_frags, 243662306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer, u32 size) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (!xdp_buff_has_frags(xdp)) { 244162306a36Sopenharmony_ci sinfo->nr_frags = 0; 244262306a36Sopenharmony_ci sinfo->xdp_frags_size = 0; 244362306a36Sopenharmony_ci xdp_buff_set_frags_flag(xdp); 244462306a36Sopenharmony_ci } else if (unlikely(sinfo->nr_frags >= MAX_SKB_FRAGS)) { 244562306a36Sopenharmony_ci /* Overflowing packet: All frags need to be dropped */ 244662306a36Sopenharmony_ci return -ENOMEM; 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buffer->page, 245062306a36Sopenharmony_ci rx_buffer->page_offset, size); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci sinfo->xdp_frags_size += size; 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci if (page_is_pfmemalloc(rx_buffer->page)) 245562306a36Sopenharmony_ci xdp_buff_set_frag_pfmemalloc(xdp); 245662306a36Sopenharmony_ci *nr_frags = sinfo->nr_frags; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci return 0; 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci/** 246262306a36Sopenharmony_ci * i40e_consume_xdp_buff - Consume all the buffers of the packet and update ntc 246362306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to transact packets on 246462306a36Sopenharmony_ci * @xdp: xdp_buff pointing to the data 246562306a36Sopenharmony_ci * @rx_buffer: rx_buffer of eop desc 246662306a36Sopenharmony_ci */ 246762306a36Sopenharmony_cistatic void i40e_consume_xdp_buff(struct i40e_ring *rx_ring, 246862306a36Sopenharmony_ci struct xdp_buff *xdp, 246962306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer) 247062306a36Sopenharmony_ci{ 247162306a36Sopenharmony_ci i40e_process_rx_buffs(rx_ring, I40E_XDP_CONSUMED, xdp); 247262306a36Sopenharmony_ci i40e_put_rx_buffer(rx_ring, rx_buffer); 247362306a36Sopenharmony_ci rx_ring->next_to_clean = rx_ring->next_to_process; 247462306a36Sopenharmony_ci xdp->data = NULL; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/** 247862306a36Sopenharmony_ci * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf 247962306a36Sopenharmony_ci * @rx_ring: rx descriptor ring to transact packets on 248062306a36Sopenharmony_ci * @budget: Total limit on number of packets to process 248162306a36Sopenharmony_ci * @rx_cleaned: Out parameter of the number of packets processed 248262306a36Sopenharmony_ci * 248362306a36Sopenharmony_ci * This function provides a "bounce buffer" approach to Rx interrupt 248462306a36Sopenharmony_ci * processing. The advantage to this is that on systems that have 248562306a36Sopenharmony_ci * expensive overhead for IOMMU access this provides a means of avoiding 248662306a36Sopenharmony_ci * it by maintaining the mapping of the page to the system. 248762306a36Sopenharmony_ci * 248862306a36Sopenharmony_ci * Returns amount of work completed 248962306a36Sopenharmony_ci **/ 249062306a36Sopenharmony_cistatic int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget, 249162306a36Sopenharmony_ci unsigned int *rx_cleaned) 249262306a36Sopenharmony_ci{ 249362306a36Sopenharmony_ci unsigned int total_rx_bytes = 0, total_rx_packets = 0; 249462306a36Sopenharmony_ci u16 cleaned_count = I40E_DESC_UNUSED(rx_ring); 249562306a36Sopenharmony_ci u16 clean_threshold = rx_ring->count / 2; 249662306a36Sopenharmony_ci unsigned int offset = rx_ring->rx_offset; 249762306a36Sopenharmony_ci struct xdp_buff *xdp = &rx_ring->xdp; 249862306a36Sopenharmony_ci unsigned int xdp_xmit = 0; 249962306a36Sopenharmony_ci struct bpf_prog *xdp_prog; 250062306a36Sopenharmony_ci bool failure = false; 250162306a36Sopenharmony_ci int xdp_res = 0; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci xdp_prog = READ_ONCE(rx_ring->xdp_prog); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci while (likely(total_rx_packets < (unsigned int)budget)) { 250662306a36Sopenharmony_ci u16 ntp = rx_ring->next_to_process; 250762306a36Sopenharmony_ci struct i40e_rx_buffer *rx_buffer; 250862306a36Sopenharmony_ci union i40e_rx_desc *rx_desc; 250962306a36Sopenharmony_ci struct sk_buff *skb; 251062306a36Sopenharmony_ci unsigned int size; 251162306a36Sopenharmony_ci u32 nfrags = 0; 251262306a36Sopenharmony_ci bool neop; 251362306a36Sopenharmony_ci u64 qword; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci /* return some buffers to hardware, one at a time is too slow */ 251662306a36Sopenharmony_ci if (cleaned_count >= clean_threshold) { 251762306a36Sopenharmony_ci failure = failure || 251862306a36Sopenharmony_ci i40e_alloc_rx_buffers(rx_ring, cleaned_count); 251962306a36Sopenharmony_ci cleaned_count = 0; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, ntp); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci /* status_error_len will always be zero for unused descriptors 252562306a36Sopenharmony_ci * because it's cleared in cleanup, and overlaps with hdr_addr 252662306a36Sopenharmony_ci * which is always zero because packet split isn't used, if the 252762306a36Sopenharmony_ci * hardware wrote DD then the length will be non-zero 252862306a36Sopenharmony_ci */ 252962306a36Sopenharmony_ci qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci /* This memory barrier is needed to keep us from reading 253262306a36Sopenharmony_ci * any other fields out of the rx_desc until we have 253362306a36Sopenharmony_ci * verified the descriptor has been written back. 253462306a36Sopenharmony_ci */ 253562306a36Sopenharmony_ci dma_rmb(); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (i40e_rx_is_programming_status(qword)) { 253862306a36Sopenharmony_ci i40e_clean_programming_status(rx_ring, 253962306a36Sopenharmony_ci rx_desc->raw.qword[0], 254062306a36Sopenharmony_ci qword); 254162306a36Sopenharmony_ci rx_buffer = i40e_rx_bi(rx_ring, ntp); 254262306a36Sopenharmony_ci i40e_inc_ntp(rx_ring); 254362306a36Sopenharmony_ci i40e_reuse_rx_page(rx_ring, rx_buffer); 254462306a36Sopenharmony_ci /* Update ntc and bump cleaned count if not in the 254562306a36Sopenharmony_ci * middle of mb packet. 254662306a36Sopenharmony_ci */ 254762306a36Sopenharmony_ci if (rx_ring->next_to_clean == ntp) { 254862306a36Sopenharmony_ci rx_ring->next_to_clean = 254962306a36Sopenharmony_ci rx_ring->next_to_process; 255062306a36Sopenharmony_ci cleaned_count++; 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci continue; 255362306a36Sopenharmony_ci } 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> 255662306a36Sopenharmony_ci I40E_RXD_QW1_LENGTH_PBUF_SHIFT; 255762306a36Sopenharmony_ci if (!size) 255862306a36Sopenharmony_ci break; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci i40e_trace(clean_rx_irq, rx_ring, rx_desc, xdp); 256162306a36Sopenharmony_ci /* retrieve a buffer from the ring */ 256262306a36Sopenharmony_ci rx_buffer = i40e_get_rx_buffer(rx_ring, size); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci neop = i40e_is_non_eop(rx_ring, rx_desc); 256562306a36Sopenharmony_ci i40e_inc_ntp(rx_ring); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci if (!xdp->data) { 256862306a36Sopenharmony_ci unsigned char *hard_start; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci hard_start = page_address(rx_buffer->page) + 257162306a36Sopenharmony_ci rx_buffer->page_offset - offset; 257262306a36Sopenharmony_ci xdp_prepare_buff(xdp, hard_start, offset, size, true); 257362306a36Sopenharmony_ci#if (PAGE_SIZE > 4096) 257462306a36Sopenharmony_ci /* At larger PAGE_SIZE, frame_sz depend on len size */ 257562306a36Sopenharmony_ci xdp->frame_sz = i40e_rx_frame_truesize(rx_ring, size); 257662306a36Sopenharmony_ci#endif 257762306a36Sopenharmony_ci } else if (i40e_add_xdp_frag(xdp, &nfrags, rx_buffer, size) && 257862306a36Sopenharmony_ci !neop) { 257962306a36Sopenharmony_ci /* Overflowing packet: Drop all frags on EOP */ 258062306a36Sopenharmony_ci i40e_consume_xdp_buff(rx_ring, xdp, rx_buffer); 258162306a36Sopenharmony_ci break; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci if (neop) 258562306a36Sopenharmony_ci continue; 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci xdp_res = i40e_run_xdp(rx_ring, xdp, xdp_prog); 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci if (xdp_res) { 259062306a36Sopenharmony_ci xdp_xmit |= xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR); 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 259362306a36Sopenharmony_ci i40e_process_rx_buffs(rx_ring, xdp_res, xdp); 259462306a36Sopenharmony_ci size = xdp_get_buff_len(xdp); 259562306a36Sopenharmony_ci } else if (xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR)) { 259662306a36Sopenharmony_ci i40e_rx_buffer_flip(rx_buffer, xdp->frame_sz); 259762306a36Sopenharmony_ci } else { 259862306a36Sopenharmony_ci rx_buffer->pagecnt_bias++; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci total_rx_bytes += size; 260162306a36Sopenharmony_ci } else { 260262306a36Sopenharmony_ci if (ring_uses_build_skb(rx_ring)) 260362306a36Sopenharmony_ci skb = i40e_build_skb(rx_ring, xdp); 260462306a36Sopenharmony_ci else 260562306a36Sopenharmony_ci skb = i40e_construct_skb(rx_ring, xdp); 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci /* drop if we failed to retrieve a buffer */ 260862306a36Sopenharmony_ci if (!skb) { 260962306a36Sopenharmony_ci rx_ring->rx_stats.alloc_buff_failed++; 261062306a36Sopenharmony_ci i40e_consume_xdp_buff(rx_ring, xdp, rx_buffer); 261162306a36Sopenharmony_ci break; 261262306a36Sopenharmony_ci } 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci if (i40e_cleanup_headers(rx_ring, skb, rx_desc)) 261562306a36Sopenharmony_ci goto process_next; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci /* probably a little skewed due to removing CRC */ 261862306a36Sopenharmony_ci total_rx_bytes += skb->len; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci /* populate checksum, VLAN, and protocol */ 262162306a36Sopenharmony_ci i40e_process_skb_fields(rx_ring, rx_desc, skb); 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci i40e_trace(clean_rx_irq_rx, rx_ring, rx_desc, xdp); 262462306a36Sopenharmony_ci napi_gro_receive(&rx_ring->q_vector->napi, skb); 262562306a36Sopenharmony_ci } 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci /* update budget accounting */ 262862306a36Sopenharmony_ci total_rx_packets++; 262962306a36Sopenharmony_ciprocess_next: 263062306a36Sopenharmony_ci cleaned_count += nfrags + 1; 263162306a36Sopenharmony_ci i40e_put_rx_buffer(rx_ring, rx_buffer); 263262306a36Sopenharmony_ci rx_ring->next_to_clean = rx_ring->next_to_process; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci xdp->data = NULL; 263562306a36Sopenharmony_ci } 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci i40e_finalize_xdp_rx(rx_ring, xdp_xmit); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci *rx_cleaned = total_rx_packets; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci /* guarantee a trip back through this routine if there was a failure */ 264462306a36Sopenharmony_ci return failure ? budget : (int)total_rx_packets; 264562306a36Sopenharmony_ci} 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_cistatic inline u32 i40e_buildreg_itr(const int type, u16 itr) 264862306a36Sopenharmony_ci{ 264962306a36Sopenharmony_ci u32 val; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci /* We don't bother with setting the CLEARPBA bit as the data sheet 265262306a36Sopenharmony_ci * points out doing so is "meaningless since it was already 265362306a36Sopenharmony_ci * auto-cleared". The auto-clearing happens when the interrupt is 265462306a36Sopenharmony_ci * asserted. 265562306a36Sopenharmony_ci * 265662306a36Sopenharmony_ci * Hardware errata 28 for also indicates that writing to a 265762306a36Sopenharmony_ci * xxINT_DYN_CTLx CSR with INTENA_MSK (bit 31) set to 0 will clear 265862306a36Sopenharmony_ci * an event in the PBA anyway so we need to rely on the automask 265962306a36Sopenharmony_ci * to hold pending events for us until the interrupt is re-enabled 266062306a36Sopenharmony_ci * 266162306a36Sopenharmony_ci * The itr value is reported in microseconds, and the register 266262306a36Sopenharmony_ci * value is recorded in 2 microsecond units. For this reason we 266362306a36Sopenharmony_ci * only need to shift by the interval shift - 1 instead of the 266462306a36Sopenharmony_ci * full value. 266562306a36Sopenharmony_ci */ 266662306a36Sopenharmony_ci itr &= I40E_ITR_MASK; 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci val = I40E_PFINT_DYN_CTLN_INTENA_MASK | 266962306a36Sopenharmony_ci (type << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) | 267062306a36Sopenharmony_ci (itr << (I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT - 1)); 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci return val; 267362306a36Sopenharmony_ci} 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci/* a small macro to shorten up some long lines */ 267662306a36Sopenharmony_ci#define INTREG I40E_PFINT_DYN_CTLN 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci/* The act of updating the ITR will cause it to immediately trigger. In order 267962306a36Sopenharmony_ci * to prevent this from throwing off adaptive update statistics we defer the 268062306a36Sopenharmony_ci * update so that it can only happen so often. So after either Tx or Rx are 268162306a36Sopenharmony_ci * updated we make the adaptive scheme wait until either the ITR completely 268262306a36Sopenharmony_ci * expires via the next_update expiration or we have been through at least 268362306a36Sopenharmony_ci * 3 interrupts. 268462306a36Sopenharmony_ci */ 268562306a36Sopenharmony_ci#define ITR_COUNTDOWN_START 3 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci/** 268862306a36Sopenharmony_ci * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt 268962306a36Sopenharmony_ci * @vsi: the VSI we care about 269062306a36Sopenharmony_ci * @q_vector: q_vector for which itr is being updated and interrupt enabled 269162306a36Sopenharmony_ci * 269262306a36Sopenharmony_ci **/ 269362306a36Sopenharmony_cistatic inline void i40e_update_enable_itr(struct i40e_vsi *vsi, 269462306a36Sopenharmony_ci struct i40e_q_vector *q_vector) 269562306a36Sopenharmony_ci{ 269662306a36Sopenharmony_ci struct i40e_hw *hw = &vsi->back->hw; 269762306a36Sopenharmony_ci u32 intval; 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci /* If we don't have MSIX, then we only need to re-enable icr0 */ 270062306a36Sopenharmony_ci if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED)) { 270162306a36Sopenharmony_ci i40e_irq_dynamic_enable_icr0(vsi->back); 270262306a36Sopenharmony_ci return; 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci /* These will do nothing if dynamic updates are not enabled */ 270662306a36Sopenharmony_ci i40e_update_itr(q_vector, &q_vector->tx); 270762306a36Sopenharmony_ci i40e_update_itr(q_vector, &q_vector->rx); 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci /* This block of logic allows us to get away with only updating 271062306a36Sopenharmony_ci * one ITR value with each interrupt. The idea is to perform a 271162306a36Sopenharmony_ci * pseudo-lazy update with the following criteria. 271262306a36Sopenharmony_ci * 271362306a36Sopenharmony_ci * 1. Rx is given higher priority than Tx if both are in same state 271462306a36Sopenharmony_ci * 2. If we must reduce an ITR that is given highest priority. 271562306a36Sopenharmony_ci * 3. We then give priority to increasing ITR based on amount. 271662306a36Sopenharmony_ci */ 271762306a36Sopenharmony_ci if (q_vector->rx.target_itr < q_vector->rx.current_itr) { 271862306a36Sopenharmony_ci /* Rx ITR needs to be reduced, this is highest priority */ 271962306a36Sopenharmony_ci intval = i40e_buildreg_itr(I40E_RX_ITR, 272062306a36Sopenharmony_ci q_vector->rx.target_itr); 272162306a36Sopenharmony_ci q_vector->rx.current_itr = q_vector->rx.target_itr; 272262306a36Sopenharmony_ci q_vector->itr_countdown = ITR_COUNTDOWN_START; 272362306a36Sopenharmony_ci } else if ((q_vector->tx.target_itr < q_vector->tx.current_itr) || 272462306a36Sopenharmony_ci ((q_vector->rx.target_itr - q_vector->rx.current_itr) < 272562306a36Sopenharmony_ci (q_vector->tx.target_itr - q_vector->tx.current_itr))) { 272662306a36Sopenharmony_ci /* Tx ITR needs to be reduced, this is second priority 272762306a36Sopenharmony_ci * Tx ITR needs to be increased more than Rx, fourth priority 272862306a36Sopenharmony_ci */ 272962306a36Sopenharmony_ci intval = i40e_buildreg_itr(I40E_TX_ITR, 273062306a36Sopenharmony_ci q_vector->tx.target_itr); 273162306a36Sopenharmony_ci q_vector->tx.current_itr = q_vector->tx.target_itr; 273262306a36Sopenharmony_ci q_vector->itr_countdown = ITR_COUNTDOWN_START; 273362306a36Sopenharmony_ci } else if (q_vector->rx.current_itr != q_vector->rx.target_itr) { 273462306a36Sopenharmony_ci /* Rx ITR needs to be increased, third priority */ 273562306a36Sopenharmony_ci intval = i40e_buildreg_itr(I40E_RX_ITR, 273662306a36Sopenharmony_ci q_vector->rx.target_itr); 273762306a36Sopenharmony_ci q_vector->rx.current_itr = q_vector->rx.target_itr; 273862306a36Sopenharmony_ci q_vector->itr_countdown = ITR_COUNTDOWN_START; 273962306a36Sopenharmony_ci } else { 274062306a36Sopenharmony_ci /* No ITR update, lowest priority */ 274162306a36Sopenharmony_ci intval = i40e_buildreg_itr(I40E_ITR_NONE, 0); 274262306a36Sopenharmony_ci if (q_vector->itr_countdown) 274362306a36Sopenharmony_ci q_vector->itr_countdown--; 274462306a36Sopenharmony_ci } 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci if (!test_bit(__I40E_VSI_DOWN, vsi->state)) 274762306a36Sopenharmony_ci wr32(hw, INTREG(q_vector->reg_idx), intval); 274862306a36Sopenharmony_ci} 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci/** 275162306a36Sopenharmony_ci * i40e_napi_poll - NAPI polling Rx/Tx cleanup routine 275262306a36Sopenharmony_ci * @napi: napi struct with our devices info in it 275362306a36Sopenharmony_ci * @budget: amount of work driver is allowed to do this pass, in packets 275462306a36Sopenharmony_ci * 275562306a36Sopenharmony_ci * This function will clean all queues associated with a q_vector. 275662306a36Sopenharmony_ci * 275762306a36Sopenharmony_ci * Returns the amount of work done 275862306a36Sopenharmony_ci **/ 275962306a36Sopenharmony_ciint i40e_napi_poll(struct napi_struct *napi, int budget) 276062306a36Sopenharmony_ci{ 276162306a36Sopenharmony_ci struct i40e_q_vector *q_vector = 276262306a36Sopenharmony_ci container_of(napi, struct i40e_q_vector, napi); 276362306a36Sopenharmony_ci struct i40e_vsi *vsi = q_vector->vsi; 276462306a36Sopenharmony_ci struct i40e_ring *ring; 276562306a36Sopenharmony_ci bool tx_clean_complete = true; 276662306a36Sopenharmony_ci bool rx_clean_complete = true; 276762306a36Sopenharmony_ci unsigned int tx_cleaned = 0; 276862306a36Sopenharmony_ci unsigned int rx_cleaned = 0; 276962306a36Sopenharmony_ci bool clean_complete = true; 277062306a36Sopenharmony_ci bool arm_wb = false; 277162306a36Sopenharmony_ci int budget_per_ring; 277262306a36Sopenharmony_ci int work_done = 0; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci if (test_bit(__I40E_VSI_DOWN, vsi->state)) { 277562306a36Sopenharmony_ci napi_complete(napi); 277662306a36Sopenharmony_ci return 0; 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci /* Since the actual Tx work is minimal, we can give the Tx a larger 278062306a36Sopenharmony_ci * budget and be more aggressive about cleaning up the Tx descriptors. 278162306a36Sopenharmony_ci */ 278262306a36Sopenharmony_ci i40e_for_each_ring(ring, q_vector->tx) { 278362306a36Sopenharmony_ci bool wd = ring->xsk_pool ? 278462306a36Sopenharmony_ci i40e_clean_xdp_tx_irq(vsi, ring) : 278562306a36Sopenharmony_ci i40e_clean_tx_irq(vsi, ring, budget, &tx_cleaned); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci if (!wd) { 278862306a36Sopenharmony_ci clean_complete = tx_clean_complete = false; 278962306a36Sopenharmony_ci continue; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci arm_wb |= ring->arm_wb; 279262306a36Sopenharmony_ci ring->arm_wb = false; 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci /* Handle case where we are called by netpoll with a budget of 0 */ 279662306a36Sopenharmony_ci if (budget <= 0) 279762306a36Sopenharmony_ci goto tx_only; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci /* normally we have 1 Rx ring per q_vector */ 280062306a36Sopenharmony_ci if (unlikely(q_vector->num_ringpairs > 1)) 280162306a36Sopenharmony_ci /* We attempt to distribute budget to each Rx queue fairly, but 280262306a36Sopenharmony_ci * don't allow the budget to go below 1 because that would exit 280362306a36Sopenharmony_ci * polling early. 280462306a36Sopenharmony_ci */ 280562306a36Sopenharmony_ci budget_per_ring = max_t(int, budget / q_vector->num_ringpairs, 1); 280662306a36Sopenharmony_ci else 280762306a36Sopenharmony_ci /* Max of 1 Rx ring in this q_vector so give it the budget */ 280862306a36Sopenharmony_ci budget_per_ring = budget; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci i40e_for_each_ring(ring, q_vector->rx) { 281162306a36Sopenharmony_ci int cleaned = ring->xsk_pool ? 281262306a36Sopenharmony_ci i40e_clean_rx_irq_zc(ring, budget_per_ring) : 281362306a36Sopenharmony_ci i40e_clean_rx_irq(ring, budget_per_ring, &rx_cleaned); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci work_done += cleaned; 281662306a36Sopenharmony_ci /* if we clean as many as budgeted, we must not be done */ 281762306a36Sopenharmony_ci if (cleaned >= budget_per_ring) 281862306a36Sopenharmony_ci clean_complete = rx_clean_complete = false; 281962306a36Sopenharmony_ci } 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci if (!i40e_enabled_xdp_vsi(vsi)) 282262306a36Sopenharmony_ci trace_i40e_napi_poll(napi, q_vector, budget, budget_per_ring, rx_cleaned, 282362306a36Sopenharmony_ci tx_cleaned, rx_clean_complete, tx_clean_complete); 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci /* If work not completed, return budget and polling will return */ 282662306a36Sopenharmony_ci if (!clean_complete) { 282762306a36Sopenharmony_ci int cpu_id = smp_processor_id(); 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci /* It is possible that the interrupt affinity has changed but, 283062306a36Sopenharmony_ci * if the cpu is pegged at 100%, polling will never exit while 283162306a36Sopenharmony_ci * traffic continues and the interrupt will be stuck on this 283262306a36Sopenharmony_ci * cpu. We check to make sure affinity is correct before we 283362306a36Sopenharmony_ci * continue to poll, otherwise we must stop polling so the 283462306a36Sopenharmony_ci * interrupt can move to the correct cpu. 283562306a36Sopenharmony_ci */ 283662306a36Sopenharmony_ci if (!cpumask_test_cpu(cpu_id, &q_vector->affinity_mask)) { 283762306a36Sopenharmony_ci /* Tell napi that we are done polling */ 283862306a36Sopenharmony_ci napi_complete_done(napi, work_done); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci /* Force an interrupt */ 284162306a36Sopenharmony_ci i40e_force_wb(vsi, q_vector); 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci /* Return budget-1 so that polling stops */ 284462306a36Sopenharmony_ci return budget - 1; 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_citx_only: 284762306a36Sopenharmony_ci if (arm_wb) { 284862306a36Sopenharmony_ci q_vector->tx.ring[0].tx_stats.tx_force_wb++; 284962306a36Sopenharmony_ci i40e_enable_wb_on_itr(vsi, q_vector); 285062306a36Sopenharmony_ci } 285162306a36Sopenharmony_ci return budget; 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci if (q_vector->tx.ring[0].flags & I40E_TXR_FLAGS_WB_ON_ITR) 285562306a36Sopenharmony_ci q_vector->arm_wb_state = false; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci /* Exit the polling mode, but don't re-enable interrupts if stack might 285862306a36Sopenharmony_ci * poll us due to busy-polling 285962306a36Sopenharmony_ci */ 286062306a36Sopenharmony_ci if (likely(napi_complete_done(napi, work_done))) 286162306a36Sopenharmony_ci i40e_update_enable_itr(vsi, q_vector); 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci return min(work_done, budget - 1); 286462306a36Sopenharmony_ci} 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci/** 286762306a36Sopenharmony_ci * i40e_atr - Add a Flow Director ATR filter 286862306a36Sopenharmony_ci * @tx_ring: ring to add programming descriptor to 286962306a36Sopenharmony_ci * @skb: send buffer 287062306a36Sopenharmony_ci * @tx_flags: send tx flags 287162306a36Sopenharmony_ci **/ 287262306a36Sopenharmony_cistatic void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, 287362306a36Sopenharmony_ci u32 tx_flags) 287462306a36Sopenharmony_ci{ 287562306a36Sopenharmony_ci struct i40e_filter_program_desc *fdir_desc; 287662306a36Sopenharmony_ci struct i40e_pf *pf = tx_ring->vsi->back; 287762306a36Sopenharmony_ci union { 287862306a36Sopenharmony_ci unsigned char *network; 287962306a36Sopenharmony_ci struct iphdr *ipv4; 288062306a36Sopenharmony_ci struct ipv6hdr *ipv6; 288162306a36Sopenharmony_ci } hdr; 288262306a36Sopenharmony_ci struct tcphdr *th; 288362306a36Sopenharmony_ci unsigned int hlen; 288462306a36Sopenharmony_ci u32 flex_ptype, dtype_cmd; 288562306a36Sopenharmony_ci int l4_proto; 288662306a36Sopenharmony_ci u16 i; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci /* make sure ATR is enabled */ 288962306a36Sopenharmony_ci if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) 289062306a36Sopenharmony_ci return; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci if (test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) 289362306a36Sopenharmony_ci return; 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci /* if sampling is disabled do nothing */ 289662306a36Sopenharmony_ci if (!tx_ring->atr_sample_rate) 289762306a36Sopenharmony_ci return; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci /* Currently only IPv4/IPv6 with TCP is supported */ 290062306a36Sopenharmony_ci if (!(tx_flags & (I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6))) 290162306a36Sopenharmony_ci return; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci /* snag network header to get L4 type and address */ 290462306a36Sopenharmony_ci hdr.network = (tx_flags & I40E_TX_FLAGS_UDP_TUNNEL) ? 290562306a36Sopenharmony_ci skb_inner_network_header(skb) : skb_network_header(skb); 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci /* Note: tx_flags gets modified to reflect inner protocols in 290862306a36Sopenharmony_ci * tx_enable_csum function if encap is enabled. 290962306a36Sopenharmony_ci */ 291062306a36Sopenharmony_ci if (tx_flags & I40E_TX_FLAGS_IPV4) { 291162306a36Sopenharmony_ci /* access ihl as u8 to avoid unaligned access on ia64 */ 291262306a36Sopenharmony_ci hlen = (hdr.network[0] & 0x0F) << 2; 291362306a36Sopenharmony_ci l4_proto = hdr.ipv4->protocol; 291462306a36Sopenharmony_ci } else { 291562306a36Sopenharmony_ci /* find the start of the innermost ipv6 header */ 291662306a36Sopenharmony_ci unsigned int inner_hlen = hdr.network - skb->data; 291762306a36Sopenharmony_ci unsigned int h_offset = inner_hlen; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci /* this function updates h_offset to the end of the header */ 292062306a36Sopenharmony_ci l4_proto = 292162306a36Sopenharmony_ci ipv6_find_hdr(skb, &h_offset, IPPROTO_TCP, NULL, NULL); 292262306a36Sopenharmony_ci /* hlen will contain our best estimate of the tcp header */ 292362306a36Sopenharmony_ci hlen = h_offset - inner_hlen; 292462306a36Sopenharmony_ci } 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci if (l4_proto != IPPROTO_TCP) 292762306a36Sopenharmony_ci return; 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci th = (struct tcphdr *)(hdr.network + hlen); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci /* Due to lack of space, no more new filters can be programmed */ 293262306a36Sopenharmony_ci if (th->syn && test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) 293362306a36Sopenharmony_ci return; 293462306a36Sopenharmony_ci if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) { 293562306a36Sopenharmony_ci /* HW ATR eviction will take care of removing filters on FIN 293662306a36Sopenharmony_ci * and RST packets. 293762306a36Sopenharmony_ci */ 293862306a36Sopenharmony_ci if (th->fin || th->rst) 293962306a36Sopenharmony_ci return; 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci tx_ring->atr_count++; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci /* sample on all syn/fin/rst packets or once every atr sample rate */ 294562306a36Sopenharmony_ci if (!th->fin && 294662306a36Sopenharmony_ci !th->syn && 294762306a36Sopenharmony_ci !th->rst && 294862306a36Sopenharmony_ci (tx_ring->atr_count < tx_ring->atr_sample_rate)) 294962306a36Sopenharmony_ci return; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci tx_ring->atr_count = 0; 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* grab the next descriptor */ 295462306a36Sopenharmony_ci i = tx_ring->next_to_use; 295562306a36Sopenharmony_ci fdir_desc = I40E_TX_FDIRDESC(tx_ring, i); 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci i++; 295862306a36Sopenharmony_ci tx_ring->next_to_use = (i < tx_ring->count) ? i : 0; 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ci flex_ptype = (tx_ring->queue_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) & 296162306a36Sopenharmony_ci I40E_TXD_FLTR_QW0_QINDEX_MASK; 296262306a36Sopenharmony_ci flex_ptype |= (tx_flags & I40E_TX_FLAGS_IPV4) ? 296362306a36Sopenharmony_ci (I40E_FILTER_PCTYPE_NONF_IPV4_TCP << 296462306a36Sopenharmony_ci I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) : 296562306a36Sopenharmony_ci (I40E_FILTER_PCTYPE_NONF_IPV6_TCP << 296662306a36Sopenharmony_ci I40E_TXD_FLTR_QW0_PCTYPE_SHIFT); 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci flex_ptype |= tx_ring->vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT; 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci dtype_cmd |= (th->fin || th->rst) ? 297362306a36Sopenharmony_ci (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE << 297462306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_PCMD_SHIFT) : 297562306a36Sopenharmony_ci (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE << 297662306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_PCMD_SHIFT); 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci dtype_cmd |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX << 297962306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_DEST_SHIFT; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci dtype_cmd |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID << 298262306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK; 298562306a36Sopenharmony_ci if (!(tx_flags & I40E_TX_FLAGS_UDP_TUNNEL)) 298662306a36Sopenharmony_ci dtype_cmd |= 298762306a36Sopenharmony_ci ((u32)I40E_FD_ATR_STAT_IDX(pf->hw.pf_id) << 298862306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & 298962306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_CNTINDEX_MASK; 299062306a36Sopenharmony_ci else 299162306a36Sopenharmony_ci dtype_cmd |= 299262306a36Sopenharmony_ci ((u32)I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id) << 299362306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & 299462306a36Sopenharmony_ci I40E_TXD_FLTR_QW1_CNTINDEX_MASK; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) 299762306a36Sopenharmony_ci dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); 300062306a36Sopenharmony_ci fdir_desc->rsvd = cpu_to_le32(0); 300162306a36Sopenharmony_ci fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd); 300262306a36Sopenharmony_ci fdir_desc->fd_id = cpu_to_le32(0); 300362306a36Sopenharmony_ci} 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci/** 300662306a36Sopenharmony_ci * i40e_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW 300762306a36Sopenharmony_ci * @skb: send buffer 300862306a36Sopenharmony_ci * @tx_ring: ring to send buffer on 300962306a36Sopenharmony_ci * @flags: the tx flags to be set 301062306a36Sopenharmony_ci * 301162306a36Sopenharmony_ci * Checks the skb and set up correspondingly several generic transmit flags 301262306a36Sopenharmony_ci * related to VLAN tagging for the HW, such as VLAN, DCB, etc. 301362306a36Sopenharmony_ci * 301462306a36Sopenharmony_ci * Returns error code indicate the frame should be dropped upon error and the 301562306a36Sopenharmony_ci * otherwise returns 0 to indicate the flags has been set properly. 301662306a36Sopenharmony_ci **/ 301762306a36Sopenharmony_cistatic inline int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, 301862306a36Sopenharmony_ci struct i40e_ring *tx_ring, 301962306a36Sopenharmony_ci u32 *flags) 302062306a36Sopenharmony_ci{ 302162306a36Sopenharmony_ci __be16 protocol = skb->protocol; 302262306a36Sopenharmony_ci u32 tx_flags = 0; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci if (protocol == htons(ETH_P_8021Q) && 302562306a36Sopenharmony_ci !(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) { 302662306a36Sopenharmony_ci /* When HW VLAN acceleration is turned off by the user the 302762306a36Sopenharmony_ci * stack sets the protocol to 8021q so that the driver 302862306a36Sopenharmony_ci * can take any steps required to support the SW only 302962306a36Sopenharmony_ci * VLAN handling. In our case the driver doesn't need 303062306a36Sopenharmony_ci * to take any further steps so just set the protocol 303162306a36Sopenharmony_ci * to the encapsulated ethertype. 303262306a36Sopenharmony_ci */ 303362306a36Sopenharmony_ci skb->protocol = vlan_get_protocol(skb); 303462306a36Sopenharmony_ci goto out; 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci /* if we have a HW VLAN tag being added, default to the HW one */ 303862306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 303962306a36Sopenharmony_ci tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; 304062306a36Sopenharmony_ci tx_flags |= I40E_TX_FLAGS_HW_VLAN; 304162306a36Sopenharmony_ci /* else if it is a SW VLAN, check the next protocol and store the tag */ 304262306a36Sopenharmony_ci } else if (protocol == htons(ETH_P_8021Q)) { 304362306a36Sopenharmony_ci struct vlan_hdr *vhdr, _vhdr; 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr); 304662306a36Sopenharmony_ci if (!vhdr) 304762306a36Sopenharmony_ci return -EINVAL; 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci protocol = vhdr->h_vlan_encapsulated_proto; 305062306a36Sopenharmony_ci tx_flags |= ntohs(vhdr->h_vlan_TCI) << I40E_TX_FLAGS_VLAN_SHIFT; 305162306a36Sopenharmony_ci tx_flags |= I40E_TX_FLAGS_SW_VLAN; 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci if (!(tx_ring->vsi->back->flags & I40E_FLAG_DCB_ENABLED)) 305562306a36Sopenharmony_ci goto out; 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci /* Insert 802.1p priority into VLAN header */ 305862306a36Sopenharmony_ci if ((tx_flags & (I40E_TX_FLAGS_HW_VLAN | I40E_TX_FLAGS_SW_VLAN)) || 305962306a36Sopenharmony_ci (skb->priority != TC_PRIO_CONTROL)) { 306062306a36Sopenharmony_ci tx_flags &= ~I40E_TX_FLAGS_VLAN_PRIO_MASK; 306162306a36Sopenharmony_ci tx_flags |= (skb->priority & 0x7) << 306262306a36Sopenharmony_ci I40E_TX_FLAGS_VLAN_PRIO_SHIFT; 306362306a36Sopenharmony_ci if (tx_flags & I40E_TX_FLAGS_SW_VLAN) { 306462306a36Sopenharmony_ci struct vlan_ethhdr *vhdr; 306562306a36Sopenharmony_ci int rc; 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci rc = skb_cow_head(skb, 0); 306862306a36Sopenharmony_ci if (rc < 0) 306962306a36Sopenharmony_ci return rc; 307062306a36Sopenharmony_ci vhdr = skb_vlan_eth_hdr(skb); 307162306a36Sopenharmony_ci vhdr->h_vlan_TCI = htons(tx_flags >> 307262306a36Sopenharmony_ci I40E_TX_FLAGS_VLAN_SHIFT); 307362306a36Sopenharmony_ci } else { 307462306a36Sopenharmony_ci tx_flags |= I40E_TX_FLAGS_HW_VLAN; 307562306a36Sopenharmony_ci } 307662306a36Sopenharmony_ci } 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ciout: 307962306a36Sopenharmony_ci *flags = tx_flags; 308062306a36Sopenharmony_ci return 0; 308162306a36Sopenharmony_ci} 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci/** 308462306a36Sopenharmony_ci * i40e_tso - set up the tso context descriptor 308562306a36Sopenharmony_ci * @first: pointer to first Tx buffer for xmit 308662306a36Sopenharmony_ci * @hdr_len: ptr to the size of the packet header 308762306a36Sopenharmony_ci * @cd_type_cmd_tso_mss: Quad Word 1 308862306a36Sopenharmony_ci * 308962306a36Sopenharmony_ci * Returns 0 if no TSO can happen, 1 if tso is going, or error 309062306a36Sopenharmony_ci **/ 309162306a36Sopenharmony_cistatic int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, 309262306a36Sopenharmony_ci u64 *cd_type_cmd_tso_mss) 309362306a36Sopenharmony_ci{ 309462306a36Sopenharmony_ci struct sk_buff *skb = first->skb; 309562306a36Sopenharmony_ci u64 cd_cmd, cd_tso_len, cd_mss; 309662306a36Sopenharmony_ci __be16 protocol; 309762306a36Sopenharmony_ci union { 309862306a36Sopenharmony_ci struct iphdr *v4; 309962306a36Sopenharmony_ci struct ipv6hdr *v6; 310062306a36Sopenharmony_ci unsigned char *hdr; 310162306a36Sopenharmony_ci } ip; 310262306a36Sopenharmony_ci union { 310362306a36Sopenharmony_ci struct tcphdr *tcp; 310462306a36Sopenharmony_ci struct udphdr *udp; 310562306a36Sopenharmony_ci unsigned char *hdr; 310662306a36Sopenharmony_ci } l4; 310762306a36Sopenharmony_ci u32 paylen, l4_offset; 310862306a36Sopenharmony_ci u16 gso_size; 310962306a36Sopenharmony_ci int err; 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 311262306a36Sopenharmony_ci return 0; 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci if (!skb_is_gso(skb)) 311562306a36Sopenharmony_ci return 0; 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci err = skb_cow_head(skb, 0); 311862306a36Sopenharmony_ci if (err < 0) 311962306a36Sopenharmony_ci return err; 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci protocol = vlan_get_protocol(skb); 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci if (eth_p_mpls(protocol)) 312462306a36Sopenharmony_ci ip.hdr = skb_inner_network_header(skb); 312562306a36Sopenharmony_ci else 312662306a36Sopenharmony_ci ip.hdr = skb_network_header(skb); 312762306a36Sopenharmony_ci l4.hdr = skb_checksum_start(skb); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci /* initialize outer IP header fields */ 313062306a36Sopenharmony_ci if (ip.v4->version == 4) { 313162306a36Sopenharmony_ci ip.v4->tot_len = 0; 313262306a36Sopenharmony_ci ip.v4->check = 0; 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci first->tx_flags |= I40E_TX_FLAGS_TSO; 313562306a36Sopenharmony_ci } else { 313662306a36Sopenharmony_ci ip.v6->payload_len = 0; 313762306a36Sopenharmony_ci first->tx_flags |= I40E_TX_FLAGS_TSO; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & (SKB_GSO_GRE | 314162306a36Sopenharmony_ci SKB_GSO_GRE_CSUM | 314262306a36Sopenharmony_ci SKB_GSO_IPXIP4 | 314362306a36Sopenharmony_ci SKB_GSO_IPXIP6 | 314462306a36Sopenharmony_ci SKB_GSO_UDP_TUNNEL | 314562306a36Sopenharmony_ci SKB_GSO_UDP_TUNNEL_CSUM)) { 314662306a36Sopenharmony_ci if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && 314762306a36Sopenharmony_ci (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) { 314862306a36Sopenharmony_ci l4.udp->len = 0; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci /* determine offset of outer transport header */ 315162306a36Sopenharmony_ci l4_offset = l4.hdr - skb->data; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci /* remove payload length from outer checksum */ 315462306a36Sopenharmony_ci paylen = skb->len - l4_offset; 315562306a36Sopenharmony_ci csum_replace_by_diff(&l4.udp->check, 315662306a36Sopenharmony_ci (__force __wsum)htonl(paylen)); 315762306a36Sopenharmony_ci } 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci /* reset pointers to inner headers */ 316062306a36Sopenharmony_ci ip.hdr = skb_inner_network_header(skb); 316162306a36Sopenharmony_ci l4.hdr = skb_inner_transport_header(skb); 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci /* initialize inner IP header fields */ 316462306a36Sopenharmony_ci if (ip.v4->version == 4) { 316562306a36Sopenharmony_ci ip.v4->tot_len = 0; 316662306a36Sopenharmony_ci ip.v4->check = 0; 316762306a36Sopenharmony_ci } else { 316862306a36Sopenharmony_ci ip.v6->payload_len = 0; 316962306a36Sopenharmony_ci } 317062306a36Sopenharmony_ci } 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci /* determine offset of inner transport header */ 317362306a36Sopenharmony_ci l4_offset = l4.hdr - skb->data; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci /* remove payload length from inner checksum */ 317662306a36Sopenharmony_ci paylen = skb->len - l4_offset; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 317962306a36Sopenharmony_ci csum_replace_by_diff(&l4.udp->check, (__force __wsum)htonl(paylen)); 318062306a36Sopenharmony_ci /* compute length of segmentation header */ 318162306a36Sopenharmony_ci *hdr_len = sizeof(*l4.udp) + l4_offset; 318262306a36Sopenharmony_ci } else { 318362306a36Sopenharmony_ci csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); 318462306a36Sopenharmony_ci /* compute length of segmentation header */ 318562306a36Sopenharmony_ci *hdr_len = (l4.tcp->doff * 4) + l4_offset; 318662306a36Sopenharmony_ci } 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci /* pull values out of skb_shinfo */ 318962306a36Sopenharmony_ci gso_size = skb_shinfo(skb)->gso_size; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci /* update GSO size and bytecount with header size */ 319262306a36Sopenharmony_ci first->gso_segs = skb_shinfo(skb)->gso_segs; 319362306a36Sopenharmony_ci first->bytecount += (first->gso_segs - 1) * *hdr_len; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci /* find the field values */ 319662306a36Sopenharmony_ci cd_cmd = I40E_TX_CTX_DESC_TSO; 319762306a36Sopenharmony_ci cd_tso_len = skb->len - *hdr_len; 319862306a36Sopenharmony_ci cd_mss = gso_size; 319962306a36Sopenharmony_ci *cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | 320062306a36Sopenharmony_ci (cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | 320162306a36Sopenharmony_ci (cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT); 320262306a36Sopenharmony_ci return 1; 320362306a36Sopenharmony_ci} 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci/** 320662306a36Sopenharmony_ci * i40e_tsyn - set up the tsyn context descriptor 320762306a36Sopenharmony_ci * @tx_ring: ptr to the ring to send 320862306a36Sopenharmony_ci * @skb: ptr to the skb we're sending 320962306a36Sopenharmony_ci * @tx_flags: the collected send information 321062306a36Sopenharmony_ci * @cd_type_cmd_tso_mss: Quad Word 1 321162306a36Sopenharmony_ci * 321262306a36Sopenharmony_ci * Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen 321362306a36Sopenharmony_ci **/ 321462306a36Sopenharmony_cistatic int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, 321562306a36Sopenharmony_ci u32 tx_flags, u64 *cd_type_cmd_tso_mss) 321662306a36Sopenharmony_ci{ 321762306a36Sopenharmony_ci struct i40e_pf *pf; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) 322062306a36Sopenharmony_ci return 0; 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci /* Tx timestamps cannot be sampled when doing TSO */ 322362306a36Sopenharmony_ci if (tx_flags & I40E_TX_FLAGS_TSO) 322462306a36Sopenharmony_ci return 0; 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_ci /* only timestamp the outbound packet if the user has requested it and 322762306a36Sopenharmony_ci * we are not already transmitting a packet to be timestamped 322862306a36Sopenharmony_ci */ 322962306a36Sopenharmony_ci pf = i40e_netdev_to_pf(tx_ring->netdev); 323062306a36Sopenharmony_ci if (!(pf->flags & I40E_FLAG_PTP)) 323162306a36Sopenharmony_ci return 0; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci if (pf->ptp_tx && 323462306a36Sopenharmony_ci !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, pf->state)) { 323562306a36Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 323662306a36Sopenharmony_ci pf->ptp_tx_start = jiffies; 323762306a36Sopenharmony_ci pf->ptp_tx_skb = skb_get(skb); 323862306a36Sopenharmony_ci } else { 323962306a36Sopenharmony_ci pf->tx_hwtstamp_skipped++; 324062306a36Sopenharmony_ci return 0; 324162306a36Sopenharmony_ci } 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN << 324462306a36Sopenharmony_ci I40E_TXD_CTX_QW1_CMD_SHIFT; 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci return 1; 324762306a36Sopenharmony_ci} 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci/** 325062306a36Sopenharmony_ci * i40e_tx_enable_csum - Enable Tx checksum offloads 325162306a36Sopenharmony_ci * @skb: send buffer 325262306a36Sopenharmony_ci * @tx_flags: pointer to Tx flags currently set 325362306a36Sopenharmony_ci * @td_cmd: Tx descriptor command bits to set 325462306a36Sopenharmony_ci * @td_offset: Tx descriptor header offsets to set 325562306a36Sopenharmony_ci * @tx_ring: Tx descriptor ring 325662306a36Sopenharmony_ci * @cd_tunneling: ptr to context desc bits 325762306a36Sopenharmony_ci **/ 325862306a36Sopenharmony_cistatic int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, 325962306a36Sopenharmony_ci u32 *td_cmd, u32 *td_offset, 326062306a36Sopenharmony_ci struct i40e_ring *tx_ring, 326162306a36Sopenharmony_ci u32 *cd_tunneling) 326262306a36Sopenharmony_ci{ 326362306a36Sopenharmony_ci union { 326462306a36Sopenharmony_ci struct iphdr *v4; 326562306a36Sopenharmony_ci struct ipv6hdr *v6; 326662306a36Sopenharmony_ci unsigned char *hdr; 326762306a36Sopenharmony_ci } ip; 326862306a36Sopenharmony_ci union { 326962306a36Sopenharmony_ci struct tcphdr *tcp; 327062306a36Sopenharmony_ci struct udphdr *udp; 327162306a36Sopenharmony_ci unsigned char *hdr; 327262306a36Sopenharmony_ci } l4; 327362306a36Sopenharmony_ci unsigned char *exthdr; 327462306a36Sopenharmony_ci u32 offset, cmd = 0; 327562306a36Sopenharmony_ci __be16 frag_off; 327662306a36Sopenharmony_ci __be16 protocol; 327762306a36Sopenharmony_ci u8 l4_proto = 0; 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 328062306a36Sopenharmony_ci return 0; 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci protocol = vlan_get_protocol(skb); 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci if (eth_p_mpls(protocol)) { 328562306a36Sopenharmony_ci ip.hdr = skb_inner_network_header(skb); 328662306a36Sopenharmony_ci l4.hdr = skb_checksum_start(skb); 328762306a36Sopenharmony_ci } else { 328862306a36Sopenharmony_ci ip.hdr = skb_network_header(skb); 328962306a36Sopenharmony_ci l4.hdr = skb_transport_header(skb); 329062306a36Sopenharmony_ci } 329162306a36Sopenharmony_ci 329262306a36Sopenharmony_ci /* set the tx_flags to indicate the IP protocol type. this is 329362306a36Sopenharmony_ci * required so that checksum header computation below is accurate. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_ci if (ip.v4->version == 4) 329662306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_IPV4; 329762306a36Sopenharmony_ci else 329862306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_IPV6; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci /* compute outer L2 header size */ 330162306a36Sopenharmony_ci offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci if (skb->encapsulation) { 330462306a36Sopenharmony_ci u32 tunnel = 0; 330562306a36Sopenharmony_ci /* define outer network header type */ 330662306a36Sopenharmony_ci if (*tx_flags & I40E_TX_FLAGS_IPV4) { 330762306a36Sopenharmony_ci tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ? 330862306a36Sopenharmony_ci I40E_TX_CTX_EXT_IP_IPV4 : 330962306a36Sopenharmony_ci I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci l4_proto = ip.v4->protocol; 331262306a36Sopenharmony_ci } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { 331362306a36Sopenharmony_ci int ret; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci tunnel |= I40E_TX_CTX_EXT_IP_IPV6; 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci exthdr = ip.hdr + sizeof(*ip.v6); 331862306a36Sopenharmony_ci l4_proto = ip.v6->nexthdr; 331962306a36Sopenharmony_ci ret = ipv6_skip_exthdr(skb, exthdr - skb->data, 332062306a36Sopenharmony_ci &l4_proto, &frag_off); 332162306a36Sopenharmony_ci if (ret < 0) 332262306a36Sopenharmony_ci return -1; 332362306a36Sopenharmony_ci } 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci /* define outer transport */ 332662306a36Sopenharmony_ci switch (l4_proto) { 332762306a36Sopenharmony_ci case IPPROTO_UDP: 332862306a36Sopenharmony_ci tunnel |= I40E_TXD_CTX_UDP_TUNNELING; 332962306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL; 333062306a36Sopenharmony_ci break; 333162306a36Sopenharmony_ci case IPPROTO_GRE: 333262306a36Sopenharmony_ci tunnel |= I40E_TXD_CTX_GRE_TUNNELING; 333362306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL; 333462306a36Sopenharmony_ci break; 333562306a36Sopenharmony_ci case IPPROTO_IPIP: 333662306a36Sopenharmony_ci case IPPROTO_IPV6: 333762306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL; 333862306a36Sopenharmony_ci l4.hdr = skb_inner_network_header(skb); 333962306a36Sopenharmony_ci break; 334062306a36Sopenharmony_ci default: 334162306a36Sopenharmony_ci if (*tx_flags & I40E_TX_FLAGS_TSO) 334262306a36Sopenharmony_ci return -1; 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci skb_checksum_help(skb); 334562306a36Sopenharmony_ci return 0; 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci /* compute outer L3 header size */ 334962306a36Sopenharmony_ci tunnel |= ((l4.hdr - ip.hdr) / 4) << 335062306a36Sopenharmony_ci I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci /* switch IP header pointer from outer to inner header */ 335362306a36Sopenharmony_ci ip.hdr = skb_inner_network_header(skb); 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci /* compute tunnel header size */ 335662306a36Sopenharmony_ci tunnel |= ((ip.hdr - l4.hdr) / 2) << 335762306a36Sopenharmony_ci I40E_TXD_CTX_QW0_NATLEN_SHIFT; 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci /* indicate if we need to offload outer UDP header */ 336062306a36Sopenharmony_ci if ((*tx_flags & I40E_TX_FLAGS_TSO) && 336162306a36Sopenharmony_ci !(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) && 336262306a36Sopenharmony_ci (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)) 336362306a36Sopenharmony_ci tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK; 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci /* record tunnel offload values */ 336662306a36Sopenharmony_ci *cd_tunneling |= tunnel; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci /* switch L4 header pointer from outer to inner */ 336962306a36Sopenharmony_ci l4.hdr = skb_inner_transport_header(skb); 337062306a36Sopenharmony_ci l4_proto = 0; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci /* reset type as we transition from outer to inner headers */ 337362306a36Sopenharmony_ci *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6); 337462306a36Sopenharmony_ci if (ip.v4->version == 4) 337562306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_IPV4; 337662306a36Sopenharmony_ci if (ip.v6->version == 6) 337762306a36Sopenharmony_ci *tx_flags |= I40E_TX_FLAGS_IPV6; 337862306a36Sopenharmony_ci } 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci /* Enable IP checksum offloads */ 338162306a36Sopenharmony_ci if (*tx_flags & I40E_TX_FLAGS_IPV4) { 338262306a36Sopenharmony_ci l4_proto = ip.v4->protocol; 338362306a36Sopenharmony_ci /* the stack computes the IP header already, the only time we 338462306a36Sopenharmony_ci * need the hardware to recompute it is in the case of TSO. 338562306a36Sopenharmony_ci */ 338662306a36Sopenharmony_ci cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ? 338762306a36Sopenharmony_ci I40E_TX_DESC_CMD_IIPT_IPV4_CSUM : 338862306a36Sopenharmony_ci I40E_TX_DESC_CMD_IIPT_IPV4; 338962306a36Sopenharmony_ci } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { 339062306a36Sopenharmony_ci cmd |= I40E_TX_DESC_CMD_IIPT_IPV6; 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci exthdr = ip.hdr + sizeof(*ip.v6); 339362306a36Sopenharmony_ci l4_proto = ip.v6->nexthdr; 339462306a36Sopenharmony_ci if (l4.hdr != exthdr) 339562306a36Sopenharmony_ci ipv6_skip_exthdr(skb, exthdr - skb->data, 339662306a36Sopenharmony_ci &l4_proto, &frag_off); 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci /* compute inner L3 header size */ 340062306a36Sopenharmony_ci offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci /* Enable L4 checksum offloads */ 340362306a36Sopenharmony_ci switch (l4_proto) { 340462306a36Sopenharmony_ci case IPPROTO_TCP: 340562306a36Sopenharmony_ci /* enable checksum offloads */ 340662306a36Sopenharmony_ci cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP; 340762306a36Sopenharmony_ci offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 340862306a36Sopenharmony_ci break; 340962306a36Sopenharmony_ci case IPPROTO_SCTP: 341062306a36Sopenharmony_ci /* enable SCTP checksum offload */ 341162306a36Sopenharmony_ci cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP; 341262306a36Sopenharmony_ci offset |= (sizeof(struct sctphdr) >> 2) << 341362306a36Sopenharmony_ci I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 341462306a36Sopenharmony_ci break; 341562306a36Sopenharmony_ci case IPPROTO_UDP: 341662306a36Sopenharmony_ci /* enable UDP checksum offload */ 341762306a36Sopenharmony_ci cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP; 341862306a36Sopenharmony_ci offset |= (sizeof(struct udphdr) >> 2) << 341962306a36Sopenharmony_ci I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; 342062306a36Sopenharmony_ci break; 342162306a36Sopenharmony_ci default: 342262306a36Sopenharmony_ci if (*tx_flags & I40E_TX_FLAGS_TSO) 342362306a36Sopenharmony_ci return -1; 342462306a36Sopenharmony_ci skb_checksum_help(skb); 342562306a36Sopenharmony_ci return 0; 342662306a36Sopenharmony_ci } 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci *td_cmd |= cmd; 342962306a36Sopenharmony_ci *td_offset |= offset; 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci return 1; 343262306a36Sopenharmony_ci} 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci/** 343562306a36Sopenharmony_ci * i40e_create_tx_ctx - Build the Tx context descriptor 343662306a36Sopenharmony_ci * @tx_ring: ring to create the descriptor on 343762306a36Sopenharmony_ci * @cd_type_cmd_tso_mss: Quad Word 1 343862306a36Sopenharmony_ci * @cd_tunneling: Quad Word 0 - bits 0-31 343962306a36Sopenharmony_ci * @cd_l2tag2: Quad Word 0 - bits 32-63 344062306a36Sopenharmony_ci **/ 344162306a36Sopenharmony_cistatic void i40e_create_tx_ctx(struct i40e_ring *tx_ring, 344262306a36Sopenharmony_ci const u64 cd_type_cmd_tso_mss, 344362306a36Sopenharmony_ci const u32 cd_tunneling, const u32 cd_l2tag2) 344462306a36Sopenharmony_ci{ 344562306a36Sopenharmony_ci struct i40e_tx_context_desc *context_desc; 344662306a36Sopenharmony_ci int i = tx_ring->next_to_use; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) && 344962306a36Sopenharmony_ci !cd_tunneling && !cd_l2tag2) 345062306a36Sopenharmony_ci return; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci /* grab the next descriptor */ 345362306a36Sopenharmony_ci context_desc = I40E_TX_CTXTDESC(tx_ring, i); 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci i++; 345662306a36Sopenharmony_ci tx_ring->next_to_use = (i < tx_ring->count) ? i : 0; 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci /* cpu_to_le32 and assign to struct fields */ 345962306a36Sopenharmony_ci context_desc->tunneling_params = cpu_to_le32(cd_tunneling); 346062306a36Sopenharmony_ci context_desc->l2tag2 = cpu_to_le16(cd_l2tag2); 346162306a36Sopenharmony_ci context_desc->rsvd = cpu_to_le16(0); 346262306a36Sopenharmony_ci context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss); 346362306a36Sopenharmony_ci} 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci/** 346662306a36Sopenharmony_ci * __i40e_maybe_stop_tx - 2nd level check for tx stop conditions 346762306a36Sopenharmony_ci * @tx_ring: the ring to be checked 346862306a36Sopenharmony_ci * @size: the size buffer we want to assure is available 346962306a36Sopenharmony_ci * 347062306a36Sopenharmony_ci * Returns -EBUSY if a stop is needed, else 0 347162306a36Sopenharmony_ci **/ 347262306a36Sopenharmony_ciint __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size) 347362306a36Sopenharmony_ci{ 347462306a36Sopenharmony_ci netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index); 347562306a36Sopenharmony_ci /* Memory barrier before checking head and tail */ 347662306a36Sopenharmony_ci smp_mb(); 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci ++tx_ring->tx_stats.tx_stopped; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci /* Check again in a case another CPU has just made room available. */ 348162306a36Sopenharmony_ci if (likely(I40E_DESC_UNUSED(tx_ring) < size)) 348262306a36Sopenharmony_ci return -EBUSY; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_ci /* A reprieve! - use start_queue because it doesn't call schedule */ 348562306a36Sopenharmony_ci netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index); 348662306a36Sopenharmony_ci ++tx_ring->tx_stats.restart_queue; 348762306a36Sopenharmony_ci return 0; 348862306a36Sopenharmony_ci} 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci/** 349162306a36Sopenharmony_ci * __i40e_chk_linearize - Check if there are more than 8 buffers per packet 349262306a36Sopenharmony_ci * @skb: send buffer 349362306a36Sopenharmony_ci * 349462306a36Sopenharmony_ci * Note: Our HW can't DMA more than 8 buffers to build a packet on the wire 349562306a36Sopenharmony_ci * and so we need to figure out the cases where we need to linearize the skb. 349662306a36Sopenharmony_ci * 349762306a36Sopenharmony_ci * For TSO we need to count the TSO header and segment payload separately. 349862306a36Sopenharmony_ci * As such we need to check cases where we have 7 fragments or more as we 349962306a36Sopenharmony_ci * can potentially require 9 DMA transactions, 1 for the TSO header, 1 for 350062306a36Sopenharmony_ci * the segment payload in the first descriptor, and another 7 for the 350162306a36Sopenharmony_ci * fragments. 350262306a36Sopenharmony_ci **/ 350362306a36Sopenharmony_cibool __i40e_chk_linearize(struct sk_buff *skb) 350462306a36Sopenharmony_ci{ 350562306a36Sopenharmony_ci const skb_frag_t *frag, *stale; 350662306a36Sopenharmony_ci int nr_frags, sum; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci /* no need to check if number of frags is less than 7 */ 350962306a36Sopenharmony_ci nr_frags = skb_shinfo(skb)->nr_frags; 351062306a36Sopenharmony_ci if (nr_frags < (I40E_MAX_BUFFER_TXD - 1)) 351162306a36Sopenharmony_ci return false; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci /* We need to walk through the list and validate that each group 351462306a36Sopenharmony_ci * of 6 fragments totals at least gso_size. 351562306a36Sopenharmony_ci */ 351662306a36Sopenharmony_ci nr_frags -= I40E_MAX_BUFFER_TXD - 2; 351762306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 351862306a36Sopenharmony_ci 351962306a36Sopenharmony_ci /* Initialize size to the negative value of gso_size minus 1. We 352062306a36Sopenharmony_ci * use this as the worst case scenerio in which the frag ahead 352162306a36Sopenharmony_ci * of us only provides one byte which is why we are limited to 6 352262306a36Sopenharmony_ci * descriptors for a single transmit as the header and previous 352362306a36Sopenharmony_ci * fragment are already consuming 2 descriptors. 352462306a36Sopenharmony_ci */ 352562306a36Sopenharmony_ci sum = 1 - skb_shinfo(skb)->gso_size; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci /* Add size of frags 0 through 4 to create our initial sum */ 352862306a36Sopenharmony_ci sum += skb_frag_size(frag++); 352962306a36Sopenharmony_ci sum += skb_frag_size(frag++); 353062306a36Sopenharmony_ci sum += skb_frag_size(frag++); 353162306a36Sopenharmony_ci sum += skb_frag_size(frag++); 353262306a36Sopenharmony_ci sum += skb_frag_size(frag++); 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci /* Walk through fragments adding latest fragment, testing it, and 353562306a36Sopenharmony_ci * then removing stale fragments from the sum. 353662306a36Sopenharmony_ci */ 353762306a36Sopenharmony_ci for (stale = &skb_shinfo(skb)->frags[0];; stale++) { 353862306a36Sopenharmony_ci int stale_size = skb_frag_size(stale); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci sum += skb_frag_size(frag++); 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci /* The stale fragment may present us with a smaller 354362306a36Sopenharmony_ci * descriptor than the actual fragment size. To account 354462306a36Sopenharmony_ci * for that we need to remove all the data on the front and 354562306a36Sopenharmony_ci * figure out what the remainder would be in the last 354662306a36Sopenharmony_ci * descriptor associated with the fragment. 354762306a36Sopenharmony_ci */ 354862306a36Sopenharmony_ci if (stale_size > I40E_MAX_DATA_PER_TXD) { 354962306a36Sopenharmony_ci int align_pad = -(skb_frag_off(stale)) & 355062306a36Sopenharmony_ci (I40E_MAX_READ_REQ_SIZE - 1); 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci sum -= align_pad; 355362306a36Sopenharmony_ci stale_size -= align_pad; 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci do { 355662306a36Sopenharmony_ci sum -= I40E_MAX_DATA_PER_TXD_ALIGNED; 355762306a36Sopenharmony_ci stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED; 355862306a36Sopenharmony_ci } while (stale_size > I40E_MAX_DATA_PER_TXD); 355962306a36Sopenharmony_ci } 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci /* if sum is negative we failed to make sufficient progress */ 356262306a36Sopenharmony_ci if (sum < 0) 356362306a36Sopenharmony_ci return true; 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci if (!nr_frags--) 356662306a36Sopenharmony_ci break; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci sum -= stale_size; 356962306a36Sopenharmony_ci } 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci return false; 357262306a36Sopenharmony_ci} 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci/** 357562306a36Sopenharmony_ci * i40e_tx_map - Build the Tx descriptor 357662306a36Sopenharmony_ci * @tx_ring: ring to send buffer on 357762306a36Sopenharmony_ci * @skb: send buffer 357862306a36Sopenharmony_ci * @first: first buffer info buffer to use 357962306a36Sopenharmony_ci * @tx_flags: collected send information 358062306a36Sopenharmony_ci * @hdr_len: size of the packet header 358162306a36Sopenharmony_ci * @td_cmd: the command field in the descriptor 358262306a36Sopenharmony_ci * @td_offset: offset for checksum or crc 358362306a36Sopenharmony_ci * 358462306a36Sopenharmony_ci * Returns 0 on success, -1 on failure to DMA 358562306a36Sopenharmony_ci **/ 358662306a36Sopenharmony_cistatic inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, 358762306a36Sopenharmony_ci struct i40e_tx_buffer *first, u32 tx_flags, 358862306a36Sopenharmony_ci const u8 hdr_len, u32 td_cmd, u32 td_offset) 358962306a36Sopenharmony_ci{ 359062306a36Sopenharmony_ci unsigned int data_len = skb->data_len; 359162306a36Sopenharmony_ci unsigned int size = skb_headlen(skb); 359262306a36Sopenharmony_ci skb_frag_t *frag; 359362306a36Sopenharmony_ci struct i40e_tx_buffer *tx_bi; 359462306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 359562306a36Sopenharmony_ci u16 i = tx_ring->next_to_use; 359662306a36Sopenharmony_ci u32 td_tag = 0; 359762306a36Sopenharmony_ci dma_addr_t dma; 359862306a36Sopenharmony_ci u16 desc_count = 1; 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci if (tx_flags & I40E_TX_FLAGS_HW_VLAN) { 360162306a36Sopenharmony_ci td_cmd |= I40E_TX_DESC_CMD_IL2TAG1; 360262306a36Sopenharmony_ci td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >> 360362306a36Sopenharmony_ci I40E_TX_FLAGS_VLAN_SHIFT; 360462306a36Sopenharmony_ci } 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci first->tx_flags = tx_flags; 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, i); 361162306a36Sopenharmony_ci tx_bi = first; 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci for (frag = &skb_shinfo(skb)->frags[0];; frag++) { 361462306a36Sopenharmony_ci unsigned int max_data = I40E_MAX_DATA_PER_TXD_ALIGNED; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci if (dma_mapping_error(tx_ring->dev, dma)) 361762306a36Sopenharmony_ci goto dma_error; 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci /* record length, and DMA address */ 362062306a36Sopenharmony_ci dma_unmap_len_set(tx_bi, len, size); 362162306a36Sopenharmony_ci dma_unmap_addr_set(tx_bi, dma, dma); 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci /* align size to end of page */ 362462306a36Sopenharmony_ci max_data += -dma & (I40E_MAX_READ_REQ_SIZE - 1); 362562306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci while (unlikely(size > I40E_MAX_DATA_PER_TXD)) { 362862306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = 362962306a36Sopenharmony_ci build_ctob(td_cmd, td_offset, 363062306a36Sopenharmony_ci max_data, td_tag); 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_ci tx_desc++; 363362306a36Sopenharmony_ci i++; 363462306a36Sopenharmony_ci desc_count++; 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci if (i == tx_ring->count) { 363762306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, 0); 363862306a36Sopenharmony_ci i = 0; 363962306a36Sopenharmony_ci } 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci dma += max_data; 364262306a36Sopenharmony_ci size -= max_data; 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci max_data = I40E_MAX_DATA_PER_TXD_ALIGNED; 364562306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 364662306a36Sopenharmony_ci } 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci if (likely(!data_len)) 364962306a36Sopenharmony_ci break; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, 365262306a36Sopenharmony_ci size, td_tag); 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci tx_desc++; 365562306a36Sopenharmony_ci i++; 365662306a36Sopenharmony_ci desc_count++; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci if (i == tx_ring->count) { 365962306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(tx_ring, 0); 366062306a36Sopenharmony_ci i = 0; 366162306a36Sopenharmony_ci } 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci size = skb_frag_size(frag); 366462306a36Sopenharmony_ci data_len -= size; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size, 366762306a36Sopenharmony_ci DMA_TO_DEVICE); 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci tx_bi = &tx_ring->tx_bi[i]; 367062306a36Sopenharmony_ci } 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount); 367362306a36Sopenharmony_ci 367462306a36Sopenharmony_ci i++; 367562306a36Sopenharmony_ci if (i == tx_ring->count) 367662306a36Sopenharmony_ci i = 0; 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci tx_ring->next_to_use = i; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci i40e_maybe_stop_tx(tx_ring, DESC_NEEDED); 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci /* write last descriptor with EOP bit */ 368362306a36Sopenharmony_ci td_cmd |= I40E_TX_DESC_CMD_EOP; 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ci /* We OR these values together to check both against 4 (WB_STRIDE) 368662306a36Sopenharmony_ci * below. This is safe since we don't re-use desc_count afterwards. 368762306a36Sopenharmony_ci */ 368862306a36Sopenharmony_ci desc_count |= ++tx_ring->packet_stride; 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci if (desc_count >= WB_STRIDE) { 369162306a36Sopenharmony_ci /* write last descriptor with RS bit set */ 369262306a36Sopenharmony_ci td_cmd |= I40E_TX_DESC_CMD_RS; 369362306a36Sopenharmony_ci tx_ring->packet_stride = 0; 369462306a36Sopenharmony_ci } 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = 369762306a36Sopenharmony_ci build_ctob(td_cmd, td_offset, size, td_tag); 369862306a36Sopenharmony_ci 369962306a36Sopenharmony_ci skb_tx_timestamp(skb); 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci /* Force memory writes to complete before letting h/w know there 370262306a36Sopenharmony_ci * are new descriptors to fetch. 370362306a36Sopenharmony_ci * 370462306a36Sopenharmony_ci * We also use this memory barrier to make certain all of the 370562306a36Sopenharmony_ci * status bits have been updated before next_to_watch is written. 370662306a36Sopenharmony_ci */ 370762306a36Sopenharmony_ci wmb(); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci /* set next_to_watch value indicating a packet is present */ 371062306a36Sopenharmony_ci first->next_to_watch = tx_desc; 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci /* notify HW of packet */ 371362306a36Sopenharmony_ci if (netif_xmit_stopped(txring_txq(tx_ring)) || !netdev_xmit_more()) { 371462306a36Sopenharmony_ci writel(i, tx_ring->tail); 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci return 0; 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_cidma_error: 372062306a36Sopenharmony_ci dev_info(tx_ring->dev, "TX DMA map failed\n"); 372162306a36Sopenharmony_ci 372262306a36Sopenharmony_ci /* clear dma mappings for failed tx_bi map */ 372362306a36Sopenharmony_ci for (;;) { 372462306a36Sopenharmony_ci tx_bi = &tx_ring->tx_bi[i]; 372562306a36Sopenharmony_ci i40e_unmap_and_free_tx_resource(tx_ring, tx_bi); 372662306a36Sopenharmony_ci if (tx_bi == first) 372762306a36Sopenharmony_ci break; 372862306a36Sopenharmony_ci if (i == 0) 372962306a36Sopenharmony_ci i = tx_ring->count; 373062306a36Sopenharmony_ci i--; 373162306a36Sopenharmony_ci } 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci tx_ring->next_to_use = i; 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci return -1; 373662306a36Sopenharmony_ci} 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_cistatic u16 i40e_swdcb_skb_tx_hash(struct net_device *dev, 373962306a36Sopenharmony_ci const struct sk_buff *skb, 374062306a36Sopenharmony_ci u16 num_tx_queues) 374162306a36Sopenharmony_ci{ 374262306a36Sopenharmony_ci u32 jhash_initval_salt = 0xd631614b; 374362306a36Sopenharmony_ci u32 hash; 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci if (skb->sk && skb->sk->sk_hash) 374662306a36Sopenharmony_ci hash = skb->sk->sk_hash; 374762306a36Sopenharmony_ci else 374862306a36Sopenharmony_ci hash = (__force u16)skb->protocol ^ skb->hash; 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci hash = jhash_1word(hash, jhash_initval_salt); 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci return (u16)(((u64)hash * num_tx_queues) >> 32); 375362306a36Sopenharmony_ci} 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ciu16 i40e_lan_select_queue(struct net_device *netdev, 375662306a36Sopenharmony_ci struct sk_buff *skb, 375762306a36Sopenharmony_ci struct net_device __always_unused *sb_dev) 375862306a36Sopenharmony_ci{ 375962306a36Sopenharmony_ci struct i40e_netdev_priv *np = netdev_priv(netdev); 376062306a36Sopenharmony_ci struct i40e_vsi *vsi = np->vsi; 376162306a36Sopenharmony_ci struct i40e_hw *hw; 376262306a36Sopenharmony_ci u16 qoffset; 376362306a36Sopenharmony_ci u16 qcount; 376462306a36Sopenharmony_ci u8 tclass; 376562306a36Sopenharmony_ci u16 hash; 376662306a36Sopenharmony_ci u8 prio; 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci /* is DCB enabled at all? */ 376962306a36Sopenharmony_ci if (vsi->tc_config.numtc == 1 || 377062306a36Sopenharmony_ci i40e_is_tc_mqprio_enabled(vsi->back)) 377162306a36Sopenharmony_ci return netdev_pick_tx(netdev, skb, sb_dev); 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci prio = skb->priority; 377462306a36Sopenharmony_ci hw = &vsi->back->hw; 377562306a36Sopenharmony_ci tclass = hw->local_dcbx_config.etscfg.prioritytable[prio]; 377662306a36Sopenharmony_ci /* sanity check */ 377762306a36Sopenharmony_ci if (unlikely(!(vsi->tc_config.enabled_tc & BIT(tclass)))) 377862306a36Sopenharmony_ci tclass = 0; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci /* select a queue assigned for the given TC */ 378162306a36Sopenharmony_ci qcount = vsi->tc_config.tc_info[tclass].qcount; 378262306a36Sopenharmony_ci hash = i40e_swdcb_skb_tx_hash(netdev, skb, qcount); 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci qoffset = vsi->tc_config.tc_info[tclass].qoffset; 378562306a36Sopenharmony_ci return qoffset + hash; 378662306a36Sopenharmony_ci} 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci/** 378962306a36Sopenharmony_ci * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring 379062306a36Sopenharmony_ci * @xdpf: data to transmit 379162306a36Sopenharmony_ci * @xdp_ring: XDP Tx ring 379262306a36Sopenharmony_ci **/ 379362306a36Sopenharmony_cistatic int i40e_xmit_xdp_ring(struct xdp_frame *xdpf, 379462306a36Sopenharmony_ci struct i40e_ring *xdp_ring) 379562306a36Sopenharmony_ci{ 379662306a36Sopenharmony_ci struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); 379762306a36Sopenharmony_ci u8 nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0; 379862306a36Sopenharmony_ci u16 i = 0, index = xdp_ring->next_to_use; 379962306a36Sopenharmony_ci struct i40e_tx_buffer *tx_head = &xdp_ring->tx_bi[index]; 380062306a36Sopenharmony_ci struct i40e_tx_buffer *tx_bi = tx_head; 380162306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc = I40E_TX_DESC(xdp_ring, index); 380262306a36Sopenharmony_ci void *data = xdpf->data; 380362306a36Sopenharmony_ci u32 size = xdpf->len; 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci if (unlikely(I40E_DESC_UNUSED(xdp_ring) < 1 + nr_frags)) { 380662306a36Sopenharmony_ci xdp_ring->tx_stats.tx_busy++; 380762306a36Sopenharmony_ci return I40E_XDP_CONSUMED; 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci tx_head->bytecount = xdp_get_frame_len(xdpf); 381162306a36Sopenharmony_ci tx_head->gso_segs = 1; 381262306a36Sopenharmony_ci tx_head->xdpf = xdpf; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci for (;;) { 381562306a36Sopenharmony_ci dma_addr_t dma; 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE); 381862306a36Sopenharmony_ci if (dma_mapping_error(xdp_ring->dev, dma)) 381962306a36Sopenharmony_ci goto unmap; 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_ci /* record length, and DMA address */ 382262306a36Sopenharmony_ci dma_unmap_len_set(tx_bi, len, size); 382362306a36Sopenharmony_ci dma_unmap_addr_set(tx_bi, dma, dma); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 382662306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = 382762306a36Sopenharmony_ci build_ctob(I40E_TX_DESC_CMD_ICRC, 0, size, 0); 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci if (++index == xdp_ring->count) 383062306a36Sopenharmony_ci index = 0; 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ci if (i == nr_frags) 383362306a36Sopenharmony_ci break; 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci tx_bi = &xdp_ring->tx_bi[index]; 383662306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(xdp_ring, index); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci data = skb_frag_address(&sinfo->frags[i]); 383962306a36Sopenharmony_ci size = skb_frag_size(&sinfo->frags[i]); 384062306a36Sopenharmony_ci i++; 384162306a36Sopenharmony_ci } 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz |= 384462306a36Sopenharmony_ci cpu_to_le64(I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT); 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci /* Make certain all of the status bits have been updated 384762306a36Sopenharmony_ci * before next_to_watch is written. 384862306a36Sopenharmony_ci */ 384962306a36Sopenharmony_ci smp_wmb(); 385062306a36Sopenharmony_ci 385162306a36Sopenharmony_ci xdp_ring->xdp_tx_active++; 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci tx_head->next_to_watch = tx_desc; 385462306a36Sopenharmony_ci xdp_ring->next_to_use = index; 385562306a36Sopenharmony_ci 385662306a36Sopenharmony_ci return I40E_XDP_TX; 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ciunmap: 385962306a36Sopenharmony_ci for (;;) { 386062306a36Sopenharmony_ci tx_bi = &xdp_ring->tx_bi[index]; 386162306a36Sopenharmony_ci if (dma_unmap_len(tx_bi, len)) 386262306a36Sopenharmony_ci dma_unmap_page(xdp_ring->dev, 386362306a36Sopenharmony_ci dma_unmap_addr(tx_bi, dma), 386462306a36Sopenharmony_ci dma_unmap_len(tx_bi, len), 386562306a36Sopenharmony_ci DMA_TO_DEVICE); 386662306a36Sopenharmony_ci dma_unmap_len_set(tx_bi, len, 0); 386762306a36Sopenharmony_ci if (tx_bi == tx_head) 386862306a36Sopenharmony_ci break; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci if (!index) 387162306a36Sopenharmony_ci index += xdp_ring->count; 387262306a36Sopenharmony_ci index--; 387362306a36Sopenharmony_ci } 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci return I40E_XDP_CONSUMED; 387662306a36Sopenharmony_ci} 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci/** 387962306a36Sopenharmony_ci * i40e_xmit_frame_ring - Sends buffer on Tx ring 388062306a36Sopenharmony_ci * @skb: send buffer 388162306a36Sopenharmony_ci * @tx_ring: ring to send buffer on 388262306a36Sopenharmony_ci * 388362306a36Sopenharmony_ci * Returns NETDEV_TX_OK if sent, else an error code 388462306a36Sopenharmony_ci **/ 388562306a36Sopenharmony_cistatic netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, 388662306a36Sopenharmony_ci struct i40e_ring *tx_ring) 388762306a36Sopenharmony_ci{ 388862306a36Sopenharmony_ci u64 cd_type_cmd_tso_mss = I40E_TX_DESC_DTYPE_CONTEXT; 388962306a36Sopenharmony_ci u32 cd_tunneling = 0, cd_l2tag2 = 0; 389062306a36Sopenharmony_ci struct i40e_tx_buffer *first; 389162306a36Sopenharmony_ci u32 td_offset = 0; 389262306a36Sopenharmony_ci u32 tx_flags = 0; 389362306a36Sopenharmony_ci u32 td_cmd = 0; 389462306a36Sopenharmony_ci u8 hdr_len = 0; 389562306a36Sopenharmony_ci int tso, count; 389662306a36Sopenharmony_ci int tsyn; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci /* prefetch the data, we'll need it later */ 389962306a36Sopenharmony_ci prefetch(skb->data); 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci i40e_trace(xmit_frame_ring, skb, tx_ring); 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_ci count = i40e_xmit_descriptor_count(skb); 390462306a36Sopenharmony_ci if (i40e_chk_linearize(skb, count)) { 390562306a36Sopenharmony_ci if (__skb_linearize(skb)) { 390662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 390762306a36Sopenharmony_ci return NETDEV_TX_OK; 390862306a36Sopenharmony_ci } 390962306a36Sopenharmony_ci count = i40e_txd_use_count(skb->len); 391062306a36Sopenharmony_ci tx_ring->tx_stats.tx_linearize++; 391162306a36Sopenharmony_ci } 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, 391462306a36Sopenharmony_ci * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, 391562306a36Sopenharmony_ci * + 4 desc gap to avoid the cache line where head is, 391662306a36Sopenharmony_ci * + 1 desc for context descriptor, 391762306a36Sopenharmony_ci * otherwise try next time 391862306a36Sopenharmony_ci */ 391962306a36Sopenharmony_ci if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { 392062306a36Sopenharmony_ci tx_ring->tx_stats.tx_busy++; 392162306a36Sopenharmony_ci return NETDEV_TX_BUSY; 392262306a36Sopenharmony_ci } 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci /* record the location of the first descriptor for this packet */ 392562306a36Sopenharmony_ci first = &tx_ring->tx_bi[tx_ring->next_to_use]; 392662306a36Sopenharmony_ci first->skb = skb; 392762306a36Sopenharmony_ci first->bytecount = skb->len; 392862306a36Sopenharmony_ci first->gso_segs = 1; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci /* prepare the xmit flags */ 393162306a36Sopenharmony_ci if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) 393262306a36Sopenharmony_ci goto out_drop; 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci tso = i40e_tso(first, &hdr_len, &cd_type_cmd_tso_mss); 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci if (tso < 0) 393762306a36Sopenharmony_ci goto out_drop; 393862306a36Sopenharmony_ci else if (tso) 393962306a36Sopenharmony_ci tx_flags |= I40E_TX_FLAGS_TSO; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci /* Always offload the checksum, since it's in the data descriptor */ 394262306a36Sopenharmony_ci tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset, 394362306a36Sopenharmony_ci tx_ring, &cd_tunneling); 394462306a36Sopenharmony_ci if (tso < 0) 394562306a36Sopenharmony_ci goto out_drop; 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss); 394862306a36Sopenharmony_ci 394962306a36Sopenharmony_ci if (tsyn) 395062306a36Sopenharmony_ci tx_flags |= I40E_TX_FLAGS_TSYN; 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci /* always enable CRC insertion offload */ 395362306a36Sopenharmony_ci td_cmd |= I40E_TX_DESC_CMD_ICRC; 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss, 395662306a36Sopenharmony_ci cd_tunneling, cd_l2tag2); 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci /* Add Flow Director ATR if it's enabled. 395962306a36Sopenharmony_ci * 396062306a36Sopenharmony_ci * NOTE: this must always be directly before the data descriptor. 396162306a36Sopenharmony_ci */ 396262306a36Sopenharmony_ci i40e_atr(tx_ring, skb, tx_flags); 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci if (i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, 396562306a36Sopenharmony_ci td_cmd, td_offset)) 396662306a36Sopenharmony_ci goto cleanup_tx_tstamp; 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci return NETDEV_TX_OK; 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ciout_drop: 397162306a36Sopenharmony_ci i40e_trace(xmit_frame_ring_drop, first->skb, tx_ring); 397262306a36Sopenharmony_ci dev_kfree_skb_any(first->skb); 397362306a36Sopenharmony_ci first->skb = NULL; 397462306a36Sopenharmony_cicleanup_tx_tstamp: 397562306a36Sopenharmony_ci if (unlikely(tx_flags & I40E_TX_FLAGS_TSYN)) { 397662306a36Sopenharmony_ci struct i40e_pf *pf = i40e_netdev_to_pf(tx_ring->netdev); 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci dev_kfree_skb_any(pf->ptp_tx_skb); 397962306a36Sopenharmony_ci pf->ptp_tx_skb = NULL; 398062306a36Sopenharmony_ci clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state); 398162306a36Sopenharmony_ci } 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci return NETDEV_TX_OK; 398462306a36Sopenharmony_ci} 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci/** 398762306a36Sopenharmony_ci * i40e_lan_xmit_frame - Selects the correct VSI and Tx queue to send buffer 398862306a36Sopenharmony_ci * @skb: send buffer 398962306a36Sopenharmony_ci * @netdev: network interface device structure 399062306a36Sopenharmony_ci * 399162306a36Sopenharmony_ci * Returns NETDEV_TX_OK if sent, else an error code 399262306a36Sopenharmony_ci **/ 399362306a36Sopenharmony_cinetdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev) 399462306a36Sopenharmony_ci{ 399562306a36Sopenharmony_ci struct i40e_netdev_priv *np = netdev_priv(netdev); 399662306a36Sopenharmony_ci struct i40e_vsi *vsi = np->vsi; 399762306a36Sopenharmony_ci struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping]; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci /* hardware can't handle really short frames, hardware padding works 400062306a36Sopenharmony_ci * beyond this point 400162306a36Sopenharmony_ci */ 400262306a36Sopenharmony_ci if (skb_put_padto(skb, I40E_MIN_TX_LEN)) 400362306a36Sopenharmony_ci return NETDEV_TX_OK; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci return i40e_xmit_frame_ring(skb, tx_ring); 400662306a36Sopenharmony_ci} 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci/** 400962306a36Sopenharmony_ci * i40e_xdp_xmit - Implements ndo_xdp_xmit 401062306a36Sopenharmony_ci * @dev: netdev 401162306a36Sopenharmony_ci * @n: number of frames 401262306a36Sopenharmony_ci * @frames: array of XDP buffer pointers 401362306a36Sopenharmony_ci * @flags: XDP extra info 401462306a36Sopenharmony_ci * 401562306a36Sopenharmony_ci * Returns number of frames successfully sent. Failed frames 401662306a36Sopenharmony_ci * will be free'ed by XDP core. 401762306a36Sopenharmony_ci * 401862306a36Sopenharmony_ci * For error cases, a negative errno code is returned and no-frames 401962306a36Sopenharmony_ci * are transmitted (caller must handle freeing frames). 402062306a36Sopenharmony_ci **/ 402162306a36Sopenharmony_ciint i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, 402262306a36Sopenharmony_ci u32 flags) 402362306a36Sopenharmony_ci{ 402462306a36Sopenharmony_ci struct i40e_netdev_priv *np = netdev_priv(dev); 402562306a36Sopenharmony_ci unsigned int queue_index = smp_processor_id(); 402662306a36Sopenharmony_ci struct i40e_vsi *vsi = np->vsi; 402762306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 402862306a36Sopenharmony_ci struct i40e_ring *xdp_ring; 402962306a36Sopenharmony_ci int nxmit = 0; 403062306a36Sopenharmony_ci int i; 403162306a36Sopenharmony_ci 403262306a36Sopenharmony_ci if (test_bit(__I40E_VSI_DOWN, vsi->state)) 403362306a36Sopenharmony_ci return -ENETDOWN; 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs || 403662306a36Sopenharmony_ci test_bit(__I40E_CONFIG_BUSY, pf->state)) 403762306a36Sopenharmony_ci return -ENXIO; 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) 404062306a36Sopenharmony_ci return -EINVAL; 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci xdp_ring = vsi->xdp_rings[queue_index]; 404362306a36Sopenharmony_ci 404462306a36Sopenharmony_ci for (i = 0; i < n; i++) { 404562306a36Sopenharmony_ci struct xdp_frame *xdpf = frames[i]; 404662306a36Sopenharmony_ci int err; 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci err = i40e_xmit_xdp_ring(xdpf, xdp_ring); 404962306a36Sopenharmony_ci if (err != I40E_XDP_TX) 405062306a36Sopenharmony_ci break; 405162306a36Sopenharmony_ci nxmit++; 405262306a36Sopenharmony_ci } 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci if (unlikely(flags & XDP_XMIT_FLUSH)) 405562306a36Sopenharmony_ci i40e_xdp_ring_update_tail(xdp_ring); 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci return nxmit; 405862306a36Sopenharmony_ci} 4059