* [RFC 1/3] ethdev: introduce device reinitialisation API
2025-10-17 11:11 [RFC 0/3] ethdev: introduce device reinitialisation API Ciara Loftus
@ 2025-10-17 11:11 ` Ciara Loftus
2025-10-17 11:11 ` [RFC 2/3] net/iavf: implement device reinitialisation callback Ciara Loftus
2025-10-17 11:11 ` [RFC 3/3] app/testpmd: support port reinitialisation Ciara Loftus
2 siblings, 0 replies; 4+ messages in thread
From: Ciara Loftus @ 2025-10-17 11:11 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus
Add a new ethdev API for resetting a device followed by a restoration of
the configuration present at the time of the invocation of the API.
In some cases if the driver can support it, the device will be restarted
if it was started when the API was invoked.
This operation could be useful for example when the user has detected an
issue with the device and wants to reset and reinitialise it in an
attempt to get it working again. While this is possible by calling a
sequence of existing APIs (reset, configure, rx_queue_setup and
tx_queue_setup), in the case where we are restoring the exact same
configuration, much of the reconfiguration performed in those calls
would be unnecessary and can be achieved by calling a subset of that
functionality, which is what this API will perform.
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
lib/ethdev/ethdev_driver.h | 4 ++++
lib/ethdev/ethdev_trace.h | 7 +++++++
lib/ethdev/ethdev_trace_points.c | 3 +++
lib/ethdev/rte_ethdev.c | 32 ++++++++++++++++++++++++++++++++
lib/ethdev/rte_ethdev.h | 25 +++++++++++++++++++++++++
5 files changed, 71 insertions(+)
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 71085bddff..18fff9f1a1 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -229,6 +229,9 @@ typedef int (*eth_dev_close_t)(struct rte_eth_dev *dev);
/** @internal Function used to reset a configured Ethernet device. */
typedef int (*eth_dev_reset_t)(struct rte_eth_dev *dev);
+/** @internal Function used to reinitialise a configured Ethernet device. */
+typedef int (*eth_dev_reinit_t)(struct rte_eth_dev *dev);
+
/** @internal Function used to detect an Ethernet device removal. */
typedef int (*eth_is_removed_t)(struct rte_eth_dev *dev);
@@ -1387,6 +1390,7 @@ struct eth_dev_ops {
eth_dev_set_link_down_t dev_set_link_down; /**< Device link down */
eth_dev_close_t dev_close; /**< Close device */
eth_dev_reset_t dev_reset; /**< Reset device */
+ eth_dev_reinit_t dev_reinit; /**< Reinitialize device */
eth_link_update_t link_update; /**< Get device link state */
eth_speed_lanes_get_t speed_lanes_get; /**< Get link speed active lanes */
eth_speed_lanes_set_t speed_lanes_set; /**< Set link speeds supported lanes */
diff --git a/lib/ethdev/ethdev_trace.h b/lib/ethdev/ethdev_trace.h
index 482befc209..a1eb5a4438 100644
--- a/lib/ethdev/ethdev_trace.h
+++ b/lib/ethdev/ethdev_trace.h
@@ -231,6 +231,13 @@ RTE_TRACE_POINT(
rte_trace_point_emit_int(ret);
)
+RTE_TRACE_POINT(
+ rte_ethdev_trace_reinit,
+ RTE_TRACE_POINT_ARGS(uint16_t port_id, int ret),
+ rte_trace_point_emit_u16(port_id);
+ rte_trace_point_emit_int(ret);
+)
+
RTE_TRACE_POINT(
rte_eth_trace_rx_hairpin_queue_setup,
RTE_TRACE_POINT_ARGS(uint16_t port_id, uint16_t rx_queue_id,
diff --git a/lib/ethdev/ethdev_trace_points.c b/lib/ethdev/ethdev_trace_points.c
index 071c508327..57713d6e70 100644
--- a/lib/ethdev/ethdev_trace_points.c
+++ b/lib/ethdev/ethdev_trace_points.c
@@ -143,6 +143,9 @@ RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_set_link_down,
RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_reset,
lib.ethdev.reset)
+RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_reinit,
+ lib.ethdev.reinit)
+
RTE_TRACE_POINT_REGISTER(rte_ethdev_trace_is_removed,
lib.ethdev.is_removed)
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index f22139cb38..67d69fef34 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -2057,6 +2057,38 @@ rte_eth_dev_reset(uint16_t port_id)
return ret;
}
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_eth_dev_reinit, 25.11)
+int
+rte_eth_dev_reinit(uint16_t port_id)
+{
+ struct rte_eth_dev *dev;
+ int ret;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+
+ if (dev->dev_ops->dev_reinit == NULL)
+ return -ENOTSUP;
+
+ if (dev->data->dev_configured == 0) {
+ RTE_ETHDEV_LOG_LINE(INFO,
+ "Cannot reinit device (port %u), device not configured",
+ port_id);
+ return -EINVAL;
+ }
+
+ ret = eth_err(port_id, dev->dev_ops->dev_reinit(dev));
+
+ if (ret == -EBUSY)
+ RTE_ETHDEV_LOG_LINE(INFO,
+ "Cannot reinit started device (port %u), please stop it first",
+ port_id);
+
+ rte_ethdev_trace_reinit(port_id, ret);
+
+ return ret;
+}
+
RTE_EXPORT_SYMBOL(rte_eth_dev_is_removed)
int
rte_eth_dev_is_removed(uint16_t port_id)
diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index d23c143eed..accc559af3 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -2989,6 +2989,31 @@ int rte_eth_dev_close(uint16_t port_id);
*/
int rte_eth_dev_reset(uint16_t port_id);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Reinitialise an Ethernet device and restore its configuration.
+ *
+ * When a device needs to be reset passively and the current configuration
+ * needs to be restored following the reset, the DPDK application can
+ * invoke this function. Some devices may also restart the device after
+ * the reinit if it was started before, if the device can do this safely.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ *
+ * @return
+ * - (0) if successful.
+ * - (-ENODEV) if *port_id* is invalid.
+ * - (-ENOTSUP) if hardware doesn't support this function.
+ * - (-EBUSY) if the device is started and the driver needs it to be
+ * stopped before performing the reinit.
+ * - (<0): Error code of the driver reinitialisation function.
+ */
+__rte_experimental
+int rte_eth_dev_reinit(uint16_t port_id);
+
/**
* Enable receipt in promiscuous mode for an Ethernet device.
*
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC 2/3] net/iavf: implement device reinitialisation callback
2025-10-17 11:11 [RFC 0/3] ethdev: introduce device reinitialisation API Ciara Loftus
2025-10-17 11:11 ` [RFC 1/3] " Ciara Loftus
@ 2025-10-17 11:11 ` Ciara Loftus
2025-10-17 11:11 ` [RFC 3/3] app/testpmd: support port reinitialisation Ciara Loftus
2 siblings, 0 replies; 4+ messages in thread
From: Ciara Loftus @ 2025-10-17 11:11 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus
Add support for the experimental device reinit API that simplifies the
process of resetting the device followed by restoring its configuration.
The reset will trigger a full PF-to-VF reset. If the device was started
when the call to reinit was made, it will be restarted again if the
no-poll-on-link-down devarg is set.
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
drivers/net/intel/iavf/iavf.h | 2 +-
drivers/net/intel/iavf/iavf_ethdev.c | 52 ++++++++++++++++++++++------
drivers/net/intel/iavf/iavf_vchnl.c | 2 +-
3 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/drivers/net/intel/iavf/iavf.h b/drivers/net/intel/iavf/iavf.h
index 435902fbc2..bce409631c 100644
--- a/drivers/net/intel/iavf/iavf.h
+++ b/drivers/net/intel/iavf/iavf.h
@@ -563,6 +563,6 @@ int iavf_flow_sub_check(struct iavf_adapter *adapter,
struct iavf_fsub_conf *filter);
void iavf_dev_watchdog_enable(struct iavf_adapter *adapter);
void iavf_dev_watchdog_disable(struct iavf_adapter *adapter);
-void iavf_handle_hw_reset(struct rte_eth_dev *dev);
+void iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset);
void iavf_set_no_poll(struct iavf_adapter *adapter, bool link_change);
#endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/intel/iavf/iavf_ethdev.c b/drivers/net/intel/iavf/iavf_ethdev.c
index 08c814725d..fc56e669ba 100644
--- a/drivers/net/intel/iavf/iavf_ethdev.c
+++ b/drivers/net/intel/iavf/iavf_ethdev.c
@@ -100,6 +100,7 @@ static int iavf_dev_start(struct rte_eth_dev *dev);
static int iavf_dev_stop(struct rte_eth_dev *dev);
static int iavf_dev_close(struct rte_eth_dev *dev);
static int iavf_dev_reset(struct rte_eth_dev *dev);
+static int iavf_dev_reinit(struct rte_eth_dev *dev);
static int iavf_dev_info_get(struct rte_eth_dev *dev,
struct rte_eth_dev_info *dev_info);
static const uint32_t *iavf_dev_supported_ptypes_get(struct rte_eth_dev *dev,
@@ -207,6 +208,7 @@ static const struct eth_dev_ops iavf_eth_dev_ops = {
.dev_stop = iavf_dev_stop,
.dev_close = iavf_dev_close,
.dev_reset = iavf_dev_reset,
+ .dev_reinit = iavf_dev_reinit,
.dev_infos_get = iavf_dev_info_get,
.dev_supported_ptypes_get = iavf_dev_supported_ptypes_get,
.link_update = iavf_dev_link_update,
@@ -3069,6 +3071,26 @@ iavf_dev_reset(struct rte_eth_dev *dev)
return iavf_dev_init(dev);
}
+/*
+ * Reinitialise VF device by resetting and reconfiguring it.
+ */
+static int
+iavf_dev_reinit(struct rte_eth_dev *dev)
+{
+ struct iavf_adapter *adapter;
+
+ adapter = dev->data->dev_private;
+ if (dev->data->dev_started && !adapter->devargs.no_poll_on_link_down) {
+ PMD_DRV_LOG(ERR, "Cannot reinit started port %u. Either stop the port or enable "
+ "no-poll-on-link-down in devargs.", dev->data->port_id);
+ return -EBUSY;
+ }
+
+ iavf_handle_hw_reset(dev, true);
+
+ return 0;
+}
+
static inline bool
iavf_is_reset(struct iavf_hw *hw)
{
@@ -3096,18 +3118,23 @@ iavf_is_reset_detected(struct iavf_adapter *adapter)
* Handle hardware reset
*/
void
-iavf_handle_hw_reset(struct rte_eth_dev *dev)
+iavf_handle_hw_reset(struct rte_eth_dev *dev, bool vf_initiated_reset)
{
struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
struct iavf_adapter *adapter = dev->data->dev_private;
int ret;
+ bool restart_device = false;
- if (!dev->data->dev_started)
- return;
+ if (vf_initiated_reset) {
+ restart_device = dev->data->dev_started;
+ } else {
+ if (!dev->data->dev_started)
+ return;
- if (!iavf_is_reset_detected(adapter)) {
- PMD_DRV_LOG(DEBUG, "reset not start");
- return;
+ if (!iavf_is_reset_detected(adapter)) {
+ PMD_DRV_LOG(DEBUG, "reset not start");
+ return;
+ }
}
vf->in_reset_recovery = true;
@@ -3124,12 +3151,15 @@ iavf_handle_hw_reset(struct rte_eth_dev *dev)
iavf_dev_xstats_reset(dev);
- /* start the device */
- ret = iavf_dev_start(dev);
- if (ret)
- goto error;
+ if (!vf_initiated_reset || restart_device) {
+ /* start the device */
+ ret = iavf_dev_start(dev);
+ if (ret)
+ goto error;
+
+ dev->data->dev_started = 1;
+ }
- dev->data->dev_started = 1;
goto exit;
error:
diff --git a/drivers/net/intel/iavf/iavf_vchnl.c b/drivers/net/intel/iavf/iavf_vchnl.c
index b1b7a5bf94..460035d772 100644
--- a/drivers/net/intel/iavf/iavf_vchnl.c
+++ b/drivers/net/intel/iavf/iavf_vchnl.c
@@ -83,7 +83,7 @@ iavf_dev_event_handle(void *param __rte_unused)
struct iavf_adapter *adapter = pos->dev->data->dev_private;
if (pos->event == RTE_ETH_EVENT_INTR_RESET &&
adapter->devargs.auto_reset) {
- iavf_handle_hw_reset(pos->dev);
+ iavf_handle_hw_reset(pos->dev, false);
rte_free(pos);
continue;
}
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC 3/3] app/testpmd: support port reinitialisation
2025-10-17 11:11 [RFC 0/3] ethdev: introduce device reinitialisation API Ciara Loftus
2025-10-17 11:11 ` [RFC 1/3] " Ciara Loftus
2025-10-17 11:11 ` [RFC 2/3] net/iavf: implement device reinitialisation callback Ciara Loftus
@ 2025-10-17 11:11 ` Ciara Loftus
2 siblings, 0 replies; 4+ messages in thread
From: Ciara Loftus @ 2025-10-17 11:11 UTC (permalink / raw)
To: dev; +Cc: Ciara Loftus
Add a new command for reinitialising the port. It differs from the "port
reset" command in that resets but also reinitialises the device,
restoring it to its original configuration and in some cases restarting
it if the driver supports it.
The command uses the following syntax:
port reinit <port_id>
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
app/test-pmd/cmdline.c | 15 ++++++++++-----
app/test-pmd/testpmd.c | 26 ++++++++++++++++++++++++++
app/test-pmd/testpmd.h | 1 +
3 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 7803e14bdc..b63b614ef9 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -1100,7 +1100,7 @@ static cmdline_parse_inst_t cmd_help_long = {
};
-/* *** start/stop/close all ports *** */
+/* *** start/stop/close/reset/reinit all ports *** */
struct cmd_operate_port_result {
cmdline_fixed_string_t keyword;
cmdline_fixed_string_t name;
@@ -1121,6 +1121,8 @@ static void cmd_operate_port_parsed(void *parsed_result,
close_port(RTE_PORT_ALL);
else if (!strcmp(res->name, "reset"))
reset_port(RTE_PORT_ALL);
+ else if (!strcmp(res->name, "reinit"))
+ reinit_port(RTE_PORT_ALL);
else
fprintf(stderr, "Unknown parameter\n");
}
@@ -1130,14 +1132,14 @@ static cmdline_parse_token_string_t cmd_operate_port_all_cmd =
"port");
static cmdline_parse_token_string_t cmd_operate_port_all_port =
TOKEN_STRING_INITIALIZER(struct cmd_operate_port_result, name,
- "start#stop#close#reset");
+ "start#stop#close#reset#reinit");
static cmdline_parse_token_string_t cmd_operate_port_all_all =
TOKEN_STRING_INITIALIZER(struct cmd_operate_port_result, value, "all");
static cmdline_parse_inst_t cmd_operate_port = {
.f = cmd_operate_port_parsed,
.data = NULL,
- .help_str = "port start|stop|close|reset all: Start/Stop/Close/Reset all ports",
+ .help_str = "port start|stop|close|reset|reinit all: Start/Stop/Close/Reset/Reinit all ports",
.tokens = {
(void *)&cmd_operate_port_all_cmd,
(void *)&cmd_operate_port_all_port,
@@ -1167,6 +1169,8 @@ static void cmd_operate_specific_port_parsed(void *parsed_result,
close_port(res->value);
else if (!strcmp(res->name, "reset"))
reset_port(res->value);
+ else if (!strcmp(res->name, "reinit"))
+ reinit_port(res->value);
else
fprintf(stderr, "Unknown parameter\n");
}
@@ -1176,7 +1180,7 @@ static cmdline_parse_token_string_t cmd_operate_specific_port_cmd =
keyword, "port");
static cmdline_parse_token_string_t cmd_operate_specific_port_port =
TOKEN_STRING_INITIALIZER(struct cmd_operate_specific_port_result,
- name, "start#stop#close#reset");
+ name, "start#stop#close#reset#reinit");
static cmdline_parse_token_num_t cmd_operate_specific_port_id =
TOKEN_NUM_INITIALIZER(struct cmd_operate_specific_port_result,
value, RTE_UINT8);
@@ -1184,7 +1188,8 @@ static cmdline_parse_token_num_t cmd_operate_specific_port_id =
static cmdline_parse_inst_t cmd_operate_specific_port = {
.f = cmd_operate_specific_port_parsed,
.data = NULL,
- .help_str = "port start|stop|close|reset <port_id>: Start/Stop/Close/Reset port_id",
+ .help_str = "port start|stop|close|reset|reinit <port_id>: "
+ "Start/Stop/Close/Reset/Reinit port_id",
.tokens = {
(void *)&cmd_operate_specific_port_cmd,
(void *)&cmd_operate_specific_port_port,
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 1a48b00e93..e1635a3035 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -3412,6 +3412,32 @@ reset_port(portid_t pid)
printf("Done\n");
}
+void
+reinit_port(portid_t pid)
+{
+ int diag;
+ portid_t pi;
+
+ if (port_id_is_invalid(pid, ENABLED_WARN))
+ return;
+
+ printf("Reinitializing ports...\n");
+
+ RTE_ETH_FOREACH_DEV(pi) {
+ if (pid != pi && pid != (portid_t)RTE_PORT_ALL)
+ continue;
+
+ if (is_proc_primary()) {
+ diag = rte_eth_dev_reinit(pi);
+ if (diag != 0)
+ fprintf(stderr, "Failed to reinit port %d. diag=%d\n",
+ pi, diag);
+ }
+ }
+
+ printf("Done\n");
+}
+
static char *
convert_pci_address_format(const char *identifier, char *pci_buffer, size_t buf_size)
{
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index fa46865c67..e47dfa3f65 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1169,6 +1169,7 @@ int start_port(portid_t pid);
void stop_port(portid_t pid);
void close_port(portid_t pid);
void reset_port(portid_t pid);
+void reinit_port(portid_t pid);
void attach_port(char *identifier);
void detach_devargs(char *identifier);
void detach_port_device(portid_t port_id);
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread