net/mana: add device reset support
v8 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 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.
- Fixed self-join deadlock: clear reset_thread_active before emitting RECOVERY_SUCCESS/FAILED callbacks from the reset thread. Without this, if the callback calls dev_stop/dev_close, mana_join_reset_thread attempts to join the current thread.
- 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: the callback itself blocks on reset_ops_lock, so retrying on -EAGAIN while holding the lock is a deadlock
- Introduced mana_join_reset_thread() helper using CAS on reset_thread_active to prevent double-join undefined behavior
- Added reset thread join in mana_dev_uninit to prevent thread leak on device removal
- Fixed ibv handle leak: priv->ib_ctx is now only set to NULL after ibv_close_device succeeds
- Fixed misleading "All secondary threads are quiescent" log in mana_mp_reset_enter — changed to "Secondary doorbell pages unmapped" since actual quiescence is enforced by the primary's per-queue atomic flag check before IPC is sent
- Changed event list in mana.rst to RST definition list style
- Squashed documentation into the feature patch per convention
Changes since v2:
- Fixed dev_state_qsv memory leak on device removal
- Fixed reset thread TCB/stack leak: reset_thread_active is now 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 | 1076 ++++++++++++++++++++++-- drivers/net/mana/mana.h | 52 +- drivers/net/mana/mp.c | 89 +- drivers/net/mana/mr.c | 6 +- drivers/net/mana/rx.c | 23 +- drivers/net/mana/tx.c | 44 +- 8 files changed, 1230 insertions(+), 108 deletions(-)
Signature · 1 line
2.34.1
PATCH v8 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. A CAS-based helper prevents double-join of the reset thread.
Multi-process support is included: secondary processes unmap and remap doorbell pages via IPC during the reset enter and exit phases. 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 and clearing the reset_thread_active flag, preventing self-join deadlock if the callback calls dev_stop or dev_close. 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 | 1076 ++++++++++++++++++++++-- drivers/net/mana/mana.h | 52 +- drivers/net/mana/mp.c | 89 +- drivers/net/mana/mr.c | 6 +- drivers/net/mana/rx.c | 23 +- drivers/net/mana/tx.c | 44 +- 8 files changed, 1230 insertions(+), 108 deletions(-)
doc/guides/nics/mana.rst +40 -0
@@ -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
@@ -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 +990 -86
1,282 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 +82 -7
153 lines not on this page · raw message
drivers/net/mana/mr.c +4 -2
@@ -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
@@ -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
Quoted 121 lines · On Wed, 10 Jun 2026 00:21:21 -0700 Wei Hu <[email protected]> wrote:
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 v7:
- Moved heavy teardown (dev_stop, IPC to secondaries,dev_close, MR btree free) frommana_reset_enter(EAL interrupt thread) tomana_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.
- Fixed self-join deadlock: clearreset_thread_activebefore emitting RECOVERY_SUCCESS/FAILED callbacks from the reset thread. Without this, if the callback calls dev_stop/dev_close,mana_join_reset_threadattempts to join the current thread.
- Simplifiedburst_statefrom 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. AddedMANA_BURST_BLOCKEDconstant.
- Updatedmana.rstto reflect that teardown runs on the control thread, not the interrupt handler.Changes since v6:
- Rebased onto latest upstream for-main
- Replaced removedRTE_ETH_DEV_TO_PCImacro withRTE_CLASS_TO_BUS_DEVICE(upstream commit4757b8df04removed the old bus-specific ethdev convenience macros)Changes since v5:
- Replaced RCU QSBR with per-queue atomicburst_stateusing 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 andfetch_and(~1)to exit. The reset path usesfetch_orto 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.
- Removedlibrte_rcudependency
- Removed__rte_no_thread_safety_analysisannotations (no longer needed after mutex conversion)
- MovedERR_RECOVERINGevent emission before acquiringreset_ops_lockand beforemana_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 callsdev_stopordev_close.
- Replaced MANA_OPS_*_LOCK macros withmana_reset_trylock()helper function and explicit per-operation wrappers
- Removed unusedrte_alarm.handrte_lock_annotations.hincludes
- AddedRECOVERY_FAILEDevent whenmana_reset_enterfails internally, so the application always receives a terminal event
- Addedmana_clear_burst_state()helper to clear per-queueburst_stateon failure paths (reset_failed,dev_stop_lock,dev_close_lock) preventing permanent silent packet drop after a failed resetChanges since v4:
- Fixed stalerte_spinlock_unlockcall inmana_intr_handlerthat was missed during the spinlock-to-mutex conversion, causing a -Wincompatible-pointer-types warningChanges since v3:
- Convertedreset_ops_lockfromrte_spinlock_ttopthread_mutex_twithPTHREAD_PROCESS_SHARED, since the lock is held across blocking IB verbs calls and IPC with 5s timeout
- Removedrte_dev_event_callback_unregisterretry loop to avoid
deadlock: the callback itself blocks onreset_ops_lock, so retrying on-EAGAINwhile holding the lock is a deadlock
- Introducedmana_join_reset_thread()helper using CAS onreset_thread_activeto prevent double-join undefined behavior
- Added reset thread join inmana_dev_uninitto prevent thread leak on device removal
- Fixed ibv handle leak:priv->ib_ctxis now only set to NULL afteribv_close_devicesucceeds
- Fixed misleading "All secondary threads are quiescent" log inmana_mp_reset_enter— changed to "Secondary doorbell pages unmapped" since actual quiescence is enforced by the primary's per-queue atomic flag check before IPC is sent
- Changed event list inmana.rstto RST definition list style
- Squashed documentation into the feature patch per conventionChanges since v2:
- Fixeddev_state_qsvmemory leak on device removal
- Fixed reset thread TCB/stack leak:reset_thread_activeis now only cleared by the joiner, not the thread itself
- Fixed second reset crash: removed reset thread join logic frommana_dev_close(inner function) to avoid corruptingdev_statewhen called frommana_reset_enter
- Madereset_thread_activeRTE_ATOMIC(bool)with explicit ordering
- Added retry loop forrte_dev_event_callback_unregisteron-EAGAIN
- Initialized condvar/mutex withPTHREAD_PROCESS_SHAREDsince priv is in hugepage shared memory
- Added re-check ofdev_stateafter lock acquisition inmana_intr_handlerto prevent racing withpci_remove_event_cb
- Replaced (void *)0 with NULL inmp.c
- Added lock ownership comment block atmana_reset_enter
- Documentedrte_dev_event_monitor_start()requirement
- Addedmana.rstdocumentation and release noteChanges since v1:
- Removed net/netvsc patch from this series
- Simplified reset exit:mana_reset_exitcallsmana_reset_exit_delaydirectly instead of spawning a thread
- Added__rte_no_thread_safety_analysisannotations for clang
- Switched torte_thread_create_internal_control
- Fixed declaration-after-statement style issues
- Removed unnecessary blank lines and stale commentsWei Hu (1):
net/mana: add device reset support
Quoted 10 lines
doc/guides/nics/mana.rst | 40 + doc/guides/rel_notes/release_26_07.rst | 8 + drivers/net/mana/mana.c | 1076 ++++++++++++++++++++++-- drivers/net/mana/mana.h | 52 +- drivers/net/mana/mp.c | 89 +- drivers/net/mana/mr.c | 6 +- drivers/net/mana/rx.c | 23 +- drivers/net/mana/tx.c | 44 +- 8 files changed, 1230 insertions(+), 108 deletions(-)
AI review thread still sees some issues:
This is close. Teardown is off the interrupt thread now, the cross-thread lock hand-off is gone, and the burst_state encoding reads cleanly. One real problem left.
The reset thread leaks on every successful recovery. mana_reset_exit_delay and the reset_failed path in mana_reset_thread clear reset_thread_active from inside the thread itself, without joining. The thread is created joinable via rte_thread_create_internal_control, so terminating it unjoined leaks its resources, and because the flag is now false none of the join sites (mana_join_reset_thread, the join-previous block in mana_reset_enter, mana_dev_uninit) will ever reap it. The PCI-remove abort path leaves the flag true and is reaped later, which is the inconsistency that exposes this: some exits expect a join and some do not, and the latter have no reaper.
Simplest fix is to detach the reset thread (rte_thread_detach) and drop the reset_thread_active / mana_join_reset_thread machinery, using reset_ops_lock and dev_state for the dev_stop/dev_close sequencing instead. That removes the self-join hazard too. If you keep the join, don't clear the flag from inside the thread; have mana_join_reset_thread detect the self case and skip only the join.
Minor: the recovery condvar wait in mana_reset_thread is a bare cond_timedwait. If pci_remove signals before the thread reaches the wait, the wakeup is lost and removal isn't seen until the 15s timer expires. Use a dev_state predicate loop under reset_cond_mutex.