Commit 36a47c90 authored by Shannon Nelson's avatar Shannon Nelson Committed by David S. Miller

ionic: refactor skb building

The existing ionic_rx_frags() code is a bit of a mess and can
be cleaned up by unrolling the first frag/header setup from
the loop, then reworking the do-while-loop into a for-loop.  We
rename the function to a more descriptive ionic_rx_build_skb().
We also change a couple of related variable names for readability.
Reviewed-by: default avatarBrett Creeley <brett.creeley@amd.com>
Signed-off-by: default avatarShannon Nelson <shannon.nelson@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8599bd4c
...@@ -185,7 +185,7 @@ static void ionic_rx_page_free(struct ionic_queue *q, ...@@ -185,7 +185,7 @@ static void ionic_rx_page_free(struct ionic_queue *q,
} }
static bool ionic_rx_buf_recycle(struct ionic_queue *q, static bool ionic_rx_buf_recycle(struct ionic_queue *q,
struct ionic_buf_info *buf_info, u32 used) struct ionic_buf_info *buf_info, u32 len)
{ {
u32 size; u32 size;
...@@ -197,7 +197,7 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, ...@@ -197,7 +197,7 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q,
if (page_to_nid(buf_info->page) != numa_mem_id()) if (page_to_nid(buf_info->page) != numa_mem_id())
return false; return false;
size = ALIGN(used, q->xdp_rxq_info ? IONIC_PAGE_SIZE : IONIC_PAGE_SPLIT_SZ); size = ALIGN(len, q->xdp_rxq_info ? IONIC_PAGE_SIZE : IONIC_PAGE_SPLIT_SZ);
buf_info->page_offset += size; buf_info->page_offset += size;
if (buf_info->page_offset >= IONIC_PAGE_SIZE) if (buf_info->page_offset >= IONIC_PAGE_SIZE)
return false; return false;
...@@ -207,8 +207,29 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q, ...@@ -207,8 +207,29 @@ static bool ionic_rx_buf_recycle(struct ionic_queue *q,
return true; return true;
} }
static struct sk_buff *ionic_rx_frags(struct net_device *netdev, static void ionic_rx_add_skb_frag(struct ionic_queue *q,
struct ionic_queue *q, struct sk_buff *skb,
struct ionic_buf_info *buf_info,
u32 off, u32 len,
bool synced)
{
if (!synced)
dma_sync_single_range_for_cpu(q->dev, ionic_rx_buf_pa(buf_info),
off, len, DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
buf_info->page, buf_info->page_offset + off,
len,
IONIC_PAGE_SIZE);
if (!ionic_rx_buf_recycle(q, buf_info, len)) {
dma_unmap_page(q->dev, buf_info->dma_addr,
IONIC_PAGE_SIZE, DMA_FROM_DEVICE);
buf_info->page = NULL;
}
}
static struct sk_buff *ionic_rx_build_skb(struct ionic_queue *q,
struct ionic_rx_desc_info *desc_info, struct ionic_rx_desc_info *desc_info,
unsigned int headroom, unsigned int headroom,
unsigned int len, unsigned int len,
...@@ -217,7 +238,6 @@ static struct sk_buff *ionic_rx_frags(struct net_device *netdev, ...@@ -217,7 +238,6 @@ static struct sk_buff *ionic_rx_frags(struct net_device *netdev,
{ {
struct ionic_buf_info *buf_info; struct ionic_buf_info *buf_info;
struct ionic_rx_stats *stats; struct ionic_rx_stats *stats;
struct device *dev = q->dev;
struct sk_buff *skb; struct sk_buff *skb;
unsigned int i; unsigned int i;
u16 frag_len; u16 frag_len;
...@@ -225,54 +245,41 @@ static struct sk_buff *ionic_rx_frags(struct net_device *netdev, ...@@ -225,54 +245,41 @@ static struct sk_buff *ionic_rx_frags(struct net_device *netdev,
stats = q_to_rx_stats(q); stats = q_to_rx_stats(q);
buf_info = &desc_info->bufs[0]; buf_info = &desc_info->bufs[0];
prefetchw(buf_info->page); prefetchw(buf_info->page);
skb = napi_get_frags(&q_to_qcq(q)->napi); skb = napi_get_frags(&q_to_qcq(q)->napi);
if (unlikely(!skb)) { if (unlikely(!skb)) {
net_warn_ratelimited("%s: SKB alloc failed on %s!\n", net_warn_ratelimited("%s: SKB alloc failed on %s!\n",
dev_name(dev), q->name); dev_name(q->dev), q->name);
stats->alloc_err++; stats->alloc_err++;
return NULL; return NULL;
} }
i = num_sg_elems + 1;
do {
if (unlikely(!buf_info->page)) {
dev_kfree_skb(skb);
return NULL;
}
if (headroom) if (headroom)
frag_len = min_t(u16, len, IONIC_XDP_MAX_LINEAR_MTU + VLAN_ETH_HLEN); frag_len = min_t(u16, len,
IONIC_XDP_MAX_LINEAR_MTU + VLAN_ETH_HLEN);
else else
frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info)); frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info));
len -= frag_len;
if (!synced)
dma_sync_single_range_for_cpu(dev, ionic_rx_buf_pa(buf_info),
headroom, frag_len, DMA_FROM_DEVICE);
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
buf_info->page, buf_info->page_offset + headroom,
frag_len, IONIC_PAGE_SIZE);
if (!ionic_rx_buf_recycle(q, buf_info, frag_len)) {
dma_unmap_page(dev, buf_info->dma_addr,
IONIC_PAGE_SIZE, DMA_FROM_DEVICE);
buf_info->page = NULL;
}
/* only needed on the first buffer */
if (headroom)
headroom = 0;
if (unlikely(!buf_info->page))
goto err_bad_buf_page;
ionic_rx_add_skb_frag(q, skb, buf_info, headroom, frag_len, synced);
len -= frag_len;
buf_info++; buf_info++;
i--; for (i = 0; i < num_sg_elems; i++, buf_info++) {
} while (i > 0); if (unlikely(!buf_info->page))
goto err_bad_buf_page;
frag_len = min_t(u16, len, ionic_rx_buf_size(buf_info));
ionic_rx_add_skb_frag(q, skb, buf_info, 0, frag_len, synced);
len -= frag_len;
}
return skb; return skb;
err_bad_buf_page:
dev_kfree_skb(skb);
return NULL;
} }
static struct sk_buff *ionic_rx_copybreak(struct net_device *netdev, static struct sk_buff *ionic_rx_copybreak(struct net_device *netdev,
...@@ -641,6 +648,8 @@ static void ionic_rx_clean(struct ionic_queue *q, ...@@ -641,6 +648,8 @@ static void ionic_rx_clean(struct ionic_queue *q,
struct bpf_prog *xdp_prog; struct bpf_prog *xdp_prog;
unsigned int headroom; unsigned int headroom;
struct sk_buff *skb; struct sk_buff *skb;
bool synced = false;
bool use_copybreak;
u16 len; u16 len;
stats = q_to_rx_stats(q); stats = q_to_rx_stats(q);
...@@ -655,17 +664,20 @@ static void ionic_rx_clean(struct ionic_queue *q, ...@@ -655,17 +664,20 @@ static void ionic_rx_clean(struct ionic_queue *q,
stats->bytes += len; stats->bytes += len;
xdp_prog = READ_ONCE(q->lif->xdp_prog); xdp_prog = READ_ONCE(q->lif->xdp_prog);
if (xdp_prog && if (xdp_prog) {
ionic_run_xdp(stats, netdev, xdp_prog, q, desc_info->bufs, len)) if (ionic_run_xdp(stats, netdev, xdp_prog, q, desc_info->bufs, len))
return; return;
synced = true;
}
headroom = q->xdp_rxq_info ? XDP_PACKET_HEADROOM : 0; headroom = q->xdp_rxq_info ? XDP_PACKET_HEADROOM : 0;
if (len <= q->lif->rx_copybreak) use_copybreak = len <= q->lif->rx_copybreak;
if (use_copybreak)
skb = ionic_rx_copybreak(netdev, q, desc_info, skb = ionic_rx_copybreak(netdev, q, desc_info,
headroom, len, !!xdp_prog); headroom, len, synced);
else else
skb = ionic_rx_frags(netdev, q, desc_info, headroom, len, skb = ionic_rx_build_skb(q, desc_info, headroom, len,
comp->num_sg_elems, !!xdp_prog); comp->num_sg_elems, synced);
if (unlikely(!skb)) { if (unlikely(!skb)) {
stats->dropped++; stats->dropped++;
...@@ -732,7 +744,7 @@ static void ionic_rx_clean(struct ionic_queue *q, ...@@ -732,7 +744,7 @@ static void ionic_rx_clean(struct ionic_queue *q,
} }
} }
if (len <= q->lif->rx_copybreak) if (use_copybreak)
napi_gro_receive(&qcq->napi, skb); napi_gro_receive(&qcq->napi, skb);
else else
napi_gro_frags(&qcq->napi); napi_gro_frags(&qcq->napi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment