[PATCH] net/gve: add passive device-requested reset

Jasper Tran O'Leary jtranoleary at google.com
Fri Mar 27 01:20:38 CET 2026


In addition to application-initiated resets, during normal operation,
the device can indicate the need to reset by writing a value to a device
status register. This patch introduces an alarm that polls the
status of that register and informs the application of the need to
reset. The application is responsible for registering a callback that
will execute in the event that the alarm discovers that the device
requests a reset.

Signed-off-by: Jasper Tran O'Leary <jtranoleary at google.com>
Reviewed-by: Joshua Washington <joshwash at google.com>
---
Depends-on: patch-1bf64edce3 ("net/gve: add reset path")

 doc/guides/nics/gve.rst      | 32 ++++++++++++++-
 drivers/net/gve/gve_ethdev.c | 77 ++++++++++++++++++++++++++++++++++++
 drivers/net/gve/gve_ethdev.h |  3 ++
 3 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/doc/guides/nics/gve.rst b/doc/guides/nics/gve.rst
index d94e4cb..f564607 100644
--- a/doc/guides/nics/gve.rst
+++ b/doc/guides/nics/gve.rst
@@ -130,8 +130,8 @@ Security Protocols
 - Flow priorities are not supported (must be 0).
 - Masking is limited to full matches i.e. ``0x00...0`` or ``0xFF...F``.
 
-Application-Initiated Reset
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Device Reset
+^^^^^^^^^^^^
 
 The driver allows an application to reset the gVNIC device.
 This function will tear down and reinitialize the device's resources,
@@ -139,3 +139,31 @@ including queues and administrative queues.
 
 It is the application's responsibility to reinitialize
 and restart the device after resetting it.
+
+In addition, the driver supports device-requested resets, which are triggered
+when the device encounters an unrecoverable error. The driver detects this via
+a device status register and raises an ``RTE_ETH_EVENT_INTR_RESET`` event.
+
+The application must register a callback to handle this event. The callback
+should handle the reset process (reset, reconfigure, restart).
+
+.. code-block:: c
+
+   static int
+   dev_rst_req_callback(uint16_t port_id, enum rte_eth_event_type type,
+                        void *param, void *ret_param)
+   {
+       RTE_SET_USED(param);
+       RTE_SET_USED(ret_param);
+
+       if (type == RTE_ETH_EVENT_INTR_RESET) {
+           printf("Device requested reset on port %u\n", port_id);
+           rte_eth_dev_reset(port_id);
+           /* Reconfigure and restart port ... */
+       }
+       return 0;
+   }
+
+   /* Register this callback in the main execution flow */
+   rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_RESET,
+                     dev_rst_req_callback, NULL);
diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c
index fce90ad..7970f46 100644
--- a/drivers/net/gve/gve_ethdev.c
+++ b/drivers/net/gve/gve_ethdev.c
@@ -13,6 +13,8 @@
 #include <ethdev_driver.h>
 
 static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device);
+static void gve_start_dev_status_polling(struct rte_eth_dev *dev);
+static void gve_stop_dev_status_polling(struct rte_eth_dev *dev);
 
 static void
 gve_write_version(uint8_t *driver_version_register)
@@ -411,6 +413,11 @@ gve_dev_start(struct rte_eth_dev *dev)
 	struct gve_priv *priv;
 	int ret;
 
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		PMD_DRV_LOG(WARNING, "Cannot start device in secondary.");
+		return -EPERM;
+	}
+
 	ret = gve_start_queues(dev);
 	if (ret != 0) {
 		PMD_DRV_LOG(ERR, "Failed to start queues");
@@ -440,6 +447,8 @@ gve_dev_start(struct rte_eth_dev *dev)
 		}
 	}
 
+	gve_start_dev_status_polling(dev);
+
 	return 0;
 }
 
@@ -448,6 +457,17 @@ gve_dev_stop(struct rte_eth_dev *dev)
 {
 	struct gve_priv *priv = dev->data->dev_private;
 
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+		PMD_DRV_LOG(WARNING, "Cannot stop device in secondary.");
+		return -EPERM;
+	}
+
+	/*
+	 * Block until all polling callbacks have concluded before tearing down
+	 * any device resources.
+	 */
+	gve_stop_dev_status_polling(dev);
+
 	dev->data->dev_started = 0;
 	dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
 
@@ -1311,6 +1331,63 @@ gve_set_default_ring_size_bounds(struct gve_priv *priv)
 	priv->min_rx_desc_cnt = GVE_DEFAULT_MIN_RX_RING_SIZE;
 }
 
+static void
+gve_check_device_status(void *arg)
+{
+	struct rte_eth_dev *dev = arg;
+	struct gve_priv *priv = dev->data->dev_private;
+	uint32_t dev_status;
+	int ret;
+
+	dev_status = ioread32be(&priv->reg_bar0->device_status);
+
+	if (dev_status & GVE_DEVICE_STATUS_RESET_MASK) {
+		PMD_DRV_LOG(INFO,
+			"Device on port %u requests a reset. Stopping device status polling.",
+			dev->data->port_id);
+		rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
+			NULL);
+	} else {
+		ret = rte_eal_alarm_set(GVE_DEV_POLL_INTERVAL_US,
+					gve_check_device_status, dev);
+		if (ret != 0) {
+			PMD_DRV_LOG(ERR,
+				"Port %u: Failed to re-arm alarm poller!",
+				dev->data->port_id);
+		}
+	}
+}
+
+static void
+gve_start_dev_status_polling(struct rte_eth_dev *dev)
+{
+	int ret;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return;
+
+	ret = rte_eal_alarm_set(GVE_DEV_POLL_INTERVAL_US,
+				gve_check_device_status,
+				dev);
+
+	if (ret != 0) {
+		PMD_DRV_LOG(ERR,
+			"Port %u: Failed to arm device reset polling alarm! Err=%d",
+			dev->data->port_id, ret);
+	} else {
+		PMD_DRV_LOG(INFO,
+			"Port %u: Armed device reset polling alarm.",
+			dev->data->port_id);
+	}
+}
+
+static void
+gve_stop_dev_status_polling(struct rte_eth_dev *dev)
+{
+	/* Blocks until all in-progress callbacks have completed. */
+	rte_eal_alarm_cancel(gve_check_device_status, dev);
+}
+
 static int
 gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
 {
diff --git a/drivers/net/gve/gve_ethdev.h b/drivers/net/gve/gve_ethdev.h
index 8fd098c..0577f03 100644
--- a/drivers/net/gve/gve_ethdev.h
+++ b/drivers/net/gve/gve_ethdev.h
@@ -7,6 +7,7 @@
 
 #include <ethdev_driver.h>
 #include <ethdev_pci.h>
+#include <rte_alarm.h>
 #include <rte_ether.h>
 #include <rte_pci.h>
 #include <pthread.h>
@@ -57,6 +58,8 @@
 	RTE_ETH_RSS_NONFRAG_IPV6_UDP |	\
 	RTE_ETH_RSS_IPV6_UDP_EX)
 
+#define GVE_DEV_POLL_INTERVAL_US (1 * 1000 * 1000) /* 1 second in microseconds */
+
 /* A list of pages registered with the device during setup and used by a queue
  * as buffers
  */
-- 
2.53.0.1118.gaef5881109-goog



More information about the dev mailing list