net/mana: add device reset support
v9 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 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 | 89 +- drivers/net/mana/mr.c | 6 +- drivers/net/mana/rx.c | 23 +- drivers/net/mana/tx.c | 44 +- 8 files changed, 1242 insertions(+), 108 deletions(-)
Signature · 1 line
2.34.1
PATCH v9 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. 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 | 89 +- drivers/net/mana/mr.c | 6 +- drivers/net/mana/rx.c | 23 +- drivers/net/mana/tx.c | 44 +- 8 files changed, 1242 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 +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 +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 128 lines · On Fri, 12 Jun 2026 01:17:22 -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 v8:
- Fixed reset thread resource leak: previouslyreset_thread_activewas 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_threaddetects the self-join case (callback calling dev_stop/dev_close from the reset thread) usingrte_thread_equaland callsrte_thread_detachinstead of join, so thread resources are freed on exit. External callers continue to join normally.
- Fixed lost condvar signal: added a predicate loop aroundpthread_cond_timedwaitthat checksdev_stateunderreset_cond_mutex. Ifmana_pci_remove_event_cbsignals before the reset thread enters the wait, the wakeup is no longer lost. The PCI remove callback setsdev_statetoRESET_FAILEDunder the same mutex before signaling.
- Added a lock/unlock barrier onreset_ops_lockinmana_pci_remove_event_cbto ensure teardown has completed before emitting theINTR_RMVevent.
- Fixedmana_reset_exit_delayreturn type fromuint32_tto int to match the negative error codes it stores.
- Removed unnecessary else-after-goto inmana_probe_port.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.
- 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 when interrupt thread and reset thread contendChanges since v2:
- Added per-queueburst_stateatomic variable with Dekker-like synchronization to block data path during reset without RCU
- Replacedrte_alarmwith condvar + control thread for reset exit
- Madereset_thread_activeatomic 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 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 | 1088 ++++++++++++++++++++++-- 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, 1242 insertions(+), 108 deletions(-)
Looks good, one bit of AI review.
---
The self-join and the condvar wait both look right now. The reset thread keeps reset_thread_active true for its whole life and mana_join_reset_thread is the only place that transitions it, using rte_thread_equal to detach on the self-call and join otherwise, so the thread is reaped exactly once with no leak and no self-join deadlock. The predicate loop under reset_cond_mutex closes the lost-wakeup window. Reset logic is in good shape.
One small thing in mp.c: in the RESET_EXIT secondary handler the received fd is only closed on the branch that maps it. If proc_priv->db_page is already non-NULL the fd from the message is leaked. Close it whenever num_fds >= 1, outside the if/else.
---
I can merge it as is, or you can send a revision to close that minor leak.
Quoted 9 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Tuesday, June 16, 2026 2:50 AM
To: Wei Hu <[email protected]>
Cc: [email protected]; Long Li <[email protected]>; Wei Hu <[email protected]>
Subject: [EXTERNAL] Re: [PATCH v9 0/1] net/mana: add device reset support
Quoted 6 lines
One small thing in
mp.c: in theRESET_EXITsecondary handler the received fd is only closed on the branch that maps it. Ifproc_priv->db_pageis already non- NULL the fd from the message is leaked. Close it whenevernum_fds>= 1, outside the if/else.
---
I can merge it as is, or you can send a revision to close that minor leak.
I will send a revision to close this leak. Thanks Stephen!
Wei