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

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
Loading
Loading
Loading
Loading
+50 −17
Original line number Diff line number Diff line
@@ -5106,8 +5106,9 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
#endif

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;

	switch (hdr->hdr.l2.id) {
@@ -5130,6 +5131,9 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
		break;
	default:
		/* never happens */
		if (uses_frags)
			napi_free_frags(napi);
		else
			dev_kfree_skb_any(skb);
		return;
	}
@@ -5141,8 +5145,6 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
		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_INC(card, rx_packets);
	if (skb_is_nonlinear(skb)) {
@@ -5151,7 +5153,12 @@ static void qeth_receive_skb(struct qeth_card *card, struct sk_buff *skb,
				   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)
@@ -5177,7 +5184,9 @@ static int qeth_extract_skb(struct qeth_card *card,
{
	struct qdio_buffer_element *element = *__element;
	struct qdio_buffer *buffer = qethbuffer->buffer;
	struct napi_struct *napi = &card->napi;
	unsigned int linear_len = 0;
	bool uses_frags = false;
	int offset = *__offset;
	bool use_rx_sg = false;
	unsigned int headroom;
@@ -5253,21 +5262,42 @@ next_packet:
		     !atomic_read(&card->force_alloc_skb) &&
		     !IS_OSN(card));

	if (use_rx_sg && qethbuffer->rx_skb) {
	if (use_rx_sg) {
		/* QETH_CQ_ENABLED only: */
		if (qethbuffer->rx_skb) {
			skb = qethbuffer->rx_skb;
			qethbuffer->rx_skb = NULL;
	} else {
		if (!use_rx_sg)
			linear_len = skb_len;
		skb = napi_alloc_skb(&card->napi, linear_len + headroom);
			goto use_skb;
		}

	if (!skb)
		skb = napi_get_frags(napi);
		if (!skb) {
			/* -ENOMEM, no point in falling back further. */
			QETH_CARD_STAT_INC(card, rx_dropped_nomem);
	else if (headroom)
		skb_reserve(skb, headroom);
			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. */
	}

	linear_len = skb_len;
	skb = napi_alloc_skb(napi, linear_len + headroom);
	if (!skb) {
		QETH_CARD_STAT_INC(card, rx_dropped_nomem);
		goto walk_packet;
	}

use_skb:
	if (headroom)
		skb_reserve(skb, headroom);
walk_packet:
	while (skb_len) {
		int data_len = min(skb_len, (int)(element->length - offset));
@@ -5300,6 +5330,9 @@ walk_packet:
				QETH_CARD_TEXT(card, 4, "unexeob");
				QETH_CARD_HEX(card, 2, buffer, sizeof(void *));
				if (skb) {
					if (uses_frags)
						napi_free_frags(napi);
					else
						dev_kfree_skb_any(skb);
					QETH_CARD_STAT_INC(card,
							   rx_length_errors);
@@ -5318,7 +5351,7 @@ walk_packet:
	*__element = element;
	*__offset = offset;

	qeth_receive_skb(card, skb, hdr);
	qeth_receive_skb(card, skb, hdr, uses_frags);
	return 0;
}