Merge branch 'a9' into a9-beta
This commit is contained in:
commit
c66f193e5a
15
config.yaml
15
config.yaml
@ -27,6 +27,21 @@ actions:
|
||||
- type: "patch"
|
||||
name: "0001-proc-fix-a-dentry-lock-race-between-release_task-and-lookup.patch"
|
||||
number: 2009
|
||||
|
||||
# GVE patches
|
||||
- type: "patch"
|
||||
name: "2100-gve-Update-QPL-page-registration-logic.patch"
|
||||
number: 2100
|
||||
- type: "patch"
|
||||
name: "2101-gve-Add-adminq-support-for-modifiable-ring-size.patch"
|
||||
number: 2101
|
||||
- type: "patch"
|
||||
name: "2102-gve-Add-ethtool-support-for-changing-ring-size.patch"
|
||||
number: 2102
|
||||
- type: "patch"
|
||||
name: "2103-gve-harden-modifiable-ring-size-support.patch"
|
||||
number: 2103
|
||||
|
||||
- type: "source"
|
||||
name: "almalinuxdup1.x509"
|
||||
number: 100
|
||||
|
||||
160
files/2100-gve-Update-QPL-page-registration-logic.patch
Normal file
160
files/2100-gve-Update-QPL-page-registration-logic.patch
Normal file
@ -0,0 +1,160 @@
|
||||
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: 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>
|
||||
[Jonathan Wright: adapted to the centralized QPL-allocation model in this kernel,
|
||||
which predates the upstream gve_{tx,rx}_alloc_rings_cfg / queues_mem_alloc
|
||||
per-ring QPL refactor and the gve_buffer_mgmt_dqo split. There are no
|
||||
alloc_rings_cfg structs here, so gve_update_num_qpl_pages operates on
|
||||
priv directly (priv->{tx,rx}_pages_per_qpl already exist) and is called
|
||||
from gve_alloc_qpls() before the QPLs are allocated. rx_pages_per_qpl is
|
||||
already consumed by gve_rx_alloc_ring_dqo() and gve_alloc_qpl_page_dqo().
|
||||
The GQI path is left unchanged: it already sizes RX QPLs from
|
||||
rx_data_slot_cnt and TX QPLs from the device-provided tx_pages_per_qpl.]
|
||||
Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
|
||||
---
|
||||
drivers/net/ethernet/google/gve/gve.h | 7 ++----
|
||||
drivers/net/ethernet/google/gve/gve_adminq.c | 12 ----------
|
||||
drivers/net/ethernet/google/gve/gve_main.c | 40 +++++++++++++++++++++++++++++
|
||||
3 files changed, 43 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
|
||||
index cbdf3a842cfe0..1d66d3834f7e6 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve.h
|
||||
+++ b/drivers/net/ethernet/google/gve/gve.h
|
||||
@@ -56,9 +56,6 @@
|
||||
|
||||
#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
|
||||
|
||||
-#define DQO_QPL_DEFAULT_TX_PAGES 512
|
||||
-#define DQO_QPL_DEFAULT_RX_PAGES 2048
|
||||
-
|
||||
/* Maximum TSO size supported on DQO */
|
||||
#define GVE_DQO_TX_MAX 0x3FFFF
|
||||
|
||||
@@ -650,8 +647,8 @@ struct gve_priv {
|
||||
u16 num_event_counters;
|
||||
u16 tx_desc_cnt; /* num desc per ring */
|
||||
u16 rx_desc_cnt; /* num desc per ring */
|
||||
- u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */
|
||||
- u16 rx_pages_per_qpl; /* Suggested number of pages per qpl for RX queues by NIC */
|
||||
+ u16 tx_pages_per_qpl; /* Number of pages per qpl for TX queues */
|
||||
+ u16 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
|
||||
u16 rx_data_slot_cnt; /* rx buffer length */
|
||||
u64 max_registered_pages;
|
||||
u64 num_registered_pages; /* num pages registered with NIC */
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
index b72cc0fa2ba2b..2c233009621bc 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
@@ -767,18 +767,6 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
||||
"JUMBO FRAMES device option enabled.\n");
|
||||
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);
|
||||
- priv->rx_pages_per_qpl =
|
||||
- be16_to_cpu(dev_op_dqo_qpl->rx_pages_per_qpl);
|
||||
- if (priv->tx_pages_per_qpl == 0)
|
||||
- priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
|
||||
- if (priv->rx_pages_per_qpl == 0)
|
||||
- priv->rx_pages_per_qpl = DQO_QPL_DEFAULT_RX_PAGES;
|
||||
- }
|
||||
}
|
||||
|
||||
int gve_adminq_describe_device(struct gve_priv *priv)
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
index 9eb4b3614c4f5..c654cf503c1a2 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_main.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/interrupt.h>
|
||||
+#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
@@ -1106,6 +1107,43 @@ static int gve_alloc_xdp_qpls(struct gve_priv *priv)
|
||||
return err;
|
||||
}
|
||||
|
||||
+/* For DQO, update the suggested number of pages per qpl to be more flexible
|
||||
+ * and honor the "max_registered_pages" parameter from the gVNIC device.
|
||||
+ *
|
||||
+ * Ignore the "tx_pages_per_qpl"/"rx_pages_per_qpl" parameters 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 "max_registered_pages".
|
||||
+ */
|
||||
+static void gve_update_num_qpl_pages(struct gve_priv *priv)
|
||||
+{
|
||||
+ u64 ideal_tx_pages, ideal_rx_pages;
|
||||
+ u16 tx_num_queues, rx_num_queues;
|
||||
+ u64 max_pages, tx_pages;
|
||||
+
|
||||
+ if (priv->queue_format != GVE_DQO_QPL_FORMAT)
|
||||
+ return;
|
||||
+
|
||||
+ /* 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 = priv->tx_cfg.num_queues;
|
||||
+ rx_num_queues = priv->rx_cfg.num_queues;
|
||||
+
|
||||
+ ideal_tx_pages = (u64)priv->tx_desc_cnt * tx_num_queues / 2;
|
||||
+ ideal_rx_pages = (u64)priv->rx_desc_cnt * 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);
|
||||
+ priv->tx_pages_per_qpl = div_u64(tx_pages, tx_num_queues);
|
||||
+ priv->rx_pages_per_qpl = div_u64(max_pages - tx_pages, rx_num_queues);
|
||||
+}
|
||||
+
|
||||
static int gve_alloc_qpls(struct gve_priv *priv)
|
||||
{
|
||||
int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues;
|
||||
@@ -1117,6 +1155,8 @@ static int gve_alloc_qpls(struct gve_priv *priv)
|
||||
if (!gve_is_qpl(priv))
|
||||
return 0;
|
||||
|
||||
+ gve_update_num_qpl_pages(priv);
|
||||
+
|
||||
priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL);
|
||||
if (!priv->qpls)
|
||||
return -ENOMEM;
|
||||
--
|
||||
2.43.0
|
||||
274
files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch
Normal file
274
files/2101-gve-Add-adminq-support-for-modifiable-ring-size.patch
Normal file
@ -0,0 +1,274 @@
|
||||
From: Joshua Washington <joshwash@google.com>
|
||||
Date: Fri, 5 Jun 2026 00:00:00 +0000
|
||||
Subject: gve: Add adminq support for modifiable ring size
|
||||
|
||||
Add support for the gVNIC "modify ring" device option, which allows the
|
||||
device to report the maximum and minimum TX/RX ring sizes it supports.
|
||||
Store those bounds in the priv struct and report the device-provided
|
||||
maximums through ethtool -g "Pre-set maximums" instead of hardcoding the
|
||||
current (default) ring size as the maximum.
|
||||
|
||||
If the device does not provide minimums, fall back to the default
|
||||
minimums of 256 descriptors for TX and 512 for RX.
|
||||
|
||||
This is the first half of the upstream gve modifiable-ring-size feature.
|
||||
It only changes the advertised ring size range; actually resizing the
|
||||
rings is added in the following patch.
|
||||
|
||||
[Jonathan Wright: backported the upstream modifiable-ring-size support to
|
||||
this kernel's gve, using the implementation carried by the RHEL 10 /
|
||||
AlmaLinux 10 gve driver (kernel 6.12.0-211.7.1.el10_2) as the reference,
|
||||
since this 5.14-based gve predates the feature entirely. Adaptations:
|
||||
threaded dev_op_modify_ring through this tree's smaller
|
||||
gve_parse_device_option()/gve_process_device_options() signatures; seeded
|
||||
the default ring-size ranges in both gve_set_desc_cnt() and
|
||||
gve_set_desc_cnt_dqo(). Dropped the upstream
|
||||
"if (priv->queue_format != GVE_DQO_QPL_FORMAT)" guard around the max ring
|
||||
size assignment: that guard exists because DQO-QPL used a fixed QPL page
|
||||
budget, which no longer applies now that QPL pages scale with ring size
|
||||
(see 1106-gve-Update-QPL-page-registration-logic.patch), and keeping it
|
||||
would deny DQO-QPL VMs the larger ring sizes this feature is for.]
|
||||
Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
|
||||
---
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
|
||||
index f916e81..a3c1caa 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve.h
|
||||
+++ b/drivers/net/ethernet/google/gve/gve.h
|
||||
@@ -52,6 +52,9 @@
|
||||
|
||||
#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
|
||||
|
||||
+#define GVE_DEFAULT_MIN_TX_RING_SIZE 256
|
||||
+#define GVE_DEFAULT_MIN_RX_RING_SIZE 512
|
||||
+
|
||||
#define GVE_XDP_ACTIONS 5
|
||||
|
||||
#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
|
||||
@@ -647,6 +650,12 @@ struct gve_priv {
|
||||
u16 num_event_counters;
|
||||
u16 tx_desc_cnt; /* num desc per ring */
|
||||
u16 rx_desc_cnt; /* num desc per ring */
|
||||
+ u16 max_tx_desc_cnt;
|
||||
+ u16 max_rx_desc_cnt;
|
||||
+ u16 min_tx_desc_cnt;
|
||||
+ u16 min_rx_desc_cnt;
|
||||
+ bool modify_ring_size_enabled;
|
||||
+ bool default_min_ring_size;
|
||||
u16 tx_pages_per_qpl; /* Number of pages per qpl for TX queues */
|
||||
u16 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
|
||||
u16 rx_data_slot_cnt; /* rx buffer length */
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
index 62817f8..b7f86bc 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#define GVE_DEVICE_OPTION_TOO_BIG_FMT "Length of %s option larger than expected. Possible older version of guest driver.\n"
|
||||
|
||||
+#define GVE_DEVICE_OPTION_NO_MIN_RING_SIZE 8
|
||||
+
|
||||
static
|
||||
struct gve_device_option *gve_get_next_option(struct gve_device_descriptor *descriptor,
|
||||
struct gve_device_option *option)
|
||||
@@ -40,7 +42,8 @@ void gve_parse_device_option(struct gve_priv *priv,
|
||||
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
|
||||
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
|
||||
struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
|
||||
- struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
|
||||
+ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl,
|
||||
+ struct gve_device_option_modify_ring **dev_op_modify_ring)
|
||||
{
|
||||
u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
|
||||
u16 option_length = be16_to_cpu(option->option_length);
|
||||
@@ -129,6 +132,27 @@ void gve_parse_device_option(struct gve_priv *priv,
|
||||
}
|
||||
*dev_op_dqo_qpl = (void *)(option + 1);
|
||||
break;
|
||||
+ case GVE_DEV_OPT_ID_MODIFY_RING:
|
||||
+ if (option_length < GVE_DEVICE_OPTION_NO_MIN_RING_SIZE ||
|
||||
+ req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING) {
|
||||
+ dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
|
||||
+ "Modify Ring", (int)sizeof(**dev_op_modify_ring),
|
||||
+ GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING,
|
||||
+ option_length, req_feat_mask);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (option_length > sizeof(**dev_op_modify_ring)) {
|
||||
+ dev_warn(&priv->pdev->dev,
|
||||
+ GVE_DEVICE_OPTION_TOO_BIG_FMT, "Modify Ring");
|
||||
+ }
|
||||
+
|
||||
+ *dev_op_modify_ring = (void *)(option + 1);
|
||||
+
|
||||
+ /* device has not provided min ring size */
|
||||
+ if (option_length == GVE_DEVICE_OPTION_NO_MIN_RING_SIZE)
|
||||
+ priv->default_min_ring_size = true;
|
||||
+ break;
|
||||
case GVE_DEV_OPT_ID_JUMBO_FRAMES:
|
||||
if (option_length < sizeof(**dev_op_jumbo_frames) ||
|
||||
req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES) {
|
||||
@@ -164,7 +188,8 @@ gve_process_device_options(struct gve_priv *priv,
|
||||
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
|
||||
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
|
||||
struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
|
||||
- struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
|
||||
+ struct gve_device_option_dqo_qpl **dev_op_dqo_qpl,
|
||||
+ struct gve_device_option_modify_ring **dev_op_modify_ring)
|
||||
{
|
||||
const int num_options = be16_to_cpu(descriptor->num_device_options);
|
||||
struct gve_device_option *dev_opt;
|
||||
@@ -185,7 +210,7 @@ gve_process_device_options(struct gve_priv *priv,
|
||||
gve_parse_device_option(priv, descriptor, dev_opt,
|
||||
dev_op_gqi_rda, dev_op_gqi_qpl,
|
||||
dev_op_dqo_rda, dev_op_jumbo_frames,
|
||||
- dev_op_dqo_qpl);
|
||||
+ dev_op_dqo_qpl, dev_op_modify_ring);
|
||||
dev_opt = next_opt;
|
||||
}
|
||||
|
||||
@@ -728,6 +753,12 @@ static int gve_set_desc_cnt(struct gve_priv *priv,
|
||||
{
|
||||
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
|
||||
priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
|
||||
+
|
||||
+ /* set default ranges */
|
||||
+ priv->max_tx_desc_cnt = priv->tx_desc_cnt;
|
||||
+ priv->max_rx_desc_cnt = priv->rx_desc_cnt;
|
||||
+ priv->min_tx_desc_cnt = priv->tx_desc_cnt;
|
||||
+ priv->min_rx_desc_cnt = priv->rx_desc_cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -739,6 +770,12 @@ gve_set_desc_cnt_dqo(struct gve_priv *priv,
|
||||
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
|
||||
priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
|
||||
|
||||
+ /* set default ranges */
|
||||
+ priv->max_tx_desc_cnt = priv->tx_desc_cnt;
|
||||
+ priv->max_rx_desc_cnt = priv->rx_desc_cnt;
|
||||
+ priv->min_tx_desc_cnt = priv->tx_desc_cnt;
|
||||
+ priv->min_rx_desc_cnt = priv->rx_desc_cnt;
|
||||
+
|
||||
if (priv->queue_format == GVE_DQO_QPL_FORMAT)
|
||||
return 0;
|
||||
|
||||
@@ -755,7 +792,9 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
||||
const struct gve_device_option_jumbo_frames
|
||||
*dev_op_jumbo_frames,
|
||||
const struct gve_device_option_dqo_qpl
|
||||
- *dev_op_dqo_qpl)
|
||||
+ *dev_op_dqo_qpl,
|
||||
+ const struct gve_device_option_modify_ring
|
||||
+ *dev_op_modify_ring)
|
||||
{
|
||||
/* Before control reaches this point, the page-size-capped max MTU from
|
||||
* the gve_device_descriptor field has already been stored in
|
||||
@@ -767,10 +806,29 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
||||
"JUMBO FRAMES device option enabled.\n");
|
||||
priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu);
|
||||
}
|
||||
+
|
||||
+ /* Read and store ring size ranges given by device */
|
||||
+ if (dev_op_modify_ring &&
|
||||
+ (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
|
||||
+ priv->modify_ring_size_enabled = true;
|
||||
+
|
||||
+ priv->max_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_rx_ring_size);
|
||||
+ priv->max_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_tx_ring_size);
|
||||
+
|
||||
+ if (priv->default_min_ring_size) {
|
||||
+ /* If device hasn't provided minimums, use default minimums */
|
||||
+ priv->min_tx_desc_cnt = GVE_DEFAULT_MIN_TX_RING_SIZE;
|
||||
+ priv->min_rx_desc_cnt = GVE_DEFAULT_MIN_RX_RING_SIZE;
|
||||
+ } else {
|
||||
+ priv->min_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_rx_ring_size);
|
||||
+ priv->min_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_tx_ring_size);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
int gve_adminq_describe_device(struct gve_priv *priv)
|
||||
{
|
||||
+ struct gve_device_option_modify_ring *dev_op_modify_ring = NULL;
|
||||
struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
|
||||
struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
|
||||
struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL;
|
||||
@@ -804,7 +862,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
|
||||
err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda,
|
||||
&dev_op_gqi_qpl, &dev_op_dqo_rda,
|
||||
&dev_op_jumbo_frames,
|
||||
- &dev_op_dqo_qpl);
|
||||
+ &dev_op_dqo_qpl, &dev_op_modify_ring);
|
||||
if (err)
|
||||
goto free_device_descriptor;
|
||||
|
||||
@@ -873,7 +931,8 @@ int gve_adminq_describe_device(struct gve_priv *priv)
|
||||
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
|
||||
|
||||
gve_enable_supported_features(priv, supported_features_mask,
|
||||
- dev_op_jumbo_frames, dev_op_dqo_qpl);
|
||||
+ dev_op_jumbo_frames, dev_op_dqo_qpl,
|
||||
+ dev_op_modify_ring);
|
||||
|
||||
free_device_descriptor:
|
||||
dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
|
||||
index 5865ccd..0d1dd38 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_adminq.h
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
|
||||
@@ -125,6 +125,16 @@ struct gve_device_option_jumbo_frames {
|
||||
|
||||
static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
|
||||
|
||||
+struct gve_device_option_modify_ring {
|
||||
+ __be32 supported_featured_mask;
|
||||
+ __be16 max_rx_ring_size;
|
||||
+ __be16 max_tx_ring_size;
|
||||
+ __be16 min_rx_ring_size;
|
||||
+ __be16 min_tx_ring_size;
|
||||
+};
|
||||
+
|
||||
+static_assert(sizeof(struct gve_device_option_modify_ring) == 12);
|
||||
+
|
||||
/* Terminology:
|
||||
*
|
||||
* RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
|
||||
@@ -138,6 +148,7 @@ enum gve_dev_opt_id {
|
||||
GVE_DEV_OPT_ID_GQI_RDA = 0x2,
|
||||
GVE_DEV_OPT_ID_GQI_QPL = 0x3,
|
||||
GVE_DEV_OPT_ID_DQO_RDA = 0x4,
|
||||
+ GVE_DEV_OPT_ID_MODIFY_RING = 0x6,
|
||||
GVE_DEV_OPT_ID_DQO_QPL = 0x7,
|
||||
GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
|
||||
};
|
||||
@@ -149,9 +160,11 @@ enum gve_dev_opt_req_feat_mask {
|
||||
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
|
||||
GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0,
|
||||
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0,
|
||||
+ GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING = 0x0,
|
||||
};
|
||||
|
||||
enum gve_sup_feature_mask {
|
||||
+ GVE_SUP_MODIFY_RING_MASK = 1 << 0,
|
||||
GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
|
||||
};
|
||||
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
index e5397aa..fb7b477 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
@@ -476,8 +476,8 @@ static void gve_get_ringparam(struct net_device *netdev,
|
||||
{
|
||||
struct gve_priv *priv = netdev_priv(netdev);
|
||||
|
||||
- cmd->rx_max_pending = priv->rx_desc_cnt;
|
||||
- cmd->tx_max_pending = priv->tx_desc_cnt;
|
||||
+ cmd->rx_max_pending = priv->max_rx_desc_cnt;
|
||||
+ cmd->tx_max_pending = priv->max_tx_desc_cnt;
|
||||
cmd->rx_pending = priv->rx_desc_cnt;
|
||||
cmd->tx_pending = priv->tx_desc_cnt;
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
166
files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch
Normal file
166
files/2102-gve-Add-ethtool-support-for-changing-ring-size.patch
Normal file
@ -0,0 +1,166 @@
|
||||
From: Joshua Washington <joshwash@google.com>
|
||||
Date: Fri, 5 Jun 2026 00:00:01 +0000
|
||||
Subject: gve: Add ethtool support for changing ring size
|
||||
|
||||
Add ethtool -G (set_ringparam) support so the TX/RX ring sizes can
|
||||
actually be changed within the bounds reported by the device in the
|
||||
"modify ring" device option.
|
||||
|
||||
Requested ring sizes are validated against the device-provided minimums
|
||||
and maximums and must be a power of two. Changing the ring size tears the
|
||||
device down, applies the new descriptor counts, and brings it back up.
|
||||
|
||||
[Jonathan Wright: backported the upstream modifiable-ring-size support to
|
||||
this kernel's gve, using the RHEL 10 / AlmaLinux 10 gve driver
|
||||
(kernel 6.12.0-211.7.1.el10_2) as the reference. Adaptations: upstream's
|
||||
gve_adjust_ring_sizes() reconfigures via gve_get_curr_alloc_cfgs() /
|
||||
gve_adjust_config(), which do not exist in this tree (it predates the
|
||||
gve_{tx,rx}_alloc_rings_cfg / queues_mem_alloc refactor). Instead
|
||||
gve_adjust_ring_sizes() lives in gve_main.c and follows the existing
|
||||
gve_adjust_queues() pattern used by this tree for ethtool -L: teardown
|
||||
with gve_close(), set the new descriptor counts, then gve_open(), which
|
||||
rebuilds the rings and re-sizes the QPLs from the new ring size via
|
||||
gve_update_num_qpl_pages() (1106). It is declared in gve.h because
|
||||
gve_close()/gve_open() are static to gve_main.c. Upstream's
|
||||
gve_set_ringparam() also handles header-split/tcp_data_split; that
|
||||
feature does not exist in this tree, so only the ring-size logic is
|
||||
carried over.]
|
||||
Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
|
||||
---
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
|
||||
index a3c1caa..acac856 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve.h
|
||||
+++ b/drivers/net/ethernet/google/gve/gve.h
|
||||
@@ -1074,6 +1074,9 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown);
|
||||
int gve_adjust_queues(struct gve_priv *priv,
|
||||
struct gve_queue_config new_rx_config,
|
||||
struct gve_queue_config new_tx_config);
|
||||
+int gve_adjust_ring_sizes(struct gve_priv *priv,
|
||||
+ u16 new_tx_desc_cnt,
|
||||
+ u16 new_rx_desc_cnt);
|
||||
/* report stats handling */
|
||||
void gve_handle_report_stats(struct gve_priv *priv);
|
||||
/* exported by ethtool.c */
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
index fb7b477..a8822c9 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
+#include <linux/log2.h>
|
||||
#include "gve.h"
|
||||
#include "gve_adminq.h"
|
||||
#include "gve_dqo.h"
|
||||
@@ -482,6 +483,50 @@ static void gve_get_ringparam(struct net_device *netdev,
|
||||
cmd->tx_pending = priv->tx_desc_cnt;
|
||||
}
|
||||
|
||||
+static int gve_validate_req_ring_size(struct gve_priv *priv, u16 new_tx_desc_cnt,
|
||||
+ u16 new_rx_desc_cnt)
|
||||
+{
|
||||
+ /* check for valid range */
|
||||
+ if (new_tx_desc_cnt < priv->min_tx_desc_cnt ||
|
||||
+ new_tx_desc_cnt > priv->max_tx_desc_cnt ||
|
||||
+ new_rx_desc_cnt < priv->min_rx_desc_cnt ||
|
||||
+ new_rx_desc_cnt > priv->max_rx_desc_cnt) {
|
||||
+ dev_err(&priv->pdev->dev, "Requested descriptor count out of range\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (!is_power_of_2(new_tx_desc_cnt) || !is_power_of_2(new_rx_desc_cnt)) {
|
||||
+ dev_err(&priv->pdev->dev, "Requested descriptor count has to be a power of 2\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gve_set_ringparam(struct net_device *netdev,
|
||||
+ struct ethtool_ringparam *cmd,
|
||||
+ struct kernel_ethtool_ringparam *kernel_cmd,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct gve_priv *priv = netdev_priv(netdev);
|
||||
+ u16 new_tx_cnt, new_rx_cnt;
|
||||
+
|
||||
+ if (cmd->tx_pending == priv->tx_desc_cnt && cmd->rx_pending == priv->rx_desc_cnt)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!priv->modify_ring_size_enabled) {
|
||||
+ dev_err(&priv->pdev->dev, "Modify ring size is not supported.\n");
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ new_tx_cnt = cmd->tx_pending;
|
||||
+ new_rx_cnt = cmd->rx_pending;
|
||||
+
|
||||
+ if (gve_validate_req_ring_size(priv, new_tx_cnt, new_rx_cnt))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return gve_adjust_ring_sizes(priv, new_tx_cnt, new_rx_cnt);
|
||||
+}
|
||||
+
|
||||
static int gve_user_reset(struct net_device *netdev, u32 *flags)
|
||||
{
|
||||
struct gve_priv *priv = netdev_priv(netdev);
|
||||
@@ -667,6 +712,7 @@ const struct ethtool_ops gve_ethtool_ops = {
|
||||
.get_coalesce = gve_get_coalesce,
|
||||
.set_coalesce = gve_set_coalesce,
|
||||
.get_ringparam = gve_get_ringparam,
|
||||
+ .set_ringparam = gve_set_ringparam,
|
||||
.reset = gve_user_reset,
|
||||
.get_tunable = gve_get_tunable,
|
||||
.set_tunable = gve_set_tunable,
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
index a21df52..e939750 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_main.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
@@ -1780,6 +1780,44 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
+int gve_adjust_ring_sizes(struct gve_priv *priv,
|
||||
+ u16 new_tx_desc_cnt,
|
||||
+ u16 new_rx_desc_cnt)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ if (netif_carrier_ok(priv->dev)) {
|
||||
+ /* To make this process as simple as possible we teardown the
|
||||
+ * device, set the new ring sizes, and then bring the device
|
||||
+ * up again.
|
||||
+ */
|
||||
+ err = gve_close(priv->dev);
|
||||
+ /* we have already tried to reset in close,
|
||||
+ * just fail at this point
|
||||
+ */
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ priv->tx_desc_cnt = new_tx_desc_cnt;
|
||||
+ priv->rx_desc_cnt = new_rx_desc_cnt;
|
||||
+
|
||||
+ err = gve_open(priv->dev);
|
||||
+ if (err)
|
||||
+ goto err;
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+ /* Set the ring sizes for the next up. */
|
||||
+ priv->tx_desc_cnt = new_tx_desc_cnt;
|
||||
+ priv->rx_desc_cnt = new_rx_desc_cnt;
|
||||
+
|
||||
+ return 0;
|
||||
+err:
|
||||
+ netif_err(priv, drv, priv->dev,
|
||||
+ "Adjust ring sizes failed! !!! DISABLING ALL QUEUES !!!\n");
|
||||
+ gve_turndown(priv);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static void gve_turndown(struct gve_priv *priv)
|
||||
{
|
||||
int idx;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
120
files/2103-gve-harden-modifiable-ring-size-support.patch
Normal file
120
files/2103-gve-harden-modifiable-ring-size-support.patch
Normal file
@ -0,0 +1,120 @@
|
||||
From: Jonathan Wright <jonathan@almalinux.org>
|
||||
Date: Wed, 5 Aug 2026 00:00:00 +0000
|
||||
Subject: gve: harden modifiable ring size support for the EL9 gve architecture
|
||||
|
||||
Follow-up hardening for the modifiable-ring-size backport (patches 1107
|
||||
and 1108), addressing three ways the older EL9 gve architecture differs
|
||||
from the EL10/upstream driver the feature was designed against. Found in
|
||||
review; none affect the DQO resize paths already validated on GCP.
|
||||
|
||||
1) Do not enable modifiable ring sizes for GQI queue formats.
|
||||
In this kernel's gve, the GQI branches of
|
||||
gve_adminq_create_{tx,rx}_queue carry no ring size (only the DQO
|
||||
branches send one), so after a resize the device would keep using its
|
||||
probe-time default ring size against rings the driver re-sized:
|
||||
device and driver would index the same DMA memory modulo different
|
||||
sizes. Shrinking the RX ring would additionally let the device DMA
|
||||
past the smaller allocation, and the GQI datapath sizes its data ring
|
||||
and mask from the fixed rx_data_slot_cnt (with a NAPI livelock
|
||||
possible on GQI-RDA once rx_desc_cnt >= 2 * data slots). Gate the
|
||||
feature on !gve_is_gqi(): GQI keeps the pre-feature fixed-ring
|
||||
behavior and ethtool -G returns -EOPNOTSUPP.
|
||||
|
||||
2) Key gve_adjust_ring_sizes() on netif_running(), not
|
||||
netif_carrier_ok(), matching the EL10 implementation. The rings are
|
||||
allocated whenever the interface is administratively up, even while
|
||||
the link is down; taking the "set for next up" shortcut in that state
|
||||
would change priv->{tx,rx}_desc_cnt under allocated rings, and the
|
||||
GQI RX free path sizes dma_free_coherent() from priv->rx_desc_cnt.
|
||||
|
||||
3) Clamp the advertised ring size range for DQO-RDA. In this kernel the
|
||||
DQO-RDA TX completion ring and RX buffer ring keep the fixed sizes
|
||||
from the DQO-RDA device option and do not scale with the descriptor
|
||||
rings (upstream removed that coupling before modifiable ring sizes
|
||||
were introduced). Growing the TX ring beyond tx_comp_ring_entries
|
||||
could overrun the TX completion queue with report-event completions
|
||||
(num_pending_packets reserves complq_size/32 slots for REs, but REs
|
||||
scale with posted descriptors on the grown ring) or have queue
|
||||
creation rejected; shrinking the RX descriptor/completion ring below
|
||||
rx_buff_ring_entries could overflow the RX completion queue. Clamp
|
||||
max_tx_desc_cnt and min_rx_desc_cnt so such sizes cannot be
|
||||
requested. DQO-QPL is unaffected (its completion/buffer rings track
|
||||
the descriptor ring size).
|
||||
Signed-off-by: Jonathan Wright <jonathan@almalinux.org>
|
||||
---
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
index b7f86bc..eef7cca 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
|
||||
@@ -807,8 +807,18 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
||||
priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu);
|
||||
}
|
||||
|
||||
- /* Read and store ring size ranges given by device */
|
||||
- if (dev_op_modify_ring &&
|
||||
+ /* Read and store ring size ranges given by device.
|
||||
+ *
|
||||
+ * Modifiable ring sizes are supported for DQO queue formats only.
|
||||
+ * In this kernel's gve, the GQI branches of
|
||||
+ * gve_adminq_create_{tx,rx}_queue do not carry a ring size, so after
|
||||
+ * a resize the device would keep using its default ring size against
|
||||
+ * rings the driver re-sized, desynchronizing device and driver views
|
||||
+ * of the rings. The GQI datapath (rx_data_slot_cnt data ring, TX
|
||||
+ * FIFO) also assumes the probe-time fixed ring sizes. Keep GQI at
|
||||
+ * fixed ring sizes.
|
||||
+ */
|
||||
+ if (dev_op_modify_ring && !gve_is_gqi(priv) &&
|
||||
(supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
|
||||
priv->modify_ring_size_enabled = true;
|
||||
|
||||
@@ -823,6 +833,27 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
||||
priv->min_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_rx_ring_size);
|
||||
priv->min_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_tx_ring_size);
|
||||
}
|
||||
+
|
||||
+ /* In this kernel's gve, the DQO-RDA TX completion ring and RX
|
||||
+ * buffer ring keep the fixed sizes provided in the DQO-RDA
|
||||
+ * device option; they do not scale with the descriptor rings
|
||||
+ * (upstream removed that coupling before modifiable ring
|
||||
+ * sizes were introduced). Clamp the advertised range so a
|
||||
+ * resize cannot create a descriptor ring the fixed rings
|
||||
+ * cannot absorb:
|
||||
+ * - growing the TX ring beyond tx_comp_ring_entries could
|
||||
+ * overrun the TX completion queue with report-event
|
||||
+ * completions (or be rejected at queue creation);
|
||||
+ * - shrinking the RX ring (the RX completion queue) below
|
||||
+ * rx_buff_ring_entries could overflow the RX completion
|
||||
+ * queue.
|
||||
+ */
|
||||
+ if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
|
||||
+ priv->max_tx_desc_cnt = min(priv->max_tx_desc_cnt,
|
||||
+ priv->options_dqo_rda.tx_comp_ring_entries);
|
||||
+ priv->min_rx_desc_cnt = max(priv->min_rx_desc_cnt,
|
||||
+ priv->options_dqo_rda.rx_buff_ring_entries);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
index e939750..516f222 100644
|
||||
--- a/drivers/net/ethernet/google/gve/gve_main.c
|
||||
+++ b/drivers/net/ethernet/google/gve/gve_main.c
|
||||
@@ -1786,7 +1786,14 @@ int gve_adjust_ring_sizes(struct gve_priv *priv,
|
||||
{
|
||||
int err;
|
||||
|
||||
- if (netif_carrier_ok(priv->dev)) {
|
||||
+ /* Key on the administrative state (netif_running), not the link
|
||||
+ * state: the rings are allocated whenever the interface is up, even
|
||||
+ * while the carrier is down. Changing the descriptor counts without
|
||||
+ * reallocating the rings would desynchronize them from
|
||||
+ * priv->{tx,rx}_desc_cnt, which the GQI free path uses to size
|
||||
+ * dma_free_coherent().
|
||||
+ */
|
||||
+ if (netif_running(priv->dev)) {
|
||||
/* To make this process as simple as possible we teardown the
|
||||
* device, set the new ring sizes, and then bring the device
|
||||
* up again.
|
||||
--
|
||||
2.43.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user