162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bpf_trace.h> 562306a36Sopenharmony_ci#include <linux/stringify.h> 662306a36Sopenharmony_ci#include <net/xdp_sock_drv.h> 762306a36Sopenharmony_ci#include <net/xdp.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "i40e.h" 1062306a36Sopenharmony_ci#include "i40e_txrx_common.h" 1162306a36Sopenharmony_ci#include "i40e_xsk.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_civoid i40e_clear_rx_bi_zc(struct i40e_ring *rx_ring) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci memset(rx_ring->rx_bi_zc, 0, 1662306a36Sopenharmony_ci sizeof(*rx_ring->rx_bi_zc) * rx_ring->count); 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic struct xdp_buff **i40e_rx_bi(struct i40e_ring *rx_ring, u32 idx) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci return &rx_ring->rx_bi_zc[idx]; 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/** 2562306a36Sopenharmony_ci * i40e_realloc_rx_xdp_bi - reallocate SW ring for either XSK or normal buffer 2662306a36Sopenharmony_ci * @rx_ring: Current rx ring 2762306a36Sopenharmony_ci * @pool_present: is pool for XSK present 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Try allocating memory and return ENOMEM, if failed to allocate. 3062306a36Sopenharmony_ci * If allocation was successful, substitute buffer with allocated one. 3162306a36Sopenharmony_ci * Returns 0 on success, negative on failure 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_cistatic int i40e_realloc_rx_xdp_bi(struct i40e_ring *rx_ring, bool pool_present) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci size_t elem_size = pool_present ? sizeof(*rx_ring->rx_bi_zc) : 3662306a36Sopenharmony_ci sizeof(*rx_ring->rx_bi); 3762306a36Sopenharmony_ci void *sw_ring = kcalloc(rx_ring->count, elem_size, GFP_KERNEL); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!sw_ring) 4062306a36Sopenharmony_ci return -ENOMEM; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (pool_present) { 4362306a36Sopenharmony_ci kfree(rx_ring->rx_bi); 4462306a36Sopenharmony_ci rx_ring->rx_bi = NULL; 4562306a36Sopenharmony_ci rx_ring->rx_bi_zc = sw_ring; 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci kfree(rx_ring->rx_bi_zc); 4862306a36Sopenharmony_ci rx_ring->rx_bi_zc = NULL; 4962306a36Sopenharmony_ci rx_ring->rx_bi = sw_ring; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/** 5562306a36Sopenharmony_ci * i40e_realloc_rx_bi_zc - reallocate rx SW rings 5662306a36Sopenharmony_ci * @vsi: Current VSI 5762306a36Sopenharmony_ci * @zc: is zero copy set 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Reallocate buffer for rx_rings that might be used by XSK. 6062306a36Sopenharmony_ci * XDP requires more memory, than rx_buf provides. 6162306a36Sopenharmony_ci * Returns 0 on success, negative on failure 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ciint i40e_realloc_rx_bi_zc(struct i40e_vsi *vsi, bool zc) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct i40e_ring *rx_ring; 6662306a36Sopenharmony_ci unsigned long q; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci for_each_set_bit(q, vsi->af_xdp_zc_qps, vsi->alloc_queue_pairs) { 6962306a36Sopenharmony_ci rx_ring = vsi->rx_rings[q]; 7062306a36Sopenharmony_ci if (i40e_realloc_rx_xdp_bi(rx_ring, zc)) 7162306a36Sopenharmony_ci return -ENOMEM; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/** 7762306a36Sopenharmony_ci * i40e_xsk_pool_enable - Enable/associate an AF_XDP buffer pool to a 7862306a36Sopenharmony_ci * certain ring/qid 7962306a36Sopenharmony_ci * @vsi: Current VSI 8062306a36Sopenharmony_ci * @pool: buffer pool 8162306a36Sopenharmony_ci * @qid: Rx ring to associate buffer pool with 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * Returns 0 on success, <0 on failure 8462306a36Sopenharmony_ci **/ 8562306a36Sopenharmony_cistatic int i40e_xsk_pool_enable(struct i40e_vsi *vsi, 8662306a36Sopenharmony_ci struct xsk_buff_pool *pool, 8762306a36Sopenharmony_ci u16 qid) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct net_device *netdev = vsi->netdev; 9062306a36Sopenharmony_ci bool if_running; 9162306a36Sopenharmony_ci int err; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (vsi->type != I40E_VSI_MAIN) 9462306a36Sopenharmony_ci return -EINVAL; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (qid >= vsi->num_queue_pairs) 9762306a36Sopenharmony_ci return -EINVAL; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (qid >= netdev->real_num_rx_queues || 10062306a36Sopenharmony_ci qid >= netdev->real_num_tx_queues) 10162306a36Sopenharmony_ci return -EINVAL; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci err = xsk_pool_dma_map(pool, &vsi->back->pdev->dev, I40E_RX_DMA_ATTR); 10462306a36Sopenharmony_ci if (err) 10562306a36Sopenharmony_ci return err; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci set_bit(qid, vsi->af_xdp_zc_qps); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (if_running) { 11262306a36Sopenharmony_ci err = i40e_queue_pair_disable(vsi, qid); 11362306a36Sopenharmony_ci if (err) 11462306a36Sopenharmony_ci return err; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], true); 11762306a36Sopenharmony_ci if (err) 11862306a36Sopenharmony_ci return err; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci err = i40e_queue_pair_enable(vsi, qid); 12162306a36Sopenharmony_ci if (err) 12262306a36Sopenharmony_ci return err; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Kick start the NAPI context so that receiving will start */ 12562306a36Sopenharmony_ci err = i40e_xsk_wakeup(vsi->netdev, qid, XDP_WAKEUP_RX); 12662306a36Sopenharmony_ci if (err) 12762306a36Sopenharmony_ci return err; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/** 13462306a36Sopenharmony_ci * i40e_xsk_pool_disable - Disassociate an AF_XDP buffer pool from a 13562306a36Sopenharmony_ci * certain ring/qid 13662306a36Sopenharmony_ci * @vsi: Current VSI 13762306a36Sopenharmony_ci * @qid: Rx ring to associate buffer pool with 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Returns 0 on success, <0 on failure 14062306a36Sopenharmony_ci **/ 14162306a36Sopenharmony_cistatic int i40e_xsk_pool_disable(struct i40e_vsi *vsi, u16 qid) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct net_device *netdev = vsi->netdev; 14462306a36Sopenharmony_ci struct xsk_buff_pool *pool; 14562306a36Sopenharmony_ci bool if_running; 14662306a36Sopenharmony_ci int err; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci pool = xsk_get_pool_from_qid(netdev, qid); 14962306a36Sopenharmony_ci if (!pool) 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if_running = netif_running(vsi->netdev) && i40e_enabled_xdp_vsi(vsi); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (if_running) { 15562306a36Sopenharmony_ci err = i40e_queue_pair_disable(vsi, qid); 15662306a36Sopenharmony_ci if (err) 15762306a36Sopenharmony_ci return err; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci clear_bit(qid, vsi->af_xdp_zc_qps); 16162306a36Sopenharmony_ci xsk_pool_dma_unmap(pool, I40E_RX_DMA_ATTR); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (if_running) { 16462306a36Sopenharmony_ci err = i40e_realloc_rx_xdp_bi(vsi->rx_rings[qid], false); 16562306a36Sopenharmony_ci if (err) 16662306a36Sopenharmony_ci return err; 16762306a36Sopenharmony_ci err = i40e_queue_pair_enable(vsi, qid); 16862306a36Sopenharmony_ci if (err) 16962306a36Sopenharmony_ci return err; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/** 17662306a36Sopenharmony_ci * i40e_xsk_pool_setup - Enable/disassociate an AF_XDP buffer pool to/from 17762306a36Sopenharmony_ci * a ring/qid 17862306a36Sopenharmony_ci * @vsi: Current VSI 17962306a36Sopenharmony_ci * @pool: Buffer pool to enable/associate to a ring, or NULL to disable 18062306a36Sopenharmony_ci * @qid: Rx ring to (dis)associate buffer pool (from)to 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * This function enables or disables a buffer pool to a certain ring. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Returns 0 on success, <0 on failure 18562306a36Sopenharmony_ci **/ 18662306a36Sopenharmony_ciint i40e_xsk_pool_setup(struct i40e_vsi *vsi, struct xsk_buff_pool *pool, 18762306a36Sopenharmony_ci u16 qid) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci return pool ? i40e_xsk_pool_enable(vsi, pool, qid) : 19062306a36Sopenharmony_ci i40e_xsk_pool_disable(vsi, qid); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * i40e_run_xdp_zc - Executes an XDP program on an xdp_buff 19562306a36Sopenharmony_ci * @rx_ring: Rx ring 19662306a36Sopenharmony_ci * @xdp: xdp_buff used as input to the XDP program 19762306a36Sopenharmony_ci * @xdp_prog: XDP program to run 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Returns any of I40E_XDP_{PASS, CONSUMED, TX, REDIR} 20062306a36Sopenharmony_ci **/ 20162306a36Sopenharmony_cistatic int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp, 20262306a36Sopenharmony_ci struct bpf_prog *xdp_prog) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci int err, result = I40E_XDP_PASS; 20562306a36Sopenharmony_ci struct i40e_ring *xdp_ring; 20662306a36Sopenharmony_ci u32 act; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci act = bpf_prog_run_xdp(xdp_prog, xdp); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (likely(act == XDP_REDIRECT)) { 21162306a36Sopenharmony_ci err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); 21262306a36Sopenharmony_ci if (!err) 21362306a36Sopenharmony_ci return I40E_XDP_REDIR; 21462306a36Sopenharmony_ci if (xsk_uses_need_wakeup(rx_ring->xsk_pool) && err == -ENOBUFS) 21562306a36Sopenharmony_ci result = I40E_XDP_EXIT; 21662306a36Sopenharmony_ci else 21762306a36Sopenharmony_ci result = I40E_XDP_CONSUMED; 21862306a36Sopenharmony_ci goto out_failure; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci switch (act) { 22262306a36Sopenharmony_ci case XDP_PASS: 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case XDP_TX: 22562306a36Sopenharmony_ci xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index]; 22662306a36Sopenharmony_ci result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring); 22762306a36Sopenharmony_ci if (result == I40E_XDP_CONSUMED) 22862306a36Sopenharmony_ci goto out_failure; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci case XDP_DROP: 23162306a36Sopenharmony_ci result = I40E_XDP_CONSUMED; 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci default: 23462306a36Sopenharmony_ci bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, act); 23562306a36Sopenharmony_ci fallthrough; 23662306a36Sopenharmony_ci case XDP_ABORTED: 23762306a36Sopenharmony_ci result = I40E_XDP_CONSUMED; 23862306a36Sopenharmony_ciout_failure: 23962306a36Sopenharmony_ci trace_xdp_exception(rx_ring->netdev, xdp_prog, act); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci return result; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cibool i40e_alloc_rx_buffers_zc(struct i40e_ring *rx_ring, u16 count) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci u16 ntu = rx_ring->next_to_use; 24762306a36Sopenharmony_ci union i40e_rx_desc *rx_desc; 24862306a36Sopenharmony_ci struct xdp_buff **xdp; 24962306a36Sopenharmony_ci u32 nb_buffs, i; 25062306a36Sopenharmony_ci dma_addr_t dma; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, ntu); 25362306a36Sopenharmony_ci xdp = i40e_rx_bi(rx_ring, ntu); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci nb_buffs = min_t(u16, count, rx_ring->count - ntu); 25662306a36Sopenharmony_ci nb_buffs = xsk_buff_alloc_batch(rx_ring->xsk_pool, xdp, nb_buffs); 25762306a36Sopenharmony_ci if (!nb_buffs) 25862306a36Sopenharmony_ci return false; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci i = nb_buffs; 26162306a36Sopenharmony_ci while (i--) { 26262306a36Sopenharmony_ci dma = xsk_buff_xdp_get_dma(*xdp); 26362306a36Sopenharmony_ci rx_desc->read.pkt_addr = cpu_to_le64(dma); 26462306a36Sopenharmony_ci rx_desc->read.hdr_addr = 0; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci rx_desc++; 26762306a36Sopenharmony_ci xdp++; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ntu += nb_buffs; 27162306a36Sopenharmony_ci if (ntu == rx_ring->count) { 27262306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, 0); 27362306a36Sopenharmony_ci ntu = 0; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* clear the status bits for the next_to_use descriptor */ 27762306a36Sopenharmony_ci rx_desc->wb.qword1.status_error_len = 0; 27862306a36Sopenharmony_ci i40e_release_rx_desc(rx_ring, ntu); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return count == nb_buffs; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * i40e_construct_skb_zc - Create skbuff from zero-copy Rx buffer 28562306a36Sopenharmony_ci * @rx_ring: Rx ring 28662306a36Sopenharmony_ci * @xdp: xdp_buff 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * This functions allocates a new skb from a zero-copy Rx buffer. 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Returns the skb, or NULL on failure. 29162306a36Sopenharmony_ci **/ 29262306a36Sopenharmony_cistatic struct sk_buff *i40e_construct_skb_zc(struct i40e_ring *rx_ring, 29362306a36Sopenharmony_ci struct xdp_buff *xdp) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci unsigned int totalsize = xdp->data_end - xdp->data_meta; 29662306a36Sopenharmony_ci unsigned int metasize = xdp->data - xdp->data_meta; 29762306a36Sopenharmony_ci struct skb_shared_info *sinfo = NULL; 29862306a36Sopenharmony_ci struct sk_buff *skb; 29962306a36Sopenharmony_ci u32 nr_frags = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (unlikely(xdp_buff_has_frags(xdp))) { 30262306a36Sopenharmony_ci sinfo = xdp_get_shared_info_from_buff(xdp); 30362306a36Sopenharmony_ci nr_frags = sinfo->nr_frags; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci net_prefetch(xdp->data_meta); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* allocate a skb to store the frags */ 30862306a36Sopenharmony_ci skb = __napi_alloc_skb(&rx_ring->q_vector->napi, totalsize, 30962306a36Sopenharmony_ci GFP_ATOMIC | __GFP_NOWARN); 31062306a36Sopenharmony_ci if (unlikely(!skb)) 31162306a36Sopenharmony_ci goto out; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci memcpy(__skb_put(skb, totalsize), xdp->data_meta, 31462306a36Sopenharmony_ci ALIGN(totalsize, sizeof(long))); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (metasize) { 31762306a36Sopenharmony_ci skb_metadata_set(skb, metasize); 31862306a36Sopenharmony_ci __skb_pull(skb, metasize); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (likely(!xdp_buff_has_frags(xdp))) 32262306a36Sopenharmony_ci goto out; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci for (int i = 0; i < nr_frags; i++) { 32562306a36Sopenharmony_ci struct skb_shared_info *skinfo = skb_shinfo(skb); 32662306a36Sopenharmony_ci skb_frag_t *frag = &sinfo->frags[i]; 32762306a36Sopenharmony_ci struct page *page; 32862306a36Sopenharmony_ci void *addr; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci page = dev_alloc_page(); 33162306a36Sopenharmony_ci if (!page) { 33262306a36Sopenharmony_ci dev_kfree_skb(skb); 33362306a36Sopenharmony_ci return NULL; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci addr = page_to_virt(page); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci memcpy(addr, skb_frag_page(frag), skb_frag_size(frag)); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci __skb_fill_page_desc_noacc(skinfo, skinfo->nr_frags++, 34062306a36Sopenharmony_ci addr, 0, skb_frag_size(frag)); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciout: 34462306a36Sopenharmony_ci xsk_buff_free(xdp); 34562306a36Sopenharmony_ci return skb; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic void i40e_handle_xdp_result_zc(struct i40e_ring *rx_ring, 34962306a36Sopenharmony_ci struct xdp_buff *xdp_buff, 35062306a36Sopenharmony_ci union i40e_rx_desc *rx_desc, 35162306a36Sopenharmony_ci unsigned int *rx_packets, 35262306a36Sopenharmony_ci unsigned int *rx_bytes, 35362306a36Sopenharmony_ci unsigned int xdp_res, 35462306a36Sopenharmony_ci bool *failure) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct sk_buff *skb; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci *rx_packets = 1; 35962306a36Sopenharmony_ci *rx_bytes = xdp_get_buff_len(xdp_buff); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (likely(xdp_res == I40E_XDP_REDIR) || xdp_res == I40E_XDP_TX) 36262306a36Sopenharmony_ci return; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (xdp_res == I40E_XDP_EXIT) { 36562306a36Sopenharmony_ci *failure = true; 36662306a36Sopenharmony_ci return; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (xdp_res == I40E_XDP_CONSUMED) { 37062306a36Sopenharmony_ci xsk_buff_free(xdp_buff); 37162306a36Sopenharmony_ci return; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci if (xdp_res == I40E_XDP_PASS) { 37462306a36Sopenharmony_ci /* NB! We are not checking for errors using 37562306a36Sopenharmony_ci * i40e_test_staterr with 37662306a36Sopenharmony_ci * BIT(I40E_RXD_QW1_ERROR_SHIFT). This is due to that 37762306a36Sopenharmony_ci * SBP is *not* set in PRT_SBPVSI (default not set). 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci skb = i40e_construct_skb_zc(rx_ring, xdp_buff); 38062306a36Sopenharmony_ci if (!skb) { 38162306a36Sopenharmony_ci rx_ring->rx_stats.alloc_buff_failed++; 38262306a36Sopenharmony_ci *rx_packets = 0; 38362306a36Sopenharmony_ci *rx_bytes = 0; 38462306a36Sopenharmony_ci return; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (eth_skb_pad(skb)) { 38862306a36Sopenharmony_ci *rx_packets = 0; 38962306a36Sopenharmony_ci *rx_bytes = 0; 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci i40e_process_skb_fields(rx_ring, rx_desc, skb); 39462306a36Sopenharmony_ci napi_gro_receive(&rx_ring->q_vector->napi, skb); 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Should never get here, as all valid cases have been handled already. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci WARN_ON_ONCE(1); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int 40462306a36Sopenharmony_cii40e_add_xsk_frag(struct i40e_ring *rx_ring, struct xdp_buff *first, 40562306a36Sopenharmony_ci struct xdp_buff *xdp, const unsigned int size) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(first); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!xdp_buff_has_frags(first)) { 41062306a36Sopenharmony_ci sinfo->nr_frags = 0; 41162306a36Sopenharmony_ci sinfo->xdp_frags_size = 0; 41262306a36Sopenharmony_ci xdp_buff_set_frags_flag(first); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) { 41662306a36Sopenharmony_ci xsk_buff_free(first); 41762306a36Sopenharmony_ci return -ENOMEM; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, 42162306a36Sopenharmony_ci virt_to_page(xdp->data_hard_start), 42262306a36Sopenharmony_ci XDP_PACKET_HEADROOM, size); 42362306a36Sopenharmony_ci sinfo->xdp_frags_size += size; 42462306a36Sopenharmony_ci xsk_buff_add_frag(xdp); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * i40e_clean_rx_irq_zc - Consumes Rx packets from the hardware ring 43162306a36Sopenharmony_ci * @rx_ring: Rx ring 43262306a36Sopenharmony_ci * @budget: NAPI budget 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Returns amount of work completed 43562306a36Sopenharmony_ci **/ 43662306a36Sopenharmony_ciint i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci unsigned int total_rx_bytes = 0, total_rx_packets = 0; 43962306a36Sopenharmony_ci u16 next_to_process = rx_ring->next_to_process; 44062306a36Sopenharmony_ci u16 next_to_clean = rx_ring->next_to_clean; 44162306a36Sopenharmony_ci unsigned int xdp_res, xdp_xmit = 0; 44262306a36Sopenharmony_ci struct xdp_buff *first = NULL; 44362306a36Sopenharmony_ci u32 count = rx_ring->count; 44462306a36Sopenharmony_ci struct bpf_prog *xdp_prog; 44562306a36Sopenharmony_ci u32 entries_to_alloc; 44662306a36Sopenharmony_ci bool failure = false; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (next_to_process != next_to_clean) 44962306a36Sopenharmony_ci first = *i40e_rx_bi(rx_ring, next_to_clean); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* NB! xdp_prog will always be !NULL, due to the fact that 45262306a36Sopenharmony_ci * this path is enabled by setting an XDP program. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci xdp_prog = READ_ONCE(rx_ring->xdp_prog); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci while (likely(total_rx_packets < (unsigned int)budget)) { 45762306a36Sopenharmony_ci union i40e_rx_desc *rx_desc; 45862306a36Sopenharmony_ci unsigned int rx_packets; 45962306a36Sopenharmony_ci unsigned int rx_bytes; 46062306a36Sopenharmony_ci struct xdp_buff *bi; 46162306a36Sopenharmony_ci unsigned int size; 46262306a36Sopenharmony_ci u64 qword; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci rx_desc = I40E_RX_DESC(rx_ring, next_to_process); 46562306a36Sopenharmony_ci qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* This memory barrier is needed to keep us from reading 46862306a36Sopenharmony_ci * any other fields out of the rx_desc until we have 46962306a36Sopenharmony_ci * verified the descriptor has been written back. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci dma_rmb(); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (i40e_rx_is_programming_status(qword)) { 47462306a36Sopenharmony_ci i40e_clean_programming_status(rx_ring, 47562306a36Sopenharmony_ci rx_desc->raw.qword[0], 47662306a36Sopenharmony_ci qword); 47762306a36Sopenharmony_ci bi = *i40e_rx_bi(rx_ring, next_to_process); 47862306a36Sopenharmony_ci xsk_buff_free(bi); 47962306a36Sopenharmony_ci if (++next_to_process == count) 48062306a36Sopenharmony_ci next_to_process = 0; 48162306a36Sopenharmony_ci continue; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> 48562306a36Sopenharmony_ci I40E_RXD_QW1_LENGTH_PBUF_SHIFT; 48662306a36Sopenharmony_ci if (!size) 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci bi = *i40e_rx_bi(rx_ring, next_to_process); 49062306a36Sopenharmony_ci xsk_buff_set_size(bi, size); 49162306a36Sopenharmony_ci xsk_buff_dma_sync_for_cpu(bi, rx_ring->xsk_pool); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!first) 49462306a36Sopenharmony_ci first = bi; 49562306a36Sopenharmony_ci else if (i40e_add_xsk_frag(rx_ring, first, bi, size)) 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (++next_to_process == count) 49962306a36Sopenharmony_ci next_to_process = 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (i40e_is_non_eop(rx_ring, rx_desc)) 50262306a36Sopenharmony_ci continue; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog); 50562306a36Sopenharmony_ci i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets, 50662306a36Sopenharmony_ci &rx_bytes, xdp_res, &failure); 50762306a36Sopenharmony_ci next_to_clean = next_to_process; 50862306a36Sopenharmony_ci if (failure) 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci total_rx_packets += rx_packets; 51162306a36Sopenharmony_ci total_rx_bytes += rx_bytes; 51262306a36Sopenharmony_ci xdp_xmit |= xdp_res & (I40E_XDP_TX | I40E_XDP_REDIR); 51362306a36Sopenharmony_ci first = NULL; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci rx_ring->next_to_clean = next_to_clean; 51762306a36Sopenharmony_ci rx_ring->next_to_process = next_to_process; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci entries_to_alloc = I40E_DESC_UNUSED(rx_ring); 52062306a36Sopenharmony_ci if (entries_to_alloc >= I40E_RX_BUFFER_WRITE) 52162306a36Sopenharmony_ci failure |= !i40e_alloc_rx_buffers_zc(rx_ring, entries_to_alloc); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci i40e_finalize_xdp_rx(rx_ring, xdp_xmit); 52462306a36Sopenharmony_ci i40e_update_rx_stats(rx_ring, total_rx_bytes, total_rx_packets); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (xsk_uses_need_wakeup(rx_ring->xsk_pool)) { 52762306a36Sopenharmony_ci if (failure || next_to_clean == rx_ring->next_to_use) 52862306a36Sopenharmony_ci xsk_set_rx_need_wakeup(rx_ring->xsk_pool); 52962306a36Sopenharmony_ci else 53062306a36Sopenharmony_ci xsk_clear_rx_need_wakeup(rx_ring->xsk_pool); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return (int)total_rx_packets; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci return failure ? budget : (int)total_rx_packets; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void i40e_xmit_pkt(struct i40e_ring *xdp_ring, struct xdp_desc *desc, 53862306a36Sopenharmony_ci unsigned int *total_bytes) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci u32 cmd = I40E_TX_DESC_CMD_ICRC | xsk_is_eop_desc(desc); 54162306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 54262306a36Sopenharmony_ci dma_addr_t dma; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci dma = xsk_buff_raw_get_dma(xdp_ring->xsk_pool, desc->addr); 54562306a36Sopenharmony_ci xsk_buff_raw_dma_sync_for_device(xdp_ring->xsk_pool, dma, desc->len); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(xdp_ring, xdp_ring->next_to_use++); 54862306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 54962306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = build_ctob(cmd, 0, desc->len, 0); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci *total_bytes += desc->len; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void i40e_xmit_pkt_batch(struct i40e_ring *xdp_ring, struct xdp_desc *desc, 55562306a36Sopenharmony_ci unsigned int *total_bytes) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci u16 ntu = xdp_ring->next_to_use; 55862306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 55962306a36Sopenharmony_ci dma_addr_t dma; 56062306a36Sopenharmony_ci u32 i; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci loop_unrolled_for(i = 0; i < PKTS_PER_BATCH; i++) { 56362306a36Sopenharmony_ci u32 cmd = I40E_TX_DESC_CMD_ICRC | xsk_is_eop_desc(&desc[i]); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci dma = xsk_buff_raw_get_dma(xdp_ring->xsk_pool, desc[i].addr); 56662306a36Sopenharmony_ci xsk_buff_raw_dma_sync_for_device(xdp_ring->xsk_pool, dma, desc[i].len); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(xdp_ring, ntu++); 56962306a36Sopenharmony_ci tx_desc->buffer_addr = cpu_to_le64(dma); 57062306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz = build_ctob(cmd, 0, desc[i].len, 0); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci *total_bytes += desc[i].len; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci xdp_ring->next_to_use = ntu; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void i40e_fill_tx_hw_ring(struct i40e_ring *xdp_ring, struct xdp_desc *descs, u32 nb_pkts, 57962306a36Sopenharmony_ci unsigned int *total_bytes) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci u32 batched, leftover, i; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci batched = nb_pkts & ~(PKTS_PER_BATCH - 1); 58462306a36Sopenharmony_ci leftover = nb_pkts & (PKTS_PER_BATCH - 1); 58562306a36Sopenharmony_ci for (i = 0; i < batched; i += PKTS_PER_BATCH) 58662306a36Sopenharmony_ci i40e_xmit_pkt_batch(xdp_ring, &descs[i], total_bytes); 58762306a36Sopenharmony_ci for (i = batched; i < batched + leftover; i++) 58862306a36Sopenharmony_ci i40e_xmit_pkt(xdp_ring, &descs[i], total_bytes); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic void i40e_set_rs_bit(struct i40e_ring *xdp_ring) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci u16 ntu = xdp_ring->next_to_use ? xdp_ring->next_to_use - 1 : xdp_ring->count - 1; 59462306a36Sopenharmony_ci struct i40e_tx_desc *tx_desc; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci tx_desc = I40E_TX_DESC(xdp_ring, ntu); 59762306a36Sopenharmony_ci tx_desc->cmd_type_offset_bsz |= cpu_to_le64(I40E_TX_DESC_CMD_RS << I40E_TXD_QW1_CMD_SHIFT); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/** 60162306a36Sopenharmony_ci * i40e_xmit_zc - Performs zero-copy Tx AF_XDP 60262306a36Sopenharmony_ci * @xdp_ring: XDP Tx ring 60362306a36Sopenharmony_ci * @budget: NAPI budget 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci * Returns true if the work is finished. 60662306a36Sopenharmony_ci **/ 60762306a36Sopenharmony_cistatic bool i40e_xmit_zc(struct i40e_ring *xdp_ring, unsigned int budget) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct xdp_desc *descs = xdp_ring->xsk_pool->tx_descs; 61062306a36Sopenharmony_ci u32 nb_pkts, nb_processed = 0; 61162306a36Sopenharmony_ci unsigned int total_bytes = 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci nb_pkts = xsk_tx_peek_release_desc_batch(xdp_ring->xsk_pool, budget); 61462306a36Sopenharmony_ci if (!nb_pkts) 61562306a36Sopenharmony_ci return true; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (xdp_ring->next_to_use + nb_pkts >= xdp_ring->count) { 61862306a36Sopenharmony_ci nb_processed = xdp_ring->count - xdp_ring->next_to_use; 61962306a36Sopenharmony_ci i40e_fill_tx_hw_ring(xdp_ring, descs, nb_processed, &total_bytes); 62062306a36Sopenharmony_ci xdp_ring->next_to_use = 0; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci i40e_fill_tx_hw_ring(xdp_ring, &descs[nb_processed], nb_pkts - nb_processed, 62462306a36Sopenharmony_ci &total_bytes); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* Request an interrupt for the last frame and bump tail ptr. */ 62762306a36Sopenharmony_ci i40e_set_rs_bit(xdp_ring); 62862306a36Sopenharmony_ci i40e_xdp_ring_update_tail(xdp_ring); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci i40e_update_tx_stats(xdp_ring, nb_pkts, total_bytes); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return nb_pkts < budget; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/** 63662306a36Sopenharmony_ci * i40e_clean_xdp_tx_buffer - Frees and unmaps an XDP Tx entry 63762306a36Sopenharmony_ci * @tx_ring: XDP Tx ring 63862306a36Sopenharmony_ci * @tx_bi: Tx buffer info to clean 63962306a36Sopenharmony_ci **/ 64062306a36Sopenharmony_cistatic void i40e_clean_xdp_tx_buffer(struct i40e_ring *tx_ring, 64162306a36Sopenharmony_ci struct i40e_tx_buffer *tx_bi) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci xdp_return_frame(tx_bi->xdpf); 64462306a36Sopenharmony_ci tx_ring->xdp_tx_active--; 64562306a36Sopenharmony_ci dma_unmap_single(tx_ring->dev, 64662306a36Sopenharmony_ci dma_unmap_addr(tx_bi, dma), 64762306a36Sopenharmony_ci dma_unmap_len(tx_bi, len), DMA_TO_DEVICE); 64862306a36Sopenharmony_ci dma_unmap_len_set(tx_bi, len, 0); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci/** 65262306a36Sopenharmony_ci * i40e_clean_xdp_tx_irq - Completes AF_XDP entries, and cleans XDP entries 65362306a36Sopenharmony_ci * @vsi: Current VSI 65462306a36Sopenharmony_ci * @tx_ring: XDP Tx ring 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * Returns true if cleanup/transmission is done. 65762306a36Sopenharmony_ci **/ 65862306a36Sopenharmony_cibool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, struct i40e_ring *tx_ring) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct xsk_buff_pool *bp = tx_ring->xsk_pool; 66162306a36Sopenharmony_ci u32 i, completed_frames, xsk_frames = 0; 66262306a36Sopenharmony_ci u32 head_idx = i40e_get_head(tx_ring); 66362306a36Sopenharmony_ci struct i40e_tx_buffer *tx_bi; 66462306a36Sopenharmony_ci unsigned int ntc; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (head_idx < tx_ring->next_to_clean) 66762306a36Sopenharmony_ci head_idx += tx_ring->count; 66862306a36Sopenharmony_ci completed_frames = head_idx - tx_ring->next_to_clean; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (completed_frames == 0) 67162306a36Sopenharmony_ci goto out_xmit; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (likely(!tx_ring->xdp_tx_active)) { 67462306a36Sopenharmony_ci xsk_frames = completed_frames; 67562306a36Sopenharmony_ci goto skip; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ntc = tx_ring->next_to_clean; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci for (i = 0; i < completed_frames; i++) { 68162306a36Sopenharmony_ci tx_bi = &tx_ring->tx_bi[ntc]; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (tx_bi->xdpf) { 68462306a36Sopenharmony_ci i40e_clean_xdp_tx_buffer(tx_ring, tx_bi); 68562306a36Sopenharmony_ci tx_bi->xdpf = NULL; 68662306a36Sopenharmony_ci } else { 68762306a36Sopenharmony_ci xsk_frames++; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (++ntc >= tx_ring->count) 69162306a36Sopenharmony_ci ntc = 0; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ciskip: 69562306a36Sopenharmony_ci tx_ring->next_to_clean += completed_frames; 69662306a36Sopenharmony_ci if (unlikely(tx_ring->next_to_clean >= tx_ring->count)) 69762306a36Sopenharmony_ci tx_ring->next_to_clean -= tx_ring->count; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (xsk_frames) 70062306a36Sopenharmony_ci xsk_tx_completed(bp, xsk_frames); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci i40e_arm_wb(tx_ring, vsi, completed_frames); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ciout_xmit: 70562306a36Sopenharmony_ci if (xsk_uses_need_wakeup(tx_ring->xsk_pool)) 70662306a36Sopenharmony_ci xsk_set_tx_need_wakeup(tx_ring->xsk_pool); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return i40e_xmit_zc(tx_ring, I40E_DESC_UNUSED(tx_ring)); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/** 71262306a36Sopenharmony_ci * i40e_xsk_wakeup - Implements the ndo_xsk_wakeup 71362306a36Sopenharmony_ci * @dev: the netdevice 71462306a36Sopenharmony_ci * @queue_id: queue id to wake up 71562306a36Sopenharmony_ci * @flags: ignored in our case since we have Rx and Tx in the same NAPI. 71662306a36Sopenharmony_ci * 71762306a36Sopenharmony_ci * Returns <0 for errors, 0 otherwise. 71862306a36Sopenharmony_ci **/ 71962306a36Sopenharmony_ciint i40e_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct i40e_netdev_priv *np = netdev_priv(dev); 72262306a36Sopenharmony_ci struct i40e_vsi *vsi = np->vsi; 72362306a36Sopenharmony_ci struct i40e_pf *pf = vsi->back; 72462306a36Sopenharmony_ci struct i40e_ring *ring; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (test_bit(__I40E_CONFIG_BUSY, pf->state)) 72762306a36Sopenharmony_ci return -EAGAIN; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (test_bit(__I40E_VSI_DOWN, vsi->state)) 73062306a36Sopenharmony_ci return -ENETDOWN; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (!i40e_enabled_xdp_vsi(vsi)) 73362306a36Sopenharmony_ci return -EINVAL; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (queue_id >= vsi->num_queue_pairs) 73662306a36Sopenharmony_ci return -EINVAL; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!vsi->xdp_rings[queue_id]->xsk_pool) 73962306a36Sopenharmony_ci return -EINVAL; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ring = vsi->xdp_rings[queue_id]; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* The idea here is that if NAPI is running, mark a miss, so 74462306a36Sopenharmony_ci * it will run again. If not, trigger an interrupt and 74562306a36Sopenharmony_ci * schedule the NAPI from interrupt context. If NAPI would be 74662306a36Sopenharmony_ci * scheduled here, the interrupt affinity would not be 74762306a36Sopenharmony_ci * honored. 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) 75062306a36Sopenharmony_ci i40e_force_wb(vsi, ring->q_vector); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_civoid i40e_xsk_clean_rx_ring(struct i40e_ring *rx_ring) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci u16 ntc = rx_ring->next_to_clean; 75862306a36Sopenharmony_ci u16 ntu = rx_ring->next_to_use; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci while (ntc != ntu) { 76162306a36Sopenharmony_ci struct xdp_buff *rx_bi = *i40e_rx_bi(rx_ring, ntc); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci xsk_buff_free(rx_bi); 76462306a36Sopenharmony_ci ntc++; 76562306a36Sopenharmony_ci if (ntc >= rx_ring->count) 76662306a36Sopenharmony_ci ntc = 0; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci/** 77162306a36Sopenharmony_ci * i40e_xsk_clean_tx_ring - Clean the XDP Tx ring on shutdown 77262306a36Sopenharmony_ci * @tx_ring: XDP Tx ring 77362306a36Sopenharmony_ci **/ 77462306a36Sopenharmony_civoid i40e_xsk_clean_tx_ring(struct i40e_ring *tx_ring) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci u16 ntc = tx_ring->next_to_clean, ntu = tx_ring->next_to_use; 77762306a36Sopenharmony_ci struct xsk_buff_pool *bp = tx_ring->xsk_pool; 77862306a36Sopenharmony_ci struct i40e_tx_buffer *tx_bi; 77962306a36Sopenharmony_ci u32 xsk_frames = 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci while (ntc != ntu) { 78262306a36Sopenharmony_ci tx_bi = &tx_ring->tx_bi[ntc]; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (tx_bi->xdpf) 78562306a36Sopenharmony_ci i40e_clean_xdp_tx_buffer(tx_ring, tx_bi); 78662306a36Sopenharmony_ci else 78762306a36Sopenharmony_ci xsk_frames++; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci tx_bi->xdpf = NULL; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ntc++; 79262306a36Sopenharmony_ci if (ntc >= tx_ring->count) 79362306a36Sopenharmony_ci ntc = 0; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (xsk_frames) 79762306a36Sopenharmony_ci xsk_tx_completed(bp, xsk_frames); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci/** 80162306a36Sopenharmony_ci * i40e_xsk_any_rx_ring_enabled - Checks if Rx rings have an AF_XDP 80262306a36Sopenharmony_ci * buffer pool attached 80362306a36Sopenharmony_ci * @vsi: vsi 80462306a36Sopenharmony_ci * 80562306a36Sopenharmony_ci * Returns true if any of the Rx rings has an AF_XDP buffer pool attached 80662306a36Sopenharmony_ci **/ 80762306a36Sopenharmony_cibool i40e_xsk_any_rx_ring_enabled(struct i40e_vsi *vsi) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct net_device *netdev = vsi->netdev; 81062306a36Sopenharmony_ci int i; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci for (i = 0; i < vsi->num_queue_pairs; i++) { 81362306a36Sopenharmony_ci if (xsk_get_pool_from_qid(netdev, i)) 81462306a36Sopenharmony_ci return true; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return false; 81862306a36Sopenharmony_ci} 819