mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 22:26:55 +00:00
sfc: ef100 representor RX top half
Representor RX uses a NAPI context driven by a 'fake interrupt': when the parent PF receives a packet destined for the representor, it adds it to an SKB list (efv->rx_list), and schedules NAPI if the 'fake interrupt' is primed. The NAPI poll then pulls packets off this list and feeds them to the stack with netif_receive_skb_list(). This scheme allows us to decouple representor RX from the parent PF's RX fast-path. This patch implements the 'top half', which builds an SKB, copies data into it from the RX buffer (which can then be released), adds it to the queue and fires the 'fake interrupt' if necessary. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
69bb5fa73d
commit
9fe00c800e
2 changed files with 56 additions and 0 deletions
|
@ -13,9 +13,12 @@
|
||||||
#include "ef100_netdev.h"
|
#include "ef100_netdev.h"
|
||||||
#include "ef100_nic.h"
|
#include "ef100_nic.h"
|
||||||
#include "mae.h"
|
#include "mae.h"
|
||||||
|
#include "rx_common.h"
|
||||||
|
|
||||||
#define EFX_EF100_REP_DRIVER "efx_ef100_rep"
|
#define EFX_EF100_REP_DRIVER "efx_ef100_rep"
|
||||||
|
|
||||||
|
#define EFX_REP_DEFAULT_PSEUDO_RING_SIZE 64
|
||||||
|
|
||||||
static int efx_ef100_rep_poll(struct napi_struct *napi, int weight);
|
static int efx_ef100_rep_poll(struct napi_struct *napi, int weight);
|
||||||
|
|
||||||
static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
|
static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
|
||||||
|
@ -198,6 +201,7 @@ static int efx_ef100_configure_rep(struct efx_rep *efv)
|
||||||
u32 selector;
|
u32 selector;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
efv->rx_pring_size = EFX_REP_DEFAULT_PSEUDO_RING_SIZE;
|
||||||
/* Construct mport selector for corresponding VF */
|
/* Construct mport selector for corresponding VF */
|
||||||
efx_mae_mport_vf(efx, efv->idx, &selector);
|
efx_mae_mport_vf(efx, efv->idx, &selector);
|
||||||
/* Look up actual mport ID */
|
/* Look up actual mport ID */
|
||||||
|
@ -320,3 +324,54 @@ static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
|
||||||
}
|
}
|
||||||
return spent;
|
return spent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf)
|
||||||
|
{
|
||||||
|
u8 *eh = efx_rx_buf_va(rx_buf);
|
||||||
|
struct sk_buff *skb;
|
||||||
|
bool primed;
|
||||||
|
|
||||||
|
/* Don't allow too many queued SKBs to build up, as they consume
|
||||||
|
* GFP_ATOMIC memory. If we overrun, just start dropping.
|
||||||
|
*/
|
||||||
|
if (efv->write_index - READ_ONCE(efv->read_index) > efv->rx_pring_size) {
|
||||||
|
atomic64_inc(&efv->stats.rx_dropped);
|
||||||
|
if (net_ratelimit())
|
||||||
|
netif_dbg(efv->parent, rx_err, efv->net_dev,
|
||||||
|
"nodesc-dropped packet of length %u\n",
|
||||||
|
rx_buf->len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = netdev_alloc_skb(efv->net_dev, rx_buf->len);
|
||||||
|
if (!skb) {
|
||||||
|
atomic64_inc(&efv->stats.rx_dropped);
|
||||||
|
if (net_ratelimit())
|
||||||
|
netif_dbg(efv->parent, rx_err, efv->net_dev,
|
||||||
|
"noskb-dropped packet of length %u\n",
|
||||||
|
rx_buf->len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(skb->data, eh, rx_buf->len);
|
||||||
|
__skb_put(skb, rx_buf->len);
|
||||||
|
|
||||||
|
skb_record_rx_queue(skb, 0); /* rep is single-queue */
|
||||||
|
|
||||||
|
/* Move past the ethernet header */
|
||||||
|
skb->protocol = eth_type_trans(skb, efv->net_dev);
|
||||||
|
|
||||||
|
skb_checksum_none_assert(skb);
|
||||||
|
|
||||||
|
atomic64_inc(&efv->stats.rx_packets);
|
||||||
|
atomic64_add(rx_buf->len, &efv->stats.rx_bytes);
|
||||||
|
|
||||||
|
/* Add it to the rx list */
|
||||||
|
spin_lock_bh(&efv->rx_lock);
|
||||||
|
primed = efv->read_index == efv->write_index;
|
||||||
|
list_add_tail(&skb->list, &efv->rx_list);
|
||||||
|
efv->write_index++;
|
||||||
|
spin_unlock_bh(&efv->rx_lock);
|
||||||
|
/* Trigger rx work */
|
||||||
|
if (primed)
|
||||||
|
napi_schedule(&efv->napi);
|
||||||
|
}
|
||||||
|
|
|
@ -57,4 +57,5 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
|
||||||
void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv);
|
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_fini_vfreps(struct efx_nic *efx);
|
||||||
|
|
||||||
|
void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
|
||||||
#endif /* EF100_REP_H */
|
#endif /* EF100_REP_H */
|
||||||
|
|
Loading…
Reference in a new issue