Add two upstream commits for the Google gVNIC (gve) driver:
07993df56091 gve: Update QPL page registration logic
a2f19184014f gve: Enable reading max ring size from the device in
DQO-QPL mode
Patches are taken as-is from rpms/kernel commit b4decc5e6c1b, where they
were already verified on the GCP branch. 07993df56091 needed a backport:
this 6.12 based kernel predates the split of gve_buffer_mgmt_dqo.c out
of gve_rx_dqo.c and the rename of the RX alloc cfg queue config field.
Those adjustments are documented in the patch header. a2f19184014f is
unchanged from upstream.
Both patches apply with --fuzz=0 on top of the AlmaLinux 10 kernel
6.12.0-211.38.1.el10_2 source, and the resulting driver builds clean,
including with W=1, against kernel-devel-6.12.0-211.38.1.el10_2.
324 lines
12 KiB
Diff
324 lines
12 KiB
Diff
From 07993df560917357610e0625a9a2e7531c3211fc Mon Sep 17 00:00:00 2001
|
|
From: Matt Olson <maolson@google.com>
|
|
Date: Wed, 25 Feb 2026 10:23:41 -0800
|
|
Subject: [PATCH AlmaLinux 10] gve: Update QPL page registration logic
|
|
|
|
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>
|
|
|
|
[ AlmaLinux: backported to the 6.12 gve driver. The upstream commit targets
|
|
the post-refactor gve driver; the equivalent changes were applied to the
|
|
older driver shipped in RHEL/AlmaLinux 10:
|
|
- rx_alloc_cfg->qcfg_rx->num_queues -> rx_alloc_cfg->qcfg->num_queues
|
|
(the rx alloc-rings cfg uses the shared gve_queue_config field name).
|
|
- The gve_alloc_qpl_page_dqo() bound check lives in gve_rx_dqo.c here
|
|
rather than in the not-yet-present gve_buffer_mgmt_dqo.c.
|
|
The QPL page-sizing logic is otherwise identical to upstream. ]
|
|
Signed-off-by: Andrew Lukoshko <alukoshko@almalinux.org>
|
|
---
|
|
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
|
|
index adc2b9a..65bd511 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve.h
|
|
+++ b/drivers/net/ethernet/google/gve/gve.h
|
|
@@ -71,8 +71,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
|
|
|
|
@@ -646,6 +644,7 @@ struct gve_ptype_lut {
|
|
/* Parameters for allocating resources for tx queues */
|
|
struct gve_tx_alloc_rings_cfg {
|
|
struct gve_queue_config *qcfg;
|
|
+ u16 pages_per_qpl;
|
|
|
|
u16 ring_size;
|
|
u16 start_idx;
|
|
@@ -661,6 +660,7 @@ struct gve_rx_alloc_rings_cfg {
|
|
/* tx config is also needed to determine QPL ids */
|
|
struct gve_queue_config *qcfg;
|
|
struct gve_queue_config *qcfg_tx;
|
|
+ u16 pages_per_qpl;
|
|
|
|
u16 ring_size;
|
|
u16 packet_buffer_size;
|
|
@@ -738,7 +738,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 */
|
|
@@ -1071,14 +1072,6 @@ static inline u32 gve_rx_start_qpl_id(const struct gve_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)
|
|
@@ -1178,6 +1171,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);
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
|
|
index e44e8b1..7335b48 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
|
|
@@ -911,14 +911,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 =
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
|
|
index 72e9ce9..a065891 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_main.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_main.c
|
|
@@ -10,6 +10,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>
|
|
@@ -926,6 +927,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->start_idx = 0;
|
|
cfg->num_rings = gve_num_tx_queues(priv);
|
|
cfg->tx = priv->tx;
|
|
@@ -981,12 +983,48 @@ static int gve_alloc_xdp_rings(struct gve_priv *priv)
|
|
return 0;
|
|
}
|
|
|
|
+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->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
|
|
@@ -1281,6 +1319,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 = gve_is_gqi(priv) ?
|
|
GVE_DEFAULT_RX_BUFFER_SIZE :
|
|
priv->data_buffer_size_dqo;
|
|
@@ -1360,6 +1399,8 @@ static int gve_queues_start(struct gve_priv *priv,
|
|
priv->rx_cfg = *rx_alloc_cfg->qcfg;
|
|
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;
|
|
|
|
if (priv->xdp_prog)
|
|
priv->num_xdp_queues = priv->rx_cfg.num_queues;
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
|
|
index acb73d4..77077ca 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_rx.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
|
|
@@ -272,7 +272,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;
|
|
@@ -308,10 +307,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;
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
|
|
index 1154c1d..1cbaf23 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
|
|
@@ -178,7 +178,7 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx,
|
|
return err;
|
|
} else {
|
|
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;
|
|
@@ -382,7 +382,6 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
|
|
int idx)
|
|
{
|
|
struct device *hdev = &priv->pdev->dev;
|
|
- int qpl_page_cnt;
|
|
size_t size;
|
|
u32 qpl_id;
|
|
|
|
@@ -397,7 +396,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
|
|
|
|
rx->dqo.num_buf_states = cfg->raw_addressing ?
|
|
min_t(s16, S16_MAX, buffer_queue_slots * 4) :
|
|
- gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
|
|
+ cfg->pages_per_qpl;
|
|
rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
|
|
sizeof(rx->dqo.buf_states[0]),
|
|
GFP_KERNEL);
|
|
@@ -426,10 +425,8 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv,
|
|
|
|
if (!cfg->raw_addressing) {
|
|
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;
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c
|
|
index e7fb7d6..d471507 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_tx.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
|
|
@@ -261,7 +261,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;
|
|
|
|
@@ -288,10 +287,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;
|
|
|
|
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
|
|
index f879426..9118256 100644
|
|
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
|
|
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
|
|
@@ -287,7 +287,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;
|
|
@@ -357,10 +356,8 @@ 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;
|
|
|