Netdev List
 help / color / mirror / Atom feed
* [PATCH RESEND v6 2/7] net: cpsw: Add missing return value
From: Markus Pargmann @ 2014-09-29  6:53 UTC (permalink / raw)
  To: David S. Miller
  Cc: Benoît Cousson, Tony Lindgren, Wolfram Sang, Steven Rostedt,
	Mugunthan V N, linux-omap, devicetree, linux-arm-kernel, netdev,
	kernel, Markus Pargmann
In-Reply-To: <1411973599-18908-1-git-send-email-mpa@pengutronix.de>

ret is set 0 at this point, so jumping to that error label would result
in a return value of 0. Set ret to -ENOMEM to return a proper error
value.

Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Reviewed-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/net/ethernet/ti/cpsw.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 999fb72688d2..f09b4639ad31 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2063,6 +2063,7 @@ static int cpsw_probe(struct platform_device *pdev)
 	priv->irq_enabled = true;
 	if (!priv->cpts) {
 		dev_err(&pdev->dev, "error allocating cpts\n");
+		ret = -ENOMEM;
 		goto clean_ndev_ret;
 	}
 
-- 
2.1.0


^ permalink raw reply related

* [PATCH RESEND v6 1/7] DT doc: net: cpsw mac-address is optional
From: Markus Pargmann @ 2014-09-29  6:53 UTC (permalink / raw)
  To: David S. Miller
  Cc: Benoît Cousson, Tony Lindgren, Wolfram Sang, Steven Rostedt,
	Mugunthan V N, linux-omap, devicetree, linux-arm-kernel, netdev,
	kernel, Markus Pargmann
In-Reply-To: <1411973599-18908-1-git-send-email-mpa@pengutronix.de>

mac-address is an optional property. If no mac-address is set, a random
mac-address will be generated.

Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Reviewed-by: Wolfram Sang <wsa@the-dreams.de>
---
 Documentation/devicetree/bindings/net/cpsw.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index ae2b8b7f9c38..107caf174a0e 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -29,10 +29,10 @@ Slave Properties:
 Required properties:
 - phy_id		: Specifies slave phy id
 - phy-mode		: See ethernet.txt file in the same directory
-- mac-address		: See ethernet.txt file in the same directory
 
 Optional properties:
 - dual_emac_res_vlan	: Specifies VID to be used to segregate the ports
+- mac-address		: See ethernet.txt file in the same directory
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
-- 
2.1.0


^ permalink raw reply related

* [PATCH RESEND v6 0/7] net: cpsw: Support for am335x chip MACIDs
From: Markus Pargmann @ 2014-09-29  6:53 UTC (permalink / raw)
  To: David S. Miller
  Cc: Benoît Cousson, Tony Lindgren, Wolfram Sang, Steven Rostedt,
	Mugunthan V N, linux-omap, devicetree, linux-arm-kernel, netdev,
	kernel, Markus Pargmann

Hi,

Another resend of this series to add the netdev list.

This series adds support to the cpsw driver to read the MACIDs of the am335x
chip and use them as fallback. These addresses are only used if there are no
mac addresses in the devicetree, for example set by a bootloader.

Best regards,

Markus


Markus Pargmann (7):
  DT doc: net: cpsw mac-address is optional
  net: cpsw: Add missing return value
  net: cpsw: header, Add missing include
  net: cpsw: Replace pr_err by dev_err
  net: cpsw: Add am33xx MACID readout
  am33xx: define syscon control module device node
  arm: dts: am33xx, Add syscon phandle to cpsw node

 Documentation/devicetree/bindings/net/cpsw.txt |  6 +++-
 arch/arm/boot/dts/am33xx.dtsi                  |  6 ++++
 drivers/net/ethernet/ti/Kconfig                |  2 ++
 drivers/net/ethernet/ti/cpsw.c                 | 45 ++++++++++++++++++++++++--
 drivers/net/ethernet/ti/cpsw.h                 |  1 +
 5 files changed, 57 insertions(+), 3 deletions(-)

-- 
2.1.0


^ permalink raw reply

* Re: [PATCH] staging: r8821ae: Remove driver from staging
From: Greg KH @ 2014-09-29  6:17 UTC (permalink / raw)
  To: Larry Finger; +Cc: devel, netdev
In-Reply-To: <1411954791-23779-1-git-send-email-Larry.Finger@lwfinger.net>

On Sun, Sep 28, 2014 at 08:39:51PM -0500, Larry Finger wrote:
> A new version of this driver has been merged into the wireless-testing tree
> as commit 21e4b0726dc671c423e2dc9a85364716219c4502. It is both possible and
> desirable to delete the staging version to avoid build errors in linux-next.
> 
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> ---
> 
> Greg,
> 
> This removal patch was generated after commit 368c75b98bdfdfad54e7f165016819ef344e3587.
> It should apply to your tree unless further modifications have been made to
> the staging driver.

Wonderful!

So, this should be done for 3.18-rc1, right?  Or does wireless-testing
take longer to get to Linus than that?

greg k-h

^ permalink raw reply

* Re: Silicom bypass driver promote from staging
From: gregkh @ 2014-09-29  1:10 UTC (permalink / raw)
  To: David Hendel
  Cc: Francois Romieu, netdev@vger.kernel.org, arnd@arndb.de,
	Anna Lukin
In-Reply-To: <3BFAEADE799AF145974162DF00E013AF018F8C5848@exchange2010.silicom.local>

On Sat, Sep 27, 2014 at 06:54:22AM +0000, David Hendel wrote:
> This is what we changed in updated patch:
> 1. Avoid redefining BIT and MII .
> 2. Fixing returning with spinlock held
> 3. Remove BP_SYNC_FLAG
> 4. Use void __iomem * instead of long long in ioremap return
> 5. Cleanup with checkpatch.pl

You sent an attached, compressed, set of patches, we can't do much at
all with them, sorry.  Please attach them in the proper format as
described in Documentation/SubmittingPatches.

thanks,

greg k-h

^ permalink raw reply

* Re: Regarding bug 82471
From: Michal Kubecek @ 2014-09-29  5:51 UTC (permalink / raw)
  To: netdev; +Cc: Laurent CARON
In-Reply-To: <542595D6.6040904@lncsa.com>

On Fri, Sep 26, 2014 at 06:35:34PM +0200, Laurent CARON wrote:
> Hi,
> 
> I've been biten by :
> https://bugzilla.kernel.org/show_bug.cgi?id=82471 today.
> 
> I tried various kernels from 3.2.0 to 3.16.3
> 
> The last unaffected kernel according to my tests is 3.14 (didn't yet
> try 3.15).
> 
> Please see logs when (on 3.16.2)
> 1/ using iptables
> 2/ having some traffic (even light) going through
> 
> http://pastebin.com/JWkFu2w2
> 
> My network config is the following:
> 
> a bond interface consisting of 2 10Gb ports (intel ixgbe / X520-SR2)
> on top of which I use 2 vlans.

I don't see why it would affect ixgbe adapters which support Tx VLAN
offloading (and with which the original patch was tested) but the
symptoms look very much like those fixed by commit db115037bb57 ("net:
fix checksum features handling in netif_skb_features()"). Could you
please test with 3.17-rc5 or later?

                                                      Michal Kubeček

^ permalink raw reply

* Re: tc rsvp filter show broke
From: John Fastabend @ 2014-09-29  5:34 UTC (permalink / raw)
  To: Cong Wang; +Cc: Jamal Hadi Salim, John Fastabend, netdev
In-Reply-To: <CAM_iQpVF8bHN8WNNH5kHyanj+fLE6kbsFOwQA+t_z_=UK_v=+w@mail.gmail.com>

On 09/28/2014 06:40 PM, Cong Wang wrote:
> On Sun, Sep 28, 2014 at 10:50 AM, John Fastabend
> <john.fastabend@gmail.com> wrote:
>>
>>
>> I don't think we need this change, (or perhaps it needs to be a bit
>> more complete if something is missing) take a look a
>> tcf_exts_validate(), notice the policer is added to act->list so the
>> if block in dump() work out,
>
> I thought it's clear that act->list is correct here. :)
>
> I was thinking the dump logic was wrong, but you are right that
> it should match the logic in validate. Actually the bug is we forgot
> to copy exts->type, I am going to submit a patch below:
>
> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
> index 77147c8..aad6a67 100644
> --- a/net/sched/cls_api.c
> +++ b/net/sched/cls_api.c
> @@ -549,6 +549,7 @@ void tcf_exts_change(struct tcf_proto *tp, struct
> tcf_exts *dst,
>    tcf_tree_lock(tp);
>    list_splice_init(&dst->actions, &tmp);
>    list_splice(&src->actions, &dst->actions);
> + dst->type = src->type;
>    tcf_tree_unlock(tp);
>    tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
>   #endif
>

Yep it does seem to be missing...

Although with the latest code can we just drop tcf_exts_change()
and call tcf_exts_validate() directly. I'll check in the morning
but a quick glance makes me think it should be OK and simplifies
things.

.John

-- 
John Fastabend         Intel Corporation

^ permalink raw reply

* [PATCH v2 net-next] net: reorganize sk_buff for faster __copy_skb_header()
From: Eric Dumazet @ 2014-09-29  5:18 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Amir Vadai, John Fastabend, Jesper Dangaard Brouer
In-Reply-To: <1411680004.16953.57.camel@edumazet-glaptop2.roam.corp.google.com>

From: Eric Dumazet <edumazet@google.com>

With proliferation of bit fields in sk_buff, __copy_skb_header() became
quite expensive, showing as the most expensive function in a GSO
workload.

__copy_skb_header() performance is also critical for non GSO TCP
operations, as it is used from skb_clone()

This patch carefully moves all the fields that were not copied in a
separate zone : cloned, nohdr, fclone, peeked, head_frag, xmit_more

Then I moved all other fields and all other copied fields in a section
delimited by headers_start[0]/headers_end[0] section so that we
can use a single memcpy() call, inlined by compiler using long
word load/stores.

I also tried to make all copies in the natural orders of sk_buff,
to help hardware prefetching.

I made sure sk_buff size did not change.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
v2 : added back ipvs_property, oops ;)

 include/linux/skbuff.h |  133 +++++++++++++++++++++------------------
 net/core/skbuff.c      |   80 ++++++++++++-----------
 2 files changed, 113 insertions(+), 100 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 8eaa62400fca..b6cced304b26 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -527,27 +527,41 @@ struct sk_buff {
 	char			cb[48] __aligned(8);
 
 	unsigned long		_skb_refdst;
+	void			(*destructor)(struct sk_buff *skb);
 #ifdef CONFIG_XFRM
 	struct	sec_path	*sp;
 #endif
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+	struct nf_conntrack	*nfct;
+#endif
+#ifdef CONFIG_BRIDGE_NETFILTER
+	struct nf_bridge_info	*nf_bridge;
+#endif
 	unsigned int		len,
 				data_len;
 	__u16			mac_len,
 				hdr_len;
-	union {
-		__wsum		csum;
-		struct {
-			__u16	csum_start;
-			__u16	csum_offset;
-		};
-	};
-	__u32			priority;
+
+	/* Following fields are _not_ copied in __copy_skb_header()
+	 * Note that queue_mapping is here mostly to fill a hole.
+	 */
 	kmemcheck_bitfield_begin(flags1);
-	__u8			ignore_df:1,
-				cloned:1,
-				ip_summed:2,
+	__u16			queue_mapping;
+	__u8			cloned:1,
 				nohdr:1,
-				nfctinfo:3;
+				fclone:2,
+				peeked:1,
+				head_frag:1,
+				xmit_more:1;
+	/* one bit hole */
+	kmemcheck_bitfield_end(flags1);
+
+
+
+	/* fields enclosed in headers_start/headers_end are copied
+	 * using a single memcpy() in __copy_skb_header()
+	 */
+	__u32			headers_start[0];
 
 /* if you move pkt_type around you also must adapt those constants */
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -558,58 +572,53 @@ struct sk_buff {
 #define PKT_TYPE_OFFSET()	offsetof(struct sk_buff, __pkt_type_offset)
 
 	__u8			__pkt_type_offset[0];
-	__u8			pkt_type:3,
-				fclone:2,
-				ipvs_property:1,
-				peeked:1,
-				nf_trace:1;
-	kmemcheck_bitfield_end(flags1);
-	__be16			protocol;
-
-	void			(*destructor)(struct sk_buff *skb);
-#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-	struct nf_conntrack	*nfct;
-#endif
-#ifdef CONFIG_BRIDGE_NETFILTER
-	struct nf_bridge_info	*nf_bridge;
-#endif
-
-	int			skb_iif;
-
-	__u32			hash;
-
-	__be16			vlan_proto;
-	__u16			vlan_tci;
-
-#ifdef CONFIG_NET_SCHED
-	__u16			tc_index;	/* traffic control index */
-#ifdef CONFIG_NET_CLS_ACT
-	__u16			tc_verd;	/* traffic control verdict */
-#endif
-#endif
-
-	__u16			queue_mapping;
-	kmemcheck_bitfield_begin(flags2);
-	__u8			xmit_more:1;
-#ifdef CONFIG_IPV6_NDISC_NODETYPE
-	__u8			ndisc_nodetype:2;
-#endif
+	__u8			pkt_type:3;
 	__u8			pfmemalloc:1;
+	__u8			ignore_df:1;
+	__u8			nfctinfo:3;
+
+	__u8			nf_trace:1;
+	__u8			ip_summed:2;
 	__u8			ooo_okay:1;
 	__u8			l4_hash:1;
 	__u8			sw_hash:1;
 	__u8			wifi_acked_valid:1;
 	__u8			wifi_acked:1;
+
 	__u8			no_fcs:1;
-	__u8			head_frag:1;
 	/* Indicates the inner headers are valid in the skbuff. */
 	__u8			encapsulation:1;
 	__u8			encap_hdr_csum:1;
 	__u8			csum_valid:1;
 	__u8			csum_complete_sw:1;
-	/* 1/3 bit hole (depending on ndisc_nodetype presence) */
-	kmemcheck_bitfield_end(flags2);
+	__u8			csum_level:2;
+	__u8			csum_bad:1;
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
+	__u8			ndisc_nodetype:2;
+#endif
+	__u8			ipvs_property:1;
+	/* 5 or 7 bit hole */
+
+#ifdef CONFIG_NET_SCHED
+	__u16			tc_index;	/* traffic control index */
+#ifdef CONFIG_NET_CLS_ACT
+	__u16			tc_verd;	/* traffic control verdict */
+#endif
+#endif
+
+	union {
+		__wsum		csum;
+		struct {
+			__u16	csum_start;
+			__u16	csum_offset;
+		};
+	};
+	__u32			priority;
+	int			skb_iif;
+	__u32			hash;
+	__be16			vlan_proto;
+	__u16			vlan_tci;
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
 	union {
 		unsigned int	napi_id;
@@ -625,19 +634,18 @@ struct sk_buff {
 		__u32		reserved_tailroom;
 	};
 
-	kmemcheck_bitfield_begin(flags3);
-	__u8			csum_level:2;
-	__u8			csum_bad:1;
-	/* 13 bit hole */
-	kmemcheck_bitfield_end(flags3);
-
 	__be16			inner_protocol;
 	__u16			inner_transport_header;
 	__u16			inner_network_header;
 	__u16			inner_mac_header;
+
+	__be16			protocol;
 	__u16			transport_header;
 	__u16			network_header;
 	__u16			mac_header;
+
+	__u32			headers_end[0];
+
 	/* These elements must be at the end, see alloc_skb() for details.  */
 	sk_buff_data_t		tail;
 	sk_buff_data_t		end;
@@ -3040,19 +3048,22 @@ static inline void nf_reset_trace(struct sk_buff *skb)
 }
 
 /* Note: This doesn't put any conntrack and bridge info in dst. */
-static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
+static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src,
+			     bool copy)
 {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 	dst->nfct = src->nfct;
 	nf_conntrack_get(src->nfct);
-	dst->nfctinfo = src->nfctinfo;
+	if (copy)
+		dst->nfctinfo = src->nfctinfo;
 #endif
 #ifdef CONFIG_BRIDGE_NETFILTER
 	dst->nf_bridge  = src->nf_bridge;
 	nf_bridge_get(src->nf_bridge);
 #endif
 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
-	dst->nf_trace = src->nf_trace;
+	if (copy)
+		dst->nf_trace = src->nf_trace;
 #endif
 }
 
@@ -3064,7 +3075,7 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
 #ifdef CONFIG_BRIDGE_NETFILTER
 	nf_bridge_put(dst->nf_bridge);
 #endif
-	__nf_copy(dst, src);
+	__nf_copy(dst, src, true);
 }
 
 #ifdef CONFIG_NETWORK_SECMARK
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d4fdc649112c..4be570a4ab21 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -261,7 +261,6 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 		atomic_t *fclone_ref = (atomic_t *) (child + 1);
 
 		kmemcheck_annotate_bitfield(child, flags1);
-		kmemcheck_annotate_bitfield(child, flags2);
 		skb->fclone = SKB_FCLONE_ORIG;
 		atomic_set(fclone_ref, 1);
 
@@ -675,57 +674,61 @@ void consume_skb(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(consume_skb);
 
+/* Make sure a field is enclosed inside headers_start/headers_end section */
+#define CHECK_SKB_FIELD(field) \
+	BUILD_BUG_ON(offsetof(struct sk_buff, field) <		\
+		     offsetof(struct sk_buff, headers_start));	\
+	BUILD_BUG_ON(offsetof(struct sk_buff, field) >		\
+		     offsetof(struct sk_buff, headers_end));	\
+
 static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 {
 	new->tstamp		= old->tstamp;
+	/* We do not copy old->sk */
 	new->dev		= old->dev;
-	new->transport_header	= old->transport_header;
-	new->network_header	= old->network_header;
-	new->mac_header		= old->mac_header;
-	new->inner_protocol	= old->inner_protocol;
-	new->inner_transport_header = old->inner_transport_header;
-	new->inner_network_header = old->inner_network_header;
-	new->inner_mac_header = old->inner_mac_header;
+	memcpy(new->cb, old->cb, sizeof(old->cb));
 	skb_dst_copy(new, old);
-	skb_copy_hash(new, old);
-	new->ooo_okay		= old->ooo_okay;
-	new->no_fcs		= old->no_fcs;
-	new->encapsulation	= old->encapsulation;
-	new->encap_hdr_csum	= old->encap_hdr_csum;
-	new->csum_valid		= old->csum_valid;
-	new->csum_complete_sw	= old->csum_complete_sw;
 #ifdef CONFIG_XFRM
 	new->sp			= secpath_get(old->sp);
 #endif
-	memcpy(new->cb, old->cb, sizeof(old->cb));
-	new->csum		= old->csum;
-	new->ignore_df		= old->ignore_df;
-	new->pkt_type		= old->pkt_type;
-	new->ip_summed		= old->ip_summed;
-	skb_copy_queue_mapping(new, old);
-	new->priority		= old->priority;
-#if IS_ENABLED(CONFIG_IP_VS)
-	new->ipvs_property	= old->ipvs_property;
+	__nf_copy(new, old, false);
+
+	/* Note : this field could be in headers_start/headers_end section
+	 * It is not yet because we do not want to have a 16 bit hole
+	 */
+	new->queue_mapping = old->queue_mapping;
+
+	memcpy(&new->headers_start, &old->headers_start,
+	       offsetof(struct sk_buff, headers_end) -
+	       offsetof(struct sk_buff, headers_start));
+	CHECK_SKB_FIELD(protocol);
+	CHECK_SKB_FIELD(csum);
+	CHECK_SKB_FIELD(hash);
+	CHECK_SKB_FIELD(priority);
+	CHECK_SKB_FIELD(skb_iif);
+	CHECK_SKB_FIELD(vlan_proto);
+	CHECK_SKB_FIELD(vlan_tci);
+	CHECK_SKB_FIELD(transport_header);
+	CHECK_SKB_FIELD(network_header);
+	CHECK_SKB_FIELD(mac_header);
+	CHECK_SKB_FIELD(inner_protocol);
+	CHECK_SKB_FIELD(inner_transport_header);
+	CHECK_SKB_FIELD(inner_network_header);
+	CHECK_SKB_FIELD(inner_mac_header);
+	CHECK_SKB_FIELD(mark);
+#ifdef CONFIG_NETWORK_SECMARK
+	CHECK_SKB_FIELD(secmark);
+#endif
+#ifdef CONFIG_NET_RX_BUSY_POLL
+	CHECK_SKB_FIELD(napi_id);
 #endif
-	new->pfmemalloc		= old->pfmemalloc;
-	new->protocol		= old->protocol;
-	new->mark		= old->mark;
-	new->skb_iif		= old->skb_iif;
-	__nf_copy(new, old);
 #ifdef CONFIG_NET_SCHED
-	new->tc_index		= old->tc_index;
+	CHECK_SKB_FIELD(tc_index);
 #ifdef CONFIG_NET_CLS_ACT
-	new->tc_verd		= old->tc_verd;
+	CHECK_SKB_FIELD(tc_verd);
 #endif
 #endif
-	new->vlan_proto		= old->vlan_proto;
-	new->vlan_tci		= old->vlan_tci;
-
-	skb_copy_secmark(new, old);
 
-#ifdef CONFIG_NET_RX_BUSY_POLL
-	new->napi_id	= old->napi_id;
-#endif
 }
 
 /*
@@ -876,7 +879,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
 			return NULL;
 
 		kmemcheck_annotate_bitfield(n, flags1);
-		kmemcheck_annotate_bitfield(n, flags2);
 		n->fclone = SKB_FCLONE_UNAVAILABLE;
 	}
 

^ permalink raw reply related

* [PATCH net 1/1 V2] hyperv: Fix a bug in netvsc_start_xmit()
From: K. Y. Srinivasan @ 2014-09-29  5:16 UTC (permalink / raw)
  To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang

After the packet is successfully sent, we should not touch the skb 
as it may have been freed. This patch is based on the work done by 
Long Li <longli@microsoft.com>.

In this version of the patch I have fixed issues pointed out by David.
David, please queue this up for stable.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Tested-by: Long Li <longli@microsoft.com>
---
 drivers/net/hyperv/netvsc_drv.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index a9c5eaa..0fcb5e7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -387,6 +387,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 	int  hdr_offset;
 	u32 net_trans_info;
 	u32 hash;
+	u32 skb_length = skb->len;
 
 
 	/* We will atmost need two pages to describe the rndis
@@ -562,7 +563,7 @@ do_send:
 
 drop:
 	if (ret == 0) {
-		net->stats.tx_bytes += skb->len;
+		net->stats.tx_bytes += skb_length;
 		net->stats.tx_packets++;
 	} else {
 		kfree(packet);
-- 
1.7.4.1

^ permalink raw reply related

* Re: [Xen-devel] [PATCH] xen/xenbus: Use 'void' instead of 'int' for the return of xenbus_switch_state()
From: Juergen Gross @ 2014-09-29  5:09 UTC (permalink / raw)
  To: Chen Gang, David Vrabel, konrad.wilk, ian.campbell, wei.liu2,
	boris.ostrovsky, bhelgaas, yongjun_wei, mukesh.rathor
  Cc: xen-devel, linux-pci, linux-kernel@vger.kernel.org, linux-scsi,
	netdev@vger.kernel.org
In-Reply-To: <5425961A.5000604@gmail.com>

On 09/26/2014 06:36 PM, Chen Gang wrote:
> When xenbus_switch_state() fails, it will call xenbus_switch_fatal()
> internally, so need not return any status value, then use 'void' instead
> of 'int' for xenbus_switch_state() and __xenbus_switch_state().
>
> Also need be sure that all callers which check the return value must let
> 'err' be 0.
>
> And also need change the related comments for xenbus_switch_state().
>
> Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>

Acked-by: Juergen Gross <jgross@suse.com>

> ---
>   drivers/block/xen-blkback/xenbus.c |  9 ++-------
>   drivers/net/xen-netback/xenbus.c   |  5 +----
>   drivers/pci/xen-pcifront.c         | 15 ++++++---------
>   drivers/xen/xen-pciback/xenbus.c   | 21 ++++-----------------
>   drivers/xen/xen-scsiback.c         |  5 +----
>   drivers/xen/xenbus/xenbus_client.c | 16 ++++++++--------
>   include/xen/xenbus.h               |  3 ++-
>   7 files changed, 24 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
> index 3a8b810..fdcc584 100644
> --- a/drivers/block/xen-blkback/xenbus.c
> +++ b/drivers/block/xen-blkback/xenbus.c
> @@ -587,9 +587,7 @@ static int xen_blkbk_probe(struct xenbus_device *dev,
>   	if (err)
>   		goto fail;
>
> -	err = xenbus_switch_state(dev, XenbusStateInitWait);
> -	if (err)
> -		goto fail;
> +	xenbus_switch_state(dev, XenbusStateInitWait);
>
>   	return 0;
>
> @@ -837,10 +835,7 @@ again:
>   	if (err)
>   		xenbus_dev_fatal(dev, err, "ending transaction");
>
> -	err = xenbus_switch_state(dev, XenbusStateConnected);
> -	if (err)
> -		xenbus_dev_fatal(dev, err, "%s: switching to Connected state",
> -				 dev->nodename);
> +	xenbus_switch_state(dev, XenbusStateConnected);
>
>   	return;
>    abort:
> diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
> index 9c47b89..b5c3d47 100644
> --- a/drivers/net/xen-netback/xenbus.c
> +++ b/drivers/net/xen-netback/xenbus.c
> @@ -337,10 +337,7 @@ static int netback_probe(struct xenbus_device *dev,
>   	if (err)
>   		pr_debug("Error writing multi-queue-max-queues\n");
>
> -	err = xenbus_switch_state(dev, XenbusStateInitWait);
> -	if (err)
> -		goto fail;
> -
> +	xenbus_switch_state(dev, XenbusStateInitWait);
>   	be->state = XenbusStateInitWait;
>
>   	/* This kicks hotplug scripts, so do it immediately. */
> diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
> index 53df39a..c1d73b7 100644
> --- a/drivers/pci/xen-pcifront.c
> +++ b/drivers/pci/xen-pcifront.c
> @@ -901,18 +901,16 @@ static int pcifront_try_connect(struct pcifront_device *pdev)
>   		}
>   	}
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
> -
> +	xenbus_switch_state(pdev->xdev, XenbusStateConnected);
> +	return 0;
>   out:
>   	return err;
>   }
>
>   static int pcifront_try_disconnect(struct pcifront_device *pdev)
>   {
> -	int err = 0;
>   	enum xenbus_state prev_state;
>
> -
>   	prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
>
>   	if (prev_state >= XenbusStateClosing)
> @@ -923,11 +921,10 @@ static int pcifront_try_disconnect(struct pcifront_device *pdev)
>   		pcifront_disconnect(pdev);
>   	}
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateClosed);
> +	xenbus_switch_state(pdev->xdev, XenbusStateClosed);
>
>   out:
> -
> -	return err;
> +	return 0;
>   }
>
>   static int pcifront_attach_devices(struct pcifront_device *pdev)
> @@ -1060,8 +1057,8 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
>   			domain, bus, slot, func);
>   	}
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring);
> -
> +	xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring);
> +	return 0;
>   out:
>   	return err;
>   }
> diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
> index c214daa..630a215 100644
> --- a/drivers/xen/xen-pciback/xenbus.c
> +++ b/drivers/xen/xen-pciback/xenbus.c
> @@ -184,10 +184,7 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
>
>   	dev_dbg(&pdev->xdev->dev, "Connecting...\n");
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
> -	if (err)
> -		xenbus_dev_fatal(pdev->xdev, err,
> -				 "Error switching to connected state!");
> +	xenbus_switch_state(pdev->xdev, XenbusStateConnected);
>
>   	dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
>   out:
> @@ -500,12 +497,7 @@ static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev)
>   		}
>   	}
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
> -	if (err) {
> -		xenbus_dev_fatal(pdev->xdev, err,
> -				 "Error switching to reconfigured state!");
> -		goto out;
> -	}
> +	xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
>
>   out:
>   	mutex_unlock(&pdev->dev_lock);
> @@ -640,10 +632,7 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
>   		goto out;
>   	}
>
> -	err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
> -	if (err)
> -		xenbus_dev_fatal(pdev->xdev, err,
> -				 "Error switching to initialised state!");
> +	xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
>
>   out:
>   	mutex_unlock(&pdev->dev_lock);
> @@ -683,9 +672,7 @@ static int xen_pcibk_xenbus_probe(struct xenbus_device *dev,
>   	}
>
>   	/* wait for xend to configure us */
> -	err = xenbus_switch_state(dev, XenbusStateInitWait);
> -	if (err)
> -		goto out;
> +	xenbus_switch_state(dev, XenbusStateInitWait);
>
>   	/* watch the backend node for backend configuration information */
>   	err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
> diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
> index ad11258..847bc9c 100644
> --- a/drivers/xen/xen-scsiback.c
> +++ b/drivers/xen/xen-scsiback.c
> @@ -1225,10 +1225,7 @@ static int scsiback_probe(struct xenbus_device *dev,
>   	if (err)
>   		xenbus_dev_error(dev, err, "writing feature-sg-grant");
>
> -	err = xenbus_switch_state(dev, XenbusStateInitWait);
> -	if (err)
> -		goto fail;
> -
> +	xenbus_switch_state(dev, XenbusStateInitWait);
>   	return 0;
>
>   fail:
> diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
> index ca74410..e2bcd1d 100644
> --- a/drivers/xen/xenbus/xenbus_client.c
> +++ b/drivers/xen/xenbus/xenbus_client.c
> @@ -166,7 +166,7 @@ EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
>   static void xenbus_switch_fatal(struct xenbus_device *, int, int,
>   				const char *, ...);
>
> -static int
> +static void
>   __xenbus_switch_state(struct xenbus_device *dev,
>   		      enum xenbus_state state, int depth)
>   {
> @@ -188,7 +188,7 @@ __xenbus_switch_state(struct xenbus_device *dev,
>   	int err, abort;
>
>   	if (state == dev->state)
> -		return 0;
> +		return;
>
>   again:
>   	abort = 1;
> @@ -196,7 +196,7 @@ again:
>   	err = xenbus_transaction_start(&xbt);
>   	if (err) {
>   		xenbus_switch_fatal(dev, depth, err, "starting transaction");
> -		return 0;
> +		return;
>   	}
>
>   	err = xenbus_scanf(xbt, dev->nodename, "state", "%d", &current_state);
> @@ -219,7 +219,7 @@ abort:
>   	} else
>   		dev->state = state;
>
> -	return 0;
> +	return;
>   }
>
>   /**
> @@ -228,12 +228,12 @@ abort:
>    * @state: new state
>    *
>    * Advertise in the store a change of the given driver to the given new_state.
> - * Return 0 on success, or -errno on error.  On error, the device will switch
> - * to XenbusStateClosing, and the error will be saved in the store.
> + * When failure occurs, it will call xenbus_switch_fatal() internally, so need
> + * not return value to notify upper caller.
>    */
> -int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
> +void xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
>   {
> -	return __xenbus_switch_state(dev, state, 0);
> +	__xenbus_switch_state(dev, state, 0);
>   }
>
>   EXPORT_SYMBOL_GPL(xenbus_switch_state);
> diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
> index 0324c6d..587c53d 100644
> --- a/include/xen/xenbus.h
> +++ b/include/xen/xenbus.h
> @@ -195,7 +195,8 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
>   					  const char **, unsigned int),
>   			 const char *pathfmt, ...);
>
> -int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
> +void xenbus_switch_state(struct xenbus_device *dev,
> +			 enum xenbus_state new_state);
>   int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
>   int xenbus_map_ring_valloc(struct xenbus_device *dev,
>   			   int gnt_ref, void **vaddr);
>

^ permalink raw reply

* Re: [PATCH net-next] mlx4: optimize xmit path
From: Alexei Starovoitov @ 2014-09-29  5:08 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Or Gerlitz, David S. Miller, Jesper Dangaard Brouer, Eric Dumazet,
	John Fastabend, Linux Netdev List, Amir Vadai, Or Gerlitz
In-Reply-To: <1411957331.15768.91.camel@edumazet-glaptop2.roam.corp.google.com>

On Sun, Sep 28, 2014 at 7:22 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Sun, 2014-09-28 at 13:49 -0700, Alexei Starovoitov wrote:
>
>> I see. So xmit_more=true overrides blueflame=on settings.
>
> Yes, unless Mellanox folks have another way.
>
>> I wonder what is the performance difference bf=on vs bf=off,
>> also whether a burst of N packets via bf is slower than
>> burst via queue+doorbell.
>> Some fun exploration for driver experts :)
>
> Prior situation : bf=on : ~4.5 Mpps
>
> queue + doorbell every 8 packets : ~8 Mpps, up to 10Mpps if tuned
> properly.
>
> Rewritten mlx4 tx path and no burst (bf=on doorbell at every packet) :
> 5.3 Mpps
>
> With the full mlx4 patch and burst = 8 -> 14.9 Mpps
>
> This is on a 40Gb NIC, with 108 bytes packets.
>
> (Using <= 104 bytes packets actually gives lower pps because of
> 'inlining' done by the driver :  8 Mpps for PKTSIZE=40 )
>
> # cat /sys/module/mlx4_en/parameters/inline_thold
> 104

nice. Understood. All makes sense.
I'm not sure whether it's worth to break it down
into small pieces. Imo it's good to go as-is.
'inlining' tuning can come later.
Thanks again!

^ permalink raw reply

* Re: [PATCH net-next] net: reorganize sk_buff for faster __copy_skb_header()
From: Eric Dumazet @ 2014-09-29  4:57 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, amirv, john.r.fastabend, brouer
In-Reply-To: <20140929.000611.1697245481977504922.davem@davemloft.net>

On Mon, 2014-09-29 at 00:06 -0400, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Sun, 28 Sep 2014 17:37:59 -0400 (EDT)
> 
> > Applied, thanks!
> 
> Eric, I had to revert.  Please enable IPVS in your build tests.
> 
> net/ipv4/ip_output.c: In function ‘ip_copy_metadata’:
> net/ipv4/ip_output.c:470:4: error: ‘struct sk_buff’ has no member named ‘ipvs_property’
>   to->ipvs_property = from->ipvs_property;
>     ^
> net/ipv4/ip_output.c:470:26: error: ‘struct sk_buff’ has no member named ‘ipvs_property’
>   to->ipvs_property = from->ipvs_property;

Ah sorry, will send a v2.

Thanks

^ permalink raw reply

* Re: [PATCH net-next v3 0/5] net: tcp: DCTCP congestion control algorithm
From: David Miller @ 2014-09-29  4:25 UTC (permalink / raw)
  To: dborkman
  Cc: hagen, lars, eric.dumazet, fontana, hannes, stephen, glenn.judd,
	fw, netdev
In-Reply-To: <1411763856-14230-1-git-send-email-dborkman@redhat.com>

From: Daniel Borkmann <dborkman@redhat.com>
Date: Fri, 26 Sep 2014 22:37:31 +0200

> This patch series adds support for the DataCenter TCP (DCTCP) congestion
> control algorithm. Please see individual patches for the details.

Series applied, thanks Daniel.

^ permalink raw reply

* Re: [PATCH V3 0/2] add Qualcomm QCA7000 ethernet driver
From: David Miller @ 2014-09-29  4:24 UTC (permalink / raw)
  To: stefan.wahren
  Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak,
	f.fainelli, netdev, devicetree
In-Reply-To: <1411770081-20995-1-git-send-email-stefan.wahren@i2se.com>

From: Stefan Wahren <stefan.wahren@i2se.com>
Date: Fri, 26 Sep 2014 22:21:19 +0000

> This patch series adds support for the Qualcomm QCA7000 Homeplug GreenPHY.
> The QCA7000 is serial-to-powerline bridge with two interfaces: UART and SPI.
> These patches handles only the last one, with an Ethernet over SPI protocol
> driver.

Applied to net-next, thanks.

^ permalink raw reply

* [PATCH v2 net-next] mlx4: optimize xmit path
From: Eric Dumazet @ 2014-09-29  4:19 UTC (permalink / raw)
  To: Or Gerlitz
  Cc: Alexei Starovoitov, David S. Miller, Jesper Dangaard Brouer,
	Eric Dumazet, John Fastabend, Linux Netdev List, Amir Vadai,
	Or Gerlitz
In-Reply-To: <1411858593.15768.51.camel@edumazet-glaptop2.roam.corp.google.com>

From: Eric Dumazet <edumazet@google.com>

First I implemented skb->xmit_more support, and pktgen throughput
went from ~5Mpps to ~10Mpps.

Then, looking closely at this driver I found false sharing problems that
should be addressed by this patch, as my pktgen now reaches 14.7 Mpps
on a single TX queue, with a burst factor of 8.

So this patch in a whole permits to improve raw performance on a single
TX queue from about 5 Mpps to 14.9 Mpps.

Note that if packets are below the inline_thold threshold (104 bytes),
driver copies packets content into tx descriptor, and throughput
is lowered to ~7.5 Mpps :
->      We might reconsider inline strategy in a followup patch.

I could split this patch into multiple components, but I prefer not
spend days on this work.

Lets instead list all changes I did :

1) align struct mlx4_en_tx_info to a cache line

2) add frag0_dma/frag0_byte_count into mlx4_en_tx_info to avoid a cache
   line miss in TX completion for frames having one dma element.
   (We avoid reading back the tx descriptor)
   Note this could be extended to 2/3 dma elements later,
   as we have free room in mlx4_en_tx_info

3) reorganize struct mlx4_en_tx_ring to have 
   3.1 - One cache line containing last_nr_txbb & cons & wake_queue,
     used by tx completion.
   3.2 - One cache line containing fields dirtied by mlx4_en_xmit()  
   3.3 - Following part is read mostly and shared by cpus.

4) struct mlx4_bf @offset field reduced to unsigned int to save space
 
5) doorbell_qpn is stored in the cpu_to_be32() way to avoid bswap() in
   fast path.

6) mdev->mr.key stored in ring->mr_key to also avoid bswap() and access
   to cold cache line.

7) mlx4_en_free_tx_desc() no longer accesses skb_shinfo(). We use a new
   nr_maps fields in mlx4_en_tx_info to avoid 2 or 3 cache misses.

8) mlx4_en_free_tx_desc() uses a prefetchw(&skb->users) to speed up
   consume_skb()

9) mlx4_en_process_tx_cq() carefully fetches and writes
   ring->last_nr_txbb & ring->cons only one time to avoid false sharing

10) mlx4_en_xmit() reads ring->cons once, and ahead of time to avoid
    stalls.

11) prefetchw(&ring->tx_queue->dql) to speed up BQL update

12) properly clears tx_info->ts_requested :
    This field was never cleared.

13) remove false sharing on prot_stats.tso_packets 

14) reorganize code to call is_inline() once, so compiler can inline it.

15) rename @i variable to @i_frag to avoid confusion, as the
    "goto tx_drop_unmap;" relied on this @i variable.
 
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
v2: prot_stats.tso_packets false sharing
    wake_queue moved into first cache line
    Missing <linux/prefetch.h>
    tx_info allocated with kmalloc() instead of vmalloc()
    A bug in mlx4_en_free_tx_desc() was fixed.
    xmit_more part was already merged by David.

 drivers/net/ethernet/mellanox/mlx4/en_port.c |   15 
 drivers/net/ethernet/mellanox/mlx4/en_tx.c   |  327 ++++++++++-------
 drivers/net/ethernet/mellanox/mlx4/mlx4_en.h |   90 ++--
 include/linux/mlx4/device.h                  |    2 
 4 files changed, 254 insertions(+), 180 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c
index c2cfb05e7290..132805799fca 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c
@@ -150,14 +150,17 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
 	priv->port_stats.tx_chksum_offload = 0;
 	priv->port_stats.queue_stopped = 0;
 	priv->port_stats.wake_queue = 0;
+	priv->port_stats.tso_packets = 0;
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
-		stats->tx_packets += priv->tx_ring[i]->packets;
-		stats->tx_bytes += priv->tx_ring[i]->bytes;
-		priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum;
-		priv->port_stats.queue_stopped +=
-			priv->tx_ring[i]->queue_stopped;
-		priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue;
+		const struct mlx4_en_tx_ring *ring = priv->tx_ring[i];
+
+		stats->tx_packets += ring->packets;
+		stats->tx_bytes += ring->bytes;
+		priv->port_stats.tx_chksum_offload += ring->tx_csum;
+		priv->port_stats.queue_stopped += ring->queue_stopped;
+		priv->port_stats.wake_queue += ring->wake_queue;
+		priv->port_stats.tso_packets += ring->tso_packets;
 	}
 
 	stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index adedc47e947d..8816592ed7be 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -37,6 +37,7 @@
 #include <linux/mlx4/qp.h>
 #include <linux/skbuff.h>
 #include <linux/if_vlan.h>
+#include <linux/prefetch.h>
 #include <linux/vmalloc.h>
 #include <linux/tcp.h>
 #include <linux/ip.h>
@@ -68,7 +69,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
 	ring->inline_thold = priv->prof->inline_thold;
 
 	tmp = size * sizeof(struct mlx4_en_tx_info);
-	ring->tx_info = vmalloc_node(tmp, node);
+	ring->tx_info = kmalloc_node(tmp, GFP_KERNEL | __GFP_NOWARN, node);
 	if (!ring->tx_info) {
 		ring->tx_info = vmalloc(tmp);
 		if (!ring->tx_info) {
@@ -151,7 +152,7 @@ err_bounce:
 	kfree(ring->bounce_buf);
 	ring->bounce_buf = NULL;
 err_info:
-	vfree(ring->tx_info);
+	kvfree(ring->tx_info);
 	ring->tx_info = NULL;
 err_ring:
 	kfree(ring);
@@ -174,7 +175,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
 	mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
 	kfree(ring->bounce_buf);
 	ring->bounce_buf = NULL;
-	vfree(ring->tx_info);
+	kvfree(ring->tx_info);
 	ring->tx_info = NULL;
 	kfree(ring);
 	*pring = NULL;
@@ -191,12 +192,12 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
 	ring->prod = 0;
 	ring->cons = 0xffffffff;
 	ring->last_nr_txbb = 1;
-	ring->poll_cnt = 0;
 	memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
 	memset(ring->buf, 0, ring->buf_size);
 
 	ring->qp_state = MLX4_QP_STATE_RST;
-	ring->doorbell_qpn = ring->qp.qpn << 8;
+	ring->doorbell_qpn = cpu_to_be32(ring->qp.qpn << 8);
+	ring->mr_key = cpu_to_be32(mdev->mr.key);
 
 	mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
 				ring->cqn, user_prio, &ring->context);
@@ -259,38 +260,45 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 				struct mlx4_en_tx_ring *ring,
 				int index, u8 owner, u64 timestamp)
 {
-	struct mlx4_en_dev *mdev = priv->mdev;
 	struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
 	struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
 	struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
-	struct sk_buff *skb = tx_info->skb;
-	struct skb_frag_struct *frag;
 	void *end = ring->buf + ring->buf_size;
-	int frags = skb_shinfo(skb)->nr_frags;
+	struct sk_buff *skb = tx_info->skb;
+	int nr_maps = tx_info->nr_maps;
 	int i;
-	struct skb_shared_hwtstamps hwts;
 
-	if (timestamp) {
-		mlx4_en_fill_hwtstamps(mdev, &hwts, timestamp);
+	/* We do not touch skb here, so prefetch skb->users location
+	 * to speedup consume_skb()
+	 */
+	prefetchw(&skb->users);
+
+	if (unlikely(timestamp)) {
+		struct skb_shared_hwtstamps hwts;
+
+		mlx4_en_fill_hwtstamps(priv->mdev, &hwts, timestamp);
 		skb_tstamp_tx(skb, &hwts);
 	}
 
 	/* Optimize the common case when there are no wraparounds */
 	if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
 		if (!tx_info->inl) {
-			if (tx_info->linear) {
+			if (tx_info->linear)
 				dma_unmap_single(priv->ddev,
-					(dma_addr_t) be64_to_cpu(data->addr),
-					 be32_to_cpu(data->byte_count),
-					 PCI_DMA_TODEVICE);
-				++data;
-			}
-
-			for (i = 0; i < frags; i++) {
-				frag = &skb_shinfo(skb)->frags[i];
+						tx_info->map0_dma,
+						tx_info->map0_byte_count,
+						PCI_DMA_TODEVICE);
+			else
+				dma_unmap_page(priv->ddev,
+					       tx_info->map0_dma,
+					       tx_info->map0_byte_count,
+					       PCI_DMA_TODEVICE);
+			for (i = 1; i < nr_maps; i++) {
+				data++;
 				dma_unmap_page(priv->ddev,
-					(dma_addr_t) be64_to_cpu(data[i].addr),
-					skb_frag_size(frag), PCI_DMA_TODEVICE);
+					(dma_addr_t)be64_to_cpu(data->addr),
+					be32_to_cpu(data->byte_count),
+					PCI_DMA_TODEVICE);
 			}
 		}
 	} else {
@@ -299,23 +307,25 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
 				data = ring->buf + ((void *)data - end);
 			}
 
-			if (tx_info->linear) {
+			if (tx_info->linear)
 				dma_unmap_single(priv->ddev,
-					(dma_addr_t) be64_to_cpu(data->addr),
-					 be32_to_cpu(data->byte_count),
-					 PCI_DMA_TODEVICE);
-				++data;
-			}
-
-			for (i = 0; i < frags; i++) {
+						tx_info->map0_dma,
+						tx_info->map0_byte_count,
+						PCI_DMA_TODEVICE);
+			else
+				dma_unmap_page(priv->ddev,
+					       tx_info->map0_dma,
+					       tx_info->map0_byte_count,
+					       PCI_DMA_TODEVICE);
+			for (i = 1; i < nr_maps; i++) {
+				data++;
 				/* Check for wraparound before unmapping */
 				if ((void *) data >= end)
 					data = ring->buf;
-				frag = &skb_shinfo(skb)->frags[i];
 				dma_unmap_page(priv->ddev,
-					(dma_addr_t) be64_to_cpu(data->addr),
-					 skb_frag_size(frag), PCI_DMA_TODEVICE);
-				++data;
+					(dma_addr_t)be64_to_cpu(data->addr),
+					be32_to_cpu(data->byte_count),
+					PCI_DMA_TODEVICE);
 			}
 		}
 	}
@@ -377,13 +387,18 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev,
 	u64 timestamp = 0;
 	int done = 0;
 	int budget = priv->tx_work_limit;
+	u32 last_nr_txbb;
+	u32 ring_cons;
 
 	if (!priv->port_up)
 		return true;
 
+	prefetchw(&ring->tx_queue->dql.limit);
 	index = cons_index & size_mask;
 	cqe = mlx4_en_get_cqe(buf, index, priv->cqe_size) + factor;
-	ring_index = ring->cons & size_mask;
+	last_nr_txbb = ACCESS_ONCE(ring->last_nr_txbb);
+	ring_cons = ACCESS_ONCE(ring->cons);
+	ring_index = ring_cons & size_mask;
 	stamp_index = ring_index;
 
 	/* Process all completed CQEs */
@@ -408,19 +423,19 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev,
 		new_index = be16_to_cpu(cqe->wqe_index) & size_mask;
 
 		do {
-			txbbs_skipped += ring->last_nr_txbb;
-			ring_index = (ring_index + ring->last_nr_txbb) & size_mask;
+			txbbs_skipped += last_nr_txbb;
+			ring_index = (ring_index + last_nr_txbb) & size_mask;
 			if (ring->tx_info[ring_index].ts_requested)
 				timestamp = mlx4_en_get_cqe_ts(cqe);
 
 			/* free next descriptor */
-			ring->last_nr_txbb = mlx4_en_free_tx_desc(
+			last_nr_txbb = mlx4_en_free_tx_desc(
 					priv, ring, ring_index,
-					!!((ring->cons + txbbs_skipped) &
+					!!((ring_cons + txbbs_skipped) &
 					ring->size), timestamp);
 
 			mlx4_en_stamp_wqe(priv, ring, stamp_index,
-					  !!((ring->cons + txbbs_stamp) &
+					  !!((ring_cons + txbbs_stamp) &
 						ring->size));
 			stamp_index = ring_index;
 			txbbs_stamp = txbbs_skipped;
@@ -441,7 +456,11 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev,
 	mcq->cons_index = cons_index;
 	mlx4_cq_set_ci(mcq);
 	wmb();
-	ring->cons += txbbs_skipped;
+
+	/* we want to dirty this cache line once */
+	ACCESS_ONCE(ring->last_nr_txbb) = last_nr_txbb;
+	ACCESS_ONCE(ring->cons) = ring_cons + txbbs_skipped;
+
 	netdev_tx_completed_queue(ring->tx_queue, packets, bytes);
 
 	/*
@@ -512,30 +531,35 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
 	return ring->buf + index * TXBB_SIZE;
 }
 
-static int is_inline(int inline_thold, struct sk_buff *skb, void **pfrag)
+/* Decide if skb can be inlined in tx descriptor to avoid dma mapping
+ *
+ * It seems strange we do not simply use skb_copy_bits().
+ * This would allow to inline all skbs iff skb->len <= inline_thold
+ *
+ * Note that caller already checked skb was not a gso packet
+ */
+static bool is_inline(int inline_thold, const struct sk_buff *skb,
+		      const struct skb_shared_info *shinfo,
+		      void **pfrag)
 {
 	void *ptr;
 
-	if (inline_thold && !skb_is_gso(skb) && skb->len <= inline_thold) {
-		if (skb_shinfo(skb)->nr_frags == 1) {
-			ptr = skb_frag_address_safe(&skb_shinfo(skb)->frags[0]);
-			if (unlikely(!ptr))
-				return 0;
-
-			if (pfrag)
-				*pfrag = ptr;
+	if (skb->len > inline_thold || !inline_thold)
+		return false;
 
-			return 1;
-		} else if (unlikely(skb_shinfo(skb)->nr_frags))
-			return 0;
-		else
-			return 1;
+	if (shinfo->nr_frags == 1) {
+		ptr = skb_frag_address_safe(&shinfo->frags[0]);
+		if (unlikely(!ptr))
+			return false;
+		*pfrag = ptr;
+		return true;
 	}
-
-	return 0;
+	if (shinfo->nr_frags)
+		return false;
+	return true;
 }
 
-static int inline_size(struct sk_buff *skb)
+static int inline_size(const struct sk_buff *skb)
 {
 	if (skb->len + CTRL_SIZE + sizeof(struct mlx4_wqe_inline_seg)
 	    <= MLX4_INLINE_ALIGN)
@@ -546,18 +570,23 @@ static int inline_size(struct sk_buff *skb)
 			     sizeof(struct mlx4_wqe_inline_seg), 16);
 }
 
-static int get_real_size(struct sk_buff *skb, struct net_device *dev,
-			 int *lso_header_size)
+static int get_real_size(const struct sk_buff *skb,
+			 const struct skb_shared_info *shinfo,
+			 struct net_device *dev,
+			 int *lso_header_size,
+			 bool *inline_ok,
+			 void **pfrag)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	int real_size;
 
-	if (skb_is_gso(skb)) {
+	if (shinfo->gso_size) {
+		*inline_ok = false;
 		if (skb->encapsulation)
 			*lso_header_size = (skb_inner_transport_header(skb) - skb->data) + inner_tcp_hdrlen(skb);
 		else
 			*lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb);
-		real_size = CTRL_SIZE + skb_shinfo(skb)->nr_frags * DS_SIZE +
+		real_size = CTRL_SIZE + shinfo->nr_frags * DS_SIZE +
 			ALIGN(*lso_header_size + 4, DS_SIZE);
 		if (unlikely(*lso_header_size != skb_headlen(skb))) {
 			/* We add a segment for the skb linear buffer only if
@@ -572,20 +601,28 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
 		}
 	} else {
 		*lso_header_size = 0;
-		if (!is_inline(priv->prof->inline_thold, skb, NULL))
-			real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE;
-		else
+		*inline_ok = is_inline(priv->prof->inline_thold, skb,
+				       shinfo, pfrag);
+
+		if (*inline_ok)
 			real_size = inline_size(skb);
+		else
+			real_size = CTRL_SIZE +
+				    (shinfo->nr_frags + 1) * DS_SIZE;
 	}
 
 	return real_size;
 }
 
-static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *skb,
-			     int real_size, u16 *vlan_tag, int tx_ind, void *fragptr)
+static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc,
+			     const struct sk_buff *skb,
+			     const struct skb_shared_info *shinfo,
+			     int real_size, u16 *vlan_tag,
+			     int tx_ind, void *fragptr)
 {
 	struct mlx4_wqe_inline_seg *inl = &tx_desc->inl;
 	int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl;
+	unsigned int hlen = skb_headlen(skb);
 
 	if (skb->len <= spc) {
 		if (likely(skb->len >= MIN_PKT_LEN)) {
@@ -595,19 +632,19 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
 			memset(((void *)(inl + 1)) + skb->len, 0,
 			       MIN_PKT_LEN - skb->len);
 		}
-		skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
-		if (skb_shinfo(skb)->nr_frags)
-			memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr,
-			       skb_frag_size(&skb_shinfo(skb)->frags[0]));
+		skb_copy_from_linear_data(skb, inl + 1, hlen);
+		if (shinfo->nr_frags)
+			memcpy(((void *)(inl + 1)) + hlen, fragptr,
+			       skb_frag_size(&shinfo->frags[0]));
 
 	} else {
 		inl->byte_count = cpu_to_be32(1 << 31 | spc);
-		if (skb_headlen(skb) <= spc) {
-			skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
-			if (skb_headlen(skb) < spc) {
-				memcpy(((void *)(inl + 1)) + skb_headlen(skb),
-					fragptr, spc - skb_headlen(skb));
-				fragptr +=  spc - skb_headlen(skb);
+		if (hlen <= spc) {
+			skb_copy_from_linear_data(skb, inl + 1, hlen);
+			if (hlen < spc) {
+				memcpy(((void *)(inl + 1)) + hlen,
+					fragptr, spc - hlen);
+				fragptr +=  spc - hlen;
 			}
 			inl = (void *) (inl + 1) + spc;
 			memcpy(((void *)(inl + 1)), fragptr, skb->len - spc);
@@ -615,10 +652,11 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
 			skb_copy_from_linear_data(skb, inl + 1, spc);
 			inl = (void *) (inl + 1) + spc;
 			skb_copy_from_linear_data_offset(skb, spc, inl + 1,
-					skb_headlen(skb) - spc);
-			if (skb_shinfo(skb)->nr_frags)
-				memcpy(((void *)(inl + 1)) + skb_headlen(skb) - spc,
-					fragptr, skb_frag_size(&skb_shinfo(skb)->frags[0]));
+							 hlen - spc);
+			if (shinfo->nr_frags)
+				memcpy(((void *)(inl + 1)) + hlen - spc,
+				       fragptr,
+				       skb_frag_size(&shinfo->frags[0]));
 		}
 
 		wmb();
@@ -642,15 +680,16 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
 	return fallback(dev, skb) % rings_p_up + up * rings_p_up;
 }
 
-static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
+static void mlx4_bf_copy(void __iomem *dst, const void *src,
+			 unsigned int bytecnt)
 {
 	__iowrite64_copy(dst, src, bytecnt / 8);
 }
 
 netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	struct skb_shared_info *shinfo = skb_shinfo(skb);
 	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_en_dev *mdev = priv->mdev;
 	struct device *ddev = priv->ddev;
 	struct mlx4_en_tx_ring *ring;
 	struct mlx4_en_tx_desc *tx_desc;
@@ -663,16 +702,25 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 	u32 index, bf_index;
 	__be32 op_own;
 	u16 vlan_tag = 0;
-	int i;
+	int i_frag;
 	int lso_header_size;
-	void *fragptr;
+	void *fragptr = NULL;
 	bool bounce = false;
 	bool send_doorbell;
+	bool inline_ok;
+	u32 ring_cons;
 
 	if (!priv->port_up)
 		goto tx_drop;
 
-	real_size = get_real_size(skb, dev, &lso_header_size);
+	tx_ind = skb_get_queue_mapping(skb);
+	ring = priv->tx_ring[tx_ind];
+
+	/* fetch ring->cons far ahead before needing it to avoid stall */
+	ring_cons = ACCESS_ONCE(ring->cons);
+
+	real_size = get_real_size(skb, shinfo, dev, &lso_header_size,
+				  &inline_ok, &fragptr);
 	if (unlikely(!real_size))
 		goto tx_drop;
 
@@ -685,13 +733,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 		goto tx_drop;
 	}
 
-	tx_ind = skb->queue_mapping;
-	ring = priv->tx_ring[tx_ind];
 	if (vlan_tx_tag_present(skb))
 		vlan_tag = vlan_tx_tag_get(skb);
 
 	/* Check available TXBBs And 2K spare for prefetch */
-	if (unlikely(((int)(ring->prod - ring->cons)) >
+	if (unlikely(((int)(ring->prod - ring_cons)) >
 		     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
 		/* every full Tx ring stops queue */
 		netif_tx_stop_queue(ring->tx_queue);
@@ -705,7 +751,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 		 */
 		wmb();
 
-		if (unlikely(((int)(ring->prod - ring->cons)) <=
+		ring_cons = ACCESS_ONCE(ring->cons);
+		if (unlikely(((int)(ring->prod - ring_cons)) <=
 			     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
 			netif_tx_wake_queue(ring->tx_queue);
 			ring->wake_queue++;
@@ -714,9 +761,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 	}
 
+	prefetchw(&ring->tx_queue->dql);
+
 	/* Track current inflight packets for performance analysis */
 	AVG_PERF_COUNTER(priv->pstats.inflight_avg,
-			 (u32) (ring->prod - ring->cons - 1));
+			 (u32)(ring->prod - ring_cons - 1));
 
 	/* Packet is good - grab an index and transmit it */
 	index = ring->prod & ring->size_mask;
@@ -736,46 +785,48 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 	tx_info->skb = skb;
 	tx_info->nr_txbb = nr_txbb;
 
+	data = &tx_desc->data;
 	if (lso_header_size)
 		data = ((void *)&tx_desc->lso + ALIGN(lso_header_size + 4,
 						      DS_SIZE));
-	else
-		data = &tx_desc->data;
 
 	/* valid only for none inline segments */
 	tx_info->data_offset = (void *)data - (void *)tx_desc;
 
+	tx_info->inl = inline_ok;
+
 	tx_info->linear = (lso_header_size < skb_headlen(skb) &&
-			   !is_inline(ring->inline_thold, skb, NULL)) ? 1 : 0;
+			   !inline_ok) ? 1 : 0;
 
-	data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1;
+	tx_info->nr_maps = shinfo->nr_frags + tx_info->linear;
+	data += tx_info->nr_maps - 1;
 
-	if (is_inline(ring->inline_thold, skb, &fragptr)) {
-		tx_info->inl = 1;
-	} else {
-		/* Map fragments */
-		for (i = skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) {
-			struct skb_frag_struct *frag;
-			dma_addr_t dma;
+	if (!tx_info->inl) {
+		dma_addr_t dma = 0;
+		u32 byte_count = 0;
 
-			frag = &skb_shinfo(skb)->frags[i];
+		/* Map fragments if any */
+		for (i_frag = shinfo->nr_frags - 1; i_frag >= 0; i_frag--) {
+			const struct skb_frag_struct *frag;
+
+			frag = &shinfo->frags[i_frag];
+			byte_count = skb_frag_size(frag);
 			dma = skb_frag_dma_map(ddev, frag,
-					       0, skb_frag_size(frag),
+					       0, byte_count,
 					       DMA_TO_DEVICE);
 			if (dma_mapping_error(ddev, dma))
 				goto tx_drop_unmap;
 
 			data->addr = cpu_to_be64(dma);
-			data->lkey = cpu_to_be32(mdev->mr.key);
+			data->lkey = ring->mr_key;
 			wmb();
-			data->byte_count = cpu_to_be32(skb_frag_size(frag));
+			data->byte_count = cpu_to_be32(byte_count);
 			--data;
 		}
 
-		/* Map linear part */
+		/* Map linear part if needed */
 		if (tx_info->linear) {
-			u32 byte_count = skb_headlen(skb) - lso_header_size;
-			dma_addr_t dma;
+			byte_count = skb_headlen(skb) - lso_header_size;
 
 			dma = dma_map_single(ddev, skb->data +
 					     lso_header_size, byte_count,
@@ -784,29 +835,28 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 				goto tx_drop_unmap;
 
 			data->addr = cpu_to_be64(dma);
-			data->lkey = cpu_to_be32(mdev->mr.key);
+			data->lkey = ring->mr_key;
 			wmb();
 			data->byte_count = cpu_to_be32(byte_count);
 		}
-		tx_info->inl = 0;
+		/* tx completion can avoid cache line miss for common cases */
+		tx_info->map0_dma = dma;
+		tx_info->map0_byte_count = byte_count;
 	}
 
 	/*
 	 * For timestamping add flag to skb_shinfo and
 	 * set flag for further reference
 	 */
-	if (ring->hwtstamp_tx_type == HWTSTAMP_TX_ON &&
-	    skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
-		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+	tx_info->ts_requested = 0;
+	if (unlikely(ring->hwtstamp_tx_type == HWTSTAMP_TX_ON &&
+		     shinfo->tx_flags & SKBTX_HW_TSTAMP)) {
+		shinfo->tx_flags |= SKBTX_IN_PROGRESS;
 		tx_info->ts_requested = 1;
 	}
 
 	/* Prepare ctrl segement apart opcode+ownership, which depends on
 	 * whether LSO is used */
-	tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
-	tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
-		!!vlan_tx_tag_present(skb);
-	tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
 	tx_desc->ctrl.srcrb_flags = priv->ctrl_flags;
 	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
 		tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
@@ -827,6 +877,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	/* Handle LSO (TSO) packets */
 	if (lso_header_size) {
+		int i;
+
 		/* Mark opcode as LSO */
 		op_own = cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)) |
 			((ring->prod & ring->size) ?
@@ -834,15 +886,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 
 		/* Fill in the LSO prefix */
 		tx_desc->lso.mss_hdr_size = cpu_to_be32(
-			skb_shinfo(skb)->gso_size << 16 | lso_header_size);
+			shinfo->gso_size << 16 | lso_header_size);
 
 		/* Copy headers;
 		 * note that we already verified that it is linear */
 		memcpy(tx_desc->lso.header, skb->data, lso_header_size);
 
-		priv->port_stats.tso_packets++;
-		i = ((skb->len - lso_header_size) / skb_shinfo(skb)->gso_size) +
-			!!((skb->len - lso_header_size) % skb_shinfo(skb)->gso_size);
+		ring->tso_packets++;
+
+		i = ((skb->len - lso_header_size) / shinfo->gso_size) +
+			!!((skb->len - lso_header_size) % shinfo->gso_size);
 		tx_info->nr_bytes = skb->len + (i - 1) * lso_header_size;
 		ring->packets += i;
 	} else {
@@ -852,16 +905,14 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 			 cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0);
 		tx_info->nr_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
 		ring->packets++;
-
 	}
 	ring->bytes += tx_info->nr_bytes;
 	netdev_tx_sent_queue(ring->tx_queue, tx_info->nr_bytes);
 	AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, skb->len);
 
-	if (tx_info->inl) {
-		build_inline_wqe(tx_desc, skb, real_size, &vlan_tag, tx_ind, fragptr);
-		tx_info->inl = 1;
-	}
+	if (tx_info->inl)
+		build_inline_wqe(tx_desc, skb, shinfo, real_size,
+				 &vlan_tag, tx_ind, fragptr);
 
 	if (skb->encapsulation) {
 		struct iphdr *ipv4 = (struct iphdr *)skb_inner_network_header(skb);
@@ -874,16 +925,19 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 	ring->prod += nr_txbb;
 
 	/* If we used a bounce buffer then copy descriptor back into place */
-	if (bounce)
+	if (unlikely(bounce))
 		tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
 
 	skb_tx_timestamp(skb);
 
 	send_doorbell = !skb->xmit_more || netif_xmit_stopped(ring->tx_queue);
 
+	real_size = (real_size / 16) & 0x3f;
+
 	if (ring->bf_enabled && desc_size <= MAX_BF && !bounce &&
 	    !vlan_tx_tag_present(skb) && send_doorbell) {
-		tx_desc->ctrl.bf_qpn |= cpu_to_be32(ring->doorbell_qpn);
+		tx_desc->ctrl.bf_qpn = ring->doorbell_qpn |
+				       cpu_to_be32(real_size);
 
 		op_own |= htonl((bf_index & 0xffff) << 8);
 		/* Ensure new descriptor hits memory
@@ -894,13 +948,18 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 
 		wmb();
 
-		mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl,
-		     desc_size);
+		mlx4_bf_copy(ring->bf.reg + ring->bf.offset, &tx_desc->ctrl,
+			     desc_size);
 
 		wmb();
 
 		ring->bf.offset ^= ring->bf.buf_size;
 	} else {
+		tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
+		tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
+			!!vlan_tx_tag_present(skb);
+		tx_desc->ctrl.fence_size = real_size;
+
 		/* Ensure new descriptor hits memory
 		 * before setting ownership of this descriptor to HW
 		 */
@@ -918,8 +977,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
 tx_drop_unmap:
 	en_err(priv, "DMA mapping error\n");
 
-	for (i++; i < skb_shinfo(skb)->nr_frags; i++) {
-		data++;
+	while (++i_frag < shinfo->nr_frags) {
+		++data;
 		dma_unmap_page(ddev, (dma_addr_t) be64_to_cpu(data->addr),
 			       be32_to_cpu(data->byte_count),
 			       PCI_DMA_TODEVICE);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 6a4fc2394cf2..8731aac89244 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -216,13 +216,16 @@ enum cq_type {
 
 struct mlx4_en_tx_info {
 	struct sk_buff *skb;
-	u32 nr_txbb;
-	u32 nr_bytes;
-	u8 linear;
-	u8 data_offset;
-	u8 inl;
-	u8 ts_requested;
-};
+	dma_addr_t	map0_dma;
+	u32		map0_byte_count;
+	u32		nr_txbb;
+	u32		nr_bytes;
+	u8		linear;
+	u8		data_offset;
+	u8		inl;
+	u8		ts_requested;
+	u8		nr_maps;
+} ____cacheline_aligned_in_smp;
 
 
 #define MLX4_EN_BIT_DESC_OWN	0x80000000
@@ -253,39 +256,48 @@ struct mlx4_en_rx_alloc {
 };
 
 struct mlx4_en_tx_ring {
+			/* cache line used and dirtied in tx completion
+			 * (mlx4_en_free_tx_buf())
+			 */
+	u32			last_nr_txbb;
+	u32			cons;
+	unsigned long		wake_queue;
+
+			/* cache line used and dirtied in mlx4_en_xmit()
+			 */
+	u32			prod ____cacheline_aligned_in_smp;
+	unsigned long		bytes;
+	unsigned long		packets;
+	unsigned long		tx_csum;
+	unsigned long		tso_packets;
+	struct mlx4_bf		bf;
+	unsigned long		queue_stopped;
+
+			/* Following part should be mostly read
+			 */
+	cpumask_t		affinity_mask;
+	struct mlx4_qp		qp;
 	struct mlx4_hwq_resources wqres;
-	u32 size ; /* number of TXBBs */
-	u32 size_mask;
-	u16 stride;
-	u16 cqn;	/* index of port CQ associated with this ring */
-	u32 prod;
-	u32 cons;
-	u32 buf_size;
-	u32 doorbell_qpn;
-	void *buf;
-	u16 poll_cnt;
-	struct mlx4_en_tx_info *tx_info;
-	u8 *bounce_buf;
-	u8 queue_index;
-	cpumask_t affinity_mask;
-	u32 last_nr_txbb;
-	struct mlx4_qp qp;
-	struct mlx4_qp_context context;
-	int qpn;
-	enum mlx4_qp_state qp_state;
-	struct mlx4_srq dummy;
-	unsigned long bytes;
-	unsigned long packets;
-	unsigned long tx_csum;
-	unsigned long queue_stopped;
-	unsigned long wake_queue;
-	struct mlx4_bf bf;
-	bool bf_enabled;
-	bool bf_alloced;
-	struct netdev_queue *tx_queue;
-	int hwtstamp_tx_type;
-	int inline_thold;
-};
+	u32			size ; /* number of TXBBs */
+	u32			size_mask;
+	u16			stride;
+	u16			cqn;	/* index of port CQ associated with this ring */
+	u32			buf_size;
+	__be32			doorbell_qpn;
+	__be32			mr_key;
+	void			*buf;
+	struct mlx4_en_tx_info	*tx_info;
+	u8			*bounce_buf;
+	struct mlx4_qp_context	context;
+	int			qpn;
+	enum mlx4_qp_state	qp_state;
+	u8			queue_index;
+	bool			bf_enabled;
+	bool			bf_alloced;
+	struct netdev_queue	*tx_queue;
+	int			hwtstamp_tx_type;
+	int			inline_thold;
+} ____cacheline_aligned_in_smp;
 
 struct mlx4_en_rx_desc {
 	/* actual number of entries depends on rx ring stride */
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 03b5608a4329..5e5ad07548b8 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -583,7 +583,7 @@ struct mlx4_uar {
 };
 
 struct mlx4_bf {
-	unsigned long		offset;
+	unsigned int		offset;
 	int			buf_size;
 	struct mlx4_uar	       *uar;
 	void __iomem	       *reg;

^ permalink raw reply related

* Re: [PATCH v3 5/7] net: Add GSO support for UDP tunnels with checksum
From: Tom Herbert @ 2014-09-29  4:11 UTC (permalink / raw)
  To: Or Gerlitz; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <CAJZOPZKVjQMhBZVoGPVLPOZM1_Jb53iPKr8ZAuNZfG_cDQbQ0Q@mail.gmail.com>

On Sat, Sep 27, 2014 at 1:39 PM, Or Gerlitz <or.gerlitz@gmail.com> wrote:
> On Sat, Sep 27, 2014 at 12:57 AM, Tom Herbert <therbert@google.com> wrote:
>> On Fri, Sep 26, 2014 at 2:05 PM, Or Gerlitz <or.gerlitz@gmail.com> wrote:
>>> On Thu, Jun 5, 2014 at 3:20 AM, Tom Herbert <therbert@google.com> wrote:
>
>>>> Added a new netif feature for GSO_UDP_TUNNEL_CSUM. This indicates
>>>> that a device is capable of computing the UDP checksum in the
>>>> encapsulating header of a UDP tunnel.
>
>>> Do we have upstream driver that supports GSO_UDP_TUNNEL_CSUM? did you
>>> had such driver/patch while doing this patches? when a driver
>>> advertizes that bit, should they look over the xmit path on the new
>>> encap_hdr_csum bit?
>
>> No, no, and encap_hdr_csum should only be set with
>> SKB_GSO_UDP_TUNNEL_CSUM or SKB_GSO_GRE_CSUM.
>
> I'm still trying to dig the bigger picture w.r.t checksum of the outer
> UDP packet from the patches -- if I got it right, once these patches
> were picked upstream, there's a scheme where the kernel either
> computes this checksum or let the device do that - when they advertize
> NETIF_F_GSO_YYY_CSUM  and in that case
> (skb->encap_hdr_csum == true) should be interpreted as a directive to
> do that, right?

NETIF_F_GSO_UDP_CSUM does indicate that device is capable of setting
outer UDP checksum. gso_type in an skbuff indicates to driver that the
outer checksum needs to be computed (e.g. SKB_GSO_UDP_TUNNEL_CSUM).
skb->encap_hdr_csum is only used in software GSO, drivers should not
care about this.

>
> So what happens when the device isn't capable to compute that checksum
> (e.g they don't set _GSO_UDP_TUNNEL_CSUM) but they do advertize the
> GSO_UDP_TUNNEL bit?
>
Then for tunnels configured to use outer checksum software GSO would be used.

> I was worried that we can run into this scheme - the stack computes
> the outer checksum for the giant 64K UDP chunck that encapsulate a 64K
> TCP segment, but when the NIC will issue the segmentation, they will
> likely to just repeat ~40 times (64K/1500) the original udp checksum
> for the packets they send, which will be treated as bad checksum on
> the receiving end, bad.
>
This shouldn't happen since the driver would not advertise
SKB_GSO_UDP_TUNNEL_CSUM.

We can add some comments in skbuff.h to clarify some of the GSO types.

Tom

>> find . -name '*.[ch]' -exec fgrep -l GSO_UDP_TUNNEL_CSUM {} \;
>> returns nothing.
>
> grepping I know, I was just hoping you were able to test such a sensitive change
> with HW that cause both code parts (outer udp checksum offloaded vs.
> non-offloaded) to be exercised
>
>> find . -name '*.[ch]' -exec fgrep -l GSO_UDP_TUNNEL {} \;
>> returns
>>
>> ./ethernet/intel/i40e/i40e_main.c
>> ./ethernet/broadcom/bnx2x/bnx2x_main.c
>> ./ethernet/qlogic/qlcnic/qlcnic_main.c
>> ./ethernet/mellanox/mlx4/en_netdev.c
>> ./ethernet/emulex/benet/be_main.c
>
> cool, I see here four 40Gbs NICs that support GSO offloading of VXLAN
> traffic, each of them can serve you for testing new developments you
> do in that area.
>
> Or.

^ permalink raw reply

* Re: [PATCH net-next] net: reorganize sk_buff for faster __copy_skb_header()
From: David Miller @ 2014-09-29  4:06 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, amirv, john.r.fastabend, brouer
In-Reply-To: <20140928.173759.584339934179620924.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Sun, 28 Sep 2014 17:37:59 -0400 (EDT)

> Applied, thanks!

Eric, I had to revert.  Please enable IPVS in your build tests.

net/ipv4/ip_output.c: In function ‘ip_copy_metadata’:
net/ipv4/ip_output.c:470:4: error: ‘struct sk_buff’ has no member named ‘ipvs_property’
  to->ipvs_property = from->ipvs_property;
    ^
net/ipv4/ip_output.c:470:26: error: ‘struct sk_buff’ has no member named ‘ipvs_property’
  to->ipvs_property = from->ipvs_property;
                          ^

^ permalink raw reply

* Re: [net-next PATCH] net: sched: cls_rcvp, complete rcu conversion
From: David Miller @ 2014-09-29  4:02 UTC (permalink / raw)
  To: john.fastabend; +Cc: xiyou.wangcong, jhs, eric.dumazet, netdev
In-Reply-To: <20140926170249.27131.97630.stgit@nitbit.x32>

From: John Fastabend <john.fastabend@gmail.com>
Date: Fri, 26 Sep 2014 10:02:50 -0700

> This completes the cls_rsvp conversion to RCU safe
> copy, update semantics.
> 
> As a result all cases of tcf_exts_change occur on
> empty lists now.
> 
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>

Applied, thanks John.

^ permalink raw reply

* Re: [PATCH net-next 0/5] udp: Generalize GSO for UDP tunnels
From: Tom Herbert @ 2014-09-29  3:59 UTC (permalink / raw)
  To: Or Gerlitz; +Cc: David Miller, Linux Netdev List
In-Reply-To: <CAJ3xEMi5V0ijSVmga0chTFF1ghUaGs7h9PGfYGb10ZdyPcs5_A@mail.gmail.com>

On Sat, Sep 27, 2014 at 12:26 PM, Or Gerlitz <gerlitz.or@gmail.com> wrote:
> On Sat, Sep 27, 2014 at 2:04 AM, Tom Herbert <therbert@google.com> wrote:
>> On Fri, Sep 26, 2014 at 1:16 PM, Or Gerlitz <gerlitz.or@gmail.com> wrote:
>>> On Fri, Sep 26, 2014 at 7:22 PM, Tom Herbert <therbert@google.com> wrote:
>>> [...]
>>>> Notes:
>>>>   - GSO for GRE/UDP where GRE checksum is enabled does not work.
>>>>     Handling this will require some special case code.
>>>>   - Software GSO now supports many varieties of encapsulation with
>>>>     SKB_GSO_UDP_TUNNEL{_CSUM}. We still need a mechanism to query
>>>>     for device support of particular combinations (I intend to
>>>>     add ndo_gso_check for that).
>>>
>>> Tom,
>>>
>>> As I wrote you earlier on another thread/s, fact is that there are
>>> upstream drivers who advertize SKB_GSO_UDP_TUNNEL and aren't capable @
>>> this point to issue proper HW segmentation of something which isn't
>>> VXLAN.
>>>
>>> Just to make sure, this series isn't expected to introduce a
>>> regression, right? we don't expect the stack to attempt and xmit a
>>> large 64KB UDP packet which isn't vxlan through these devices.
>
>> I am planning to post ndo_gso_check shortly. These patches should not
>> cause a regression with currently deployed functionality (VXLAN).
>
> Can you sum up (please) in 1-2 liner what is the trick to avoid such
> regression? that is what/where is the knob that would prevent such
> giant chunk to be sent down to a NIC driver which does advertize
> SKB_GSO_UDP_TUNNEL?
>
I posted patch for ndo_gso_check. Please let me know if you'll be able
to work with this. I'll also post the iproute changes soon so that the
FOU results can be repro'd.

>
>>>>   - MPLS seems to be the only previous user of inner_protocol. I don't
>>>>     believe these patches can affect that. For supporting GSO with
>>>>     MPLS over UDP, the inner_protocol should be set using the
>>>>     helper functions in this patch.
>>>>   - GSO for L2TP/UDP should also be straightforward now.
>>>
>>>> Tested GRE, IPIP, and SIT over fou as well as VLXAN. This was
>>>> done using 200 TCP_STREAMs in netperf.
>>> [...]
>>>>    VXLAN
>>>>       TCP_STREAM TSO enabled on tun interface
>>>>         16.42% TX CPU utilization
>>>>         23.66% RX CPU utilization
>>>>         9081 Mbps
>>>>       TCP_STREAM TSO disabled on tun interface
>>>>         30.32% TX CPU utilization
>>>>         30.55% RX CPU utilization
>>>>         9185 Mbps
>>>
>>> so TSO disabled has better BW vs TSO enabled?
>>>
>> Yes, I've noticed that on occasion, it does seem like TSO disabled
>> tends to get a little more throughput. I see this with plain GRE, so I
>> don't think it's directly related to fou or these patches. I suppose
>> there may be some subtle interactions with BQL or something like that.
>> I'd probably want to repro this on some other devices at some point to
>> dig deeper.
>>
>>>>    Baseline (no encp, TSO and LRO enabled)
>>>>       TCP_STREAM
>>>>         11.85% TX CPU utilization
>>>>         15.13% RX CPU utilization
>>>>         9452 Mbps
>>>
>>> I would strongly recommend to have a far better baseline when
>>> developing and testing these changes in the stack in the form of 40Gbs
>>> NICs.
>>>
>> The only point of putting the baseline was to show that encapsulation
>> with GSO/GRO/checksum-unnec-conversion is in the ballpark of
>> performance with native traffic which was a goal.
>
> under (over...) 10Gbs, in the ballpark indeed.
>
> We know nothing what would happen with baseline of 38Gbs (SB 40Gbs
> NIC) 56Gbs (two bonded ports of 40Gbs NIC on PCIe gen3) or 100Gbs
> (tomorrow's NIC HW, probably coming up next year)
>
>> So I'm pretty happy
>> with this performance right now, although it probably does mean remote
>> checksum offload won't show so impressive results with this test (TX
>> csum with data in case isn't so expensive).
>> Out of curiosity, why do you think using 40Gbs is far better for a baseline?
>
> Oh, simply b/c with 40Gbs NICs, the baseline I expect for few sessions
> (1,2,4 or 200 as you did) of plain TCP is four times better vs. your
> current one (38Gbs vs 9.5Gbs) and this should pose a harder challenge
> for the GSO/encapsulating stack to catch up with, agree?
>
Sure, I agree that it would be nice to have this tested on different
devices (40G, 1G, wireless, etc.)-- but right now I don't see anything
particularly obvious why performance shouldn't scale linearly.

> Or.

^ permalink raw reply

* Re: [PATCH net-next v3] bonding: make global bonding stats more reliable
From: Ding Tianhong @ 2014-09-29  3:52 UTC (permalink / raw)
  To: Andy Gospodarek, netdev; +Cc: j.vosburgh, vfalico, nikolay
In-Reply-To: <1411693935-4191-1-git-send-email-gospo@cumulusnetworks.com>

On 2014/9/26 9:12, Andy Gospodarek wrote:
> As the code stands today, bonding stats are based simply on the stats
> from the member interfaces.  If a member was to be removed from a bond,
> the stats would instantly drop.  This would be confusing to an admin
> would would suddonly see interface stats drop while traffic is still
> flowing.
> 
> In addition to preventing the stats drops mentioned above, new members
> will now be added to the bond and only traffic received after the member
> was added to the bond will be counted as part of bonding stats.
> 
> v2: Changes suggested by Nik to properly allocate/free stats memory.
> v3: Properly destroy workqueue and fix netlink configuration path.
> 
> Signed-off-by: Andy Gospodarek <gospo@cumulusnetworks.com>
> ---
>  drivers/net/bonding/bond_main.c    | 84 +++++++++++++++++++++++++-------------
>  drivers/net/bonding/bond_netlink.c | 13 +++++-
>  drivers/net/bonding/bonding.h      |  3 ++
>  3 files changed, 71 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 5390475..10c2dc3 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -1147,17 +1147,26 @@ static struct slave *bond_alloc_slave(struct bonding *bond)
>  
>  	slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
>  	if (!slave)
> -		return NULL;
> +		goto slave_fail;
> +
> +	slave->slave_stats = kzalloc(sizeof(struct rtnl_link_stats64),
> +				     GFP_KERNEL);
> +	if (!slave->slave_stats)
> +		goto slave_stats_fail;
>  
>  	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
>  		SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info),
>  					       GFP_KERNEL);
> -		if (!SLAVE_AD_INFO(slave)) {
> -			kfree(slave);
> -			return NULL;
> -		}
> +		if (!SLAVE_AD_INFO(slave))
> +			goto slave_ad_fail;
>  	}
>  	return slave;
> +slave_ad_fail:
> +	kfree(slave->slave_stats);
> +slave_stats_fail:
> +	kfree(slave);
> +slave_fail:
> +	return NULL;
>  }
>  
>  static void bond_free_slave(struct slave *slave)
> @@ -1167,6 +1176,7 @@ static void bond_free_slave(struct slave *slave)
>  	if (BOND_MODE(bond) == BOND_MODE_8023AD)
>  		kfree(SLAVE_AD_INFO(slave));
>  
> +	kfree(slave->slave_stats);
>  	kfree(slave);
>  }
>  
> @@ -1344,6 +1354,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
>  	}
>  
>  	slave_dev->priv_flags |= IFF_BONDING;
> +	/* initialize slave stats */
> +	dev_get_stats(new_slave->dev, new_slave->slave_stats);
>  
>  	if (bond_is_lb(bond)) {
>  		/* bond_alb_init_slave() must be called before all other stages since
> @@ -3085,38 +3097,43 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
>  	struct list_head *iter;
>  	struct slave *slave;
>  
> -	memset(stats, 0, sizeof(*stats));
> +	memcpy(stats, bond->bond_stats, sizeof(*stats));
>  
>  	bond_for_each_slave(bond, slave, iter) {
>  		const struct rtnl_link_stats64 *sstats =
>  			dev_get_stats(slave->dev, &temp);
> +		struct rtnl_link_stats64 *pstats = slave->slave_stats;
> +
> +		stats->rx_packets +=  sstats->rx_packets - pstats->rx_packets;
> +		stats->rx_bytes += sstats->rx_bytes - pstats->rx_bytes;
> +		stats->rx_errors += sstats->rx_errors - pstats->rx_errors;
> +		stats->rx_dropped += sstats->rx_dropped - pstats->rx_dropped;
>  
> -		stats->rx_packets += sstats->rx_packets;
> -		stats->rx_bytes += sstats->rx_bytes;
> -		stats->rx_errors += sstats->rx_errors;
> -		stats->rx_dropped += sstats->rx_dropped;
> +		stats->tx_packets += sstats->tx_packets - pstats->tx_packets;;
> +		stats->tx_bytes += sstats->tx_bytes - pstats->tx_bytes;
> +		stats->tx_errors += sstats->tx_errors - pstats->tx_errors;
> +		stats->tx_dropped += sstats->tx_dropped - pstats->tx_dropped;
>  
> -		stats->tx_packets += sstats->tx_packets;
> -		stats->tx_bytes += sstats->tx_bytes;
> -		stats->tx_errors += sstats->tx_errors;
> -		stats->tx_dropped += sstats->tx_dropped;
> +		stats->multicast += sstats->multicast - pstats->multicast;
> +		stats->collisions += sstats->collisions - pstats->collisions;
>  
> -		stats->multicast += sstats->multicast;
> -		stats->collisions += sstats->collisions;
> +		stats->rx_length_errors += sstats->rx_length_errors - pstats->rx_length_errors;
> +		stats->rx_over_errors += sstats->rx_over_errors - pstats->rx_over_errors;
> +		stats->rx_crc_errors += sstats->rx_crc_errors - pstats->rx_crc_errors;
> +		stats->rx_frame_errors += sstats->rx_frame_errors - pstats->rx_frame_errors;
> +		stats->rx_fifo_errors += sstats->rx_fifo_errors - pstats->rx_fifo_errors;
> +		stats->rx_missed_errors += sstats->rx_missed_errors - pstats->rx_missed_errors;
>  
> -		stats->rx_length_errors += sstats->rx_length_errors;
> -		stats->rx_over_errors += sstats->rx_over_errors;
> -		stats->rx_crc_errors += sstats->rx_crc_errors;
> -		stats->rx_frame_errors += sstats->rx_frame_errors;
> -		stats->rx_fifo_errors += sstats->rx_fifo_errors;
> -		stats->rx_missed_errors += sstats->rx_missed_errors;
> +		stats->tx_aborted_errors += sstats->tx_aborted_errors - pstats->tx_aborted_errors;
> +		stats->tx_carrier_errors += sstats->tx_carrier_errors - pstats->tx_carrier_errors;
> +		stats->tx_fifo_errors += sstats->tx_fifo_errors - pstats->tx_fifo_errors;
> +		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors - pstats->tx_heartbeat_errors;
> +		stats->tx_window_errors += sstats->tx_window_errors - pstats->tx_window_errors;
>  
> -		stats->tx_aborted_errors += sstats->tx_aborted_errors;
> -		stats->tx_carrier_errors += sstats->tx_carrier_errors;
> -		stats->tx_fifo_errors += sstats->tx_fifo_errors;
> -		stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
> -		stats->tx_window_errors += sstats->tx_window_errors;
> +		/* save off the slave stats for the next run */
> +		memcpy(pstats, sstats, sizeof(*sstats));
>  	}
> +	memcpy(bond->bond_stats, stats, sizeof(*stats));
>  
>  	return stats;
>  }
> @@ -3790,6 +3807,9 @@ static void bond_destructor(struct net_device *bond_dev)
>  	struct bonding *bond = netdev_priv(bond_dev);
>  	if (bond->wq)
>  		destroy_workqueue(bond->wq);
> +	if (bond->bond_stats)
> +		kfree(bond->bond_stats);
> +
>  	free_netdev(bond_dev);
>  }
>  
> @@ -4274,7 +4294,8 @@ unsigned int bond_get_num_tx_queues(void)
>  int bond_create(struct net *net, const char *name)
>  {
>  	struct net_device *bond_dev;
> -	int res;
> +	struct bonding *bond;
> +	int res = -ENOMEM;
>  
>  	rtnl_lock();
>  
> @@ -4286,8 +4307,15 @@ int bond_create(struct net *net, const char *name)
>  		rtnl_unlock();
>  		return -ENOMEM;
>  	}
> +	/* alloc persistent stats for the bond */
> +	bond = netdev_priv(bond_dev);
> +	bond->bond_stats = kzalloc(sizeof(struct rtnl_link_stats64),
> +				   GFP_KERNEL);
> +	if (!bond->bond_stats)
> +		printk(KERN_CRIT "Stats not available!\n");
>  
hi Andy:

why not return here, otherwise terrible things will happen, later other code will access this point directly.

Ding

>  	dev_net_set(bond_dev, net);
> +
>  	bond_dev->rtnl_link_ops = &bond_link_ops;
>  
>  	res = register_netdevice(bond_dev);
> diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
> index c13d83e..2fdcbe2 100644
> --- a/drivers/net/bonding/bond_netlink.c
> +++ b/drivers/net/bonding/bond_netlink.c
> @@ -381,10 +381,21 @@ static int bond_newlink(struct net *src_net, struct net_device *bond_dev,
>  			struct nlattr *tb[], struct nlattr *data[])
>  {
>  	int err;
> +	struct bonding *bond = netdev_priv(bond_dev);
> +
> +	/* alloc persistent stats for the bond if not already allocated */
> +	if (!bond->bond_stats) {
> +		bond->bond_stats = kzalloc(sizeof(struct rtnl_link_stats64),
> +					   GFP_KERNEL);
> +		if (!bond->bond_stats)
> +			return -ENOMEM;
> +	}
>  
>  	err = bond_changelink(bond_dev, tb, data);
> -	if (err < 0)
> +	if (err < 0) {
> +		kfree(bond->bond_stats);
>  		return err;
> +	}
>  
>  	return register_netdevice(bond_dev);
>  }
> diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
> index 6140bf0..fe25265 100644
> --- a/drivers/net/bonding/bonding.h
> +++ b/drivers/net/bonding/bonding.h
> @@ -24,6 +24,7 @@
>  #include <linux/inetdevice.h>
>  #include <linux/etherdevice.h>
>  #include <linux/reciprocal_div.h>
> +#include <linux/if_link.h>
>  
>  #include "bond_3ad.h"
>  #include "bond_alb.h"
> @@ -175,6 +176,7 @@ struct slave {
>  	struct netpoll *np;
>  #endif
>  	struct kobject kobj;
> +	struct rtnl_link_stats64 *slave_stats;
>  };
>  
>  /*
> @@ -224,6 +226,7 @@ struct bonding {
>  	/* debugging support via debugfs */
>  	struct	 dentry *debug_dir;
>  #endif /* CONFIG_DEBUG_FS */
> +	struct rtnl_link_stats64 *bond_stats;
>  };
>  
>  #define bond_slave_get_rcu(dev) \
> 

^ permalink raw reply

* RE: [PATCH 1/1] Drivers: net-next: hyperv: Fix a bug in netvsc_start_xmit()
From: KY Srinivasan @ 2014-09-29  3:51 UTC (permalink / raw)
  To: David Miller
  Cc: olaf@aepfle.de, netdev@vger.kernel.org, jasowang@redhat.com,
	linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	apw@canonical.com, devel@linuxdriverproject.org
In-Reply-To: <20140928.231647.1355757349883305047.davem@davemloft.net>



> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net]
> Sent: Sunday, September 28, 2014 8:17 PM
> To: KY Srinivasan
> Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; olaf@aepfle.de; apw@canonical.com;
> jasowang@redhat.com; stable@vger.kernel.org
> Subject: Re: [PATCH 1/1] Drivers: net-next: hyperv: Fix a bug in
> netvsc_start_xmit()
> 
> From: "K. Y. Srinivasan" <kys@microsoft.com>
> Date: Sun, 28 Sep 2014 19:49:51 -0700
> 
> > After the packet is successfully sent, we should not touch the skb as
> > it may have been freed. This patch is based on the work done by Long
> > Li <longli@microsoft.com>.
> >
> > Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> > Tested-by: Long Li <longli@microsoft.com>
> > Cc: <stable@vger.kernel.org>
> 
> You hyperv guys really have to get your act together.  This is not properly
> submitted.
> 
> Most importantly, this is a serious reference to free memory bug.
> Therefore it should be targetted at 'net' not 'net-next'.
> 
> Secondly, you do not CC: stable for networking changes, you instead ask me
> to queue it up for my next batch of -stable networking changes.
> 
> Thirdly, your Subject line is malformed.  You should not use
> "Drivers: " as a prefix.  Just the driver name is sufficient.
> You should also not mentionen the target GIT tree outside of the [PATCH ...]
> bracketed area.
> 
> Also, please be cognizant of how much of my time you unnecessarily
> consume when you make a malformed submission like this.  That is time I
> could spend reviewing other patches.

Sorry about that; I will resubmit this patch after addressing all the issues you have raised.

Regards,

K. Y

^ permalink raw reply

* [PATCH] net: Add ndo_gso_check
From: Tom Herbert @ 2014-09-29  3:50 UTC (permalink / raw)
  To: davem, netdev, gerlitz.or

Add ndo_gso_check which a device can define to indicate whether is
is capable of doing GSO on a packet. This funciton would be called from
the stack to determine whether software GSO is needed to be done. A
driver should populate this function if it advertises GSO types for
which there are combinations that it wouldn't be able to handle. For
instance a device that performs UDP tunneling might only implement
support for transparent Ethernet bridging type of inner packets
or might have limitations on lengths of inner headers.

Signed-off-by: Tom Herbert <therbert@google.com>
---
 include/linux/netdevice.h | 12 +++++++++++-
 net/core/dev.c            |  2 +-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9f5d293..f8c2027 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -997,6 +997,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *	Callback to use for xmit over the accelerated station. This
  *	is used in place of ndo_start_xmit on accelerated net
  *	devices.
+ * bool	(*ndo_gso_check) (struct sk_buff *skb,
+ *			  struct net_device *dev);
+ *	Called by core transmit path to determine if device is capable of
+ *	performing GSO on a packet. The device returns true if it is
+ *	able to GSO the packet, false otherwise. If the return value is
+ *	false the stack will do software GSO.
  */
 struct net_device_ops {
 	int			(*ndo_init)(struct net_device *dev);
@@ -1146,6 +1152,8 @@ struct net_device_ops {
 							struct net_device *dev,
 							void *priv);
 	int			(*ndo_get_lock_subclass)(struct net_device *dev);
+	bool			(*ndo_gso_check) (struct sk_buff *skb,
+						  struct net_device *dev);
 };
 
 /**
@@ -3536,10 +3544,12 @@ static inline bool skb_gso_ok(struct sk_buff *skb, netdev_features_t features)
 	       (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
 }
 
-static inline bool netif_needs_gso(struct sk_buff *skb,
+static inline bool netif_needs_gso(struct net_device *dev, struct sk_buff *skb,
 				   netdev_features_t features)
 {
 	return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
+		(dev->netdev_ops->ndo_gso_check &&
+		 !dev->netdev_ops->ndo_gso_check(skb, dev)) ||
 		unlikely((skb->ip_summed != CHECKSUM_PARTIAL) &&
 			 (skb->ip_summed != CHECKSUM_UNNECESSARY)));
 }
diff --git a/net/core/dev.c b/net/core/dev.c
index e2ced01..8c2b9bb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2680,7 +2680,7 @@ struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
 	if (skb->encapsulation)
 		features &= dev->hw_enc_features;
 
-	if (netif_needs_gso(skb, features)) {
+	if (netif_needs_gso(dev, skb, features)) {
 		struct sk_buff *segs;
 
 		segs = skb_gso_segment(skb, features);
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related

* Re: [PATCH 1/1] Drivers: net-next: hyperv: Fix a bug in netvsc_start_xmit()
From: David Miller @ 2014-09-29  3:16 UTC (permalink / raw)
  To: kys; +Cc: netdev, linux-kernel, devel, olaf, apw, jasowang, stable
In-Reply-To: <1411958991-28049-1-git-send-email-kys@microsoft.com>

From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Sun, 28 Sep 2014 19:49:51 -0700

> After the packet is successfully sent, we should not touch the skb as it may
> have been freed. This patch is based on the work done by
> Long Li <longli@microsoft.com>. 
> 
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Tested-by: Long Li <longli@microsoft.com>
> Cc: <stable@vger.kernel.org>

You hyperv guys really have to get your act together.  This is not
properly submitted.

Most importantly, this is a serious reference to free memory bug.
Therefore it should be targetted at 'net' not 'net-next'.

Secondly, you do not CC: stable for networking changes, you instead
ask me to queue it up for my next batch of -stable networking changes.

Thirdly, your Subject line is malformed.  You should not use
"Drivers: " as a prefix.  Just the driver name is sufficient.
You should also not mentionen the target GIT tree outside of the
[PATCH ...] bracketed area.

Also, please be cognizant of how much of my time you unnecessarily
consume when you make a malformed submission like this.  That is
time I could spend reviewing other patches.

Thank you.

^ permalink raw reply

* i40e nics are down when we use them on Dual CPU
From: Liu, Wei @ 2014-09-29  3:04 UTC (permalink / raw)
  To: netdev

Hi All,

When we use netperf to generate traffic, i40e nics are down very soon(
the throughput is about 76Gbps).

CPU: "Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz" X2

TOPO:
port5, port6, port11, port12 are i40e interfaces.
port6 and port12 are in a net namespace.
port5<--->port6: port5 is connected port6 directly.
port11<--->port12: port11 is connected port12 directly.

nics interrupt bind cpu:
port5: 0, 1, 2, 3, 4 (CPU0)
port6: 10, 11, 12, 13, 14 (CPU1)
port11: 5, 6, 7, 8, 9(CPU0)
port12: 15, 16, 17, 18, 19 (CPU1)

kernel: 3.13.11
driver: i40e stable
1.0.15(http://sourceforge.net/projects/e1000/files/i40e%20stable/1.0.15/):
version: 1.0.15
firmware-version: f4.1 a1.1 n04.10 e800010e0
bus-info: 0000:09:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no
We also tried latest kernel 3.16.3 (with its own driver), it has the same issue.

netperf cmd:
netperf -T 14,19 -L 15.3.2.1 -H 15.3.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 13,18 -L 15.5.2.1 -H 15.5.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 12,17 -L 15.2.2.1 -H 15.2.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 11,16 -L 15.1.2.1 -H 15.1.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 10,15 -L 15.4.2.1 -H 15.4.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 4,9 -L 14.4.2.1 -H 14.4.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 3,8 -L 14.1.2.1 -H 14.1.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 2,7 -L 14.5.2.1 -H 14.5.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 1,6 -L 14.2.2.1 -H 14.2.1.100 -f m -D 1 -l 600 >/dev/null &
netperf -T 0,5 -L 14.3.2.1 -H 14.3.1.100 -f m -D 1 -l 600 >/dev/null &

dmesg:
...
i40e 0000:09:00.1 port6: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
i40e 0000:09:00.0 port5: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
IPv6: ADDRCONF(NETDEV_CHANGE): port6: link becomes ready
IPv6: ADDRCONF(NETDEV_CHANGE): port5: link becomes ready
i40e 0000:8a:00.0 port11: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
i40e 0000:8a:00.1 port12: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
IPv6: ADDRCONF(NETDEV_CHANGE): port11: link becomes ready
IPv6: ADDRCONF(NETDEV_CHANGE): port12: link becomes ready
------------[ cut here ]------------
WARNING: at net/sched/sch_generic.c:254 dev_watchdog+0x174/0x1da()
Hardware name: To be filled by O.E.M.
NETDEV WATCHDOG: port5 (i40e): transmit queue 3 timed out
Modules linked in: khttpc(O) khttpd(O) i40e(O) ixgbe(O)
Pid: 883, comm: kworker/0:1 Tainted: G           O 3.8.4+ #1
Call Trace:
<IRQ>  [<ffffffff8022d914>] ? warn_slowpath_common+0x76/0x8a
[<ffffffff8022d96f>] ? warn_slowpath_fmt+0x47/0x49
[<ffffffff802373b5>] ? mod_timer+0x107/0x11b
[<ffffffff80549ec7>] ? dev_watchdog+0x174/0x1da
[<ffffffff80549d53>] ? dev_graft_qdisc+0x61/0x61
[<ffffffff802375e8>] ? call_timer_fn.isra.35+0x1c/0x6f
[<ffffffff8023779e>] ? run_timer_softirq+0x163/0x182
[<ffffffff80232f11>] ? __do_softirq+0xa0/0x13d
[<ffffffff8066260c>] ? call_softirq+0x1c/0x26
[<ffffffff802032b5>] ? do_softirq+0x2a/0x64
[<ffffffff8023306f>] ? irq_exit+0x3d/0x5a
[<ffffffff80218af2>] ? smp_apic_timer_interrupt+0x81/0x8d
[<ffffffff8066200a>] ? apic_timer_interrupt+0x6a/0x70
<EOI>  [<ffffffffa003e220>] ? i40e_do_reset_safe+0xcd2/0xd84 [i40e]
[<ffffffffa003dff5>] ? i40e_do_reset_safe+0xaa7/0xd84 [i40e]
[<ffffffff803af706>] ? delay_tsc+0x20/0x44
[<ffffffffa0042412>] ? i40e_asq_send_command+0x316/0x441 [i40e]
[<ffffffffa0043546>] ? i40e_aq_get_link_info+0x47/0x123 [i40e]
[<ffffffffa0043d64>] ? i40e_get_link_status+0x20/0x28 [i40e]
[<ffffffffa0036e45>] ? i40e_ioctl+0x1858/0x1a0b [i40e]
[<ffffffffa003e228>] ? i40e_do_reset_safe+0xcda/0xd84 [i40e]
[<ffffffff802370ca>] ? internal_add_timer+0xd/0x28
[<ffffffff802373b5>] ? mod_timer+0x107/0x11b
[<ffffffff8023f37e>] ? process_one_work+0x1d6/0x2d8
[<ffffffff8023f6a4>] ? worker_thread+0x201/0x2eb
[<ffffffff8023f4a3>] ? process_scheduled_works+0x23/0x23
[<ffffffff80243034>] ? kthread+0xa9/0xb1
[<ffffffff80242f8b>] ? kthread_stop+0x49/0x49
[<ffffffff8066146c>] ? ret_from_fork+0x7c/0xb0
[<ffffffff80242f8b>] ? kthread_stop+0x49/0x49
---[ end trace bdce93fbb0280b12 ]---
i40e 0000:09:00.0 port5: tx_timeout recovery level 1
i40e 0000:09:00.0: i40e_vsi_control_tx: VSI seid 518 Tx ring 3 disable timeout
i40e 0000:09:00.0: i40e_ptp_init: added PHC on port5
i40e 0000:09:00.0 port5: adding 00:90:0b:38:4f:7c vid=0
i40e 0000:09:00.0 port5: set fc fail, aq_err -7
i40e 0000:09:00.0 port5: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
i40e 0000:09:00.0 port5: NIC Link is Down
i40e 0000:09:00.1 port6: NIC Link is Down
i40e 0000:09:00.1 port6: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None
i40e 0000:09:00.0 port5: NIC Link is Up 40 Gbps Full Duplex, Flow Control: None

^ permalink raw reply

* [PATCH 1/1] Drivers: net-next: hyperv: Fix a bug in netvsc_start_xmit()
From: K. Y. Srinivasan @ 2014-09-29  2:49 UTC (permalink / raw)
  To: davem, netdev, linux-kernel, devel, olaf, apw, jasowang
  Cc: K. Y. Srinivasan, stable

After the packet is successfully sent, we should not touch the skb as it may
have been freed. This patch is based on the work done by
Long Li <longli@microsoft.com>. 

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Tested-by: Long Li <longli@microsoft.com>
Cc: <stable@vger.kernel.org>
---
 drivers/net/hyperv/netvsc_drv.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index a9c5eaa..0fcb5e7 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -387,6 +387,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 	int  hdr_offset;
 	u32 net_trans_info;
 	u32 hash;
+	u32 skb_length = skb->len;
 
 
 	/* We will atmost need two pages to describe the rndis
@@ -562,7 +563,7 @@ do_send:
 
 drop:
 	if (ret == 0) {
-		net->stats.tx_bytes += skb->len;
+		net->stats.tx_bytes += skb_length;
 		net->stats.tx_packets++;
 	} else {
 		kfree(packet);
-- 
1.7.4.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox