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
prev parent 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.