Netdev List
 help / color / mirror / Atom feed
* Re: [RFC net-next] ipv6: Use destination address determined by IPVS
From: Hannes Frederic Sowa @ 2013-10-16 14:32 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: Simon Horman,
	YOSHIFUJI Hideaki / 吉藤英明, lvs-devel,
	netdev, Mark Brooks
In-Reply-To: <alpine.LFD.2.03.1310161015550.1560@ssi.bg>

On Wed, Oct 16, 2013 at 10:27:47AM +0300, Julian Anastasov wrote:
> 
> 	Hello,
> 
> On Wed, 16 Oct 2013, Simon Horman wrote:
> 
> > In v3.9 6fd6ce2056de2709 ("ipv6: Do not depend on rt->n in
> > ip6_finish_output2()") changed the behaviour of ip6_finish_output2()
> > such that it creates and uses a neigh entry if none is found.
> > Subsequently the 'n' field was removed from struct rt6_info.
> 
> 	Similar change in IPv4 opened the Pandora box:
> IPVS, xt_TEE, raw.c (IP_HDRINCL). May be the corrsponding
> places in IPv6 have the same problem.
> 
> 	I don't know the IPv6 routing but if we find a way
> to keep the desired nexthop in rt6i_gateway and to add
> RTF_GATEWAY checks here and there such solution would be more
> general. FLOWI_FLAG_KNOWN_NH flag can help, if needed.

I thought about this yesterday but did not see an easy way. How does the IPv4
implementation accomplish this?

ipvs caches the dst in its own infrastructure, so we need to be sure we don't
disconnect this dst from the ipv6 routing table, otherwise ip6_dst_check won't
recognize when relookups should be done. Playing games with RTF_GATEWAY seems
dangerous then.

I am currently thinking about using a new flag to replace the nexthop
information with rt6i_dst in these circumstances. The flag would have
to be included in the skb somewhere.

Greetings,

  Hannes


^ permalink raw reply

* [PATCH: Iproute bridge] remove redundant check
From: Jamal Hadi Salim @ 2013-10-16 14:33 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev@vger.kernel.org

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


attached,

cheers,
jamal

[-- Attachment #2: patch-simp1 --]
[-- Type: text/plain, Size: 1038 bytes --]

commit 355c2d4679e81c1e1c2ae12e03b6a2ced5ebb7d0
Author: Jamal Hadi Salim <jhs@mojatatu.com>
Date:   Wed Oct 16 10:30:01 2013 -0400

    [Iproute: bridge] Remove redundant check
    
    Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>

diff --git a/bridge/link.c b/bridge/link.c
index 38dfaea..ab4a5d5 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -271,7 +271,7 @@ static int brlink_modify(int argc, char **argv)
 				exit(-1);
 		} else if (strcmp(*argv, "hairpin") == 0) {
 			NEXT_ARG();
-			if (!on_off("hairping", &hairpin, *argv))
+			if (!on_off("hairpin", &hairpin, *argv))
 				exit(-1);
 		} else if (strcmp(*argv, "fastleave") == 0) {
 			NEXT_ARG();
@@ -357,9 +357,7 @@ static int brlink_modify(int argc, char **argv)
 		nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 
 		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
-
-		if (mode >= 0)
-			addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
+		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
 
 		addattr_nest_end(&req.n, nest);
 	}

^ permalink raw reply related

* Re: [PATCH net v2] be2net: Warn users of possible broken functionality on BE2 cards with very old FW versions with latest driver
From: Ivan Vecera @ 2013-10-16 14:59 UTC (permalink / raw)
  To: somnath.kotur; +Cc: David Miller, netdev
In-Reply-To: <20131007.123116.1462434377931881914.davem@davemloft.net>

On 10/07/2013 06:31 PM, David Miller wrote:
> From: Somnath Kotur <somnath.kotur@emulex.com>
> Date: Thu, 3 Oct 2013 15:34:29 +0530
>
>> +	if (BE2_chip(adapter) && memcmp(adapter->fw_ver, "4.", 2) < 0) {
>> +		dev_err(dev, "Firmware version is too old.IRQs may not work\n");
>
> So many grammatical mistakes in one line.
>
> First sentence got a period, second one did not.
>
> Missing space between period and second sentence.
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
Som, any plan to send v3?

Ivan

^ permalink raw reply

* Re: [Xen-devel] DomU's network interface will hung when Dom0 running 32bit
From: jianhai luan @ 2013-10-16 15:04 UTC (permalink / raw)
  To: Wei Liu; +Cc: annie li, xen-devel, Ian Campbell, netdev
In-Reply-To: <20131016134740.GG16371@zion.uk.xensource.com>

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


On 2013-10-16 21:47, Wei Liu wrote:
> On Wed, Oct 16, 2013 at 09:08:03PM +0800, jianhai luan wrote:
> [...]
>>>>>     expires   now   next_credit
>>>>>     ----time increases this direction--->
>>>>>
>>>>> * time_after_eq(now, next_credit) -> false
>>>>> * time_before(now, expires) -> false
>>>>>
>>>>> Then it's stuck again. You're merely narrowing the window, not fixing
>>>>> the real problem.
>>>> The above environment isn't stack again. The netback will
>>>> pending one timer to process the environment.
>>>>
>>>> The attachment program will prove if !(time_after_eq(now,
>>>> next_credit) || time_before(now, vif->credit_timeout.expires)),
>>>> now will only be placed in above environment [ expires
>>>> next_credit),  and the above environment will be processed by
>>>> timer in soon.
>>> Or check following to see what the if condition really do,
>>>
>>> ----------expires-------now-------credit----------    is the only
>>> case where we need to add a timer.
>>>
>>> Other cases like following would match the if condition above,
>>> then no timer is added.
>>> ----------expires----------credit------now------
>>> -----now-----expires----------credit----------
>>>
>>> Or we can consider the extreme condition, when the rate control
>>> does not exist, "credit_usec" is zero, and "next_credit" is equal
>>> to "expires". The above if condition would cover all conditions,
>>> and no rate control really happens. If credit_usec is not zero,
>>> the "if condition" would cover the range outside of that from
>>> expires to next_credit.
>>>
>>> Even if "now" is wrapped again into the range from "expires" to
>>> "next_credit", the "next_credit" that is set in __mod_timer is
>>> reasonable value(this can be gotten from credit_usec), and the
>>> timer would be hit soon.
>> Thanks Annie's express, my option is consistent with Annie.
>>
> OK, thanks for the explanation. I think I get the idea.
>
> In any case, could you use !time_in_range / !time_in_range_open instead
> of open coded one-liner? Though I presume one-liner open coding would
> not hurt.

I agree above the suggest. The attachment patch may be better than 
previous patch.

Jason
>
> Wei.


[-- Attachment #2: 0001-xen-netback-pending-timer-only-in-the-range-expire-n.patch --]
[-- Type: text/plain, Size: 1627 bytes --]

>From ef02403a10173896c5c102f768741d0700b8a3a2 Mon Sep 17 00:00:00 2001
From: Jason Luan <jianhai.luan@oracle.com>
Date: Tue, 15 Oct 2013 17:07:49 +0800
Subject: [PATCH] xen-netback: pending timer only in the range [expire,
 next_credit)

The function time_after_eq() do correct judge in range of MAX_UNLONG/2.
If net-front send lesser package, the delta between now and next_credit
will out of the range and time_after_eq() will do wrong judge in result
to net-front hung.  For example:
    expire    next_credit    ....    next_credit+MAX_UNLONG/2    now
    -----------------time increases this direction----------------->

We should be add the environment which now beyond next_credit+MAX_UNLONG/2.
Because the fact now mustn't before expire, time_before(now, expire) == true
will show the environment.
    time_after_eq(now, next_credit) || time_before (now, expire)
    ==
    !time_in_range_open(now, expire, next_credit)

Signed-off-by: Jason Luan <jianhai.luan@oracle.com>
---
 drivers/net/xen-netback/netback.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index f3e591c..62492f0 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1195,7 +1195,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
 		return true;
 
 	/* Passed the point where we can replenish credit? */
-	if (time_after_eq(now, next_credit)) {
+	if (!time_in_range(now, vif->credit_timeout.expires, next_credit)) {
 		vif->credit_timeout.expires = now;
 		tx_add_credit(vif);
 	}
-- 
1.7.6.5


^ permalink raw reply related

* Re: SW csum errors
From: Kyle Hubert @ 2013-10-16 15:10 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20131014135859.74f38507@nehalam.linuxnetplumber.net>

On Mon, Oct 14, 2013 at 4:58 PM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
> On Mon, 14 Oct 2013 16:13:15 -0400
> Kyle Hubert <khubert@gmail.com> wrote:
>
>> My problem is rather specific. I am working on an RDMA device, and we
>> have full end to end reliability. However, one of the initial spins of
>> our chip had some errors, since fixed, where the csum was unreliable.
>> So, we did exactly what Dave Miller warned not to do in the linked
>> message. We ran outgoing IP packets through the SKB checksum
>> function.. Unfortunately, we occasionally saw NFS csum errors on full
>> MTU packets.
>>
>> Here is his response:
>>
>> http://marc.info/?l=linux-netdev&m=128286758300676&w=2
>>
>> Relevant portion:
>>
>> "
>> Paged SKBs can have references to page cache pages and similar.  These
>> can be updated asynchronously to the transmit, there is no locking at
>> all to freeze the contents, and therefore full checksum offload is
>> required to support SG correctly.
>>
>> So don't get the idea to do the checksum in software in the infiniband
>> layer, and advertize hw checksumming support, to get around this :-)
>> "
>>
>> Now that those chips have long gone, I am left pondering about these
>> packets "corrupted" before the device transfers them. Can I get more
>> information about these paged SKBs with asynchronous modifications?
>> How does NFS use them?
>
> You would have to either mark the pages as copy on write or copy the data.
> Setting COW is expensive because you have to coordinate with other CPU's
> on SMP. Not sure exactly how.
>
> You can demonstrate this with either sendfile() or NFS where underlying
> file contents are being modified while packet is in the queue.

Thanks, I didn't realize it was as simple as file backed pages being
changed. Yes, our device does support SG, so we do have zero-copy
sendfile() support. I'll concoct a simple test to prove this.

-Kyle

^ permalink raw reply

* Re: [PATCH net-next] {selinux, af_key} Rework pfkey_sadb2xfrm_user_sec_ctx
From: Paul Moore @ 2013-10-16 15:15 UTC (permalink / raw)
  To: Fan Du; +Cc: steffen.klassert, davem, netdev
In-Reply-To: <1381904114-29556-1-git-send-email-fan.du@windriver.com>

On Wednesday, October 16, 2013 02:15:14 PM Fan Du wrote:
> Taking advantages of sadb_x_sec_ctx and xfrm_user_sec_ctx share the same
> structure arrangement, rework pfkey_sadb2xfrm_user_sec_ctx by casting
> sadb_x_sec_ctx into xfrm_user_sec_ctx with minor len fix.
> 
> Then we can:
>  -Avoid kmalloc/free memory for xfrm_user_sec_ctx, sadb_x_sec_ctx would be
>   fine.
>  -Fix missing return value check bug for pfkey_compile_policy when
>   kmalloc fails
> 
> Signed-off-by: Fan Du <fan.du@windriver.com>
> ---
>  net/key/af_key.c |   33 +--------------------------------
>  1 file changed, 1 insertion(+), 32 deletions(-)
> 
> diff --git a/net/key/af_key.c b/net/key/af_key.c
> index 9d58537..c7d304d 100644
> --- a/net/key/af_key.c
> +++ b/net/key/af_key.c
> @@ -435,22 +435,9 @@ static inline int verify_sec_ctx_len(const void *p)
> 
>  static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const
> struct sadb_x_sec_ctx *sec_ctx) {
> -	struct xfrm_user_sec_ctx *uctx = NULL;
> -	int ctx_size = sec_ctx->sadb_x_ctx_len;
> -
> -	uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL);
> -
> -	if (!uctx)
> -		return NULL;
> +	struct xfrm_user_sec_ctx *uctx = (struct xfrm_user_sec_ctx *)sec_ctx;
> 
>  	uctx->len = pfkey_sec_ctx_len(sec_ctx);
> -	uctx->exttype = sec_ctx->sadb_x_sec_exttype;
> -	uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi;
> -	uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg;
> -	uctx->ctx_len = sec_ctx->sadb_x_ctx_len;
> -	memcpy(uctx + 1, sec_ctx + 1,
> -	       uctx->ctx_len);
> -
>  	return uctx;
>  }

The fact that you are now changing sadb_x_sec_ctx->sadb_x_sec_len whenever
pfkey_sadb2xfrm_user_sec_ctx() is called raises an eyebrow.  Can you elaborate 
on why this is not a problem?

-- 
paul moore
www.paul-moore.com

^ permalink raw reply

* Re: [Xen-devel] DomU's network interface will hung when Dom0 running 32bit
From: Wei Liu @ 2013-10-16 15:17 UTC (permalink / raw)
  To: jianhai luan; +Cc: Wei Liu, annie li, xen-devel, Ian Campbell, netdev
In-Reply-To: <525EAB02.9050207@oracle.com>

On Wed, Oct 16, 2013 at 11:04:34PM +0800, jianhai luan wrote:
[...]
> >From ef02403a10173896c5c102f768741d0700b8a3a2 Mon Sep 17 00:00:00 2001
> From: Jason Luan <jianhai.luan@oracle.com>
> Date: Tue, 15 Oct 2013 17:07:49 +0800
> Subject: [PATCH] xen-netback: pending timer only in the range [expire,
>  next_credit)
> 
> The function time_after_eq() do correct judge in range of MAX_UNLONG/2.
> If net-front send lesser package, the delta between now and next_credit
> will out of the range and time_after_eq() will do wrong judge in result
> to net-front hung.  For example:
>     expire    next_credit    ....    next_credit+MAX_UNLONG/2    now
>     -----------------time increases this direction----------------->
> 
> We should be add the environment which now beyond next_credit+MAX_UNLONG/2.
> Because the fact now mustn't before expire, time_before(now, expire) == true
> will show the environment.
>     time_after_eq(now, next_credit) || time_before (now, expire)
>     ==
>     !time_in_range_open(now, expire, next_credit)
> 

OK, you say !time_in_range_open here but the code below has
!time_in_range. I suppose it is a typo?

Your patch should go against "net" tree so you need to have
"[PATCH net]" as prefix.

Also don't send your patch as attachment, send it inline. You can use
git format-patch, git send-email to do this.

Could you please fix the above issues and resend the patch to netdev,
with Ian and me CC'ed.

You can find out how netdev works in
Documentation/networking/netdev-FAQ.txt.

Last but not least, thanks for your contribution!

Wei.

> Signed-off-by: Jason Luan <jianhai.luan@oracle.com>
> ---
>  drivers/net/xen-netback/netback.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
> index f3e591c..62492f0 100644
> --- a/drivers/net/xen-netback/netback.c
> +++ b/drivers/net/xen-netback/netback.c
> @@ -1195,7 +1195,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
>  		return true;
>  
>  	/* Passed the point where we can replenish credit? */
> -	if (time_after_eq(now, next_credit)) {
> +	if (!time_in_range(now, vif->credit_timeout.expires, next_credit)) {
>  		vif->credit_timeout.expires = now;
>  		tx_add_credit(vif);
>  	}
> -- 
> 1.7.6.5
> 

^ permalink raw reply

* Re: SW csum errors
From: Eric Dumazet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: Kyle Hubert; +Cc: Stephen Hemminger, netdev
In-Reply-To: <CAJoZ4U0PNtk2e_x4D3N_fFN32uTVe6Z+FPg7ofG69KjQzsZ7xA@mail.gmail.com>

On Wed, 2013-10-16 at 11:10 -0400, Kyle Hubert wrote:

> Thanks, I didn't realize it was as simple as file backed pages being
> changed. Yes, our device does support SG, so we do have zero-copy
> sendfile() support. I'll concoct a simple test to prove this.

You also can use vmsplice()/splice() and touch anonymous memory,
no need to play with a file ;)

^ permalink raw reply

* [PATCH] WAN: Adding support for Infineon PEF2256 E1 chipset
From: Christophe Leroy @ 2013-10-16 15:25 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren,
	Ian Campbell, Rob Landley, Grant Likely, Krzysztof Halasa
  Cc: devicetree, linux-doc, linux-kernel, netdev, devicetree,
	jerome.chantelauze

The patch adds WAN support for Infineon PEF2256 E1 Chipset.

Signed-off-by: Jerome Chantelauze <jerome.chantelauze@c-s.fr>
Acked-by: Christophe Leroy <christophe.leroy@c-s.fr>

diff -urN a/drivers/net/wan/pef2256.c b/drivers/net/wan/pef2256.c
--- a/drivers/net/wan/pef2256.c	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/wan/pef2256.c	2013-10-13 13:05:01.000000000 +0200
@@ -0,0 +1,1124 @@
+/*
+ * drivers/net/wan/pef2256.c : a PEF2256 HDLC driver for Linux
+ *
+ * This software may be used and distributed according to the terms of the
+ * GNU General Public License.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/cache.h>
+#include <asm/byteorder.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/hdlc.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/etherdevice.h>
+#include "pef2256.h"
+
+static irqreturn_t pef2256_irq(int irq, void *dev_priv);
+static int Config_HDLC(struct pef2256_dev_priv *priv);
+static int init_FALC(struct pef2256_dev_priv *priv);
+static int pef2256_open(struct net_device *netdev);
+static int pef2256_close(struct net_device *netdev);
+
+void print_regs(struct device *dev)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+	struct pef2256_regs *base_addr = (struct pef2256_regs *)priv->base_addr;
+
+	netdev_info(ndev, "	MODE = 0x%02x\n", base_addr->MODE);
+	netdev_info(ndev, "	RAH1 = 0x%02x\n", base_addr->RAH1);
+	netdev_info(ndev, "	RAH2 = 0x%02x\n", base_addr->RAH2);
+	netdev_info(ndev, "	RAL1 = 0x%02x\n", base_addr->RAL1);
+	netdev_info(ndev, "	RAL2 = 0x%02x\n", base_addr->RAL2);
+	netdev_info(ndev, "	IPC = 0x%02x\n", base_addr->IPC);
+	netdev_info(ndev, "	CCR1 = 0x%02x\n", base_addr->CCR1);
+	netdev_info(ndev, "	CCR2 = 0x%02x\n", base_addr->CCR2);
+	netdev_info(ndev, "	RTR1 = 0x%02x\n", base_addr->RTR1);
+	netdev_info(ndev, "	RTR2 = 0x%02x\n", base_addr->RTR2);
+	netdev_info(ndev, "	RTR3 = 0x%02x\n", base_addr->RTR3);
+	netdev_info(ndev, "	RTR4 = 0x%02x\n", base_addr->RTR4);
+	netdev_info(ndev, "	TTR1 = 0x%02x\n", base_addr->TTR1);
+	netdev_info(ndev, "	TTR2 = 0x%02x\n", base_addr->TTR2);
+	netdev_info(ndev, "	TTR3 = 0x%02x\n", base_addr->TTR3);
+	netdev_info(ndev, "	TTR4 = 0x%02x\n", base_addr->TTR4);
+	netdev_info(ndev, "	IMR0 = 0x%02x\n", base_addr->IMR0);
+	netdev_info(ndev, "	IMR1 = 0x%02x\n", base_addr->IMR1);
+	netdev_info(ndev, "	IMR2 = 0x%02x\n", base_addr->IMR2);
+	netdev_info(ndev, "	IMR3 = 0x%02x\n", base_addr->IMR3);
+	netdev_info(ndev, "	IMR4 = 0x%02x\n", base_addr->IMR4);
+	netdev_info(ndev, "	IMR5 = 0x%02x\n", base_addr->IMR5);
+	netdev_info(ndev, "	IERR = 0x%02x\n", base_addr->IERR);
+	netdev_info(ndev, "	FMR0 = 0x%02x\n", base_addr->FMR0);
+	netdev_info(ndev, "	FMR1 = 0x%02x\n", base_addr->FMR1);
+	netdev_info(ndev, "	FMR2 = 0x%02x\n", base_addr->FMR2);
+	netdev_info(ndev, "	LOOP = 0x%02x\n", base_addr->LOOP);
+	netdev_info(ndev, "	XSW = 0x%02x\n", base_addr->XSW);
+	netdev_info(ndev, "	XSP = 0x%02x\n", base_addr->XSP);
+	netdev_info(ndev, "	XC0 = 0x%02x\n", base_addr->XC0);
+	netdev_info(ndev, "	XC1 = 0x%02x\n", base_addr->XC1);
+	netdev_info(ndev, "	RC0 = 0x%02x\n", base_addr->RC0);
+	netdev_info(ndev, "	RC1 = 0x%02x\n", base_addr->RC1);
+	netdev_info(ndev, "	XPM0 = 0x%02x\n", base_addr->XPM0);
+	netdev_info(ndev, "	XPM1 = 0x%02x\n", base_addr->XPM1);
+	netdev_info(ndev, "	XPM2 = 0x%02x\n", base_addr->XPM2);
+	netdev_info(ndev, "	TSWM = 0x%02x\n", base_addr->TSWM);
+	netdev_info(ndev, "	IDLE = 0x%02x\n", base_addr->IDLE);
+	netdev_info(ndev, "	XSA4 = 0x%02x\n", base_addr->XSA4);
+	netdev_info(ndev, "	XSA5 = 0x%02x\n", base_addr->XSA5);
+	netdev_info(ndev, "	XSA6 = 0x%02x\n", base_addr->XSA6);
+	netdev_info(ndev, "	XSA7 = 0x%02x\n", base_addr->XSA7);
+	netdev_info(ndev, "	XSA8 = 0x%02x\n", base_addr->XSA8);
+	netdev_info(ndev, "	FMR3 = 0x%02x\n", base_addr->FMR3);
+	netdev_info(ndev, "	ICB1 = 0x%02x\n", base_addr->ICB1);
+	netdev_info(ndev, "	ICB2 = 0x%02x\n", base_addr->ICB2);
+	netdev_info(ndev, "	ICB3 = 0x%02x\n", base_addr->ICB3);
+	netdev_info(ndev, "	ICB4 = 0x%02x\n", base_addr->ICB4);
+	netdev_info(ndev, "	LIM0 = 0x%02x\n", base_addr->LIM0);
+	netdev_info(ndev, "	LIM1 = 0x%02x\n", base_addr->LIM1);
+	netdev_info(ndev, "	PCD = 0x%02x\n", base_addr->PCD);
+	netdev_info(ndev, "	PCR = 0x%02x\n", base_addr->PCR);
+	netdev_info(ndev, "	LIM2 = 0x%02x\n", base_addr->LIM2);
+	netdev_info(ndev, "	LCR1 = 0x%02x\n", base_addr->LCR1);
+	netdev_info(ndev, "	LCR2 = 0x%02x\n", base_addr->LCR2);
+	netdev_info(ndev, "	LCR3 = 0x%02x\n", base_addr->LCR3);
+	netdev_info(ndev, "	SIC1 = 0x%02x\n", base_addr->SIC1);
+	netdev_info(ndev, "	SIC2 = 0x%02x\n", base_addr->SIC2);
+	netdev_info(ndev, "	SIC3 = 0x%02x\n", base_addr->SIC3);
+	netdev_info(ndev, "	CMR1 = 0x%02x\n", base_addr->CMR1);
+	netdev_info(ndev, "	CMR2 = 0x%02x\n", base_addr->CMR2);
+	netdev_info(ndev, "	GCR = 0x%02x\n", base_addr->GCR);
+	netdev_info(ndev, "	ESM = 0x%02x\n", base_addr->ESM);
+	netdev_info(ndev, "	CMR3 = 0x%02x\n", base_addr->CMR3);
+	netdev_info(ndev, "	PC1 = 0x%02x\n", base_addr->PC1);
+	netdev_info(ndev, "	PC2 = 0x%02x\n", base_addr->PC2);
+	netdev_info(ndev, "	PC3 = 0x%02x\n", base_addr->PC3);
+	netdev_info(ndev, "	PC4 = 0x%02x\n", base_addr->PC4);
+	netdev_info(ndev, "	PC5 = 0x%02x\n", base_addr->PC5);
+	netdev_info(ndev, "	GPC1 = 0x%02x\n", base_addr->GPC1);
+	netdev_info(ndev, "	PC6 = 0x%02x\n", base_addr->PC6);
+	netdev_info(ndev, "	CCR3 = 0x%02x\n", base_addr->CCR3);
+	netdev_info(ndev, "	CCR4 = 0x%02x\n", base_addr->CCR4);
+	netdev_info(ndev, "	CCR5 = 0x%02x\n", base_addr->CCR5);
+	netdev_info(ndev, "	MODE2 = 0x%02x\n", base_addr->MODE2);
+	netdev_info(ndev, "	MODE3 = 0x%02x\n", base_addr->MODE3);
+	netdev_info(ndev, "	RBC2 = 0x%02x\n", base_addr->RBC2);
+	netdev_info(ndev, "	RBC3 = 0x%02x\n", base_addr->RBC3);
+	netdev_info(ndev, "	GCM1 = 0x%02x\n", base_addr->GCM1);
+	netdev_info(ndev, "	GCM2 = 0x%02x\n", base_addr->GCM2);
+	netdev_info(ndev, "	GCM3 = 0x%02x\n", base_addr->GCM3);
+	netdev_info(ndev, "	GCM4 = 0x%02x\n", base_addr->GCM4);
+	netdev_info(ndev, "	GCM5 = 0x%02x\n", base_addr->GCM5);
+	netdev_info(ndev, "	GCM6 = 0x%02x\n", base_addr->GCM6);
+	netdev_info(ndev, "	SIS2/GCM7 = 0x%02x\n", base_addr->Dif1.SIS2);
+	netdev_info(ndev, "	RSIS2/GCM8 = 0x%02x\n",
+						base_addr->Dif2.RSIS2);
+	netdev_info(ndev, "	TSEO = 0x%02x\n", base_addr->TSEO);
+	netdev_info(ndev, "	TSBS1 = 0x%02x\n", base_addr->TSBS1);
+	netdev_info(ndev, "	TSBS2 = 0x%02x\n", base_addr->TSBS2);
+	netdev_info(ndev, "	TSBS3 = 0x%02x\n", base_addr->TSBS3);
+	netdev_info(ndev, "	TSS2 = 0x%02x\n", base_addr->TSS2);
+	netdev_info(ndev, "	TSS3 = 0x%02x\n", base_addr->TSS3);
+	netdev_info(ndev, "	Res10 = 0x%02x\n", base_addr->Res10);
+	netdev_info(ndev, "	Res11 = 0x%02x\n", base_addr->Res11);
+	netdev_info(ndev, "	TPC0 = 0x%02x\n", base_addr->TPC0);
+	netdev_info(ndev, "	GLC1 = 0x%02x\n", base_addr->GLC1);
+}
+
+static ssize_t fs_attr_regs_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	print_regs(dev);
+	return sprintf(buf, "*** printk DEBUG ***\n");
+}
+
+static DEVICE_ATTR(regs, S_IRUGO, fs_attr_regs_show, NULL);
+
+static ssize_t fs_attr_mode_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+
+	return sprintf(buf, "%d\n", priv->mode);
+}
+
+
+static ssize_t fs_attr_mode_store(struct device *dev,
+			struct device_attribute *attr,  const char *buf,
+			size_t count)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+	u32 value;
+	int ret = kstrtol(buf, 10, (long int *)&value);
+	int reconfigure = (value != priv->mode);
+
+	if (ret != 0)
+		return ret;
+
+	if (value != MASTER_MODE && value != SLAVE_MODE)
+		return -EINVAL;
+
+	priv->mode = value;
+	if (reconfigure && priv->init_done) {
+		pef2256_close(ndev);
+		init_FALC(priv);
+		pef2256_open(ndev);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, fs_attr_mode_show,
+						fs_attr_mode_store);
+
+
+
+static ssize_t fs_attr_Tx_TS_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+
+	return sprintf(buf, "0x%08x\n", priv->Tx_TS);
+}
+
+
+static ssize_t fs_attr_Tx_TS_store(struct device *dev,
+			struct device_attribute *attr,  const char *buf,
+			size_t count)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+	u32 value;
+	int ret = kstrtol(buf, 10, (long int *)&value);
+	int reconfigure = (value != priv->mode);
+
+	if (ret != 0)
+		return ret;
+
+	/* TS 0 is reserved */
+	if (value & 0x80000000)
+		return -EINVAL;
+
+	priv->Tx_TS = value;
+	if (reconfigure && priv->init_done)
+		Config_HDLC(priv);
+
+	return count;
+}
+
+static DEVICE_ATTR(Tx_TS, S_IRUGO | S_IWUSR, fs_attr_Tx_TS_show,
+			fs_attr_Tx_TS_store);
+
+
+static ssize_t fs_attr_Rx_TS_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+
+	return sprintf(buf, "0x%08x\n", priv->Rx_TS);
+}
+
+
+static ssize_t fs_attr_Rx_TS_store(struct device *dev,
+			struct device_attribute *attr,  const char *buf,
+			size_t count)
+{
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+	u32 value;
+	int ret = kstrtol(buf, 10, (long int *)&value);
+	int reconfigure = (value != priv->mode);
+
+	if (ret != 0)
+		return ret;
+
+	/* TS 0 is reserved */
+	if (value & 0x80000000)
+		return -EINVAL;
+
+	priv->Rx_TS = value;
+	if (reconfigure && priv->init_done)
+		Config_HDLC(priv);
+
+	return count;
+}
+
+static DEVICE_ATTR(Rx_TS, S_IRUGO | S_IWUSR, fs_attr_Rx_TS_show,
+	 fs_attr_Rx_TS_store);
+
+/*
+ * Setting up HDLC channel
+ */
+int Config_HDLC(struct pef2256_dev_priv *priv)
+{
+	int i;
+	int TS_idx;
+	struct pef2256_regs *base_addr;
+	u8 dummy;
+
+	/* Set framer E1 address */
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+
+	/* Read to remove pending IT */
+	dummy = base_addr->ISR0;
+	dummy = base_addr->ISR1;
+
+	/* Mask HDLC 1 Transmit IT */
+	base_addr->IMR1 |= 1;
+	base_addr->IMR1 |= 1 << 4;
+	base_addr->IMR1 |= 1 << 5;
+
+	/* Mask HDLC 1 Receive IT */
+	base_addr->IMR0 |= 1;
+	base_addr->IMR0 |= 1 << 7;
+	base_addr->IMR1 |= 1 << 6;
+
+	udelay((2 * 32) * 125);
+
+	/* MODE.HRAC = 0 (Receiver inactive)
+	   MODE.DIV = 0 (Data normal operation)
+	   for FALC V2.2 : MODE.HDLCI = 0 (normal operation) */
+	/* MODE.MDS2:0 = 100 (No address comparison) */
+	/* MODE.HRAC = 1 (Receiver active) */
+	out_8(&(base_addr->MODE), 1 << 3);
+	/* CCR1.EITS = 1 (Enable internal Time Slot 31:0 Signaling)
+	   CCR1.XMFA = 0 (No transmit multiframe alignment)
+	   CCR1.RFT1:0 = 00 (RFIFO sur 32 bytes) */
+	/* setting up Interframe Time Fill */
+	/* CCR1.ITF = 1 (Interframe Time Fill Continuous flag) */
+	out_8(&(base_addr->CCR1), 0x10 | (1 << 3));
+	/* CCR2.XCRC = 0 (Transmit CRC ON)
+	   CCR2.RCRC = 0 (Receive CRC ON, no write in RFIFO)
+	   CCR2.RADD = 0 (No write address in RFIFO) */
+	out_8(&(base_addr->CCR2), 0x00);
+
+	udelay((2 * 32) * 125);
+
+	/* MODE.HRAC = 0 (Receiver inactive)
+	   MODE.DIV = 0 (Data normal operation)
+	   for FALC V2.2 : MODE.HDLCI = 0 (normal operation) */
+	/* MODE.MDS2:0 = 100 (No address comparison) */
+	/* MODE.HRAC = 1 (Receiver active) */
+	out_8(&(base_addr->MODE), 1 << 3);
+	/* CCR1.EITS = 1 (Enable internal Time Slot 31:0 Signaling)
+	   CCR1.XMFA = 0 (No transmit multiframe alignment)
+	   CCR1.RFT1:0 = 00 (RFIFO sur 32 bytes) */
+	/* setting up Interframe Time Fill */
+	/* CCR1.ITF = 1 (Interframe Time Fill Continuous flag) */
+	out_8(&(base_addr->CCR1), 0x10 | (1 << 3));
+	/* CCR2.XCRC = 0 (Transmit CRC ON)
+	   CCR2.RCRC = 0 (Receive CRC ON, no write in RFIFO)
+	   CCR2.RADD = 0 (No write address in RFIFO) */
+	out_8(&(base_addr->CCR2), 0x00);
+
+	udelay((2 * 32) * 125);
+
+	/* MODE.HRAC = 0 (Receiver inactive)
+	   MODE.DIV = 0 (Data normal operation)
+	   for FALC V2.2 : MODE.HDLCI = 0 (normal operation) */
+	/* MODE.MDS2:0 = 100 (No address comparison) */
+	/* MODE.HRAC = 1 (Receiver active) */
+	out_8(&(base_addr->MODE), 1 << 3);
+	/* CCR1.EITS = 1 (Enable internal Time Slot 31:0 Signaling)
+	   CCR1.XMFA = 0 (No transmit multiframe alignment)
+	   CCR1.RFT1:0 = 00 (RFIFO sur 32 bytes) */
+	/* setting up Interframe Time Fill */
+	/* CCR1.ITF = 1 (Interframe Time Fill Continuous flag) */
+	out_8(&(base_addr->CCR1), 0x10 | (1 << 3));
+	/* CCR2.XCRC = 0 (Transmit CRC ON)
+	   CCR2.RCRC = 0 (Receive CRC ON, no write in RFIFO)
+	   CCR2.RADD = 0 (No write address in RFIFO) */
+	out_8(&(base_addr->CCR2), 0x00);
+
+	udelay((2 * 32) * 125);
+
+	/* Init  Time Slot select */
+	out_8(&(base_addr->TTR1), 0x00);
+	out_8(&(base_addr->TTR2), 0x00);
+	out_8(&(base_addr->TTR3), 0x00);
+	out_8(&(base_addr->TTR4), 0x00);
+	out_8(&(base_addr->RTR1), 0x00);
+	out_8(&(base_addr->RTR2), 0x00);
+	out_8(&(base_addr->RTR3), 0x00);
+	out_8(&(base_addr->RTR4), 0x00);
+	/* Set selected TS bits */
+	/* Starting at TS 1, TS 0 is reserved */
+	for (TS_idx = 1; TS_idx < 32; TS_idx++) {
+		i = 7 - (TS_idx % 8);
+		switch (TS_idx / 8) {
+		case 0:
+			if (priv->Tx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->TTR1), 1 << i);
+			if (priv->Rx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->RTR1), 1 << i);
+			break;
+		case 1:
+			if (priv->Tx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->TTR2), 1 << i);
+			if (priv->Rx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->RTR2), 1 << i);
+			break;
+		case 2:
+			if (priv->Tx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->TTR3), 1 << i);
+			if (priv->Rx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->RTR3), 1 << i);
+			break;
+		case 3:
+			if (priv->Tx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->TTR4), 1 << i);
+			if (priv->Rx_TS & (1 << (31 - TS_idx)))
+				setbits8(&(base_addr->RTR4), 1 << i);
+			break;
+		}
+	}
+
+	/* Unmask HDLC 1 Transmit IT */
+	base_addr->IMR1 &= ~1;
+	base_addr->IMR1 &= ~(1 << 4);
+	base_addr->IMR1 &= ~(1 << 5);
+
+	/* Unmask HDLC 1 Receive IT */
+	base_addr->IMR0 &= ~1;
+	base_addr->IMR0 &= ~(1 << 7);
+	base_addr->IMR1 &= ~(1 << 6);
+
+	return 0;
+}
+
+
+/*
+ * Init FALC56
+ */
+static int init_FALC(struct pef2256_dev_priv *priv)
+{
+	struct pef2256_regs *base_addr;
+	int Version;
+
+	/* Get controller version */
+	Version = priv->component_id;
+
+	/* Init FALC56 */
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+	/* RCLK output : DPLL clock, DCO-X enabled, DCO-X internal reference
+	   clock */
+	out_8(&(base_addr->CMR1), 0x00);
+	/* SCLKR selected, SCLKX selected, receive synchro pulse sourced by
+	   SYPR, transmit synchro pulse sourced by SYPX */
+	out_8(&(base_addr->CMR2), 0x00);
+	/* NRZ coding, no alarm simulation */
+	out_8(&(base_addr->FMR0), 0x00);
+	/* E1 double frame format, 2 Mbit/s system data rate, no AIS
+	   transmission to remote end or system interface, payload loop
+	   off, transmit remote alarm on */
+	out_8(&(base_addr->FMR1), 0x00);
+	out_8(&(base_addr->FMR2), 0x02);
+	/* E1 default for LIM2 */
+	out_8(&(base_addr->LIM2), 0x20);
+	if (priv->mode == MASTER_MODE)
+		/* SEC input, active high */
+		out_8(&(base_addr->GPC1), 0x00);
+	else
+		/* FSC output, active high */
+		out_8(&(base_addr->GPC1), 0x40);
+	/* internal second timer, power on */
+	out_8(&(base_addr->GCR), 0x00);
+	/* slave mode, local loop off, mode short-haul */
+	if (Version == VERSION_1_2)
+		out_8(&(base_addr->LIM0), 0x00);
+	else
+		out_8(&(base_addr->LIM0), 0x08);
+	/* analog interface selected, remote loop off */
+	out_8(&(base_addr->LIM1), 0x00);
+	if (Version == VERSION_1_2) {
+		/* function of ports RP(A to D) : output receive sync pulse
+		   function of ports XP(A to D) : output transmit line clock */
+		out_8(&(base_addr->PC1), 0x77);
+		out_8(&(base_addr->PC2), 0x77);
+		out_8(&(base_addr->PC3), 0x77);
+		out_8(&(base_addr->PC4), 0x77);
+	} else {
+		/* function of ports RP(A to D) : output high
+		   function of ports XP(A to D) : output high */
+		out_8(&(base_addr->PC1), 0xAA);
+		out_8(&(base_addr->PC2), 0xAA);
+		out_8(&(base_addr->PC3), 0xAA);
+		out_8(&(base_addr->PC4), 0xAA);
+	}
+	/* function of port RPA : input SYPR
+	   function of port XPA : input SYPX */
+	out_8(&(base_addr->PC1), 0x00);
+	/* SCLKR, SCLKX, RCLK configured to inputs,
+	   XFMS active low, CLK1 and CLK2 pin configuration */
+	out_8(&(base_addr->PC5), 0x00);
+	out_8(&(base_addr->PC6), 0x00);
+	/* the receive clock offset is cleared
+	   the receive time slot offset is cleared */
+	out_8(&(base_addr->RC0), 0x00);
+	out_8(&(base_addr->RC1), 0x9C);
+	/* 2.048 MHz system clocking rate, receive buffer 2 frames, transmit
+	   buffer bypass, data sampled and transmitted on the falling edge of
+	   SCLKR/X, automatic freeze signaling, data is active in the first
+	   channel phase */
+	out_8(&(base_addr->SIC1), 0x00);
+	out_8(&(base_addr->SIC2), 0x00);
+	out_8(&(base_addr->SIC3), 0x00);
+	/* channel loop-back and single frame mode are disabled */
+	out_8(&(base_addr->LOOP), 0x00);
+	/* all bits of the transmitted service word are cleared */
+	out_8(&(base_addr->XSW), 0x1F);
+	/* spare bit values are cleared */
+	out_8(&(base_addr->XSP), 0x00);
+	/* no transparent mode active */
+	out_8(&(base_addr->TSWM), 0x00);
+	/* the transmit clock offset is cleared
+	   the transmit time slot offset is cleared */
+	out_8(&(base_addr->XC0), 0x00);
+	out_8(&(base_addr->XC1), 0x9C);
+	/* transmitter in tristate mode */
+	out_8(&(base_addr->XPM2), 0x40);
+	/* transmit pulse mask */
+	if (Version != VERSION_1_2)
+		out_8(&(base_addr->XPM0), 0x9C);
+
+	if (Version == VERSION_1_2) {
+		/* master clock is 16,384 MHz (flexible master clock) */
+		out_8(&(base_addr->GCM2), 0x58);
+		out_8(&(base_addr->GCM3), 0xD2);
+		out_8(&(base_addr->GCM4), 0xC2);
+		out_8(&(base_addr->GCM5), 0x07);
+		out_8(&(base_addr->GCM6), 0x10);
+	} else {
+		/* master clock is 16,384 MHz (flexible master clock) */
+		out_8(&(base_addr->GCM2), 0x18);
+		out_8(&(base_addr->GCM3), 0xFB);
+		out_8(&(base_addr->GCM4), 0x0B);
+		out_8(&(base_addr->GCM5), 0x01);
+		out_8(&(base_addr->GCM6), 0x0B);
+		out_8(&(base_addr->Dif1.GCM7), 0xDB);
+		out_8(&(base_addr->Dif2.GCM8), 0xDF);
+	}
+
+	/* master mode => LIM0.MAS = 1 (bit 0) */
+	if (priv->mode == MASTER_MODE)
+		setbits8(&(base_addr->LIM0), 1 << 0);
+
+	/* transmit line in normal operation => XPM2.XLT = 0 (bit 6) */
+	clrbits8(&(base_addr->XPM2), 1 << 6);
+
+	if (Version == VERSION_1_2) {
+		/* receive input threshold = 0,21V =>
+			LIM1.RIL2:0 = 101 (bits 6, 5 et 4) */
+		setbits8(&(base_addr->LIM1), 1 << 4);
+		setbits8(&(base_addr->LIM1), 1 << 6);
+	} else {
+		/* receive input threshold = 0,21V =>
+			LIM1.RIL2:0 = 100 (bits 6, 5 et 4) */
+		setbits8(&(base_addr->LIM1), 1 << 6);
+	}
+	/* transmit line coding = HDB3 => FMR0.XC1:0 = 11 (bits 7 et 6) */
+	setbits8(&(base_addr->FMR0), 1 << 6);
+	setbits8(&(base_addr->FMR0), 1 << 7);
+	/* receive line coding = HDB3 => FMR0.RC1:0 = 11 (bits 5 et 4) */
+	setbits8(&(base_addr->FMR0), 1 << 4);
+	setbits8(&(base_addr->FMR0), 1 << 5);
+	/* detection of LOS alarm = 176 pulses (soit (10 + 1) * 16) */
+	out_8(&(base_addr->PCD), 10);
+	/* recovery of LOS alarm = 22 pulses (soit 21 + 1) */
+	out_8(&(base_addr->PCR), 21);
+	/* DCO-X center frequency => CMR2.DCOXC = 1 (bit 5) */
+	setbits8(&(base_addr->CMR2), 1 << 5);
+	if (priv->mode == SLAVE_MODE) {
+		/* select RCLK source = 2M => CMR1.RS(1:0) = 10 (bits 5 et 4) */
+		setbits8(&(base_addr->CMR1), 1 << 5);
+		/* disable switching RCLK -> SYNC => CMR1.DCS = 1 (bit 3) */
+		setbits8(&(base_addr->CMR1), 1 << 3);
+	}
+	if (Version != VERSION_1_2)
+		/* during inactive channel phase RDO into tri-state mode */
+		setbits8(&(base_addr->SIC3), 1 << 5);
+	if (!strcmp(priv->rising_edge_sync_pulse, "transmit")) {
+		/* rising edge sync pulse transmit => SIC3.RESX = 1 (bit 3) */
+		setbits8(&(base_addr->SIC3), 1 << 3);
+	} else {
+		/* rising edge sync pulse receive => SIC3.RESR = 1 (bit 2) */
+		setbits8(&(base_addr->SIC3), 1 << 2);
+	}
+	/* transmit offset counter = 4
+	   => XC0.XCO10:8 = 000 (bits 2, 1 et 0);
+	      XC1.XCO7:0 = 4 (bits 7 ... 0) */
+	out_8(&(base_addr->XC1), 4);
+	/* receive offset counter = 4
+	   => RC0.RCO10:8 = 000 (bits 2, 1 et 0);
+	      RC1.RCO7:0 = 4 (bits 7 ... 0) */
+	out_8(&(base_addr->RC1), 4);
+
+	/* clocking rate 8M and data rate 2M on the system highway */
+	setbits8(&(base_addr->SIC1), 1 << 7);
+	/* data rate 4M on the system highway */
+	if (priv->data_rate == DATA_RATE_4M)
+		setbits8(&(base_addr->FMR1), 1 << 1);
+	/* data rate 8M on the system highway */
+	if (priv->data_rate == DATA_RATE_8M)
+		setbits8(&(base_addr->SIC1), 1 << 6);
+	/* channel phase for FALC56 */
+	if ((priv->channel_phase == CHANNEL_PHASE_1)
+		|| (priv->channel_phase == CHANNEL_PHASE_3))
+		setbits8(&(base_addr->SIC2), 1 << 1);
+	if ((priv->channel_phase == CHANNEL_PHASE_2)
+		|| (priv->channel_phase == CHANNEL_PHASE_3))
+		setbits8(&(base_addr->SIC2), 1 << 2);
+
+	if (priv->mode == SLAVE_MODE) {
+		/* transmit buffer size = 2 frames =>
+			SIC1.XBS1:0 = 10 (bits 1 et 0) */
+		setbits8(&(base_addr->SIC1), 1 << 1);
+	}
+
+	/* transmit in multiframe => FMR1.XFS = 1 (bit 3) */
+	setbits8(&(base_addr->FMR1), 1 << 3);
+	/* receive in multiframe => FMR2.RFS1:0 = 10 (bits 7 et 6) */
+	setbits8(&(base_addr->FMR2), 1 << 7);
+	/* Automatic transmission of submultiframe status =>
+		XSP.AXS = 1 (bit 3) */
+	setbits8(&(base_addr->XSP), 1 << 3);
+
+	/* error counter mode toutes les 1s => FMR1.ECM = 1 (bit 2) */
+	setbits8(&(base_addr->FMR1), 1 << 2);
+	/* error counter mode COFA => GCR.ECMC = 1 (bit 4) */
+	setbits8(&(base_addr->GCR), 1 << 4);
+	/* errors in service words with no influence => RC0.SWD = 1 (bit 7) */
+	setbits8(&(base_addr->RC0), 1 << 7);
+	/* 4 consecutive incorrect FAS = loss of sync => RC0.ASY4 = 1 (bit 6) */
+	setbits8(&(base_addr->RC0), 1 << 6);
+	/* Si-Bit in service word from XDI => XSW.XSIS = 1 (bit 7) */
+	setbits8(&(base_addr->XSW), 1 << 7);
+	/* Si-Bit in FAS word from XDI => XSP.XSIF = 1 (bit 2) */
+	setbits8(&(base_addr->XSP), 1 << 2);
+
+	/* port RCLK is output => PC5.CRP = 1 (bit 0) */
+	setbits8(&(base_addr->PC5), 1 << 0);
+	/* visibility of the masked interrupts => GCR.VIS = 1 (bit 7) */
+	setbits8(&(base_addr->GCR), 1 << 7);
+	/* reset lines
+	   => CMDR.RRES = 1 (bit 6); CMDR.XRES = 1 (bit 4);
+	      CMDR.SRES = 1 (bit 0) */
+	out_8(&(base_addr->CMDR), 0x51);
+
+	return 0;
+}
+
+
+
+static int pef2256_open(struct net_device *netdev)
+{
+	struct pef2256_dev_priv *priv = dev_to_hdlc(netdev)->priv;
+	struct pef2256_regs *base_addr = (struct pef2256_regs *)priv->base_addr;
+	int ret;
+
+	if (hdlc_open(netdev))
+		return -EAGAIN;
+
+	ret = request_irq(priv->irq, pef2256_irq, 0, "e1-wan", priv);
+	if (ret) {
+		dev_err(priv->dev, "Cannot request irq. Device seems busy.\n");
+		return -EBUSY;
+	}
+
+	if (priv->component_id != VERSION_UNDEF) {
+		ret = init_FALC(priv);
+	} else {
+		dev_err(priv->dev, "Composant ident (%X/%X) = %d\n",
+			base_addr->VSTR, base_addr->WID, priv->component_id);
+		ret = -ENODEV;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	priv->tx_skb = NULL;
+	priv->rx_len = 0;
+
+	Config_HDLC(priv);
+
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
+	priv->init_done = 1;
+
+	return 0;
+}
+
+
+static int pef2256_close(struct net_device *netdev)
+{
+	struct pef2256_dev_priv *priv = dev_to_hdlc(netdev)->priv;
+
+	if (!priv->init_done)
+		return 0;
+
+	priv->init_done = 0;
+	netif_stop_queue(netdev);
+	hdlc_close(netdev);
+	free_irq(priv->irq, priv);
+
+	/* Do E1 stuff */
+
+	return 0;
+}
+
+
+
+static int pef2256_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	int ret;
+
+	ret = hdlc_ioctl(dev, ifr, cmd);
+	return ret;
+}
+
+static int pef2256_rx(struct pef2256_dev_priv *priv)
+{
+	struct sk_buff *skb;
+	int idx, size;
+	struct pef2256_regs *base_addr;
+
+	base_addr = priv->base_addr;
+
+	/* RDO has been received -> wait for RME */
+	if (priv->rx_len == -1) {
+		/* Acknowledge the FIFO */
+		setbits8(&(base_addr->CMDR), 1 << 7);
+
+		if (priv->ISR0 & (1 << 7))
+			priv->rx_len = 0;
+
+		return 0;
+	}
+
+	/* RPF : a block is available in the receive FIFO */
+	if (priv->ISR0 & 1) {
+		for (idx = 0; idx < 32; idx++)
+			priv->rx_buff[priv->rx_len + idx] =
+				base_addr->FIFO.RFIFO[idx & 1];
+
+		/* Acknowledge the FIFO */
+		setbits8(&(base_addr->CMDR), 1 << 7);
+
+		priv->rx_len += 32;
+	}
+
+	/* RME : Message end : Read the receive FIFO */
+	if (priv->ISR0 & (1 << 7)) {
+		/* Get size of last block */
+		size = base_addr->RBCL & 0x1F;
+
+		/* Read last block */
+		for (idx = 0; idx < size; idx++)
+			priv->rx_buff[priv->rx_len + idx] =
+				base_addr->FIFO.RFIFO[idx & 1];
+
+		/* Acknowledge the FIFO */
+		setbits8(&(base_addr->CMDR), 1 << 7);
+
+		priv->rx_len += size;
+
+		/* Packet received */
+		if (priv->rx_len > 0) {
+			skb = dev_alloc_skb(priv->rx_len);
+			if (!skb) {
+				priv->rx_len = 0;
+				priv->netdev->stats.rx_dropped++;
+				return -ENOMEM;
+			}
+			memcpy(skb->data, priv->rx_buff, priv->rx_len);
+			skb_put(skb, priv->rx_len);
+			priv->rx_len = 0;
+			skb->protocol = hdlc_type_trans(skb, priv->netdev);
+			priv->netdev->stats.rx_packets++;
+			priv->netdev->stats.rx_bytes += skb->len;
+			netif_rx(skb);
+		}
+	}
+
+	return 0;
+}
+
+
+static int pef2256_tx(struct pef2256_dev_priv *priv)
+{
+	int idx, size;
+	struct pef2256_regs *base_addr;
+	u8 *tx_buff = priv->tx_skb->data;
+
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+
+	/* ALLS : transmit all done */
+	if (priv->ISR1 & (1 << 5)) {
+		priv->netdev->stats.tx_packets++;
+		priv->netdev->stats.tx_bytes += priv->tx_skb->len;
+		/* dev_kfree_skb(priv->tx_skb); */
+		priv->tx_skb = NULL;
+		priv->tx_len = 0;
+		netif_wake_queue(priv->netdev);
+	}
+	/* XPR : write a new block in transmit FIFO */
+	else if (priv->tx_len < priv->tx_skb->len) {
+		size = priv->tx_skb->len - priv->tx_len;
+		if (size > 32)
+			size = 32;
+
+		for (idx = 0; idx < size; idx++)
+			base_addr->FIFO.XFIFO[idx & 1] =
+				tx_buff[priv->tx_len + idx];
+
+		priv->tx_len += size;
+
+		if (priv->tx_len == priv->tx_skb->len)
+			base_addr->CMDR |= ((1 << 3) | (1 << 1));
+		else
+			setbits8(&(base_addr->CMDR), 1 << 3);
+	}
+
+	return 0;
+}
+
+
+irqreturn_t pef2256_irq(int irq, void *dev_priv)
+{
+	struct pef2256_dev_priv *priv = (struct pef2256_dev_priv *)dev_priv;
+	struct pef2256_regs *base_addr;
+	u8 GIS;
+
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+	GIS = base_addr->GIS;
+
+	priv->ISR0 = priv->ISR1 = 0;
+
+	/* We only care about ISR0 and ISR1 */
+	/* ISR0 */
+	if (GIS & 1)
+		priv->ISR0 = base_addr->ISR0 & ~(base_addr->IMR0);
+	/* ISR1 */
+	if (GIS & (1 << 1))
+		priv->ISR1 = base_addr->ISR1 & ~(base_addr->IMR1);
+
+	/* Don't do anything else before init is done */
+	if (!priv->init_done)
+		return IRQ_HANDLED;
+
+	/* RDO : Receive data overflow -> RX error */
+	if (priv->ISR1 & (1 << 6)) {
+		/* Acknowledge the FIFO */
+		setbits8(&(base_addr->CMDR), 1 << 7);
+		priv->netdev->stats.rx_errors++;
+		/* RME received ? */
+		if (priv->ISR0 & (1 << 7))
+			priv->rx_len = 0;
+		else
+			priv->rx_len = -1;
+		return IRQ_HANDLED;
+	}
+
+	/* XDU : Transmit data underrun -> TX error */
+	if (priv->ISR1 & (1 << 4)) {
+		priv->netdev->stats.tx_errors++;
+		/* dev_kfree_skb(priv->tx_skb); */
+		priv->tx_skb = NULL;
+		netif_wake_queue(priv->netdev);
+		return IRQ_HANDLED;
+	}
+
+	/* RPF or RME : FIFO received */
+	if (priv->ISR0 & (1 | (1 << 7)))
+		pef2256_rx(priv);
+
+	/* XPR or ALLS : FIFO sent */
+	if (priv->ISR1 & (1 | (1 << 5)))
+		pef2256_tx(priv);
+
+	return IRQ_HANDLED;
+}
+
+
+static netdev_tx_t pef2256_start_xmit(struct sk_buff *skb,
+					  struct net_device *netdev)
+{
+	struct pef2256_dev_priv *priv = dev_to_hdlc(netdev)->priv;
+	int idx, size;
+	struct pef2256_regs *base_addr;
+	u8 *tx_buff = skb->data;
+
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+
+	priv->tx_skb = skb;
+	priv->tx_len = 0;
+
+	size = priv->tx_skb->len - priv->tx_len;
+	if (size > 32)
+		size = 32;
+
+	for (idx = 0; idx < size; idx++)
+		base_addr->FIFO.XFIFO[idx & 1] = tx_buff[priv->tx_len + idx];
+
+	priv->tx_len += size;
+
+	setbits8(&(base_addr->CMDR), 1 << 3);
+	if (priv->tx_len == priv->tx_skb->len)
+		setbits8(&(base_addr->CMDR), 1 << 1);
+
+	netif_stop_queue(netdev);
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops pef2256_ops = {
+	.ndo_open       = pef2256_open,
+	.ndo_stop       = pef2256_close,
+	.ndo_change_mtu = hdlc_change_mtu,
+	.ndo_start_xmit = hdlc_start_xmit,
+	.ndo_do_ioctl   = pef2256_ioctl,
+};
+
+
+static int pef2256_hdlc_attach(struct net_device *netdev,
+				unsigned short encoding, unsigned short parity)
+{
+	struct pef2256_dev_priv *priv = dev_to_hdlc(netdev)->priv;
+
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
+
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0_CCITT &&
+	    parity != PARITY_CRC16_PR1_CCITT &&
+	    parity != PARITY_CRC32_PR0_CCITT &&
+	    parity != PARITY_CRC32_PR1_CCITT)
+		return -EINVAL;
+
+	priv->encoding = encoding;
+	priv->parity = parity;
+	return 0;
+}
+
+
+/*
+ * Loading module
+ */
+static const struct of_device_id pef2256_match[];
+static int pef2256_probe(struct platform_device *ofdev)
+{
+	const struct of_device_id *match;
+	struct pef2256_dev_priv *priv;
+	int ret = -ENOMEM;
+	struct net_device *netdev;
+	hdlc_device *hdlc;
+	int sys_ret;
+	struct pef2256_regs *base_addr;
+	struct device_node *np = (&ofdev->dev)->of_node;
+	const u32 *data;
+	int len;
+
+	match = of_match_device(pef2256_match, &ofdev->dev);
+	if (!match)
+		return -EINVAL;
+
+	dev_err(&ofdev->dev, "Found PEF2256\n");
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return ret;
+
+	priv->dev = &ofdev->dev;
+
+	data = of_get_property(np, "data-rate", &len);
+	if (!data || len != 4) {
+		dev_err(&ofdev->dev, "failed to read data-rate -> using 8Mb\n");
+		priv->data_rate = DATA_RATE_8M;
+	} else
+		priv->data_rate = *data;
+
+	data = of_get_property(np, "channel-phase", &len);
+	if (!data || len != 4) {
+		dev_err(&ofdev->dev, "failed to read channel phase -> using 0\n");
+		priv->channel_phase = CHANNEL_PHASE_0;
+	} else
+		priv->channel_phase = *data;
+
+	data = of_get_property(np, "rising-edge-sync-pulse", NULL);
+	if (!data) {
+		dev_err(&ofdev->dev, "failed to read rising edge sync pulse -> using \"transmit\"\n");
+		strcpy(priv->rising_edge_sync_pulse, "transmit");
+	} else if (strcmp((char *)data, "transmit") &&
+			strcmp((char *)data, "receive")) {
+		dev_err(&ofdev->dev, "invalid rising edge sync pulse -> using \"transmit\"\n");
+		strcpy(priv->rising_edge_sync_pulse, "transmit");
+	} else
+		strncpy(priv->rising_edge_sync_pulse, (char *)data, 10);
+
+	priv->irq = of_irq_to_resource(np, 0, NULL);
+	if (!priv->irq) {
+		dev_err(priv->dev, "no irq defined\n");
+		return -EINVAL;
+	}
+
+	priv->base_addr = of_iomap(np, 0);
+	if (!priv->base_addr) {
+		dev_err(&ofdev->dev, "of_iomap failed\n");
+		kfree(priv);
+		return ret;
+	}
+
+	/* Get the component Id */
+	base_addr = (struct pef2256_regs *)priv->base_addr;
+	priv->component_id = VERSION_UNDEF;
+	if (base_addr->VSTR == 0x00) {
+		if ((base_addr->WID & WID_IDENT_1) ==
+			WID_IDENT_1_2)
+			priv->component_id = VERSION_1_2;
+	} else if (base_addr->VSTR == 0x05) {
+		if ((base_addr->WID & WID_IDENT_2) ==
+			WID_IDENT_2_1)
+			priv->component_id = VERSION_2_1;
+		else if ((base_addr->WID & WID_IDENT_2) == WID_IDENT_2_2)
+			priv->component_id = VERSION_2_2;
+	}
+
+	priv->tx_skb = NULL;
+
+	/* Default settings ; Rx and Tx use TS 1, mode = MASTER */
+	priv->Rx_TS = 0x40000000;
+	priv->Tx_TS = 0x40000000;
+	priv->mode = 0;
+
+	netdev = alloc_hdlcdev(priv);
+	if (!netdev) {
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	priv->netdev = netdev;
+	hdlc = dev_to_hdlc(netdev);
+	netdev->netdev_ops = &pef2256_ops;
+	SET_NETDEV_DEV(netdev, &ofdev->dev);
+	hdlc->attach = pef2256_hdlc_attach;
+	hdlc->xmit = pef2256_start_xmit;
+
+	dev_set_drvdata(&ofdev->dev, netdev);
+
+	ret = register_hdlc_device(netdev);
+	if (ret < 0) {
+		pr_err("unable to register\n");
+		return ret;
+	}
+
+	sys_ret = 0;
+	sys_ret |= device_create_file(priv->dev, &dev_attr_mode);
+	sys_ret |= device_create_file(priv->dev, &dev_attr_Tx_TS);
+	sys_ret |= device_create_file(priv->dev, &dev_attr_Rx_TS);
+	sys_ret |= device_create_file(priv->dev, &dev_attr_regs);
+
+	if (sys_ret) {
+		device_remove_file(priv->dev, &dev_attr_mode);
+		unregister_hdlc_device(priv->netdev);
+		free_netdev(priv->netdev);
+	}
+
+	priv->init_done = 0;
+
+	return 0;
+}
+
+
+/*
+ * Suppression du module
+ */
+static int pef2256_remove(struct platform_device *ofdev)
+{
+	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+	struct pef2256_dev_priv *priv = dev_to_hdlc(ndev)->priv;
+
+	device_remove_file(priv->dev, &dev_attr_Rx_TS);
+	device_remove_file(priv->dev, &dev_attr_Tx_TS);
+	device_remove_file(priv->dev, &dev_attr_mode);
+
+	unregister_hdlc_device(priv->netdev);
+	free_netdev(priv->netdev);
+
+	/* Do E1 stuff */
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(ofdev);
+	return 0;
+}
+
+static const struct of_device_id pef2256_match[] = {
+	{
+		.compatible = "infineon,pef2256",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, pef2256_match);
+
+
+static struct platform_driver pef2256_driver = {
+	.probe		= pef2256_probe,
+	.remove		= pef2256_remove,
+	.driver		= {
+		.name	= "pef2256",
+		.owner	= THIS_MODULE,
+		.of_match_table	= pef2256_match,
+	},
+};
+
+
+static int __init pef2256_init(void)
+{
+	int ret;
+	ret = platform_driver_register(&pef2256_driver);
+	return ret;
+}
+module_init(pef2256_init);
+
+
+static void __exit pef2256_exit(void)
+{
+	platform_driver_unregister(&pef2256_driver);
+}
+module_exit(pef2256_exit);
+
+
+/* GENERAL INFORMATIONS */
+MODULE_AUTHOR("CHANTELAUZE Jerome - April 2013");
+MODULE_VERSION("0.1");
+MODULE_DESCRIPTION("Infineon PEF 2256 E1 Controller");
+MODULE_LICENSE("GPL");
diff -urN a/drivers/net/wan/pef2256.h b/drivers/net/wan/pef2256.h
--- a/drivers/net/wan/pef2256.h	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/wan/pef2256.h	2013-10-13 13:06:00.000000000 +0200
@@ -0,0 +1,269 @@
+/*
+ * drivers/net/wan/pef2256.c : a PEF2256 HDLC driver for Linux
+ *
+ * This software may be used and distributed according to the terms of the
+ * GNU General Public License.
+ *
+ */
+
+#ifndef _PEF2256_H
+#define _PEF2256_H
+
+#define MASTER_MODE 0
+#define SLAVE_MODE  1
+
+#define CHANNEL_PHASE_0 0
+#define CHANNEL_PHASE_1 1
+#define CHANNEL_PHASE_2 2
+#define CHANNEL_PHASE_3 3
+
+#define DATA_RATE_4M 4
+#define DATA_RATE_8M 8
+
+#define RX_TIMEOUT 500
+
+enum versions {
+	VERSION_UNDEF = 0,
+	VERSION_1_2 = 0x12,
+	VERSION_2_1 = 0x21,
+	VERSION_2_2 = 0x22,
+};
+
+#define WID_IDENT_1		0x03
+#define WID_IDENT_1_2		0x03
+#define WID_IDENT_2		0xC0
+#define WID_IDENT_2_1		0x00
+#define WID_IDENT_2_2		0x40
+
+
+struct pef2256_dev_priv {
+	struct sk_buff *tx_skb;
+	u16 tx_len;
+	struct device *dev;
+
+	int init_done;
+
+	void *base_addr;
+	int component_id;
+	int mode;	/* MASTER or SLAVE */
+	int board_type;
+	int channel_phase;
+	int data_rate;
+	char rising_edge_sync_pulse[10];
+
+	u16 rx_len;
+	u8 rx_buff[2048];
+
+	u32 Tx_TS;	/* Transmit Time Slots */
+	u32 Rx_TS;	/* Receive Time Slots */
+
+	unsigned short encoding;
+	unsigned short parity;
+	struct net_device *netdev;
+
+	int irq;
+
+	u8 ISR0;			/* ISR0 register */
+	u8 ISR1;			/* ISR1 register */
+};
+
+
+/* Framer E1 registers */
+union pef2256_Fifo {
+	u8	XFIFO[sizeof(u16)];		/* Transmit FIFO */
+	u8	RFIFO[sizeof(u16)];		/* Receive FIFO */
+};
+
+union pef2256_60 {
+	unsigned char	DEC;	/* Disable Error Counter */
+	unsigned char	RSA8;	/* Receive Sa8-Bit Regiter */
+};
+
+union pef2256_CAS {
+	unsigned char	XS;	/* Transmit CAS Register */
+	unsigned char	RS;	/* Receive CAS Regiter */
+};
+
+union pef2256_Dif1 {
+	unsigned char	SIS2;	/* V1.2 : Signaling Status Register 2 */
+	unsigned char	GCM7;	/* V2.2 : Global Counter Mode 7 */
+};
+
+union pef2256_Dif2 {
+	unsigned char	RSIS2;	/* V1.2 : Rx Signaling Status Register 2 */
+	unsigned char	GCM8;	/* V2.2 : Global Counter Mode 8 */
+};
+
+struct pef2256_regs {
+	union pef2256_Fifo	FIFO;	/* 0x00/0x01	FIFO (Tx or rx) */
+	unsigned char	CMDR;	/* 0x02	Command Register */
+	unsigned char	MODE;	/* 0x03	Mode Register */
+	unsigned char	RAH1;	/* 0x04	Receive Address High 1 */
+	unsigned char	RAH2;	/* 0x05	Receive Address High 2 */
+	unsigned char	RAL1;	/* 0x06	Receive Address Low 1 */
+	unsigned char	RAL2;	/* 0x07	Receive Address Low 2 */
+	unsigned char	IPC;	/* 0x08	Interrupt Port Configuration */
+	unsigned char	CCR1;	/* 0x09	Common Configuration Register 1 */
+	unsigned char	CCR2;	/* 0x0A	Common Configuration Register 2 */
+	unsigned char	Res1;	/* 0x0B	Free Register 1 */
+	unsigned char	RTR1;	/* 0x0C	Receive Time Slot Register 1 */
+	unsigned char	RTR2;	/* 0x0D	Receive Time Slot Register 2 */
+	unsigned char	RTR3;	/* 0x0E	Receive Time Slot Register 3 */
+	unsigned char	RTR4;	/* 0x0F	Receive Time Slot Register 4 */
+	unsigned char	TTR1;	/* 0x10	Transmit Time Slot Register 1 */
+	unsigned char	TTR2;	/* 0x11	Transmit Time Slot Register 2 */
+	unsigned char	TTR3;	/* 0x12	Transmit Time Slot Register 3 */
+	unsigned char	TTR4;	/* 0x13	Transmit Time Slot Register 4 */
+	unsigned char	IMR0;	/* 0x14	Interrupt Mask Register 0 */
+	unsigned char	IMR1;	/* 0x15	Interrupt Mask Register 1 */
+	unsigned char	IMR2;	/* 0x16	Interrupt Mask Register 2 */
+	unsigned char	IMR3;	/* 0x17	Interrupt Mask Register 3 */
+	unsigned char	IMR4;	/* 0x18	Interrupt Mask Register 4 */
+	unsigned char	IMR5;	/* 0x19	Interrupt Mask Register 5 */
+	unsigned char	Res2;	/* 0x1A	Free Register 2 */
+	unsigned char	IERR;	/* 0x1B	Single Bit Error Insertion Register */
+	unsigned char	FMR0;	/* 0x1C	Framer Mode Register 0 */
+	unsigned char	FMR1;	/* 0x1D	Framer Mode Register 1 */
+	unsigned char	FMR2;	/* 0x1E	Framer Mode Register 2 */
+	unsigned char	LOOP;	/* 0x1F	Channel Loop-Back */
+	unsigned char	XSW;	/* 0x20	Transmit Service Word */
+	unsigned char	XSP;	/* 0x21	Transmit Spare Bits */
+	unsigned char	XC0;	/* 0x22	Transmit Control 0 */
+	unsigned char	XC1;	/* 0x23	Transmit Control 1 */
+	unsigned char	RC0;	/* 0x24	Receive Control 0 */
+	unsigned char	RC1;	/* 0x25	Receive Control 1 */
+	unsigned char	XPM0;	/* 0x26	Transmit Pulse Mask 0 */
+	unsigned char	XPM1;	/* 0x27	Transmit Pulse Mask 1 */
+	unsigned char	XPM2;	/* 0x28	Transmit Pulse Mask 2 */
+	unsigned char	TSWM;	/* 0x29	Transparent Service Word Mask */
+	unsigned char	Res3;	/* 0x2A	Free Register 3 */
+	unsigned char	IDLE;	/* 0x2B	Idle Channel Code */
+	unsigned char	XSA4;	/* 0x2C	Transmit Sa4-Bit Register */
+	unsigned char	XSA5;	/* 0x2D	Transmit Sa5-Bit Register */
+	unsigned char	XSA6;	/* 0x2E	Transmit Sa6-Bit Register */
+	unsigned char	XSA7;	/* 0x2F	Transmit Sa7-Bit Register */
+	unsigned char	XSA8;	/* 0x30	Transmit Sa8-Bit Register */
+	unsigned char	FMR3;	/* 0x31	Framer Mode Register 3 */
+	unsigned char	ICB1;	/* 0x32	Idle Channel Register 1 */
+	unsigned char	ICB2;	/* 0x33	Idle Channel Register 2 */
+	unsigned char	ICB3;	/* 0x34	Idle Channel Register 3 */
+	unsigned char	ICB4;	/* 0x35	Idle Channel Register 4 */
+	unsigned char	LIM0;	/* 0x36	Line Interface Mode 0 */
+	unsigned char	LIM1;	/* 0x37	Line Interface Mode 1 */
+	unsigned char	PCD;	/* 0x38	Pulse Count Detection */
+	unsigned char	PCR;	/* 0x39	Pulse Count Recovery */
+	unsigned char	LIM2;	/* 0x3A	Line Interface Mode 2 */
+	unsigned char	LCR1;	/* 0x3B	Loop Code Register 1 */
+	unsigned char	LCR2;	/* 0x3C	Loop Code Register 2 */
+	unsigned char	LCR3;	/* 0x3D	Loop Code Register 3 */
+	unsigned char	SIC1;	/* 0x3E	System Interface Control 1 */
+	unsigned char	SIC2;	/* 0x3F	System Interface Control 2 */
+	unsigned char	SIC3;	/* 0x40	System Interface Control 3 */
+	unsigned char	Res4;	/* 0x41	Free Register 4 */
+	unsigned char	Res5;	/* 0x42	Free Register 5 */
+	unsigned char	Res6;	/* 0x43	Free Register 6 */
+	unsigned char	CMR1;	/* 0x44	Clock Mode Register 1 */
+	unsigned char	CMR2;	/* 0x45	Clock Mode Register 2 */
+	unsigned char	GCR;	/* 0x46	Global Configuration Register */
+	unsigned char	ESM;	/* 0x47	Errored Second Mask */
+	unsigned char	CMR3;	/* 0x48	Clock Mode Register 3 en V2.2 */
+	unsigned char	RBD;	/* 0x49	Receive Buffer Delay */
+	unsigned char	VSTR;	/* 0x4A	Version Status Regiter */
+	unsigned char	RES;	/* 0x4B	Receive Equalizer Status */
+	unsigned char	FRS0;	/* 0x4C	Framer Receive Status 0 */
+	unsigned char	FRS1;	/* 0x4D	Framer Receive Status 1 */
+	unsigned char	RSW;	/* 0x4E	Receive Service Word */
+	unsigned char	RSP;	/* 0x4F	Receive Spare Bits */
+	unsigned short	FEC;	/* 0x50/0x51 Framing Error Counter */
+	unsigned short	CVC;	/* 0x52/0x53 Code Violation Counter */
+	unsigned short	CEC1;	/* 0x54/0x55 CRC Error Counter 1 */
+	unsigned short	EBC;	/* 0x56/0x57 E-Bit Error Counter */
+	unsigned short	CEC2;	/* 0x58/0x59 CRC Error Counter 2 */
+	unsigned short	CEC3;	/* 0x5A/0x5B CRC Error Counter 3 */
+	unsigned char	RSA4;	/* 0x5C	Receive Sa4-Bit Register */
+	unsigned char	RSA5;	/* 0x5D	Receive Sa5-Bit Register */
+	unsigned char	RSA6;	/* 0x5E	Receive Sa6-Bit Register */
+	unsigned char	RSA7;	/* 0x5F	Receive Sa7-Bit Register */
+	union pef2256_60	Reg60;	/* 0x60	Common Register */
+	unsigned char	RSA6S;	/* 0x61	Receive Sa6-Bit Status Register */
+	unsigned char	RSP1;	/* 0x62	Receive Signaling Pointer 1 */
+	unsigned char	RSP2;	/* 0x63	Receive Signaling Pointer 2 */
+	unsigned char	SIS;	/* 0x64	Signaling Status Register */
+	unsigned char	RSIS;	/* 0x65	Receive Signaling Status Register */
+	unsigned char	RBCL;	/* 0x66	Receive Byte Control */
+	unsigned char	RBCH;	/* 0x67	Receive Byte Control */
+	unsigned char	ISR0;	/* 0x68	Interrupt Status Register 0 */
+	unsigned char	ISR1;	/* 0x69	Interrupt Status Register 1 */
+	unsigned char	ISR2;	/* 0x6A	Interrupt Status Register 2 */
+	unsigned char	ISR3;	/* 0x6B	Interrupt Status Register 3 */
+	unsigned char	ISR4;	/* 0x6C	Interrupt Status Register 4 */
+	unsigned char	ISR5;	/* 0x6D	Interrupt Status Register 5 */
+	unsigned char	GIS;	/* 0x6E	Global Interrupt Status */
+	unsigned char	Res8;	/* 0x6F	Free Register 8 */
+	union pef2256_CAS	CAS1;	/* 0x70	CAS Register 1 */
+	union pef2256_CAS	CAS2;	/* 0x71	CAS Register 2 */
+	union pef2256_CAS	CAS3;	/* 0x72	CAS Register 3 */
+	union pef2256_CAS	CAS4;	/* 0x73	CAS Register 4 */
+	union pef2256_CAS	CAS5;	/* 0x74	CAS Register 5 */
+	union pef2256_CAS	CAS6;	/* 0x75	CAS Register 6 */
+	union pef2256_CAS	CAS7;	/* 0x76	CAS Register 7 */
+	union pef2256_CAS	CAS8;	/* 0x77	CAS Register 8 */
+	union pef2256_CAS	CAS9;	/* 0x78	CAS Register 9 */
+	union pef2256_CAS	CAS10;	/* 0x79	CAS Register 10 */
+	union pef2256_CAS	CAS11;	/* 0x7A	CAS Register 11 */
+	union pef2256_CAS	CAS12;	/* 0x7B	CAS Register 12 */
+	union pef2256_CAS	CAS13;	/* 0x7C	CAS Register 13 */
+	union pef2256_CAS	CAS14;	/* 0x7D	CAS Register 14 */
+	union pef2256_CAS	CAS15;	/* 0x7E	CAS Register 15 */
+	union pef2256_CAS	CAS16;	/* 0x7F	CAS Register 16 */
+	unsigned char	PC1;	/* 0x80	Port Configuration 1 */
+	unsigned char	PC2;	/* 0x81	Port Configuration 2 */
+	unsigned char	PC3;	/* 0x82	Port Configuration 3 */
+	unsigned char	PC4;	/* 0x83	Port Configuration 4 */
+	unsigned char	PC5;	/* 0x84	Port Configuration 5 */
+	unsigned char	GPC1;	/* 0x85	Global Port Configuration 1 */
+	unsigned char	PC6;	/* 0x86	Port Configuration 6 */
+	unsigned char	CMDR2;	/* 0x87	Command Register 2 */
+	unsigned char	CMDR3;	/* 0x88	Command Register 3 */
+	unsigned char	CMDR4;	/* 0x89	Command Register 4 */
+	unsigned char	Res9;	/* 0x8A	Free Register 9 */
+	unsigned char	CCR3;	/* 0x8B	Common Control Register 3 */
+	unsigned char	CCR4;	/* 0x8C	Common Control Register 4 */
+	unsigned char	CCR5;	/* 0x8D	Common Control Register 5 */
+	unsigned char	MODE2;	/* 0x8E	Mode Register 2 */
+	unsigned char	MODE3;	/* 0x8F	Mode Register 3 */
+	unsigned char	RBC2;	/* 0x90	Receive Byte Count Register 2 */
+	unsigned char	RBC3;	/* 0x91	Receive Byte Count Register 3 */
+	unsigned char	GCM1;	/* 0x92	Global Counter Mode 1 */
+	unsigned char	GCM2;	/* 0x93	Global Counter Mode 2 */
+	unsigned char	GCM3;	/* 0x94	Global Counter Mode 3 */
+	unsigned char	GCM4;	/* 0x95	Global Counter Mode 4 */
+	unsigned char	GCM5;	/* 0x96	Global Counter Mode 5 */
+	unsigned char	GCM6;	/* 0x97	Global Counter Mode 6 */
+	union pef2256_Dif1	Dif1;	/* 0x98	SIS2 en V1.2, GCM7 en V2.2 */
+	union pef2256_Dif2	Dif2;	/* 0x99	RSIS2 en V1.2, GCM8 en V2.2 */
+	unsigned char	SIS3;	/* 0x9A	Signaling Status Register 3 */
+	unsigned char	RSIS3;	/* 0x9B	Receive Signaling Status Register 3 */
+	union pef2256_Fifo	FIFO2;	/* 0x9C/0x9D FIFO 2 (Tx or rx) */
+	union pef2256_Fifo	FIFO3;	/* 0x9E/0x9F FIFO 3 (Tx or rx) */
+	unsigned char	TSEO;	/* 0xA0	Time Slot Even/Odd select */
+	unsigned char	TSBS1;	/* 0xA1	Time Slot Bit select 1 */
+	unsigned char	TSBS2;	/* 0xA2	Time Slot Bit select 2 */
+	unsigned char	TSBS3;	/* 0xA3	Time Slot Bit select 3 */
+	unsigned char	TSS2;	/* 0xA4	Time Slot select 2 */
+	unsigned char	TSS3;	/* 0xA5	Time Slot select 3 */
+	unsigned char	Res10;	/* 0xA6	Free Register 10 */
+	unsigned char	Res11;	/* 0xA7	Free Register 11 */
+	unsigned char	TPC0;	/* 0xA8	Test Pattern Control Register 0 */
+	unsigned char	SIS2;	/* 0xA9	Signaling Status Register 2 (V2.2) */
+	unsigned char	RSIS2;	/* 0xAA	Rx Signaling Status Register 2 (V2.2) */
+	unsigned char	MFPI;	/* 0xAB	Multi Function Port Input Status */
+	unsigned char	Res12;	/* 0xAC	Free Register 12 */
+	unsigned char	Res13;	/* 0xAD	Free Register 13 */
+	unsigned char	Res14;	/* 0xAE	Free Register 14 */
+	unsigned char	GLC1;	/* 0xAF	Global Line Control Register 1 */
+	unsigned char	Res[0xEB-0xAF];	/* 0xB0/0xEB Free Registers */
+	unsigned char	WID;	/* 0xEC	Identification Register */
+};
+
+#endif /* _PEF2256_H */
diff -urN a/Documentation/devicetree/bindings/net/pef2256.txt b/Documentation/devicetree/bindings/net/pef2256.txt
--- a/Documentation/devicetree/bindings/net/pef2256.txt	1970-01-01 01:00:00.000000000 +0100
+++ b/Documentation/devicetree/bindings/net/pef2256.txt	2013-10-13 15:05:42.000000000 +0200
@@ -0,0 +1,29 @@
+* Wan on Infineon pef2256 E1 controller
+
+Required properties:
+- compatible: Should be "infineon,pef2256"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain interrupts
+
+Optional properties:
+- data-rate: Data rate on the system highway.
+  Supported values are: 2, 4, 8, 16.
+  8 if not defined.
+- channel-phase: First time slot transmission channel phase.
+  Supported values are: 0, 1, 2, 3, 4, 5, 6, 7.
+  0 if not defined.
+- rising-edge-sync-pulse: rising edge synchronous pulse.
+  Supported values are: "receive", "transmit".
+  "transmit" if not defined.
+
+Examples:
+
+	e1-wan@4,2000000 {
+		compatible = "infineon,pef2256";
+		reg = <4 0x2000000 0xFF>;
+		interrupts = <8 1>;
+		interrupt-parent = <&PIC>;
+		data-rate = <4>;
+		channel-phase = <1>;
+		rising-edge-sync-pulse = "transmit";
+	};
diff -urN a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
--- a/drivers/net/wan/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/wan/Makefile	2013-10-13 13:05:01.000000000 +0200
@@ -22,6 +22,7 @@
 obj-$(CONFIG_COSA)		+= cosa.o
 obj-$(CONFIG_FARSYNC)		+= farsync.o
 obj-$(CONFIG_DSCC4)             += dscc4.o
+obj-$(CONFIG_PEF2256)           += pef2256.o
 obj-$(CONFIG_X25_ASY)		+= x25_asy.o
 
 obj-$(CONFIG_LANMEDIA)		+= lmc/
diff -urN a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
--- a/drivers/net/wan/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/wan/Kconfig	2013-10-13 13:05:01.000000000 +0200
@@ -266,6 +266,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called farsync.
 
+config PEF2256
+	tristate "PEF2256 support"
+	depends on HDLC && OF && SYSFS
+	help
+	  Driver for Infineon FALC56 E1/T1/J1 Framer and Line Interface
+	  based on PEF2256 chipset.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pef2256.
+
 config DSCC4
 	tristate "Etinc PCISYNC serial board support"
 	depends on HDLC && PCI && m

^ permalink raw reply

* Re: [Xen-devel] DomU's network interface will hung when Dom0 running 32bit
From: annie li @ 2013-10-16 15:26 UTC (permalink / raw)
  To: jianhai luan; +Cc: Wei Liu, xen-devel, Ian Campbell, netdev
In-Reply-To: <525EAB02.9050207@oracle.com>


On 2013-10-16 23:04, jianhai luan wrote:
>
>  From ef02403a10173896c5c102f768741d0700b8a3a2 Mon Sep 17 00:00:00 2001
> From: Jason Luan<jianhai.luan@oracle.com>
> Date: Tue, 15 Oct 2013 17:07:49 +0800
> Subject: [PATCH] xen-netback: pending timer only in the range [expire,
>   next_credit)
>
> The function time_after_eq() do correct judge in range of MAX_UNLONG/2.
> If net-front send lesser package, the delta between now and next_credit
> will out of the range and time_after_eq() will do wrong judge in result
> to net-front hung.  For example:
>      expire    next_credit    ....    next_credit+MAX_UNLONG/2    now
>      -----------------time increases this direction----------------->
>
> We should be add the environment which now beyond next_credit+MAX_UNLONG/2.
> Because the fact now mustn't before expire, time_before(now, expire) == true
> will show the environment.
>      time_after_eq(now, next_credit) || time_before (now, expire)
>      ==
>      !time_in_range_open(now, expire, next_credit)
>
> Signed-off-by: Jason Luan<jianhai.luan@oracle.com>
> ---
>   drivers/net/xen-netback/netback.c |    2 +-
>   1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
> index f3e591c..62492f0 100644
> --- a/drivers/net/xen-netback/netback.c
> +++ b/drivers/net/xen-netback/netback.c
> @@ -1195,7 +1195,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
>   		return true;
>   
>   	/* Passed the point where we can replenish credit? */

I think the comments above can be removed, and it is better to explain 
the if condition here briefly.

Thanks
Annie

> -	if (time_after_eq(now, next_credit)) {
> +	if (!time_in_range(now, vif->credit_timeout.expires, next_credit)) {
>   		vif->credit_timeout.expires = now;
>   		tx_add_credit(vif);
>   	}

^ permalink raw reply

* [PATCH RFC 0/5] net:stmmac: fix jumbo frames handling and optimisation
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet

Hello,

I began using Synopsys IP few weeks ago and figured out that jumbo frames
are not well supported by stmmac driver.

This patch series addresses several issues which prevent them from working
properly :
*(1/5) Threshold dma mode is needed on rx path if jumbo frames are expected.

*(2/5) RX buffers are not allocated with the needed size because
priv->dma_buf_sz is updated too late (i.e. after stmmac_init_rx_buffers call)

*(3/5) On low speed link (10MBit/s), some TX descriptors can remain dirty
if the tx coalescence timer expires before they were treated. Re-arm timer
in this case.

*(4/5) There is several confusions regarding descriptor's max buffer size, 
typically the "-1" is often forgotten.
*(4/5) Jumbo frames' last descriptor is never "closed", resulting in truncated
frames transfer.
*(4/5) Frags could not be jumbo.
Regarding these last points, I didn't find simpler way than writing
new "prepare frame" functions for both ring and chain mode and update
xmit function accordingly.


The last patch is not related to jumbo frames but concern a possible
optimisation :
*(5/5) Tx descriptor's cleanup and preparation are serialized, which is not
necessary and decrease performance. In addition TX descriptor's cleanup is
performed on NET_-RX- softirq, this is confusing.
By taking care of "cur_tx" and "dirty_tx" it is possible to avoid serialization
and defer cleanup in workqueue.
On my smp embedded system, with 1Gbit/s link which is cpu bound, it increases
througput by about 90MBit/s (400MBit/s to 490MBit/s).


Best Regards,
Jimmy Perchet

Jimmy Perchet (5):
  net:stmmac: set threshold/store and forward mode according to mtu
    size.
  net:stmmac: fix rx buffer allocation.
  net:stmmac: ensure we reclaim all dirty descriptors.
  net:stmmac: fix jumbo frame handling.
  net:stmmac: asynchronous tx_clean

 drivers/net/ethernet/stmicro/stmmac/chain_mode.c  |  99 +++++-----
 drivers/net/ethernet/stmicro/stmmac/common.h      |   6 +
 drivers/net/ethernet/stmicro/stmmac/descs_com.h   |   8 +-
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c    |   6 +
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c   |   6 +
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c   |  90 ++++-----
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |   6 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 219 +++++++++++++---------
 8 files changed, 233 insertions(+), 207 deletions(-)

-- 
1.8.1.2

^ permalink raw reply

* [PATCH RFC 1/5] net:stmmac: set threshold/store and forward mode according to mtu size.
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet
In-Reply-To: <1381937052-8999-1-git-send-email-jimmy.perchet@parrot.com>

Threshold mode dma is needed on rx path if jumbo frames are expected.


Signed-off-by: Jimmy Perchet <jimmy.perchet@parrot.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 48 ++++++++++++++++-------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 8d4ccd3..170f043 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1222,22 +1222,40 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
  *  Description: it sets the DMA operation mode: tx/rx DMA thresholds
  *  or Store-And-Forward capability.
  */
-static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
-{
-	if (priv->plat->force_thresh_dma_mode)
-		priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
-	else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
-		/*
-		 * In case of GMAC, SF mode can be enabled
-		 * to perform the TX COE in HW. This depends on:
-		 * 1) TX COE if actually supported
-		 * 2) There is no bugged Jumbo frame support
-		 *    that needs to not insert csum in the TDES.
-		 */
-		priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);
+static void stmmac_dma_operation_mode(int mtu, struct stmmac_priv *priv)
+{
+	int rx_tc, tx_tc;
+
+	/*
+	 * In case of GMAC, SF mode can be enabled
+	 * to perform the TX COE in HW. This depends on:
+	 * 1) TX COE if actually supported
+	 * 2) There is no bugged Jumbo frame support
+	 *    that needs to not insert csum in the TDES.
+	 */
+	if (priv->plat->tx_coe &&
+	    !(priv->plat->bugged_jumbo && (mtu > ETH_DATA_LEN))) {
 		tc = SF_DMA_MODE;
+		tx_tc = SF_DMA_MODE;
 	} else
-		priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
+		tx_tc = tc;
+
+	if (mtu > ETH_DATA_LEN && priv->hw_cap_support
+	    && !priv->dma_cap.rxfifo_over_2048)
+		rx_tc = tc;
+	else
+		rx_tc = SF_DMA_MODE;
+
+	if (priv->plat->force_sf_dma_mode) {
+		tc = SF_DMA_MODE;
+		tx_tc = SF_DMA_MODE;
+		rx_tc = SF_DMA_MODE;
+	} else if (priv->plat->force_thresh_dma_mode) {
+		tx_tc = tc;
+		rx_tc = tc;
+	}
+
+	priv->hw->dma->dma_mode(priv->ioaddr, tx_tc, rx_tc);
 }
 
 /**
@@ -1687,7 +1705,7 @@ static int stmmac_open(struct net_device *dev)
 	stmmac_set_mac(priv->ioaddr, true);
 
 	/* Set the HW DMA mode and the COE */
-	stmmac_dma_operation_mode(priv);
+	stmmac_dma_operation_mode(dev->mtu, priv);
 
 	/* Extra statistics */
 	memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH RFC 2/5] net:stmmac: fix rx buffer allocation.
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet
In-Reply-To: <1381937052-8999-1-git-send-email-jimmy.perchet@parrot.com>

Rx buffers used wrong size, because priv->dma_buf_sz was updated after allocation.

Signed-off-by: Jimmy Perchet <jimmy.perchet@parrot.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 170f043..0015175 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -998,6 +998,9 @@ static int init_dma_desc_rings(struct net_device *dev)
 	if (bfsize < BUF_SIZE_16KiB)
 		bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
 
+	priv->dma_buf_sz = bfsize;
+	buf_sz = bfsize;
+
 	if (netif_msg_probe(priv))
 		pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__,
 			 txsize, rxsize, bfsize);
@@ -1087,8 +1090,6 @@ static int init_dma_desc_rings(struct net_device *dev)
 	}
 	priv->cur_rx = 0;
 	priv->dirty_rx = (unsigned int)(i - rxsize);
-	priv->dma_buf_sz = bfsize;
-	buf_sz = bfsize;
 
 	/* Setup the chained descriptor addresses */
 	if (priv->mode == STMMAC_CHAIN_MODE) {
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH RFC 3/5] net:stmmac: ensure we reclaim all dirty descriptors.
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet
In-Reply-To: <1381937052-8999-1-git-send-email-jimmy.perchet@parrot.com>

On low speed link (10MBit/s), some TX descriptors can remain dirty
if the tx coalescence timer expires before they were treated. Re-arm timer
in this case.

Signed-off-by: Jimmy Perchet <jimmy.perchet@parrot.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 0015175..af04b5d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1284,8 +1284,12 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 			p = priv->dma_tx + entry;
 
 		/* Check if the descriptor is owned by the DMA. */
-		if (priv->hw->desc->get_tx_owner(p))
+		if (priv->hw->desc->get_tx_owner(p)) {
+			/* Be sure to harvest remaining descriptor. */
+			mod_timer(&priv->txtimer,
+			  STMMAC_COAL_TIMER(priv->tx_coal_timer));
 			break;
+		}
 
 		/* Verify tx error by looking at the last segment. */
 		last = priv->hw->desc->get_tx_ls(p);
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH RFC 4/5] net:stmmac: fix jumbo frame handling.
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet
In-Reply-To: <1381937052-8999-1-git-send-email-jimmy.perchet@parrot.com>

This patch addresses several issues which prevent jumbo frames from working properly :
.jumbo frames' last descriptor was not closed
.several confusion regarding descriptor's max buffer size
.frags could not be jumbo

Signed-off-by: Jimmy Perchet <jimmy.perchet@parrot.com>
---
 drivers/net/ethernet/stmicro/stmmac/chain_mode.c  |  95 ++++++++----------
 drivers/net/ethernet/stmicro/stmmac/common.h      |   6 ++
 drivers/net/ethernet/stmicro/stmmac/descs_com.h   |   8 +-
 drivers/net/ethernet/stmicro/stmmac/enh_desc.c    |   6 ++
 drivers/net/ethernet/stmicro/stmmac/norm_desc.c   |   6 ++
 drivers/net/ethernet/stmicro/stmmac/ring_mode.c   |  90 ++++++++---------
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 112 +++++++++++-----------
 7 files changed, 158 insertions(+), 165 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index d234ab5..d6ed0ce 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -28,70 +28,58 @@
 
 #include "stmmac.h"
 
-static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+static unsigned int stmmac_prepare_frm(void *p, void *data, unsigned int len,
+						 int csum, unsigned int entry)
 {
 	struct stmmac_priv *priv = (struct stmmac_priv *)p;
-	unsigned int txsize = priv->dma_tx_size;
-	unsigned int entry = priv->cur_tx % txsize;
-	struct dma_desc *desc = priv->dma_tx + entry;
-	unsigned int nopaged_len = skb_headlen(skb);
+	unsigned int entry_count = 0;
+	struct dma_desc *desc;
 	unsigned int bmax;
-	unsigned int i = 1, len;
 
-	if (priv->plat->enh_desc)
-		bmax = BUF_SIZE_8KiB;
-	else
-		bmax = BUF_SIZE_2KiB;
-
-	len = nopaged_len - bmax;
-
-	desc->des2 = dma_map_single(priv->device, skb->data,
-				    bmax, DMA_TO_DEVICE);
-	priv->tx_skbuff_dma[entry] = desc->des2;
-	priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
-
-	while (len != 0) {
-		entry = (++priv->cur_tx) % txsize;
+	if (priv->plat->enh_desc) {
+		desc = (struct dma_desc *)(priv->dma_etx + entry);
+		bmax = BUF_SIZE_8KiB - 1;
+	} else{
 		desc = priv->dma_tx + entry;
-
-		if (len > bmax) {
-			desc->des2 = dma_map_single(priv->device,
-						    (skb->data + bmax * i),
-						    bmax, DMA_TO_DEVICE);
-			priv->tx_skbuff_dma[entry] = desc->des2;
-			priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
-							STMMAC_CHAIN_MODE);
-			priv->hw->desc->set_tx_owner(desc);
-			priv->tx_skbuff[entry] = NULL;
-			len -= bmax;
-			i++;
-		} else {
-			desc->des2 = dma_map_single(priv->device,
-						    (skb->data + bmax * i), len,
-						    DMA_TO_DEVICE);
-			priv->tx_skbuff_dma[entry] = desc->des2;
-			priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
-							STMMAC_CHAIN_MODE);
-			priv->hw->desc->set_tx_owner(desc);
-			priv->tx_skbuff[entry] = NULL;
-			len = 0;
-		}
+		bmax = BUF_SIZE_2KiB - 1;
 	}
-	return entry;
-}
 
-static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
-{
-	unsigned int ret = 0;
+	while (len > bmax) {
+		desc->des2 = dma_map_single(priv->device,
+					    data + bmax*entry_count,
+					    bmax, DMA_TO_DEVICE);
+		priv->tx_skbuff_dma[entry] = desc->des2;
+		priv->tx_skbuff[entry] = NULL;
+		priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
+						STMMAC_CHAIN_MODE);
+
+		len -= bmax;
+		entry++;
+		entry %= priv->dma_tx_size;
+		entry_count++;
+
+		if (priv->plat->enh_desc)
+			desc = (struct dma_desc *)
+					(((struct dma_extended_desc *)desc)+1);
+		else
+			desc++;
+	}
 
-	if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
-	    (!enh_desc && (len > BUF_SIZE_2KiB))) {
-		ret = 1;
+	if (len)	{
+		desc->des2 = dma_map_single(priv->device,
+					    data + bmax*entry_count,
+					    len, DMA_TO_DEVICE);
+		priv->tx_skbuff_dma[entry] = desc->des2;
+		priv->tx_skbuff[entry] = NULL;
+		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+						STMMAC_CHAIN_MODE);
+		entry_count++;
 	}
 
-	return ret;
+	return entry_count;
 }
 
+
 static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
 				  unsigned int size, unsigned int extend_desc)
 {
@@ -154,8 +142,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
 
 const struct stmmac_chain_mode_ops chain_mode_ops = {
 	.init = stmmac_init_dma_chain,
-	.is_jumbo_frm = stmmac_is_jumbo_frm,
-	.jumbo_frm = stmmac_jumbo_frm,
+	.prepare_frm = stmmac_prepare_frm,
 	.refill_desc3 = stmmac_refill_desc3,
 	.clean_desc3 = stmmac_clean_desc3,
 };
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 7eb8bab..5d3f734 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -323,6 +323,8 @@ struct stmmac_desc_ops {
 	/* Handle extra events on specific interrupts hw dependent */
 	int (*get_rx_owner) (struct dma_desc *p);
 	void (*set_rx_owner) (struct dma_desc *p);
+
+	void (*set_tx_first) (struct dma_desc *p);
 	/* Get the receive frame size */
 	int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
 	/* Return the reception status looking at the RDES1 */
@@ -421,6 +423,8 @@ struct mii_regs {
 struct stmmac_ring_mode_ops {
 	unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
 	unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+	unsigned int (*prepare_frm) (void *p, void *data, unsigned int len,
+						int csum, unsigned int entry);
 	void (*refill_desc3) (void *priv, struct dma_desc *p);
 	void (*init_desc3) (struct dma_desc *p);
 	void (*clean_desc3) (void *priv, struct dma_desc *p);
@@ -432,6 +436,8 @@ struct stmmac_chain_mode_ops {
 		      unsigned int extend_desc);
 	unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
 	unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+	unsigned int (*prepare_frm) (void *p, void *data, unsigned int len,
+					 int csum, unsigned int entry);
 	void (*refill_desc3) (void *priv, struct dma_desc *p);
 	void (*clean_desc3) (void *priv, struct dma_desc *p);
 };
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index 6f2cc78..cf199d6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -53,9 +53,9 @@ static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
 
 static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
 {
-	if (unlikely(len > BUF_SIZE_4KiB)) {
-		p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
-		p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+	if (unlikely(len >= BUF_SIZE_8KiB)) {
+		p->des01.etx.buffer1_size = BUF_SIZE_8KiB - 1;
+		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
 	} else
 		p->des01.etx.buffer1_size = len;
 }
@@ -81,7 +81,7 @@ static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
 
 static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
 {
-	if (unlikely(len > BUF_SIZE_2KiB)) {
+	if (unlikely(len >= BUF_SIZE_2KiB)) {
 		p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
 		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
 	} else
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 7e6628a..915a7ab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -297,6 +297,11 @@ static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
 		enh_desc_end_tx_desc_on_ring(p, ter);
 }
 
+static void enh_desc_set_tx_first(struct dma_desc *p)
+{
+	p->des01.etx.first_segment = 1;
+}
+
 static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 				     int csum_flag, int mode)
 {
@@ -393,6 +398,7 @@ const struct stmmac_desc_ops enh_desc_ops = {
 	.get_tx_ls = enh_desc_get_tx_ls,
 	.set_tx_owner = enh_desc_set_tx_owner,
 	.set_rx_owner = enh_desc_set_rx_owner,
+	.set_tx_first = enh_desc_set_tx_first,
 	.get_rx_frame_len = enh_desc_get_rx_frame_len,
 	.rx_extended_status = enh_desc_get_ext_status,
 	.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 35ad4f4..6363776 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -180,6 +180,11 @@ static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 		ndesc_end_tx_desc_on_ring(p, ter);
 }
 
+static void ndesc_set_tx_first(struct dma_desc *p)
+{
+	p->des01.etx.first_segment = 1;
+}
+
 static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 				  int csum_flag, int mode)
 {
@@ -265,6 +270,7 @@ const struct stmmac_desc_ops ndesc_ops = {
 	.get_tx_ls = ndesc_get_tx_ls,
 	.set_tx_owner = ndesc_set_tx_owner,
 	.set_rx_owner = ndesc_set_rx_owner,
+	.set_tx_first = ndesc_set_tx_first,
 	.get_rx_frame_len = ndesc_get_rx_frame_len,
 	.enable_tx_timestamp = ndesc_enable_tx_timestamp,
 	.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 1ef9d8a..7faa42a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -28,73 +28,60 @@
 
 #include "stmmac.h"
 
-static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+
+static unsigned int stmmac_prepare_frm(void *p, void *data, unsigned int len,
+						 int csum, unsigned int entry)
 {
 	struct stmmac_priv *priv = (struct stmmac_priv *)p;
-	unsigned int txsize = priv->dma_tx_size;
-	unsigned int entry = priv->cur_tx % txsize;
+	unsigned int entry_count = 0;
 	struct dma_desc *desc;
-	unsigned int nopaged_len = skb_headlen(skb);
-	unsigned int bmax, len;
+	unsigned int bmax;
 
-	if (priv->extend_desc)
+	if (priv->plat->enh_desc) {
 		desc = (struct dma_desc *)(priv->dma_etx + entry);
-	else
+		bmax = BUF_SIZE_8KiB - 1;
+	} else{
 		desc = priv->dma_tx + entry;
+		bmax = BUF_SIZE_2KiB - 1;
+	}
 
-	if (priv->plat->enh_desc)
-		bmax = BUF_SIZE_8KiB;
-	else
-		bmax = BUF_SIZE_2KiB;
-
-	len = nopaged_len - bmax;
-
-	if (nopaged_len > BUF_SIZE_8KiB) {
-
-		desc->des2 = dma_map_single(priv->device, skb->data,
-					    bmax, DMA_TO_DEVICE);
+	while (len > 2*bmax) {
+		desc->des2 = dma_map_single(priv->device,
+						data + 2*bmax*entry_count,
+						2*bmax, DMA_TO_DEVICE);
 		priv->tx_skbuff_dma[entry] = desc->des2;
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
+		priv->tx_skbuff[entry] = NULL;
+		desc->des3 = desc->des2 + bmax;
+		priv->hw->desc->prepare_tx_desc(desc, 0, 2*bmax, csum,
 						STMMAC_RING_MODE);
-		wmb();
-		entry = (++priv->cur_tx) % txsize;
 
-		if (priv->extend_desc)
-			desc = (struct dma_desc *)(priv->dma_etx + entry);
+		len -= 2*bmax;
+		entry++;
+		entry %= priv->dma_tx_size;
+		entry_count++;
+
+		if (priv->plat->enh_desc)
+			desc = (struct dma_desc *)
+					(((struct dma_extended_desc *)desc)+1);
 		else
-			desc = priv->dma_tx + entry;
+			desc++;
+	}
+	if (len) {
 
-		desc->des2 = dma_map_single(priv->device, skb->data + bmax,
-					    len, DMA_TO_DEVICE);
+		desc->des2 = dma_map_single(priv->device,
+						data + 2*bmax*entry_count,
+						len, DMA_TO_DEVICE);
 		priv->tx_skbuff_dma[entry] = desc->des2;
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
-						STMMAC_RING_MODE);
-		wmb();
-		priv->hw->desc->set_tx_owner(desc);
 		priv->tx_skbuff[entry] = NULL;
-	} else {
-		desc->des2 = dma_map_single(priv->device, skb->data,
-					    nopaged_len, DMA_TO_DEVICE);
-		priv->tx_skbuff_dma[entry] = desc->des2;
-		desc->des3 = desc->des2 + BUF_SIZE_4KiB;
-		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
+		desc->des3 = desc->des2 + bmax;
+		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
 						STMMAC_RING_MODE);
+		entry_count++;
 	}
 
-	return entry;
+	return entry_count;
 }
 
-static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
-{
-	unsigned int ret = 0;
-
-	if (len >= BUF_SIZE_4KiB)
-		ret = 1;
-
-	return ret;
-}
 
 static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 {
@@ -103,13 +90,13 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 	if (unlikely(priv->plat->has_gmac))
 		/* Fill DES3 in case of RING mode */
 		if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
-			p->des3 = p->des2 + BUF_SIZE_8KiB;
+			p->des3 = p->des2 + BUF_SIZE_8KiB - 1;
 }
 
 /* In ring mode we need to fill the desc3 because it is used as buffer */
 static void stmmac_init_desc3(struct dma_desc *p)
 {
-	p->des3 = p->des2 + BUF_SIZE_8KiB;
+	p->des3 = p->des2 + BUF_SIZE_8KiB - 1;
 }
 
 static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
@@ -127,8 +114,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
 }
 
 const struct stmmac_ring_mode_ops ring_mode_ops = {
-	.is_jumbo_frm = stmmac_is_jumbo_frm,
-	.jumbo_frm = stmmac_jumbo_frm,
+	.prepare_frm = stmmac_prepare_frm,
 	.refill_desc3 = stmmac_refill_desc3,
 	.init_desc3 = stmmac_init_desc3,
 	.clean_desc3 = stmmac_clean_desc3,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index af04b5d..5873246 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1832,6 +1832,20 @@ static int stmmac_release(struct net_device *dev)
 	return 0;
 }
 
+
+static struct dma_desc *get_desc(struct stmmac_priv *priv, unsigned int entry)
+{
+	struct dma_desc *desc;
+
+	if (priv->plat->enh_desc)
+		desc = (struct dma_desc *)(priv->dma_etx + entry);
+	else
+		desc = priv->dma_tx + entry;
+
+	return  desc;
+}
+
+
 /**
  *  stmmac_xmit: Tx entry point of the driver
  *  @skb : the socket buffer
@@ -1844,11 +1858,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 	unsigned int txsize = priv->dma_tx_size;
-	unsigned int entry;
-	int i, csum_insertion = 0, is_jumbo = 0;
+	unsigned int entry, first_entry, nb_desc = 0;
+	int i, csum_insertion = 0;
 	int nfrags = skb_shinfo(skb)->nr_frags;
-	struct dma_desc *desc, *first;
-	unsigned int nopaged_len = skb_headlen(skb);
+	struct dma_desc *desc = NULL, *first;
 
 	if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
 		if (!netif_queue_stopped(dev)) {
@@ -1858,73 +1871,53 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 		return NETDEV_TX_BUSY;
 	}
-
 	spin_lock(&priv->tx_lock);
 
 	if (priv->tx_path_in_lpi_mode)
 		stmmac_disable_eee_mode(priv);
 
-	entry = priv->cur_tx % txsize;
+	first_entry = entry = priv->cur_tx % txsize;
 
 	csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
-
-	if (priv->extend_desc)
-		desc = (struct dma_desc *)(priv->dma_etx + entry);
+	/* To program the descriptors according to the size of the frame */
+	if (priv->mode == STMMAC_RING_MODE)
+		entry += priv->hw->ring->prepare_frm(priv, skb->data,
+				skb_headlen(skb), csum_insertion, entry);
 	else
-		desc = priv->dma_tx + entry;
+		entry += priv->hw->chain->prepare_frm(priv, skb->data,
+				 skb_headlen(skb), csum_insertion, entry);
 
-	first = desc;
-
-	priv->tx_skbuff[entry] = skb;
-
-	/* To program the descriptors according to the size of the frame */
-	if (priv->mode == STMMAC_RING_MODE) {
-		is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
-							priv->plat->enh_desc);
-		if (unlikely(is_jumbo))
-			entry = priv->hw->ring->jumbo_frm(priv, skb,
-							  csum_insertion);
-	} else {
-		is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
-							 priv->plat->enh_desc);
-		if (unlikely(is_jumbo))
-			entry = priv->hw->chain->jumbo_frm(priv, skb,
-							   csum_insertion);
-	}
-	if (likely(!is_jumbo)) {
-		desc->des2 = dma_map_single(priv->device, skb->data,
-					    nopaged_len, DMA_TO_DEVICE);
-		priv->tx_skbuff_dma[entry] = desc->des2;
-		priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
-						csum_insertion, priv->mode);
-	} else
-		desc = first;
+	entry %= txsize;
 
 	for (i = 0; i < nfrags; i++) {
 		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-		int len = skb_frag_size(frag);
 
-		entry = (++priv->cur_tx) % txsize;
-		if (priv->extend_desc)
-			desc = (struct dma_desc *)(priv->dma_etx + entry);
+		if (priv->mode == STMMAC_RING_MODE)
+			entry += priv->hw->ring->prepare_frm(priv,
+						 skb_frag_address(frag),
+						 skb_frag_size(frag),
+						 csum_insertion, entry);
 		else
-			desc = priv->dma_tx + entry;
-
-		desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
-					      DMA_TO_DEVICE);
-		priv->tx_skbuff_dma[entry] = desc->des2;
-		priv->tx_skbuff[entry] = NULL;
-		priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
-						priv->mode);
-		wmb();
-		priv->hw->desc->set_tx_owner(desc);
-		wmb();
-	}
-
+			entry += priv->hw->chain->prepare_frm(priv,
+						 skb_frag_address(frag),
+						 skb_frag_size(frag),
+						 csum_insertion, entry);
+
+		entry %= txsize;
+	}
+	/*Set owner for all segment but the first one */
+	for (i = first_entry; i != entry;) {
+		desc = get_desc(priv, i);
+		nb_desc++;
+		if (i != first_entry)
+			priv->hw->desc->set_tx_owner(desc);
+		i++;
+		i %= txsize;
+	}
+	BUG_ON(desc == NULL);
 	/* Finalize the latest segment. */
 	priv->hw->desc->close_tx_desc(desc);
 
-	wmb();
 	/* According to the coalesce parameter the IC bit for the latest
 	 * segment could be reset and the timer re-started to invoke the
 	 * stmmac_tx function. This approach takes care about the fragments.
@@ -1938,11 +1931,20 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	} else
 		priv->tx_count_frames = 0;
 
+	/*Prepare first segment */
+	priv->tx_skbuff[first_entry] = skb;
+
+	first = get_desc(priv, first_entry);
+
+	priv->hw->desc->set_tx_first(first);
+
+	wmb();
+
 	/* To avoid raise condition */
 	priv->hw->desc->set_tx_owner(first);
 	wmb();
 
-	priv->cur_tx++;
+	priv->cur_tx += nb_desc;
 
 	if (netif_msg_pktdata(priv)) {
 		pr_debug("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH RFC 5/5] net:stmmac: asynchronous tx_clean
From: Jimmy Perchet @ 2013-10-16 15:24 UTC (permalink / raw)
  To: peppe.cavallaro; +Cc: netdev, Jimmy Perchet
In-Reply-To: <1381937052-8999-1-git-send-email-jimmy.perchet@parrot.com>

Tx descriptor's cleanup and preparation are serialized, which is not necessary
and decrease performance.
In addition TX descriptor's cleanup is performed on NET_RX softirq, this is
confusing.

This patch unserialize tx descriptor's cleanup and preparation
and defer cleanup in workqueue.

Signed-off-by: Jimmy Perchet <jimmy.perchet@parrot.com>
---
 drivers/net/ethernet/stmicro/stmmac/chain_mode.c  |  6 +--
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |  6 ++-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 52 +++++++++++++----------
 3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index d6ed0ce..8ab83cb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -120,7 +120,7 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 		 * to keep explicit chaining in the descriptor.
 		 */
 		p->des3 = (unsigned int)(priv->dma_rx_phy +
-					 (((priv->dirty_rx) + 1) %
+					 ((priv->dirty_rx + 1) %
 					  priv->dma_rx_size) *
 					 sizeof(struct dma_desc));
 }
@@ -135,9 +135,9 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
 		 * to keep explicit chaining in the descriptor.
 		 */
 		p->des3 = (unsigned int)(priv->dma_tx_phy +
-					 (((priv->dirty_tx + 1) %
+					 ((atomic_read(&priv->dirty_tx) + 1) %
 					   priv->dma_tx_size) *
-					  sizeof(struct dma_desc)));
+					  sizeof(struct dma_desc));
 }
 
 const struct stmmac_chain_mode_ops chain_mode_ops = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index f16a9bd..d5b8906 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -38,8 +38,8 @@ struct stmmac_priv {
 	struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
 	struct dma_desc *dma_tx;
 	struct sk_buff **tx_skbuff;
-	unsigned int cur_tx;
-	unsigned int dirty_tx;
+	atomic_t cur_tx;
+	atomic_t dirty_tx;
 	unsigned int dma_tx_size;
 	u32 tx_count_frames;
 	u32 tx_coal_frames;
@@ -106,6 +106,8 @@ struct stmmac_priv {
 	u32 adv_ts;
 	int use_riwt;
 	spinlock_t ptp_lock;
+	struct work_struct txclean_work;
+	struct workqueue_struct *wq;
 };
 
 extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 5873246..de614ad 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -48,6 +48,7 @@
 #include <linux/seq_file.h>
 #endif /* CONFIG_STMMAC_DEBUG_FS */
 #include <linux/net_tstamp.h>
+#include <linux/workqueue.h>
 #include "stmmac_ptp.h"
 #include "stmmac.h"
 
@@ -205,7 +206,8 @@ static void print_pkt(unsigned char *buf, int len)
 
 static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
 {
-	return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
+	return atomic_read(&priv->dirty_tx) + priv->dma_tx_size
+					 - atomic_read(&priv->cur_tx) - 1;
 }
 
 /**
@@ -230,7 +232,7 @@ static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
 static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
 {
 	/* Check and enter in LPI mode */
-	if ((priv->dirty_tx == priv->cur_tx) &&
+	if ((atomic_read(&priv->dirty_tx) == atomic_read(&priv->cur_tx)) &&
 	    (priv->tx_path_in_lpi_mode == false))
 		priv->hw->mac->set_eee_mode(priv->ioaddr);
 }
@@ -1118,8 +1120,8 @@ static int init_dma_desc_rings(struct net_device *dev)
 		priv->tx_skbuff[i] = NULL;
 	}
 
-	priv->dirty_tx = 0;
-	priv->cur_tx = 0;
+	atomic_set(&priv->dirty_tx, 0);
+	atomic_set(&priv->cur_tx, 0);
 
 	stmmac_clear_descriptors(priv);
 
@@ -1264,17 +1266,17 @@ static void stmmac_dma_operation_mode(int mtu, struct stmmac_priv *priv)
  * @priv: driver private structure
  * Description: it reclaims resources after transmission completes.
  */
-static void stmmac_tx_clean(struct stmmac_priv *priv)
+static void stmmac_tx_clean(struct work_struct *work)
 {
+	struct stmmac_priv *priv =
+			container_of(work, struct stmmac_priv, txclean_work);
 	unsigned int txsize = priv->dma_tx_size;
 
-	spin_lock(&priv->tx_lock);
-
 	priv->xstats.tx_clean++;
 
-	while (priv->dirty_tx != priv->cur_tx) {
+	while (atomic_read(&priv->dirty_tx) != atomic_read(&priv->cur_tx)) {
 		int last;
-		unsigned int entry = priv->dirty_tx % txsize;
+		unsigned int entry = atomic_read(&priv->dirty_tx) % txsize;
 		struct sk_buff *skb = priv->tx_skbuff[entry];
 		struct dma_desc *p;
 
@@ -1308,7 +1310,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 		}
 		if (netif_msg_tx_done(priv))
 			pr_debug("%s: curr %d, dirty %d\n", __func__,
-				 priv->cur_tx, priv->dirty_tx);
+				 atomic_read(&priv->cur_tx),
+				 atomic_read(&priv->dirty_tx));
 
 		if (likely(priv->tx_skbuff_dma[entry])) {
 			dma_unmap_single(priv->device,
@@ -1326,7 +1329,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 
 		priv->hw->desc->release_tx_desc(p, priv->mode);
 
-		priv->dirty_tx++;
+		wmb();
+		atomic_inc(&priv->dirty_tx);
 	}
 	if (unlikely(netif_queue_stopped(priv->dev) &&
 		     stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
@@ -1344,7 +1348,6 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 		stmmac_enable_eee_mode(priv);
 		mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_T(eee_timer));
 	}
-	spin_unlock(&priv->tx_lock);
 }
 
 static inline void stmmac_enable_dma_irq(struct stmmac_priv *priv)
@@ -1380,8 +1383,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 			priv->hw->desc->init_tx_desc(&priv->dma_tx[i],
 						     priv->mode,
 						     (i == txsize - 1));
-	priv->dirty_tx = 0;
-	priv->cur_tx = 0;
+	atomic_set(&priv->dirty_tx, 0);
+	atomic_set(&priv->cur_tx, 0);
 	priv->hw->dma->start_tx(priv->ioaddr);
 
 	priv->dev->stats.tx_errors++;
@@ -1401,12 +1404,16 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 	int status;
 
 	status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
-	if (likely((status & handle_rx)) || (status & handle_tx)) {
+	if (likely(status & handle_rx)) {
 		if (likely(napi_schedule_prep(&priv->napi))) {
 			stmmac_disable_dma_irq(priv);
 			__napi_schedule(&priv->napi);
 		}
 	}
+	if (likely(status & handle_tx))
+		queue_work(priv->wq, &priv->txclean_work);
+
+
 	if (unlikely(status & tx_hard_error_bump_tc)) {
 		/* Try to bump up the dma threshold on this failure */
 		if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
@@ -1596,8 +1603,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 static void stmmac_tx_timer(unsigned long data)
 {
 	struct stmmac_priv *priv = (struct stmmac_priv *)data;
-
-	stmmac_tx_clean(priv);
+	queue_work(priv->wq, &priv->txclean_work);
 }
 
 /**
@@ -1876,7 +1882,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (priv->tx_path_in_lpi_mode)
 		stmmac_disable_eee_mode(priv);
 
-	first_entry = entry = priv->cur_tx % txsize;
+	first_entry = entry = atomic_read(&priv->cur_tx) % txsize;
 
 	csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
 	/* To program the descriptors according to the size of the frame */
@@ -1944,12 +1950,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 	priv->hw->desc->set_tx_owner(first);
 	wmb();
 
-	priv->cur_tx += nb_desc;
+	atomic_add(nb_desc, &priv->cur_tx);
 
 	if (netif_msg_pktdata(priv)) {
 		pr_debug("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
-			__func__, (priv->cur_tx % txsize),
-			(priv->dirty_tx % txsize), entry, first, nfrags);
+			__func__, (atomic_read(&priv->cur_tx) % txsize),
+			(atomic_read(&priv->dirty_tx) % txsize), entry,
+			first, nfrags);
 
 		if (priv->extend_desc)
 			stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
@@ -2171,7 +2178,6 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
 	int work_done = 0;
 
 	priv->xstats.napi_poll++;
-	stmmac_tx_clean(priv);
 
 	work_done = stmmac_rx(priv, budget);
 	if (work_done < budget) {
@@ -2747,6 +2753,8 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 
 	spin_lock_init(&priv->lock);
 	spin_lock_init(&priv->tx_lock);
+	priv->wq = create_singlethread_workqueue("stmmac_wq");
+	INIT_WORK(&priv->txclean_work, stmmac_tx_clean);
 
 	ret = register_netdev(ndev);
 	if (ret) {
-- 
1.8.1.2

^ permalink raw reply related

* Re: [PATCH v2 net 1/4] bridge: Don't use VID 0 and 4095 in vlan filtering
From: Stephen Hemminger @ 2013-10-16 15:47 UTC (permalink / raw)
  To: Toshiaki Makita; +Cc: David S . Miller, Vlad Yasevich, netdev, Toshiaki Makita
In-Reply-To: <1381910836-718-2-git-send-email-makita.toshiaki@lab.ntt.co.jp>

On Wed, 16 Oct 2013 17:07:13 +0900
Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> wrote:

> IEEE 802.1Q says that:
> - VID 0 shall not be configured as a PVID, or configured in any Filtering
> Database entry.
> - VID 4095 shall not be configured as a PVID, or transmitted in a tag
> header. This VID value may be used to indicate a wildcard match for the VID
> in management operations or Filtering Database entries.
> (See IEEE 802.1Q-2011 6.9.1 and Table 9-2)
> 
> Don't accept adding these VIDs in the vlan_filtering implementation.
> 
> Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
> Reviewed-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>  net/bridge/br_fdb.c     |  4 +-
>  net/bridge/br_netlink.c |  2 +-
>  net/bridge/br_vlan.c    | 97 +++++++++++++++++++++++--------------------------
>  3 files changed, 49 insertions(+), 54 deletions(-)

This one looks good, thanks.

Acked-by: Stephen Hemminger <stephen@networkplumber.org>

^ permalink raw reply

* Re: IPv6 path discovery oddities - flushing the routing cache resolves
From: Hannes Frederic Sowa @ 2013-10-16 15:48 UTC (permalink / raw)
  To: Valentijn Sessink; +Cc: netdev
In-Reply-To: <525E6B03.1040409@blub.net>

On Wed, Oct 16, 2013 at 12:31:31PM +0200, Valentijn Sessink wrote:
> Hello list,
> 
> I'm experiencing difficulties with IPv6 path discovery. The setup is 
> quite simple, a machine with native IPv6, no special routing - let's 
> call it the "server" for now. Unfortunately, I seem to loose 
> connectivity multiple times a day - and after digging in, I found this 
> to be "too big" messages that weren't honored at the server. The network 
> consists of something like:
> 
> server --- hosting --- others ---- SIXXS tunnel with 1280 MTU --- me.
> 
> A "ip -6 route list cache" would show a cached route to my "client", but 
> one without MTU. Then after "ip -6 route flush cache", and after trying 
> to send a large packet (for example issuing "ps uaxww" on an ssh 
> prompt), "ip -6 route list cache" will show a correct MTU.

Oh, thats another very good hint.

> But after a while, things start to go wrong again, and another "ip -6 
> route flush cache" is needed.
> 
> The server is running 3.8.0-something (ubuntu 12.04 with a newer kernel).
> 
> tcpdump shows that on reception of icmpv6 "too big", nothing happens 
> (i.e. the "too big" packet will be sent time and again), and after the 
> "ip -6 route flush cache", suddenly the "too big" message is honored.
> 
> I saw a couple of path discovery issues on this list, more specifically 
> one with the subject "IPv6 path MTU discovery broken" earlier this month 
> - but I'm not sure it's the same issue (because the original submitter 
> specifically mentions kernels 3.10 and 3.11 and has a much more 
> complicated routing table).

I do think these two issues are connected. Could you send me a the
corresponding ip route output and /proc/net/ipv6_route output for when it
works and mtus are correctly handled and when it does not work?

Thanks,

  Hannes

^ permalink raw reply

* Re: [PATCH v2 net 2/4] bridge: Apply the PVID to priority-tagged frames
From: Vlad Yasevich @ 2013-10-16 15:52 UTC (permalink / raw)
  To: Toshiaki Makita, David S . Miller, netdev; +Cc: Toshiaki Makita
In-Reply-To: <1381910836-718-3-git-send-email-makita.toshiaki@lab.ntt.co.jp>

On 10/16/2013 04:07 AM, Toshiaki Makita wrote:
> IEEE 802.1Q says that when we receive priority-tagged (VID 0) frames
> use the PVID for the port as its VID.
> (See IEEE 802.1Q-2011 6.9.1 and Table 9-2)
>
> Apply the PVID to not only untagged frames but also priority-tagged frames.
>
> Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>

Reviewed-by: Vlad Yasevich <vyasevic@redhat.com>

> ---
>   net/bridge/br_vlan.c | 27 ++++++++++++++++++++-------
>   1 file changed, 20 insertions(+), 7 deletions(-)
>
> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
> index 21b6d21..5a9c44a 100644
> --- a/net/bridge/br_vlan.c
> +++ b/net/bridge/br_vlan.c
> @@ -189,6 +189,8 @@ out:
>   bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>   			struct sk_buff *skb, u16 *vid)
>   {
> +	int err;
> +
>   	/* If VLAN filtering is disabled on the bridge, all packets are
>   	 * permitted.
>   	 */
> @@ -201,20 +203,31 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>   	if (!v)
>   		return false;
>
> -	if (br_vlan_get_tag(skb, vid)) {
> +	err = br_vlan_get_tag(skb, vid);
> +	if (!*vid) {
>   		u16 pvid = br_get_pvid(v);
>
> -		/* Frame did not have a tag.  See if pvid is set
> -		 * on this port.  That tells us which vlan untagged
> -		 * traffic belongs to.
> +		/* Frame had a tag with VID 0 or did not have a tag.
> +		 * See if pvid is set on this port.  That tells us which
> +		 * vlan untagged or priority-tagged traffic belongs to.
>   		 */
>   		if (pvid == VLAN_N_VID)
>   			return false;
>
> -		/* PVID is set on this port.  Any untagged ingress
> -		 * frame is considered to belong to this vlan.
> +		/* PVID is set on this port.  Any untagged or priority-tagged
> +		 * ingress frame is considered to belong to this vlan.
>   		 */
> -		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
> +		if (likely(err))
> +			/* Untagged Frame. */
> +			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
> +		else
> +			/* Priority-tagged Frame.
> +			 * At this point, We know that skb->vlan_tci had
> +			 * VLAN_TAG_PRESENT bit and its VID field was 0x000.
> +			 * We update only VID field and preserve PCP field.
> +			 */
> +			skb->vlan_tci |= pvid;
> +
>   		return true;
>   	}
>
>

^ permalink raw reply

* Re: [PATCH v2 net 2/4] bridge: Apply the PVID to priority-tagged frames
From: Stephen Hemminger @ 2013-10-16 15:55 UTC (permalink / raw)
  To: Toshiaki Makita; +Cc: David S . Miller, Vlad Yasevich, netdev, Toshiaki Makita
In-Reply-To: <1381910836-718-3-git-send-email-makita.toshiaki@lab.ntt.co.jp>

On Wed, 16 Oct 2013 17:07:14 +0900
Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> wrote:

> IEEE 802.1Q says that when we receive priority-tagged (VID 0) frames
> use the PVID for the port as its VID.
> (See IEEE 802.1Q-2011 6.9.1 and Table 9-2)
> 
> Apply the PVID to not only untagged frames but also priority-tagged frames.
> 
> Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
> ---
>  net/bridge/br_vlan.c | 27 ++++++++++++++++++++-------
>  1 file changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
> index 21b6d21..5a9c44a 100644
> --- a/net/bridge/br_vlan.c
> +++ b/net/bridge/br_vlan.c
> @@ -189,6 +189,8 @@ out:
>  bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>  			struct sk_buff *skb, u16 *vid)
>  {
> +	int err;
> +
>  	/* If VLAN filtering is disabled on the bridge, all packets are
>  	 * permitted.
>  	 */
> @@ -201,20 +203,31 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>  	if (!v)
>  		return false;
>  
> -	if (br_vlan_get_tag(skb, vid)) {
> +	err = br_vlan_get_tag(skb, vid);
> +	if (!*vid) {
>  		u16 pvid = br_get_pvid(v);

Ok, but it looks like br_vlan_get_tag() could be cleaner if it just returned
the tag, and there was another br_vlan_tag_present() function.

Also, does this still work if CONFIG_BRIDGE_VLAN_FILTERING is disabled?

^ permalink raw reply

* Re: [PATCH v2 net 4/4] bridge: Fix updating FDB entries when the PVID is applied
From: Stephen Hemminger @ 2013-10-16 15:57 UTC (permalink / raw)
  To: Toshiaki Makita; +Cc: David S . Miller, Vlad Yasevich, netdev, Toshiaki Makita
In-Reply-To: <1381910836-718-5-git-send-email-makita.toshiaki@lab.ntt.co.jp>

On Wed, 16 Oct 2013 17:07:16 +0900
Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> wrote:

> We currently set the value that variable vid is pointing, which will be
> used in FDB later, to 0 at br_allowed_ingress() when we receive untagged
> or priority-tagged frames, even though the PVID is valid.
> This leads to FDB updates in such a wrong way that they are learned with
> VID 0.
> Update the value to that of PVID if the PVID is applied.
> 
> Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
> Reviewed-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>  net/bridge/br_vlan.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
> index 5a9c44a..53f0990 100644
> --- a/net/bridge/br_vlan.c
> +++ b/net/bridge/br_vlan.c
> @@ -217,6 +217,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>  		/* PVID is set on this port.  Any untagged or priority-tagged
>  		 * ingress frame is considered to belong to this vlan.
>  		 */
> +		*vid = pvid;
>  		if (likely(err))
>  			/* Untagged Frame. */
>  			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);


Ok, but side-effects seem like an indication of poor code logic
flow design. Not your fault but part of the the per-vlan filtering code.

^ permalink raw reply

* Re: SW csum errors
From: Kyle Hubert @ 2013-10-16 15:58 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Stephen Hemminger, netdev
In-Reply-To: <1381937065.2045.131.camel@edumazet-glaptop.roam.corp.google.com>

On Wed, Oct 16, 2013 at 11:24 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Wed, 2013-10-16 at 11:10 -0400, Kyle Hubert wrote:
>
>> Thanks, I didn't realize it was as simple as file backed pages being
>> changed. Yes, our device does support SG, so we do have zero-copy
>> sendfile() support. I'll concoct a simple test to prove this.
>
> You also can use vmsplice()/splice() and touch anonymous memory,
> no need to play with a file ;)

Thanks, this would be even easier to test. It also reminds me that
there are other vectors to constructing SKB frags. It looks like if we
need to enable SW checksumming ever again, we should just disable the
SG feature and let the normal stack handle validity.

-Kyle

^ permalink raw reply

* Re: [PATCH net-next v4 1/5] xen-netback: add support for IPv6 checksum offload to guest
From: Ian Campbell @ 2013-10-16 16:10 UTC (permalink / raw)
  To: Paul Durrant
  Cc: xen-devel@lists.xen.org, netdev@vger.kernel.org, Wei Liu,
	David Vrabel
In-Reply-To: <9AAE0902D5BC7E449B7C8E4E778ABCD0138C0B@AMSPEX01CL01.citrite.net>

On Mon, 2013-10-14 at 12:10 +0100, Paul Durrant wrote:
> > -----Original Message-----
> > From: Ian Campbell
> > Sent: 14 October 2013 11:54
> > To: Paul Durrant
> > Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; David Vrabel
> > Subject: Re: [PATCH net-next v4 1/5] xen-netback: add support for IPv6
> > checksum offload to guest
> > 
> > On Fri, 2013-10-11 at 16:06 +0100, Paul Durrant wrote:
> > > Check xenstore flag feature-ipv6-csum-offload to determine if a
> > > guest is happy to accept IPv6 packets with only partial checksum.
> > > Also check analogous feature-ip-csum-offload to determine if a
> > > guest is happy to accept IPv4 packets with only partial checksum
> > > as a replacement for a negated feature-no-csum-offload value and
> > > add a comment to deprecate use of feature-no-csum-offload.
> > >
> > > Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> > > Cc: Wei Liu <wei.liu2@citrix.com>
> > > Cc: David Vrabel <david.vrabel@citrix.com>
> > > Cc: Ian Campbell <ian.campbell@citrix.com>
> > 
> > Shouldn't this come later in the series, i.e. after netback is actually
> > able to cope with ipv6 offloads?
> > 
> 
> I guess that's debatable. The patches don't have any dependency relation; offloads to and from the guest are quite independent.
> 
> > > diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-
> > netback/common.h
> > > index 5715318..b4a9a3c 100644
> > > --- a/drivers/net/xen-netback/common.h
> > > +++ b/drivers/net/xen-netback/common.h
> > > @@ -153,7 +153,8 @@ struct xenvif {
> > >  	u8 can_sg:1;
> > >  	u8 gso:1;
> > >  	u8 gso_prefix:1;
> > > -	u8 csum:1;
> > > +	u8 ip_csum:1;
> > > +	u8 ipv6_csum:1;
> > 
> > Why not ipv4_csum for consistency/unambiguity?
> > 
> 
> I followed general linux naming conventions e.g. ip_hdr and ipv6_hdr.

True. I would be more concerned about the netif.h name, but I think you
now intend to drop the v4 variant of that, so no worries.

^ permalink raw reply

* Re: [Xen-devel] DomU's network interface will hung when Dom0 running 32bit
From: David Vrabel @ 2013-10-16 16:11 UTC (permalink / raw)
  To: Wei Liu; +Cc: jianhai luan, xen-devel, annie li, Ian Campbell, netdev
In-Reply-To: <20131016151732.GJ16371@zion.uk.xensource.com>

On 16/10/13 16:17, Wei Liu wrote:
> On Wed, Oct 16, 2013 at 11:04:34PM +0800, jianhai luan wrote:
> [...]
>> >From ef02403a10173896c5c102f768741d0700b8a3a2 Mon Sep 17 00:00:00 2001
>> From: Jason Luan <jianhai.luan@oracle.com>
>> Date: Tue, 15 Oct 2013 17:07:49 +0800
>> Subject: [PATCH] xen-netback: pending timer only in the range [expire,
>>  next_credit)
>>
>> The function time_after_eq() do correct judge in range of MAX_UNLONG/2.
>> If net-front send lesser package, the delta between now and next_credit
>> will out of the range and time_after_eq() will do wrong judge in result
>> to net-front hung.  For example:
>>     expire    next_credit    ....    next_credit+MAX_UNLONG/2    now
>>     -----------------time increases this direction----------------->
>>
>> We should be add the environment which now beyond next_credit+MAX_UNLONG/2.
>> Because the fact now mustn't before expire, time_before(now, expire) == true
>> will show the environment.
>>     time_after_eq(now, next_credit) || time_before (now, expire)
>>     ==
>>     !time_in_range_open(now, expire, next_credit)
>>

I would like the description improved because it's too hard to understand.

How about something like:

"time_after_eq() only works if the delta is < MAX_ULONG/2.

If netfront sends at a very low rate, the time between subsequent calls
to tx_credit_exceeded() may exceed MAX_ULONG/2 and the test for
timer_after_eq() will be incorrect.  Credit will not be replenished and
the guest may become unable to send (e.g., if prior to the long gap, all
credit was exhausted)."

But that's as far as I get because I can't see how the fix is correct.
The time_in_range() test might still return the wrong value if now has
advanced even further and wrapped so it is between expire and
next_credit again.

I think the credit timeout should be always armed to expire in
MAX_ULONG/4 jiffies (or some other large value).  If credit is exceeded,
this timer is then adjusted to fire earlier (at next_credit as it does
already).

David

^ permalink raw reply

* Re: [PATCH v2 net 4/4] bridge: Fix updating FDB entries when the PVID is applied
From: Vlad Yasevich @ 2013-10-16 16:11 UTC (permalink / raw)
  To: Stephen Hemminger, Toshiaki Makita
  Cc: David S . Miller, netdev, Toshiaki Makita
In-Reply-To: <20131016085715.3442e8c3@nehalam.linuxnetplumber.net>

On 10/16/2013 11:57 AM, Stephen Hemminger wrote:
> On Wed, 16 Oct 2013 17:07:16 +0900
> Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> wrote:
>
>> We currently set the value that variable vid is pointing, which will be
>> used in FDB later, to 0 at br_allowed_ingress() when we receive untagged
>> or priority-tagged frames, even though the PVID is valid.
>> This leads to FDB updates in such a wrong way that they are learned with
>> VID 0.
>> Update the value to that of PVID if the PVID is applied.
>>
>> Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
>> Reviewed-by: Vlad Yasevich <vyasevic@redhat.com>
>> ---
>>   net/bridge/br_vlan.c | 1 +
>>   1 file changed, 1 insertion(+)
>>
>> diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
>> index 5a9c44a..53f0990 100644
>> --- a/net/bridge/br_vlan.c
>> +++ b/net/bridge/br_vlan.c
>> @@ -217,6 +217,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
>>   		/* PVID is set on this port.  Any untagged or priority-tagged
>>   		 * ingress frame is considered to belong to this vlan.
>>   		 */
>> +		*vid = pvid;
>>   		if (likely(err))
>>   			/* Untagged Frame. */
>>   			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
>
>
> Ok, but side-effects seem like an indication of poor code logic
> flow design. Not your fault but part of the the per-vlan filtering code.
>

I'll see if I can re-work the code to get rid of the side-effects.

-vlad

^ 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