From: Joshua Washington Relying on xsk_get_pool_from_qid for getting whether zero copy is enabled on a queue is erroneous, as an XSK pool is registered in xp_assign_dev whether AF_XDP zero-copy is enabled or not. This becomes problematic when queues are restarted in copy mode, as all RX queues with XSKs will register a pool, causing the driver to exercise the zero-copy codepath. This patch adds a bitmap to keep track of which queues have zero-copy enabled. Reviewed-by: Willem de Bruijn Signed-off-by: Joshua Washington Signed-off-by: Jeroen de Borst --- drivers/net/ethernet/google/gve/gve.h | 1 + drivers/net/ethernet/google/gve/gve_main.c | 37 +++++++++++++++++++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index b2be3fca4125..9925c08e595e 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -802,6 +802,7 @@ struct gve_priv { struct gve_tx_queue_config tx_cfg; struct gve_rx_queue_config rx_cfg; + unsigned long *xsk_pools; /* bitmap of RX queues with XSK pools */ u32 num_ntfy_blks; /* split between TX and RX so must be even */ int numa_node; diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index d2797f55ae7c..02020d5d2f92 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -4,6 +4,7 @@ * Copyright (C) 2015-2024 Google LLC */ +#include #include #include #include @@ -1217,6 +1218,14 @@ static void gve_unreg_xdp_info(struct gve_priv *priv) } } +static struct xsk_buff_pool *gve_get_xsk_pool(struct gve_priv *priv, int qid) +{ + if (!test_bit(qid, priv->xsk_pools)) + return NULL; + + return xsk_get_pool_from_qid(priv->dev, qid); +} + static int gve_reg_xdp_info(struct gve_priv *priv, struct net_device *dev) { struct napi_struct *napi; @@ -1238,7 +1247,7 @@ static int gve_reg_xdp_info(struct gve_priv *priv, struct net_device *dev) if (err) goto err; - xsk_pool = xsk_get_pool_from_qid(dev, i); + xsk_pool = gve_get_xsk_pool(priv, i); if (xsk_pool) err = gve_reg_xsk_pool(priv, dev, xsk_pool, i); else if (gve_is_qpl(priv)) @@ -1590,15 +1599,19 @@ static int gve_xsk_pool_enable(struct net_device *dev, if (err) return err; + set_bit(qid, priv->xsk_pools); + /* If XDP prog is not installed or interface is down, return. */ if (!priv->xdp_prog || !netif_running(dev)) return 0; err = gve_reg_xsk_pool(priv, dev, pool, qid); - if (err) + if (err) { + clear_bit(qid, priv->xsk_pools); xsk_pool_dma_unmap(pool, DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING); + } return err; } @@ -1615,6 +1628,8 @@ static int gve_xsk_pool_disable(struct net_device *dev, if (qid >= priv->rx_cfg.num_queues) return -EINVAL; + clear_bit(qid, priv->xsk_pools); + pool = xsk_get_pool_from_qid(dev, qid); if (pool) xsk_pool_dma_unmap(pool, @@ -2362,10 +2377,22 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) priv->ts_config.rx_filter = HWTSTAMP_FILTER_NONE; setup_device: + priv->xsk_pools = bitmap_zalloc(priv->rx_cfg.max_queues, GFP_KERNEL); + if (!priv->xsk_pools) { + err = -ENOMEM; + goto err; + } + gve_set_netdev_xdp_features(priv); err = gve_setup_device_resources(priv); - if (!err) - return 0; + if (err) + goto err_free_xsk_bitmap; + + return 0; + +err_free_xsk_bitmap: + bitmap_free(priv->xsk_pools); + priv->xsk_pools = NULL; err: gve_adminq_free(&priv->pdev->dev, priv); return err; @@ -2375,6 +2402,8 @@ static void gve_teardown_priv_resources(struct gve_priv *priv) { gve_teardown_device_resources(priv); gve_adminq_free(&priv->pdev->dev, priv); + bitmap_free(priv->xsk_pools); + priv->xsk_pools = NULL; } static void gve_trigger_reset(struct gve_priv *priv) -- 2.50.0.727.gbf7dc18ff4-goog