OSDN Git Service

sfc: handle VI shortage on ef100 by readjusting the channels
authorPieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Wed, 24 May 2023 09:36:38 +0000 (10:36 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 26 May 2023 09:15:30 +0000 (10:15 +0100)
When fewer VIs are allocated than what is allowed we can readjust
the channels by calling efx_mcdi_alloc_vis() again.

Signed-off-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Reviewed-by: Martin Habets <habetsm.xilinx@gmail.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef100_netdev.c

index be395cd..274f3a2 100644 (file)
@@ -40,19 +40,26 @@ static int ef100_alloc_vis(struct efx_nic *efx, unsigned int *allocated_vis)
        unsigned int tx_vis = efx->n_tx_channels + efx->n_extra_tx_channels;
        unsigned int rx_vis = efx->n_rx_channels;
        unsigned int min_vis, max_vis;
+       int rc;
 
        EFX_WARN_ON_PARANOID(efx->tx_queues_per_channel != 1);
 
        tx_vis += efx->n_xdp_channels * efx->xdp_tx_per_channel;
 
        max_vis = max(rx_vis, tx_vis);
-       /* Currently don't handle resource starvation and only accept
-        * our maximum needs and no less.
+       /* We require at least a single complete TX channel worth of queues. */
+       min_vis = efx->tx_queues_per_channel;
+
+       rc = efx_mcdi_alloc_vis(efx, min_vis, max_vis,
+                               NULL, allocated_vis);
+
+       /* We retry allocating VIs by reallocating channels when we have not
+        * been able to allocate the maximum VIs.
         */
-       min_vis = max_vis;
+       if (!rc && *allocated_vis < max_vis)
+               rc = -EAGAIN;
 
-       return efx_mcdi_alloc_vis(efx, min_vis, max_vis,
-                                 NULL, allocated_vis);
+       return rc;
 }
 
 static int ef100_remap_bar(struct efx_nic *efx, int max_vis)
@@ -133,9 +140,41 @@ static int ef100_net_open(struct net_device *net_dev)
                goto fail;
 
        rc = ef100_alloc_vis(efx, &allocated_vis);
-       if (rc)
+       if (rc && rc != -EAGAIN)
                goto fail;
 
+       /* Try one more time but with the maximum number of channels
+        * equal to the allocated VIs, which would more likely succeed.
+        */
+       if (rc == -EAGAIN) {
+               rc = efx_mcdi_free_vis(efx);
+               if (rc)
+                       goto fail;
+
+               efx_remove_interrupts(efx);
+               efx->max_channels = allocated_vis;
+
+               rc = efx_probe_interrupts(efx);
+               if (rc)
+                       goto fail;
+
+               rc = efx_set_channels(efx);
+               if (rc)
+                       goto fail;
+
+               rc = ef100_alloc_vis(efx, &allocated_vis);
+               if (rc && rc != -EAGAIN)
+                       goto fail;
+
+               /* It should be very unlikely that we failed here again, but in
+                * such a case we return ENOSPC.
+                */
+               if (rc == -EAGAIN) {
+                       rc = -ENOSPC;
+                       goto fail;
+               }
+       }
+
        rc = efx_probe_channels(efx);
        if (rc)
                return rc;