diff options
author | Edward Cree <ecree.xilinx@gmail.com> | 2022-07-28 19:57:48 +0100 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-07-29 21:22:06 -0700 |
commit | f50e8fcda6b8d39db9098f7e1146dc491696ab91 (patch) | |
tree | 9f560eb39c58de3058f8d889e3c2836b553b7ade /drivers/net/ethernet/sfc | |
parent | 08d0b16ecb3649025336e104d8d25f56abde563c (diff) | |
download | linux-stable-f50e8fcda6b8d39db9098f7e1146dc491696ab91.tar.gz linux-stable-f50e8fcda6b8d39db9098f7e1146dc491696ab91.tar.bz2 linux-stable-f50e8fcda6b8d39db9098f7e1146dc491696ab91.zip |
sfc: receive packets from EF100 VFs into representors
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>
Diffstat (limited to 'drivers/net/ethernet/sfc')
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_rep.c | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_rep.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/sfc/ef100_rx.c | 18 |
3 files changed, 42 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c index e6c6e9e764b2..c0bc12b9e348 100644 --- a/drivers/net/ethernet/sfc/ef100_rep.c +++ b/drivers/net/ethernet/sfc/ef100_rep.c @@ -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; +} diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h index 7d2f15cee8d1..f3787133f793 100644 --- a/drivers/net/ethernet/sfc/ef100_rep.h +++ b/drivers/net/ethernet/sfc/ef100_rep.h @@ -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 */ diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c index b8da9e3b7bf2..65bbe37753e6 100644 --- a/drivers/net/ethernet/sfc/ef100_rx.c +++ b/drivers/net/ethernet/sfc/ef100_rx.c @@ -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", |