]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gve: Update QPL page registration logic
authorMatt Olson <maolson@google.com>
Wed, 25 Feb 2026 18:23:41 +0000 (10:23 -0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Feb 2026 16:58:29 +0000 (08:58 -0800)
For DQO, change QPL page registration logic to be more flexible to honor
the "max_registered_pages" parameter from the gVNIC device.

Previously the number of RX pages per QPL was hardcoded to twice the
ring size, and the number of TX pages per QPL was dictated by the device
in the DQO-QPL device option. Now [in DQO-QPL mode], the driver will
ignore the "tx_pages_per_qpl" parameter indicated in the DQO-QPL device
option and instead allocate up to (tx_queue_length / 2) pages per TX QPL
and up to (rx_queue_length * 2) pages per RX QPL while keeping the total
number of pages under the "max_registered_pages".

Merge DQO and GQI QPL page calculation logic into a unified
gve_update_num_qpl_pages function. Add rx_pages_per_qpl to the priv
struct for consumption by both DQO and GQI.

Signed-off-by: Matt Olson <maolson@google.com>
Signed-off-by: Max Yuan <maxyuan@google.com>
Reviewed-by: Jordan Rhee <jordanrhee@google.com>
Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
Signed-off-by: Joshua Washington <joshwash@google.com>
Link: https://patch.msgid.link/20260225182342.1049816-2-joshwash@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_adminq.c
drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
drivers/net/ethernet/google/gve/gve_main.c
drivers/net/ethernet/google/gve/gve_rx.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c
drivers/net/ethernet/google/gve/gve_tx.c
drivers/net/ethernet/google/gve/gve_tx_dqo.c

index cbdf3a842cfe00c326d3d82a02494e0f93acf16c..1d66d3834f7e6cf531df3456e0cbc7f0dd4cf239 100644 (file)
@@ -79,8 +79,6 @@
 
 #define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
-#define DQO_QPL_DEFAULT_TX_PAGES 512
-
 /* Maximum TSO size supported on DQO */
 #define GVE_DQO_TX_MAX 0x3FFFF
 
@@ -711,6 +709,7 @@ struct gve_ptype_lut {
 /* Parameters for allocating resources for tx queues */
 struct gve_tx_alloc_rings_cfg {
        struct gve_tx_queue_config *qcfg;
+       u16 pages_per_qpl;
 
        u16 num_xdp_rings;
 
@@ -726,6 +725,7 @@ struct gve_rx_alloc_rings_cfg {
        /* tx config is also needed to determine QPL ids */
        struct gve_rx_queue_config *qcfg_rx;
        struct gve_tx_queue_config *qcfg_tx;
+       u16 pages_per_qpl;
 
        u16 ring_size;
        u16 packet_buffer_size;
@@ -816,7 +816,8 @@ struct gve_priv {
        u16 min_rx_desc_cnt;
        bool modify_ring_size_enabled;
        bool default_min_ring_size;
-       u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */
+       u16 tx_pages_per_qpl;
+       u16 rx_pages_per_qpl;
        u64 max_registered_pages;
        u64 num_registered_pages; /* num pages registered with NIC */
        struct bpf_prog *xdp_prog; /* XDP BPF program */
@@ -1150,14 +1151,6 @@ static inline u32 gve_rx_start_qpl_id(const struct gve_tx_queue_config *tx_cfg)
        return gve_get_rx_qpl_id(tx_cfg, 0);
 }
 
-static inline u32 gve_get_rx_pages_per_qpl_dqo(u32 rx_desc_cnt)
-{
-       /* For DQO, page count should be more than ring size for
-        * out-of-order completions. Set it to two times of ring size.
-        */
-       return 2 * rx_desc_cnt;
-}
-
 /* Returns the correct dma direction for tx and rx qpls */
 static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv,
                                                      int id)
@@ -1308,6 +1301,9 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown);
 void gve_get_curr_alloc_cfgs(struct gve_priv *priv,
                             struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
                             struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);
+void gve_update_num_qpl_pages(struct gve_priv *priv,
+                             struct gve_rx_alloc_rings_cfg *rx_alloc_cfg,
+                             struct gve_tx_alloc_rings_cfg *tx_alloc_cfg);
 int gve_adjust_config(struct gve_priv *priv,
                      struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
                      struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);
index b72cc0fa2ba2b260154092ebd3874f4d31e389ae..2c233009621bc42080080f56941def91a6153e50 100644 (file)
@@ -970,14 +970,6 @@ static void gve_enable_supported_features(struct gve_priv *priv,
                priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu);
        }
 
-       /* Override pages for qpl for DQO-QPL */
-       if (dev_op_dqo_qpl) {
-               priv->tx_pages_per_qpl =
-                       be16_to_cpu(dev_op_dqo_qpl->tx_pages_per_qpl);
-               if (priv->tx_pages_per_qpl == 0)
-                       priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
-       }
-
        if (dev_op_buffer_sizes &&
            (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) {
                priv->max_rx_buffer_size =
index 0e2b703c673ac2071618e81802382bca06e5479b..6880d1531ba5efaec2f2dffafb64c42db54ce913 100644 (file)
@@ -133,7 +133,7 @@ int gve_alloc_qpl_page_dqo(struct gve_rx_ring *rx,
        u32 idx;
 
        idx = rx->dqo.next_qpl_page_idx;
-       if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) {
+       if (idx >= priv->rx_pages_per_qpl) {
                net_err_ratelimited("%s: Out of QPL pages\n",
                                    priv->dev->name);
                return -ENOMEM;
index 9eb4b3614c4f5431038a7f57960c82bb4c6b2ec2..c654cf503c1a27c4119671ffe2ce52a187d1b5d9 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/filter.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
@@ -966,6 +967,7 @@ static void gve_tx_get_curr_alloc_cfg(struct gve_priv *priv,
        cfg->qcfg = &priv->tx_cfg;
        cfg->raw_addressing = !gve_is_qpl(priv);
        cfg->ring_size = priv->tx_desc_cnt;
+       cfg->pages_per_qpl = priv->tx_pages_per_qpl;
        cfg->num_xdp_rings = cfg->qcfg->num_xdp_queues;
        cfg->tx = priv->tx;
 }
@@ -997,12 +999,48 @@ static void gve_tx_start_rings(struct gve_priv *priv, int num_rings)
        }
 }
 
+void gve_update_num_qpl_pages(struct gve_priv *priv,
+                             struct gve_rx_alloc_rings_cfg *rx_alloc_cfg,
+                             struct gve_tx_alloc_rings_cfg *tx_alloc_cfg)
+{
+       u64 ideal_tx_pages, ideal_rx_pages;
+       u16 tx_num_queues, rx_num_queues;
+       u64 max_pages, tx_pages;
+
+       if (priv->queue_format == GVE_GQI_QPL_FORMAT) {
+               rx_alloc_cfg->pages_per_qpl = rx_alloc_cfg->ring_size;
+       } else if (priv->queue_format == GVE_DQO_QPL_FORMAT) {
+               /*
+                * We want 2 pages per RX descriptor and half a page per TX
+                * descriptor, which means the fraction ideal_tx_pages /
+                * (ideal_tx_pages + ideal_rx_pages) of the pages we allocate
+                * should be for TX. Shrink proportionally as necessary to avoid
+                * allocating more than max_registered_pages total pages.
+                */
+               tx_num_queues = tx_alloc_cfg->qcfg->num_queues;
+               rx_num_queues = rx_alloc_cfg->qcfg_rx->num_queues;
+
+               ideal_tx_pages = tx_alloc_cfg->ring_size * tx_num_queues / 2;
+               ideal_rx_pages = rx_alloc_cfg->ring_size * rx_num_queues * 2;
+               max_pages = min(priv->max_registered_pages,
+                               ideal_tx_pages + ideal_rx_pages);
+
+               tx_pages = div64_u64(max_pages * ideal_tx_pages,
+                                    ideal_tx_pages + ideal_rx_pages);
+               tx_alloc_cfg->pages_per_qpl = div_u64(tx_pages, tx_num_queues);
+               rx_alloc_cfg->pages_per_qpl = div_u64(max_pages - tx_pages,
+                                                     rx_num_queues);
+       }
+}
+
 static int gve_queues_mem_alloc(struct gve_priv *priv,
                                struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
                                struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
        int err;
 
+       gve_update_num_qpl_pages(priv, rx_alloc_cfg, tx_alloc_cfg);
+
        if (gve_is_gqi(priv))
                err = gve_tx_alloc_rings_gqi(priv, tx_alloc_cfg);
        else
@@ -1293,6 +1331,7 @@ static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv,
        cfg->raw_addressing = !gve_is_qpl(priv);
        cfg->enable_header_split = priv->header_split_enabled;
        cfg->ring_size = priv->rx_desc_cnt;
+       cfg->pages_per_qpl = priv->rx_pages_per_qpl;
        cfg->packet_buffer_size = priv->rx_cfg.packet_buffer_size;
        cfg->rx = priv->rx;
        cfg->xdp = !!cfg->qcfg_tx->num_xdp_queues;
@@ -1372,6 +1411,8 @@ static int gve_queues_start(struct gve_priv *priv,
        priv->rx_cfg = *rx_alloc_cfg->qcfg_rx;
        priv->tx_desc_cnt = tx_alloc_cfg->ring_size;
        priv->rx_desc_cnt = rx_alloc_cfg->ring_size;
+       priv->tx_pages_per_qpl = tx_alloc_cfg->pages_per_qpl;
+       priv->rx_pages_per_qpl = rx_alloc_cfg->pages_per_qpl;
 
        gve_tx_start_rings(priv, gve_num_tx_queues(priv));
        gve_rx_start_rings(priv, rx_alloc_cfg->qcfg_rx->num_queues);
index 4eb6ed29d3cc6f45db940c951b6fdea84575398d..81ea800e66e94134b135c95254ba37153b88b794 100644 (file)
@@ -278,7 +278,6 @@ int gve_rx_alloc_ring_gqi(struct gve_priv *priv,
        struct device *hdev = &priv->pdev->dev;
        u32 slots = cfg->ring_size;
        int filled_pages;
-       int qpl_page_cnt;
        u32 qpl_id = 0;
        size_t bytes;
        int err;
@@ -314,10 +313,8 @@ int gve_rx_alloc_ring_gqi(struct gve_priv *priv,
 
        if (!rx->data.raw_addressing) {
                qpl_id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx->q_num);
-               qpl_page_cnt = cfg->ring_size;
-
                rx->data.qpl = gve_alloc_queue_page_list(priv, qpl_id,
-                                                        qpl_page_cnt);
+                                                        cfg->pages_per_qpl);
                if (!rx->data.qpl) {
                        err = -ENOMEM;
                        goto abort_with_copy_pool;
index c706c793215942bc7e3232bf98c439ac5a025b9a..3b10139941ea163dca4d330bf58f2a3895741e9c 100644 (file)
@@ -218,7 +218,6 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
 {
        struct device *hdev = &priv->pdev->dev;
        struct page_pool *pool;
-       int qpl_page_cnt;
        size_t size;
        u32 qpl_id;
 
@@ -246,7 +245,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
        XSK_CHECK_PRIV_TYPE(struct gve_xdp_buff);
 
        rx->dqo.num_buf_states = cfg->raw_addressing ? buffer_queue_slots :
-               gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
+               cfg->pages_per_qpl;
        rx->dqo.buf_states = kvcalloc_node(rx->dqo.num_buf_states,
                                           sizeof(rx->dqo.buf_states[0]),
                                           GFP_KERNEL, priv->numa_node);
@@ -281,10 +280,9 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
                rx->dqo.page_pool = pool;
        } else {
                qpl_id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx->q_num);
-               qpl_page_cnt = gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
 
                rx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
-                                                       qpl_page_cnt);
+                                                       cfg->pages_per_qpl);
                if (!rx->dqo.qpl)
                        goto err;
                rx->dqo.next_qpl_page_idx = 0;
index 0b856e269eac5c26138272b77c16cbd4fa55b215..79338fd9bf66e55ab232e61ad49f2486364a0fa0 100644 (file)
@@ -264,7 +264,6 @@ static int gve_tx_alloc_ring_gqi(struct gve_priv *priv,
                                 int idx)
 {
        struct device *hdev = &priv->pdev->dev;
-       int qpl_page_cnt;
        u32 qpl_id = 0;
        size_t bytes;
 
@@ -291,10 +290,8 @@ static int gve_tx_alloc_ring_gqi(struct gve_priv *priv,
        tx->dev = hdev;
        if (!tx->raw_addressing) {
                qpl_id = gve_tx_qpl_id(priv, tx->q_num);
-               qpl_page_cnt = priv->tx_pages_per_qpl;
-
                tx->tx_fifo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
-                                                           qpl_page_cnt);
+                                                           cfg->pages_per_qpl);
                if (!tx->tx_fifo.qpl)
                        goto abort_with_desc;
 
index 4db9d4f9ed6f9211f68183d127f25ee8b942b786..f33035018b89ce3e5f84b1c22c246c2f68177ef3 100644 (file)
@@ -311,7 +311,6 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv,
 {
        struct device *hdev = &priv->pdev->dev;
        int num_pending_packets;
-       int qpl_page_cnt;
        size_t bytes;
        u32 qpl_id;
        int i;
@@ -392,10 +391,9 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv,
 
        if (!cfg->raw_addressing) {
                qpl_id = gve_tx_qpl_id(priv, tx->q_num);
-               qpl_page_cnt = priv->tx_pages_per_qpl;
 
                tx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
-                                                       qpl_page_cnt);
+                                                       cfg->pages_per_qpl);
                if (!tx->dqo.qpl)
                        goto err;