Linux RDMA and InfiniBand development
 help / color / mirror / Atom feed
From: Sahil Chandna <sahilchandna@linux.microsoft.com>
To: netdev-bot+sashiko@kernel.org
Cc: haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@kernel.org,
	kuba@kernel.org, pabeni@redhat.com, weh@microsoft.com,
	kotaranov@microsoft.com, horms@kernel.org,
	ernis@linux.microsoft.com, gargaditya@linux.microsoft.com,
	mawasthi@linux.microsoft.com, kees+treewide@kernel.org,
	schakrabarti@linux.microsoft.com, linux-hyperv@vger.kernel.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-rdma@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH net] net: mana: Avoid waiting on dead HWC after device reset
Date: Wed, 28 Oct 2026 13:52:26 +0530	[thread overview]
Message-ID: <59685bcc-b9bb-4c50-bbf8-db52b9580ad8@linux.microsoft.com> (raw)
In-Reply-To: <179300287088.3134.14257201772829101717@kernel.org>

On 26-10-2026 13:51, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 6 potential
> issue(s) to consider.
> 
> Critical: 0 · High: 1 · Medium: 3 · Low: 2 (1)
> 
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
> 
> - [High] mana_dealloc_queues()
>   (drivers/net/ethernet/microsoft/mana/mana_en.c) no longer waits for TX…
> - [Medium] If mana_gd_dev_reset() fails without quiescing the device,
>   mana_dealloc_queues() only logs the error.
> - [Medium] The new fail-fast check in mana_hwc_send_request() comes after
>   mana_hwc_get_msg_index(), which calls down(&hwc->sema) unconditionally.
> - [Medium] mana_dealloc_queues() sets hwc_dead only when
>   mana_gd_dev_reset() returns 0.
> - [Low] Several comments still say the DIM counters cq->tx_dim_pkts and
>   cq->tx_dim_bytes are touched only in NAPI context, which the patch…
> - [Low] The comment in mana_destroy_txq() (mana_en.c, about line 2728)
>   says 'Forget the SKBs freed without being completed after a drain…
> 
> Pre-existing issues:
> - [Low] This problem wasn't introduced by this patch, but the timeout
>   path in mana_hwc_send_request() does a non-atomic check-then-write:…
> 
> --
> 
> net: mana: Avoid waiting on dead HWC after device reset
> 
> This commit replaces the 120 second sleep-based TX drain in
> mana_dealloc_queues() with a single synchronous CQ sweep done while NAPI
> is disabled. If sends are still pending after the sweep, it resets the
> device. A successful reset sets a new hwc_dead flag, which makes
> mana_hwc_send_request() fail fast with -ETIMEDOUT and skips
> mana_fence_rqs() and the SHM teardown handshake.
> 
>> diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
>> index 3bca4b683134b..c9337f49fbe15 100644
>> --- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
>> +++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
> 
> [ ... ]
> 
>> @@ -897,6 +903,17 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
>>  	dest_vrq = hwc->dest_vrq_id;
>>  	dest_vrcq = hwc->dest_vrcq_id;
>>  
>> +	/* If the HWC is unavailable (e.g. hwc_timeout was set to 0 or
>> +	 * hwc_dead set after device reset), do not post the WQE: the
>> +	 * hardware cannot respond, so fail fast instead of waiting out
>> +	 * the full timeout.
>> +	 */
>> +	timeout = READ_ONCE(hwc->hwc_timeout);
>> +	if (timeout == 0 || READ_ONCE(hwc->hwc_dead)) {
>> +		err = -ETIMEDOUT;
>> +		goto out;
>> +	}
> 
> [Severity: Medium]
> Is this check reached early enough to avoid the RTNL stall after a reset?
> 
> Before getting here, mana_hwc_send_request() calls mana_hwc_get_msg_index(),
> which does an unconditional down(&hwc->sema). The HWC has a single request
> slot (HW_CHANNEL_VF_BOOTSTRAP_QUEUE_DEPTH = 1).
> 
> Some HWC users run without RTNL, for example
> mana_gf_stats_work_handler()->mana_query_gf_stats() every 2 seconds, and
> mana_ib verbs. Suppose one of them has already taken the slot, passed this
> check, and is sitting in wait_for_completion_timeout() with the full
> timeout (60s on the tested system). The reset in mana_dealloc_queues()
> then guarantees that request never completes.
> 
> The teardown thread then does:
> 
> mana_dealloc_queues()
>   mana_disable_vport_rx()
>     ...
>       mana_hwc_send_request()
>         mana_hwc_get_msg_index()
>           down(&hwc->sema);    <-- waits out the other request's timeout
> 
> Setting hwc_dead does not wake the waiter that is already in flight. Can
> RTNL still be held here for the full hwc_timeout, which is the symptom the
> commit message says is fixed?
> 
Ack, will fix the hwc->sema based wait in v2.>> +
>>  	err = mana_hwc_post_tx_wqe(txq, tx_wr, dest_vrq, dest_vrcq, false);
>>  	if (err) {
>>  		dev_err(hwc->dev, "HWC: Failed to post send WQE: %d\n", err);
>> @@ -904,14 +921,13 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
>>  	}
>>  
>>  	if (!wait_for_completion_timeout(&ctx->comp_event,
>> -					 (msecs_to_jiffies(hwc->hwc_timeout)))) {
>> -		if (hwc->hwc_timeout != 0)
>> -			dev_err(hwc->dev, "Command 0x%x timed out: %u ms\n",
>> -				command, hwc->hwc_timeout);
>> +					 (msecs_to_jiffies(timeout)))) {
>> +		dev_err(hwc->dev, "Command 0x%x timed out: %u ms\n",
>> +			command, timeout);
>>  
>>  		/* Reduce further waiting if HWC no response */
>> -		if (hwc->hwc_timeout > 1)
>> -			hwc->hwc_timeout = 1;
>> +		if (READ_ONCE(hwc->hwc_timeout) > 1)
>> +			WRITE_ONCE(hwc->hwc_timeout, 1);
> 
> [Severity: Low]
> This isn't a bug introduced by this patch, but this read-then-write is not
> atomic. If mana_serv_reset() runs WRITE_ONCE(hwc->hwc_timeout, 0) between
> the READ_ONCE() and the WRITE_ONCE() here, the 0 is overwritten with 1.
> An HWC_DATA_CFG_HWC_TIMEOUT update from mana_hwc_init_event_handler() can
> be lost the same way.
> 
> The new fail-fast check depends on timeout == 0. With the 0 lost, later
> commands would post WQEs and wait about a jiffy each instead of failing
> immediately. Now that 0 means fail fast, would a cmpxchg() be worth using
> here?
> 
> [ ... ]
> 
>> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
>> index 6b7c027e497ed..00885d21a9af0 100644
>> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
>> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> 
> [ ... ]
> 
>> @@ -3774,42 +3777,92 @@ static int mana_dealloc_queues(struct net_device *ndev)
> 
> [ ... ]
> 
>>  	if (apc->tx_qp) {
>>  		for (i = 0; i < apc->num_queues; i++) {
> 
> [ ... ]
> 
>>  			txq = &apc->tx_qp[i]->txq;
>> -			tsleep = 1000;
>> -			while (atomic_read(&txq->pending_sends) > 0 &&
>> -			       time_before(jiffies, timeout)) {
>> -				usleep_range(tsleep, tsleep + 1000);
>> -				tsleep <<= 1;
>> +			napi = &tx_cq->napi;
>> +
>> +			if (txq->napi_initialized) {
>> +				/* Stop the NAPI poll so it cannot run
>> +				 * concurrently with the synchronous drain.
>> +				 */
>> +				napi_synchronize(napi);
>> +				napi_disable_locked(napi);
>> +				cancel_work_sync(&tx_cq->dim.work);
>> +
>> +				/* Reap all TX completions currently in the CQ.
>> +				 * A zero budget frees skbs via the non-NAPI
>> +				 * path, which is required outside softirq.
>> +				 */
>> +				tx_cq->budget = 0;
>> +				do {
>> +					tx_cq->work_done = 0;
>> +					mana_poll_tx_cq(tx_cq);
>> +				} while (tx_cq->work_done);
>>  			}
> 
> [Severity: Low]
> This isn't a bug, but this adds a process context caller of
> mana_poll_tx_cq(), which still updates cq->tx_dim_pkts and
> cq->tx_dim_bytes. The struct mana_cq comment in include/net/mana/mana.h
> says:
> 
> 	/* Cumulative TX completions fed to DIM. Updated and read only in
> 	 * NAPI context (mana_poll_tx_cq() / mana_update_tx_dim()), so they
> 	 * measure the hardware completion rate and need no u64_stats_sync.
> 	 */
> 
> mana_poll_tx_cq() and mana_update_tx_dim() have similar comments. NAPI is
> disabled and dim.work is cancelled before this loop runs. Should those
> comments be updated to mention this drain path?
> 
>> -			if (atomic_read(&txq->pending_sends)) {
>> -				err = mana_gd_dev_reset(gd->gdma_context);
>> -				if (err) {
>> -					netdev_err(ndev, "device reset failed %d with %d pkts pending in txq %u\n",
>> -						   err,
>> -					    atomic_read(&txq->pending_sends),
>> -					    txq->gdma_txq_id);
>> -				}
>> -				break;
>> +
>> +			pending = atomic_read(&txq->pending_sends);
>> +			if (!trigger_flr && pending > 0) {
>> +				trigger_flr = true;
>> +				flr_txq_id = txq->gdma_txq_id;
>> +				flr_pending = pending;
>>  			}
>>  		}
> 
> [Severity: High]
> Can this reset a healthy device during routine reconfiguration?
> 
> The do/while loop above stops as soon as mana_gd_poll_cq() finds no CQE
> already written. NAPI is disabled by then, so a completion that arrives
> later is never reaped. Before this patch the driver waited with NAPI
> enabled, for up to 120s, before treating pending_sends as a hardware
> failure.
> 
> mana_detach() calls this right after stopping TX:
> 
> mana_detach()
> 	netif_tx_disable(ndev);
> 
> 	if (apc->port_st_save) {
> 		err = mana_dealloc_queues(ndev);
> 
> The SQ can hold up to tx_queue_size WQEs (default 256, max 16384), and
> each can be a 64KB TSO frame. Under TX load, pending_sends > 0 after one
> sweep looks likely on a working device, which leads to:
> 
> mana_change_mtu() / mana_close() / mana_set_channels() / mana_xdp_set() ...
>   mana_detach()
>     mana_dealloc_queues()
>       mana_gd_dev_reset()      <-- pcie_flr() on PCI, cdx_dev_reset() on CDX
>       WRITE_ONCE(hwc->hwc_dead, true);
>   mana_attach()
>     ...
>       mana_hwc_send_request()  <-- -ETIMEDOUT since hwc_dead is set
> 
> The FLR also takes down the HWC, the EQs, the vPorts of every port on the
> function and the mana_ib device. None of them is notified.
> 
> On PCI, recovery only comes indirectly: the gf_stats worker sees
> -ETIMEDOUT and schedules mana_serv_reset(), which sleeps for
> MANA_SERVICE_PERIOD seconds. CDX has no service reset path, so the port
> stays down until reprobe.
> 
> The commit message says the device is reset "only if sends remain
> unacknowledged". After this change, that means "not yet completed at the
> instant of the sweep". Should there be a bounded wait for pending_sends
> before deciding the hardware is unresponsive, for example polling the CQ
> with a timeout?
> 
>> +		if (trigger_flr && !(hwc && hwc->hwc_dead)) {
>> +			/* Completions never arrived: the device is
>> +			 * unresponsive. Issue device reset and
>> +			 * mark the HWC dead so subsequent HWC commands
>> +			 * fail fast instead of each waiting the full
>> +			 * hwc_timeout.
>> +			 */
>> +			err = mana_gd_dev_reset(gd->gdma_context);
>> +			if (err)
>> +				netdev_err(ndev, "device reset failed %d with %d pkts pending in txq %u\n",
>> +					   err,
>> +					   flr_pending,
>> +					   flr_txq_id);
>> +			else if (hwc)
>> +				WRITE_ONCE(hwc->hwc_dead, true);
>> +		}
> 
Ack, will add bounded wait in v2.> [Severity: Medium]
> Is it safe to leave hwc_dead clear whenever mana_gd_dev_reset() returns an
> error?
> 
> On PCI the reset is mana_pci_dev_reset()->pcie_flr(). Once pcie_flr() gets
> past its early checks, it always issues the reset and then waits for the
> device:
> 
> 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
> 	...
> 	msleep(100);
> 
> 	ret = pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
> 
> If the device is not ready within about 60s, pci_dev_wait() fails. The
> function has been reset, but hwc_dead stays false and hwc_timeout keeps
> the firmware value.
> 
> The next command, MANA_CONFIG_VPORT_RX from mana_disable_vport_rx(), then
> passes the new check in mana_hwc_send_request(). It posts to the reset
> function and waits the full timeout with RTNL held. mana_fence_rqs() and
> the SHM teardown handshake also still run.
> 
> A device that has stopped producing TX completions seems the most likely
> one to also come back late. Could this path keep the stall the commit
> message describes, on top of the pci_dev_wait() time?
> 
>>  		for (i = 0; i < apc->num_queues; i++) {
> 
> [ ... ]
> 
>>  			txq = &apc->tx_qp[i]->txq;
>>  			while ((skb = skb_dequeue(&txq->pending_skbs))) {
>>  				mana_unmap_skb(skb, apc);
>>  				dev_kfree_skb_any(skb);
>>  			}
>>  			atomic_set(&txq->pending_sends, 0);
> 
> [Severity: Medium]
> What happens here if mana_gd_dev_reset() failed without quiescing the
> device?
> 
> In that case the error is only logged. These SKBs are then unmapped and
> freed while the SQ is still live in hardware; the SQ is only destroyed
> later, in mana_destroy_txq()->mana_destroy_wq_obj().
> 
> pcie_flr() can return before issuing the FLR:
> 
> 	ret = pci_dev_reset_iommu_prepare(dev);
> 	if (ret) {
> 		pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret);
> 		return ret;
> 	}
> 
> On CDX, cdx_dev_reset() can likewise fail in dev_configure().
> 
> Before this patch, this sequence only ran after up to 120s of waiting, by
> which point a working device had finished. With the single sweep,
> outstanding WQEs on a healthy device are normal.
> 
> Can the device then DMA from unmapped or freed TX buffers? Under an IOMMU
> that would fault. Without strict IOMMU, it could send the new contents of
> reused pages.
> 
>> +
>> +			if (txq->napi_initialized) {
>> +				netif_napi_del_locked(napi);
>> +				txq->napi_initialized = false;
>> +			}
>>  		}
>>  	}
>
Ack, I will check above two comments and see if these can be fixed in v2.
> [Severity: Low]
> This isn't a bug, but since NAPI is now deleted here and napi_initialized
> is cleared, the NAPI teardown block in mana_destroy_txq() no longer runs
> on this path. Its comment also refers to the drain timeout that this patch
> removes:
> 
> 		/* Forget the SKBs freed without being completed after a drain
> 		 * timeout, now that NAPI can't complete any. Doing it here also
> 		 * covers the queues that a lower channel count won't recreate,
> 		 * which could otherwise stay stopped.
> 		 */
> 		netdev_tx_reset_queue(apc->tx_qp[i]->txq.net_txq);
> 
> Should this comment be updated to match the new drain?
> 
> [ ... ]
> 
pw-bot: cr

      reply	other threads:[~2026-10-28  8:22 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-25  7:28 [PATCH net] net: mana: Avoid waiting on dead HWC after device reset Sahil Chandna
2026-10-26  7:29 ` sashiko-bot
2026-10-28  8:18   ` Sahil Chandna
2026-10-26  8:21 ` netdev-bot+sashiko
2026-10-28  8:22   ` Sahil Chandna [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=59685bcc-b9bb-4c50-bbf8-db52b9580ad8@linux.microsoft.com \
    --to=sahilchandna@linux.microsoft.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=decui@microsoft.com \
    --cc=edumazet@kernel.org \
    --cc=ernis@linux.microsoft.com \
    --cc=gargaditya@linux.microsoft.com \
    --cc=haiyangz@microsoft.com \
    --cc=horms@kernel.org \
    --cc=kees+treewide@kernel.org \
    --cc=kotaranov@microsoft.com \
    --cc=kuba@kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=mawasthi@linux.microsoft.com \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=schakrabarti@linux.microsoft.com \
    --cc=stable@vger.kernel.org \
    --cc=weh@microsoft.com \
    --cc=wei.liu@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox