Commit dcdcf867 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: use napi_gro_frags() for SG skbs

For non-linear packets, get the skb for attaching the page fragments
from napi_get_frags() so that it can be recycled during GRO.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c04b116a
...@@ -5106,8 +5106,9 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -5106,8 +5106,9 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
#endif #endif
static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb, static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr) struct qeth_hdr *hdr, bool uses_frags)
{ {
struct napi_struct *napi = &card->napi;
bool is_cso; bool is_cso;
switch (hdr->hdr.l2.id) { switch (hdr->hdr.l2.id) {
...@@ -5130,7 +5131,10 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -5130,7 +5131,10 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
break; break;
default: default:
/* never happens */ /* never happens */
dev_kfree_skb_any(skb); if (uses_frags)
napi_free_frags(napi);
else
dev_kfree_skb_any(skb);
return; return;
} }
...@@ -5141,8 +5145,6 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -5141,8 +5145,6 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
} }
skb->protocol = eth_type_trans(skb, skb->dev);
QETH_CARD_STAT_ADD(card, rx_bytes, skb->len); QETH_CARD_STAT_ADD(card, rx_bytes, skb->len);
QETH_CARD_STAT_INC(card, rx_packets); QETH_CARD_STAT_INC(card, rx_packets);
if (skb_is_nonlinear(skb)) { if (skb_is_nonlinear(skb)) {
...@@ -5151,7 +5153,12 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -5151,7 +5153,12 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
skb_shinfo(skb)->nr_frags); skb_shinfo(skb)->nr_frags);
} }
napi_gro_receive(&card->napi, skb); if (uses_frags) {
napi_gro_frags(napi);
} else {
skb->protocol = eth_type_trans(skb, skb->dev);
napi_gro_receive(napi, skb);
}
} }
static void qeth_create_skb_frag(struct sk_buff *skb, char *data, int data_len) static void qeth_create_skb_frag(struct sk_buff *skb, char *data, int data_len)
...@@ -5177,7 +5184,9 @@ static int qeth_extract_skb(struct qeth_card *card, ...@@ -5177,7 +5184,9 @@ static int qeth_extract_skb(struct qeth_card *card,
{ {
struct qdio_buffer_element *element = *__element; struct qdio_buffer_element *element = *__element;
struct qdio_buffer *buffer = qethbuffer->buffer; struct qdio_buffer *buffer = qethbuffer->buffer;
struct napi_struct *napi = &card->napi;
unsigned int linear_len = 0; unsigned int linear_len = 0;
bool uses_frags = false;
int offset = *__offset; int offset = *__offset;
bool use_rx_sg = false; bool use_rx_sg = false;
unsigned int headroom; unsigned int headroom;
...@@ -5253,21 +5262,42 @@ static int qeth_extract_skb(struct qeth_card *card, ...@@ -5253,21 +5262,42 @@ static int qeth_extract_skb(struct qeth_card *card,
!atomic_read(&card->force_alloc_skb) && !atomic_read(&card->force_alloc_skb) &&
!IS_OSN(card)); !IS_OSN(card));
if (use_rx_sg && qethbuffer->rx_skb) { if (use_rx_sg) {
/* QETH_CQ_ENABLED only: */ /* QETH_CQ_ENABLED only: */
skb = qethbuffer->rx_skb; if (qethbuffer->rx_skb) {
qethbuffer->rx_skb = NULL; skb = qethbuffer->rx_skb;
} else { qethbuffer->rx_skb = NULL;
if (!use_rx_sg) goto use_skb;
linear_len = skb_len; }
skb = napi_alloc_skb(&card->napi, linear_len + headroom);
skb = napi_get_frags(napi);
if (!skb) {
/* -ENOMEM, no point in falling back further. */
QETH_CARD_STAT_INC(card, rx_dropped_nomem);
goto walk_packet;
}
if (skb_tailroom(skb) >= linear_len + headroom) {
uses_frags = true;
goto use_skb;
}
netdev_info_once(card->dev,
"Insufficient linear space in NAPI frags skb, need %u but have %u\n",
linear_len + headroom, skb_tailroom(skb));
/* Shouldn't happen. Don't optimize, fall back to linear skb. */
} }
if (!skb) linear_len = skb_len;
skb = napi_alloc_skb(napi, linear_len + headroom);
if (!skb) {
QETH_CARD_STAT_INC(card, rx_dropped_nomem); QETH_CARD_STAT_INC(card, rx_dropped_nomem);
else if (headroom) goto walk_packet;
skb_reserve(skb, headroom); }
use_skb:
if (headroom)
skb_reserve(skb, headroom);
walk_packet: walk_packet:
while (skb_len) { while (skb_len) {
int data_len = min(skb_len, (int)(element->length - offset)); int data_len = min(skb_len, (int)(element->length - offset));
...@@ -5300,7 +5330,10 @@ static int qeth_extract_skb(struct qeth_card *card, ...@@ -5300,7 +5330,10 @@ static int qeth_extract_skb(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "unexeob"); QETH_CARD_TEXT(card, 4, "unexeob");
QETH_CARD_HEX(card, 2, buffer, sizeof(void *)); QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
if (skb) { if (skb) {
dev_kfree_skb_any(skb); if (uses_frags)
napi_free_frags(napi);
else
dev_kfree_skb_any(skb);
QETH_CARD_STAT_INC(card, QETH_CARD_STAT_INC(card,
rx_length_errors); rx_length_errors);
} }
...@@ -5318,7 +5351,7 @@ static int qeth_extract_skb(struct qeth_card *card, ...@@ -5318,7 +5351,7 @@ static int qeth_extract_skb(struct qeth_card *card,
*__element = element; *__element = element;
*__offset = offset; *__offset = offset;
qeth_receive_skb(card, skb, hdr); qeth_receive_skb(card, skb, hdr, uses_frags);
return 0; return 0;
} }
......
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