162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2018 Netronome Systems, Inc */ 362306a36Sopenharmony_ci/* Copyright (C) 2021 Corigine, Inc */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/bpf_trace.h> 662306a36Sopenharmony_ci#include <linux/netdevice.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "../nfp_app.h" 962306a36Sopenharmony_ci#include "../nfp_net.h" 1062306a36Sopenharmony_ci#include "../nfp_net_dp.h" 1162306a36Sopenharmony_ci#include "../nfp_net_xsk.h" 1262306a36Sopenharmony_ci#include "nfd3.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic bool 1562306a36Sopenharmony_cinfp_nfd3_xsk_tx_xdp(const struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, 1662306a36Sopenharmony_ci struct nfp_net_rx_ring *rx_ring, 1762306a36Sopenharmony_ci struct nfp_net_tx_ring *tx_ring, 1862306a36Sopenharmony_ci struct nfp_net_xsk_rx_buf *xrxbuf, unsigned int pkt_len, 1962306a36Sopenharmony_ci int pkt_off) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct xsk_buff_pool *pool = r_vec->xsk_pool; 2262306a36Sopenharmony_ci struct nfp_nfd3_tx_buf *txbuf; 2362306a36Sopenharmony_ci struct nfp_nfd3_tx_desc *txd; 2462306a36Sopenharmony_ci unsigned int wr_idx; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (nfp_net_tx_space(tx_ring) < 1) 2762306a36Sopenharmony_ci return false; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci xsk_buff_raw_dma_sync_for_device(pool, xrxbuf->dma_addr + pkt_off, 3062306a36Sopenharmony_ci pkt_len); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci wr_idx = D_IDX(tx_ring, tx_ring->wr_p); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci txbuf = &tx_ring->txbufs[wr_idx]; 3562306a36Sopenharmony_ci txbuf->xdp = xrxbuf->xdp; 3662306a36Sopenharmony_ci txbuf->real_len = pkt_len; 3762306a36Sopenharmony_ci txbuf->is_xsk_tx = true; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* Build TX descriptor */ 4062306a36Sopenharmony_ci txd = &tx_ring->txds[wr_idx]; 4162306a36Sopenharmony_ci txd->offset_eop = NFD3_DESC_TX_EOP; 4262306a36Sopenharmony_ci txd->dma_len = cpu_to_le16(pkt_len); 4362306a36Sopenharmony_ci nfp_desc_set_dma_addr_40b(txd, xrxbuf->dma_addr + pkt_off); 4462306a36Sopenharmony_ci txd->data_len = cpu_to_le16(pkt_len); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci txd->flags = 0; 4762306a36Sopenharmony_ci txd->mss = 0; 4862306a36Sopenharmony_ci txd->lso_hdrlen = 0; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci tx_ring->wr_ptr_add++; 5162306a36Sopenharmony_ci tx_ring->wr_p++; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return true; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring, 5762306a36Sopenharmony_ci const struct nfp_net_rx_desc *rxd, 5862306a36Sopenharmony_ci struct nfp_net_xsk_rx_buf *xrxbuf, 5962306a36Sopenharmony_ci const struct nfp_meta_parsed *meta, 6062306a36Sopenharmony_ci unsigned int pkt_len, 6162306a36Sopenharmony_ci bool meta_xdp, 6262306a36Sopenharmony_ci unsigned int *skbs_polled) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = rx_ring->r_vec; 6562306a36Sopenharmony_ci struct nfp_net_dp *dp = &r_vec->nfp_net->dp; 6662306a36Sopenharmony_ci struct net_device *netdev; 6762306a36Sopenharmony_ci struct sk_buff *skb; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (likely(!meta->portid)) { 7062306a36Sopenharmony_ci netdev = dp->netdev; 7162306a36Sopenharmony_ci } else { 7262306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dp->netdev); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci netdev = nfp_app_dev_get(nn->app, meta->portid, NULL); 7562306a36Sopenharmony_ci if (unlikely(!netdev)) { 7662306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 7762306a36Sopenharmony_ci return; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci nfp_repr_inc_rx_stats(netdev, pkt_len); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci skb = napi_alloc_skb(&r_vec->napi, pkt_len); 8362306a36Sopenharmony_ci if (!skb) { 8462306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 8562306a36Sopenharmony_ci return; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci skb_put_data(skb, xrxbuf->xdp->data, pkt_len); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci skb->mark = meta->mark; 9062306a36Sopenharmony_ci skb_set_hash(skb, meta->hash, meta->hash_type); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci skb_record_rx_queue(skb, rx_ring->idx); 9362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, netdev); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) { 9862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 9962306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 10062306a36Sopenharmony_ci return; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (meta_xdp) 10462306a36Sopenharmony_ci skb_metadata_set(skb, 10562306a36Sopenharmony_ci xrxbuf->xdp->data - xrxbuf->xdp->data_meta); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci napi_gro_receive(&rx_ring->r_vec->napi, skb); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci nfp_net_xsk_rx_free(xrxbuf); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci (*skbs_polled)++; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic unsigned int 11562306a36Sopenharmony_cinfp_nfd3_xsk_rx(struct nfp_net_rx_ring *rx_ring, int budget, 11662306a36Sopenharmony_ci unsigned int *skbs_polled) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = rx_ring->r_vec; 11962306a36Sopenharmony_ci struct nfp_net_dp *dp = &r_vec->nfp_net->dp; 12062306a36Sopenharmony_ci struct nfp_net_tx_ring *tx_ring; 12162306a36Sopenharmony_ci struct bpf_prog *xdp_prog; 12262306a36Sopenharmony_ci bool xdp_redir = false; 12362306a36Sopenharmony_ci int pkts_polled = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci xdp_prog = READ_ONCE(dp->xdp_prog); 12662306a36Sopenharmony_ci tx_ring = r_vec->xdp_ring; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci while (pkts_polled < budget) { 12962306a36Sopenharmony_ci unsigned int meta_len, data_len, pkt_len, pkt_off; 13062306a36Sopenharmony_ci struct nfp_net_xsk_rx_buf *xrxbuf; 13162306a36Sopenharmony_ci struct nfp_net_rx_desc *rxd; 13262306a36Sopenharmony_ci struct nfp_meta_parsed meta; 13362306a36Sopenharmony_ci int idx, act; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci idx = D_IDX(rx_ring, rx_ring->rd_p); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci rxd = &rx_ring->rxds[idx]; 13862306a36Sopenharmony_ci if (!(rxd->rxd.meta_len_dd & PCIE_DESC_RX_DD)) 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci rx_ring->rd_p++; 14262306a36Sopenharmony_ci pkts_polled++; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci xrxbuf = &rx_ring->xsk_rxbufs[idx]; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* If starved of buffers "drop" it and scream. */ 14762306a36Sopenharmony_ci if (rx_ring->rd_p >= rx_ring->wr_p) { 14862306a36Sopenharmony_ci nn_dp_warn(dp, "Starved of RX buffers\n"); 14962306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Memory barrier to ensure that we won't do other reads 15462306a36Sopenharmony_ci * before the DD bit. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci dma_rmb(); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci memset(&meta, 0, sizeof(meta)); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Only supporting AF_XDP with dynamic metadata so buffer layout 16162306a36Sopenharmony_ci * is always: 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * --------------------------------------------------------- 16462306a36Sopenharmony_ci * | off | metadata | packet | XXXX | 16562306a36Sopenharmony_ci * --------------------------------------------------------- 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci meta_len = rxd->rxd.meta_len_dd & PCIE_DESC_RX_META_LEN_MASK; 16862306a36Sopenharmony_ci data_len = le16_to_cpu(rxd->rxd.data_len); 16962306a36Sopenharmony_ci pkt_len = data_len - meta_len; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (unlikely(meta_len > NFP_NET_MAX_PREPEND)) { 17262306a36Sopenharmony_ci nn_dp_warn(dp, "Oversized RX packet metadata %u\n", 17362306a36Sopenharmony_ci meta_len); 17462306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 17562306a36Sopenharmony_ci continue; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Stats update. */ 17962306a36Sopenharmony_ci u64_stats_update_begin(&r_vec->rx_sync); 18062306a36Sopenharmony_ci r_vec->rx_pkts++; 18162306a36Sopenharmony_ci r_vec->rx_bytes += pkt_len; 18262306a36Sopenharmony_ci u64_stats_update_end(&r_vec->rx_sync); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci xrxbuf->xdp->data += meta_len; 18562306a36Sopenharmony_ci xrxbuf->xdp->data_end = xrxbuf->xdp->data + pkt_len; 18662306a36Sopenharmony_ci xdp_set_data_meta_invalid(xrxbuf->xdp); 18762306a36Sopenharmony_ci xsk_buff_dma_sync_for_cpu(xrxbuf->xdp, r_vec->xsk_pool); 18862306a36Sopenharmony_ci net_prefetch(xrxbuf->xdp->data); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (meta_len) { 19162306a36Sopenharmony_ci if (unlikely(nfp_nfd3_parse_meta(dp->netdev, &meta, 19262306a36Sopenharmony_ci xrxbuf->xdp->data - 19362306a36Sopenharmony_ci meta_len, 19462306a36Sopenharmony_ci xrxbuf->xdp->data, 19562306a36Sopenharmony_ci pkt_len, meta_len))) { 19662306a36Sopenharmony_ci nn_dp_warn(dp, "Invalid RX packet metadata\n"); 19762306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 19862306a36Sopenharmony_ci continue; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (unlikely(meta.portid)) { 20262306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(dp->netdev); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (meta.portid != NFP_META_PORT_ID_CTRL) { 20562306a36Sopenharmony_ci nfp_nfd3_xsk_rx_skb(rx_ring, rxd, 20662306a36Sopenharmony_ci xrxbuf, &meta, 20762306a36Sopenharmony_ci pkt_len, false, 20862306a36Sopenharmony_ci skbs_polled); 20962306a36Sopenharmony_ci continue; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci nfp_app_ctrl_rx_raw(nn->app, xrxbuf->xdp->data, 21362306a36Sopenharmony_ci pkt_len); 21462306a36Sopenharmony_ci nfp_net_xsk_rx_free(xrxbuf); 21562306a36Sopenharmony_ci continue; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci act = bpf_prog_run_xdp(xdp_prog, xrxbuf->xdp); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci pkt_len = xrxbuf->xdp->data_end - xrxbuf->xdp->data; 22262306a36Sopenharmony_ci pkt_off = xrxbuf->xdp->data - xrxbuf->xdp->data_hard_start; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci switch (act) { 22562306a36Sopenharmony_ci case XDP_PASS: 22662306a36Sopenharmony_ci nfp_nfd3_xsk_rx_skb(rx_ring, rxd, xrxbuf, &meta, pkt_len, 22762306a36Sopenharmony_ci true, skbs_polled); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci case XDP_TX: 23062306a36Sopenharmony_ci if (!nfp_nfd3_xsk_tx_xdp(dp, r_vec, rx_ring, tx_ring, 23162306a36Sopenharmony_ci xrxbuf, pkt_len, pkt_off)) 23262306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci nfp_net_xsk_rx_unstash(xrxbuf); 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case XDP_REDIRECT: 23762306a36Sopenharmony_ci if (xdp_do_redirect(dp->netdev, xrxbuf->xdp, xdp_prog)) { 23862306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 23962306a36Sopenharmony_ci } else { 24062306a36Sopenharmony_ci nfp_net_xsk_rx_unstash(xrxbuf); 24162306a36Sopenharmony_ci xdp_redir = true; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci default: 24562306a36Sopenharmony_ci bpf_warn_invalid_xdp_action(dp->netdev, xdp_prog, act); 24662306a36Sopenharmony_ci fallthrough; 24762306a36Sopenharmony_ci case XDP_ABORTED: 24862306a36Sopenharmony_ci trace_xdp_exception(dp->netdev, xdp_prog, act); 24962306a36Sopenharmony_ci fallthrough; 25062306a36Sopenharmony_ci case XDP_DROP: 25162306a36Sopenharmony_ci nfp_net_xsk_rx_drop(r_vec, xrxbuf); 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci nfp_net_xsk_rx_ring_fill_freelist(r_vec->rx_ring); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (xdp_redir) 25962306a36Sopenharmony_ci xdp_do_flush_map(); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (tx_ring->wr_ptr_add) 26262306a36Sopenharmony_ci nfp_net_tx_xmit_more_flush(tx_ring); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return pkts_polled; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid nfp_nfd3_xsk_tx_free(struct nfp_nfd3_tx_buf *txbuf) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci xsk_buff_free(txbuf->xdp); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci txbuf->dma_addr = 0; 27262306a36Sopenharmony_ci txbuf->xdp = NULL; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic bool nfp_nfd3_xsk_complete(struct nfp_net_tx_ring *tx_ring) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = tx_ring->r_vec; 27862306a36Sopenharmony_ci u32 done_pkts = 0, done_bytes = 0, reused = 0; 27962306a36Sopenharmony_ci bool done_all; 28062306a36Sopenharmony_ci int idx, todo; 28162306a36Sopenharmony_ci u32 qcp_rd_p; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (tx_ring->wr_p == tx_ring->rd_p) 28462306a36Sopenharmony_ci return true; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Work out how many descriptors have been transmitted. */ 28762306a36Sopenharmony_ci qcp_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (qcp_rd_p == tx_ring->qcp_rd_p) 29062306a36Sopenharmony_ci return true; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci todo = D_IDX(tx_ring, qcp_rd_p - tx_ring->qcp_rd_p); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci done_all = todo <= NFP_NET_XDP_MAX_COMPLETE; 29562306a36Sopenharmony_ci todo = min(todo, NFP_NET_XDP_MAX_COMPLETE); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci tx_ring->qcp_rd_p = D_IDX(tx_ring, tx_ring->qcp_rd_p + todo); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci done_pkts = todo; 30062306a36Sopenharmony_ci while (todo--) { 30162306a36Sopenharmony_ci struct nfp_nfd3_tx_buf *txbuf; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci idx = D_IDX(tx_ring, tx_ring->rd_p); 30462306a36Sopenharmony_ci tx_ring->rd_p++; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci txbuf = &tx_ring->txbufs[idx]; 30762306a36Sopenharmony_ci if (unlikely(!txbuf->real_len)) 30862306a36Sopenharmony_ci continue; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci done_bytes += txbuf->real_len; 31162306a36Sopenharmony_ci txbuf->real_len = 0; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (txbuf->is_xsk_tx) { 31462306a36Sopenharmony_ci nfp_nfd3_xsk_tx_free(txbuf); 31562306a36Sopenharmony_ci reused++; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci u64_stats_update_begin(&r_vec->tx_sync); 32062306a36Sopenharmony_ci r_vec->tx_bytes += done_bytes; 32162306a36Sopenharmony_ci r_vec->tx_pkts += done_pkts; 32262306a36Sopenharmony_ci u64_stats_update_end(&r_vec->tx_sync); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci xsk_tx_completed(r_vec->xsk_pool, done_pkts - reused); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci WARN_ONCE(tx_ring->wr_p - tx_ring->rd_p > tx_ring->cnt, 32762306a36Sopenharmony_ci "XDP TX ring corruption rd_p=%u wr_p=%u cnt=%u\n", 32862306a36Sopenharmony_ci tx_ring->rd_p, tx_ring->wr_p, tx_ring->cnt); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return done_all; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void nfp_nfd3_xsk_tx(struct nfp_net_tx_ring *tx_ring) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = tx_ring->r_vec; 33662306a36Sopenharmony_ci struct xdp_desc desc[NFP_NET_XSK_TX_BATCH]; 33762306a36Sopenharmony_ci struct xsk_buff_pool *xsk_pool; 33862306a36Sopenharmony_ci struct nfp_nfd3_tx_desc *txd; 33962306a36Sopenharmony_ci u32 pkts = 0, wr_idx; 34062306a36Sopenharmony_ci u32 i, got; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci xsk_pool = r_vec->xsk_pool; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci while (nfp_net_tx_space(tx_ring) >= NFP_NET_XSK_TX_BATCH) { 34562306a36Sopenharmony_ci for (i = 0; i < NFP_NET_XSK_TX_BATCH; i++) 34662306a36Sopenharmony_ci if (!xsk_tx_peek_desc(xsk_pool, &desc[i])) 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci got = i; 34962306a36Sopenharmony_ci if (!got) 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci wr_idx = D_IDX(tx_ring, tx_ring->wr_p + i); 35362306a36Sopenharmony_ci prefetchw(&tx_ring->txds[wr_idx]); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci for (i = 0; i < got; i++) 35662306a36Sopenharmony_ci xsk_buff_raw_dma_sync_for_device(xsk_pool, desc[i].addr, 35762306a36Sopenharmony_ci desc[i].len); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci for (i = 0; i < got; i++) { 36062306a36Sopenharmony_ci wr_idx = D_IDX(tx_ring, tx_ring->wr_p + i); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci tx_ring->txbufs[wr_idx].real_len = desc[i].len; 36362306a36Sopenharmony_ci tx_ring->txbufs[wr_idx].is_xsk_tx = false; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Build TX descriptor. */ 36662306a36Sopenharmony_ci txd = &tx_ring->txds[wr_idx]; 36762306a36Sopenharmony_ci nfp_desc_set_dma_addr_40b(txd, 36862306a36Sopenharmony_ci xsk_buff_raw_get_dma(xsk_pool, desc[i].addr)); 36962306a36Sopenharmony_ci txd->offset_eop = NFD3_DESC_TX_EOP; 37062306a36Sopenharmony_ci txd->dma_len = cpu_to_le16(desc[i].len); 37162306a36Sopenharmony_ci txd->data_len = cpu_to_le16(desc[i].len); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci tx_ring->wr_p += got; 37562306a36Sopenharmony_ci pkts += got; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!pkts) 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci xsk_tx_release(xsk_pool); 38262306a36Sopenharmony_ci /* Ensure all records are visible before incrementing write counter. */ 38362306a36Sopenharmony_ci wmb(); 38462306a36Sopenharmony_ci nfp_qcp_wr_ptr_add(tx_ring->qcp_q, pkts); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciint nfp_nfd3_xsk_poll(struct napi_struct *napi, int budget) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct nfp_net_r_vector *r_vec = 39062306a36Sopenharmony_ci container_of(napi, struct nfp_net_r_vector, napi); 39162306a36Sopenharmony_ci unsigned int pkts_polled, skbs = 0; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci pkts_polled = nfp_nfd3_xsk_rx(r_vec->rx_ring, budget, &skbs); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (pkts_polled < budget) { 39662306a36Sopenharmony_ci if (r_vec->tx_ring) 39762306a36Sopenharmony_ci nfp_nfd3_tx_complete(r_vec->tx_ring, budget); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (!nfp_nfd3_xsk_complete(r_vec->xdp_ring)) 40062306a36Sopenharmony_ci pkts_polled = budget; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci nfp_nfd3_xsk_tx(r_vec->xdp_ring); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (pkts_polled < budget && napi_complete_done(napi, skbs)) 40562306a36Sopenharmony_ci nfp_net_irq_unmask(r_vec->nfp_net, r_vec->irq_entry); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return pkts_polled; 40962306a36Sopenharmony_ci} 410