Skip to contentSkip to conversation

net/mana: add device reset support

PATCH Applied Wei Hu 2 participants 3 messages Jun 16 Network drivers

lore
Share & tools
lore

Wei Hu

author
#0 lore raw

v10 cover net/mana: add device reset support

From: Wei Hu <[email protected]>

Add support for handling hardware service reset events in the MANA driver. When the MANA kernel driver receives a hardware service event, it initiates a device reset and notifies userspace via IBV_EVENT_DEVICE_FATAL. The MANA PMD handles this by performing an automatic teardown and recovery sequence.

The driver uses ethdev recovery events (ERR_RECOVERING, RECOVERY_SUCCESS, RECOVERY_FAILED) to notify upper layers of the reset lifecycle, and a PCI device removal event callback to distinguish hot-remove from service reset.

Changes since v9:
- Fixed fd leak in the secondary RESET_EXIT IPC handler: when the doorbell page was already mapped, the fd from the message was not closed. Moved close(fd) outside the if/else so it runs unconditionally whenever an fd is present.

Changes since v8:
- Fixed reset thread resource leak: previously reset_thread_active was cleared before emitting recovery callbacks, so no join site would reap the thread. Now the flag stays true throughout the thread lifetime. mana_join_reset_thread detects the self-join case (callback calling dev_stop/dev_close from the reset thread) using rte_thread_equal and calls rte_thread_detach instead of join, so thread resources are freed on exit. External callers continue to join normally.
- Fixed lost condvar signal: added a predicate loop around pthread_cond_timedwait that checks dev_state under reset_cond_mutex. If mana_pci_remove_event_cb signals before the reset thread enters the wait, the wakeup is no longer lost. The PCI remove callback sets dev_state to RESET_FAILED under the same mutex before signaling.
- Added a lock/unlock barrier on reset_ops_lock in mana_pci_remove_event_cb to ensure teardown has completed before emitting the INTR_RMV event.
- Fixed mana_reset_exit_delay return type from uint32_t to int to match the negative error codes it stores.
- Removed unnecessary else-after-goto in mana_probe_port.

Changes since v7:
- Moved heavy teardown (dev_stop, IPC to secondaries, dev_close, MR btree free) from mana_reset_enter (EAL interrupt thread) to mana_reset_thread (control thread). The interrupt handler now only sets state, drains in-flight bursts, and spawns the thread. Teardown runs immediately in the control thread before the recovery timer wait, avoiding blocking the interrupt thread on multi-second IPC timeouts and ibverbs calls. Each function now owns its own lock scope with no lock hand-off between threads.
- Simplified burst_state from encoding device state in bits 1+ to a single blocked flag (bit 1). Only one value was ever stored, so the multi-state encoding was misleading. Added MANA_BURST_BLOCKED constant.
- Updated mana.rst to reflect that teardown runs on the control thread, not the interrupt handler.

Changes since v6:
- Rebased onto latest upstream for-main
- Replaced removed RTE_ETH_DEV_TO_PCI macro with RTE_CLASS_TO_BUS_DEVICE (upstream commit 4757b8df04 removed the old bus-specific ethdev convenience macros)

Changes since v5:
- Replaced RCU QSBR with per-queue atomic burst_state using a single-variable CAS design: bit 0 is the in-burst flag, bit 1 is the blocked flag. The data path uses CAS(0→1) to enter burst and fetch_and(~1) to exit. The reset path uses fetch_or to set the blocked bit and polls bit 0 to drain in-flight bursts. This eliminates the two-variable Dekker pattern and the need for sequential consistency (seq_cst) ordering.
- Removed librte_rcu dependency
- Removed __rte_no_thread_safety_analysis annotations (no longer needed after mutex conversion)
- Moved ERR_RECOVERING event emission before acquiring reset_ops_lock and before mana_reset_enter, so upper layers (e.g. netvsc) can switch data path before mana stops queues. Emitting outside the lock avoids deadlock if the callback calls dev_stop or dev_close.
- Replaced MANA_OPS_*_LOCK macros with mana_reset_trylock() helper function and explicit per-operation wrappers
- Removed unused rte_alarm.h and rte_lock_annotations.h includes
- Added RECOVERY_FAILED event when mana_reset_enter fails internally, so the application always receives a terminal event
- Added mana_clear_burst_state() helper to clear per-queue burst_state on failure paths (reset_failed, dev_stop_lock, dev_close_lock) preventing permanent silent packet drop after a failed reset

Changes since v4:
- Fixed stale rte_spinlock_unlock call in mana_intr_handler that was missed during the spinlock-to-mutex conversion, causing a -Wincompatible-pointer-types warning

Changes since v3:
- Converted reset_ops_lock from rte_spinlock_t to pthread_mutex_t with PTHREAD_PROCESS_SHARED, since the lock is held across blocking IB verbs calls and IPC with 5s timeout
- Removed rte_dev_event_callback_unregister retry loop to avoid deadlock when interrupt thread and reset thread contend

Changes since v2:
- Added per-queue burst_state atomic variable with Dekker-like synchronization to block data path during reset without RCU
- Replaced rte_alarm with condvar + control thread for reset exit
- Made reset_thread_active atomic with CAS — flag is set by creator and only cleared by the joiner, not the thread itself
- Fixed second reset crash: removed reset thread join logic from mana_dev_close (inner function) to avoid corrupting dev_state when called from mana_reset_enter
- Made reset_thread_active RTE_ATOMIC(bool) with explicit ordering
- Added retry loop for rte_dev_event_callback_unregister on -EAGAIN
- Initialized condvar/mutex with PTHREAD_PROCESS_SHARED since priv is in hugepage shared memory
- Added re-check of dev_state after lock acquisition in mana_intr_handler to prevent racing with pci_remove_event_cb
- Replaced (void *)0 with NULL in mp.c
- Added lock ownership comment block at mana_reset_enter
- Documented rte_dev_event_monitor_start() requirement
- Added mana.rst documentation and release note

Changes since v1:
- Removed net/netvsc patch from this series
- Simplified reset exit: mana_reset_exit calls mana_reset_exit_delay directly instead of spawning a thread
- Added __rte_no_thread_safety_analysis annotations for clang
- Switched to rte_thread_create_internal_control
- Fixed declaration-after-statement style issues
- Removed unnecessary blank lines and stale comments

Wei Hu (1):
net/mana: add device reset support

 doc/guides/nics/mana.rst               |   40 +
 doc/guides/rel_notes/release_26_07.rst |    8 +
 drivers/net/mana/mana.c                | 1088 ++++++++++++++++++++++--
 drivers/net/mana/mana.h                |   52 +-
 drivers/net/mana/mp.c                  |   92 +-
 drivers/net/mana/mr.c                  |    6 +-
 drivers/net/mana/rx.c                  |   23 +-
 drivers/net/mana/tx.c                  |   44 +-
 8 files changed, 1245 insertions(+), 108 deletions(-)
Signature · 1 line
2.34.1
author
#1 lore raw

PATCH v10 1/1 net/mana: add device reset support

From: Wei Hu <[email protected]>

Add support for handling hardware reset events in the MANA driver. When the MANA kernel driver receives a hardware service event, it initiates a device reset and notifies userspace via IBV_EVENT_DEVICE_FATAL. The DPDK driver handles this by performing an automatic teardown and recovery sequence.

The interrupt handler sets the device state, blocks new data path bursts, waits for in-flight bursts to drain using per-queue atomic flags, and spawns a control thread. The control thread performs teardown immediately (dev_stop, secondary IPC, dev_close, MR cache free) before waiting for the hardware recovery timer to fire. This avoids blocking the EAL interrupt thread on multi-second IPC timeouts and ibverbs calls. After the recovery delay, the thread unregisters the interrupt handler, re-probes the PCI device, reinitializes MR caches, and restarts queues. Each function owns its own lock scope with no lock hand-off between threads.

Each queue has an atomic burst_state variable where bit 0 is the in-burst flag and bit 1 is a blocked flag. The data path uses a single compare-and-swap (0 to 1) to enter a burst, which fails immediately if the blocked bit is set. The reset path sets the blocked bit via atomic fetch-or and polls bit 0 to wait for in-flight bursts to drain. This single-variable design avoids the need for sequential consistency ordering.

A per-device mutex serializes the reset path with ethdev operations. The mutex uses PTHREAD_PROCESS_SHARED for multi-process support and is held across blocking IB verbs calls. A trylock helper encapsulates the lock acquisition and device state check for all ethdev operation wrappers. Operations that cannot wait (configure, queue setup) return -EBUSY during reset, while dev_stop and dev_close join the reset thread before acquiring the lock to ensure proper sequencing.

The reset thread keeps reset_thread_active true throughout its lifetime. mana_join_reset_thread uses rte_thread_equal to detect the self-join case (when a recovery callback calls dev_stop or dev_close from the reset thread itself) and calls rte_thread_detach instead of join, so thread resources are freed on exit. External callers join normally.

The condvar wait in the reset thread uses a predicate loop that checks dev_state under reset_cond_mutex, so a PCI remove signal that arrives before the thread enters the wait is not lost. The PCI remove callback sets dev_state to RESET_FAILED under the same mutex before signaling. A lock/unlock barrier on reset_ops_lock in the PCI remove path ensures teardown has completed before emitting the INTR_RMV event.

Multi-process support is included: secondary processes unmap and remap doorbell pages via IPC during the reset enter and exit phases. The secondary RESET_EXIT handler closes the received fd unconditionally after processing, even when the doorbell page is already mapped. Data path functions in both primary and secondary processes check the device state atomically and return early when the device is not active.

The driver emits RTE_ETH_EVENT_ERR_RECOVERING before entering the reset path so that upper layers (e.g. netvsc) can switch their data path before queues are stopped. The event is emitted outside the reset lock to avoid deadlock if the callback calls dev_stop or dev_close. On completion, the driver emits RECOVERY_SUCCESS or RECOVERY_FAILED after releasing the lock. If a recovery callback triggers dev_stop or dev_close, the self-join detection in mana_join_reset_thread detaches the thread to avoid deadlock. If the enter phase fails internally, RECOVERY_FAILED is sent immediately so the application receives a terminal event. A PCI device removal event callback distinguishes hot-remove from service reset.

Documentation for the device reset feature is added in the MANA NIC guide and the 26.07 release notes.

---
 doc/guides/nics/mana.rst               |   40 +
 doc/guides/rel_notes/release_26_07.rst |    8 +
 drivers/net/mana/mana.c                | 1088 ++++++++++++++++++++++--
 drivers/net/mana/mana.h                |   52 +-
 drivers/net/mana/mp.c                  |   92 +-
 drivers/net/mana/mr.c                  |    6 +-
 drivers/net/mana/rx.c                  |   23 +-
 drivers/net/mana/tx.c                  |   44 +-
 8 files changed, 1245 insertions(+), 108 deletions(-)
doc/guides/nics/mana.rst +40 -0
index 0fcab6e2f6..08e345ea61 100644
@@ -71,3 +71,43 @@ The user can specify below argument in devargs.
     The default value is not set,
     meaning all the NICs will be probed and loaded.
     User can specify multiple mac=xx:xx:xx:xx:xx:xx arguments for up to 8 NICs.
+
+Device Reset Support
+--------------------
+
+The MANA PMD supports automatic recovery from hardware service reset events.
+When the MANA kernel driver receives a hardware service event,
+it initiates a device reset and notifies userspace
+via ``IBV_EVENT_DEVICE_FATAL``.
+
+The driver handles this transparently through a two-phase reset flow:
+
+* **Enter phase**: The interrupt handler blocks new data path bursts
+  and waits for all in-flight burst calls to drain
+  using per-queue atomic flags,
+  then spawns a control thread for the remaining work.
+
+* **Teardown and exit phase**: The control thread tears down
+  IB resources and queues, unmaps secondary process doorbell pages,
+  and closes the device. After a delay for hardware recovery,
+  it re-probes the PCI device,
+  reinstalls the interrupt handler,
+  reinitializes resources, and restarts queues.
+
+The driver emits the following ethdev recovery events
+to notify upper layers (e.g. netvsc) of the reset lifecycle:
+
+``RTE_ETH_EVENT_ERR_RECOVERING``
+   Reset has started.
+
+``RTE_ETH_EVENT_RECOVERY_SUCCESS``
+   Device has recovered successfully.
+
+``RTE_ETH_EVENT_RECOVERY_FAILED``
+   Recovery failed.
+
+To distinguish a PCI hot-remove from a service reset,
+the driver registers for PCI device removal events.
+This requires the application to call ``rte_dev_event_monitor_start()``
+for removal events to be delivered
+(e.g. testpmd ``--hot-plug-handling`` option).
doc/guides/rel_notes/release_26_07.rst +8 -0
index bd0cec2709..58e8c2422e 100644
@@ -122,6 +122,14 @@ New Features
   Added AGENTS.md file for AI review
   and supporting scripts to review patches and documentation.
 
+* **Added device reset support to the MANA PMD.**
+
+  Added automatic recovery from hardware service reset events
+  in the MANA poll mode driver. The driver uses ethdev recovery events
+  (``RTE_ETH_EVENT_ERR_RECOVERING``, ``RTE_ETH_EVENT_RECOVERY_SUCCESS``,
+  ``RTE_ETH_EVENT_RECOVERY_FAILED``) to notify upper layers of the
+  reset lifecycle.
+
 
 Removed Items
 -------------
drivers/net/mana/mana.c +1002 -86

1,294 lines not on this page · raw message

drivers/net/mana/mana.h +51 -1

95 lines not on this page · raw message

drivers/net/mana/mp.c +85 -7

156 lines not on this page · raw message

drivers/net/mana/mr.c +4 -2
index c4045141bc..8914f4cf04 100644
@@ -314,8 +314,10 @@ mana_mr_btree_init(struct mana_mr_btree *bt, int n, int socket)
 void
 mana_mr_btree_free(struct mana_mr_btree *bt)
 {
-	rte_free(bt->table);
-	memset(bt, 0, sizeof(*bt));
+	if (bt && bt->table) {
+		rte_free(bt->table);
+		memset(bt, 0, sizeof(*bt));
+	}
 }
 
 int
drivers/net/mana/rx.c +22 -1
index 1b8ba1f3a9..aedb05d46f 100644
@@ -36,6 +36,11 @@ mana_rq_ring_doorbell(struct mana_rxq *rxq)
 		db_page = process_priv->db_page;
 	}
 
+	if (!db_page) {
+		DP_LOG(ERR, "db_page is NULL, cannot ring RX doorbell");
+		return -EINVAL;
+	}
+
 	/* Hardware Spec specifies that software client should set 0 for
 	 * wqe_cnt for Receive Queues.
 	 */
@@ -172,7 +177,7 @@ mana_stop_rx_queues(struct rte_eth_dev *dev)
 
 	for (i = 0; i < priv->num_queues; i++)
 		if (dev->data->rx_queue_state[i] == RTE_ETH_QUEUE_STATE_STOPPED)
-			return -EINVAL;
+			return 0;
 
 	if (priv->rwq_qp) {
 		ret = ibv_destroy_qp(priv->rwq_qp);
@@ -256,6 +261,9 @@ mana_start_rx_queues(struct rte_eth_dev *dev)
 		struct mana_rxq *rxq = dev->data->rx_queues[i];
 		struct ibv_wq_init_attr wq_attr = {};
 
+		rxq->rxq_idx = i;
+		DRV_LOG(DEBUG, "assigning rxq_idx to %d", i);
+
 		manadv_set_context_attr(priv->ib_ctx,
 			MANADV_CTX_ATTR_BUF_ALLOCATORS,
 			(void *)((uintptr_t)&(struct manadv_ctx_allocators){
@@ -451,6 +459,16 @@ mana_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
 	uint32_t pkt_len;
 	uint32_t i;
 	int polled = 0;
+	uint32_t expected = 0;
+
+	/* Single atomic CAS: enter burst only if device is active (0→1).
+	 * Fails immediately if reset path has set the blocked bit.
+	 */
+	if (unlikely(!rte_atomic_compare_exchange_strong_explicit(
+			&rxq->burst_state, &expected, 1,
+			rte_memory_order_acquire,
+			rte_memory_order_relaxed)))
+		return 0;
 
 repoll:
 	/* Polling on new completions if we have no backlog */
@@ -592,6 +610,9 @@ mana_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
 				wqe_consumed, ret);
 	}
 
+	rte_atomic_fetch_and_explicit(&rxq->burst_state, ~(uint32_t)1,
+				     rte_memory_order_release);
+
 	return pkt_received;
 }
 
drivers/net/mana/tx.c +33 -11

83 lines not on this page · raw message

Signature · 1 line
2.34.1
#2 lore raw
Quoted 61 lines · On Tue, 16 Jun 2026 05:31:58 -0700 Wei Hu <[email protected]> wrote:

teardown immediately (dev_stop, secondary IPC, dev_close, MR cache free) before waiting for the hardware recovery timer to fire. This avoids blocking the EAL interrupt thread on multi-second IPC timeouts and ibverbs calls. After the recovery delay, the thread unregisters the interrupt handler, re-probes the PCI device, reinitializes MR caches, and restarts queues. Each function owns its own lock scope with no lock hand-off between threads.

Each queue has an atomic burst_state variable where bit 0 is the in-burst flag and bit 1 is a blocked flag. The data path uses a single compare-and-swap (0 to 1) to enter a burst, which fails immediately if the blocked bit is set. The reset path sets the blocked bit via atomic fetch-or and polls bit 0 to wait for in-flight bursts to drain. This single-variable design avoids the need for sequential consistency ordering.

A per-device mutex serializes the reset path with ethdev operations. The mutex uses PTHREAD_PROCESS_SHARED for multi-process support and is held across blocking IB verbs calls. A trylock helper encapsulates the lock acquisition and device state check for all ethdev operation wrappers. Operations that cannot wait (configure, queue setup) return -EBUSY during reset, while dev_stop and dev_close join the reset thread before acquiring the lock to ensure proper sequencing.

The reset thread keeps reset_thread_active true throughout its lifetime. mana_join_reset_thread uses rte_thread_equal to detect the self-join case (when a recovery callback calls dev_stop or dev_close from the reset thread itself) and calls rte_thread_detach instead of join, so thread resources are freed on exit. External callers join normally.

The condvar wait in the reset thread uses a predicate loop that checks dev_state under reset_cond_mutex, so a PCI remove signal that arrives before the thread enters the wait is not lost. The PCI remove callback sets dev_state to RESET_FAILED under the same mutex before signaling. A lock/unlock barrier on reset_ops_lock in the PCI remove path ensures teardown has completed before emitting the INTR_RMV event.

Multi-process support is included: secondary processes unmap and remap doorbell pages via IPC during the reset enter and exit phases. The secondary RESET_EXIT handler closes the received fd unconditionally after processing, even when the doorbell page is already mapped. Data path functions in both primary and secondary processes check the device state atomically and return early when the device is not active.

The driver emits RTE_ETH_EVENT_ERR_RECOVERING before entering the reset path so that upper layers (e.g. netvsc) can switch their data path before queues are stopped. The event is emitted outside the reset lock to avoid deadlock if the callback calls dev_stop or dev_close. On completion, the driver emits RECOVERY_SUCCESS or RECOVERY_FAILED after releasing the lock. If a recovery callback triggers dev_stop or dev_close, the self-join detection in mana_join_reset_thread detaches the thread to avoid deadlock. If the enter phase fails internally, RECOVERY_FAILED is sent immediately so the application receives a terminal event. A PCI device removal event callback distinguishes hot-remove from service reset.

Quoted 5 lines

Documentation for the device reset feature is added in the MANA NIC guide and the 26.07 release notes.

---

Applied to next-net