sfc: attach/detach EF100 representors along with their owning PF
authorEdward Cree <ecree.xilinx@gmail.com>
Wed, 20 Jul 2022 18:33:49 +0000 (19:33 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 22 Jul 2022 11:50:06 +0000 (12:50 +0100)
Since representors piggy-back on the PF's queues for TX, they can
 only accept new TXes while the PF is up.  Thus, any operation which
 detaches the PF must first detach all its VFreps.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ef100_netdev.c
drivers/net/ethernet/sfc/ef100_rep.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/efx_common.c
drivers/net/ethernet/sfc/efx_common.h

index 3443477c26dacd6884ee8bc7ad391392841dce4d..9e65de1ab88952cc7643c92f1d42cb9daf064f2a 100644 (file)
@@ -85,6 +85,7 @@ static int ef100_net_stop(struct net_device *net_dev)
        netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
                  raw_smp_processor_id());
 
+       efx_detach_reps(efx);
        netif_stop_queue(net_dev);
        efx_stop_all(efx);
        efx_mcdi_mac_fini_stats(efx);
@@ -176,6 +177,8 @@ static int ef100_net_open(struct net_device *net_dev)
        mutex_unlock(&efx->mac_lock);
 
        efx->state = STATE_NET_UP;
+       if (netif_running(efx->net_dev))
+               efx_attach_reps(efx);
 
        return 0;
 
index 6d4c3f0eee0ab704088a04ab30439a8c48204d95..d07539f091b833cf279ca4f6b5c416b3e1aaf44d 100644 (file)
@@ -132,8 +132,13 @@ static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
        spin_lock_bh(&efx->vf_reps_lock);
        list_add_tail(&efv->list, &efx->vf_reps);
        spin_unlock_bh(&efx->vf_reps_lock);
-       netif_carrier_off(net_dev);
-       netif_tx_stop_all_queues(net_dev);
+       if (netif_running(efx->net_dev) && efx->state == STATE_NET_UP) {
+               netif_device_attach(net_dev);
+               netif_carrier_on(net_dev);
+       } else {
+               netif_carrier_off(net_dev);
+               netif_tx_stop_all_queues(net_dev);
+       }
        rtnl_unlock();
 
        net_dev->netdev_ops = &efx_ef100_rep_netdev_ops;
@@ -171,9 +176,11 @@ static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
 {
        struct efx_nic *efx = efv->parent;
 
+       rtnl_lock();
        spin_lock_bh(&efx->vf_reps_lock);
        list_del(&efv->list);
        spin_unlock_bh(&efx->vf_reps_lock);
+       rtnl_unlock();
        free_netdev(efv->net_dev);
 }
 
index c05a83da9e44d2ce250b740a82d1f5077a883ab8..4239c7ece1235527c51190facbfb45857b402c2e 100644 (file)
@@ -12,6 +12,7 @@
 #include "net_driver.h"
 #include "ef100_rx.h"
 #include "ef100_tx.h"
+#include "efx_common.h"
 #include "filter.h"
 
 int efx_net_open(struct net_device *net_dev);
@@ -206,6 +207,9 @@ static inline void efx_device_detach_sync(struct efx_nic *efx)
 {
        struct net_device *dev = efx->net_dev;
 
+       /* We must stop reps (which use our TX) before we stop ourselves. */
+       efx_detach_reps(efx);
+
        /* Lock/freeze all TX queues so that we can be sure the
         * TX scheduler is stopped when we're done and before
         * netif_device_present() becomes false.
@@ -217,8 +221,11 @@ static inline void efx_device_detach_sync(struct efx_nic *efx)
 
 static inline void efx_device_attach_if_not_resetting(struct efx_nic *efx)
 {
-       if ((efx->state != STATE_DISABLED) && !efx->reset_pending)
+       if ((efx->state != STATE_DISABLED) && !efx->reset_pending) {
                netif_device_attach(efx->net_dev);
+               if (efx->state == STATE_NET_UP)
+                       efx_attach_reps(efx);
+       }
 }
 
 static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
index fb6b66b8707ba7bd854275c8c1e3c6a10ec74798..a929a1aaba9291e5b840416b4849447d1f598340 100644 (file)
@@ -24,6 +24,7 @@
 #include "mcdi_port_common.h"
 #include "io.h"
 #include "mcdi_pcol.h"
+#include "ef100_rep.h"
 
 static unsigned int debug = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
                             NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
@@ -1391,3 +1392,38 @@ int efx_get_phys_port_name(struct net_device *net_dev, char *name, size_t len)
                return -EINVAL;
        return 0;
 }
+
+void efx_detach_reps(struct efx_nic *efx)
+{
+       struct net_device *rep_dev;
+       struct efx_rep *efv;
+
+       ASSERT_RTNL();
+       netif_dbg(efx, drv, efx->net_dev, "Detaching VF representors\n");
+       list_for_each_entry(efv, &efx->vf_reps, list) {
+               rep_dev = efv->net_dev;
+               if (!rep_dev)
+                       continue;
+               netif_carrier_off(rep_dev);
+               /* See efx_device_detach_sync() */
+               netif_tx_lock_bh(rep_dev);
+               netif_tx_stop_all_queues(rep_dev);
+               netif_tx_unlock_bh(rep_dev);
+       }
+}
+
+void efx_attach_reps(struct efx_nic *efx)
+{
+       struct net_device *rep_dev;
+       struct efx_rep *efv;
+
+       ASSERT_RTNL();
+       netif_dbg(efx, drv, efx->net_dev, "Attaching VF representors\n");
+       list_for_each_entry(efv, &efx->vf_reps, list) {
+               rep_dev = efv->net_dev;
+               if (!rep_dev)
+                       continue;
+               netif_tx_wake_all_queues(rep_dev);
+               netif_carrier_on(rep_dev);
+       }
+}
index 93babc1a2678ea77b819dc8c44df1a3ccacfe6a3..2c54dac3e6624591ae50c6be233a2af724f851cd 100644 (file)
@@ -111,4 +111,7 @@ int efx_get_phys_port_id(struct net_device *net_dev,
 
 int efx_get_phys_port_name(struct net_device *net_dev,
                           char *name, size_t len);
+
+void efx_detach_reps(struct efx_nic *efx);
+void efx_attach_reps(struct efx_nic *efx);
 #endif