Netdev List
 help / color / mirror / Atom feed
From: mingming cao <mmc@linux.ibm.com>
To: netdev-bot+sashiko@kernel.org
Cc: netdev@vger.kernel.org, davem@davemloft.net, kuba@kernel.org,
	horms@kernel.org, edumazet@google.com, pabeni@redhat.com,
	andrew+netdev@lunn.ch, nnac123@linux.ibm.com,
	maddy@linux.ibm.com, mpe@ellerman.id.au,
	linuxppc-dev@lists.ozlabs.org, haren@linux.ibm.com,
	ricklind@linux.ibm.com, davemarq@linux.ibm.com,
	bjking1@linux.ibm.com, shaik.abdulla1@ibm.com
Subject: Re: [net-next,v6,15/15] ibmveth: Complete set_channels down-path and mq_fallback max_rx cap
Date: Fri, 25 Sep 2026 00:43:56 -0700	[thread overview]
Message-ID: <7fee78c3-b79e-48d7-932a-81a1f3083f64@linux.ibm.com> (raw)
In-Reply-To: <178845904669.3394541.24513769216494846@kernel.org>

Thanks for the review!

On 9/3/26 11:10 AM, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential
> issue(s) to consider:
>
> Critical: 0 · High: 0 · Medium: 1 · Low: 3
>
> - [Medium] Advertised RX channel range does not match the enforced range
>    once `mq_fallback` latches.
> - [Low] In `ibmveth_set_channels()` the comment above the RX rollback
>    describes code that no longer exists: it claims…
> - [Low] The new up-path TX-failure rollback in `ibmveth_set_channels()`
>    calls `ibmveth_resize_rx_queues_incremental(adapter, old_rx,…
> - [Low] `adapter->mq_fallback` is written with a plain store from
>    softirq/NAPI context — `ibmveth_replenish_task()` does…
>
> --
>
> ibmveth: Complete set_channels down-path and mq_fallback max_rx cap
>
> This completes the ethtool -L path in ibmveth: the down-path publishes the
> desired RX count without allocating, the up-path resizes RX then TX and
> rolls RX back if TX cannot reach the requested count, and get_channels()
> now caps max_rx at the live rx_count once mq_fallback is set.
> ibmveth_poll_controller() also returns early when the adapter is closed.
>
>> diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
>> index 5aef8a1f2c23d..4cd00ff3d43e4 100644
>> --- a/drivers/net/ethernet/ibm/ibmveth.c
>> +++ b/drivers/net/ethernet/ibm/ibmveth.c
>> @@ -3156,15 +3156,24 @@ static void ibmveth_get_channels(struct net_device *netdev,
>>   				 struct ethtool_channels *channels)
>>   {
>>   	struct ibmveth_adapter *adapter = netdev_priv(netdev);
>> +	unsigned int rx_count = ibmveth_get_num_rx_queues(adapter);
>>   
>>   	channels->max_tx = ibmveth_real_max_tx_queues();
>>   	channels->tx_count = netdev->real_num_tx_queues;
>>   
>> -	if (adapter->multi_queue)
>> +	/*
>> +	 * Always report the live RX count. ethtool -L is read-modify-
>> +	 * write, so a TX-only request echoes rx_count back at us; an
>> +	 * understated value would be applied as a silent RX shrink.
>> +	 * mq_fallback instead caps max_rx at the live count, which
>> +	 * blocks growth in the core without misreporting what is
>> +	 * currently configured.
>> +	 */
>> +	channels->rx_count = rx_count;
>> +	if (adapter->multi_queue && !adapter->mq_fallback)
>>   		channels->max_rx = IBMVETH_MAX_RX_QUEUES;
>>   	else
>> -		channels->max_rx = 1;
>> -	channels->rx_count = ibmveth_get_num_rx_queues(adapter);
>> +		channels->max_rx = rx_count;
>>   }
> [Severity: Medium]
> Once mq_fallback is set, does the advertised max_rx still match what the
> driver will accept?
>
> Here max_rx becomes the live rx_count, which can be 8 or 16.  The core only
> bounds the request by that value, in ethtool_set_channels():
>
>      if (channels.rx_count > curr.max_rx ||
>          channels.tx_count > curr.max_tx ||
>
> So every value in 1..rx_count reaches the driver.  But
> ibmveth_resize_rx_channels() refuses any changed count above 1 in that
> state, after the no-op shortcut:
>
>      if (goal_rx == old_rx)
>              return 0;
>      ...
>      if (goal_rx > 1 && (!adapter->multi_queue || adapter->mq_fallback)) {
>              netdev_err(netdev,
>                         "Cannot resize to %u RX queues: multi-queue mode not supported by firmware\n",
>                         goal_rx);
>              return -EOPNOTSUPP;
>      }
>
> With mq_fallback set and a live count of 8, ethtool -l reports max_rx 8 while
> ethtool -L ethX rx 2 through rx 7 all fail with -EOPNOTSUPP; only 1 and the
> current count are accepted.
>
> This state looks persistent rather than transient, since
> ibmveth_register_rx_queues() latches the flag and then fails the open:
>
>      if (rc) {
>              /* Firmware MQ gone: fall back to SQ on next open. */
>              if (rc == -EOPNOTSUPP)
>                      adapter->mq_fallback = true;
>              goto err_unregister;
>      }
>
> adapter->opened stays false and num_rx_queues keeps its old value above 1
> until the next successful open.
>
> Would it be clearer to advertise max_rx = 1 in the fallback state and keep
> the no-op shortcut for the read-modify-write case?  The kernel-doc for
> ibmveth_resize_rx_channels() ("Rejects rx > 1 without MQ firmware
> (-EOPNOTSUPP)") also does not mention that the no-op shortcut precedes the
> gate.
get_channels reports the live count and
caps max_rx at that count once mq_fallback.
Advertising max_rx = 1 while rx_count is
still live fails the core (rx_count >
max_rx) and blocks a TX-only ethtool -L.
Clamping rx_count would shrink RX. rx > 1
is -EOPNOTSUPP except the current-count
no-op.
> [Severity: Low]
> Is the read of adapter->mq_fallback here synchronized against its writer?
>
> The flag is stored from softirq/NAPI context in ibmveth_replenish_task(),
> after the replenish_lock has already been dropped:
>
>      spin_unlock_irqrestore(&rxq->replenish_lock, flags);
>      ...
>              adapter->mq_fallback = true;
>              schedule_work(&adapter->work);
>
> The new reader added here, and the capability gate in
> ibmveth_resize_rx_channels():
>
>      if (goal_rx > 1 && (!adapter->multi_queue || adapter->mq_fallback)) {
>
> run under RTNL / the netdev ops lock, which does not exclude the softirq
> writer.  There is no lock, no READ_ONCE()/WRITE_ONCE() and no acquire/release
> pairing on this field, while the sibling field num_rx_queues in the same
> struct is deliberately published with:
>
>      smp_store_release(&adapter->num_rx_queues, num);
>
> A stale false read here would advertise max_rx = IBMVETH_MAX_RX_QUEUES right
> after firmware refused MQ buffer adds, and a stale read in the gate would let
> the driver allocate and replenish RX queues on that firmware, re-latching
> mq_fallback and queueing another reset.  Would WRITE_ONCE()/READ_ONCE() on
> mq_fallback, or folding it into the existing publish/consume helpers, be
> appropriate?
No — RTNL does not exclude the NAPI store, so
this is an unannotated race. v7 keeps it as a
benign sticky latch: a stale false is one extra
MQ attempt, then the flag latches again.
WRITE_ONCE on the store without READ_ONCE on
apply / get_channels / set_channels is only half
a pass, so I left it plain. Happy to annotate
the store and all three readers together if you
would prefer that spelled out.
>> @@ -3233,28 +3242,83 @@ static int ibmveth_set_channels(struct net_device *netdev,
>>   				struct ethtool_channels *channels)
>>   {
>>   	struct ibmveth_adapter *adapter = netdev_priv(netdev);
>> -	unsigned int old = netdev->real_num_tx_queues,
>> -		     goal = channels->tx_count;
>> +	unsigned int old_rx = ibmveth_get_num_rx_queues(adapter);
>> +	unsigned int goal_rx = channels->rx_count;
>> +	unsigned int old_tx = netdev->real_num_tx_queues;
>> +	unsigned int goal_tx = channels->tx_count;
>> +	unsigned int want_tx = goal_tx;
>> +	bool rx_changed = false;
>>   	int rc, i;
>>   
>> -	/* Validate RX (and resize when opened) before the down-path
>> -	 * early return so MQ/range errors are reported here. Publishing
>> -	 * the desired RX count and CMO while down is the next patch.
>> -	 */
>> -	rc = ibmveth_resize_rx_channels(adapter, channels->rx_count);
>> +	if (goal_tx < 1 || goal_tx > ibmveth_real_max_tx_queues()) {
>> +		netdev_err(netdev,
>> +			   "Invalid TX queue count %u (must be 1-%u)\n",
>> +			   goal_tx, ibmveth_real_max_tx_queues());
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* RX range / MQ checks live in ibmveth_resize_rx_channels(). */
>> +	rc = ibmveth_resize_rx_channels(adapter, goal_rx);
>>   	if (rc)
>>   		return rc;
> [ ... down-path publish/rollback block snipped ... ]
>
>> -	return rc;
>> +	if (netdev->real_num_tx_queues != want_tx) {
>> +		if (rx_changed) {
>> +			/*
>> +			 * Only meaningful once RX is live. num_slots is
>> +			 * embedded in the adapter and outlives the DMA ring,
>> +			 * so reading it at function entry is safe but can
>> +			 * return a stale geometry from before the resize.
>> +			 */
>> +			int rxq_entries = adapter->rx_queue[0].num_slots;
> [Severity: Low]
> This isn't a bug, but does this comment still describe the code below it?
>
> It says num_slots is read "at function entry" and "can return a stale
> geometry from before the resize", yet the read it annotates happens right
> here, inside the if (rx_changed) block, after ibmveth_resize_rx_channels()
> has already changed the RX geometry.  Function entry only reads
> num_rx_queues, real_num_tx_queues, channels->rx_count and channels->tx_count.
>
> The comment looks like a leftover from the v5 layout mentioned in the
> changelog, and now warns about a hazard that would only exist if the read
> were moved back to function entry.
The comment was leftover from the earlier
layout. The read is after the RX resize.
v7 replaces it to match that restore.
>> +			int rb;
>> +
>> +			rb = ibmveth_resize_rx_queues_incremental(adapter,
>> +								  old_rx,
>> +								  rxq_entries);
>> +			if (rb)
>> +				netdev_err(netdev,
>> +					   "Failed to roll back RX queues to %u after TX failure: %d\n",
>> +					   old_rx, rb);
>> +		}
>> +		return rc ? rc : -ENOMEM;
>> +	}
> [Severity: Low]
> Can this rollback re-attempt a queue geometry that the forward path would
> have refused?
>
> The rollback calls ibmveth_resize_rx_queues_incremental() directly, so the
> multi_queue / mq_fallback gate in ibmveth_resize_rx_channels() is not
> consulted.  That gate only rejects goal_rx > 1:
>
>      if (goal_rx > 1 && (!adapter->multi_queue || adapter->mq_fallback)) {
>              ...
>              return -EOPNOTSUPP;
>      }
>
> Consider adapter->opened true, mq_fallback already latched from softirq in
> ibmveth_replenish_task():
>
>      adapter->mq_fallback = true;
>      schedule_work(&adapter->work);
>
> and a live RX count of 8.  A request of rx 1 with a larger tx passes the gate
> (goal_rx is 1), RX shrinks 8 -> 1 and rx_changed becomes true.  If the TX
> step then fails in ibmveth_allocate_tx_ltb() or
> netif_set_real_num_tx_queues(), the rollback runs the scale-up path back to
> old_rx = 8 on firmware that has already refused MQ buffer adds, so
> H_REG_LOGICAL_LAN_QUEUE / replenish hit the same H_FUNCTION, mq_fallback is
> re-latched and another schedule_work(&adapter->work) reset is queued from an
> ethtool error path.
>
> Would it be better to route the rollback through
> ibmveth_resize_rx_channels(), or to skip it when mq_fallback is set and leave
> RX at 1?
>
> [ ... ]
The rollback restores the count we just
left. If firmware already refused MQ, that
scale-up can fail and latch again. !opened
is the documented down path and does not
allocate.

Thanks,
Mingming

      reply	other threads:[~2026-09-25  7:44 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 15:07 [PATCH net-next v6 00/15] ibmveth: Add multi-queue RX support Mingming Cao
2026-08-31 15:07 ` [PATCH net-next v6 01/15] ibmveth: Add MQ RX hypercall wrappers and call definitions Mingming Cao
2026-09-03 18:10   ` [net-next,v6,01/15] " netdev-bot+sashiko
2026-09-25  5:52     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 02/15] ibmveth: Prepare MQ RX adapter data structures Mingming Cao
2026-08-31 15:07 ` [PATCH net-next v6 03/15] ibmveth: Refactor RX resource allocation for MQ RX bring-up Mingming Cao
2026-09-03 18:10   ` [net-next,v6,03/15] " netdev-bot+sashiko
2026-09-25  6:08     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 04/15] ibmveth: Refactor buffer pool management for per-queue MQ RX Mingming Cao
2026-09-03 18:10   ` [net-next,v6,04/15] " netdev-bot+sashiko
2026-09-25  6:16     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 05/15] ibmveth: Refactor RX interrupt control for MQ RX queues Mingming Cao
2026-09-03 18:10   ` [net-next,v6,05/15] " netdev-bot+sashiko
2026-09-25  6:21     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 06/15] ibmveth: Refactor TX resource allocation in open/close paths Mingming Cao
2026-09-03 18:10   ` [net-next,v6,06/15] " netdev-bot+sashiko
2026-09-25  6:28     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 07/15] ibmveth: Add RX queue register helpers for MQ Mingming Cao
2026-08-31 15:07 ` [PATCH net-next v6 08/15] ibmveth: Add queue-aware RX buffer submit helper " Mingming Cao
2026-09-03 18:10   ` [net-next,v6,08/15] " netdev-bot+sashiko
2026-09-25  6:32     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 09/15] ibmveth: Harden RX poll path with helpers Mingming Cao
2026-09-03 18:10   ` [net-next,v6,09/15] " netdev-bot+sashiko
2026-09-25  6:40     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 10/15] ibmveth: Enable multi-queue RX receive path Mingming Cao
2026-09-03 18:10   ` [net-next,v6,10/15] " netdev-bot+sashiko
2026-09-25  6:48     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 11/15] ibmveth: Add per-queue RX and TX statistics collection Mingming Cao
2026-09-03 18:10   ` [net-next,v6,11/15] " netdev-bot+sashiko
2026-09-25  7:08     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 12/15] ibmveth: Report MQ-aware RX counts in ethtool get_channels Mingming Cao
2026-09-03 18:10   ` [net-next,v6,12/15] " netdev-bot+sashiko
2026-09-25  7:43     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 13/15] ibmveth: Expose per-queue buffer pool details via debugfs Mingming Cao
2026-08-31 15:07 ` [PATCH net-next v6 14/15] ibmveth: Implement incremental MQ RX queue resize Mingming Cao
2026-09-03 18:10   ` [net-next,v6,14/15] " netdev-bot+sashiko
2026-09-25  7:43     ` mingming cao
2026-08-31 15:07 ` [PATCH net-next v6 15/15] ibmveth: Complete set_channels down-path and mq_fallback max_rx cap Mingming Cao
2026-09-03 18:10   ` [net-next,v6,15/15] " netdev-bot+sashiko
2026-09-25  7:43     ` mingming cao [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=7fee78c3-b79e-48d7-932a-81a1f3083f64@linux.ibm.com \
    --to=mmc@linux.ibm.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bjking1@linux.ibm.com \
    --cc=davem@davemloft.net \
    --cc=davemarq@linux.ibm.com \
    --cc=edumazet@google.com \
    --cc=haren@linux.ibm.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.ibm.com \
    --cc=mpe@ellerman.id.au \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=nnac123@linux.ibm.com \
    --cc=pabeni@redhat.com \
    --cc=ricklind@linux.ibm.com \
    --cc=shaik.abdulla1@ibm.com \
    /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