Yikes, ran git format-patch one patch too soon. There's also a hidden, bonus patch "12/11" below. Doesn't affect first 11 patches in any way, though. Here it is. >From f7f10232622309d66a7a1ae1932d0c081936d546 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean <vladimir.oltean@xxxxxxx> Date: Tue, 25 Oct 2022 02:32:24 +0300 Subject: [RFC PATCH net-next 12/12] net: enetc: add support for XDP_TX with zero-copy XDP sockets Add support for the case when the BPF program attached to a ring with an XSK pool returns the XDP_TX verdict. The frame needs to go back on the interface it came from. No dma_map or dma_sync_for_device is necessary, just a small impedance matching logic with the XDP_TX procedure we have in place for non-XSK, since the data structures are different (xdp_buff vs xdp_frame; cannot have multi-buffer with XSK). In the TX confirmation routine, just release the RX buffer (as opposed to non-XSK XDP_TX). Recycling might be possible, but I haven't experimented with it. Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx> --- drivers/net/ethernet/freescale/enetc/enetc.c | 35 ++++++++++++++++++-- drivers/net/ethernet/freescale/enetc/enetc.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index bc0db788afc7..06aaf0334dc3 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -855,7 +855,9 @@ static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget, tx_win_drop++; } - if (tx_swbd->is_xsk) + if (tx_swbd->is_xsk && tx_swbd->is_xdp_tx) + xsk_buff_free(tx_swbd->xsk_buff); + else if (tx_swbd->is_xsk) (*xsk_confirmed)++; else if (tx_swbd->is_xdp_tx) enetc_recycle_xdp_tx_buff(tx_ring, tx_swbd); @@ -1661,6 +1663,21 @@ static int enetc_rx_swbd_to_xdp_tx_swbd(struct enetc_tx_swbd *xdp_tx_arr, return n; } +static bool enetc_xsk_xdp_tx(struct enetc_bdr *tx_ring, + struct xdp_buff *xsk_buff) +{ + struct enetc_tx_swbd tx_swbd = { + .dma = xsk_buff_xdp_get_dma(xsk_buff), + .len = xdp_get_buff_len(xsk_buff), + .is_xdp_tx = true, + .is_xsk = true, + .is_eof = true, + .xsk_buff = xsk_buff, + }; + + return enetc_xdp_tx(tx_ring, &tx_swbd, 1); +} + static void enetc_xdp_drop(struct enetc_bdr *rx_ring, int rx_ring_first, int rx_ring_last) { @@ -1839,10 +1856,12 @@ static int enetc_clean_rx_ring_xsk(struct enetc_bdr *rx_ring, struct bpf_prog *prog, struct xsk_buff_pool *pool) { + struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev); + struct enetc_bdr *tx_ring = priv->xdp_tx_ring[rx_ring->index]; + int xdp_redirect_frm_cnt = 0, xdp_tx_frm_cnt = 0; struct net_device *ndev = rx_ring->ndev; union enetc_rx_bd *rxbd, *orig_rxbd; int rx_frm_cnt = 0, rx_byte_cnt = 0; - int xdp_redirect_frm_cnt = 0; struct xdp_buff *xsk_buff; int buffs_missing, err, i; bool wakeup_xsk = false; @@ -1895,6 +1914,15 @@ static int enetc_clean_rx_ring_xsk(struct enetc_bdr *rx_ring, enetc_xsk_buff_to_skb(xsk_buff, rx_ring, orig_rxbd, napi); break; + case XDP_TX: + if (enetc_xsk_xdp_tx(tx_ring, xsk_buff)) { + xdp_tx_frm_cnt++; + tx_ring->stats.xdp_tx++; + } else { + xsk_buff_free(xsk_buff); + tx_ring->stats.xdp_tx_drops++; + } + break; case XDP_REDIRECT: err = xdp_do_redirect(ndev, xsk_buff, prog); if (unlikely(err)) { @@ -1919,6 +1947,9 @@ static int enetc_clean_rx_ring_xsk(struct enetc_bdr *rx_ring, if (xdp_redirect_frm_cnt) xdp_do_flush_map(); + if (xdp_tx_frm_cnt) + enetc_update_tx_ring_tail(tx_ring); + if (xsk_uses_need_wakeup(pool)) { if (wakeup_xsk) xsk_set_rx_need_wakeup(pool); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index 403f40473b52..58df6c32cfb3 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -24,6 +24,7 @@ struct enetc_tx_swbd { union { struct sk_buff *skb; struct xdp_frame *xdp_frame; + struct xdp_buff *xsk_buff; }; dma_addr_t dma; struct page *page; /* valid only if is_xdp_tx */ -- 2.34.1