Skip to content

[rlc-9/5.14.0-687.31.1.el9_8] Multiple patches tested (17 commits) - #1498

Open
ciq-kernel-automation[bot] wants to merge 17 commits into
rlc-9/5.14.0-687.31.1.el9_8from
{shreeya_gce}_rlc-9/5.14.0-687.31.1.el9_8
Open

[rlc-9/5.14.0-687.31.1.el9_8] Multiple patches tested (17 commits)#1498
ciq-kernel-automation[bot] wants to merge 17 commits into
rlc-9/5.14.0-687.31.1.el9_8from
{shreeya_gce}_rlc-9/5.14.0-687.31.1.el9_8

Conversation

@ciq-kernel-automation

@ciq-kernel-automation ciq-kernel-automation Bot commented Jul 31, 2026

Copy link
Copy Markdown

Summary

This PR has been automatically created after successful completion of all CI stages.

Commit Message(s)

gve: Define config structs for queue allocation

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 7cea48b9a4b2433a59826ee7cdb594faab3ac1e7
gve: Switch to config-aware queue allocation

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit f13697cc7a19225307d85b0a77ef1c15abe95a7d
upstream-diff (CIQ review fixes folded in) Restored the error-cleanup
  loops in gve_tx_alloc_rings_gqi()/gve_tx_alloc_rings_dqo() to start at
  cfg->start_idx (not 0) so a failed XDP ring alloc does not free the
  live non-XDP rings; and added an unreg_xdp_qpls label in
  gve_add_xdp_queues() to unregister QPLs before freeing them on a
  create failure. Both are RLC-only regressions vs the base (the loop is
  byte-identical to upstream f13697; upstream never fixed it directly).
upstream-diff Resolved conflicts in gve.h and gve_main.c against RLC 9.
  Kept the existing gve_add_napi()/gve_remove_napi() helpers, which this
  series now calls from the per-ring start functions in gve_tx.c/gve_rx.c;
  made them non-static and declared them in gve.h so the cross-file
  callers link. Preserved the gve_xsk_tx_poll() prototype present in RLC 9.
gve: Refactor gve_open and gve_close

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 92a6d7a4010c3e84894f4fb7f481e648f0b12e53
gve: Alloc before freeing when adjusting queues

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 5f08cd3d6423e7ea81467e7216426d65b65297fa
gve: Alloc before freeing when changing features

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit f3753771e7cc965c31eff20fa3d10056e64aa07c
gve: simplify setting decriptor count defaults

jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 4cbc70f6ec5e06f93e617d3f2d7f8dc47c0c9067
gve: make the completion and buffer ring size equal for DQO

jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 5dee3c702c20b62bc12b72edb495740bf06d97b3
gve: set page count for RX QPL for GQI and DQO queue formats

jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit b94d3703c1a6a57323256a687f4cbdabfffbe408
gve: add support to read ring size ranges from the device

jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit ed4fb326947dc486f97c66168f6ac50f5d1efd19
upstream-diff Kept only the MODIFY_RING handling. Dropped the
  BUFFER_SIZES option case and enable block (depend on header-split
  fields not present in RLC 9); the dev_op_buffer_sizes param is kept as
  NULL plumbing to preserve upstream signatures.
gve: add support to change ring size via ethtool

jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 834f9458f2fdb48dfb95976934c1594d086a956d
upstream-diff Resolved conflict in gve_ethtool.c against RLC 9. Omitted
  the header-split (tcp_data_split) handling in gve_get_ringparam and the
  gve_set_hsplit_config() call in gve_set_ringparam, as the header-split
  feature (gve_header_split_supported / priv->header_split_enabled /
  gve_set_hsplit_config) is not present in RLC 9 and is unrelated to
  ring-size support. Added the ".set_ringparam = gve_set_ringparam" entry
  to gve_ethtool_ops, which upstream carried on a pre-existing stub that
  RLC 9 did not have. gve_adjust_ring_sizes uses the qpls_alloc_cfg form
  matching the pre-qpl-removal queue-alloc config in RLC 9.
gve: Update QPL page registration logic

jira KERNEL-1218
commit-author Matt Olson <maolson@google.com>
commit 07993df560917357610e0625a9a2e7531c3211fc
upstream-diff (CIQ review fixes folded in) Clamp num_buf_states to
  min_t(u32, S16_MAX, ...) in gve_rx_alloc_ring_dqo() for both the RDA
  and QPL arms: the s16 free-list links overflow and the count can
  truncate at large ring sizes routed in by the ring-size series. Clamp
  num_tx_qpl_bufs to S16_MAX in gve_tx_qpl_buf_init() (64K-page builds).
  Initialize cfg->pages_per_qpl in the get-curr helpers. Upstream is
  unclamped here (u16 field, plain assignment); these are deliberate
  deviations and upstream-report candidates.
upstream-diff Page-count math copied verbatim from this commit's
  gve_update_num_qpl_pages(); placed inline in gve_alloc_qpls() since
  RLC 9 sizes QPLs from a pool. Counts are stored in the tx/rx alloc
  cfg structs (pages_per_qpl added) and copied into priv only in
  gve_queues_start(), matching upstream so a failed resize cannot leave
  priv describing a rejected config. Only deviation is the struct-field
  rename to RLC 9 cfg shapes. No new logic.
gve: Enable reading max ring size from the device in DQO-QPL mode

jira KERNEL-1218
commit-author Matt Olson <maolson@google.com>
commit a2f19184014f309165d2d4cfb41088b75c1121a4
gve: Remove unused declaration gve_rx_alloc_rings()

jira KERNEL-1218
commit-author Ziwei Xiao <ziweixiao@google.com>
commit 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060
upstream-diff Only removed the dead gve_rx_alloc_rings() declaration.
  Upstream's hunk also (re)declared gve_rx_alloc_ring_gqi/
  gve_rx_free_ring_gqi non-static; RLC 9 keeps gve_rx_alloc_ring_gqi
  static in gve_rx.c (used only there), so those declarations were not
  added. The plural gve_rx_alloc_rings_gqi/free_rings_gqi decls this
  branch uses are retained.
gve: Fix use of netif_carrier_ok()

jira KERNEL-1218
commit-author Ziwei Xiao <ziweixiao@google.com>
commit fba917b169bea48b7f2c8c46e084a2e2b3512b76
upstream-diff Kept RLC 9's 4-arg gve_adjust_config(priv, &qpls_alloc_cfg,
  &tx_alloc_cfg, &rx_alloc_cfg) signature and the existing inline
  feature-revert in gve_set_features (RLC 9 lacks the later qpl-cfg
  removal and the goto revert_features refactor); only the
  netif_carrier_ok()->netif_running() change from this commit was taken.
gve: fix XDP allocation path in edge cases

jira KERNEL-1218
commit-author Joshua Washington <joshwash@google.com>
commit de63ac44a527b6c626ba7adb54873d4d6bd8de23
upstream-diff Kept RLC 9's qpls_alloc_cfg / new_qpl_cfg locals in
  gve_adjust_queues (pool-based QPL model; RLC 9 lacks the later qpl-cfg
  removal) alongside the num_xdp_queues local this commit adds. The
  functional hunks (num_xdp_queues accounting) apply unchanged.
gve: clean XDP queues in gve_tx_stop_ring_gqi

jira KERNEL-1218
commit-author Joshua Washington <joshwash@google.com>
commit 6321f5fb70d502d95de8a212a7b484c297ec9644
gve: prevent ethtool ops after shutdown

jira KERNEL-1218
commit-author Jordan Rhee <jordanrhee@google.com>
commit 75a9a46d67f46d608205888f9b34e315c1786345

Test Results

✅ Build Stage

Architecture Build Time Total Time
x86_64 25m 52s 26m 50s
aarch64 20m 15s 21m 19s

✅ Boot Verification

✅ Kernel Selftests

Architecture Passed Failed Compared Against Status
x86_64 204 51 rlc-9/5.14.0-687.31.1.el9_8 ⚠️ No baseline available
aarch64 153 50 rlc-9/5.14.0-687.31.1.el9_8 ⚠️ No baseline available

✅ LTP Results

Architecture Passed Failed Compared Against Status
x86_64 1456 81 rlc-9/5.14.0-687.31.1.el9_8 ⚠️ No baseline available
aarch64 1429 82 rlc-9/5.14.0-687.31.1.el9_8 ⚠️ No baseline available

🤖 This PR was automatically generated by GitHub Actions
Run ID: 30918618030

jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 7cea48b

Queue allocation functions currently can only allocate into priv and
free memory in priv. These new structs would be passed into the queue
functions in a subsequent change to make them capable of returning newly
allocated resources and not just writing them into priv. They also make
it possible to allocate resources for queues with a different config
than that of the currently active queues.

	Signed-off-by: Shailend Chand <shailend@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Reviewed-by: Jeroen de Borst <jeroendb@google.com>
	Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240122182632.1102721-2-shailend@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 7cea48b)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
@ciq-kernel-automation ciq-kernel-automation Bot added the created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI) label Jul 31, 2026
@github-actions

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/30648162529

@github-actions

Copy link
Copy Markdown

🔍 Upstream Linux Kernel Commit Check

  • ⚠️ PR commit 021a231e2bc (gve: Alloc before freeing when adjusting queues) references upstream commit
    5f08cd3d6423 which has been referenced by a Fixes: tag in the upstream
    Linux kernel:
    de63ac44a52 gve: fix XDP allocation path in edge cases (Joshua Washington)
    fba917b169b gve: Fix use of netif_carrier_ok() (Praveen Kaligineedi)
  • ❗ PR commit 9cad693c7fe (gve: Remove unused declaration gve_rx_alloc_rings()) references upstream commit
    359c5eb0f736 which does not exist in the upstream Linux kernel.

  • ❗ PR commit 8c6cc0b68e0 (gve: Fix use of netif_carrier_ok()) references upstream commit
    fba917b169be which does not exist in the upstream Linux kernel.

  • ❗ PR commit 4f23d623242 (gve: fix XDP allocation path in edge cases) references upstream commit
    de63ac44a527 which does not exist in the upstream Linux kernel.

This is an automated message from the kernel commit checker workflow.

@github-actions

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit 6a202b31de9 (gve: Switch to config-aware queue allocation) → upstream f13697cc7a19
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1119,12 +1115,6 @@
 			   struct gve_rx_alloc_rings_cfg *cfg);
 void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);
 void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx);
-/* napi handling */
-int gve_napi_poll(struct napi_struct *napi, int budget);
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget);
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int));
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx);
 /* Reset */
 void gve_schedule_reset(struct gve_priv *priv);
 int gve_reset(struct gve_priv *priv, bool attempt_teardown);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -253,7 +253,7 @@
 	return IRQ_HANDLED;
 }
 
-int gve_napi_poll(struct napi_struct *napi, int budget)
+static int gve_napi_poll(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block;
 	__be32 __iomem *irq_doorbell;
@@ -311,7 +311,7 @@
 	return work_done;
 }
 
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
+static int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block =
 		container_of(napi, struct gve_notify_block, napi);
@@ -590,15 +590,15 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int))
+static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+			 int (*gve_poll)(struct napi_struct *, int))
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 
 	netif_napi_add(priv->dev, &block->napi, gve_poll);
 }
 
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1102,8 +1101,12 @@
 void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid);
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
-void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
+int gve_tx_alloc_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_free_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx);
+void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1097,8 +1087,7 @@
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_xsk_tx_poll(struct gve_notify_block *block, int budget);
 int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
 void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -590,21 +582,6 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-			 int (*gve_poll)(struct napi_struct *, int))
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_add(priv->dev, &block->napi, gve_poll);
-}
-
-static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_del(&block->napi);
-}
-
 static int gve_register_xdp_qpls(struct gve_priv *priv)
 {
 	int start_id;
  • ⚠️ PR commit 5780df3ecab (gve: make the completion and buffer ring size equal for DQO) → upstream 5dee3c702c20
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -640,4 +659,4 @@
 			cpu_to_be16(rx_buff_ring_entries);
 		cmd.create_rx_queue.enable_rsc =
 			!!(priv->dev->features & NETIF_F_LRO);
-	}
+		if (priv->header_split_enabled)
  • ⚠️ PR commit 078c209745d (gve: set page count for RX QPL for GQI and DQO queue formats) → upstream b94d3703c1a6
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -54,4 +54,4 @@
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 #define DQO_QPL_DEFAULT_RX_PAGES 2048
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -749,3 +773,2 @@
 	}
-}
  • ⚠️ PR commit 07137eb1363 (gve: add support to read ring size ranges from the device) → upstream ed4fb326947d
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -42,9 +42,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes,
-			     struct gve_device_option_modify_ring **dev_op_modify_ring)
+			     struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -189,9 +187,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes,
-			   struct gve_device_option_modify_ring **dev_op_modify_ring)
+			   struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -212,8 +208,7 @@
 		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_buffer_sizes,
-					dev_op_modify_ring);
+					dev_op_dqo_qpl);
 		dev_opt = next_opt;
 	}
 
@@ -757,11 +752,7 @@
 					  const struct gve_device_option_jumbo_frames
 					  *dev_op_jumbo_frames,
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl,
-					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes,
-					  const struct gve_device_option_modify_ring
-					  *dev_op_modify_ring)
+					  *dev_op_dqo_qpl)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -805,7 +796,6 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
-	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = NULL;
 	struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
 	struct gve_device_option_modify_ring *dev_op_modify_ring = NULL;
 	struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
@@ -839,9 +829,8 @@
 
 	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_buffer_sizes,
-					 &dev_op_modify_ring);
+					 &dev_op_jumbo_frames,
+					 &dev_op_dqo_qpl);
 	if (err)
 		goto free_device_descriptor;
 
@@ -901,8 +890,7 @@
 	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_buffer_sizes, dev_op_modify_ring);
+				      dev_op_jumbo_frames, dev_op_dqo_qpl);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -124,15 +124,6 @@
 
 static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
 
-struct gve_device_option_buffer_sizes {
-	/* GVE_SUP_BUFFER_SIZES_MASK bit should be set */
-	__be32 supported_features_mask;
-	__be16 packet_buffer_size;
-	__be16 header_buffer_size;
-};
-
-static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
-
 struct gve_device_option_modify_ring {
 	__be32 supported_featured_mask;
 	__be16 max_rx_ring_size;
@@ -143,7 +134,6 @@
 
 static_assert(sizeof(struct gve_device_option_modify_ring) == 12);
 
-
 /* Terminology:
  *
  * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
@@ -153,31 +143,25 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
-	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,
-	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
+	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_DQO_QPL = 0x7,
+	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
-	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_BUFFER_SIZES		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
+	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,
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
-	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
+	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -43,7 +45,8 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
+			     struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			     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);
@@ -206,7 +230,8 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
+			   struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			   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;
@@ -227,7 +252,8 @@
 		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_buffer_sizes);
+					dev_op_dqo_qpl, dev_op_buffer_sizes,
+					dev_op_modify_ring);
 		dev_opt = next_opt;
 	}
 
@@ -776,7 +808,9 @@
 					  const struct gve_device_option_dqo_qpl
 					  *dev_op_dqo_qpl,
 					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes)
+					  *dev_op_buffer_sizes,
+					  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
@@ -865,9 +920,9 @@
 
 	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_buffer_sizes);
+					 &dev_op_jumbo_frames, &dev_op_dqo_qpl,
+					 &dev_op_buffer_sizes,
+					 &dev_op_modify_ring);
 	if (err)
 		goto free_device_descriptor;
 
@@ -928,7 +983,7 @@
 
 	gve_enable_supported_features(priv, supported_features_mask,
 				      dev_op_jumbo_frames, dev_op_dqo_qpl,
-				      dev_op_buffer_sizes);
+				      dev_op_buffer_sizes, dev_op_modify_ring);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -152,13 +162,14 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
-	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_DQO_QPL = 0x7,
-	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
-	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
+	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,
+	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -162,13 +173,14 @@
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
-	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_BUFFER_SIZES = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
+	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_BUFFER_SIZES		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
 };
 
 enum gve_sup_feature_mask {
@@ -172,8 +184,9 @@
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
+	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
+	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -45,6 +45,6 @@
 /* PTYPEs are always 10 bits. */
 #define GVE_NUM_PTYPES	1024
 
 #define GVE_DEFAULT_RX_BUFFER_SIZE 2048
 
-#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
+#define GVE_MAX_RX_BUFFER_SIZE 4096
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -36,6 +35,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -162,6 +179,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -185,7 +204,7 @@
 		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_buffer_sizes);
 		dev_opt = next_opt;
 	}
 
@@ -715,5 +732,7 @@
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl)
+					  *dev_op_dqo_qpl,
+					  const struct gve_device_option_buffer_sizes
+					  *dev_op_buffer_sizes)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -742,6 +765,7 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
+	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = 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;
@@ -780,7 +816,8 @@
 	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_buffer_sizes);
 	if (err)
 		goto free_device_descriptor;
 
@@ -838,6 +874,7 @@
 
 	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_buffer_sizes);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -121,6 +123,5 @@
 
-static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
 
 /* Terminology:
  *
  * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
@@ -139,6 +147,7 @@
 	GVE_DEV_OPT_ID_DQO_RDA = 0x4,
 	GVE_DEV_OPT_ID_DQO_QPL = 0x7,
 	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
+	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -148,10 +157,12 @@
 	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_BUFFER_SIZES = 0x0,
 };
 
 enum gve_sup_feature_mask {
 	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
  • ⚠️ PR commit b963e9f5227 (gve: add support to change ring size via ethtool) → upstream 834f9458f2fd
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -482,90 +482,6 @@
 	cmd->tx_pending = priv->tx_desc_cnt;
 }
 
-static int gve_adjust_ring_sizes(struct gve_priv *priv,
-				 u16 new_tx_desc_cnt,
-				 u16 new_rx_desc_cnt)
-{
-	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
-	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
-	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
-	struct gve_qpl_config new_qpl_cfg;
-	int err;
-
-	/* get current queue configuration */
-	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
-				&tx_alloc_cfg, &rx_alloc_cfg);
-
-	/* copy over the new ring_size from ethtool */
-	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
-	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
-
-	/* qpl_cfg is not read-only, it contains a map that gets updated as
-	 * rings are allocated, which is why we cannot use the yet unreleased
-	 * one in priv.
-	 */
-	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-
-	if (netif_running(priv->dev)) {
-		err = gve_adjust_config(priv, &qpls_alloc_cfg,
-					&tx_alloc_cfg, &rx_alloc_cfg);
-		if (err)
-			return err;
-	}
-
-	/* Set new ring_size for the next up */
-	priv->tx_desc_cnt = new_tx_desc_cnt;
-	priv->rx_desc_cnt = new_rx_desc_cnt;
-
-	return 0;
-}
-
-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);
@@ -751,7 +667,6 @@
 	.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,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -503,6 +503,65 @@
 		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
 }
 
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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,
@@ -506,6 +565,12 @@
 			     struct netlink_ext_ack *extack)
 {
 	struct gve_priv *priv = netdev_priv(netdev);
+	u16 new_tx_cnt, new_rx_cnt;
+	int err;
+
+	err = gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	if (err)
+		return err;
 
 	if (priv->tx_desc_cnt != cmd->tx_pending ||
 	    priv->rx_desc_cnt != cmd->rx_pending) {
@@ -507,9 +572,11 @@
 {
 	struct gve_priv *priv = netdev_priv(netdev);
 
-	if (priv->tx_desc_cnt != cmd->tx_pending ||
-	    priv->rx_desc_cnt != cmd->rx_pending) {
-		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+	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;
 	}
 
@@ -513,7 +580,13 @@
 		return -EOPNOTSUPP;
 	}
 
-	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	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)

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -595,6 +487,112 @@
-	.get_coalesce = gve_get_coalesce,
-	.set_coalesce = gve_set_coalesce,
-	.get_ringparam = gve_get_ringparam,
-	.reset = gve_user_reset,
-	.get_tunable = gve_get_tunable,
-	.set_tunable = gve_set_tunable,
+{
+	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_pending = priv->rx_desc_cnt;
+	cmd->tx_pending = priv->tx_desc_cnt;
+
+		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
+}
+
+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);
+
+	if (priv->tx_desc_cnt != cmd->tx_pending ||
+	    priv->rx_desc_cnt != cmd->rx_pending) {
+		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+		return -EOPNOTSUPP;
+	}
+
+	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+}
+
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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)
  • ⚠️ PR commit 3ae6991e9c1 (gve: Update QPL page registration logic) → upstream 07993df56091
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -703,7 +701,7 @@
 	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 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
+	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 */
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1128,13 +1127,11 @@
 }
 
 static int gve_alloc_qpls(struct gve_priv *priv, struct gve_qpls_alloc_cfg *cfg,
-			  struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
 			  struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
 	int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues;
 	int rx_start_id, tx_num_qpls, rx_num_qpls;
 	struct gve_queue_page_list *qpls;
-	u32 tx_page_count, rx_page_count;
 	u32 page_count;
 	int err;
 
@@ -1154,38 +1151,8 @@
 		goto free_qpl_array;
 	}
 
-	/* Compute the number of pages per QPL. For DQO-QPL, honor the device's
-	 * max_registered_pages limit by allocating up to (tx ring_size / 2)
-	 * pages per TX QPL and up to (rx ring_size * 2) pages per RX QPL,
-	 * shrinking proportionally if the total would exceed the limit. For
-	 * GQI-QPL the RX page count keeps a 1:1 relationship with descriptors.
-	 */
-	tx_page_count = priv->tx_pages_per_qpl;
-
-	if (cfg->is_gqi) {
-		rx_page_count = rx_alloc_cfg->ring_size;
-	} else {
-		u16 tx_num_queues = cfg->tx_cfg->num_queues;
-		u16 rx_num_queues = cfg->rx_cfg->num_queues;
-		u64 ideal_tx_pages, ideal_rx_pages, max_pages, tx_pages;
-
-		ideal_tx_pages = (u64)tx_alloc_cfg->ring_size * tx_num_queues / 2;
-		ideal_rx_pages = (u64)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_page_count = div_u64(tx_pages, tx_num_queues);
-		rx_page_count = div_u64(max_pages - tx_pages, rx_num_queues);
-	}
-
-	/* Store the computed per-QPL page counts for the datapath to consume */
-	tx_alloc_cfg->pages_per_qpl = tx_page_count;
-	rx_alloc_cfg->pages_per_qpl = rx_page_count;
-
 	/* Allocate TX QPLs */
-	page_count = tx_page_count;
+	page_count = priv->tx_pages_per_qpl;
 	tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues,
 				      gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls);
@@ -1194,7 +1161,15 @@
 
 	/* Allocate RX QPLs */
 	rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg);
-	page_count = rx_page_count;
+	/* For GQI_QPL number of pages allocated have 1:1 relationship with
+	 * number of descriptors. For DQO, number of pages required are
+	 * more than descriptors (because of out of order completions).
+	 * Set it to twice the number of descriptors.
+	 */
+	if (cfg->is_gqi)
+		page_count = rx_alloc_cfg->ring_size;
+	else
+		page_count = gve_get_rx_pages_per_qpl_dqo(rx_alloc_cfg->ring_size);
 	rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls);
 	if (err)
@@ -1418,7 +1393,7 @@
 {
 	int err;
 
-	err = gve_alloc_qpls(priv, qpls_alloc_cfg, tx_alloc_cfg, rx_alloc_cfg);
+	err = gve_alloc_qpls(priv, qpls_alloc_cfg, rx_alloc_cfg);
 	if (err) {
 		netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n");
 		return err;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -178,7 +178,7 @@
 			return err;
 	} else {
 		idx = rx->dqo.next_qpl_page_idx;
-		if (idx >= priv->rx_pages_per_qpl) {
+		if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) {
 			net_err_ratelimited("%s: Out of QPL pages\n",
 					    priv->dev->name);
 			return -ENOMEM;

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -709,6 +707,7 @@
 /* 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;
 
@@ -724,6 +723,7 @@
 	/* 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;
@@ -1149,14 +1150,6 @@
 	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)
@@ -1307,6 +1300,9 @@
 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);
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -970,14 +970,6 @@
 		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 =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -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 @@
 	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,6 +999,40 @@
 	}
 }
 
+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)
@@ -1000,6 +1036,8 @@
 {
 	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 @@
 	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;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -218,7 +218,6 @@
 {
 	struct device *hdev = &priv->pdev->dev;
 	struct page_pool *pool;
-	int qpl_page_cnt;
 	size_t size;
 	u32 qpl_id;
 
@@ -246,7 +245,7 @@
 	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,7 +280,6 @@
 		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);
@@ -284,7 +282,7 @@
 		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;

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -57,5 +57,5 @@
 
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 
@@ -658,4 +674,3 @@
 
-	u16 ring_size;
-	bool raw_addressing;
-	bool enable_header_split;
+	u16 num_xdp_rings;
+
@@ -1030,6 +1158,6 @@
 	return 2 * rx_desc_cnt;
 }
 
-/* Returns a pointer to the next available tx qpl in the list of qpls */
-static inline
-struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg,
+/* 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)
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -782,6 +978,6 @@
 			priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
 	}
 
-	/* Read and store ring size ranges given by device */
-	if (dev_op_modify_ring &&
-	    (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
+	if (dev_op_buffer_sizes &&
+	    (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) {
+		priv->max_rx_buffer_size =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -7,5 +6,6 @@
 #include <linux/filter.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
@@ -1447,6 +1369,6 @@
-	priv->rx_cfg = *rx_alloc_cfg->qcfg;
+	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;
 
-	if (priv->xdp_prog)
-		priv->num_xdp_queues = priv->rx_cfg.num_queues;
+	gve_tx_start_rings(priv, gve_num_tx_queues(priv));
+	gve_rx_start_rings(priv, rx_alloc_cfg->qcfg_rx->num_queues);
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -291,7 +282,6 @@
 
-	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);
-	rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
-				      sizeof(rx->dqo.buf_states[0]),
-				      GFP_KERNEL);
+		rx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
+							qpl_page_cnt);
+		if (!rx->dqo.qpl)
+			goto err;
+		rx->dqo.next_qpl_page_idx = 0;

================================================================================
*    ONLY IN PATCH2 - files not modified by patch1                             *
================================================================================

--- a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -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;
 
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -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;
  • ❌ PR commit 9cad693c7fe (gve: Remove unused declaration gve_rx_alloc_rings())359c5eb0f736
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060
    fatal: bad object 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060

  • ❌ PR commit 8c6cc0b68e0 (gve: Fix use of netif_carrier_ok())fba917b169be
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout fba917b169bea48b7f2c8c46e084a2e2b3512b76
    fatal: bad object fba917b169bea48b7f2c8c46e084a2e2b3512b76

  • ❌ PR commit 4f23d623242 (gve: fix XDP allocation path in edge cases)de63ac44a527
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout de63ac44a527b6c626ba7adb54873d4d6bd8de23
    fatal: bad object de63ac44a527b6c626ba7adb54873d4d6bd8de23

This is an automated interdiff check for backported commits.

@github-actions

Copy link
Copy Markdown

Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/30648162529

@shreeya-patel98
shreeya-patel98 requested a review from a team July 31, 2026 16:55

@bmastbergen bmastbergen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an issue in gve_qpls_get_curr_alloc_cfg which doesn't exist in upstream but may need to be fixed up in this kernel. The rlc-8 PR may have the same issue

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed to use priv->xdp_prog too?

cfg->num_xdp_queues = priv->xdp_prog ? priv->rx_cfg.num_queues : 0;

This code doesn't exist in upstream, but from what I gather this commit is moving away from using priv->num_xdp_queues because its stale and yet here is a place that still uses it.

@shreeya-patel98
shreeya-patel98 force-pushed the {shreeya_gce}_rlc-9/5.14.0-687.31.1.el9_8 branch from 4f23d62 to 4550119 Compare August 4, 2026 14:22
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/30919502665

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

🔍 Upstream Linux Kernel Commit Check

  • ⚠️ PR commit f25aa5a3ac3 (gve: Alloc before freeing when adjusting queues) references upstream commit
    5f08cd3d6423 which has been referenced by a Fixes: tag in the upstream
    Linux kernel:
    de63ac44a52 gve: fix XDP allocation path in edge cases (Joshua Washington)
    fba917b169b gve: Fix use of netif_carrier_ok() (Praveen Kaligineedi)
  • ❗ PR commit b26a94060ec (gve: Remove unused declaration gve_rx_alloc_rings()) references upstream commit
    359c5eb0f736 which does not exist in the upstream Linux kernel.

  • ❗ PR commit 5f08c240a72 (gve: Fix use of netif_carrier_ok()) references upstream commit
    fba917b169be which does not exist in the upstream Linux kernel.

  • ❗ PR commit 54ffe647799 (gve: fix XDP allocation path in edge cases) references upstream commit
    de63ac44a527 which does not exist in the upstream Linux kernel.

  • ⚠️ PR commit 45501194369 (gve: prevent ethtool ops after shutdown) does not reference a CVE but
    upstream commit 75a9a46d67f4 is associated with CVE-2025-38735

This is an automated message from the kernel commit checker workflow.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit e300397e50c (gve: Switch to config-aware queue allocation) → upstream f13697cc7a19
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1119,12 +1115,6 @@
 			   struct gve_rx_alloc_rings_cfg *cfg);
 void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);
 void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx);
-/* napi handling */
-int gve_napi_poll(struct napi_struct *napi, int budget);
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget);
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int));
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx);
 /* Reset */
 void gve_schedule_reset(struct gve_priv *priv);
 int gve_reset(struct gve_priv *priv, bool attempt_teardown);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -253,7 +253,7 @@
 	return IRQ_HANDLED;
 }
 
-int gve_napi_poll(struct napi_struct *napi, int budget)
+static int gve_napi_poll(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block;
 	__be32 __iomem *irq_doorbell;
@@ -311,7 +311,7 @@
 	return work_done;
 }
 
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
+static int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block =
 		container_of(napi, struct gve_notify_block, napi);
@@ -590,15 +590,15 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int))
+static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+			 int (*gve_poll)(struct napi_struct *, int))
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 
 	netif_napi_add(priv->dev, &block->napi, gve_poll);
 }
 
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 
@@ -1315,13 +1315,13 @@
 static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv,
 					struct gve_qpls_alloc_cfg *cfg)
 {
-	cfg->raw_addressing = !gve_is_qpl(priv);
-	cfg->is_gqi = gve_is_gqi(priv);
-	cfg->num_xdp_queues = priv->num_xdp_queues;
-	cfg->qpl_cfg = &priv->qpl_cfg;
-	cfg->tx_cfg = &priv->tx_cfg;
-	cfg->rx_cfg = &priv->rx_cfg;
-	cfg->qpls = priv->qpls;
+	  cfg->raw_addressing = !gve_is_qpl(priv);
+	  cfg->is_gqi = gve_is_gqi(priv);
+	  cfg->num_xdp_queues = priv->num_xdp_queues;
+	  cfg->qpl_cfg = &priv->qpl_cfg;
+	  cfg->tx_cfg = &priv->tx_cfg;
+	  cfg->rx_cfg = &priv->rx_cfg;
+	  cfg->qpls = priv->qpls;
 }
 
 static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv,
@@ -1556,12 +1556,10 @@
 
 	err = gve_create_xdp_rings(priv);
 	if (err)
-		goto unreg_xdp_qpls;
+		goto free_xdp_rings;
 
 	return 0;
 
-unreg_xdp_qpls:
-	gve_unregister_xdp_qpls(priv);
 free_xdp_rings:
 	gve_free_xdp_rings(priv);
 free_xdp_qpls:
--- b/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -358,7 +358,7 @@
 	return 0;
 
 cleanup:
-	for (j = cfg->start_idx; j < i; j++)
+	for (j = 0; j < i; j++)
 		gve_tx_free_ring_gqi(priv, &tx[j], cfg);
 	if (cfg->start_idx == 0)
 		kvfree(tx);
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -413,7 +413,7 @@
 	return 0;
 
 err:
-	for (j = cfg->start_idx; j < i; j++)
+	for (j = 0; j < i; j++)
 		gve_tx_free_ring_dqo(priv, &tx[j], cfg);
 	if (cfg->start_idx == 0)
 		kvfree(tx);

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1102,8 +1101,12 @@
 void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid);
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
-void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
+int gve_tx_alloc_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_free_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx);
+void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1097,8 +1087,7 @@
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_xsk_tx_poll(struct gve_notify_block *block, int budget);
 int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
 void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -590,21 +582,6 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-			 int (*gve_poll)(struct napi_struct *, int))
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_add(priv->dev, &block->napi, gve_poll);
-}
-
-static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_del(&block->napi);
-}
-
 static int gve_register_xdp_qpls(struct gve_priv *priv)
 {
 	int start_id;
  • ⚠️ PR commit fa05cacbffd (gve: make the completion and buffer ring size equal for DQO) → upstream 5dee3c702c20
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -640,4 +659,4 @@
 			cpu_to_be16(rx_buff_ring_entries);
 		cmd.create_rx_queue.enable_rsc =
 			!!(priv->dev->features & NETIF_F_LRO);
-	}
+		if (priv->header_split_enabled)
  • ⚠️ PR commit a010620fcaa (gve: set page count for RX QPL for GQI and DQO queue formats) → upstream b94d3703c1a6
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -54,4 +54,4 @@
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 #define DQO_QPL_DEFAULT_RX_PAGES 2048
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -749,3 +773,2 @@
 	}
-}
  • ⚠️ PR commit 57a23624cb1 (gve: add support to read ring size ranges from the device) → upstream ed4fb326947d
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -42,9 +42,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes,
-			     struct gve_device_option_modify_ring **dev_op_modify_ring)
+			     struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -189,9 +187,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes,
-			   struct gve_device_option_modify_ring **dev_op_modify_ring)
+			   struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -212,8 +208,7 @@
 		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_buffer_sizes,
-					dev_op_modify_ring);
+					dev_op_dqo_qpl);
 		dev_opt = next_opt;
 	}
 
@@ -757,11 +752,7 @@
 					  const struct gve_device_option_jumbo_frames
 					  *dev_op_jumbo_frames,
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl,
-					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes,
-					  const struct gve_device_option_modify_ring
-					  *dev_op_modify_ring)
+					  *dev_op_dqo_qpl)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -805,7 +796,6 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
-	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = NULL;
 	struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
 	struct gve_device_option_modify_ring *dev_op_modify_ring = NULL;
 	struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
@@ -839,9 +829,8 @@
 
 	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_buffer_sizes,
-					 &dev_op_modify_ring);
+					 &dev_op_jumbo_frames,
+					 &dev_op_dqo_qpl);
 	if (err)
 		goto free_device_descriptor;
 
@@ -901,8 +890,7 @@
 	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_buffer_sizes, dev_op_modify_ring);
+				      dev_op_jumbo_frames, dev_op_dqo_qpl);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -124,15 +124,6 @@
 
 static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
 
-struct gve_device_option_buffer_sizes {
-	/* GVE_SUP_BUFFER_SIZES_MASK bit should be set */
-	__be32 supported_features_mask;
-	__be16 packet_buffer_size;
-	__be16 header_buffer_size;
-};
-
-static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
-
 struct gve_device_option_modify_ring {
 	__be32 supported_featured_mask;
 	__be16 max_rx_ring_size;
@@ -152,31 +143,25 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
-	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,
-	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
+	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_DQO_QPL = 0x7,
+	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
-	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_BUFFER_SIZES		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
+	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,
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
-	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
+	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -43,7 +45,8 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
+			     struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			     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);
@@ -206,7 +230,8 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
+			   struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			   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;
@@ -227,7 +252,8 @@
 		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_buffer_sizes);
+					dev_op_dqo_qpl, dev_op_buffer_sizes,
+					dev_op_modify_ring);
 		dev_opt = next_opt;
 	}
 
@@ -776,7 +808,9 @@
 					  const struct gve_device_option_dqo_qpl
 					  *dev_op_dqo_qpl,
 					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes)
+					  *dev_op_buffer_sizes,
+					  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
@@ -865,9 +920,9 @@
 
 	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_buffer_sizes);
+					 &dev_op_jumbo_frames, &dev_op_dqo_qpl,
+					 &dev_op_buffer_sizes,
+					 &dev_op_modify_ring);
 	if (err)
 		goto free_device_descriptor;
 
@@ -928,7 +983,7 @@
 
 	gve_enable_supported_features(priv, supported_features_mask,
 				      dev_op_jumbo_frames, dev_op_dqo_qpl,
-				      dev_op_buffer_sizes);
+				      dev_op_buffer_sizes, dev_op_modify_ring);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -152,13 +162,14 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
-	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_DQO_QPL = 0x7,
-	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
-	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
+	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,
+	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -162,13 +173,14 @@
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
-	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_BUFFER_SIZES = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
+	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_BUFFER_SIZES		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
 };
 
 enum gve_sup_feature_mask {
@@ -172,8 +184,9 @@
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
+	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
+	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -45,6 +45,6 @@
 /* PTYPEs are always 10 bits. */
 #define GVE_NUM_PTYPES	1024
 
 #define GVE_DEFAULT_RX_BUFFER_SIZE 2048
 
-#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
+#define GVE_MAX_RX_BUFFER_SIZE 4096
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -36,6 +35,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -162,6 +179,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -185,7 +204,7 @@
 		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_buffer_sizes);
 		dev_opt = next_opt;
 	}
 
@@ -715,5 +732,7 @@
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl)
+					  *dev_op_dqo_qpl,
+					  const struct gve_device_option_buffer_sizes
+					  *dev_op_buffer_sizes)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -742,6 +765,7 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
+	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = 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;
@@ -780,7 +816,8 @@
 	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_buffer_sizes);
 	if (err)
 		goto free_device_descriptor;
 
@@ -838,6 +874,7 @@
 
 	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_buffer_sizes);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -121,6 +121,6 @@
 
-static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
+static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
 
 /* Terminology:
  *
  * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
@@ -139,6 +145,7 @@
 	GVE_DEV_OPT_ID_DQO_RDA = 0x4,
 	GVE_DEV_OPT_ID_DQO_QPL = 0x7,
 	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
+	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -148,10 +155,12 @@
 	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_BUFFER_SIZES = 0x0,
 };
 
 enum gve_sup_feature_mask {
 	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
  • ⚠️ PR commit 5c6d01261bb (gve: add support to change ring size via ethtool) → upstream 834f9458f2fd
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -482,90 +482,6 @@
 	cmd->tx_pending = priv->tx_desc_cnt;
 }
 
-static int gve_adjust_ring_sizes(struct gve_priv *priv,
-				 u16 new_tx_desc_cnt,
-				 u16 new_rx_desc_cnt)
-{
-	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
-	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
-	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
-	struct gve_qpl_config new_qpl_cfg;
-	int err;
-
-	/* get current queue configuration */
-	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
-				&tx_alloc_cfg, &rx_alloc_cfg);
-
-	/* copy over the new ring_size from ethtool */
-	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
-	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
-
-	/* qpl_cfg is not read-only, it contains a map that gets updated as
-	 * rings are allocated, which is why we cannot use the yet unreleased
-	 * one in priv.
-	 */
-	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-
-	if (netif_running(priv->dev)) {
-		err = gve_adjust_config(priv, &qpls_alloc_cfg,
-					&tx_alloc_cfg, &rx_alloc_cfg);
-		if (err)
-			return err;
-	}
-
-	/* Set new ring_size for the next up */
-	priv->tx_desc_cnt = new_tx_desc_cnt;
-	priv->rx_desc_cnt = new_rx_desc_cnt;
-
-	return 0;
-}
-
-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);
@@ -751,7 +667,6 @@
 	.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,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -503,6 +503,65 @@
 		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
 }
 
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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,
@@ -506,6 +565,12 @@
 			     struct netlink_ext_ack *extack)
 {
 	struct gve_priv *priv = netdev_priv(netdev);
+	u16 new_tx_cnt, new_rx_cnt;
+	int err;
+
+	err = gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	if (err)
+		return err;
 
 	if (priv->tx_desc_cnt != cmd->tx_pending ||
 	    priv->rx_desc_cnt != cmd->rx_pending) {
@@ -507,9 +572,11 @@
 {
 	struct gve_priv *priv = netdev_priv(netdev);
 
-	if (priv->tx_desc_cnt != cmd->tx_pending ||
-	    priv->rx_desc_cnt != cmd->rx_pending) {
-		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+	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;
 	}
 
@@ -513,7 +580,13 @@
 		return -EOPNOTSUPP;
 	}
 
-	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	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)

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -595,6 +487,112 @@
-	.get_coalesce = gve_get_coalesce,
-	.set_coalesce = gve_set_coalesce,
-	.get_ringparam = gve_get_ringparam,
-	.reset = gve_user_reset,
-	.get_tunable = gve_get_tunable,
-	.set_tunable = gve_set_tunable,
+{
+	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_pending = priv->rx_desc_cnt;
+	cmd->tx_pending = priv->tx_desc_cnt;
+
+		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
+}
+
+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);
+
+	if (priv->tx_desc_cnt != cmd->tx_pending ||
+	    priv->rx_desc_cnt != cmd->rx_pending) {
+		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+		return -EOPNOTSUPP;
+	}
+
+	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+}
+
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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)
  • ⚠️ PR commit 539b2e8c09e (gve: Update QPL page registration logic) → upstream 07993df56091
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -703,7 +701,7 @@
 	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 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
+	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 */
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1129,13 +1127,11 @@
 }
 
 static int gve_alloc_qpls(struct gve_priv *priv, struct gve_qpls_alloc_cfg *cfg,
-			  struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
 			  struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
 	int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues;
-	struct gve_queue_page_list *qpls;
 	int rx_start_id, tx_num_qpls, rx_num_qpls;
-	u32 tx_page_count, rx_page_count;
+	struct gve_queue_page_list *qpls;
 	u32 page_count;
 	int err;
 
@@ -1155,38 +1151,8 @@
 		goto free_qpl_array;
 	}
 
-	/* Compute the number of pages per QPL. For DQO-QPL, honor the device's
-	 * max_registered_pages limit by allocating up to (tx ring_size / 2)
-	 * pages per TX QPL and up to (rx ring_size * 2) pages per RX QPL,
-	 * shrinking proportionally if the total would exceed the limit. For
-	 * GQI-QPL the RX page count keeps a 1:1 relationship with descriptors.
-	 */
-	tx_page_count = priv->tx_pages_per_qpl;
-
-	if (cfg->is_gqi) {
-		rx_page_count = rx_alloc_cfg->ring_size;
-	} else {
-		u16 tx_num_queues = cfg->tx_cfg->num_queues;
-		u16 rx_num_queues = cfg->rx_cfg->num_queues;
-		u64 ideal_tx_pages, ideal_rx_pages, max_pages, tx_pages;
-
-		ideal_tx_pages = (u64)tx_alloc_cfg->ring_size * tx_num_queues / 2;
-		ideal_rx_pages = (u64)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_page_count = div_u64(tx_pages, tx_num_queues);
-		rx_page_count = div_u64(max_pages - tx_pages, rx_num_queues);
-	}
-
-	/* Store the computed per-QPL page counts for the datapath to consume */
-	tx_alloc_cfg->pages_per_qpl = tx_page_count;
-	rx_alloc_cfg->pages_per_qpl = rx_page_count;
-
 	/* Allocate TX QPLs */
-	page_count = tx_page_count;
+	page_count = priv->tx_pages_per_qpl;
 	tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues,
 				      gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls);
@@ -1195,7 +1161,15 @@
 
 	/* Allocate RX QPLs */
 	rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg);
-	page_count = rx_page_count;
+	/* For GQI_QPL number of pages allocated have 1:1 relationship with
+	 * number of descriptors. For DQO, number of pages required are
+	 * more than descriptors (because of out of order completions).
+	 * Set it to twice the number of descriptors.
+	 */
+	if (cfg->is_gqi)
+		page_count = rx_alloc_cfg->ring_size;
+	else
+		page_count = gve_get_rx_pages_per_qpl_dqo(rx_alloc_cfg->ring_size);
 	rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls);
 	if (err)
@@ -1420,7 +1393,7 @@
 {
 	int err;
 
-	err = gve_alloc_qpls(priv, qpls_alloc_cfg, tx_alloc_cfg, rx_alloc_cfg);
+	err = gve_alloc_qpls(priv, qpls_alloc_cfg, rx_alloc_cfg);
 	if (err) {
 		netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n");
 		return err;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -178,7 +178,7 @@
 			return err;
 	} else {
 		idx = rx->dqo.next_qpl_page_idx;
-		if (idx >= priv->rx_pages_per_qpl) {
+		if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) {
 			net_err_ratelimited("%s: Out of QPL pages\n",
 					    priv->dev->name);
 			return -ENOMEM;
@@ -293,8 +293,8 @@
 	rx->ctx.skb_tail = NULL;
 
 	rx->dqo.num_buf_states = cfg->raw_addressing ?
-		min_t(u32, S16_MAX, buffer_queue_slots * 4) :
-		min_t(u32, S16_MAX, cfg->pages_per_qpl);
+		min_t(s16, S16_MAX, buffer_queue_slots * 4) :
+		gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
 	rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
 				      sizeof(rx->dqo.buf_states[0]),
 				      GFP_KERNEL);
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -246,10 +246,8 @@
 
 static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx)
 {
-	int num_tx_qpl_bufs = min_t(int,
-				    GVE_TX_BUFS_PER_PAGE_DQO *
-					    tx->dqo.qpl->num_entries,
-				    S16_MAX);
+	int num_tx_qpl_bufs = GVE_TX_BUFS_PER_PAGE_DQO *
+		tx->dqo.qpl->num_entries;
 	int i;
 
 	tx->dqo.tx_qpl_buf_next = kvcalloc(num_tx_qpl_bufs,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -709,6 +707,7 @@
 /* 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;
 
@@ -724,6 +723,7 @@
 	/* 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;
@@ -1149,14 +1150,6 @@
 	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)
@@ -1307,6 +1300,9 @@
 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);
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -970,14 +970,6 @@
 		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 =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -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 @@
 	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,6 +999,40 @@
 	}
 }
 
+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)
@@ -1000,6 +1036,8 @@
 {
 	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 @@
 	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;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -218,7 +218,6 @@
 {
 	struct device *hdev = &priv->pdev->dev;
 	struct page_pool *pool;
-	int qpl_page_cnt;
 	size_t size;
 	u32 qpl_id;
 
@@ -246,7 +245,7 @@
 	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,7 +280,6 @@
 		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);
@@ -284,7 +282,7 @@
 		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;
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -311,7 +311,6 @@
 {
 	struct device *hdev = &priv->pdev->dev;
 	int num_pending_packets;
-	int qpl_page_cnt;
 	size_t bytes;
 	u32 qpl_id;
 	int i;
@@ -392,7 +391,6 @@
 
 	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);
@@ -395,7 +393,7 @@
 		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;
 

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -57,5 +57,5 @@
 
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 
@@ -658,4 +674,3 @@
 
-	u16 ring_size;
-	bool raw_addressing;
-	bool enable_header_split;
+	u16 num_xdp_rings;
+
@@ -1030,6 +1158,6 @@
 	return 2 * rx_desc_cnt;
 }
 
-/* Returns a pointer to the next available tx qpl in the list of qpls */
-static inline
-struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg,
+/* 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)
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -782,6 +978,6 @@
 			priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
 	}
 
-	/* Read and store ring size ranges given by device */
-	if (dev_op_modify_ring &&
-	    (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
+	if (dev_op_buffer_sizes &&
+	    (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) {
+		priv->max_rx_buffer_size =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -7,5 +6,6 @@
 #include <linux/filter.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
@@ -1326,4 +1290,5 @@
-	cfg->qpls = priv->qpls;
-	cfg->qpl_cfg = &priv->qpl_cfg;
+	cfg->raw_addressing = !gve_is_qpl(priv);
+	cfg->enable_header_split = priv->header_split_enabled;
 	cfg->ring_size = priv->rx_desc_cnt;
+	cfg->packet_buffer_size = priv->rx_cfg.packet_buffer_size;
 	cfg->rx = priv->rx;
@@ -1447,6 +1369,6 @@
-	priv->rx_cfg = *rx_alloc_cfg->qcfg;
+	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;
 
-	if (priv->xdp_prog)
-		priv->num_xdp_queues = priv->rx_cfg.num_queues;
+	gve_tx_start_rings(priv, gve_num_tx_queues(priv));
+	gve_rx_start_rings(priv, rx_alloc_cfg->qcfg_rx->num_queues);
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -290,8 +278,10 @@
-	rx->ctx.skb_tail = NULL;
+		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.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);
-	rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
-				      sizeof(rx->dqo.buf_states[0]),
-				      GFP_KERNEL);
+		rx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
+							qpl_page_cnt);
+		if (!rx->dqo.qpl)
+			goto err;
+		rx->dqo.next_qpl_page_idx = 0;
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -243,4 +243,7 @@
 {
-	int num_tx_qpl_bufs = GVE_TX_BUFS_PER_PAGE_DQO *
-		tx->dqo.qpl->num_entries;
+	struct device *hdev = &priv->pdev->dev;
+	int num_pending_packets;
+	int qpl_page_cnt;
+	size_t bytes;
+	u32 qpl_id;
 	int i;

================================================================================
*    ONLY IN PATCH2 - files not modified by patch1                             *
================================================================================

--- a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -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;
  • ❌ PR commit b26a94060ec (gve: Remove unused declaration gve_rx_alloc_rings())359c5eb0f736
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060
    fatal: bad object 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060

  • ❌ PR commit 5f08c240a72 (gve: Fix use of netif_carrier_ok())fba917b169be
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout fba917b169bea48b7f2c8c46e084a2e2b3512b76
    fatal: bad object fba917b169bea48b7f2c8c46e084a2e2b3512b76

  • ❌ PR commit 54ffe647799 (gve: fix XDP allocation path in edge cases)de63ac44a527
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout de63ac44a527b6c626ba7adb54873d4d6bd8de23
    fatal: bad object de63ac44a527b6c626ba7adb54873d4d6bd8de23

  • ⚠️ PR commit 45501194369 (gve: prevent ethtool ops after shutdown) → upstream 75a9a46d67f4
    Differences found:

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -2643,2 +2643,3 @@
 	rtnl_lock();
+	netdev_lock(netdev);
 	if (was_up && gve_close(priv->dev)) {

This is an automated interdiff check for backported commits.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/30919502665

@ciq-kernel-automation ciq-kernel-automation Bot changed the title [rlc-9/5.14.0-687.31.1.el9_8] Multiple patches tested (15 commits) [rlc-9/5.14.0-687.31.1.el9_8] Multiple patches tested (17 commits) Aug 4, 2026
shailend-g and others added 16 commits August 6, 2026 11:22
jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit f13697c
upstream-diff Conflicts in gve.h and gve_main.c: kept RLC 9's existing
  gve_add_napi()/gve_remove_napi() helpers (now called from the per-ring
  start functions in gve_tx.c/gve_rx.c), made them non-static and declared
  them in gve.h so the cross-file callers link, and preserved RLC 9's
  gve_xsk_tx_poll() prototype. The error-cleanup loops in
  gve_tx_alloc_rings_gqi()/_dqo() start at cfg->start_idx (not 0) so a
  failed XDP ring alloc does not free live non-XDP rings, and
  gve_add_xdp_queues() has an unreg_xdp_qpls label to unregister QPLs
  before freeing them on a create failure.

The new config-aware functions will help achieve the goal of being able
to allocate resources for new queues while there already are active
queues serving traffic.

These new functions work off of arbitrary queue allocation configs
rather than just the currently active config in priv, and they return
the newly allocated resources instead of writing them into priv.

	Signed-off-by: Shailend Chand <shailend@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Reviewed-by: Jeroen de Borst <jeroendb@google.com>
	Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240122182632.1102721-4-shailend@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit f13697c)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 92a6d7a

gve_open is rewritten to be composed of two funcs: gve_queues_mem_alloc
and gve_queues_start. The former only allocates queue resources without
doing anything to install the queues, which is taken up by the latter.
Similarly gve_close is split into gve_queues_stop and
gve_queues_mem_free.

Separating the acts of queue resource allocation and making the queue
become live help with subsequent changes that aim to not take down the
datapath when applying new configurations.

	Signed-off-by: Shailend Chand <shailend@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Reviewed-by: Jeroen de Borst <jeroendb@google.com>
Link: https://lore.kernel.org/r/20240122182632.1102721-5-shailend@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 92a6d7a)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit 5f08cd3

Previously, existing queues were being freed before the resources for
the new queues were being allocated. This would take down the interface
if someone were to attempt to change queue counts under a resource
crunch.

	Signed-off-by: Shailend Chand <shailend@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Reviewed-by: Jeroen de Borst <jeroendb@google.com>
Link: https://lore.kernel.org/r/20240122182632.1102721-6-shailend@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 5f08cd3)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Shailend Chand <shailend@google.com>
commit f375377

Previously, existing queues were being freed before the resources for
the new queues were being allocated. This would take down the interface
if someone were to attempt to change feature flags under a resource
crunch.

	Signed-off-by: Shailend Chand <shailend@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Reviewed-by: Jeroen de Borst <jeroendb@google.com>
Link: https://lore.kernel.org/r/20240122182632.1102721-7-shailend@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit f375377)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 4cbc70f

Combine the gve_set_desc_cnt and gve_set_desc_cnt_dqo into
one function which sets the counts after checking the queue
format. Both the functions in the previous code and the new
combined function never return an error so make the new
function void and remove the goto on error.

Also rename the new function to gve_set_default_desc_cnt to
be clearer about its intention.

	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 4cbc70f)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 5dee3c7

For the DQO queue format, the gve driver stores two ring sizes
for both TX and RX - one for completion queue ring and one for
data buffer ring. This is supposed to enable asymmetric sizes
for these two rings but that is not supported. Make both fields
reference the same single variable.

This change renders reading supported TX completion ring size
and RX buffer ring size for DQO from the device useless, so change
those fields to reserved and remove related code.

	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 5dee3c7)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit b94d370

Fulfill the requirement that for GQI, the number of pages per
RX QPL is equal to the ring size. Set this value to be equal to
ring size. Because of this change, the rx_data_slot_cnt and
rx_pages_per_qpl fields stored in the priv structure are not
needed, so remove their usage. And for DQO, the number of pages
per RX QPL is more than ring size to account for out-of-order
completions. So set it to two times of rx ring size.

	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit b94d370)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit ed4fb32
upstream-diff Kept only the MODIFY_RING handling. Dropped the
  BUFFER_SIZES option case and enable block (depend on header-split
  fields not present in RLC 9); the dev_op_buffer_sizes param is kept as
  NULL plumbing to preserve upstream signatures.

Up until now, the ring size if configurable was only configurable to the
two limits: default and min. This change allows the driver to read the
ring size ranges from the device and use them if provided by the device.

	Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Shailend Chand <shailend@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit ed4fb32)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Harshitha Ramamurthy <hramamurthy@google.com>
commit 834f945
upstream-diff Resolved conflict in gve_ethtool.c against RLC 9. Omitted
  the header-split (tcp_data_split) handling in gve_get_ringparam and the
  gve_set_hsplit_config() call in gve_set_ringparam, as the header-split
  feature (gve_header_split_supported / priv->header_split_enabled /
  gve_set_hsplit_config) is not present in RLC 9 and is unrelated to
  ring-size support. Added the ".set_ringparam = gve_set_ringparam" entry
  to gve_ethtool_ops, which upstream carried on a pre-existing stub that
  RLC 9 did not have. gve_adjust_ring_sizes uses the qpls_alloc_cfg form
  matching the pre-qpl-removal queue-alloc config in RLC 9.

This change adds support to change ring size via ethtool -G. The ring
size is validated against the min and max ring size limits provided by
the device, and must be a power of 2.

	Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Shailend Chand <shailend@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 834f945)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Matt Olson <maolson@google.com>
commit 07993df
upstream-diff gve_update_num_qpl_pages()'s page math is inlined in
  gve_alloc_qpls(), since RLC 9 keeps the pool-based QPL model: u32
  intermediates and (u64) casts on the math; the GQI branch writes both tx
  and rx counts (upstream writes only rx via get-curr seeding this backport
  lacks); cfg->is_gqi gating and cfg->tx_cfg/rx_cfg queue counts in place of
  upstream's queue_format/qcfg forms. rx_page_count > U16_MAX is rejected
  and the QPLs are sized from the u16 pages_per_qpl fields so QPL size and
  num_buf_states agree; tx_num_qpls is derived from the xdp_prog-aware
  tx_alloc_cfg->num_rings (from upstream 542a58f, paired with the
  gve_set_channels() guard in de63ac4); num_buf_states (both arms) and
  num_tx_qpl_bufs are clamped to S16_MAX; cfg->pages_per_qpl is initialized
  in the get-curr helpers.

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 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".

	Signed-off-by: Matt Olson <maolson@google.com>
	Signed-off-by: Joshua Washington <joshwash@google.com>
	Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 07993df)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Matt Olson <maolson@google.com>
commit a2f1918

The gVNIC device indicates a device option (MODIFY_RING) to the driver,
which presents a range of ring sizes from which the user is allowed to
select. But in DQO-QPL queue format, the driver ignores the "max" of
this range and instead allows the user to configure the ring size in the
range [min, default]. This was done because increasing the ring size
could result in the number of registered pages being higher than the max
allowed by the device.

In order to support large ring sizes, stop ignoring the "max" of the
range presented in the MODIFY_RING option.

	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: Praveen Kaligineedi <pkaligineedi@google.com>
	Signed-off-by: Joshua Washington <joshwash@google.com>
Link: https://patch.msgid.link/20260225182342.1049816-3-joshwash@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit a2f1918)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Ziwei Xiao <ziweixiao@google.com>
commit 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060
upstream-diff The removed line (int gve_rx_alloc_rings(struct gve_priv *))
  is identical to upstream, but it applies against different surrounding
  context: upstream deletes it just below the singular gve_rx_alloc_ring_gqi/
  gve_rx_free_ring_gqi declarations, which RLC 9's gve.h does not carry
  (this branch predates the singular-ring-helper split and uses only the
  plural gve_rx_alloc_rings_gqi/gve_rx_free_rings_gqi forms). The deletion
  was reanchored below gve_rx_work_pending() accordingly; no other lines
  change.

Remove the unused declaration gve_rx_alloc_rings() in gve.h, which has no
definition anywhere in the driver.

	Signed-off-by: Ziwei Xiao <ziweixiao@google.com>
	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Ziwei Xiao <ziweixiao@google.com>
commit fba917b169bea48b7f2c8c46e084a2e2b3512b76
upstream-diff Kept RLC 9's 4-arg gve_adjust_config(priv, &qpls_alloc_cfg,
  &tx_alloc_cfg, &rx_alloc_cfg) signature and the existing inline
  feature-revert in gve_set_features (RLC 9 lacks the later qpl-cfg
  removal and the goto revert_features refactor); only the
  netif_carrier_ok()->netif_running() change from this commit was taken.

The driver was using netif_carrier_ok() to check the interface state,
which reflects link (carrier) state, not administrative state. Switch the
administrative-state checks to netif_running() so that reconfiguration
paths reallocate rings for an interface that is up but whose carrier is
down.

	Signed-off-by: Ziwei Xiao <ziweixiao@google.com>
	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit fba917b169bea48b7f2c8c46e084a2e2b3512b76)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Joshua Washington <joshwash@google.com>
commit de63ac44a527b6c626ba7adb54873d4d6bd8de23
upstream-diff Kept RLC 9's qpls_alloc_cfg / new_qpl_cfg locals in
  gve_adjust_queues (pool-based QPL model; RLC 9 lacks the later qpl-cfg
  removal) alongside the num_xdp_queues local this commit adds; functional
  hunks apply unchanged. gve_set_channels() guards its XDP symmetry check
  on priv->xdp_prog instead of priv->num_xdp_queues (0 when the program is
  attached while the interface is down), from the guard change in upstream
  542a58f, whose full form depends on the num_xdp_queues->cfg
  refactor RLC 9 does not take.

This patch fixes a number of consistency issues in the queue allocation
path related to XDP. The number of allocated XDP queues now consistently
tracks priv->xdp_prog across the up/down and program add/remove paths.

	Signed-off-by: Joshua Washington <joshwash@google.com>
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit de63ac44a527b6c626ba7adb54873d4d6bd8de23)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Joshua Washington <joshwash@google.com>
commit 6321f5f

When stopping XDP TX rings, the XDP clean function needs to be called to
clean out the entire queue, similar to what happens in the normal TX
queue case. Otherwise, the FIFO won't be cleared correctly, and
xsk_tx_completed won't be reported.

Fixes: 75eaae1 ("gve: Add XDP DROP and TX support for GQI-QPL format")
	Cc: stable@vger.kernel.org
	Signed-off-by: Joshua Washington <joshwash@google.com>
	Signed-off-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Praveen Kaligineedi <pkaligineedi@google.com>
	Reviewed-by: Willem de Bruijn <willemb@google.com>
	Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 6321f5f)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
jira KERNEL-1218
commit-author Jordan Rhee <jordanrhee@google.com>
commit 75a9a46

A crash can occur if an ethtool operation is invoked
after shutdown() is called.

shutdown() is invoked during system shutdown to stop DMA operations
without performing expensive deallocations. It is discouraged to
unregister the netdev in this path, so the device may still be visible
to userspace and kernel helpers.

In gve, shutdown() tears down most internal data structures. If an
ethtool operation is dispatched after shutdown(), it will dereference
freed or NULL pointers, leading to a kernel panic. While graceful
shutdown normally quiesces userspace before invoking the reboot
syscall, forced shutdowns (as observed on GCP VMs) can still trigger
this path.

Fix by calling netif_device_detach() in shutdown().
This marks the device as detached so the ethtool ioctl handler
will skip dispatching operations to the driver.

Fixes: 974365e ("gve: Implement suspend/resume/shutdown")
	Signed-off-by: Jordan Rhee <jordanrhee@google.com>
	Signed-off-by: Jeroen de Borst <jeroendb@google.com>
Link: https://patch.msgid.link/20250818211245.1156919-1-jeroendb@google.com
	Signed-off-by: Jakub Kicinski <kuba@kernel.org>
(cherry picked from commit 75a9a46)
	Signed-off-by: Shreeya Patel <spatel@ciq.com>
@shreeya-patel98
shreeya-patel98 force-pushed the {shreeya_gce}_rlc-9/5.14.0-687.31.1.el9_8 branch from 4550119 to 56fb607 Compare August 6, 2026 11:25
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/31097964018

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔍 Upstream Linux Kernel Commit Check

  • ⚠️ PR commit 8b4dc437a0b (gve: Alloc before freeing when adjusting queues) references upstream commit
    5f08cd3d6423 which has been referenced by a Fixes: tag in the upstream
    Linux kernel:
    de63ac44a52 gve: fix XDP allocation path in edge cases (Joshua Washington)
    fba917b169b gve: Fix use of netif_carrier_ok() (Praveen Kaligineedi)
  • ❗ PR commit 19573271446 (gve: Remove unused declaration gve_rx_alloc_rings()) references upstream commit
    359c5eb0f736 which does not exist in the upstream Linux kernel.

  • ❗ PR commit d7c93110786 (gve: Fix use of netif_carrier_ok()) references upstream commit
    fba917b169be which does not exist in the upstream Linux kernel.

  • ❗ PR commit 6897e23b1a4 (gve: fix XDP allocation path in edge cases) references upstream commit
    de63ac44a527 which does not exist in the upstream Linux kernel.

  • ⚠️ PR commit 56fb60775a7 (gve: prevent ethtool ops after shutdown) does not reference a CVE but
    upstream commit 75a9a46d67f4 is associated with CVE-2025-38735

This is an automated message from the kernel commit checker workflow.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔍 Interdiff Analysis

  • ⚠️ PR commit d5596b74888 (gve: Switch to config-aware queue allocation) → upstream f13697cc7a19
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1119,12 +1115,6 @@
 			   struct gve_rx_alloc_rings_cfg *cfg);
 void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);
 void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx);
-/* napi handling */
-int gve_napi_poll(struct napi_struct *napi, int budget);
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget);
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int));
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx);
 /* Reset */
 void gve_schedule_reset(struct gve_priv *priv);
 int gve_reset(struct gve_priv *priv, bool attempt_teardown);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -253,7 +253,7 @@
 	return IRQ_HANDLED;
 }
 
-int gve_napi_poll(struct napi_struct *napi, int budget)
+static int gve_napi_poll(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block;
 	__be32 __iomem *irq_doorbell;
@@ -311,7 +311,7 @@
 	return work_done;
 }
 
-int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
+static int gve_napi_poll_dqo(struct napi_struct *napi, int budget)
 {
 	struct gve_notify_block *block =
 		container_of(napi, struct gve_notify_block, napi);
@@ -590,15 +590,15 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-		  int (*gve_poll)(struct napi_struct *, int))
+static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
+			 int (*gve_poll)(struct napi_struct *, int))
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 
 	netif_napi_add(priv->dev, &block->napi, gve_poll);
 }
 
-void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
+static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
 {
 	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
 
@@ -1315,13 +1315,13 @@
 static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv,
 					struct gve_qpls_alloc_cfg *cfg)
 {
-	cfg->raw_addressing = !gve_is_qpl(priv);
-	cfg->is_gqi = gve_is_gqi(priv);
-	cfg->num_xdp_queues = priv->num_xdp_queues;
-	cfg->qpl_cfg = &priv->qpl_cfg;
-	cfg->tx_cfg = &priv->tx_cfg;
-	cfg->rx_cfg = &priv->rx_cfg;
-	cfg->qpls = priv->qpls;
+	  cfg->raw_addressing = !gve_is_qpl(priv);
+	  cfg->is_gqi = gve_is_gqi(priv);
+	  cfg->num_xdp_queues = priv->num_xdp_queues;
+	  cfg->qpl_cfg = &priv->qpl_cfg;
+	  cfg->tx_cfg = &priv->tx_cfg;
+	  cfg->rx_cfg = &priv->rx_cfg;
+	  cfg->qpls = priv->qpls;
 }
 
 static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv,
@@ -1556,12 +1556,10 @@
 
 	err = gve_create_xdp_rings(priv);
 	if (err)
-		goto unreg_xdp_qpls;
+		goto free_xdp_rings;
 
 	return 0;
 
-unreg_xdp_qpls:
-	gve_unregister_xdp_qpls(priv);
 free_xdp_rings:
 	gve_free_xdp_rings(priv);
 free_xdp_qpls:
--- b/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -358,7 +358,7 @@
 	return 0;
 
 cleanup:
-	for (j = cfg->start_idx; j < i; j++)
+	for (j = 0; j < i; j++)
 		gve_tx_free_ring_gqi(priv, &tx[j], cfg);
 	if (cfg->start_idx == 0)
 		kvfree(tx);
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -413,7 +413,7 @@
 	return 0;
 
 err:
-	for (j = cfg->start_idx; j < i; j++)
+	for (j = 0; j < i; j++)
 		gve_tx_free_ring_dqo(priv, &tx[j], cfg);
 	if (cfg->start_idx == 0)
 		kvfree(tx);

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1102,8 +1101,12 @@
 void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid);
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
-void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
+int gve_tx_alloc_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_free_rings_gqi(struct gve_priv *priv,
+			   struct gve_tx_alloc_rings_cfg *cfg);
+void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx);
+void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -1097,8 +1087,7 @@
 bool gve_tx_poll(struct gve_notify_block *block, int budget);
 bool gve_xdp_poll(struct gve_notify_block *block, int budget);
-int gve_xsk_tx_poll(struct gve_notify_block *block, int budget);
 int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings);
 void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings);
 u32 gve_tx_load_event_counter(struct gve_priv *priv,
 			      struct gve_tx_ring *tx);
 bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx);
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -590,21 +582,6 @@
 	gve_clear_device_resources_ok(priv);
 }
 
-static void gve_add_napi(struct gve_priv *priv, int ntfy_idx,
-			 int (*gve_poll)(struct napi_struct *, int))
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_add(priv->dev, &block->napi, gve_poll);
-}
-
-static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx)
-{
-	struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
-
-	netif_napi_del(&block->napi);
-}
-
 static int gve_register_xdp_qpls(struct gve_priv *priv)
 {
 	int start_id;
  • ⚠️ PR commit b1b837b76a3 (gve: make the completion and buffer ring size equal for DQO) → upstream 5dee3c702c20
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -640,4 +659,4 @@
 			cpu_to_be16(rx_buff_ring_entries);
 		cmd.create_rx_queue.enable_rsc =
 			!!(priv->dev->features & NETIF_F_LRO);
-	}
+		if (priv->header_split_enabled)
  • ⚠️ PR commit f43f51ef91b (gve: set page count for RX QPL for GQI and DQO queue formats) → upstream b94d3703c1a6
    Differences found:
================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -54,4 +54,4 @@
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 #define DQO_QPL_DEFAULT_RX_PAGES 2048
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -749,3 +773,2 @@
 	}
-}
  • ⚠️ PR commit ec6f7e2be57 (gve: add support to read ring size ranges from the device) → upstream ed4fb326947d
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -42,9 +42,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes,
-			     struct gve_device_option_modify_ring **dev_op_modify_ring)
+			     struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -189,9 +187,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes,
-			   struct gve_device_option_modify_ring **dev_op_modify_ring)
+			   struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -212,8 +208,7 @@
 		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_buffer_sizes,
-					dev_op_modify_ring);
+					dev_op_dqo_qpl);
 		dev_opt = next_opt;
 	}
 
@@ -757,11 +752,7 @@
 					  const struct gve_device_option_jumbo_frames
 					  *dev_op_jumbo_frames,
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl,
-					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes,
-					  const struct gve_device_option_modify_ring
-					  *dev_op_modify_ring)
+					  *dev_op_dqo_qpl)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -805,7 +796,6 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
-	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = NULL;
 	struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
 	struct gve_device_option_modify_ring *dev_op_modify_ring = NULL;
 	struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
@@ -839,9 +829,8 @@
 
 	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_buffer_sizes,
-					 &dev_op_modify_ring);
+					 &dev_op_jumbo_frames,
+					 &dev_op_dqo_qpl);
 	if (err)
 		goto free_device_descriptor;
 
@@ -901,8 +890,7 @@
 	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_buffer_sizes, dev_op_modify_ring);
+				      dev_op_jumbo_frames, dev_op_dqo_qpl);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -124,15 +124,6 @@
 
 static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
 
-struct gve_device_option_buffer_sizes {
-	/* GVE_SUP_BUFFER_SIZES_MASK bit should be set */
-	__be32 supported_features_mask;
-	__be16 packet_buffer_size;
-	__be16 header_buffer_size;
-};
-
-static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
-
 struct gve_device_option_modify_ring {
 	__be32 supported_featured_mask;
 	__be16 max_rx_ring_size;
@@ -152,31 +143,25 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
-	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,
-	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
+	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_DQO_QPL = 0x7,
+	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
-	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_BUFFER_SIZES		= 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
+	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,
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
-	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
+	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -43,7 +45,8 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
+			     struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			     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);
@@ -206,7 +230,8 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
+			   struct gve_device_option_buffer_sizes **dev_op_buffer_sizes,
+			   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;
@@ -227,7 +252,8 @@
 		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_buffer_sizes);
+					dev_op_dqo_qpl, dev_op_buffer_sizes,
+					dev_op_modify_ring);
 		dev_opt = next_opt;
 	}
 
@@ -776,7 +808,9 @@
 					  const struct gve_device_option_dqo_qpl
 					  *dev_op_dqo_qpl,
 					  const struct gve_device_option_buffer_sizes
-					  *dev_op_buffer_sizes)
+					  *dev_op_buffer_sizes,
+					  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
@@ -865,9 +920,9 @@
 
 	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_buffer_sizes);
+					 &dev_op_jumbo_frames, &dev_op_dqo_qpl,
+					 &dev_op_buffer_sizes,
+					 &dev_op_modify_ring);
 	if (err)
 		goto free_device_descriptor;
 
@@ -928,7 +983,7 @@
 
 	gve_enable_supported_features(priv, supported_features_mask,
 				      dev_op_jumbo_frames, dev_op_dqo_qpl,
-				      dev_op_buffer_sizes);
+				      dev_op_buffer_sizes, dev_op_modify_ring);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -152,13 +162,14 @@
  *       the device for read/write and data is copied from/to SKBs.
  */
 enum gve_dev_opt_id {
-	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
-	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_DQO_QPL = 0x7,
-	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
-	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
+	GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING	= 0x1,
+	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,
+	GVE_DEV_OPT_ID_BUFFER_SIZES		= 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -162,13 +173,14 @@
 };
 
 enum gve_dev_opt_req_feat_mask {
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
-	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
-	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_BUFFER_SIZES = 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING	= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL		= 0x0,
+	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_BUFFER_SIZES		= 0x0,
+	GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING		= 0x0,
 };
 
 enum gve_sup_feature_mask {
@@ -172,8 +184,9 @@
 };
 
 enum gve_sup_feature_mask {
-	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
-	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
+	GVE_SUP_MODIFY_RING_MASK	= 1 << 0,
+	GVE_SUP_JUMBO_FRAMES_MASK	= 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK	= 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -45,6 +45,6 @@
 /* PTYPEs are always 10 bits. */
 #define GVE_NUM_PTYPES	1024
 
 #define GVE_DEFAULT_RX_BUFFER_SIZE 2048
 
-#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
+#define GVE_MAX_RX_BUFFER_SIZE 4096
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -36,6 +35,7 @@
 			     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_buffer_sizes **dev_op_buffer_sizes)
 {
 	u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
 	u16 option_length = be16_to_cpu(option->option_length);
@@ -162,6 +179,7 @@
 			   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_buffer_sizes **dev_op_buffer_sizes)
 {
 	const int num_options = be16_to_cpu(descriptor->num_device_options);
 	struct gve_device_option *dev_opt;
@@ -185,7 +204,7 @@
 		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_buffer_sizes);
 		dev_opt = next_opt;
 	}
 
@@ -715,5 +732,7 @@
 					  const struct gve_device_option_dqo_qpl
-					  *dev_op_dqo_qpl)
+					  *dev_op_dqo_qpl,
+					  const struct gve_device_option_buffer_sizes
+					  *dev_op_buffer_sizes)
 {
 	/* Before control reaches this point, the page-size-capped max MTU from
 	 * the gve_device_descriptor field has already been stored in
@@ -742,6 +765,7 @@
 
 int gve_adminq_describe_device(struct gve_priv *priv)
 {
+	struct gve_device_option_buffer_sizes *dev_op_buffer_sizes = 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;
@@ -780,7 +816,8 @@
 	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_buffer_sizes);
 	if (err)
 		goto free_device_descriptor;
 
@@ -838,6 +874,7 @@
 
 	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_buffer_sizes);
 
 free_device_descriptor:
 	dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
--- b/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -121,6 +121,6 @@
 
-static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
+static_assert(sizeof(struct gve_device_option_buffer_sizes) == 8);
 
 /* Terminology:
  *
  * RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
@@ -139,6 +145,7 @@
 	GVE_DEV_OPT_ID_DQO_RDA = 0x4,
 	GVE_DEV_OPT_ID_DQO_QPL = 0x7,
 	GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
+	GVE_DEV_OPT_ID_BUFFER_SIZES = 0xa,
 };
 
 enum gve_dev_opt_req_feat_mask {
@@ -148,10 +155,12 @@
 	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_BUFFER_SIZES = 0x0,
 };
 
 enum gve_sup_feature_mask {
 	GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
+	GVE_SUP_BUFFER_SIZES_MASK = 1 << 4,
 };
 
 #define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
  • ⚠️ PR commit 21e0ccc9f96 (gve: add support to change ring size via ethtool) → upstream 834f9458f2fd
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -482,90 +482,6 @@
 	cmd->tx_pending = priv->tx_desc_cnt;
 }
 
-static int gve_adjust_ring_sizes(struct gve_priv *priv,
-				 u16 new_tx_desc_cnt,
-				 u16 new_rx_desc_cnt)
-{
-	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
-	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
-	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
-	struct gve_qpl_config new_qpl_cfg;
-	int err;
-
-	/* get current queue configuration */
-	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
-				&tx_alloc_cfg, &rx_alloc_cfg);
-
-	/* copy over the new ring_size from ethtool */
-	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
-	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
-
-	/* qpl_cfg is not read-only, it contains a map that gets updated as
-	 * rings are allocated, which is why we cannot use the yet unreleased
-	 * one in priv.
-	 */
-	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
-
-	if (netif_running(priv->dev)) {
-		err = gve_adjust_config(priv, &qpls_alloc_cfg,
-					&tx_alloc_cfg, &rx_alloc_cfg);
-		if (err)
-			return err;
-	}
-
-	/* Set new ring_size for the next up */
-	priv->tx_desc_cnt = new_tx_desc_cnt;
-	priv->rx_desc_cnt = new_rx_desc_cnt;
-
-	return 0;
-}
-
-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);
@@ -751,7 +667,6 @@
 	.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,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -503,6 +503,65 @@
 		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
 }
 
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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,
@@ -506,6 +565,12 @@
 			     struct netlink_ext_ack *extack)
 {
 	struct gve_priv *priv = netdev_priv(netdev);
+	u16 new_tx_cnt, new_rx_cnt;
+	int err;
+
+	err = gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	if (err)
+		return err;
 
 	if (priv->tx_desc_cnt != cmd->tx_pending ||
 	    priv->rx_desc_cnt != cmd->rx_pending) {
@@ -507,9 +572,11 @@
 {
 	struct gve_priv *priv = netdev_priv(netdev);
 
-	if (priv->tx_desc_cnt != cmd->tx_pending ||
-	    priv->rx_desc_cnt != cmd->rx_pending) {
-		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+	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;
 	}
 
@@ -513,7 +580,13 @@
 		return -EOPNOTSUPP;
 	}
 
-	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+	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)

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -595,6 +487,112 @@
-	.get_coalesce = gve_get_coalesce,
-	.set_coalesce = gve_set_coalesce,
-	.get_ringparam = gve_get_ringparam,
-	.reset = gve_user_reset,
-	.get_tunable = gve_get_tunable,
-	.set_tunable = gve_set_tunable,
+{
+	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_pending = priv->rx_desc_cnt;
+	cmd->tx_pending = priv->tx_desc_cnt;
+
+		kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_DISABLED;
+}
+
+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);
+
+	if (priv->tx_desc_cnt != cmd->tx_pending ||
+	    priv->rx_desc_cnt != cmd->rx_pending) {
+		dev_info(&priv->pdev->dev, "Modify ring size is not supported.\n");
+		return -EOPNOTSUPP;
+	}
+
+	return gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split);
+}
+
+static int gve_adjust_ring_sizes(struct gve_priv *priv,
+				 u16 new_tx_desc_cnt,
+				 u16 new_rx_desc_cnt)
+{
+	struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0};
+	struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0};
+	struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0};
+	struct gve_qpl_config new_qpl_cfg;
+	int err;
+
+	/* get current queue configuration */
+	gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg,
+				&tx_alloc_cfg, &rx_alloc_cfg);
+
+	/* copy over the new ring_size from ethtool */
+	tx_alloc_cfg.ring_size = new_tx_desc_cnt;
+	rx_alloc_cfg.ring_size = new_rx_desc_cnt;
+
+	/* qpl_cfg is not read-only, it contains a map that gets updated as
+	 * rings are allocated, which is why we cannot use the yet unreleased
+	 * one in priv.
+	 */
+	qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	tx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+	rx_alloc_cfg.qpl_cfg = &new_qpl_cfg;
+
+	if (netif_running(priv->dev)) {
+		err = gve_adjust_config(priv, &qpls_alloc_cfg,
+					&tx_alloc_cfg, &rx_alloc_cfg);
+		if (err)
+			return err;
+	}
+
+	/* Set new ring_size for the next up */
+	priv->tx_desc_cnt = new_tx_desc_cnt;
+	priv->rx_desc_cnt = new_rx_desc_cnt;
+
+	return 0;
+}
+
+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)
  • ⚠️ PR commit 47052263b0a (gve: Update QPL page registration logic) → upstream 07993df56091
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -703,7 +701,7 @@
 	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 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
+	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 */
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -1129,13 +1127,11 @@
 }
 
 static int gve_alloc_qpls(struct gve_priv *priv, struct gve_qpls_alloc_cfg *cfg,
-			  struct gve_tx_alloc_rings_cfg *tx_alloc_cfg,
 			  struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
 {
 	int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues;
-	struct gve_queue_page_list *qpls;
 	int rx_start_id, tx_num_qpls, rx_num_qpls;
-	u32 tx_page_count, rx_page_count;
+	struct gve_queue_page_list *qpls;
 	u32 page_count;
 	int err;
 
@@ -1155,62 +1151,25 @@
 		goto free_qpl_array;
 	}
 
-	/* Compute the number of pages per QPL. For DQO-QPL, honor the device's
-	 * max_registered_pages limit by allocating up to (tx ring_size / 2)
-	 * pages per TX QPL and up to (rx ring_size * 2) pages per RX QPL,
-	 * shrinking proportionally if the total would exceed the limit. For
-	 * GQI-QPL the RX page count keeps a 1:1 relationship with descriptors.
-	 */
-	tx_page_count = priv->tx_pages_per_qpl;
-
-	if (cfg->is_gqi) {
-		rx_page_count = rx_alloc_cfg->ring_size;
-	} else {
-		u64 ideal_tx_pages, ideal_rx_pages, max_pages, tx_pages;
-		u16 tx_num_queues = cfg->tx_cfg->num_queues;
-		u16 rx_num_queues = cfg->rx_cfg->num_queues;
-
-		ideal_tx_pages = (u64)tx_alloc_cfg->ring_size * tx_num_queues / 2;
-		ideal_rx_pages = (u64)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_page_count = div_u64(tx_pages, tx_num_queues);
-		rx_page_count = div_u64(max_pages - tx_pages, rx_num_queues);
-	}
-
-	/* The per-QPL page count is stored in a u16 cfg field; reject a ring
-	 * size whose count would not fit rather than truncate it (which would
-	 * yield a 0-length buffer-state allocation and an out-of-bounds free
-	 * list). The datapath consumes the u16 field, so the QPL is allocated
-	 * from the same field to keep its size and num_buf_states in agreement.
-	 */
-	if (rx_page_count > U16_MAX) {
-		err = -EINVAL;
-		goto free_qpl_map;
-	}
-
-	/* Store the computed per-QPL page counts for the datapath to consume */
-	tx_alloc_cfg->pages_per_qpl = tx_page_count;
-	rx_alloc_cfg->pages_per_qpl = rx_page_count;
-
-	/* Allocate TX QPLs. Derive the count from the (already xdp_prog-aware)
-	 * TX ring count in tx_alloc_cfg->num_rings rather than the qpls cfg's
-	 * own num_xdp_queues, which is filled from the possibly-stale
-	 * priv->num_xdp_queues and would otherwise disagree with the ring count
-	 * (leaving XDP TX rings backed by zeroed QPL entries).
-	 */
-	page_count = tx_alloc_cfg->pages_per_qpl;
-	tx_num_qpls = gve_is_qpl(priv) ? tx_alloc_cfg->num_rings : 0;
+	/* Allocate TX QPLs */
+	page_count = priv->tx_pages_per_qpl;
+	tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues,
+				      gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls);
 	if (err)
 		goto free_qpl_map;
 
 	/* Allocate RX QPLs */
 	rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg);
-	page_count = rx_alloc_cfg->pages_per_qpl;
+	/* For GQI_QPL number of pages allocated have 1:1 relationship with
+	 * number of descriptors. For DQO, number of pages required are
+	 * more than descriptors (because of out of order completions).
+	 * Set it to twice the number of descriptors.
+	 */
+	if (cfg->is_gqi)
+		page_count = rx_alloc_cfg->ring_size;
+	else
+		page_count = gve_get_rx_pages_per_qpl_dqo(rx_alloc_cfg->ring_size);
 	rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv));
 	err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls);
 	if (err)
@@ -1435,7 +1393,7 @@
 {
 	int err;
 
-	err = gve_alloc_qpls(priv, qpls_alloc_cfg, tx_alloc_cfg, rx_alloc_cfg);
+	err = gve_alloc_qpls(priv, qpls_alloc_cfg, rx_alloc_cfg);
 	if (err) {
 		netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n");
 		return err;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -178,7 +178,7 @@
 			return err;
 	} else {
 		idx = rx->dqo.next_qpl_page_idx;
-		if (idx >= priv->rx_pages_per_qpl) {
+		if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) {
 			net_err_ratelimited("%s: Out of QPL pages\n",
 					    priv->dev->name);
 			return -ENOMEM;
@@ -293,8 +293,8 @@
 	rx->ctx.skb_tail = NULL;
 
 	rx->dqo.num_buf_states = cfg->raw_addressing ?
-		min_t(u32, S16_MAX, buffer_queue_slots * 4) :
-		min_t(u32, S16_MAX, cfg->pages_per_qpl);
+		min_t(s16, S16_MAX, buffer_queue_slots * 4) :
+		gve_get_rx_pages_per_qpl_dqo(cfg->ring_size);
 	rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
 				      sizeof(rx->dqo.buf_states[0]),
 				      GFP_KERNEL);
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -246,10 +246,8 @@
 
 static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx)
 {
-	int num_tx_qpl_bufs = min_t(int,
-				    GVE_TX_BUFS_PER_PAGE_DQO *
-					    tx->dqo.qpl->num_entries,
-				    S16_MAX);
+	int num_tx_qpl_bufs = GVE_TX_BUFS_PER_PAGE_DQO *
+		tx->dqo.qpl->num_entries;
 	int i;
 
 	tx->dqo.tx_qpl_buf_next = kvcalloc(num_tx_qpl_bufs,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -709,6 +707,7 @@
 /* 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;
 
@@ -724,6 +723,7 @@
 	/* 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;
@@ -1149,14 +1150,6 @@
 	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)
@@ -1307,6 +1300,9 @@
 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);
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -970,14 +970,6 @@
 		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 =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -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 @@
 	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,6 +999,40 @@
 	}
 }
 
+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)
@@ -1000,6 +1036,8 @@
 {
 	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 @@
 	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;
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -218,7 +218,6 @@
 {
 	struct device *hdev = &priv->pdev->dev;
 	struct page_pool *pool;
-	int qpl_page_cnt;
 	size_t size;
 	u32 qpl_id;
 
@@ -246,7 +245,7 @@
 	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,7 +280,6 @@
 		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);
@@ -284,7 +282,7 @@
 		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;
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -311,7 +311,6 @@
 {
 	struct device *hdev = &priv->pdev->dev;
 	int num_pending_packets;
-	int qpl_page_cnt;
 	size_t bytes;
 	u32 qpl_id;
 	int i;
@@ -392,7 +391,6 @@
 
 	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);
@@ -395,7 +393,7 @@
 		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;
 

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -57,5 +57,5 @@
 
-#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
+#define GVE_DEFAULT_HEADER_BUFFER_SIZE 128
 
 #define DQO_QPL_DEFAULT_TX_PAGES 512
 
@@ -658,4 +674,3 @@
 
-	u16 ring_size;
-	bool raw_addressing;
-	bool enable_header_split;
+	u16 num_xdp_rings;
+
@@ -1030,6 +1158,6 @@
 	return 2 * rx_desc_cnt;
 }
 
-/* Returns a pointer to the next available tx qpl in the list of qpls */
-static inline
-struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg,
+/* 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)
--- b/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -782,6 +978,6 @@
 			priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
 	}
 
-	/* Read and store ring size ranges given by device */
-	if (dev_op_modify_ring &&
-	    (supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
+	if (dev_op_buffer_sizes &&
+	    (supported_features_mask & GVE_SUP_BUFFER_SIZES_MASK)) {
+		priv->max_rx_buffer_size =
--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -7,5 +6,6 @@
 #include <linux/filter.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
@@ -1327,4 +1290,5 @@
-	cfg->qpls = priv->qpls;
-	cfg->qpl_cfg = &priv->qpl_cfg;
+	cfg->raw_addressing = !gve_is_qpl(priv);
+	cfg->enable_header_split = priv->header_split_enabled;
 	cfg->ring_size = priv->rx_desc_cnt;
+	cfg->packet_buffer_size = priv->rx_cfg.packet_buffer_size;
 	cfg->rx = priv->rx;
@@ -1447,6 +1369,6 @@
-	priv->rx_cfg = *rx_alloc_cfg->qcfg;
+	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;
 
-	if (priv->xdp_prog)
-		priv->num_xdp_queues = priv->rx_cfg.num_queues;
+	gve_tx_start_rings(priv, gve_num_tx_queues(priv));
+	gve_rx_start_rings(priv, rx_alloc_cfg->qcfg_rx->num_queues);
--- b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -290,8 +278,10 @@
-	rx->ctx.skb_tail = NULL;
+		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.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);
-	rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states,
-				      sizeof(rx->dqo.buf_states[0]),
-				      GFP_KERNEL);
+		rx->dqo.qpl = gve_alloc_queue_page_list(priv, qpl_id,
+							qpl_page_cnt);
+		if (!rx->dqo.qpl)
+			goto err;
+		rx->dqo.next_qpl_page_idx = 0;
--- b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -243,4 +243,7 @@
 {
-	int num_tx_qpl_bufs = GVE_TX_BUFS_PER_PAGE_DQO *
-		tx->dqo.qpl->num_entries;
+	struct device *hdev = &priv->pdev->dev;
+	int num_pending_packets;
+	int qpl_page_cnt;
+	size_t bytes;
+	u32 qpl_id;
 	int i;

================================================================================
*    ONLY IN PATCH2 - files not modified by patch1                             *
================================================================================

--- a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -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;
--- a/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -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;
  • ❌ PR commit 19573271446 (gve: Remove unused declaration gve_rx_alloc_rings())359c5eb0f736
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060
    fatal: bad object 359c5eb0f7364eef5f5c9dabc9d3fe5cb01b0060

  • ❌ PR commit d7c93110786 (gve: Fix use of netif_carrier_ok())fba917b169be
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout fba917b169bea48b7f2c8c46e084a2e2b3512b76
    fatal: bad object fba917b169bea48b7f2c8c46e084a2e2b3512b76

  • ❌ PR commit 6897e23b1a4 (gve: fix XDP allocation path in edge cases)de63ac44a527
    Error: Failed to generate patch for upstream commit: Git command failed: format-patch -1 --stdout de63ac44a527b6c626ba7adb54873d4d6bd8de23
    fatal: bad object de63ac44a527b6c626ba7adb54873d4d6bd8de23

  • ⚠️ PR commit 56fb60775a7 (gve: prevent ethtool ops after shutdown) → upstream 75a9a46d67f4
    Differences found:

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -2658,2 +2658,3 @@
 	rtnl_lock();
+	netdev_lock(netdev);
 	if (was_up && gve_close(priv->dev)) {

This is an automated interdiff check for backported commits.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/31097964018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

created-by-kernelci Tag PRs that were automatically created when a user branch was pushed to the repo (kernelCI)

Development

Successfully merging this pull request may close these issues.

5 participants