Complete set_channels() RX handling around ibmveth_resize_rx_channels():

  - When the interface is down: set TX queues first, then stash the
    desired RX count in adapter->num_rx_queues for the next open()
    (open publishes via netif_set_real_num_rx_queues). While down
    there are no RX queue mappings, buffers, or IRQs to grow or
    shrink, so do not allocate immediately.
  - When up: resize RX via ibmveth_resize_rx_channels(), then adjust
    TX LTBs with the existing stop/alloc/set_real_num_tx/free/wake
    path.
  - Non-MQ firmware returns -EOPNOTSUPP for rx > 1.
  - Validate rx_count within 1..IBMVETH_MAX_RX_QUEUES.

TX path hardening:
  - Initialize i = old_tx so a scale-down path that never enters the
    alloc loop still has defined bounds if set_real_num_tx_queues()
    fails.
  - Always return rc from set_channels().

Signed-off-by: Mingming Cao <[email protected]>
Reviewed-by: Dave Marquardt <[email protected]>
Tested-by: Shaik Abdulla <[email protected]>
---

Changes in v4:
- On !IFF_UP, stash num_rx_queues only after TX set succeeds; do not
  allocate live subordinate IRQs/buffers while down.
- Initialize i = old_tx on the TX adjust path.
- Always return rc from set_channels().
- Split from the resize-helper patch (same split as v3) while keeping
  a live caller of resize_rx_channels() in the previous patch.

 drivers/net/ethernet/ibm/ibmveth.c | 51 ++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ibmveth.c 
b/drivers/net/ethernet/ibm/ibmveth.c
index b57c7df92853..c99d8e8be7b3 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -2723,20 +2723,28 @@ 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 goal_rx = channels->rx_count;
+       unsigned int old_tx = netdev->real_num_tx_queues;
+       unsigned int goal_tx = channels->tx_count;
        int rc, i;
 
        /* If ndo_open has not been called yet then don't allocate, just set
         * desired netdev_queue's and return
         */
-       if (!(netdev->flags & IFF_UP))
-               return netif_set_real_num_tx_queues(netdev, goal);
+       if (!(netdev->flags & IFF_UP)) {
+               if (goal_tx != old_tx) {
+                       rc = netif_set_real_num_tx_queues(netdev, goal_tx);
+                       if (rc)
+                               return rc;
+               }
+
+               /* Stash desired RX count only after TX succeeds (or was
+                * already correct); open() publishes it via
+                * netif_set_real_num_rx_queues().
+                */
+               return ibmveth_resize_rx_channels(adapter, goal_rx);
+       }
 
-       /* Resize RX first while UP so ibmveth_resize_rx_channels() is used
-        * in this patch. !IFF_UP RX stash ordering lands next.
-        */
        rc = ibmveth_resize_rx_channels(adapter, goal_rx);
        if (rc)
                return rc;
@@ -2744,10 +2752,17 @@ static int ibmveth_set_channels(struct net_device 
*netdev,
        /* We have IBMVETH_MAX_QUEUES netdev_queue's allocated
         * but we may need to alloc/free the ltb's.
         */
+       if (goal_tx == old_tx)
+               return 0;
+
        netif_tx_stop_all_queues(netdev);
 
-       /* Allocate any queue that we need */
-       for (i = old; i < goal; i++) {
+       /* Allocate any queue that we need. Initialize i to old_tx so a
+        * scale-down path that never enters the loop still has defined
+        * bounds if set_real_num_tx_queues() fails.
+        */
+       i = old_tx;
+       for (; i < goal_tx; i++) {
                if (adapter->tx_ltb_ptr[i])
                        continue;
 
@@ -2755,20 +2770,22 @@ static int ibmveth_set_channels(struct net_device 
*netdev,
                if (!rc)
                        continue;
 
+               /* if something goes wrong, free everything we just allocated */
                netdev_err(netdev, "Failed to allocate more tx queues, 
returning to %d queues\n",
-                          old);
-               goal = old;
-               old = i;
+                          old_tx);
+               goal_tx = old_tx;
+               old_tx = i;
                break;
        }
-       rc = netif_set_real_num_tx_queues(netdev, goal);
+       rc = netif_set_real_num_tx_queues(netdev, goal_tx);
        if (rc) {
                netdev_err(netdev, "Failed to set real tx queues, returning to 
%d queues\n",
-                          old);
-               goal = old;
-               old = i;
+                          old_tx);
+               goal_tx = old_tx;
+               old_tx = i;
        }
-       for (i = old; i > goal; i--) {
+       /* Free any that are no longer needed */
+       for (i = old_tx; i > goal_tx; i--) {
                if (adapter->tx_ltb_ptr[i - 1])
                        ibmveth_free_tx_ltb(adapter, i - 1);
        }
-- 
2.50.1 (Apple Git-155)


Reply via email to