// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (C) 2018 Netronome Systems, Inc */ /* Copyright (C) 2021 Corigine, Inc */ #include #include #include #include #include #include "nfp_app.h" #include "nfp_net.h" #include "nfp_net_dp.h" #include "nfp_net_xsk.h" static void nfp_net_xsk_rx_bufs_stash(struct nfp_net_rx_ring *rx_ring, unsigned int idx, struct xdp_buff *xdp) { unsigned int headroom; headroom = xsk_pool_get_headroom(rx_ring->r_vec->xsk_pool); rx_ring->rxds[idx].fld.reserved = 0; rx_ring->rxds[idx].fld.meta_len_dd = 0; rx_ring->xsk_rxbufs[idx].xdp = xdp; rx_ring->xsk_rxbufs[idx].dma_addr = xsk_buff_xdp_get_frame_dma(xdp) + headroom; } void nfp_net_xsk_rx_unstash(struct nfp_net_xsk_rx_buf *rxbuf) { rxbuf->dma_addr = 0; rxbuf->xdp = NULL; } void nfp_net_xsk_rx_free(struct nfp_net_xsk_rx_buf *rxbuf) { if (rxbuf->xdp) xsk_buff_free(rxbuf->xdp); nfp_net_xsk_rx_unstash(rxbuf); } void nfp_net_xsk_rx_bufs_free(struct nfp_net_rx_ring *rx_ring) { unsigned int i; if (!rx_ring->cnt) return; for (i = 0; i < rx_ring->cnt - 1; i++) nfp_net_xsk_rx_free(&rx_ring->xsk_rxbufs[i]); } void nfp_net_xsk_rx_ring_fill_freelist(struct nfp_net_rx_ring *rx_ring) { struct nfp_net_r_vector *r_vec = rx_ring->r_vec; struct xsk_buff_pool *pool = r_vec->xsk_pool; unsigned int wr_idx, wr_ptr_add = 0; struct xdp_buff *xdp; while (nfp_net_rx_space(rx_ring)) { wr_idx = D_IDX(rx_ring, rx_ring->wr_p); xdp = xsk_buff_alloc(pool); if (!xdp) break; nfp_net_xsk_rx_bufs_stash(rx_ring, wr_idx, xdp); /* DMA address is expanded to 48-bit width in freelist for NFP3800, * so the *_48b macro is used accordingly, it's also OK to fill * a 40-bit address since the top 8 bits are get set to 0. */ nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld, rx_ring->xsk_rxbufs[wr_idx].dma_addr); rx_ring->wr_p++; wr_ptr_add++; } /* Ensure all records are visible before incrementing write counter. */ wmb(); nfp_qcp_wr_ptr_add(rx_ring->qcp_fl, wr_ptr_add); } void nfp_net_xsk_rx_drop(struct nfp_net_r_vector *r_vec, struct nfp_net_xsk_rx_buf *xrxbuf) { u64_stats_update_begin(&r_vec->rx_sync); r_vec->rx_drops++; u64_stats_update_end(&r_vec->rx_sync); nfp_net_xsk_rx_free(xrxbuf); } static void nfp_net_xsk_pool_unmap(struct device *dev, struct xsk_buff_pool *pool) { return xsk_pool_dma_unmap(pool, 0); } static int nfp_net_xsk_pool_map(struct device *dev, struct xsk_buff_pool *pool) { return xsk_pool_dma_map(pool, dev, 0); } int nfp_net_xsk_setup_pool(struct net_device *netdev, struct xsk_buff_pool *pool, u16 queue_id) { struct nfp_net *nn = netdev_priv(netdev); struct xsk_buff_pool *prev_pool; struct nfp_net_dp *dp; int err; /* NFDK doesn't implement xsk yet. */ if (nn->dp.ops->version == NFP_NFD_VER_NFDK) return -EOPNOTSUPP; /* Reject on old FWs so we can drop some checks on datapath. */ if (nn->dp.rx_offset != NFP_NET_CFG_RX_OFFSET_DYNAMIC) return -EOPNOTSUPP; if (!nn->dp.chained_metadata_format) return -EOPNOTSUPP; /* Install */ if (pool) { err = nfp_net_xsk_pool_map(nn->dp.dev, pool); if (err) return err; } /* Reconfig/swap */ dp = nfp_net_clone_dp(nn); if (!dp) { err = -ENOMEM; goto err_unmap; } prev_pool = dp->xsk_pools[queue_id]; dp->xsk_pools[queue_id] = pool; err = nfp_net_ring_reconfig(nn, dp, NULL); if (err) goto err_unmap; /* Uninstall */ if (prev_pool) nfp_net_xsk_pool_unmap(nn->dp.dev, prev_pool); return 0; err_unmap: if (pool) nfp_net_xsk_pool_unmap(nn->dp.dev, pool); return err; } int nfp_net_xsk_wakeup(struct net_device *netdev, u32 queue_id, u32 flags) { struct nfp_net *nn = netdev_priv(netdev); /* queue_id comes from a zero-copy socket, installed with XDP_SETUP_XSK_POOL, * so it must be within our vector range. Moreover, our napi structs * are statically allocated, so we can always kick them without worrying * if reconfig is in progress or interface down. */ napi_schedule(&nn->r_vecs[queue_id].napi); return 0; }