All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alice Michael <alice.michael@intel.com>
To: intel-wired-lan@osuosl.org
Subject: [Intel-wired-lan] [next S66 v2 11/11] i40e/i40evf: Use build_skb to build frames
Date: Wed,  5 Apr 2017 07:51:03 -0400	[thread overview]
Message-ID: <20170405115103.67374-11-alice.michael@intel.com> (raw)
In-Reply-To: <20170405115103.67374-1-alice.michael@intel.com>

From: Alexander Duyck <alexander.h.duyck@intel.com>

This patch is meant to improve the performance of the Rx path.
Specifically by using build_skb we have several distinct advantages.

In the case of small frames we were previously using a copy-break approach.
This means that we were allocating a page fragment to use for skb->head,
and were having to copy the packet into that region.  Both of those calls
are now avoided since we just build the skb around the data.

In the case of large frames the gains are much more significant.
Specifically we were having to allocate skb->head, and copy the headers as
before.  However in addition we were having to parse the header using
eth_get_headlen which could be quite expensive.  All of this is avoided by
building the frame around the data.  I have seen gains as high as 30% when
using VXLAN for instance due to just header pulling overhead.

Finally with all this in place it also sets us up to start looking at
enabling XDP.  Specifically we now have a path in which the data is in the
page and the frame is built around it.  So if we parse it with XDP before
we call build_skb we can take care of any necessary processing there.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Change-ID: Id4bdd618e94473d41f892417e5d8019639e421e3
---
 drivers/net/ethernet/intel/i40e/i40e_txrx.c   | 47 +++++++++++++++++++++++++++
 drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 47 +++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 4b31aec..b4a7bfc 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1816,6 +1816,51 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
 }
 
 /**
+ * i40e_build_skb - Build skb around an existing buffer
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @rx_buffer: rx buffer to pull data from
+ * @size: size of buffer to add to skb
+ *
+ * This function builds an skb around an existing Rx buffer, taking care
+ * to set up the skb correctly and avoid any memcpy overhead.
+ */
+static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
+				      struct i40e_rx_buffer *rx_buffer,
+				      unsigned int size)
+{
+	void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+#if (PAGE_SIZE < 8192)
+	unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+#else
+	unsigned int truesize = SKB_DATA_ALIGN(size);
+#endif
+	struct sk_buff *skb;
+
+	/* prefetch first cache line of first page */
+	prefetch(va);
+#if L1_CACHE_BYTES < 128
+	prefetch(va + L1_CACHE_BYTES);
+#endif
+	/* build an skb around the page buffer */
+	skb = build_skb(va - I40E_SKB_PAD, truesize);
+	if (unlikely(!skb))
+		return NULL;
+
+	/* update pointers within the skb to store the data */
+	skb_reserve(skb, I40E_SKB_PAD);
+	__skb_put(skb, size);
+
+	/* buffer is used by skb, update page_offset */
+#if (PAGE_SIZE < 8192)
+	rx_buffer->page_offset ^= truesize;
+#else
+	rx_buffer->page_offset += truesize;
+#endif
+
+	return skb;
+}
+
+/**
  * i40e_put_rx_buffer - Clean up used buffer and either recycle or free
  * @rx_ring: rx descriptor ring to transact packets on
  * @rx_buffer: rx buffer to pull data from
@@ -1939,6 +1984,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 		/* retrieve a buffer from the ring */
 		if (skb)
 			i40e_add_rx_frag(rx_ring, rx_buffer, skb, size);
+		else if (ring_uses_build_skb(rx_ring))
+			skb = i40e_build_skb(rx_ring, rx_buffer, size);
 		else
 			skb = i40e_construct_skb(rx_ring, rx_buffer, size);
 
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index d96f10a..7f1341c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -1177,6 +1177,51 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
 }
 
 /**
+ * i40e_build_skb - Build skb around an existing buffer
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @rx_buffer: rx buffer to pull data from
+ * @size: size of buffer to add to skb
+ *
+ * This function builds an skb around an existing Rx buffer, taking care
+ * to set up the skb correctly and avoid any memcpy overhead.
+ */
+static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
+				      struct i40e_rx_buffer *rx_buffer,
+				      unsigned int size)
+{
+	void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+#if (PAGE_SIZE < 8192)
+	unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+#else
+	unsigned int truesize = SKB_DATA_ALIGN(size);
+#endif
+	struct sk_buff *skb;
+
+	/* prefetch first cache line of first page */
+	prefetch(va);
+#if L1_CACHE_BYTES < 128
+	prefetch(va + L1_CACHE_BYTES);
+#endif
+	/* build an skb around the page buffer */
+	skb = build_skb(va - I40E_SKB_PAD, truesize);
+	if (unlikely(!skb))
+		return NULL;
+
+	/* update pointers within the skb to store the data */
+	skb_reserve(skb, I40E_SKB_PAD);
+	__skb_put(skb, size);
+
+	/* buffer is used by skb, update page_offset */
+#if (PAGE_SIZE < 8192)
+	rx_buffer->page_offset ^= truesize;
+#else
+	rx_buffer->page_offset += truesize;
+#endif
+
+	return skb;
+}
+
+/**
  * i40e_put_rx_buffer - Clean up used buffer and either recycle or free
  * @rx_ring: rx descriptor ring to transact packets on
  * @rx_buffer: rx buffer to pull data from
@@ -1295,6 +1340,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 		/* retrieve a buffer from the ring */
 		if (skb)
 			i40e_add_rx_frag(rx_ring, rx_buffer, skb, size);
+		else if (ring_uses_build_skb(rx_ring))
+			skb = i40e_build_skb(rx_ring, rx_buffer, size);
 		else
 			skb = i40e_construct_skb(rx_ring, rx_buffer, size);
 
-- 
2.9.3


  parent reply	other threads:[~2017-04-05 11:51 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-05 11:50 [Intel-wired-lan] [next S66 v2 01/11] i40e: update error message when trying to add invalid filters Alice Michael
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 02/11] i40e: Swap use of pf->flags and pf->hw_disabled_flags for ATR Eviction Alice Michael
2017-04-06 21:37   ` Bowers, AndrewX
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 03/11] i40e: Decrease the scope of rtnl lock Alice Michael
2017-04-06 22:05   ` Bowers, AndrewX
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 04/11] i40e: Simplify i40e_detect_recover_hung_queue logic Alice Michael
2017-04-06 21:39   ` Bowers, AndrewX
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 05/11] i40e: allow look-up of MAC address from Open Firmware or IDPROM Alice Michael
2017-04-06 21:42   ` Bowers, AndrewX
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 06/11] i40e: remove extraneous loop in i40e_vsi_wait_queues_disabled Alice Michael
2017-04-06 16:00   ` Shannon Nelson
2017-04-06 21:43   ` Bowers, AndrewX
2017-04-05 11:50 ` [Intel-wired-lan] [next S66 v2 07/11] i40e: remove I40E_FLAG_NEED_LINK_UPDATE Alice Michael
2017-04-06 21:44   ` Bowers, AndrewX
2017-04-05 11:51 ` [Intel-wired-lan] [next S66 v2 08/11] i40e: clean up historic deprecated flag definitions Alice Michael
2017-04-06 16:01   ` Shannon Nelson
2017-04-06 21:44   ` Bowers, AndrewX
2017-04-05 11:51 ` [Intel-wired-lan] [next S66 v2 09/11] i40e/i40evf: Add support for using order 1 pages with a 3K buffer Alice Michael
2017-04-06 21:49   ` Bowers, AndrewX
2017-04-05 11:51 ` [Intel-wired-lan] [next S66 v2 10/11] i40e/i40evf: Add support for padding start of frames Alice Michael
2017-04-06 21:50   ` Bowers, AndrewX
2017-04-05 11:51 ` Alice Michael [this message]
2017-04-06 22:02   ` [Intel-wired-lan] [next S66 v2 11/11] i40e/i40evf: Use build_skb to build frames Bowers, AndrewX
2017-04-06 21:33 ` [Intel-wired-lan] [next S66 v2 01/11] i40e: update error message when trying to add invalid filters Bowers, AndrewX

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170405115103.67374-11-alice.michael@intel.com \
    --to=alice.michael@intel.com \
    --cc=intel-wired-lan@osuosl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.