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