sfc: receive packets from EF100 VFs into representors
authorEdward Cree <ecree.xilinx@gmail.com>
Thu, 28 Jul 2022 18:57:48 +0000 (19:57 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 30 Jul 2022 04:22:06 +0000 (21:22 -0700)
If the source m-port of a packet in __ef100_rx_packet() is a VF,
 hand off the packet to the corresponding representor with
 efx_ef100_rep_rx_packet().

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/sfc/ef100_rep.c
drivers/net/ethernet/sfc/ef100_rep.h
drivers/net/ethernet/sfc/ef100_rx.c

index e6c6e9e..c0bc12b 100644 (file)
@@ -224,6 +224,7 @@ static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
        list_del(&efv->list);
        spin_unlock_bh(&efx->vf_reps_lock);
        rtnl_unlock();
+       synchronize_rcu();
        free_netdev(efv->net_dev);
 }
 
@@ -375,3 +376,21 @@ void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf)
        if (primed)
                napi_schedule(&efv->napi);
 }
+
+struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport)
+{
+       struct efx_rep *efv, *out = NULL;
+
+       /* spinlock guards against list mutation while we're walking it;
+        * but caller must also hold rcu_read_lock() to ensure the netdev
+        * isn't freed after we drop the spinlock.
+        */
+       spin_lock_bh(&efx->vf_reps_lock);
+       list_for_each_entry(efv, &efx->vf_reps, list)
+               if (efv->mport == mport) {
+                       out = efv;
+                       break;
+               }
+       spin_unlock_bh(&efx->vf_reps_lock);
+       return out;
+}
index 7d2f15c..f378713 100644 (file)
@@ -58,4 +58,9 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv);
 void efx_ef100_fini_vfreps(struct efx_nic *efx);
 
 void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
+/* Returns the representor corresponding to a VF m-port, or NULL
+ * @mport is an m-port label, *not* an m-port ID!
+ * Caller must hold rcu_read_lock().
+ */
+struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
 #endif /* EF100_REP_H */
index b8da9e3..65bbe37 100644 (file)
@@ -85,6 +85,24 @@ void __ef100_rx_packet(struct efx_channel *channel)
        nic_data = efx->nic_data;
 
        if (nic_data->have_mport && ing_port != nic_data->base_mport) {
+#ifdef CONFIG_SFC_SRIOV
+               struct efx_rep *efv;
+
+               rcu_read_lock();
+               efv = efx_ef100_find_rep_by_mport(efx, ing_port);
+               if (efv) {
+                       if (efv->net_dev->flags & IFF_UP)
+                               efx_ef100_rep_rx_packet(efv, rx_buf);
+                       rcu_read_unlock();
+                       /* Representor Rx doesn't care about PF Rx buffer
+                        * ownership, it just makes a copy. So, we are done
+                        * with the Rx buffer from PF point of view and should
+                        * free it.
+                        */
+                       goto free_rx_buffer;
+               }
+               rcu_read_unlock();
+#endif
                if (net_ratelimit())
                        netif_warn(efx, drv, efx->net_dev,
                                   "Unrecognised ing_port %04x (base %04x), dropping\n",