Netdev List
 help / color / mirror / Atom feed
* Re: [net-next, v2, 1/2] net: stmmac: Rework coalesce timer and fix multi-queue races
From: Neil Armstrong @ 2018-09-10 13:46 UTC (permalink / raw)
  To: Jose Abreu, netdev
  Cc: Jerome Brunet, Martin Blumenstingl, David S. Miller, Joao Pinto,
	Giuseppe Cavallaro, Alexandre Torgue
In-Reply-To: <ffed5dd1-cded-eab3-c7b3-4502a3b85095@synopsys.com>

hi Jose,

On 10/09/2018 14:55, Jose Abreu wrote:
> On 10-09-2018 13:52, Jose Abreu wrote:
>>
>> Can you please try attached follow-up patch ? 
> 
> Oh, please apply the whole series otherwise this will not apply
> cleanly.

Indeed, it helps!

With the fixups, it fails later, around 15s instead of 3, in RX and TX.

Neil

> 
> Thanks and Best Regards,
> Jose Miguel Abreu
> 
> 

^ permalink raw reply

* Re: [PATCH 2/5] include: add setbits32/clrbits32/clrsetbits32/setbits64/clrbits64/clrsetbits64 in linux/setbits.h
From: LABBE Corentin @ 2018-09-10 18:49 UTC (permalink / raw)
  To: Scott Wood
  Cc: Gilles.Muller, Julia.Lawall, agust, alexandre.torgue, alistair,
	benh, carlo, davem, galak, joabreu, khilman, maxime.ripard,
	michal.lkml, mpe, mporter, nicolas.palix, paulus, peppe.cavallaro,
	tj, vitb, wens, cocci, linux-amlogic, linux-arm-kernel, linux-ide,
	linux-kernel, linuxppc-dev, netdev, linux-sunxi
In-Reply-To: <8bfa1740800ca494028350addd7c874a8b4804bb.camel@buserror.net>

On Fri, Sep 07, 2018 at 03:00:40PM -0500, Scott Wood wrote:
> On Fri, 2018-09-07 at 19:41 +0000, Corentin Labbe wrote:
> > This patch adds setbits32/clrbits32/clrsetbits32 and
> > setbits64/clrbits64/clrsetbits64 in linux/setbits.h header.
> > 
> > Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
> > ---
> >  include/linux/setbits.h | 55
> > +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 55 insertions(+)
> >  create mode 100644 include/linux/setbits.h
> > 
> > diff --git a/include/linux/setbits.h b/include/linux/setbits.h
> > new file mode 100644
> > index 000000000000..3e1e273551bb
> > --- /dev/null
> > +++ b/include/linux/setbits.h
> > @@ -0,0 +1,55 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef __LINUX_SETBITS_H
> > +#define __LINUX_SETBITS_H
> > +
> > +#include <linux/io.h>
> > +
> > +#define __setbits(readfunction, writefunction, addr, set) \
> > +	writefunction((readfunction(addr) | (set)), addr)
> > +#define __clrbits(readfunction, writefunction, addr, mask) \
> > +	writefunction((readfunction(addr) & ~(mask)), addr)
> > +#define __clrsetbits(readfunction, writefunction, addr, mask, set) \
> > +	writefunction(((readfunction(addr) & ~(mask)) | (set)), addr)
> > +#define __setclrbits(readfunction, writefunction, addr, mask, set) \
> > +	writefunction(((readfunction(addr) | (seti)) & ~(mask)), addr)
> > +
> > +#define setbits32(addr, set) __setbits(readl, writel, addr, set)
> > +#define setbits32_relaxed(addr, set) __setbits(readl_relaxed,
> > writel_relaxed, \
> > +					       addr, set)
> > +
> > +#define clrbits32(addr, mask) __clrbits(readl, writel, addr, mask)
> > +#define clrbits32_relaxed(addr, mask) __clrbits(readl_relaxed,
> > writel_relaxed, \
> > +						addr, mask)
> 
> So now setbits32/clrbits32 is implicitly little-endian?  Introducing new
> implicit-endian accessors is probably a bad thing in general, but doing it
> with a name that until this patchset was implicitly big-endian (at least on
> powerpc) seems worse.  Why not setbits32_le()?
> 

I believed that writel/readl was endian agnostic, but It seems that I was wrong.
So I will use _le32.

> 
> > +
> > +#define clrsetbits32(addr, mask, set) __clrsetbits(readl, writel, addr,
> > mask, set)
> > +#define clrsetbits32_relaxed(addr, mask, set) __clrsetbits(readl_relaxed, \
> > +							   writel_relaxed,
> > \
> > +							   addr, mask, set)
> > +
> > +#define setclrbits32(addr, mask, set) __setclrbits(readl, writel, addr,
> > mask, set)
> > +#define setclrbits32_relaxed(addr, mask, set) __setclrbits(readl_relaxed, \
> > +							   writel_relaxed,
> > \
> > +							   addr, mask, set)
> 
> What's the use case for setclrbits?  I don't see it used anywhere in this
> patchset (not even in the coccinelle patterns), it doesn't seem like it would
> be a common pattern, and it could easily get confused with clrsetbits.
> 

It is absent from the coccinelle script due to copy/paste error.
And absent from patchset since it is only two possible example that I can test.

If you run the next fixed coccinelle script, you will find some setclrbits.
Since I fear that mask and set could have some common bits sometimes, I prefer to keep separate clrsetbits and setclrbits.

Regards

^ permalink raw reply

* Re: [PATCH 1/5] powerpc: rename setbits32/clrbits32 to setbits32_be/clrbits32_be
From: LABBE Corentin @ 2018-09-10 18:50 UTC (permalink / raw)
  To: Christophe LEROY
  Cc: Gilles.Muller, Julia.Lawall, agust, alexandre.torgue, alistair,
	benh, carlo, davem, galak, joabreu, khilman, maxime.ripard,
	michal.lkml, mpe, mporter, nicolas.palix, oss, paulus,
	peppe.cavallaro, tj, vitb, wens, netdev, linux-kernel, linux-ide,
	linux-sunxi, linux-amlogic, linuxppc-dev, cocci, linux-arm-kernel
In-Reply-To: <d16bf608-5b97-4baf-2ac1-a6d98656d716@c-s.fr>

On Mon, Sep 10, 2018 at 07:16:56AM +0200, Christophe LEROY wrote:
> 
> 
> Le 07/09/2018 à 21:41, Corentin Labbe a écrit :
> > Since setbits32/clrbits32 work on be32, it's better to remove ambiguity on
> > the used data type.
> 
> Wouldn't it be better to call them setbits_be32() / clrbits_be32() to 
> have something looking similar to in_be32() / ou_be32() ?
> 

I agree, I will update the patch.

Thanks

^ permalink raw reply

* Re: [PATCH 2/5] include: add setbits32/clrbits32/clrsetbits32/setbits64/clrbits64/clrsetbits64 in linux/setbits.h
From: LABBE Corentin @ 2018-09-10 18:53 UTC (permalink / raw)
  To: Christophe LEROY
  Cc: Gilles.Muller, Julia.Lawall, agust, alexandre.torgue, alistair,
	benh, carlo, davem, galak, joabreu, khilman, maxime.ripard,
	michal.lkml, mpe, mporter, nicolas.palix, oss, paulus,
	peppe.cavallaro, tj, vitb, wens, netdev, linux-kernel, linux-ide,
	linux-sunxi, linux-amlogic, linuxppc-dev, cocci, linux-arm-kernel
In-Reply-To: <a1795266-5679-289d-5cce-1111babf3180@c-s.fr>

On Mon, Sep 10, 2018 at 07:22:04AM +0200, Christophe LEROY wrote:
> 
> 
> Le 07/09/2018 à 21:41, Corentin Labbe a écrit :
> > This patch adds setbits32/clrbits32/clrsetbits32 and
> > setbits64/clrbits64/clrsetbits64 in linux/setbits.h header.
> 
> So you changed the name of setbits32() ... to setbits32_be() and now you 
> are adding new functions called setbits32() ... which do something 
> different ?
> 
> What will happen if any file has been forgotten during the conversion, 
> or if anybody has outoftree drivers and missed this change ?
> They will silently successfully compile without any error or warning, 
> and the result will be crap buggy.
> 
> And why would it be more legitim to have setbits32() be implicitely LE 
> instead of implicitely BE ?
> 
> I really think those new functions should be called something like 
> setbits_le32() ...
> 

I believed that writel/readl was endian agnostic so it explain my mistake.

I will use xxxbits_le32 as you requests.

Thanks
Regards

^ permalink raw reply

* Re: [PATCH net-next v3 2/7] net: aquantia: definitions for WOL
From: Andrew Lunn @ 2018-09-10 14:08 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, netdev, Yana Esina, Nikita Danilov
In-Reply-To: <a686a7557c50a9171dd3bf80e4e6494becafc232.1536572107.git.igor.russkikh@aquantia.com>

On Mon, Sep 10, 2018 at 12:39:29PM +0300, Igor Russkikh wrote:
> From: Yana Esina <yana.esina@aquantia.com>
> 
> Added definitions and structures needed to support WOL.
> 
> Signed-off-by: Yana Esina <yana.esina@aquantia.com>
> Signed-off-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Tested-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH net-next v3 3/7] net: aquantia: implement WOL support
From: Andrew Lunn @ 2018-09-10 14:09 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, netdev, Yana Esina, Nikita Danilov
In-Reply-To: <62221cd36d7ff20a2218e02ba901c6107020e048.1536572107.git.igor.russkikh@aquantia.com>

On Mon, Sep 10, 2018 at 12:39:30PM +0300, Igor Russkikh wrote:
> From: Yana Esina <yana.esina@aquantia.com>
> 
> Add WOL support. Currently only magic packet
> (ethtool -s <ethX> wol g) feature is implemented.
> 
> Remove hw_set_power and move that to FW_OPS set_power:
> because WOL configuration behaves differently on 1x and 2x
> firmwares
> 
> Signed-off-by: Yana Esina <yana.esina@aquantia.com>
> Signed-off-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Tested-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH net-next v3 4/7] net: aquantia: implement EEE support
From: Andrew Lunn @ 2018-09-10 14:09 UTC (permalink / raw)
  To: Igor Russkikh; +Cc: David S . Miller, netdev, Yana Esina, Nikita Danilov
In-Reply-To: <fa9136b460dea9399bf33b93444726d684973eec.1536572107.git.igor.russkikh@aquantia.com>

On Mon, Sep 10, 2018 at 12:39:31PM +0300, Igor Russkikh wrote:
> From: Yana Esina <yana.esina@aquantia.com>
> 
> Support of Energy-Efficient Ethernet to aQuantia NIC's via ethtool
> (according to the IEEE 802.3az specifications)
> 
> Signed-off-by: Yana Esina <yana.esina@aquantia.com>
> Signed-off-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Tested-by: Nikita Danilov <nikita.danilov@aquantia.com>
> Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH net] qmi_wwan: Support dynamic config on Quectel EP06
From: Dan Williams @ 2018-09-10 14:42 UTC (permalink / raw)
  To: Bjørn Mork, Kristian Evensen; +Cc: netdev
In-Reply-To: <87musst6wo.fsf@miraculix.mork.no>

On Sat, 2018-09-08 at 16:12 +0200, Bjørn Mork wrote:
> Kristian Evensen <kristian.evensen@gmail.com> writes:
> 
> > Quectel EP06 (and EM06/EG06) supports dynamic configuration of USB
> > interfaces, without the device changing VID/PID or configuration
> > number.
> > When the configuration is updated and interfaces are added/removed,
> > the
> > interface numbers change. This means that the current code for
> > matching
> > EP06 does not work.
> 
> That's annoying, but hardly surprising. They obviously try to make
> life
> as hard as possible for the drivers.  I wonder what the Windows
> drivers
> do here, if there are any?  Or are these modules only used in
> embedded
> Linux devices?
> 
> > This patch removes the current EP06 interface number match, and
> > replaces
> > it with a match on class, subclass and protocol. Unfortunately,
> > matching
> > on those three alone is not enough, as the diag interface exports
> > the
> > same values as QMI. The other serial interfaces + adb export
> > different
> > values and do not match.
> > 
> > The diag interface only has two endpoints, while the QMI interface
> > has
> > three. I have therefore added a check for number of interfaces, and
> > we
> > ignore the interface if the number of endpoints equals two.
> 
> Could this break if more/other functions are enabled?  Are you sure
> there can't be any other type of serial function with 3 endpoints and
> ff/ff/ff?  Well, I guess no one knows for sure... And this is more
> than
> good enough until it breaks. Thanks for solving the puzzle.  Looks
> good
> to me.

I'm sure they could add another serial interface with ff/ff/ff and 3
endpoints, but I don't know what else we can do to make this device
work correctly.  I double-checked the permutations & logic and it makes
sense to me.

Acked-by: Dan Williams <dcbw@redhat.com>

Dan

^ permalink raw reply

* Re: [net-next, v2, 1/2] net: stmmac: Rework coalesce timer and fix multi-queue races
From: Jose Abreu @ 2018-09-10 14:44 UTC (permalink / raw)
  To: Neil Armstrong, Jose Abreu, netdev
  Cc: Jerome Brunet, Martin Blumenstingl, David S. Miller, Joao Pinto,
	Giuseppe Cavallaro, Alexandre Torgue
In-Reply-To: <2f7c89f1-3416-2327-8158-67c318c62214@baylibre.com>

[-- Attachment #1: Type: text/plain, Size: 569 bytes --]

On 10-09-2018 14:46, Neil Armstrong wrote:
> hi Jose,
>
> On 10/09/2018 14:55, Jose Abreu wrote:
>> On 10-09-2018 13:52, Jose Abreu wrote:
>>> Can you please try attached follow-up patch ? 
>> Oh, please apply the whole series otherwise this will not apply
>> cleanly.
> Indeed, it helps!
>
> With the fixups, it fails later, around 15s instead of 3, in RX and TX.

Thanks for testing Neil. What if we keep rearming the timer
whilst there are pending packets ? Something like in the attach.
(applies on top of previous one).

Thanks and Best Regards,
Jose Miguel Abreu

[-- Attachment #2: 0001-fixup_coalesce_2.patch --]
[-- Type: text/x-patch, Size: 1130 bytes --]

>From 5d5a6bd882006f14c59b351f4324160115f818c0 Mon Sep 17 00:00:00 2001
Message-Id: <5d5a6bd882006f14c59b351f4324160115f818c0.1536590220.git.joabreu@synopsys.com>
From: Jose Abreu <joabreu@synopsys.com>
Date: Mon, 10 Sep 2018 16:36:37 +0200
Subject: [PATCH] fixup_coalesce_2

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7875e81966fb..76a6196b3263 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2262,9 +2262,12 @@ static void stmmac_tx_timer(struct timer_list *t)
 {
 	struct stmmac_tx_queue *tx_q = from_timer(tx_q, t, txtimer);
 	struct stmmac_priv *priv = tx_q->priv_data;
+	bool more;
 
-	stmmac_tx_clean(priv, ~0, tx_q->queue_index, NULL);
 	tx_q->tx_timer_active = false;
+	stmmac_tx_clean(priv, ~0, tx_q->queue_index, &more);
+	if (more)
+		stmmac_tx_timer_arm(priv, tx_q->queue_index);
 }
 
 /**
-- 
2.7.4


^ permalink raw reply related

* unexpected GRO/veth behavior
From: Paolo Abeni @ 2018-09-10 14:44 UTC (permalink / raw)
  To: netdev; +Cc: eric.dumazet, Toshiaki Makita

hi all,

while testing some local patches I observed that the TCP tput in the
following scenario:

# the following enable napi on veth0, so that we can trigger the
# GRO path with namespaces
ip netns add test
ip link add type veth
ip link set dev veth0 netns test
ip -n test link set lo up
ip -n test link set veth0 up
ip -n test addr add dev veth0 172.16.1.2/24
ip link set dev veth1 up
ip addr add dev veth1 172.16.1.1/24
IDX=`ip netns exec test cat /sys/class/net/veth0/ifindex`

# 'xdp_pass' is a NO-OP XDP program that simply return XDP_PASS
ip netns exec test ./xdp_pass $IDX &
taskset 0x2 ip netns exec test iperf3 -s -i 60 &
taskset 0x1 iperf3 -c 172.16.1.2 -t 60 -i 60

is quite lower than expected (~800Mbps). 'perf' shows a weird topmost 
offender:

  80.42%  [kernel]           [k] find_bug

I *think* skb_gro_receive() does not behave correctly if !skb->sk, and
I experimented with the following patch, so far with success (in the
above scenario tput is now ~11Gbps). Am I missing something? it that
overkill?

Thank you,

Paolo

---
diff --git a/net/core/dev.c b/net/core/dev.c
index ca78dc5..94723b1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5554,6 +5554,11 @@ struct packet_offload *gro_find_complete_by_type(__be16 type)
 
 static void napi_skb_free_stolen_head(struct sk_buff *skb)
 {
+	if (skb->destructor) {
+		WARN_ON(in_irq());
+		skb->destructor(skb);
+	}
+
 	skb_dst_drop(skb);
 	secpath_reset(skb);
 	kmem_cache_free(skbuff_head_cache, skb);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c996c09..19f2fd9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3827,6 +3827,7 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
 	unsigned int offset = skb_gro_offset(skb);
 	unsigned int headlen = skb_headlen(skb);
 	unsigned int len = skb_gro_len(skb);
+	unsigned int new_skb_truesize;
 	unsigned int delta_truesize;
 	struct sk_buff *lp;
 
@@ -3858,11 +3859,13 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
 		frag->page_offset += offset;
 		skb_frag_size_sub(frag, offset);
 
-		/* all fragments truesize : remove (head size + sk_buff) */
-		delta_truesize = skb->truesize -
-				 SKB_TRUESIZE(skb_end_offset(skb));
+		/* all fragments truesize : remove (head size + sk_buff);
+		 * keep unchanged the amount of memory accounted to skb->sk
+		 */
+		new_skb_truesize = SKB_TRUESIZE(skb_end_offset(skb));
+		delta_truesize = skb->truesize - new_skb_truesize;
 
-		skb->truesize -= skb->data_len;
+		skb->truesize -= new_skb_truesize;
 		skb->len -= skb->data_len;
 		skb->data_len = 0;
 
@@ -3891,12 +3894,24 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb)
 		memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags);
 		/* We dont need to clear skbinfo->nr_frags here */
 
-		delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff));
+		/* keep unchanged the amount of memory accounted to skb->sk */
+		new_skb_truesize = SKB_DATA_ALIGN(sizeof(struct sk_buff));
+		delta_truesize = skb->truesize - new_skb_truesize;
+		skb->truesize = new_skb_truesize;
 		NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD;
 		goto done;
 	}
 
 merge:
+	if (skb->destructor) {
+		/* skb's truesize onwership is transferred to p, avoid
+		 * releasing it twice when p is freed
+		 */
+		WARN_ON_ONCE(p->sk != skb->sk || p->destructor != skb->destructor);
+		skb->sk = 0;
+		skb->destructor = NULL;
+	}
+
 	delta_truesize = skb->truesize;
 	if (offset > headlen) {
 		unsigned int eat = offset - headlen;

^ permalink raw reply related

* Re: unexpected GRO/veth behavior
From: Eric Dumazet @ 2018-09-10 14:56 UTC (permalink / raw)
  To: Paolo Abeni, netdev; +Cc: eric.dumazet, Toshiaki Makita
In-Reply-To: <4106d3f7eee7f0186fcfdd0331cdafeecd3240c0.camel@redhat.com>



On 09/10/2018 07:44 AM, Paolo Abeni wrote:
> hi all,
> 
> while testing some local patches I observed that the TCP tput in the
> following scenario:
> 
> # the following enable napi on veth0, so that we can trigger the
> # GRO path with namespaces
> ip netns add test
> ip link add type veth
> ip link set dev veth0 netns test
> ip -n test link set lo up
> ip -n test link set veth0 up
> ip -n test addr add dev veth0 172.16.1.2/24
> ip link set dev veth1 up
> ip addr add dev veth1 172.16.1.1/24
> IDX=`ip netns exec test cat /sys/class/net/veth0/ifindex`
> 
> # 'xdp_pass' is a NO-OP XDP program that simply return XDP_PASS
> ip netns exec test ./xdp_pass $IDX &
> taskset 0x2 ip netns exec test iperf3 -s -i 60 &
> taskset 0x1 iperf3 -c 172.16.1.2 -t 60 -i 60
> 
> is quite lower than expected (~800Mbps). 'perf' shows a weird topmost 
> offender:
>


But... why GRO would even be needed in this scenario ?

GRO is really meant for physical devices, having to mess with skb->sk adds extra cost
in this already heavy cost engine.

Virtual devices should already be fed with TSO packets.

^ permalink raw reply

* Re: [PATCH] PCI: Reprogram bridge prefetch registers on resume
From: Thomas Martitz @ 2018-09-10 19:57 UTC (permalink / raw)
  To: Daniel Drake, bhelgaas-hpIqsD4AKlfQT0dZR+AlfA
  Cc: nic_swsd-Rasf1IRRPZFBDgjK7y7TUQ,
	mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	keith.busch-ral2JQCrhuEAvxtiuMwx3w, netdev-u79uwXL29TY76Z2rM5mHXA,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
	linux-6IF/jdPJHihWk0Htik3J/w, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	jonathan.derrick-ral2JQCrhuEAvxtiuMwx3w,
	hkallweit1-Re5JQEeQqe8AvxtiuMwx3w
In-Reply-To: <20180907053614.6540-1-drake-6IF/jdPJHihWk0Htik3J/w@public.gmane.org>

Hello Daniel,

Am 07.09.18 um 07:36 schrieb Daniel Drake:
> On 38+ Intel-based Asus products, the nvidia GPU becomes unusable
> after S3 suspend/resume. The affected products include multiple
> generations of nvidia GPUs and Intel SoCs. After resume, nouveau logs
> many errors such as:
> 
>      fifo: fault 00 [READ] at 0000005555555000 engine 00 [GR] client 04 [HUB/FE] reason 4a [] on channel -1 [007fa91000 unknown]
>      DRM: failed to idle channel 0 [DRM]
> 
> Similarly, the nvidia proprietary driver also fails after resume
> (black screen, 100% CPU usage in Xorg process). We shipped a sample
> to Nvidia for diagnosis, and their response indicated that it's a
> problem with the parent PCI bridge (on the Intel SoC), not the GPU.
> 
> Runtime suspend/resume works fine, only S3 suspend is affected.
> 
> We found a workaround: on resume, rewrite the Intel PCI bridge
> 'Prefetchable Base Upper 32 Bits' register (PCI_PREF_BASE_UPPER32). In
> the cases that I checked, this register has value 0 and we just have to
> rewrite that value.
> 
> It's very strange that rewriting the exact same register value
> makes a difference, but it definitely makes the issue go away.
> It's not just acting as some kind of memory barrier, because rewriting
> other bridge registers does not work around the issue. There's something
> magic in this particular register. We have confirmed this on all
> the affected models we have in-hands (X542UQ, UX533FD, X530UN, V272UN).
> 
> Additionally, this workaround solves an issue where r8169 MSI-X
> interrupts were broken after S3 suspend/resume on Asus X441UAR. This
> issue was recently worked around in commit 7bb05b85bc2d ("r8169:
> don't use MSI-X on RTL8106e"). It also fixes the same issue on
> RTL6186evl/8111evl on an Aimfor-tech laptop that we had not yet
> patched. I suspect it will also fix the issue that was worked around in
> commit 7c53a722459c ("r8169: don't use MSI-X on RTL8168g").
> 
> Thomas Martitz reports that this workaround also solves an issue where
> the AMD Radeon Polaris 10 GPU on the HP Zbook 14u G5 is unresponsive
> after S3 suspend/resume.


I can confirm that this exact patch also helps on my HP Zbook. Thanks 
for your work on this, resume has been a real pain until now.



> 
>   drivers/pci/pci-driver.c | 14 ++++++++++++++
>   drivers/pci/setup-bus.c  |  2 +-
>   include/linux/pci.h      |  1 +
>   3 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index bef17c3fca67..034f816570ad 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -524,6 +524,20 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
>   	pci_power_up(pci_dev);
>   	pci_restore_state(pci_dev);
>   	pci_pme_restore(pci_dev);
> +
> +	/*
> +	 * Redo the PCI bridge prefetch register setup.
> +	 *
> +	 * This works around an Intel PCI bridge issue seen on Asus and HP
> +	 * laptops, where the GPU is not usable after S3 resume.
> +	 * Even though PCI bridge register contents appear to be intact
> +	 * at resume time, rewriting the value of PREF_BASE_UPPER32 is
> +	 * required to make the GPU work.
> +	 * Windows 10 also reprograms these registers during S3 resume.
> +	 */
> +	if (pci_dev->class == PCI_CLASS_BRIDGE_PCI << 8)
> +		pci_setup_bridge_mmio_pref(pci_dev);
> +
>   	pci_fixup_device(pci_fixup_resume_early, pci_dev);
>   }
>   
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index 79b1824e83b4..cb88288d2a69 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -630,7 +630,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
>   	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
>   }
>   
> -static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
> +void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
>   {
>   	struct resource *res;
>   	struct pci_bus_region region;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index e72ca8dd6241..b15828fc26a4 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -934,6 +934,7 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn);
>   void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
>   unsigned int pci_scan_child_bus(struct pci_bus *bus);
>   void pci_bus_add_device(struct pci_dev *dev);
> +void pci_setup_bridge_mmio_pref(struct pci_dev *bridge);
>   void pci_read_bridge_bases(struct pci_bus *child);
>   struct resource *pci_find_parent_resource(const struct pci_dev *dev,
>   					  struct resource *res);
> 

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply

* Re: [PATCH] cxgb4: fix abort_req_rss6 struct
From: Steve Wise @ 2018-09-10 15:16 UTC (permalink / raw)
  To: Jason Gunthorpe; +Cc: netdev, dledford, davem, linux-rdma
In-Reply-To: <20180905225555.GA3775@ziepe.ca>


(sorry for the late reply, I was out all last week)


On 9/5/2018 5:55 PM, Jason Gunthorpe wrote:
> On Fri, Aug 31, 2018 at 11:52:00AM -0700, Steve Wise wrote:
>> Remove the incorrect WR_HDR field which can cause a misinterpretation
>> of this CPL by ULDs.
> 
> What does that mean?
> 

It means iw_cxgb4 doesn't correctly handle incoming ABORT CPL messages
due to this incorrect struct.


> Is this an -rc patch?
> 

Yes. Since it fixes a3cdaa69e4ae ("cxgb4: Adds CPL support for Shared
Receive Queues") which went into 4.19.

Steve.

^ permalink raw reply

* [PATCH 1/2] dt-bindings: can: tcan4x5x: Add DT bindings for TCAN4x5X driver
From: Dan Murphy @ 2018-09-10 20:12 UTC (permalink / raw)
  To: wg, mkl, davem; +Cc: linux-can, netdev, linux-kernel, Dan Murphy

DT binding documentation for TI TCAN4x5x driver.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
 .../devicetree/bindings/net/can/tcan4x5x.txt  | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/can/tcan4x5x.txt

diff --git a/Documentation/devicetree/bindings/net/can/tcan4x5x.txt b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
new file mode 100644
index 000000000000..3eea2f2bb8a7
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/tcan4x5x.txt
@@ -0,0 +1,33 @@
+Texas Instruments TCAN4x5x CAN Controller
+================================================
+
+This file provides device node information for the TCAN4x5x interface contains.
+
+Required properties:
+	- compatible: "ti,tcan4x5x"
+	- reg: 0
+	- #address-cells : 1
+	- #size-cells : 0
+	- spi-max-frequency: Maximum frequency of the SPI bus the chip can
+			     operate at should be less than or equal to 18 MHz.
+	- data-ready-gpios: Interrupt GPIO for data and error reporting. 
+	- wake-up-gpios: Wake up GPIO to wake up the TCAN device
+
+Optional properties:
+	- clocks: Processor clock phandles (see clock bindings for details)
+		  If no clock is defined then the default 40MHz freq is set.
+	- reset-gpios: Hardwired output GPIO. If not defined then software
+		       reset.
+
+Example:
+tcan4x5x: tcan4x5x@0 {
+		compatible = "ti,tcan4x5x";
+		reg = <0>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		clocks = <&tclkin_ck>;
+		spi-max-frequency = <10000000>;
+		data-ready-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
+		wake-up-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
+		reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
+	};
-- 
2.17.0.1855.g63749b2dea

^ permalink raw reply related

* [PATCH 2/2] can: tcan4x5x: Add tcan4x5x driver to the kernel
From: Dan Murphy @ 2018-09-10 20:12 UTC (permalink / raw)
  To: wg, mkl, davem; +Cc: linux-can, netdev, linux-kernel, Dan Murphy
In-Reply-To: <20180910201241.24092-1-dmurphy@ti.com>

Add the TCAN4x5x SPI CAN driver.  This device
uses the Bosch MCAN IP core along with a SPI
interface map.  The register and data are
32 bits wide.

Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
 drivers/net/can/spi/Kconfig    |    5 +
 drivers/net/can/spi/Makefile   |    1 +
 drivers/net/can/spi/tcan4x5x.c | 1206 ++++++++++++++++++++++++++++++++
 drivers/net/can/spi/tcan4x5x.h |  109 +++
 4 files changed, 1321 insertions(+)
 create mode 100644 drivers/net/can/spi/tcan4x5x.c
 create mode 100644 drivers/net/can/spi/tcan4x5x.h

diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 8f2e0dd7b756..8cac6ce37506 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -13,4 +13,9 @@ config CAN_MCP251X
 	---help---
 	  Driver for the Microchip MCP251x SPI CAN controllers.
 
+config CAN_TCAN4X5X
+	tristate "Texas Instruments TCAN4X5X SPI CAN controllers"
+	depends on HAS_DMA
+	---help---
+	  Driver for the Texas Instruments TCAN4X5X SPI CAN controllers.
 endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index f59fa3731073..8ecaace7a920 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_CAN_HI311X)	+= hi311x.o
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
+obj-$(CONFIG_CAN_TCAN4X5X)	+= tcan4x5x.o
diff --git a/drivers/net/can/spi/tcan4x5x.c b/drivers/net/can/spi/tcan4x5x.c
new file mode 100644
index 000000000000..ca3753efe35a
--- /dev/null
+++ b/drivers/net/can/spi/tcan4x5x.c
@@ -0,0 +1,1206 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPI to CAN driver for the Texas Instruments TCAN4x5x
+// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+
+#include <linux/can/core.h>
+#include <linux/can/dev.h>
+#include <linux/can/led.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/uaccess.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+
+#include "tcan4x5x.h"
+
+#define DEVICE_NAME "tcan4x5x"
+#define TCAN4X5X_EXT_CLK_DEF	40000000
+
+#define TCAN4X5X_CLEAR_ALL_INT	0xffffffff
+#define TCAN4X5X_SET_ALL_INT	0xffffffff
+
+#define TCAN4X5X_TX_ECHO_SKB_MAX 1
+#define TCAN4X5X_DATA_PKT_OFF	2
+#define TCAN4X5X_WRITE_CMD	(0x61 << 24)
+#define TCAN4X5X_READ_CMD	(0x41 << 24)
+
+#define TCAN4X5X_SID_SHIFT	18
+#define TCAN4X5X_DLC_SHIFT	16
+
+#define TCAN4X5X_ESI_SHIFT	31
+#define TCAN4X5X_XTD_SHIFT	30
+#define TCAN4X5X_RTR_SHIFT	29
+#define TCAN4X5X_FDF_SHIFT	21
+#define TCAN4X5X_BRS_SHIFT	20
+#define TCAN4X5X_DLC_SHIFT	16
+
+#define TCAN4X5X_ESI_MASK	BIT(31)
+#define TCAN4X5X_XTD_MASK	BIT(30)
+#define TCAN4X5X_RTR_MASK	BIT(29)
+
+#define TCAN4X5X_DLC_MASK	0xf0000
+#define TCAN4X5X_SW_RESET	BIT(2)
+
+#define TCAN4X5X_MODE_SEL_MASK		(BIT(7) | BIT(6))
+#define TCAN4X5X_MODE_SLEEP		0x00
+#define TCAN4X5X_MODE_STANDBY		BIT(6)
+#define TCAN4X5X_MODE_NORMAL		BIT(7)
+#define TCAN4X5X_MCAN_CONFIGURED	BIT(5)
+#define TCAN4X5X_WATCHDOG_EN		BIT(3)
+#define TCAN4X5X_WD_60_MS_TIMER		0
+#define TCAN4X5X_WD_600_MS_TIMER	BIT(28)
+#define TCAN4X5X_WD_3_S_TIMER		BIT(29)
+#define TCAN4X5X_WD_6_S_TIMER		(BIT(28) | BIT(29))
+
+/* Nominal Bit Timing & Prescaler Register */
+#define TCAN4X5X_NSJW_SHIFT	25
+#define TCAN4X5X_NBRP_SHIFT	16
+#define TCAN4X5X_NTSEG1_SHIFT	8
+
+#define TCAN4X5X_TDCR_TDCO_SHIFT	8
+
+/* Data Bit Timing & Prescaler Register (DBTP) */
+#define DBTP_TDC		BIT(23)
+#define DBTP_DBRP_SHIFT		16
+#define DBTP_DBRP_MASK		(0x1f << DBTP_DBRP_SHIFT)
+#define DBTP_DTSEG1_SHIFT	8
+#define DBTP_DTSEG1_MASK	(0x1f << DBTP_DTSEG1_SHIFT)
+#define DBTP_DTSEG2_SHIFT	4
+#define DBTP_DTSEG2_MASK	(0xf << DBTP_DTSEG2_SHIFT)
+#define DBTP_DSJW_SHIFT		0
+#define DBTP_DSJW_MASK		(0xf << DBTP_DSJW_SHIFT)
+
+#define TCAN4x5x_QUEUE_LVL_MASK		0x1f
+#define TCAN4x5x_QUEUE_IDX_SHIFT	16
+#define TCAN4x5x_QUEUE_IDX_MASK		0x1f00
+
+#define TCAN4X5X_CANBUSNOM_INT_EN	BIT(14)
+
+#define TCAN4X5X_NUM_TX_BUF	5
+#define TCAN4X5X_TX_QUEUE_SHIFT	24
+#define TCAN4X5X_TX_NDTB_SHIFT	16
+#define TCAN4X5X_TX_BUF_START	0x324
+
+#define TCAN4X5X_NUM_RX_BUF		3
+#define TCAN4X5X_RX_WATER_MARK		2
+#define TCAN4X5X_RX_WATER_MARK_SHIFT	24
+#define TCAN4X5X_RX_FIFO_SZ_SHIFT	16
+#define TCAN4X5X_RX_BUF_START		0x4
+
+#define TCAN4X5X_RX_F1DS_SHIFT	4
+#define TCAN4X5X_RX_RBDS_SHIFT	8
+
+#define TCAN4X5X_RX_FIFO0_MESSAGE	BIT(0)
+#define TCAN4X5X_RX_FIFO1_MESSAGE	BIT(4)
+#define TCAN4X5X_RX_BUFFER_MESSAGE	BIT(19)
+#define TCAN4X5X_RX_INDEX_MASK		0x3f00
+#define TCAN4X5X_RX_INDEX_SHIFT		8
+
+#define TCAN4X5X_RX_ADDR_OFFSET		0x8000
+#define TCAN4X5X_RX_BUF_ADDR_OFFSET	0x8100
+#define TCAN4X5X_RX_ADDR_MASK		0xffff
+
+#define TCAN4X5X_ERR_PROTOCOL_MASK	0x7
+#define TCAN4X5X_ERR_STUFERR		0x1
+#define TCAN4X5X_ERR_FRMERR		0x2
+#define TCAN4X5X_ERR_ACKERR		0x3
+#define TCAN4X5X_ERR_BIT1ERR		0x4
+#define TCAN4X5X_ERR_BIT0ERR		0x5
+#define TCAN4X5X_ERR_CRCERR		0x6
+
+/* Interrupt bits */
+#define TCAN4X5X_CANBUSTERMOPEN_INT_EN	BIT(30)
+#define TCAN4X5X_CANHCANL_INT_EN	BIT(29)
+#define TCAN4X5X_CANHBAT_INT_EN		BIT(28)
+#define TCAN4X5X_CANLGND_INT_EN		BIT(27)
+#define TCAN4X5X_CANBUSOPEN_INT_EN	BIT(26)
+#define TCAN4X5X_CANBUSGND_INT_EN	BIT(25)
+#define TCAN4X5X_CANBUSBAT_INT_EN	BIT(24)
+#define TCAN4X5X_UVSUP_INT_EN		BIT(22)
+#define TCAN4X5X_UVIO_INT_EN		BIT(21)
+#define TCAN4X5X_TSD_INT_EN		BIT(19)
+#define TCAN4X5X_ECCERR_INT_EN		BIT(16)
+#define TCAN4X5X_CANINT_INT_EN		BIT(15)
+#define TCAN4X5X_LWU_INT_EN		BIT(14)
+#define TCAN4X5X_CANSLNT_INT_EN		BIT(10)
+#define TCAN4X5X_CANDOM_INT_EN		BIT(8)
+#define TCAN4X5X_CANBUS_ERR_INT_EN	BIT(5)
+#define TCAN4X5X_BUS_FAULT		BIT(4)
+#define TCAN4X5X_MCAN_INT		BIT(1)
+#define TCAN4X5X_ENABLE_ALL_INT		(TCAN4X5X_MCAN_INT | \
+					TCAN4X5X_BUS_FAULT | \
+					TCAN4X5X_CANBUS_ERR_INT_EN | \
+					TCAN4X5X_CANINT_INT_EN)
+
+/* MCAN Interrupt bits */
+#define TCAN4X5X_MCAN_IR_ARA		BIT(29)
+#define TCAN4X5X_MCAN_IR_PED		BIT(28)
+#define TCAN4X5X_MCAN_IR_PEA		BIT(27)
+#define TCAN4X5X_MCAN_IR_WD		BIT(26)
+#define TCAN4X5X_MCAN_IR_BO		BIT(25)
+#define TCAN4X5X_MCAN_IR_EW		BIT(24)
+#define TCAN4X5X_MCAN_IR_EP		BIT(23)
+#define TCAN4X5X_MCAN_IR_ELO		BIT(22)
+#define TCAN4X5X_MCAN_IR_BEU		BIT(21)
+#define TCAN4X5X_MCAN_IR_BEC		BIT(20)
+#define TCAN4X5X_MCAN_IR_DRX		BIT(19)
+#define TCAN4X5X_MCAN_IR_TOO		BIT(18)
+#define TCAN4X5X_MCAN_IR_MRAF		BIT(17)
+#define TCAN4X5X_MCAN_IR_TSW		BIT(16)
+#define TCAN4X5X_MCAN_IR_TEFL		BIT(15)
+#define TCAN4X5X_MCAN_IR_TEFF		BIT(14)
+#define TCAN4X5X_MCAN_IR_TEFW		BIT(13)
+#define TCAN4X5X_MCAN_IR_TEFN		BIT(12)
+#define TCAN4X5X_MCAN_IR_TFE		BIT(11)
+#define TCAN4X5X_MCAN_IR_TCF		BIT(10)
+#define TCAN4X5X_MCAN_IR_TC		BIT(9)
+#define TCAN4X5X_MCAN_IR_HPM		BIT(8)
+#define TCAN4X5X_MCAN_IR_RF1L		BIT(7)
+#define TCAN4X5X_MCAN_IR_RF1F		BIT(6)
+#define TCAN4X5X_MCAN_IR_RF1W		BIT(5)
+#define TCAN4X5X_MCAN_IR_RF1N		BIT(4)
+#define TCAN4X5X_MCAN_IR_RF0L		BIT(3)
+#define TCAN4X5X_MCAN_IR_RF0F		BIT(2)
+#define TCAN4X5X_MCAN_IR_RF0W		BIT(1)
+#define TCAN4X5X_MCAN_IR_RF0N		BIT(0)
+#define TCAN4X5X_ENABLE_MCAN_INT	(TCAN4X5X_MCAN_IR_TC | \
+					TCAN4X5X_MCAN_IR_RF0N | \
+					TCAN4X5X_MCAN_IR_RF1N | \
+					TCAN4X5X_MCAN_IR_RF0F | \
+					TCAN4X5X_MCAN_IR_RF1F)
+
+/* CCR bits */
+#define TCAN4X5X_CCCR_NISO_BOSCH	BIT(15)
+#define TCAN4X5X_CCCR_TXP		BIT(15)
+#define TCAN4X5X_CCCR_EFBI		BIT(13)
+#define TCAN4X5X_CCCR_PXHD_DIS		BIT(12)
+#define TCAN4X5X_CCCR_BRSE		BIT(9)
+#define TCAN4X5X_CCCR_FDOE		BIT(8)
+#define TCAN4X5X_CCCR_TEST		BIT(7)
+#define TCAN4X5X_CCCR_DAR_DIS		BIT(6)
+#define TCAN4X5X_CCCR_MON		BIT(5)
+#define TCAN4X5X_CCCR_CSR		BIT(4)
+#define TCAN4X5X_CCCR_CSA		BIT(3)
+#define TCAN4X5X_CCCR_ASM		BIT(2)
+#define TCAN4X5X_CCCR_CCE		BIT(1)
+#define TCAN4X5X_CCCR_INIT		BIT(0)
+
+#define TCAN4X5X_EINT0			BIT(0)
+#define TCAN4X5X_EINT1			BIT(1)
+
+struct tcan4x5x_rx_regs {
+	u32 fifo_status_reg;
+	u32 fifo_config_reg;
+	u32 fifo_ack_reg;
+	u32 rx_buf_shift;
+};
+
+struct tcan4x5x_rx_regs tcan4x5x_fifo_regs[] = {
+	{ TCAN4X5X_MCAN_RXF0S, TCAN4X5X_MCAN_RXF0C, TCAN4X5X_MCAN_RXF0A, 0},
+	{ TCAN4X5X_MCAN_RXF1S, TCAN4X5X_MCAN_RXF1C, TCAN4X5X_MCAN_RXF1A, 4},
+	{ TCAN4X5X_MCAN_NDAT1, TCAN4X5X_MCAN_RXBC, TCAN4X5X_MCAN_NDAT1, 8},
+};
+
+enum tcan4x5x_data_size {
+	TCAN4X5X_8_BYTE = 0,
+	TCAN4X5X_12_BYTE,
+	TCAN4X5X_16_BYTE,
+	TCAN4X5X_20_BYTE,
+	TCAN4X5X_24_BYTE,
+	TCAN4X5X_32_BYTE,
+	TCAN4X5X_48_BYTE,
+	TCAN4X5X_64_BYTE,
+};
+
+static const struct can_bittiming_const tcan4x5x_bittiming_const = {
+	.name = DEVICE_NAME,
+	.tseg1_min = 2,
+	.tseg1_max = 31,
+	.tseg2_min = 2,
+	.tseg2_max = 16,
+	.sjw_max = 16,
+	.brp_min = 1,
+	.brp_max = 32,
+	.brp_inc = 1,
+};
+
+static const struct can_bittiming_const tcan4x5x_data_bittiming_const = {
+	.name = DEVICE_NAME,
+	.tseg1_min = 1,
+	.tseg1_max = 32,
+	.tseg2_min = 1,
+	.tseg2_max = 16,
+	.sjw_max = 16,
+	.brp_min = 1,
+	.brp_max = 32,
+	.brp_inc = 1,
+};
+
+static void tcan4x5x_clean(struct net_device *net)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+
+	if (priv->tx_skb || priv->tx_len)
+		net->stats.tx_errors++;
+	if (priv->tx_skb)
+		dev_kfree_skb(priv->tx_skb);
+	if (priv->tx_len)
+		can_free_echo_skb(priv->net, 0);
+
+	priv->tx_skb = NULL;
+	priv->tx_len = 0;
+}
+
+static int regmap_spi_gather_write(void *context, const void *reg,
+				   size_t reg_len, const void *val,
+				   size_t val_len)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+	u32 addr;
+	struct spi_message m;
+	struct spi_transfer t[2] = {{ .tx_buf = &addr, .len = 4, .cs_change = 0,},
+				   { .tx_buf = val, .len = val_len, },};
+
+	addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	return spi_sync(spi, &m);
+}
+
+static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
+{
+	u16 *reg = (u16 *)(data);
+	const u32 *val = data + 2;
+
+	return regmap_spi_gather_write(context, reg, 2, val, count - 2);
+}
+
+static int regmap_spi_async_write(void *context,
+				  const void *reg, size_t reg_len,
+				  const void *val, size_t val_len,
+				  struct regmap_async *a)
+{
+	return -ENOTSUPP;
+}
+
+static struct regmap_async *regmap_spi_async_alloc(void)
+{
+	return NULL;
+}
+
+static int tcan4x5x_regmap_read(void *context,
+				const void *reg, size_t reg_size,
+				void *val, size_t val_size)
+{
+	struct device *dev = context;
+	struct spi_device *spi = to_spi_device(dev);
+
+	u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2;
+
+	return spi_write_then_read(spi, &addr, 4, val, val_size);
+}
+
+static struct regmap_bus tcan4x5x_bus = {
+	.write = tcan4x5x_regmap_write,
+	.gather_write = regmap_spi_gather_write,
+	.async_write = regmap_spi_async_write,
+	.async_alloc = regmap_spi_async_alloc,
+	.read = tcan4x5x_regmap_read,
+	.read_flag_mask = 0x00,
+	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static uint8_t tcan4x5x_dlc_conv(uint8_t input)
+{
+	const static u8 lookup[7] = {12, 16, 20, 24, 32, 48, 64};
+
+	if (input < 9)
+		return input;
+
+	if (input < 16)
+		return lookup[(unsigned int)(input - 9)];
+
+	return 0;
+}
+
+static uint8_t tcan4x5x_txrxesc_value(uint8_t input)
+{
+	const u8 lookup[8] = {8, 12, 16, 20, 24, 32, 48, 64};
+	return lookup[(unsigned int)(input & 0x07)];
+}
+
+static void tcan4x5x_hw_tx(struct tcan4x5x_priv *tcan4x5x)
+{
+	u32 sid, eid, exide, rtr, brs, esi, fdf, xtd, data_len;
+	u32 mcan_address, mcan_tx_element_sz;
+	int queue_stat, queue_lvl, queue_idx;
+	struct canfd_frame *fd_frame;
+	struct can_frame *frame;
+	int tx_element_sz, i, temp;
+	canid_t frame_id;
+	u8 dlc_len;
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXFQS, &queue_stat);
+	queue_lvl = queue_stat & TCAN4x5x_QUEUE_LVL_MASK;
+	queue_idx = (queue_stat & TCAN4x5x_QUEUE_IDX_MASK) >> TCAN4x5x_QUEUE_IDX_SHIFT;
+
+	if (tcan4x5x->tx_skb->len == CAN_MTU) {
+		fd_frame = NULL;
+		frame = (struct can_frame *)tcan4x5x->tx_skb->data;
+		frame_id = frame->can_id;
+		dlc_len = frame->can_dlc;
+		data_len = ((dlc_len % 4) + dlc_len) / 4;
+		brs = 0;
+	} else if (tcan4x5x->tx_skb->len == CANFD_MTU) {
+		frame = NULL;
+		fd_frame = (struct canfd_frame *)tcan4x5x->tx_skb->data;
+		frame_id = fd_frame->can_id;
+		dlc_len = fd_frame->len;
+		data_len = ((dlc_len % 4) + dlc_len) / 4;
+		brs = fd_frame->flags & CANFD_BRS;
+		esi = fd_frame->flags & CANFD_ESI;
+		fdf = 1;
+	} else {
+		return;
+	}
+
+	eid = frame_id & CAN_EFF_MASK;
+	rtr = (frame_id & CAN_RTR_FLAG) ? 1 : 0;
+
+	exide = (frame_id & CAN_EFF_FLAG) ? 1 : 0;
+	if (exide) {
+		sid = frame_id & CAN_EFF_MASK;
+		xtd = 1;
+	} else {
+		sid = (frame_id & CAN_SFF_MASK) << TCAN4X5X_SID_SHIFT;
+		xtd = 0;
+	}
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBC, &mcan_address);
+
+	mcan_address = (mcan_address & 0xffff) + TCAN4X5X_MRAM_START;
+	temp = (uint8_t)((mcan_address >> 24) & 0x3F);
+
+	tx_element_sz = temp > 32 ? 32 : temp;
+	temp = (uint8_t)((mcan_address >> 16) & 0x3F);
+
+	tx_element_sz += temp > 32 ? 32 : temp;
+	mcan_address += ((uint32_t)tx_element_sz * queue_idx);
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_TXESC, &mcan_tx_element_sz);
+	tx_element_sz = tcan4x5x_txrxesc_value(mcan_tx_element_sz & 0x07) + 8;
+	mcan_address += ((uint32_t)tx_element_sz * 0);
+
+	tx_element_sz = (tcan4x5x_dlc_conv(dlc_len & 0x0F) + 8) >> 2;
+	if (tcan4x5x_dlc_conv(dlc_len & 0x0F) % 4)
+		tx_element_sz += 1;
+
+	tcan4x5x->spi_tx_buf[0] = esi << TCAN4X5X_ESI_SHIFT |
+				  xtd << TCAN4X5X_XTD_SHIFT |
+				  rtr << TCAN4X5X_RTR_SHIFT | sid;
+
+	tcan4x5x->spi_tx_buf[1] = fdf << TCAN4X5X_FDF_SHIFT |
+		 brs << TCAN4X5X_BRS_SHIFT | dlc_len << TCAN4X5X_DLC_SHIFT;
+
+	if (tcan4x5x->tx_skb->len == CAN_MTU)
+		memcpy(tcan4x5x->spi_tx_buf + TCAN4X5X_DATA_PKT_OFF,
+		       frame->data, dlc_len);
+	else
+		memcpy(tcan4x5x->spi_tx_buf + TCAN4X5X_DATA_PKT_OFF,
+		       fd_frame->data, dlc_len);
+
+	for (i = dlc_len + 1; i < TCAN4X5X_BUF_LEN / 4; i++)
+		tcan4x5x->spi_tx_buf[i] = 0;
+
+	regmap_bulk_write(tcan4x5x->regmap, mcan_address, tcan4x5x->spi_tx_buf,
+			  TCAN4X5X_BUF_LEN);
+
+	regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBAR, (1 << (queue_idx)));
+}
+
+int tcan4x5x_hw_rx(struct tcan4x5x_priv *tcan4x5x)
+{
+	u32 queue_idx, fifo_idx, fifo_start_addr, rx_buf_size, msg_type;
+	u32 data_buffer[TCAN4X5X_BUF_LEN] = {0x0};
+	u32 rx_header[2] = {0x0};
+	struct tcan4x5x_rx_regs *buffer_regs;
+	struct canfd_frame *fd_frame;
+	int dlc_len, data_len;
+	struct sk_buff *skb;
+
+	skb = alloc_canfd_skb(tcan4x5x->net, &fd_frame);
+	if (!skb) {
+		dev_err(&tcan4x5x->spi->dev, "cannot allocate RX skb\n");
+		tcan4x5x->net->stats.rx_dropped++;
+		return -ENOMEM;
+	}
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG, &msg_type);
+	if (msg_type & TCAN4X5X_RX_FIFO0_MESSAGE) {
+		buffer_regs = &tcan4x5x_fifo_regs[0];
+	} else if (msg_type & TCAN4X5X_RX_FIFO1_MESSAGE) {
+		buffer_regs = &tcan4x5x_fifo_regs[1];
+	} else if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE) {
+		buffer_regs = &tcan4x5x_fifo_regs[2];
+	} else {
+		buffer_regs = NULL;
+		return -EINVAL;
+	}
+
+	rx_buf_size = TCAN4X5X_BUF_LEN;
+
+	/* Determine which FIFO needs service */
+	regmap_read(tcan4x5x->regmap, buffer_regs->fifo_status_reg, &fifo_idx);
+	if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE)
+		queue_idx = fifo_idx - 1;
+	else
+		queue_idx = (TCAN4X5X_RX_INDEX_MASK & fifo_idx) >> TCAN4X5X_RX_INDEX_SHIFT;
+
+	/* Calculate the FIFO start address to service */
+	regmap_read(tcan4x5x->regmap, buffer_regs->fifo_config_reg, &fifo_start_addr);
+	fifo_start_addr = (TCAN4X5X_RX_ADDR_MASK & fifo_start_addr);
+	if (msg_type & TCAN4X5X_RX_BUFFER_MESSAGE)
+		fifo_start_addr = fifo_start_addr + TCAN4X5X_RX_BUF_ADDR_OFFSET +
+				  (rx_buf_size * queue_idx);
+	else
+		fifo_start_addr = fifo_start_addr + TCAN4X5X_RX_ADDR_OFFSET +
+				  (rx_buf_size * queue_idx);
+
+	regmap_bulk_read(tcan4x5x->regmap, fifo_start_addr, rx_header, 2);
+
+	dlc_len = (rx_header[1] & TCAN4X5X_DLC_MASK) >> TCAN4X5X_DLC_SHIFT;
+	if (dlc_len <= 8)
+		data_len = dlc_len;
+	else
+		data_len = tcan4x5x_txrxesc_value(dlc_len);
+
+	regmap_bulk_read(tcan4x5x->regmap, fifo_start_addr + 8,
+			 data_buffer, data_len / 4);
+
+	/* Acknowledge receipt of the data */
+	regmap_write(tcan4x5x->regmap, buffer_regs->fifo_ack_reg, queue_idx);
+
+	if (rx_header[0] &  TCAN4X5X_XTD_MASK) {
+		fd_frame->can_id = CAN_EFF_FLAG;
+		fd_frame->can_id |= (rx_header[0] & CAN_EFF_MASK);
+	} else {
+		fd_frame->can_id |= ((rx_header[0] >> TCAN4X5X_SID_SHIFT) &
+				    CAN_SFF_MASK);
+	}
+
+	if (rx_header[0] & TCAN4X5X_RTR_MASK)
+		fd_frame->can_id |= CAN_RTR_FLAG;
+
+	if (rx_header[0] & TCAN4X5X_ESI_MASK) {
+		fd_frame->can_id |= CAN_ERR_FLAG;
+		fd_frame->flags |= CANFD_ESI;
+		netdev_dbg(tcan4x5x->net, "ESI Error\n");
+	}
+
+	fd_frame->len = data_len;
+	memcpy(fd_frame->data, data_buffer, fd_frame->len);
+
+	tcan4x5x->net->stats.rx_packets++;
+	tcan4x5x->net->stats.rx_bytes += fd_frame->len;
+
+	can_led_event(tcan4x5x->net, CAN_LED_EVENT_RX);
+	netif_rx_ni(skb);
+
+	return 0;
+}
+
+static void tcan4x5x_sleep(struct spi_device *spi)
+{
+	struct tcan4x5x_priv *tcan4x5x = spi_get_drvdata(spi);
+
+	regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
+			   TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_STANDBY);
+}
+
+static int tcan4x5x_reset(struct net_device *net)
+{
+	struct tcan4x5x_priv *tcan4x5x = netdev_priv(net);
+
+	if (tcan4x5x->reset_gpio) {
+		gpiod_set_value_cansleep(tcan4x5x->reset_gpio, 1);
+		udelay(10);
+		gpiod_set_value_cansleep(tcan4x5x->reset_gpio, 0);
+	} else {
+		regmap_write(tcan4x5x->regmap, TCAN4X5X_CONFIG,
+			     TCAN4X5X_SW_RESET);
+	}
+
+	return 0;
+}
+
+static int tcan4x5x_power_enable(struct regulator *reg, int enable)
+{
+	if (IS_ERR_OR_NULL(reg))
+		return 0;
+
+	if (enable)
+		return regulator_enable(reg);
+	else
+		return regulator_disable(reg);
+}
+
+static irqreturn_t tcan4x5x_can_ist(int irq, void *dev_id)
+{
+	struct tcan4x5x_priv *tcan4x5x = dev_id;
+	struct spi_device *spi = tcan4x5x->spi;
+	struct net_device *net = tcan4x5x->net;
+	enum can_state new_state;
+	int intf, eflag, mcan_intf;
+
+	mutex_lock(&tcan4x5x->tcan4x5x_lock);
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_INT_FLAGS, &intf);
+	if (intf & TCAN4X5X_MCAN_INT)
+		tcan4x5x_hw_rx(tcan4x5x);
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG, &mcan_intf);
+
+	regmap_read(tcan4x5x->regmap, TCAN4X5X_STATUS, &eflag);
+	/* Update can state */
+	if (eflag & TCAN4X5X_MCAN_IR_BO)
+		new_state = CAN_STATE_BUS_OFF;
+	else if (eflag & TCAN4X5X_MCAN_IR_EP)
+		new_state = CAN_STATE_ERROR_PASSIVE;
+	else if (eflag & TCAN4X5X_MCAN_IR_EW)
+		new_state = CAN_STATE_ERROR_WARNING;
+	else
+		new_state = CAN_STATE_ERROR_ACTIVE;
+
+	if (new_state != tcan4x5x->can.state) {
+		struct can_frame *cf;
+		struct sk_buff *skb;
+		enum can_state rx_state, tx_state;
+		u32 error_count;
+
+		skb = alloc_can_err_skb(net, &cf);
+		if (!skb)
+			goto ist_out;
+
+		regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_ECR, &error_count);
+		cf->data[6] = error_count & 0xff;
+		cf->data[7] = error_count & 0x7f00 >> 8;
+		tx_state = cf->data[6] >= cf->data[7] ? new_state : 0;
+		rx_state = cf->data[6] <= cf->data[7] ? new_state : 0;
+		can_change_state(net, cf, tx_state, rx_state);
+		netif_rx_ni(skb);
+
+		if (new_state == CAN_STATE_BUS_OFF) {
+			can_bus_off(net);
+			if (tcan4x5x->can.restart_ms == 0) {
+				tcan4x5x->force_quit = 1;
+				tcan4x5x_sleep(spi);
+				goto ist_out;
+			}
+		}
+	}
+
+	/* Update bus errors */
+	if ((intf & TCAN4X5X_BUS_FAULT) &&
+	    (tcan4x5x->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) {
+		struct can_frame *cf;
+		struct sk_buff *skb;
+		u32 psr_err, error_count;
+
+		/* Check for protocol errors */
+		regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_PSR, &psr_err);
+		if (psr_err & TCAN4X5X_ERR_PROTOCOL_MASK) {
+			skb = alloc_can_err_skb(net, &cf);
+			if (!skb)
+				goto ist_out;
+
+			cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+			tcan4x5x->can.can_stats.bus_error++;
+			tcan4x5x->net->stats.rx_errors++;
+			if (psr_err & TCAN4X5X_ERR_BIT0ERR)
+				cf->data[2] |= CAN_ERR_PROT_BIT0;
+			else if (psr_err & TCAN4X5X_ERR_BIT1ERR)
+				cf->data[2] |= CAN_ERR_PROT_BIT1;
+			else if (psr_err & TCAN4X5X_ERR_FRMERR)
+				cf->data[2] |= CAN_ERR_PROT_FORM;
+			else if (psr_err & TCAN4X5X_ERR_STUFERR)
+				cf->data[2] |= CAN_ERR_PROT_STUFF;
+			else if (psr_err & TCAN4X5X_ERR_CRCERR)
+				cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+			else if (psr_err & TCAN4X5X_ERR_ACKERR)
+				cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+
+			regmap_read(tcan4x5x->regmap, TCAN4X5X_MCAN_ECR,
+				    &error_count);
+			cf->data[6] = error_count & 0xff;
+			cf->data[7] = error_count & 0x7f00 >> 8;
+			netdev_dbg(tcan4x5x->net, "Bus Error\n");
+			netif_rx_ni(skb);
+		}
+	}
+
+	if (mcan_intf & TCAN4X5X_MCAN_IR_TC) {
+		net->stats.tx_packets++;
+		net->stats.tx_bytes += tcan4x5x->tx_len - 1;
+		can_led_event(net, CAN_LED_EVENT_TX);
+		if (tcan4x5x->tx_len) {
+			can_get_echo_skb(net, 0);
+			tcan4x5x->tx_len = 0;
+		}
+		netif_wake_queue(net);
+	}
+
+ist_out:
+	regmap_write(tcan4x5x->regmap, TCAN4X5X_INT_FLAGS, TCAN4X5X_CLEAR_ALL_INT);
+	regmap_write(tcan4x5x->regmap, TCAN4X5X_STATUS, TCAN4X5X_CLEAR_ALL_INT);
+	regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_FLAG,
+		     TCAN4X5X_CLEAR_ALL_INT);
+
+	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
+	return IRQ_HANDLED;
+}
+
+static int tcan4x5x_do_set_bittiming(struct net_device *net)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+	struct can_bittiming *bt = &priv->can.bittiming;
+	struct can_bittiming *dbt = &priv->can.data_bittiming;
+	u16 brp, sjw, tseg1, tseg2;
+	int ret;
+	u32 val;
+
+	brp = bt->brp - 1;
+	sjw = bt->sjw - 1;
+	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+	tseg2 = bt->phase_seg2 - 1;
+	val = (brp << TCAN4X5X_NBRP_SHIFT) | (sjw << TCAN4X5X_NSJW_SHIFT) |
+		(tseg1 << TCAN4X5X_NTSEG1_SHIFT) | tseg2;
+
+	ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_NBTP, val);
+	if (ret)
+		return -EIO;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+		val = 0;
+		brp = dbt->brp - 1;
+		sjw = dbt->sjw - 1;
+		tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+		tseg2 = dbt->phase_seg2 - 1;
+
+		/* TDC is only needed for bitrates beyond 2.5 MBit/s.
+		 * This is mentioned in the "Bit Time Requirements for CAN FD"
+		 * paper presented at the International CAN Conference 2013
+		 */
+		if (dbt->bitrate > 2500000) {
+			u32 tdco, ssp;
+
+			/* Use the same value of secondary sampling point
+			 * as the data sampling point
+			 */
+			ssp = dbt->sample_point;
+
+			/* Equation based on Bosch's M_CAN User Manual's
+			 * Transmitter Delay Compensation Section
+			 */
+			tdco = (priv->can.clock.freq / 1000) *
+			       ssp / dbt->bitrate;
+
+			/* Max valid TDCO value is 127 */
+			if (tdco > 127) {
+				netdev_warn(net, "TDCO value of %u is beyond maximum. Using maximum possible value\n",
+					    tdco);
+				tdco = 127;
+			}
+
+			val |= DBTP_TDC;
+			ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_TDCR,
+					   tdco << TCAN4X5X_TDCR_TDCO_SHIFT);
+			if (ret)
+				return -EIO;
+		}
+
+		val |= (brp << DBTP_DBRP_SHIFT) |
+			   (sjw << DBTP_DSJW_SHIFT) |
+			   (tseg1 << DBTP_DTSEG1_SHIFT) |
+			   (tseg2 << DBTP_DTSEG2_SHIFT);
+
+		ret = regmap_write(priv->regmap, TCAN4X5X_MCAN_DBTP, val);
+	}
+
+	return ret;
+}
+
+static int tcan4x5x_setup(struct spi_device *spi)
+{
+	struct tcan4x5x_priv *tcan4x5x = spi_get_drvdata(spi);
+	int start_reg = TCAN4X5X_MRAM_START;
+	int end_reg = start_reg + TCAN4X5X_MRAM_SIZE;
+	int ret;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_REG,
+			   TCAN4X5X_CLEAR_ALL_INT);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_INT_EN,
+			   TCAN4X5X_ENABLE_MCAN_INT);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_CCCR,
+			   TCAN4X5X_CCCR_INIT | TCAN4X5X_CCCR_CCE);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_CCCR,
+			   TCAN4X5X_CCCR_INIT | TCAN4X5X_CCCR_CCE |
+			   TCAN4X5X_CCCR_FDOE | TCAN4X5X_CCCR_BRSE);
+	if (ret)
+		return -EIO;
+
+	ret = tcan4x5x_do_set_bittiming(tcan4x5x->net);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXESC,
+			   TCAN4X5X_64_BYTE);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBC,
+			   (TCAN4X5X_NUM_TX_BUF << TCAN4X5X_TX_QUEUE_SHIFT |
+			   TCAN4X5X_TX_BUF_START));
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_RXF0C,
+			   (TCAN4X5X_RX_WATER_MARK << TCAN4X5X_RX_WATER_MARK_SHIFT |
+			   TCAN4X5X_NUM_RX_BUF << TCAN4X5X_RX_FIFO_SZ_SHIFT |
+			   TCAN4X5X_RX_BUF_START));
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_RXESC,
+			   (TCAN4X5X_64_BYTE << TCAN4X5X_RX_RBDS_SHIFT |
+			   TCAN4X5X_64_BYTE << TCAN4X5X_RX_F1DS_SHIFT |
+			   TCAN4X5X_64_BYTE));
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_TXBTIE,
+			   TCAN4X5X_SET_ALL_INT);
+	if (ret)
+		return -EIO;
+
+
+	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
+				 TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
+	if (ret)
+		return -EIO;
+
+	ret = regmap_write(tcan4x5x->regmap, TCAN4X5X_MCAN_ILE, TCAN4X5X_EINT0);
+	if (ret)
+		return -EIO;
+
+	/* Zero out the MCAN buffers */
+	while (start_reg < end_reg) {
+		regmap_write(tcan4x5x->regmap, start_reg, 0);
+		start_reg += 4;
+	}
+
+	return ret;
+}
+
+static void tcan4x5x_tx_work_handler(struct work_struct *ws)
+{
+	struct tcan4x5x_priv *tcan4x5x = container_of(ws, struct tcan4x5x_priv,
+						tx_work);
+	struct net_device *net = tcan4x5x->net;
+	struct can_frame *frame;
+
+	mutex_lock(&tcan4x5x->tcan4x5x_lock);
+	if (tcan4x5x->tx_skb) {
+		if (tcan4x5x->can.state == CAN_STATE_BUS_OFF) {
+			tcan4x5x_clean(net);
+		} else {
+			frame = (struct can_frame *)tcan4x5x->tx_skb->data;
+			tcan4x5x_hw_tx(tcan4x5x);
+			tcan4x5x->tx_len = 1 + frame->can_dlc;
+			can_put_echo_skb(tcan4x5x->tx_skb, net, 0);
+			tcan4x5x->tx_skb = NULL;
+		}
+	}
+	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
+}
+
+static void tcan4x5x_restart_work_handler(struct work_struct *ws)
+{
+	struct tcan4x5x_priv *tcan4x5x = container_of(ws, struct tcan4x5x_priv,
+						restart_work);
+	struct spi_device *spi = tcan4x5x->spi;
+	struct net_device *net = tcan4x5x->net;
+
+	mutex_lock(&tcan4x5x->tcan4x5x_lock);
+	if (tcan4x5x->after_suspend) {
+		tcan4x5x_reset(net);
+		tcan4x5x_setup(spi);
+		if (tcan4x5x->after_suspend & AFTER_SUSPEND_RESTART) {
+			tcan4x5x_setup(spi);
+		} else if (tcan4x5x->after_suspend & AFTER_SUSPEND_UP) {
+			netif_device_attach(net);
+			tcan4x5x_clean(net);
+			tcan4x5x_setup(spi);
+			netif_wake_queue(net);
+		} else {
+			tcan4x5x_sleep(spi);
+		}
+		tcan4x5x->after_suspend = 0;
+		tcan4x5x->force_quit = 0;
+	}
+
+	if (tcan4x5x->restart_tx) {
+		tcan4x5x->restart_tx = 0;
+		tcan4x5x_reset(net);
+		tcan4x5x_clean(net);
+		tcan4x5x_setup(spi);
+		netif_wake_queue(net);
+	}
+	mutex_unlock(&tcan4x5x->tcan4x5x_lock);
+}
+
+static int tcan4x5x_open(struct net_device *net)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+	unsigned long flags = IRQF_ONESHOT | IRQF_TRIGGER_LOW;
+	int ret;
+
+	ret = open_candev(net);
+	if (ret)
+		return ret;
+
+	mutex_lock(&priv->tcan4x5x_lock);
+	tcan4x5x_power_enable(priv->power, 1);
+
+	priv->force_quit = 0;
+	priv->tx_skb = NULL;
+	priv->tx_len = 0;
+
+	ret = request_threaded_irq(priv->irq, NULL, tcan4x5x_can_ist,
+				   flags, DEVICE_NAME, priv);
+	if (ret) {
+		dev_err(&spi->dev, "failed to acquire irq %d %i\n",
+			priv->irq, ret);
+		goto out_close;
+	}
+
+	priv->wq = alloc_workqueue("tcan4x5x_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM,
+				   0);
+	if (!priv->wq) {
+		ret = -ENOMEM;
+		goto out_free_irq;
+	}
+
+	INIT_WORK(&priv->tx_work, tcan4x5x_tx_work_handler);
+	INIT_WORK(&priv->restart_work, tcan4x5x_restart_work_handler);
+
+	priv->spi_tx_buf = devm_kzalloc(&spi->dev, TCAN4X5X_BUF_LEN,
+					GFP_KERNEL);
+	if (!priv->spi_tx_buf) {
+		ret = -ENOMEM;
+		goto  out_free_wq;
+	}
+
+	priv->spi_rx_buf = devm_kzalloc(&spi->dev, TCAN4X5X_BUF_LEN,
+					GFP_KERNEL);
+	if (!priv->spi_rx_buf) {
+		ret = -ENOMEM;
+		goto  out_free_wq;
+	}
+
+	if (priv->wake_gpio)
+		gpiod_set_value_cansleep(priv->wake_gpio, 1);
+
+	ret = tcan4x5x_reset(net);
+	if (ret)
+		goto out_free_wq;
+
+	ret = tcan4x5x_setup(spi);
+	if (ret)
+		goto out_free_wq;
+
+	can_led_event(net, CAN_LED_EVENT_OPEN);
+	netif_wake_queue(net);
+	mutex_unlock(&priv->tcan4x5x_lock);
+
+	return 0;
+
+ out_free_wq:
+	destroy_workqueue(priv->wq);
+ out_free_irq:
+	free_irq(priv->irq, priv);
+	tcan4x5x_sleep(spi);
+ out_close:
+	tcan4x5x_power_enable(priv->power, 0);
+	close_candev(net);
+	mutex_unlock(&priv->tcan4x5x_lock);
+	return ret;
+}
+
+static int tcan4x5x_stop(struct net_device *net)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+
+	close_candev(net);
+
+	priv->force_quit = 1;
+	free_irq(priv->irq, priv);
+	destroy_workqueue(priv->wq);
+	priv->wq = NULL;
+
+	mutex_lock(&priv->tcan4x5x_lock);
+
+	priv->can.state = CAN_STATE_STOPPED;
+	tcan4x5x_sleep(spi);
+	tcan4x5x_power_enable(priv->power, 0);
+
+	mutex_unlock(&priv->tcan4x5x_lock);
+
+	can_led_event(net, CAN_LED_EVENT_STOP);
+
+	return 0;
+}
+
+static netdev_tx_t tcan4x5x_hard_start_xmit(struct sk_buff *skb,
+					    struct net_device *net)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+	struct spi_device *spi = priv->spi;
+
+	if (priv->tx_skb || priv->tx_len) {
+		dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	if (can_dropped_invalid_skb(net, skb))
+		return NETDEV_TX_OK;
+
+	netif_stop_queue(net);
+	priv->tx_skb = skb;
+	queue_work(priv->wq, &priv->tx_work);
+
+	return NETDEV_TX_OK;
+}
+
+static int tcan4x5x_do_set_mode(struct net_device *net, enum can_mode mode)
+{
+	struct tcan4x5x_priv *priv = netdev_priv(net);
+
+	switch (mode) {
+	case CAN_MODE_START:
+		tcan4x5x_clean(net);
+		priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		priv->restart_tx = 1;
+		queue_work(priv->wq, &priv->restart_work);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static const struct net_device_ops tcan4x5x_netdev_ops = {
+	.ndo_open = tcan4x5x_open,
+	.ndo_stop = tcan4x5x_stop,
+	.ndo_start_xmit = tcan4x5x_hard_start_xmit,
+	.ndo_change_mtu = can_change_mtu,
+};
+
+static int tcan4x5x_parse_config(struct tcan4x5x_priv *tcan4x5x)
+{
+	tcan4x5x->reset_gpio = devm_gpiod_get_optional(&tcan4x5x->spi->dev,
+						       "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(tcan4x5x->reset_gpio))
+		tcan4x5x->reset_gpio = NULL;
+
+	tcan4x5x->wake_gpio = devm_gpiod_get_optional(&tcan4x5x->spi->dev,
+						      "wake-up", GPIOD_OUT_LOW);
+	if (IS_ERR(tcan4x5x->wake_gpio))
+		tcan4x5x->wake_gpio = NULL;
+
+	tcan4x5x->interrupt_gpio = devm_gpiod_get(&tcan4x5x->spi->dev,
+						  "data-ready", GPIOD_IN);
+	if (IS_ERR(tcan4x5x->interrupt_gpio)) {
+		dev_err(&tcan4x5x->spi->dev, "data-ready gpio not defined\n");
+		return -EINVAL;
+	}
+
+	tcan4x5x->irq = gpiod_to_irq(tcan4x5x->interrupt_gpio);
+
+	tcan4x5x->power = devm_regulator_get_optional(&tcan4x5x->spi->dev,
+						      "vsup");
+	if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	return 0;
+}
+
+static const struct regmap_config tcan4x5x_regmap = {
+	.reg_bits = 16,
+	.val_bits = 32,
+	.cache_type = REGCACHE_NONE,
+	.max_register = TCAN4X5X_MAX_REGISTER,
+};
+
+static int tcan4x5x_can_probe(struct spi_device *spi)
+{
+	struct net_device *net;
+	struct tcan4x5x_priv *priv;
+	struct clk *clk;
+	int freq, ret;
+
+	clk = devm_clk_get(&spi->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&spi->dev, "no CAN clock source defined\n");
+		freq = TCAN4X5X_EXT_CLK_DEF;
+	} else {
+		freq = clk_get_rate(clk);
+	}
+
+	/* Sanity check */
+	if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF)
+		return -ERANGE;
+
+	/* Allocate can/net device */
+	net = alloc_candev(sizeof(*priv), TCAN4X5X_TX_ECHO_SKB_MAX);
+	if (!net)
+		return -ENOMEM;
+
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret)
+			goto out_free;
+	}
+
+	net->netdev_ops = &tcan4x5x_netdev_ops;
+	net->flags |= IFF_ECHO;
+	net->mtu = CANFD_MTU;
+
+	priv = netdev_priv(net);
+	priv->can.bittiming_const = &tcan4x5x_bittiming_const;
+	priv->can.data_bittiming_const = &tcan4x5x_data_bittiming_const;
+	priv->can.do_set_mode = tcan4x5x_do_set_mode;
+	priv->can.clock.freq = freq;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+				       CAN_CTRLMODE_LISTENONLY |
+				       CAN_CTRLMODE_BERR_REPORTING |
+				       CAN_CTRLMODE_FD |
+				       CAN_CTRLMODE_FD_NON_ISO;
+	priv->net = net;
+	priv->spi = spi;
+	priv->clk = clk;
+	spi_set_drvdata(spi, priv);
+
+	ret = tcan4x5x_parse_config(priv);
+	if (ret)
+		goto out_clk;
+
+	/* Configure the SPI bus */
+	spi->bits_per_word = 32;
+	ret = spi_setup(spi);
+	if (ret)
+		goto out_clk;
+
+	mutex_init(&priv->tcan4x5x_lock);
+
+	priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
+					&spi->dev, &tcan4x5x_regmap);
+
+	SET_NETDEV_DEV(net, &spi->dev);
+	ret = register_candev(net);
+	if (ret)
+		goto error_probe;
+
+	devm_can_led_init(net);
+
+	netdev_info(net, "TCAN4X5X successfully initialized.\n");
+	return 0;
+
+error_probe:
+	tcan4x5x_power_enable(priv->power, 0);
+out_clk:
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+out_free:
+	free_candev(net);
+	dev_err(&spi->dev, "Probe failed, err=%d\n", -ret);
+	return ret;
+}
+
+static int tcan4x5x_can_remove(struct spi_device *spi)
+{
+	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
+	struct net_device *net = priv->net;
+
+	unregister_candev(net);
+
+	tcan4x5x_power_enable(priv->power, 0);
+
+	if (!IS_ERR(priv->clk))
+		clk_disable_unprepare(priv->clk);
+
+	free_candev(net);
+
+	return 0;
+}
+
+static const struct of_device_id tcan4x5x_of_match[] = {
+	{ .compatible = "ti,tcan4x5x", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, tcan4x5x_of_match);
+
+static const struct spi_device_id tcan4x5x_id_table[] = {
+	{
+		.name		= "tcan4x5x",
+		.driver_data	= 0,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table);
+
+static struct spi_driver tcan4x5x_can_driver = {
+	.driver = {
+		.name = DEVICE_NAME,
+		.of_match_table = tcan4x5x_of_match,
+		.pm = NULL,
+	},
+	.id_table = tcan4x5x_id_table,
+	.probe = tcan4x5x_can_probe,
+	.remove = tcan4x5x_can_remove,
+};
+module_spi_driver(tcan4x5x_can_driver);
+
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments TCAN4x5x CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/spi/tcan4x5x.h b/drivers/net/can/spi/tcan4x5x.h
new file mode 100644
index 000000000000..5e14ba571d49
--- /dev/null
+++ b/drivers/net/can/spi/tcan4x5x.h
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPI to CAN driver for the Texas Instruments TCA4x5x
+// Flash driver chip family
+// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+
+#define TCAN4X5X_DEV_ID0	0x00
+#define TCAN4X5X_DEV_ID1	0x04
+#define TCAN4X5X_REV		0x08
+#define TCAN4X5X_STATUS		0x0C
+#define TCAN4X5X_ERROR_STATUS	0x10
+#define TCAN4X5X_CONTROL	0x14
+
+#define TCAN4X5X_CONFIG		0x800
+#define TCAN4X5X_TS_PRESCALE	0x804
+#define TCAN4X5X_TEST_REG	0x808
+#define TCAN4X5X_INT_FLAGS	0x820
+#define TCAN4X5X_MCAN_INT_REG	0x824
+#define TCAN4X5X_INT_EN		0x830
+
+#define TCAN4X5X_MCAN_CREL	0x1000
+#define TCAN4X5X_MCAN_ENDN	0x1004
+#define TCAN4X5X_MCAN_CUST	0x1008
+#define TCAN4X5X_MCAN_DBTP	0x100C
+#define TCAN4X5X_MCAN_TEST	0x1010
+#define TCAN4X5X_MCAN_RWD	0x1014
+#define TCAN4X5X_MCAN_CCCR	0x1018
+#define TCAN4X5X_MCAN_NBTP	0x101C
+#define TCAN4X5X_MCAN_TSCC	0x1020
+#define TCAN4X5X_MCAN_TSCV	0x1024
+#define TCAN4X5X_MCAN_TOCC	0x1028
+#define TCAN4X5X_MCAN_TOCV	0x102C
+#define TCAN4X5X_MCAN_ECR	0x1040
+#define TCAN4X5X_MCAN_PSR	0x1044
+#define TCAN4X5X_MCAN_TDCR	0x1048
+#define TCAN4X5X_MCAN_INT_FLAG	0x1050
+#define TCAN4X5X_MCAN_INT_EN	0x1054
+#define TCAN4X5X_MCAN_ILS	0x1058
+#define TCAN4X5X_MCAN_ILE	0x105C
+#define TCAN4X5X_MCAN_GFC	0x1080
+#define TCAN4X5X_MCAN_SIDFC	0x1084
+#define TCAN4X5X_MCAN_XIDFC	0x1088
+#define TCAN4X5X_MCAN_XIDAM	0x1090
+#define TCAN4X5X_MCAN_HPMS	0x1094
+#define TCAN4X5X_MCAN_NDAT1	0x1098
+#define TCAN4X5X_MCAN_NDAT2	0x109C
+#define TCAN4X5X_MCAN_RXF0C	0x10A0
+#define TCAN4X5X_MCAN_RXF0S	0x10A4
+#define TCAN4X5X_MCAN_RXF0A	0x10A8
+#define TCAN4X5X_MCAN_RXBC	0x10AC
+#define TCAN4X5X_MCAN_RXF1C	0x10B0
+#define TCAN4X5X_MCAN_RXF1S	0x10B4
+#define TCAN4X5X_MCAN_RXF1A	0x10B8
+#define TCAN4X5X_MCAN_RXESC	0x10BC
+#define TCAN4X5X_MCAN_TXBC	0x10C0
+#define TCAN4X5X_MCAN_TXFQS	0x10C4
+#define TCAN4X5X_MCAN_TXESC	0x10C8
+#define TCAN4X5X_MCAN_TXBRP	0x10CC
+#define TCAN4X5X_MCAN_TXBAR	0x10D0
+#define TCAN4X5X_MCAN_TXBCR	0x10D4
+#define TCAN4X5X_MCAN_TXBTO	0x10D8
+#define TCAN4X5X_MCAN_TXBCF	0x10DC
+#define TCAN4X5X_MCAN_TXBTIE	0x10E0
+#define TCAN4X5X_MCAN_TXBCIE	0x10E4
+#define TCAN4X5X_MCAN_TXEFC	0x10F0
+#define TCAN4X5X_MCAN_TXEFS	0x10F4
+#define TCAN4X5X_MCAN_TXEFA	0x10F8
+
+#define TCAN4X5X_MRAM_START	0x8000
+#define TCAN4X5X_MRAM_SIZE	2048
+
+#define TCAN4X5X_MAX_REGISTER	0x8fff
+
+/* 64 byte buffer + 8 byte MCAN header */
+#define TCAN4X5X_BUF_LEN 	72
+
+struct tcan4x5x_priv {
+	struct can_priv can;
+	struct net_device *net;
+	struct regmap *regmap;
+	struct spi_device *spi;
+
+	struct mutex tcan4x5x_lock; /* SPI device lock */
+
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *interrupt_gpio;
+	struct gpio_desc *wake_gpio;
+	struct regulator *power;
+	struct clk *clk;
+
+	struct sk_buff *tx_skb;
+	int tx_len;
+
+	struct workqueue_struct *wq;
+	struct work_struct tx_work;
+	struct work_struct restart_work;
+
+	u32 *spi_tx_buf;
+	u32 *spi_rx_buf;
+
+	int force_quit;
+	int after_suspend;
+#define AFTER_SUSPEND_UP 1
+#define AFTER_SUSPEND_DOWN 2
+#define AFTER_SUSPEND_POWER 4
+#define AFTER_SUSPEND_RESTART 8
+	int restart_tx;
+
+	int irq;
+};
-- 
2.17.0.1855.g63749b2dea

^ permalink raw reply related

* Re: unexpected GRO/veth behavior
From: Paolo Abeni @ 2018-09-10 15:22 UTC (permalink / raw)
  To: Eric Dumazet, netdev; +Cc: Toshiaki Makita
In-Reply-To: <f84e9363-bdc0-5e41-ca1a-99f612fcc708@gmail.com>

On Mon, 2018-09-10 at 07:56 -0700, Eric Dumazet wrote:
> 
> On 09/10/2018 07:44 AM, Paolo Abeni wrote:
> > hi all,
> > 
> > while testing some local patches I observed that the TCP tput in the
> > following scenario:
> > 
> > # the following enable napi on veth0, so that we can trigger the
> > # GRO path with namespaces
> > ip netns add test
> > ip link add type veth
> > ip link set dev veth0 netns test
> > ip -n test link set lo up
> > ip -n test link set veth0 up
> > ip -n test addr add dev veth0 172.16.1.2/24
> > ip link set dev veth1 up
> > ip addr add dev veth1 172.16.1.1/24
> > IDX=`ip netns exec test cat /sys/class/net/veth0/ifindex`
> > 
> > # 'xdp_pass' is a NO-OP XDP program that simply return XDP_PASS
> > ip netns exec test ./xdp_pass $IDX &
> > taskset 0x2 ip netns exec test iperf3 -s -i 60 &
> > taskset 0x1 iperf3 -c 172.16.1.2 -t 60 -i 60
> > 
> > is quite lower than expected (~800Mbps). 'perf' shows a weird topmost 
> > offender:
> > 
> 
> 
> But... why GRO would even be needed in this scenario ?

AFAICS, attaching an XDP program to a veth device makes TCP flows over
such veth unconditionally hit this code path since:

commit 948d4f214fde43743c57aae0c708bff44f6345f2
Author: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Date:   Fri Aug 3 16:58:10 2018 +0900

    veth: Add driver XDP

I'm personally looking for some way to hit the GRO code path with
selftest/namespaces.

> GRO is really meant for physical devices, having to mess with skb->sk adds extra cost
> in this already heavy cost engine.

Yup, even if I do not see any measurable cost added by the posted code.

Cheers,

Paolo

^ permalink raw reply

* Re: [PATCH] net: ipv4: Use BUG_ON directly instead of a if condition followed by BUG
From: kbuild test robot @ 2018-09-10 20:23 UTC (permalink / raw)
  To: zhong jiang
  Cc: kbuild-all, davem, edumazet, kuznet, yoshfuji, netdev,
	linux-kernel
In-Reply-To: <1536590282-23899-1-git-send-email-zhongjiang@huawei.com>

[-- Attachment #1: Type: text/plain, Size: 5317 bytes --]

Hi zhong,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on net/master]
[also build test ERROR on v4.19-rc3 next-20180910]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/zhong-jiang/net-ipv4-Use-BUG_ON-directly-instead-of-a-if-condition-followed-by-BUG/20180911-034152
config: x86_64-randconfig-x009-201836 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   net//ipv4/tcp_input.c: In function 'tcp_collapse':
>> net//ipv4/tcp_input.c:4925:35: error: macro "BUG" passed 1 arguments, but takes just 0
            skb_put(nskb, size), size));
                                      ^
>> net//ipv4/tcp_input.c:4924:5: error: 'BUG' undeclared (first use in this function)
        BUG(skb_copy_bits(skb, offset,
        ^~~
   net//ipv4/tcp_input.c:4924:5: note: each undeclared identifier is reported only once for each function it appears in
   net//ipv4/tcp_input.c: In function 'tcp_urg':
   net//ipv4/tcp_input.c:5318:40: error: macro "BUG" passed 1 arguments, but takes just 0
       BUG(skb_copy_bits(skb, ptr, &tmp, 1));
                                           ^
   net//ipv4/tcp_input.c:5318:4: error: 'BUG' undeclared (first use in this function)
       BUG(skb_copy_bits(skb, ptr, &tmp, 1));
       ^~~

vim +/BUG +4925 net//ipv4/tcp_input.c

  4838	
  4839	/* Collapse contiguous sequence of skbs head..tail with
  4840	 * sequence numbers start..end.
  4841	 *
  4842	 * If tail is NULL, this means until the end of the queue.
  4843	 *
  4844	 * Segments with FIN/SYN are not collapsed (only because this
  4845	 * simplifies code)
  4846	 */
  4847	static void
  4848	tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
  4849		     struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end)
  4850	{
  4851		struct sk_buff *skb = head, *n;
  4852		struct sk_buff_head tmp;
  4853		bool end_of_skbs;
  4854	
  4855		/* First, check that queue is collapsible and find
  4856		 * the point where collapsing can be useful.
  4857		 */
  4858	restart:
  4859		for (end_of_skbs = true; skb != NULL && skb != tail; skb = n) {
  4860			n = tcp_skb_next(skb, list);
  4861	
  4862			/* No new bits? It is possible on ofo queue. */
  4863			if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
  4864				skb = tcp_collapse_one(sk, skb, list, root);
  4865				if (!skb)
  4866					break;
  4867				goto restart;
  4868			}
  4869	
  4870			/* The first skb to collapse is:
  4871			 * - not SYN/FIN and
  4872			 * - bloated or contains data before "start" or
  4873			 *   overlaps to the next one.
  4874			 */
  4875			if (!(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) &&
  4876			    (tcp_win_from_space(sk, skb->truesize) > skb->len ||
  4877			     before(TCP_SKB_CB(skb)->seq, start))) {
  4878				end_of_skbs = false;
  4879				break;
  4880			}
  4881	
  4882			if (n && n != tail &&
  4883			    TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(n)->seq) {
  4884				end_of_skbs = false;
  4885				break;
  4886			}
  4887	
  4888			/* Decided to skip this, advance start seq. */
  4889			start = TCP_SKB_CB(skb)->end_seq;
  4890		}
  4891		if (end_of_skbs ||
  4892		    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)))
  4893			return;
  4894	
  4895		__skb_queue_head_init(&tmp);
  4896	
  4897		while (before(start, end)) {
  4898			int copy = min_t(int, SKB_MAX_ORDER(0, 0), end - start);
  4899			struct sk_buff *nskb;
  4900	
  4901			nskb = alloc_skb(copy, GFP_ATOMIC);
  4902			if (!nskb)
  4903				break;
  4904	
  4905			memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
  4906	#ifdef CONFIG_TLS_DEVICE
  4907			nskb->decrypted = skb->decrypted;
  4908	#endif
  4909			TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start;
  4910			if (list)
  4911				__skb_queue_before(list, skb, nskb);
  4912			else
  4913				__skb_queue_tail(&tmp, nskb); /* defer rbtree insertion */
  4914			skb_set_owner_r(nskb, sk);
  4915	
  4916			/* Copy data, releasing collapsed skbs. */
  4917			while (copy > 0) {
  4918				int offset = start - TCP_SKB_CB(skb)->seq;
  4919				int size = TCP_SKB_CB(skb)->end_seq - start;
  4920	
  4921				BUG_ON(offset < 0);
  4922				if (size > 0) {
  4923					size = min(copy, size);
> 4924					BUG(skb_copy_bits(skb, offset,
> 4925							  skb_put(nskb, size), size));
  4926					TCP_SKB_CB(nskb)->end_seq += size;
  4927					copy -= size;
  4928					start += size;
  4929				}
  4930				if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
  4931					skb = tcp_collapse_one(sk, skb, list, root);
  4932					if (!skb ||
  4933					    skb == tail ||
  4934					    (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)))
  4935						goto end;
  4936	#ifdef CONFIG_TLS_DEVICE
  4937					if (skb->decrypted != nskb->decrypted)
  4938						goto end;
  4939	#endif
  4940				}
  4941			}
  4942		}
  4943	end:
  4944		skb_queue_walk_safe(&tmp, skb, n)
  4945			tcp_rbtree_insert(root, skb);
  4946	}
  4947	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27230 bytes --]

^ permalink raw reply

* Re: [net-next, v2, 1/2] net: stmmac: Rework coalesce timer and fix multi-queue races
From: Neil Armstrong @ 2018-09-10 15:49 UTC (permalink / raw)
  To: Jose Abreu, netdev
  Cc: Jerome Brunet, Martin Blumenstingl, David S. Miller, Joao Pinto,
	Giuseppe Cavallaro, Alexandre Torgue
In-Reply-To: <9283e03e-5167-0d04-5ad9-59593a46fa8a@synopsys.com>

Hi Jose,

On 10/09/2018 16:44, Jose Abreu wrote:
> On 10-09-2018 14:46, Neil Armstrong wrote:
>> hi Jose,
>>
>> On 10/09/2018 14:55, Jose Abreu wrote:
>>> On 10-09-2018 13:52, Jose Abreu wrote:
>>>> Can you please try attached follow-up patch ? 
>>> Oh, please apply the whole series otherwise this will not apply
>>> cleanly.
>> Indeed, it helps!
>>
>> With the fixups, it fails later, around 15s instead of 3, in RX and TX.
> 
> Thanks for testing Neil. What if we keep rearming the timer
> whilst there are pending packets ? Something like in the attach.
> (applies on top of previous one).

It fixes RX, but TX fails after ~13s.

Neil

> 
> Thanks and Best Regards,
> Jose Miguel Abreu
> 

^ permalink raw reply

* Re: [PATCH 2/2] erspan: fix error handling for erspan tunnel
From: William Tu @ 2018-09-10 15:52 UTC (permalink / raw)
  To: Haishuang Yan
  Cc: David Miller, Alexey Kuznetsov, Linux Kernel Network Developers,
	LKML
In-Reply-To: <1536589188-27550-2-git-send-email-yanhaishuang@cmss.chinamobile.com>

On Mon, Sep 10, 2018 at 7:20 AM Haishuang Yan
<yanhaishuang@cmss.chinamobile.com> wrote:
>
> When processing icmp unreachable message for erspan tunnel, tunnel id
> should be erspan_net_id instead of ipgre_net_id.
>
> Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN")
> Cc: William Tu <u9012063@gmail.com>
> Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
> ---

Thanks for the fix.
Acked-by: William Tu <u9012063@gmail.com>

^ permalink raw reply

* Re: [PATCH 1/2] erspan: return PACKET_REJECT when the appropriate tunnel is not found
From: William Tu @ 2018-09-10 15:53 UTC (permalink / raw)
  To: Haishuang Yan
  Cc: David Miller, Alexey Kuznetsov, Linux Kernel Network Developers,
	LKML
In-Reply-To: <1536589188-27550-1-git-send-email-yanhaishuang@cmss.chinamobile.com>

On Mon, Sep 10, 2018 at 7:20 AM Haishuang Yan
<yanhaishuang@cmss.chinamobile.com> wrote:
>
> If erspan tunnel hasn't been established, we'd better send icmp port
> unreachable message after receive erspan packets.
>
> Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN")
> Cc: William Tu <u9012063@gmail.com>
> Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
> ---

LGTM.
Acked-by: William Tu <u9012063@gmail.com>

^ permalink raw reply

* Corrupted sit-tunnelled packets when using skb_gso_segment() on an IFB interface?
From: Toke Høiland-Jørgensen @ 2018-09-10 16:04 UTC (permalink / raw)
  To: netdev; +Cc: cake

Hi everyone

While investigating a bug report on CAKE[0], I've run into the following
behaviour:

When running CAKE as an ingress shaper on an IFB interface, if the GSO
splitting feature is turned on, TCP throughput will drop dramatically on
6in4 (sit) tunnels running over the interface in question. Looking at a
traffic dump, I'm seeing ~15% packet loss on the encapsulated TCP
stream.

IPv4 traffic is fine on the same interface, as is native IPv6 traffic.
And turning off GSO splitting in CAKE makes the packet loss go away. The
issue only seems to appear on IFB interfaces. So I'm wondering if there
is some interaction that corrupts packets when they are being split in
this configuration?

Steps to reproduce (assuming the box you are running on has IP 10.0.0.2
on eth0, and has a peer at 10.0.0.1 with a suitably configured sit
tunnel):

# modprobe ifb
# ip link set dev ifb0 up
# tc qdisc add dev eth0 handle ffff: ingress
# tc filter add dev eth0 parent ffff: protocol all prio 10 matchall action mirred egress redirect dev ifb0
# tc qdisc replace dev ifb0 root cake
# ip link add type sit local 10.0.0.2 remote 10.0.0.1
# ip link set dev sit1 up
# netperf -H fe80::a00:1%sit1 -t TCP_MAERTS

Whereas, in the same setup, this will work fine:

# netperf -H 10.0.0.1 -t TCP_MAERTS

As will this:

# tc qdisc replace dev ifb0 root cake no-split-gso
# netperf -H fe80::a00:1%sit1 -t TCP_MAERTS


Does anyone have any ideas? :)

-Toke

[0] https://github.com/tohojo/sqm-scripts/issues/72

^ permalink raw reply

* [PATCH net-next] net/ipv6: Remove rt6i_prefsrc
From: dsahern @ 2018-09-10 16:11 UTC (permalink / raw)
  To: netdev; +Cc: lucien.xin, David Ahern

From: David Ahern <dsahern@gmail.com>

After the conversion to fib6_info, rt6i_prefsrc has a single user that
reads the value and otherwise it is only set. The one reader can be
converted to use rt->from so rt6i_prefsrc can be removed, reducing
rt6_info by another 20 bytes.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 drivers/scsi/cxgbi/libcxgbi.c |  4 ++--
 include/net/ip6_fib.h         |  1 -
 net/ipv6/route.c              | 27 ---------------------------
 3 files changed, 2 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 3f3af5e74a07..6b3ea50c594e 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -784,7 +784,7 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex)
 	csk->mtu = mtu;
 	csk->dst = dst;
 
-	if (ipv6_addr_any(&rt->rt6i_prefsrc.addr)) {
+	if (!rt->from || ipv6_addr_any(&rt->from->fib6_prefsrc.addr)) {
 		struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
 
 		err = ipv6_dev_get_saddr(&init_net, idev ? idev->dev : NULL,
@@ -795,7 +795,7 @@ cxgbi_check_route6(struct sockaddr *dst_addr, int ifindex)
 			goto rel_rt;
 		}
 	} else {
-		pref_saddr = rt->rt6i_prefsrc.addr;
+		pref_saddr = rt->from->fib6_prefsrc.addr;
 	}
 
 	csk->csk_family = AF_INET6;
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 3d4930528db0..c7496663f99a 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -182,7 +182,6 @@ struct rt6_info {
 	struct in6_addr			rt6i_gateway;
 	struct inet6_dev		*rt6i_idev;
 	u32				rt6i_flags;
-	struct rt6key			rt6i_prefsrc;
 
 	struct list_head		rt6i_uncached;
 	struct uncached_list		*rt6i_uncached_list;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 18e00ce1719a..41f04b966008 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -995,7 +995,6 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct fib6_info *ort)
 #ifdef CONFIG_IPV6_SUBTREES
 	rt->rt6i_src = ort->fib6_src;
 #endif
-	rt->rt6i_prefsrc = ort->fib6_prefsrc;
 }
 
 static struct fib6_node* fib6_backtrack(struct fib6_node *fn,
@@ -1449,11 +1448,6 @@ static int rt6_insert_exception(struct rt6_info *nrt,
 	if (ort->fib6_src.plen)
 		src_key = &nrt->rt6i_src.addr;
 #endif
-
-	/* Update rt6i_prefsrc as it could be changed
-	 * in rt6_remove_prefsrc()
-	 */
-	nrt->rt6i_prefsrc = ort->fib6_prefsrc;
 	/* rt6_mtu_change() might lower mtu on ort.
 	 * Only insert this exception route if its mtu
 	 * is less than ort's mtu value.
@@ -1635,25 +1629,6 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
 	rcu_read_unlock();
 }
 
-static void rt6_exceptions_remove_prefsrc(struct fib6_info *rt)
-{
-	struct rt6_exception_bucket *bucket;
-	struct rt6_exception *rt6_ex;
-	int i;
-
-	bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
-					lockdep_is_held(&rt6_exception_lock));
-
-	if (bucket) {
-		for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
-			hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
-				rt6_ex->rt6i->rt6i_prefsrc.plen = 0;
-			}
-			bucket++;
-		}
-	}
-}
-
 static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
 					 struct rt6_info *rt, int mtu)
 {
@@ -3795,8 +3770,6 @@ static int fib6_remove_prefsrc(struct fib6_info *rt, void *arg)
 		spin_lock_bh(&rt6_exception_lock);
 		/* remove prefsrc entry */
 		rt->fib6_prefsrc.plen = 0;
-		/* need to update cache as well */
-		rt6_exceptions_remove_prefsrc(rt);
 		spin_unlock_bh(&rt6_exception_lock);
 	}
 	return 0;
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH net] ipv6: use rt6_info members when dst is set in rt6_fill_node
From: David Ahern @ 2018-09-10 16:13 UTC (permalink / raw)
  To: Xin Long; +Cc: network dev, davem, Roopa Prabhu
In-Reply-To: <CADvbK_fgFM+VZ=kew4QkuM1xP90T2rWetXo3Awu48AEjJ+nvkg@mail.gmail.com>

On 9/9/18 12:29 AM, Xin Long wrote:
>>> diff --git a/net/ipv6/route.c b/net/ipv6/route.c
>>> index 18e00ce..e554922 100644
>>> --- a/net/ipv6/route.c
>>> +++ b/net/ipv6/route.c
>>> @@ -4670,20 +4670,33 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
>>>                        int iif, int type, u32 portid, u32 seq,
>>>                        unsigned int flags)
>>>  {
>>> -     struct rtmsg *rtm;
>>> +     struct rt6key *fib6_prefsrc, *fib6_dst, *fib6_src;
>>> +     struct rt6_info *rt6 = (struct rt6_info *)dst;
>>> +     u32 *pmetrics, table, fib6_flags;
>>>       struct nlmsghdr *nlh;
>>> +     struct rtmsg *rtm;
>>>       long expires = 0;
>>> -     u32 *pmetrics;
>>> -     u32 table;
>>>
>>>       nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
>>>       if (!nlh)
>>>               return -EMSGSIZE;
>>>
>>> +     if (rt6) {
>>> +             fib6_dst = &rt6->rt6i_dst;
>>> +             fib6_src = &rt6->rt6i_src;
>>> +             fib6_flags = rt6->rt6i_flags;
>>> +             fib6_prefsrc = &rt6->rt6i_prefsrc;
>>> +     } else {
>>> +             fib6_dst = &rt->fib6_dst;
>>> +             fib6_src = &rt->fib6_src;
>>> +             fib6_flags = rt->fib6_flags;
>>> +             fib6_prefsrc = &rt->fib6_prefsrc;
>>> +     }
>>
>> Unless I am missing something at the moment, an rt6_info can only have
>> the same dst, src and prefsrc as the fib6_info on which it is based.
>> Thus, only the flags is needed above. That simplifies this patch a lot.
> If dst, src and prefsrc in rt6_info are always the same as these in fib6_info,
> why do we need them in rt6_info? we could just get it by 'from'.
> 

I just sent a patch removing rt6i_prefsrc. It is set with only 1 reader
that can be converted.

rt6i_src is checked against the fib6_info to invalidate a dst if the src
has changed, so a valid rt will always have the same rt6i_src as the
rt->from.

rt6i_dst is set to the dest address / 128 in cases, so it should be used
for rt6_info cases above.

^ permalink raw reply

* Re: [net-next, v2, 1/2] net: stmmac: Rework coalesce timer and fix multi-queue races
From: Jose Abreu @ 2018-09-10 16:21 UTC (permalink / raw)
  To: Neil Armstrong, Jose Abreu, netdev
  Cc: Jerome Brunet, Martin Blumenstingl, David S. Miller, Joao Pinto,
	Giuseppe Cavallaro, Alexandre Torgue
In-Reply-To: <d190300c-269b-1bae-569e-f09e782e49cc@baylibre.com>

[-- Attachment #1: Type: text/plain, Size: 930 bytes --]

On 10-09-2018 16:49, Neil Armstrong wrote:
> Hi Jose,
>
> On 10/09/2018 16:44, Jose Abreu wrote:
>> On 10-09-2018 14:46, Neil Armstrong wrote:
>>> hi Jose,
>>>
>>> On 10/09/2018 14:55, Jose Abreu wrote:
>>>> On 10-09-2018 13:52, Jose Abreu wrote:
>>>>> Can you please try attached follow-up patch ? 
>>>> Oh, please apply the whole series otherwise this will not apply
>>>> cleanly.
>>> Indeed, it helps!
>>>
>>> With the fixups, it fails later, around 15s instead of 3, in RX and TX.
>> Thanks for testing Neil. What if we keep rearming the timer
>> whilst there are pending packets ? Something like in the attach.
>> (applies on top of previous one).
> It fixes RX, but TX fails after ~13s.

Ok :(

Can you please try attached follow-up patch ?

I'm so sorry about this back and forth and I appreciate all your
help .

Thanks and Best Regards,
Jose Miguel Abreu


>
> Neil
>
>> Thanks and Best Regards,
>> Jose Miguel Abreu
>>


[-- Attachment #2: 0001-fixup_coalesce_3.patch --]
[-- Type: text/x-patch, Size: 3315 bytes --]

>From 4f2ba5fca6c8858cfe640f3d466fd01904c451e3 Mon Sep 17 00:00:00 2001
Message-Id: <4f2ba5fca6c8858cfe640f3d466fd01904c451e3.1536596296.git.joabreu@synopsys.com>
From: Jose Abreu <joabreu@synopsys.com>
Date: Mon, 10 Sep 2018 18:18:10 +0200
Subject: [PATCH] fixup_coalesce_3

Signed-off-by: Jose Abreu <joabreu@synopsys.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 25 ++++++-----------------
 1 file changed, 6 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 76a6196b3263..f6587ee372ab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2245,11 +2245,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue)
 {
 	struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue];
 
-	if (tx_q->tx_timer_active)
-		return;
-
 	mod_timer(&tx_q->txtimer, STMMAC_COAL_TIMER(priv->tx_coal_timer));
-	tx_q->tx_timer_active = true;
 }
 
 /**
@@ -2264,10 +2260,7 @@ static void stmmac_tx_timer(struct timer_list *t)
 	struct stmmac_priv *priv = tx_q->priv_data;
 	bool more;
 
-	tx_q->tx_timer_active = false;
 	stmmac_tx_clean(priv, ~0, tx_q->queue_index, &more);
-	if (more)
-		stmmac_tx_timer_arm(priv, tx_q->queue_index);
 }
 
 /**
@@ -2866,9 +2859,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Compute header lengths */
 	proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 
-	/* Start coalesce timer earlier in case TX Queue is stopped */
-	stmmac_tx_timer_arm(priv, queue);
-
 	/* Desc availability based on threshold should be enough safe */
 	if (unlikely(stmmac_tx_avail(priv, queue) <
 		(((skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1)))) {
@@ -2975,6 +2965,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
 		stmmac_set_tx_ic(priv, desc);
 		priv->xstats.tx_set_ic_bit++;
 		tx_q->tx_count_frames = 0;
+	} else {
+		stmmac_tx_timer_arm(priv, queue);
 	}
 
 	skb_tx_timestamp(skb);
@@ -3065,9 +3057,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 			return stmmac_tso_xmit(skb, dev);
 	}
 
-	/* Start coalesce timer earlier in case TX Queue is stopped */
-	stmmac_tx_timer_arm(priv, queue);
-
 	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
 		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
 			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
@@ -3186,6 +3175,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		stmmac_set_tx_ic(priv, desc);
 		priv->xstats.tx_set_ic_bit++;
 		tx_q->tx_count_frames = 0;
+	} else {
+		stmmac_tx_timer_arm(priv, queue);
 	}
 
 	skb_tx_timestamp(skb);
@@ -3572,16 +3563,12 @@ static int stmmac_tx_poll(struct napi_struct *napi, int budget)
 	struct stmmac_priv *priv = tx_q->priv_data;
 	u32 chan = tx_q->queue_index;
 	int work_done = 0;
-	bool more;
 
 	priv->xstats.napi_poll++;
 
-	work_done = stmmac_tx_clean(priv, budget, chan, &more);
-	if (work_done < budget) {
+	work_done = stmmac_tx_clean(priv, budget, chan, NULL);
+	if (work_done < budget)
 		napi_complete_done(napi, work_done);
-		if (more)
-			napi_reschedule(napi);
-	}
 
 	return min(work_done, budget);
 }
-- 
2.7.4


^ permalink raw reply related

* Re: [net-next, PATCH 2/2, v1] net: socionext: add AF_XDP support
From: Ilias Apalodimas @ 2018-09-10 16:21 UTC (permalink / raw)
  To: Toshiaki Makita
  Cc: netdev, jaswinder.singh, ard.biesheuvel, masami.hiramatsu, arnd,
	mykyta.iziumtsev, bjorn.topel, magnus.karlsson
In-Reply-To: <8bfd8219-acea-8b63-b6be-d17a7e3b6e24@lab.ntt.co.jp>

> > @@ -707,6 +731,26 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
> >  		if (unlikely(!buf_addr))
> >  			break;
> >  
> > +		if (xdp_prog) {
> > +			xdp_result = netsec_run_xdp(desc, priv, xdp_prog,
> > +						    pkt_len);
> > +			if (xdp_result != NETSEC_XDP_PASS) {
> > +				xdp_flush |= xdp_result & NETSEC_XDP_REDIR;
> > +
> > +				dma_unmap_single_attrs(priv->dev,
> > +						       desc->dma_addr,
> > +						       desc->len, DMA_TO_DEVICE,
> > +						       DMA_ATTR_SKIP_CPU_SYNC);
> > +
> > +				desc->len = desc_len;
> > +				desc->dma_addr = dma_handle;
> > +				desc->addr = buf_addr;
> > +				netsec_rx_fill(priv, idx, 1);
> > +				nsetsec_adv_desc(&dring->tail);
> > +			}
> > +			continue;
> 
> Continue even on XDP_PASS? Is this really correct?
> 
> Also seems there is no handling of adjust_head/tail for XDP_PASS case.
> 
A question on this. Should XDP related frames be allocated using 1 page
per packet?

Thanks

Ilias

^ permalink raw reply


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