Convert the ring size path to pre-allocate and swap, for the same reasons
as the channel count path: an allocation failure returns the error with
the running configuration untouched, and the vport is never released.

This drops the fallback on failure. Previously a failed mana_attach() was
retried with the previous values, or the defaults, or the minimums, so a
user who asked for a specific size could end up with a different one with
no indication beyond dmesg. There is nothing to recover from now, so the
error is returned.

Also return early when the requested sizes round to the values already in
use.

Signed-off-by: Long Li <[email protected]>
---
 .../ethernet/microsoft/mana/mana_ethtool.c    | 74 +++++++++++++------
 1 file changed, 51 insertions(+), 23 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c 
b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 
b12291555eaeb4fafc305ffe7d9e550ec01952c8..40e9886c87a81c86080e52955a0a685cf0472772
 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -761,19 +761,18 @@ static void mana_get_ringparam(struct net_device *ndev,
        ring->tx_max_pending = MAX_TX_BUFFERS_PER_QUEUE;
 }
 
+
 static int mana_set_ringparam(struct net_device *ndev,
                              struct ethtool_ringparam *ring,
                              struct kernel_ethtool_ringparam *kernel_ring,
                              struct netlink_ext_ack *extack)
 {
        struct mana_port_context *apc = netdev_priv(ndev);
+       struct mana_port_context *scratch;
+       struct mana_qset newq, oldq;
        u32 new_tx, new_rx;
-       u32 old_tx, old_rx;
        int err;
 
-       old_tx = apc->tx_queue_size;
-       old_rx = apc->rx_queue_size;
-
        if (ring->tx_pending < MIN_TX_BUFFERS_PER_QUEUE) {
                NL_SET_ERR_MSG_FMT(extack, "tx:%d less than the min:%d", 
ring->tx_pending,
                                   MIN_TX_BUFFERS_PER_QUEUE);
@@ -791,32 +790,61 @@ static int mana_set_ringparam(struct net_device *ndev,
        netdev_info(ndev, "Using nearest power of 2 values for Txq:%d Rxq:%d\n",
                    new_tx, new_rx);
 
-       /* pre-allocating new buffers to prevent failures in mana_attach() 
later */
-       apc->rx_queue_size = new_rx;
-       err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
-       apc->rx_queue_size = old_rx;
-       if (err) {
-               netdev_err(ndev, "Insufficient memory for new allocations\n");
-               return err;
+       if (new_rx == apc->rx_queue_size && new_tx == apc->tx_queue_size)
+               return 0;
+
+       /* Port is down: no queues to rebuild, just record the new sizes. */
+       if (!apc->port_is_up) {
+               apc->rx_queue_size = new_rx;
+               apc->tx_queue_size = new_tx;
+               return 0;
        }
 
-       err = mana_detach(ndev, false);
-       if (err) {
-               netdev_err(ndev, "mana_detach failed: %d\n", err);
-               goto out;
+       /* Block RDMA from acquiring the vport for the duration. The vport
+        * itself is never released, so vport_use_count stays > 0.
+        */
+       mutex_lock(&apc->vport_mutex);
+       if (apc->channel_changing) {
+               mutex_unlock(&apc->vport_mutex);
+               return -EBUSY;
        }
+       apc->channel_changing = true;
+       mutex_unlock(&apc->vport_mutex);
 
-       apc->tx_queue_size = new_tx;
-       apc->rx_queue_size = new_rx;
+       scratch = mana_qset_scratch_alloc(apc);
+       if (!scratch) {
+               err = -ENOMEM;
+               goto clear_flag;
+       }
 
-       err = mana_attach(ndev);
+       err = mana_alloc_qset(scratch, apc->num_queues, new_rx, new_tx,
+                             apc->priv_flags, &newq);
        if (err) {
-               netdev_err(ndev, "mana_attach failed: %d\n", err);
-               apc->tx_queue_size = old_tx;
-               apc->rx_queue_size = old_rx;
+               NL_SET_ERR_MSG_FMT(extack, "failed to change ring params: %d",
+                                  err);
+               goto free_scratch; /* current qset untouched */
        }
-out:
-       mana_pre_dealloc_rxbufs(apc);
+
+       err = mana_publish_qset(apc, &newq, &oldq);
+       if (err) {
+               NL_SET_ERR_MSG_FMT(extack, "failed to change ring params: %d",
+                                  err);
+               mana_free_qset(scratch, &newq);
+               goto free_scratch;
+       }
+
+       mana_free_qset(scratch, &oldq);
+
+free_scratch:
+       /* After the caller-side cleanup above, so the EQ pool outlives the
+        * CQs that reference it.
+        */
+       mana_publish_close_if_needed(apc);
+       mana_qset_scratch_free(scratch);
+clear_flag:
+       mutex_lock(&apc->vport_mutex);
+       apc->channel_changing = false;
+       mutex_unlock(&apc->vport_mutex);
        return err;
 }
 
-- 
2.43.0


Reply via email to