Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v5 1/4] ethernet: arc: Add support for Rockchip SoC layer device tree bindings
From: David Miller @ 2014-09-05 22:10 UTC (permalink / raw)
  To: romain.perier
  Cc: heiko, linux-rockchip, linux-arm-kernel, netdev, devicetree, arnd
In-Reply-To: <1409763165-16461-1-git-send-email-romain.perier@gmail.com>

From: Romain Perier <romain.perier@gmail.com>
Date: Wed,  3 Sep 2014 16:52:42 +0000

> This patch defines a platform glue layer for Rockchip SoCs which
> support arc-emac driver. It ensures that regulator for the rmii is on
> before trying to connect to the ethernet controller. It applies right
> speed and mode changes to the grf when ethernet settings change.
> 
> Signed-off-by: Romain Perier <romain.perier@gmail.com>

You'll need to resubmit this series with the Kconfig warnings fixed.

^ permalink raw reply

* Re: Compilation error on freshly pulled net-next?
From: David Miller @ 2014-09-05 22:09 UTC (permalink / raw)
  To: rick.jones2; +Cc: netdev
In-Reply-To: <540A2F7F.8060809@hp.com>

From: Rick Jones <rick.jones2@hp.com>
Date: Fri, 05 Sep 2014 14:47:43 -0700

> Looks like someone slipped a J in there and confused things:
> 
>                + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS +
>                IFLA_PORT_SELF */J + rtnl_link_get_size(dev) /* IFLA_LINKINFO */
>                + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */
> 
> (hopefully my mail client won't have mangled things too badly)
> 
> What is odd though is a git diff after I've replaced that 'J' with a
> return isn't giving me any output.

That doesn't exist in my tree.

^ permalink raw reply

* Re: [PATCH net] net-timestamp: only report sw timestamp if reporting bit is set
From: David Miller @ 2014-09-05 22:03 UTC (permalink / raw)
  To: willemb; +Cc: netdev
In-Reply-To: <1409760078-25930-1-git-send-email-willemb@google.com>

From: Willem de Bruijn <willemb@google.com>
Date: Wed,  3 Sep 2014 12:01:18 -0400

> The timestamping API has separate bits for generating and reporting
> timestamps. A software timestamp should only be reported for a packet
> when the packet has the relevant generation flag (SKBTX_..) set
> and the socket has reporting bit SOF_TIMESTAMPING_SOFTWARE set.
> 
> The second check was accidentally removed. Reinstitute the original
> behavior.
> 
> Tested:
>   Without this patch, Documentation/networking/txtimestamp reports
>   timestamps regardless of whether SOF_TIMESTAMPING_SOFTWARE is set.
>   After the patch, it only reports them when the flag is set.
> 
> Fixes: f24b9be5957b ("net-timestamp: extend SCM_TIMESTAMPING ancillary data struct")
> 
> Signed-off-by: Willem de Bruijn <willemb@google.com>

Applied and queued up for -stable, thanks Willem.

^ permalink raw reply

* Re: [PATCH] drivers/net/fddi/skfp/h/skfbi.h: Remove useless PCI_BASE_2ND macros
From: David Miller @ 2014-09-05 21:52 UTC (permalink / raw)
  To: gang.chen.5i5j; +Cc: netdev, linux-kernel, michal.simek, monstr
In-Reply-To: <54073322.6030508@gmail.com>

From: Chen Gang <gang.chen.5i5j@gmail.com>
Date: Wed, 03 Sep 2014 23:26:26 +0800

> They are use less, and may generate compiling warnings, so remove them
> (microblaze, arc, arm64, and unicore32 have already defined PCI_IOBASE).
> 
> The related warnings (with allmodconfig under microblaze):
> 
>   CC [M]  drivers/net/fddi/skfp/skfddi.o
>   In file included from drivers/net/fddi/skfp/skfddi.c:95:0:
>   drivers/net/fddi/skfp/h/skfbi.h:151:0: warning: "PCI_IOBASE" redefined
>    #define PCI_IOBASE 0xffffff00L  /* Bit 31..8:  I/O Base address */
>    ^
>   In file included from include/linux/io.h:22:0,
>                    from include/linux/pci.h:31,
>                    from drivers/net/fddi/skfp/skfddi.c:82:
>   ./arch/microblaze/include/asm/io.h:33:0: note: this is the location of the previous definition
>    #define PCI_IOBASE ((void __iomem *)_IO_BASE)
>    ^
> 
> Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>

Applied, thanks.

^ permalink raw reply

* Compilation error on freshly pulled net-next?
From: Rick Jones @ 2014-09-05 21:47 UTC (permalink / raw)
  To: netdev, davem

I was going to do some additional "floor sweeping" and put 
dev_consume_skb_any() into another driver or two, so I did a fresh pull 
of net-next and a make and got:

   CC      net/core/rtnetlink.o
net/core/rtnetlink.c: In function ‘if_nlmsg_size’:
net/core/rtnetlink.c:868:84: error: expected ‘;’ before ‘J’
net/core/rtnetlink.c: At top level:
net/core/rtnetlink.c:420:15: warning: ‘rtnl_link_get_size’ defined but 
not used [-Wunused-function]
net/core/rtnetlink.c:497:15: warning: ‘rtnl_link_get_af_size’ defined 
but not used [-Wunused-function]


Looks like someone slipped a J in there and confused things:

                + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS 
+ IFLA_PORT_SELF */J            + rtnl_link_get_size(dev) /* 
IFLA_LINKINFO */
                + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */

(hopefully my mail client won't have mangled things too badly)

What is odd though is a git diff after I've replaced that 'J' with a 
return isn't giving me any output.

rick jones

^ permalink raw reply

* Re: [PATCH net] l2tp: fix race while getting PMTU on PPP pseudo-wire
From: Cong Wang @ 2014-09-05 21:47 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Guillaume Nault, Dmitry Petukhov, netdev, James Chapman,
	David S. Miller
In-Reply-To: <1409752526.26422.36.camel@edumazet-glaptop2.roam.corp.google.com>

On Wed, Sep 3, 2014 at 6:55 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
>
> Probably introduced in commit f34c4a35d879 ("l2tp: take PMTU from tunnel
> UDP socket")
>
> CC Dmitry
>
> Before this patch, the bug could not happen.
>
> Acked-by: Eric Dumazet <edumazet@google.com>
> Fixes: f34c4a35d879 ("l2tp: take PMTU from tunnel UDP socket")

Probably it's the time to add "Fixes:" in netdev-FAQ.txt.

^ permalink raw reply

* Re: [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Ani Sinha @ 2014-09-05 21:44 UTC (permalink / raw)
  To: Hannes Frederic Sowa
  Cc: David Miller, matthew.leach, netdev, fenner, fruggeri, travisb
In-Reply-To: <1409952419.5306.29.camel@localhost>

On Fri, Sep 5, 2014 at 2:26 PM, Hannes Frederic Sowa
> If you set msg_namelen = 0 if msg_name == NULL prior to the < 0 check it
> should not trigger the return -EINVAL and also we don't run into the
> unsafe implicit conversion case when comparing msg_namelen with the
> result of the sizeof(). Do you see any problems with that?

yes, sorry I misunderstood you. Here's the updated patch :

>From ea39174d4475d7def61410210613ab24a4ce0e81 Mon Sep 17 00:00:00 2001
From: Ani Sinha <ani@aristanetworks.com>
Date: Fri, 5 Sep 2014 14:33:20 -0700
Subject: [PATCH] net:socket: set msg_namelen to 0 if msg_name is
passed as NULL in msghdr struct from userland.

Linux manpage for recvmsg and sendmsg calls does not explicitly
mention setting msg_namelen to 0 when
msg_name passed set as NULL. When developers don't set msg_namelen
member in msghdr, it might contain garbage
value which will fail the validation check and sendmsg and recvmsg
calls from kernel will return EINVAL. This will
break old binaries and any code for which there is no access to source code.
To fix this, we set msg_namelen to 0 when msg_name is passed as NULL
from userland.

Signed-off-by: Ani Sinha <ani@aristanetworks.com>
---
 net/socket.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index 95ee7d8..457be6a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1997,6 +1997,9 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
  if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
  return -EFAULT;

+ if (kmsg->msg_name == NULL)
+ kmsg->msg_namelen = 0;
+
  if (kmsg->msg_namelen < 0)
  return -EINVAL;

-- 
1.7.4.4

^ permalink raw reply related

* Re: [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Eric Dumazet @ 2014-09-05 21:42 UTC (permalink / raw)
  To: Hannes Frederic Sowa
  Cc: Ani Sinha, David Miller, matthew.leach, netdev, fenner, fruggeri,
	travisb
In-Reply-To: <1409952419.5306.29.camel@localhost>

On Fri, 2014-09-05 at 23:26 +0200, Hannes Frederic Sowa wrote:

> Yes, I understood. Same issues with sin6_flowinfo where a specific
> setsockopt is needed so the kernel will look at it at all.
> 
> If you set msg_namelen = 0 if msg_name == NULL prior to the < 0 check it
> should not trigger the return -EINVAL and also we don't run into the
> unsafe implicit conversion case when comparing msg_namelen with the
> result of the sizeof(). Do you see any problems with that?

BTW, it looks some of the tests are done in different places, like
verify_iovec()

We certainly can cleanup the confusion.

^ permalink raw reply

* Re: [PATCH net] l2tp: fix race while getting PMTU on PPP pseudo-wire
From: David Miller @ 2014-09-05 21:41 UTC (permalink / raw)
  To: g.nault; +Cc: netdev, jchapman
In-Reply-To: <3a4673ddb2556634d0cbeae9b31ebc386e720335.1409746289.git.g.nault@alphalink.fr>

From: Guillaume Nault <g.nault@alphalink.fr>
Date: Wed, 3 Sep 2014 14:12:55 +0200

> Use dst_entry held by sk_dst_get() to retrieve tunnel's PMTU.
> 
> The dst_mtu(__sk_dst_get(tunnel->sock)) call was racy. __sk_dst_get()
> could return NULL if tunnel->sock->sk_dst_cache was reset just before the
> call, thus making dst_mtu() dereference a NULL pointer:
 ...
> Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>

Applied and queued up for -stable, thanks!

^ permalink raw reply

* [Patch net] ipv6: restore the behavior of ipv6_sock_ac_drop()
From: Cong Wang @ 2014-09-05 21:33 UTC (permalink / raw)
  To: netdev; +Cc: Cong Wang, Sabrina Dubroca, David S. Miller

It is possible that the interface is already gone after joining
the list of anycast on this interface as we don't hold a refcount
for the device, in this case we are safe to ignore the error.

What's more important, for API compatibility we should not
change this behavior for applications even if it were correct.

Fixes: commit a9ed4a2986e13011 ("ipv6: fix rtnl locking in setsockopt for anycast and multicast")
Cc: Sabrina Dubroca <sd@queasysnail.net>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
 net/ipv6/anycast.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 45b9d81..ff2de7d 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -182,8 +182,6 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
 	rtnl_unlock();
 
 	sock_kfree_s(sk, pac, sizeof(*pac));
-	if (!dev)
-		return -ENODEV;
 	return 0;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH V2 net] core: Don't attempt to load the "" driver.
From: David Miller @ 2014-09-05 21:32 UTC (permalink / raw)
  To: David.Laight; +Cc: netdev
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D174862E0@AcuExch.aculab.com>

From: David Laight <David.Laight@ACULAB.COM>
Date: Wed, 3 Sep 2014 08:55:21 +0000

> Requests like 'ifconfig ""' cause dev_load(net, "") be called, since
> request_module("") return 0 (success) this generates the error message:
> "Loading kernel module for a network device with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev- instead."
> 
> Since dev_load() doesn't have to work, just ignore such names.
> 
> Signed-off-by: David Laight <david.laight@aculab.com>
> ---
> 
> V2: Added sign off.
> 
> If you search for the above error message, you'll find a lot of complaints.
> While the applications shouldn't be calling an SIOCxxx ioctl with ifr_name[0] == 0
> the kernel shouldn't be tracing the error either.
> 
> Due to the complaints from users, this might be a backport candidate.

I have to say that I don't like this.

Why is request_module("") signalled with success unconditionally?
A module didn't get loaded, so semantically this behavior makes
no sense at all.

I would rather than simply request_module() signal an error in this
case, and then _NOBODY_ has to have all of this duplicated logic to
check for name[0]=='\0' throughout all of the call chains leading to
request_module().

^ permalink raw reply

* Re: [net PATCH 1/1] drivers: net: cpsw: dual_emac: fix reducing of rx descriptor during ifdown
From: David Miller @ 2014-09-05 21:29 UTC (permalink / raw)
  To: mugunthanvnm; +Cc: netdev
In-Reply-To: <5406C067.5080103@ti.com>

From: Mugunthan V N <mugunthanvnm@ti.com>
Date: Wed, 3 Sep 2014 12:46:55 +0530

> On Wednesday 03 September 2014 12:24 AM, David Miller wrote:
>> Also this doesn't explain why the "status < 0" case applies to this
>> new logic, you have not explained that at all.
>> 
> 
> This scenario is not generated when "status < 0", "status < 0" happens
> when DMA is in tear-down mode, the above scenario happens when
> netif_running(ndev) is false which denotes that netdev is down already.

Your condition was:

	if (status < 0 || !netif_running(ndev))

so this "scenerio" is being handled when status < 0, which is what
I am objecting to.

^ permalink raw reply

* Re: [PATCH 0/3] virtio: simplify virtio_ring.
From: David Miller @ 2014-09-05 21:27 UTC (permalink / raw)
  To: rusty; +Cc: netdev, luto, mst, virtualization
In-Reply-To: <1409718556-3041-1-git-send-email-rusty@rustcorp.com.au>

From: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed,  3 Sep 2014 13:59:13 +0930

> I resurrected these patches after prompting from Andy Lutomirski's
> recent patches.  I put them on the back-burner because vring_bench
> had a 15% slowdown on my laptop: pktgen testing revealed a speedup,
> if anything, so I've cleaned them up.

If you want to merge this via your virtio tree that's fine with me.

For virtio_net:

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Hannes Frederic Sowa @ 2014-09-05 21:26 UTC (permalink / raw)
  To: Ani Sinha; +Cc: David Miller, matthew.leach, netdev, fenner, fruggeri, travisb
In-Reply-To: <CAOxq_8NSGeeJYZP-5Pau+ehhnzrywYJ0Qr4fqrVD3cwQT-2eZQ@mail.gmail.com>

On Fr, 2014-09-05 at 14:21 -0700, Ani Sinha wrote:
> On Fri, Sep 5, 2014 at 2:14 PM, Hannes Frederic Sowa
> <hannes@stressinduktion.org> wrote:
> > Hi,
> >
> > On Fri, Sep 5, 2014, at 23:00, Ani Sinha wrote:
> >> Hi guys :
> >>
> >> I am looking at the thread :
> >>
> >>  [PATCH] net: socket: error on a negative msg_namelen
> >>
> >> and the patch that was submitted in that thread :
> >>
> >> commit dbb490b96584d4e958533fb637f08b557f505657
> >> Author: Matthew Leach <matthew.leach@arm.com>
> >> Date:   Tue Mar 11 11:58:27 2014 +0000
> >>
> >>     net: socket: error on a negative msg_namelen
> >>
> >>
> >> According to the linux recvmsg manpage, the caller of recvmsg() may
> >> set msg_name to NULL if he does not care about source address but the
> >> manpage does not say that one has to set msg_namelen to 0 in this
> >> case. Essentially msg_namelen is a don't care if msg_name is NULL. I
> >> think in the kernel, we should validate msg_namelen only if the caller
> >> has also set msg_name and return EINVAL only when msg_name is non-null
> >> and msg_namelen is negative.
> >>
> >> The following patch will do the intended :
> >>
> >>
> >> From ef8e8bd78635ac677f2d4b76fec9990ed1db763c Mon Sep 17 00:00:00 2001
> >> From: Ani Sinha <ani@aristanetworks.com>
> >> Date: Fri, 5 Sep 2014 13:25:22 -0700
> >> Subject:[PATCH] net: socket: do not validate msg_namelen unless
> >> msg_name is non-NULL
> >>
> >> The value of msg_namelen in msghdr structure is irrelevant
> >>  when msg_name is NULL. We should not validate the value
> >>  passed in msg_namelen unless msg_name is non-NULL.
> >>
> >> Signed-off-by: Ani Sinha <ani@aristanetworks.com>
> >> ---
> >>  net/socket.c |    2 +-
> >>  1 files changed, 1 insertions(+), 1 deletions(-)
> >>
> >> diff --git a/net/socket.c b/net/socket.c
> >> index 95ee7d8..a5dfe01 100644
> >> --- a/net/socket.c
> >> +++ b/net/socket.c
> >> @@ -1997,7 +1997,7 @@ static int copy_msghdr_from_user(struct msghdr
> >> *kmsg,
> >>   if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
> >>   return -EFAULT;
> >>
> >> - if (kmsg->msg_namelen < 0)
> >> + if (kmsg->msg_name && kmsg->msg_namelen < 0)
> >>   return -EINVAL;
> >>
> >>   if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
> >
> > The reason for the above mentioned commit was the signed/unsigned
> > conversion by this check. To not trigger any static checker tools, I
> > would suggest to just set kmsg->msg_namelen to zero in case msg_name is
> > NULL.
> 
> I suspect any code that was previously written without taking into
> account this new restriction will now begin to fail. For some of them,
> we may not have the freedom to change the code as per this new
> restrictions. Since the manpage did not enforce this, the developers
> can not be blamed for not setting namelen when passing name with NULL
> value.

Yes, I understood. Same issues with sin6_flowinfo where a specific
setsockopt is needed so the kernel will look at it at all.

If you set msg_namelen = 0 if msg_name == NULL prior to the < 0 check it
should not trigger the return -EINVAL and also we don't run into the
unsafe implicit conversion case when comparing msg_namelen with the
result of the sizeof(). Do you see any problems with that?

Thanks,
Hannes

^ permalink raw reply

* Re: [PATCH] pktgen: nowait parameter.
From: David Miller @ 2014-09-05 21:26 UTC (permalink / raw)
  To: rusty; +Cc: netdev, brouer, minipli
In-Reply-To: <87oauxibda.fsf@rustcorp.com.au>

From: Rusty Russell <rusty@rustcorp.com.au>
Date: Wed, 03 Sep 2014 13:50:01 +0930

> While trying to measure speed of virtio_net, I was getting hangs.
> This is because we skb_orphan() but delay the tx interrupt
> indefinitely (by number of slots).
> 
> With nowait, pktgen won't wait for the skb to be released.  This
> introduces an error, but it's ok if count >> ringsize.
> 
> I updated the documentation, but it needs far more work (it
> refers to pgset and an examples directory, none of which exist
> in the kernel tree).
> 
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

Please just make this a flag, like UDPCSUM, NO_TIMESTAMP, et al.
Which also means that it should be capitalized.

BTW, wrt. holding onto TX frames for unbounded amounts of time, I
think this is a bad idea even with skb_orphan().  There are resources
from the SKB you are hanging onto which can stall the removal of
modules indefinitely, such as netfilter references.

^ permalink raw reply

* Re: [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Ani Sinha @ 2014-09-05 21:21 UTC (permalink / raw)
  To: Hannes Frederic Sowa
  Cc: David Miller, matthew.leach, netdev, fenner, fruggeri, travisb
In-Reply-To: <1409951660.1177372.164202273.1FB2783A@webmail.messagingengine.com>

On Fri, Sep 5, 2014 at 2:14 PM, Hannes Frederic Sowa
<hannes@stressinduktion.org> wrote:
> Hi,
>
> On Fri, Sep 5, 2014, at 23:00, Ani Sinha wrote:
>> Hi guys :
>>
>> I am looking at the thread :
>>
>>  [PATCH] net: socket: error on a negative msg_namelen
>>
>> and the patch that was submitted in that thread :
>>
>> commit dbb490b96584d4e958533fb637f08b557f505657
>> Author: Matthew Leach <matthew.leach@arm.com>
>> Date:   Tue Mar 11 11:58:27 2014 +0000
>>
>>     net: socket: error on a negative msg_namelen
>>
>>
>> According to the linux recvmsg manpage, the caller of recvmsg() may
>> set msg_name to NULL if he does not care about source address but the
>> manpage does not say that one has to set msg_namelen to 0 in this
>> case. Essentially msg_namelen is a don't care if msg_name is NULL. I
>> think in the kernel, we should validate msg_namelen only if the caller
>> has also set msg_name and return EINVAL only when msg_name is non-null
>> and msg_namelen is negative.
>>
>> The following patch will do the intended :
>>
>>
>> From ef8e8bd78635ac677f2d4b76fec9990ed1db763c Mon Sep 17 00:00:00 2001
>> From: Ani Sinha <ani@aristanetworks.com>
>> Date: Fri, 5 Sep 2014 13:25:22 -0700
>> Subject:[PATCH] net: socket: do not validate msg_namelen unless
>> msg_name is non-NULL
>>
>> The value of msg_namelen in msghdr structure is irrelevant
>>  when msg_name is NULL. We should not validate the value
>>  passed in msg_namelen unless msg_name is non-NULL.
>>
>> Signed-off-by: Ani Sinha <ani@aristanetworks.com>
>> ---
>>  net/socket.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/net/socket.c b/net/socket.c
>> index 95ee7d8..a5dfe01 100644
>> --- a/net/socket.c
>> +++ b/net/socket.c
>> @@ -1997,7 +1997,7 @@ static int copy_msghdr_from_user(struct msghdr
>> *kmsg,
>>   if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
>>   return -EFAULT;
>>
>> - if (kmsg->msg_namelen < 0)
>> + if (kmsg->msg_name && kmsg->msg_namelen < 0)
>>   return -EINVAL;
>>
>>   if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
>
> The reason for the above mentioned commit was the signed/unsigned
> conversion by this check. To not trigger any static checker tools, I
> would suggest to just set kmsg->msg_namelen to zero in case msg_name is
> NULL.

I suspect any code that was previously written without taking into
account this new restriction will now begin to fail. For some of them,
we may not have the freedom to change the code as per this new
restrictions. Since the manpage did not enforce this, the developers
can not be blamed for not setting namelen when passing name with NULL
value.

Cheers,
ani

^ permalink raw reply

* RE: [PATCH RFC 1/1] net: fec: change data structure to support multiqueue
From: Frank.Li @ 2014-09-05 20:40 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: Florian Fainelli, fugang.duan@freescale.com,
	netdev@vger.kernel.org
In-Reply-To: <CAOMZO5B08M6n0rXfgZkVNb-0awVQdJ56aMokimCunVsjg03AZg@mail.gmail.com>



> -----Original Message-----
> From: Fabio Estevam [mailto:festevam@gmail.com]
> Sent: Friday, September 05, 2014 3:33 PM
> To: Li Frank-B20596
> Cc: Florian Fainelli; Duan Fugang-B38611; netdev@vger.kernel.org
> Subject: Re: [PATCH RFC 1/1] net: fec: change data structure to support
> multiqueue
> 
> On Fri, Sep 5, 2014 at 4:39 PM, Frank Li <Frank.Li@freescale.com> wrote:
> 
> > +       txq = kzalloc(sizeof(*txq), GFP_KERNEL);
> > +       if (!txq)
> > +               return -ENOMEM;
> > +       fep->tx_queue[0] = txq;
> > +
> > +       rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
> > +       if (!rxq) {
> > +               kfree(txq);
> > +               return -ENOMEM;
> > +       }
> 
> ....
> 
> >         /* Allocate memory for buffer descriptors. */
> > -       cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
> > +       cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
> >                                       GFP_KERNEL);
> >         if (!cbd_base)
> >                 return -ENOMEM;
> 
> You should kfree txq and rxq before returning here.

Yes, 
Actually this part code will be rewrite totally in next patch. 
You can refer original patch serial. 

Best regards
Frank Li

^ permalink raw reply

* Re: [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Hannes Frederic Sowa @ 2014-09-05 21:14 UTC (permalink / raw)
  To: Ani Sinha, David Miller, matthew.leach; +Cc: netdev, fenner, fruggeri, travisb
In-Reply-To: <CAOxq_8O=8epuyj2+V8RFep2tHVwk06q5gEK1ho0RUSV4GQV0Kw@mail.gmail.com>

Hi,

On Fri, Sep 5, 2014, at 23:00, Ani Sinha wrote:
> Hi guys :
> 
> I am looking at the thread :
> 
>  [PATCH] net: socket: error on a negative msg_namelen
> 
> and the patch that was submitted in that thread :
> 
> commit dbb490b96584d4e958533fb637f08b557f505657
> Author: Matthew Leach <matthew.leach@arm.com>
> Date:   Tue Mar 11 11:58:27 2014 +0000
> 
>     net: socket: error on a negative msg_namelen
> 
> 
> According to the linux recvmsg manpage, the caller of recvmsg() may
> set msg_name to NULL if he does not care about source address but the
> manpage does not say that one has to set msg_namelen to 0 in this
> case. Essentially msg_namelen is a don't care if msg_name is NULL. I
> think in the kernel, we should validate msg_namelen only if the caller
> has also set msg_name and return EINVAL only when msg_name is non-null
> and msg_namelen is negative.
> 
> The following patch will do the intended :
> 
> 
> From ef8e8bd78635ac677f2d4b76fec9990ed1db763c Mon Sep 17 00:00:00 2001
> From: Ani Sinha <ani@aristanetworks.com>
> Date: Fri, 5 Sep 2014 13:25:22 -0700
> Subject:[PATCH] net: socket: do not validate msg_namelen unless
> msg_name is non-NULL
> 
> The value of msg_namelen in msghdr structure is irrelevant
>  when msg_name is NULL. We should not validate the value
>  passed in msg_namelen unless msg_name is non-NULL.
> 
> Signed-off-by: Ani Sinha <ani@aristanetworks.com>
> ---
>  net/socket.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/net/socket.c b/net/socket.c
> index 95ee7d8..a5dfe01 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -1997,7 +1997,7 @@ static int copy_msghdr_from_user(struct msghdr
> *kmsg,
>   if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
>   return -EFAULT;
> 
> - if (kmsg->msg_namelen < 0)
> + if (kmsg->msg_name && kmsg->msg_namelen < 0)
>   return -EINVAL;
> 
>   if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))

The reason for the above mentioned commit was the signed/unsigned
conversion by this check. To not trigger any static checker tools, I
would suggest to just set kmsg->msg_namelen to zero in case msg_name is
NULL.

Thanks,
Hannes

^ permalink raw reply

* Re: [RFC net-next 1/5] bonding: 3ad: use curr_slave_lock instead of bond->lock
From: Nikolay Aleksandrov @ 2014-09-05 21:00 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: netdev, vfalico, andy, davem
In-Reply-To: <23382.1409949468@localhost.localdomain>

On 09/05/2014 10:37 PM, Jay Vosburgh wrote:
> Nikolay Aleksandrov <nikolay@redhat.com> wrote:
> 
>> In 3ad mode the only syncing needed by bond->lock is for the wq
>> and the recv handler, so change them to use curr_slave_lock.
>> There're no locking dependencies here as 3ad doesn't use
>> curr_slave_lock at all.
> 
> 	One subtle aspect of the 3ad locking is that it's not really
> using the "read" property of the read lock with regard to the state
> machine; it's largely using it as a spin lock, because there is at most
> one reader and at most one writer in the full state machine code
> (although there are multiple reader possibilities elsewhere).  The code
> would break if there actually were multiple read-lock holders in the
> full state machine or aggregator selection logic simultaneously.
> 
> 	Because the state machine and incoming LACPDU cases both acquire
> the read lock for read, there is a separate per-port "state machine"
> spin lock to protect only the per-port fields that LACPDU and periodic
> state machine both touch.  The incoming LACPDU case doesn't call into
> the full state machine, only the RX processing which can't go into agg
> selection, so this works.
> 
> 	The agg selection can be entered via the unbind path or the
> periodic state machine (and only these two paths), and relies on the
> "one reader max" usage of the read lock to mutex the code paths that may
> enter agg selection.
> 
> 	I suspect that what 3ad may need is a spin lock, not a read
> lock, because the multiple reader property isn't really being utilized;
> the incoming LACPDU and periodic state machine both acquire the read
> lock for read, but then acquire a second per-port spin lock.  If the
> "big" (bond->lock currently) lock is a spin lock, then the per-port
> state machine lock is unnecessary, as the only purpose of the per-port
> lock is to mutex the one case that does have multiple readers.
> 
> 	In actual practice I doubt there are multiple simultaneous
> readers very often; the periodic machine runs every 100 ms, but LACPDUs
> arrive for each port either every second or every 30 seconds (depending
> on admin configuration).
> 
> 	Since contention on these locks is generally low, we're probably
> better off in the long run with something simpler to understand.
> 
> 	So, what I'm kind of saying here is that this patch isn't a bad
> first step, but at least for the 3ad case, removal of the bond->lock
> itself doesn't really simplify the locking as much as could be done.
> 
> 	Thoughts?
> 
> 	-J
> 
> 

Hi Jay,
That is a very good point, my main idea was to protect __bond_release_one
and the machine handler otherwise I'd have removed it altogether. I know
that this doesn't improve on the 3ad situation, I did it mostly to get rid
of bond->lock first. Going with a spinlock certainly makes sense there as
we don't spend much time inside and the contention is not high as you said
and would simplify the 3ad code so I like it :-)
I will include it in my bond-locking todo list and will post a follow-up
once I've cleared the details up as I'm speaking from the top of my head
right now, but first I'd like to clean the current lock use especially with
regard to curr_slave_lock and bring it to the necessary minimum. In the
long run I think that we either might be able to remove curr_slave_lock
completely or at least reduce it to ~ 3 places and with the spinlock that
you suggested here, we'll be definitely able to remove it from the 3ad code.

Thanks for the suggestion!

Nik

^ permalink raw reply

* [PATCH] net: socket: do not validate msg_namelen unless msg_name is non-NULL
From: Ani Sinha @ 2014-09-05 21:00 UTC (permalink / raw)
  To: David Miller, matthew.leach; +Cc: netdev, fenner, fruggeri, travisb

Hi guys :

I am looking at the thread :

 [PATCH] net: socket: error on a negative msg_namelen

and the patch that was submitted in that thread :

commit dbb490b96584d4e958533fb637f08b557f505657
Author: Matthew Leach <matthew.leach@arm.com>
Date:   Tue Mar 11 11:58:27 2014 +0000

    net: socket: error on a negative msg_namelen


According to the linux recvmsg manpage, the caller of recvmsg() may
set msg_name to NULL if he does not care about source address but the
manpage does not say that one has to set msg_namelen to 0 in this
case. Essentially msg_namelen is a don't care if msg_name is NULL. I
think in the kernel, we should validate msg_namelen only if the caller
has also set msg_name and return EINVAL only when msg_name is non-null
and msg_namelen is negative.

The following patch will do the intended :


>From ef8e8bd78635ac677f2d4b76fec9990ed1db763c Mon Sep 17 00:00:00 2001
From: Ani Sinha <ani@aristanetworks.com>
Date: Fri, 5 Sep 2014 13:25:22 -0700
Subject:[PATCH] net: socket: do not validate msg_namelen unless
msg_name is non-NULL

The value of msg_namelen in msghdr structure is irrelevant
 when msg_name is NULL. We should not validate the value
 passed in msg_namelen unless msg_name is non-NULL.

Signed-off-by: Ani Sinha <ani@aristanetworks.com>
---
 net/socket.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index 95ee7d8..a5dfe01 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1997,7 +1997,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
  if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
  return -EFAULT;

- if (kmsg->msg_namelen < 0)
+ if (kmsg->msg_name && kmsg->msg_namelen < 0)
  return -EINVAL;

  if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
-- 
1.7.4.4

^ permalink raw reply related

* Re: [RFC net-next 1/5] bonding: 3ad: use curr_slave_lock instead of bond->lock
From: Jay Vosburgh @ 2014-09-05 20:37 UTC (permalink / raw)
  To: Nikolay Aleksandrov; +Cc: netdev, vfalico, andy, davem
In-Reply-To: <1409941011-5494-2-git-send-email-nikolay@redhat.com>

Nikolay Aleksandrov <nikolay@redhat.com> wrote:

>In 3ad mode the only syncing needed by bond->lock is for the wq
>and the recv handler, so change them to use curr_slave_lock.
>There're no locking dependencies here as 3ad doesn't use
>curr_slave_lock at all.

	One subtle aspect of the 3ad locking is that it's not really
using the "read" property of the read lock with regard to the state
machine; it's largely using it as a spin lock, because there is at most
one reader and at most one writer in the full state machine code
(although there are multiple reader possibilities elsewhere).  The code
would break if there actually were multiple read-lock holders in the
full state machine or aggregator selection logic simultaneously.

	Because the state machine and incoming LACPDU cases both acquire
the read lock for read, there is a separate per-port "state machine"
spin lock to protect only the per-port fields that LACPDU and periodic
state machine both touch.  The incoming LACPDU case doesn't call into
the full state machine, only the RX processing which can't go into agg
selection, so this works.

	The agg selection can be entered via the unbind path or the
periodic state machine (and only these two paths), and relies on the
"one reader max" usage of the read lock to mutex the code paths that may
enter agg selection.

	I suspect that what 3ad may need is a spin lock, not a read
lock, because the multiple reader property isn't really being utilized;
the incoming LACPDU and periodic state machine both acquire the read
lock for read, but then acquire a second per-port spin lock.  If the
"big" (bond->lock currently) lock is a spin lock, then the per-port
state machine lock is unnecessary, as the only purpose of the per-port
lock is to mutex the one case that does have multiple readers.

	In actual practice I doubt there are multiple simultaneous
readers very often; the periodic machine runs every 100 ms, but LACPDUs
arrive for each port either every second or every 30 seconds (depending
on admin configuration).

	Since contention on these locks is generally low, we're probably
better off in the long run with something simpler to understand.

	So, what I'm kind of saying here is that this patch isn't a bad
first step, but at least for the 3ad case, removal of the bond->lock
itself doesn't really simplify the locking as much as could be done.

	Thoughts?

	-J


>Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
>---
> drivers/net/bonding/bond_3ad.c  |  9 ++++-----
> drivers/net/bonding/bond_main.c | 12 +++++++-----
> 2 files changed, 11 insertions(+), 10 deletions(-)
>
>diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
>index ee2c73a9de39..5d27a6207384 100644
>--- a/drivers/net/bonding/bond_3ad.c
>+++ b/drivers/net/bonding/bond_3ad.c
>@@ -2057,7 +2057,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
> 	struct port *port;
> 	bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
> 
>-	read_lock(&bond->lock);
>+	read_lock(&bond->curr_slave_lock);
> 	rcu_read_lock();
> 
> 	/* check if there are any slaves */
>@@ -2120,7 +2120,7 @@ re_arm:
> 		}
> 	}
> 	rcu_read_unlock();
>-	read_unlock(&bond->lock);
>+	read_unlock(&bond->curr_slave_lock);
> 
> 	if (should_notify_rtnl && rtnl_trylock()) {
> 		bond_slave_state_notify(bond);
>@@ -2395,7 +2395,6 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
> 	return 0;
> }
> 
>-/* Wrapper used to hold bond->lock so no slave manipulation can occur */
> int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
> {
> 	int ret;
>@@ -2487,9 +2486,9 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
> 	if (!lacpdu)
> 		return ret;
> 
>-	read_lock(&bond->lock);
>+	read_lock(&bond->curr_slave_lock);
> 	ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
>-	read_unlock(&bond->lock);
>+	read_unlock(&bond->curr_slave_lock);
> 	return ret;
> }
> 
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index f0f5eab0fab1..dcd331bd0c17 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -1687,13 +1687,15 @@ static int __bond_release_one(struct net_device *bond_dev,
> 	 * for this slave anymore.
> 	 */
> 	netdev_rx_handler_unregister(slave_dev);
>-	write_lock_bh(&bond->lock);
> 
>-	/* Inform AD package of unbinding of slave. */
>-	if (BOND_MODE(bond) == BOND_MODE_8023AD)
>+	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
>+		/* Sync against bond_3ad_rx_indication and
>+		 * bond_3ad_state_machine_handler
>+		 */
>+		write_lock_bh(&bond->curr_slave_lock);
> 		bond_3ad_unbind_slave(slave);
>-
>-	write_unlock_bh(&bond->lock);
>+		write_unlock_bh(&bond->curr_slave_lock);
>+	}
> 
> 	netdev_info(bond_dev, "Releasing %s interface %s\n",
> 		    bond_is_active_slave(slave) ? "active" : "backup",
>-- 
>1.9.3
>

---
	-Jay Vosburgh, jay.vosburgh@canonical.com

^ permalink raw reply

* Re: [PATCH RFC 1/1] net: fec: change data structure to support multiqueue
From: Fabio Estevam @ 2014-09-05 20:32 UTC (permalink / raw)
  To: Frank Li; +Cc: Florian Fainelli, Duan Fugang-B38611, netdev@vger.kernel.org
In-Reply-To: <1409945994-15593-1-git-send-email-Frank.Li@freescale.com>

On Fri, Sep 5, 2014 at 4:39 PM, Frank Li <Frank.Li@freescale.com> wrote:

> +       txq = kzalloc(sizeof(*txq), GFP_KERNEL);
> +       if (!txq)
> +               return -ENOMEM;
> +       fep->tx_queue[0] = txq;
> +
> +       rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
> +       if (!rxq) {
> +               kfree(txq);
> +               return -ENOMEM;
> +       }

....

>         /* Allocate memory for buffer descriptors. */
> -       cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
> +       cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
>                                       GFP_KERNEL);
>         if (!cbd_base)
>                 return -ENOMEM;

You should kfree txq and rxq before returning here.

^ permalink raw reply

* Re: [PATCH net-next 1/3] net: Add function for parsing the header length out of linear ethernet frames
From: Alexei Starovoitov @ 2014-09-05 20:02 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: netdev@vger.kernel.org, David S. Miller, Eric Dumazet,
	jeffrey.t.kirsher
In-Reply-To: <20140905180951.730.86041.stgit@ahduyck-bv4.jf.intel.com>

On Fri, Sep 5, 2014 at 11:10 AM, Alexander Duyck
<alexander.h.duyck@intel.com> wrote:
> This patch updates some of the flow_dissector api so that it can be used to
> parse the length of ethernet buffers stored in fragments.  Most of the
> changes needed were to __skb_get_poff as it needed to be updated to support
> sending a linear buffer instead of a skb.
>
>
>  u32 __skb_get_poff(const struct sk_buff *skb);
> +u32 ___skb_get_poff(const struct sk_buff *skb, void *data,
> +                   const struct flow_keys *keys, int hlen);

three underscores and not a static function?
May be we need to come with a proper name for it.
Two easy to confuse with two underscore version...

^ permalink raw reply

* [PATCH RFC 1/1] net: fec: change data structure to support multiqueue
From: Frank Li @ 2014-09-05 19:39 UTC (permalink / raw)
  To: f.fainelli, b38611, netdev; +Cc: Fugang Duan, Frank Li

From: Fugang Duan <B38611@freescale.com>

This patch just change data structure to support multi-queue.
Only 1 queue enabled.

Ethernet multiqueue mechanism can improve performance in SMP system.
For single hw queue, multiqueue can balance cpu loading.
For multi hw queues, multiple cores can process network packets in parallel,
and refer the article for the detail advantage for multiqueue:
http://vger.kernel.org/~davem/davem_nyc09.pdf

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Frank Li <frank.li@freescale.com>
---

According to feedback from Florian Fainelli
Multi queue patches need be spritted to more small part.
This RFC check if it is small enough before continue left work.

best regards
Frank Li

 drivers/net/ethernet/freescale/fec.h      | 115 ++++++--
 drivers/net/ethernet/freescale/fec_main.c | 474 +++++++++++++++++++-----------
 2 files changed, 394 insertions(+), 195 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 635772b..b2b91f8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -27,8 +27,8 @@
  */
 #define FEC_IEVENT		0x004 /* Interrupt event reg */
 #define FEC_IMASK		0x008 /* Interrupt mask reg */
-#define FEC_R_DES_ACTIVE	0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE	0x014 /* Transmit descriptor reg */
+#define FEC_R_DES_ACTIVE_0	0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE_0	0x014 /* Transmit descriptor reg */
 #define FEC_ECNTRL		0x024 /* Ethernet control reg */
 #define FEC_MII_DATA		0x040 /* MII manage frame reg */
 #define FEC_MII_SPEED		0x044 /* MII speed control reg */
@@ -45,14 +45,26 @@
 #define FEC_X_WMRK		0x144 /* FIFO transmit water mark */
 #define FEC_R_BOUND		0x14c /* FIFO receive bound reg */
 #define FEC_R_FSTART		0x150 /* FIFO receive start reg */
-#define FEC_R_DES_START		0x180 /* Receive descriptor ring */
-#define FEC_X_DES_START		0x184 /* Transmit descriptor ring */
+#define FEC_R_DES_START_1	0x160 /* Receive descriptor ring 1 */
+#define FEC_X_DES_START_1	0x164 /* Transmit descriptor ring 1 */
+#define FEC_R_DES_START_2	0x16c /* Receive descriptor ring 2 */
+#define FEC_X_DES_START_2	0x170 /* Transmit descriptor ring 2 */
+#define FEC_R_DES_START_0	0x180 /* Receive descriptor ring */
+#define FEC_X_DES_START_0	0x184 /* Transmit descriptor ring */
 #define FEC_R_BUFF_SIZE		0x188 /* Maximum receive buff size */
 #define FEC_R_FIFO_RSFL		0x190 /* Receive FIFO section full threshold */
 #define FEC_R_FIFO_RSEM		0x194 /* Receive FIFO section empty threshold */
 #define FEC_R_FIFO_RAEM		0x198 /* Receive FIFO almost empty threshold */
 #define FEC_R_FIFO_RAFL		0x19c /* Receive FIFO almost full threshold */
 #define FEC_RACC		0x1C4 /* Receive Accelerator function */
+#define FEC_RCMR_1		0x1c8 /* Receive classification match ring 1 */
+#define FEC_RCMR_2		0x1cc /* Receive classification match ring 2 */
+#define FEC_DMA_CFG_1		0x1d8 /* DMA class configuration for ring 1 */
+#define FEC_DMA_CFG_2		0x1dc /* DMA class Configuration for ring 2 */
+#define FEC_R_DES_ACTIVE_1	0x1e0 /* Rx descriptor active for ring 1 */
+#define FEC_X_DES_ACTIVE_1	0x1e4 /* Tx descriptor active for ring 1 */
+#define FEC_R_DES_ACTIVE_2	0x1e8 /* Rx descriptor active for ring 2 */
+#define FEC_X_DES_ACTIVE_2	0x1ec /* Tx descriptor active for ring 2 */
 #define FEC_MIIGSK_CFGR		0x300 /* MIIGSK Configuration reg */
 #define FEC_MIIGSK_ENR		0x308 /* MIIGSK Enable reg */
 
@@ -233,6 +245,43 @@ struct bufdesc_ex {
 /* This device has up to three irqs on some platforms */
 #define FEC_IRQ_NUM		3
 
+/* Maximum number of queues supported
+ * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
+ * User can point the queue number that is less than or equal to 3.
+ */
+#define FEC_ENET_MAX_TX_QS	3
+#define FEC_ENET_MAX_RX_QS	3
+
+#define FEC_R_DES_START(X)	((X == 1) ? FEC_R_DES_START_1 : \
+				((X == 2) ? \
+					FEC_R_DES_START_2 : FEC_R_DES_START_0))
+#define FEC_X_DES_START(X)	((X == 1) ? FEC_X_DES_START_1 : \
+				((X == 2) ? \
+					FEC_X_DES_START_2 : FEC_X_DES_START_0))
+#define FEC_R_DES_ACTIVE(X)	((X == 1) ? FEC_R_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_R_DES_ACTIVE_2 : FEC_R_DES_ACTIVE_0))
+#define FEC_X_DES_ACTIVE(X)	((X == 1) ? FEC_X_DES_ACTIVE_1 : \
+				((X == 2) ? \
+				   FEC_X_DES_ACTIVE_2 : FEC_X_DES_ACTIVE_0))
+
+#define FEC_DMA_CFG(X)		((X == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
+
+#define DMA_CLASS_EN		(1 << 16)
+#define FEC_RCMR(X)		((X == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
+#define IDLE_SLOPE_MASK		0xFFFF
+#define IDLE_SLOPE_1		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE_2		0x200 /* BW fraction: 0.5 */
+#define IDLE_SLOPE(X)		((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
+				(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
+#define RCMR_MATCHEN            (0x1 << 16)
+#define RCMR_CMP_CFG(v, n)	((v & 0x7) <<  (n << 2))
+#define RCMR_CMP_1		(RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
+				RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
+#define RCMR_CMP_2		(RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
+				RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
+#define RCMR_CMP(X)		((X == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
+
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -256,6 +305,35 @@ struct bufdesc_ex {
 #define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 #define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
 
+struct fec_enet_priv_tx_q {
+	int index;
+	unsigned char *tx_bounce[TX_RING_SIZE];
+	struct  sk_buff *tx_skbuff[TX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*tx_bd_base;
+	uint tx_ring_size;
+
+	unsigned short tx_stop_threshold;
+	unsigned short tx_wake_threshold;
+
+	struct bufdesc	*cur_tx;
+	struct bufdesc	*dirty_tx;
+	char *tso_hdrs;
+	dma_addr_t tso_hdrs_dma;
+};
+
+struct fec_enet_priv_rx_q {
+	int index;
+	struct  sk_buff *rx_skbuff[RX_RING_SIZE];
+
+	dma_addr_t	bd_dma;
+	struct bufdesc	*rx_bd_base;
+	uint rx_ring_size;
+
+	struct bufdesc	*cur_rx;
+};
+
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
  * tx_bd_base always point to the base of the buffer descriptors.  The
  * cur_rx and cur_tx point to the currently available buffer.
@@ -280,29 +358,18 @@ struct fec_enet_private {
 	struct mutex ptp_clk_mutex;
 
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	unsigned char *tx_bounce[TX_RING_SIZE];
-	struct	sk_buff *tx_skbuff[TX_RING_SIZE];
-	struct	sk_buff *rx_skbuff[RX_RING_SIZE];
+	struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS];
+	struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS];
 
-	/* CPM dual port RAM relative addresses */
-	dma_addr_t	bd_dma;
-	/* Address of Rx and Tx buffers */
-	struct bufdesc	*rx_bd_base;
-	struct bufdesc	*tx_bd_base;
-	/* The next free ring entry */
-	struct bufdesc	*cur_rx, *cur_tx;
-	/* The ring entries to be free()ed */
-	struct bufdesc	*dirty_tx;
+	unsigned int total_tx_ring_size;
+	unsigned int total_rx_ring_size;
 
-	unsigned short bufdesc_size;
-	unsigned short tx_ring_size;
-	unsigned short rx_ring_size;
-	unsigned short tx_stop_threshold;
-	unsigned short tx_wake_threshold;
+	unsigned long work_tx;
+	unsigned long work_rx;
+	unsigned long work_ts;
+	unsigned long work_mdio;
 
-	/* Software TSO */
-	char *tso_hdrs;
-	dma_addr_t tso_hdrs_dma;
+	unsigned short bufdesc_size;
 
 	struct	platform_device *pdev;
 
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index ee9f04f..dd5c9dc 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -72,6 +72,8 @@ static void set_multicast_list(struct net_device *ndev);
 
 #define DRIVER_NAME	"fec"
 
+#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+
 /* Pause frame feild and FIFO threshold */
 #define FEC_ENET_FCE	(1 << 5)
 #define FEC_ENET_RSEM_V	0x84
@@ -258,22 +260,26 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 static int mii_cnt;
 
 static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp + 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
+	struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rxq = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= txq->tx_bd_base) {
+		base = txq->tx_bd_base;
+		ring_size = txq->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)txq->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rxq->rx_bd_base;
+		ring_size = rxq->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rxq->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -285,22 +291,26 @@ struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_priva
 }
 
 static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
+				      struct fec_enet_private *fep,
+				      int queue_id)
 {
 	struct bufdesc *new_bd = bdp - 1;
 	struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
+	struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id];
+	struct fec_enet_priv_rx_q *rxq = fep->rx_queue[queue_id];
 	struct bufdesc_ex *ex_base;
 	struct bufdesc *base;
 	int ring_size;
 
-	if (bdp >= fep->tx_bd_base) {
-		base = fep->tx_bd_base;
-		ring_size = fep->tx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+	if (bdp >= txq->tx_bd_base) {
+		base = txq->tx_bd_base;
+		ring_size = txq->tx_ring_size;
+		ex_base = (struct bufdesc_ex *)txq->tx_bd_base;
 	} else {
-		base = fep->rx_bd_base;
-		ring_size = fep->rx_ring_size;
-		ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+		base = rxq->rx_bd_base;
+		ring_size = rxq->rx_ring_size;
+		ex_base = (struct bufdesc_ex *)rxq->rx_bd_base;
 	}
 
 	if (fep->bufdesc_ex)
@@ -316,14 +326,15 @@ static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
 	return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
 }
 
-static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep)
+static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
+					struct fec_enet_priv_tx_q *txq)
 {
 	int entries;
 
-	entries = ((const char *)fep->dirty_tx -
-			(const char *)fep->cur_tx) / fep->bufdesc_size - 1;
+	entries = ((const char *)txq->dirty_tx -
+			(const char *)txq->cur_tx) / fep->bufdesc_size - 1;
 
-	return entries > 0 ? entries : entries + fep->tx_ring_size;
+	return entries > 0 ? entries : entries + txq->tx_ring_size;
 }
 
 static void *swap_buffer(void *bufaddr, int len)
@@ -340,22 +351,26 @@ static void *swap_buffer(void *bufaddr, int len)
 static void fec_dump(struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
-	struct bufdesc *bdp = fep->tx_bd_base;
-	unsigned int index = 0;
+	struct bufdesc *bdp;
+	struct fec_enet_priv_tx_q *txq;
+	int index = 0;
 
 	netdev_info(ndev, "TX ring dump\n");
 	pr_info("Nr     SC     addr       len  SKB\n");
 
+	txq = fep->tx_queue[0];
+	bdp = txq->tx_bd_base;
+
 	do {
 		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
 			index,
-			bdp == fep->cur_tx ? 'S' : ' ',
-			bdp == fep->dirty_tx ? 'H' : ' ',
+			bdp == txq->cur_tx ? 'S' : ' ',
+			bdp == txq->dirty_tx ? 'H' : ' ',
 			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
-			fep->tx_skbuff[index]);
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+			txq->tx_skbuff[index]);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 		index++;
-	} while (bdp != fep->tx_bd_base);
+	} while (bdp != txq->tx_bd_base);
 }
 
 static inline bool is_ipv4_pkt(struct sk_buff *skb)
@@ -381,14 +396,17 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
 }
 
 static int
-fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
+fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
+			     struct sk_buff *skb,
+			     struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
 	struct bufdesc_ex *ebdp;
 	int nr_frags = skb_shinfo(skb)->nr_frags;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	int frag, frag_len;
 	unsigned short status;
 	unsigned int estatus = 0;
@@ -400,7 +418,7 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 	for (frag = 0; frag < nr_frags; frag++) {
 		this_frag = &skb_shinfo(skb)->frags[frag];
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		ebdp = (struct bufdesc_ex *)bdp;
 
 		status = bdp->cbd_sc;
@@ -428,11 +446,11 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 
 		bufaddr = page_address(this_frag->page.p) + this_frag->page_offset;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 			id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-			memcpy(fep->tx_bounce[index], bufaddr, frag_len);
-			bufaddr = fep->tx_bounce[index];
+			memcpy(txq->tx_bounce[index], bufaddr, frag_len);
+			bufaddr = txq->tx_bounce[index];
 
 			if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 				swap_buffer(bufaddr, frag_len);
@@ -452,21 +470,22 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
 		bdp->cbd_sc = status;
 	}
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	return 0;
 
 dma_mapping_error:
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	for (i = 0; i < frag; i++) {
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 				bdp->cbd_datlen, DMA_TO_DEVICE);
 	}
 	return NETDEV_TX_OK;
 }
 
-static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -477,12 +496,13 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	dma_addr_t addr;
 	unsigned short status;
 	unsigned short buflen;
+	unsigned short queue;
 	unsigned int estatus = 0;
 	unsigned int index;
 	int entries_free;
 	int ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
 	if (entries_free < MAX_SKB_FRAGS + 1) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
@@ -497,7 +517,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	/* Fill in a Tx ring entry */
-	bdp = fep->cur_tx;
+	bdp = txq->cur_tx;
 	status = bdp->cbd_sc;
 	status &= ~BD_ENET_TX_STATS;
 
@@ -505,11 +525,12 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bufaddr = skb->data;
 	buflen = skb_headlen(skb);
 
-	index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+	queue = skb_get_queue_mapping(skb);
+	index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, buflen);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, buflen);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, buflen);
@@ -525,7 +546,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	if (nr_frags) {
-		ret = fec_enet_txq_submit_frag_skb(skb, ndev);
+		ret = fec_enet_txq_submit_frag_skb(txq, skb, ndev);
 		if (ret)
 			return ret;
 	} else {
@@ -553,10 +574,10 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 		ebdp->cbd_esc = estatus;
 	}
 
-	last_bdp = fep->cur_tx;
-	index = fec_enet_get_bd_index(fep->tx_bd_base, last_bdp, fep);
+	last_bdp = txq->cur_tx;
+	index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	bdp->cbd_datlen = buflen;
 	bdp->cbd_bufaddr = addr;
@@ -568,22 +589,23 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
 	bdp->cbd_sc = status;
 
 	/* If this was the last BD in the ring, start at the beginning again. */
-	bdp = fec_enet_get_nextdesc(last_bdp, fep);
+	bdp = fec_enet_get_nextdesc(last_bdp, fep, queue);
 
 	skb_tx_timestamp(skb);
 
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 }
 
 static int
-fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index, char *data,
-			int size, bool last_tcp, bool is_last)
+fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
+			  struct net_device *ndev,
+			  struct bufdesc *bdp, int index, char *data,
+			  int size, bool last_tcp, bool is_last)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -600,8 +622,8 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 
 	if (((unsigned long) data) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], data, size);
-		data = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], data, size);
+		data = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(data, size);
@@ -640,8 +662,9 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
 }
 
 static int
-fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
-			struct bufdesc *bdp, int index)
+fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
+			 struct sk_buff *skb, struct net_device *ndev,
+			 struct bufdesc *bdp, int index)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
@@ -657,12 +680,12 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	status &= ~BD_ENET_TX_STATS;
 	status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
 
-	bufaddr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
-	dmabuf = fep->tso_hdrs_dma + index * TSO_HEADER_SIZE;
+	bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
+	dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
 		id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
-		memcpy(fep->tx_bounce[index], skb->data, hdr_len);
-		bufaddr = fep->tx_bounce[index];
+		memcpy(txq->tx_bounce[index], skb->data, hdr_len);
+		bufaddr = txq->tx_bounce[index];
 
 		if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
 			swap_buffer(bufaddr, hdr_len);
@@ -692,17 +715,20 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
 	return 0;
 }
 
-static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
+				   struct sk_buff *skb,
+				   struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 	int total_len, data_left;
-	struct bufdesc *bdp = fep->cur_tx;
+	struct bufdesc *bdp = txq->cur_tx;
+	unsigned short queue = skb_get_queue_mapping(skb);
 	struct tso_t tso;
 	unsigned int index = 0;
 	int ret;
 
-	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep)) {
+	if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
 		dev_kfree_skb_any(skb);
 		if (net_ratelimit())
 			netdev_err(ndev, "NOT enough BD for TSO!\n");
@@ -722,14 +748,14 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 	while (total_len > 0) {
 		char *hdr;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 		data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
 		total_len -= data_left;
 
 		/* prepare packet headers: MAC + IP + TCP */
-		hdr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
+		hdr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
 		tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
-		ret = fec_enet_txq_put_hdr_tso(skb, ndev, bdp, index);
+		ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index);
 		if (ret)
 			goto err_release;
 
@@ -737,10 +763,13 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			int size;
 
 			size = min_t(int, tso.size, data_left);
-			bdp = fec_enet_get_nextdesc(bdp, fep);
-			index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
-			ret = fec_enet_txq_put_data_tso(skb, ndev, bdp, index, tso.data,
-							size, size == data_left,
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+			index = fec_enet_get_bd_index(txq->tx_bd_base,
+						      bdp, fep);
+			ret = fec_enet_txq_put_data_tso(txq, skb, ndev,
+							bdp, index,
+							tso.data, size,
+							size == data_left,
 							total_len == 0);
 			if (ret)
 				goto err_release;
@@ -749,17 +778,17 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
 			tso_build_data(skb, &tso, size);
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue);
 	}
 
 	/* Save skb pointer */
-	fep->tx_skbuff[index] = skb;
+	txq->tx_skbuff[index] = skb;
 
 	skb_tx_timestamp(skb);
-	fep->cur_tx = bdp;
+	txq->cur_tx = bdp;
 
 	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
 
 	return 0;
 
@@ -773,18 +802,25 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	int entries_free;
+	unsigned short queue;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int ret;
 
+	queue = skb_get_queue_mapping(skb);
+	txq = fep->tx_queue[queue];
+	nq = netdev_get_tx_queue(ndev, queue);
+
 	if (skb_is_gso(skb))
-		ret = fec_enet_txq_submit_tso(skb, ndev);
+		ret = fec_enet_txq_submit_tso(txq, skb, ndev);
 	else
-		ret = fec_enet_txq_submit_skb(skb, ndev);
+		ret = fec_enet_txq_submit_skb(txq, skb, ndev);
 	if (ret)
 		return ret;
 
-	entries_free = fec_enet_get_free_txdesc_num(fep);
-	if (entries_free <= fep->tx_stop_threshold)
-		netif_stop_queue(ndev);
+	entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+	if (entries_free <= txq->tx_stop_threshold)
+		netif_tx_stop_queue(nq);
 
 	return NETDEV_TX_OK;
 }
@@ -794,46 +830,51 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static void fec_enet_bd_init(struct net_device *dev)
 {
 	struct fec_enet_private *fep = netdev_priv(dev);
+	struct fec_enet_priv_tx_q *txq;
+	struct fec_enet_priv_rx_q *rxq;
 	struct bufdesc *bdp;
 	unsigned int i;
 
 	/* Initialize the receive buffer descriptors. */
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
+	rxq = fep->rx_queue[0];
+	bdp = rxq->rx_bd_base;
+
+	for (i = 0; i < rxq->rx_ring_size; i++) {
 
 		/* Initialize the BD for every fragment in the page. */
 		if (bdp->cbd_bufaddr)
 			bdp->cbd_sc = BD_ENET_RX_EMPTY;
 		else
 			bdp->cbd_sc = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 	}
 
 	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
+	bdp = fec_enet_get_prevdesc(bdp, fep, 0);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
-	fep->cur_rx = fep->rx_bd_base;
+	rxq->cur_rx = rxq->rx_bd_base;
 
 	/* ...and the same for transmit */
-	bdp = fep->tx_bd_base;
-	fep->cur_tx = bdp;
-	for (i = 0; i < fep->tx_ring_size; i++) {
+	txq = fep->tx_queue[0];
+	bdp = txq->tx_bd_base;
+	txq->cur_tx = bdp;
 
+	for (i = 0; i < txq->tx_ring_size; i++) {
 		/* Initialize the BD for every fragment in the page. */
 		bdp->cbd_sc = 0;
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
+		if (txq->tx_skbuff[i]) {
+			dev_kfree_skb_any(txq->tx_skbuff[i]);
+			txq->tx_skbuff[i] = NULL;
 		}
 		bdp->cbd_bufaddr = 0;
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 	}
 
 	/* Set the last buffer to wrap */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
+	bdp = fec_enet_get_prevdesc(bdp, fep, 0);
 	bdp->cbd_sc |= BD_SC_WRAP;
-	fep->dirty_tx = bdp;
+	txq->dirty_tx = bdp;
 }
 
 /*
@@ -852,6 +893,8 @@ fec_restart(struct net_device *ndev)
 	u32 temp_mac[2];
 	u32 rcntl = OPT_FRAME_SIZE | 0x04;
 	u32 ecntl = 0x2; /* ETHEREN */
+	struct fec_enet_priv_tx_q *txq;
+	struct fec_enet_priv_rx_q *rxq;
 
 	/* Whack a reset.  We should wait for this. */
 	writel(1, fep->hwp + FEC_ECNTRL);
@@ -876,19 +919,21 @@ fec_restart(struct net_device *ndev)
 	fec_enet_bd_init(ndev);
 
 	/* Set receive and transmit descriptor base. */
-	writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
+	rxq = fep->rx_queue[0];
+	writel(rxq->bd_dma, fep->hwp + FEC_R_DES_START(0));
 	if (fep->bufdesc_ex)
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
-			* fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
+		writel((unsigned long)rxq->bd_dma + sizeof(struct bufdesc_ex)
+			* rxq->rx_ring_size, fep->hwp + FEC_X_DES_START(0));
 	else
-		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
-			* fep->rx_ring_size,	fep->hwp + FEC_X_DES_START);
+		writel((unsigned long)rxq->bd_dma + sizeof(struct bufdesc)
+			* rxq->rx_ring_size,    fep->hwp + FEC_X_DES_START(0));
 
 
+	txq = fep->tx_queue[0];
 	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
-		if (fep->tx_skbuff[i]) {
-			dev_kfree_skb_any(fep->tx_skbuff[i]);
-			fep->tx_skbuff[i] = NULL;
+		if (txq->tx_skbuff[i]) {
+			dev_kfree_skb_any(txq->tx_skbuff[i]);
+			txq->tx_skbuff[i] = NULL;
 		}
 	}
 
@@ -1012,7 +1057,7 @@ fec_restart(struct net_device *ndev)
 
 	/* And last, enable the transmit and receive processing */
 	writel(ecntl, fep->hwp + FEC_ECNTRL);
-	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+	writel(0, fep->hwp + FEC_R_DES_ACTIVE(0));
 
 	if (fep->bufdesc_ex)
 		fec_ptp_start_cyclecounter(ndev);
@@ -1097,37 +1142,45 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
 }
 
 static void
-fec_enet_tx(struct net_device *ndev)
+fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
 {
 	struct	fec_enet_private *fep;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
+	struct fec_enet_priv_tx_q *txq;
+	struct netdev_queue *nq;
 	int	index = 0;
 	int	entries_free;
 
 	fep = netdev_priv(ndev);
-	bdp = fep->dirty_tx;
+
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+
+	txq = fep->tx_queue[queue_id];
+	/* get next bdp of dirty_tx */
+	nq = netdev_get_tx_queue(ndev, queue_id);
+	bdp = txq->dirty_tx;
 
 	/* get next bdp of dirty_tx */
-	bdp = fec_enet_get_nextdesc(bdp, fep);
+	bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
 
 		/* current queue is empty */
-		if (bdp == fep->cur_tx)
+		if (bdp == txq->cur_tx)
 			break;
 
-		index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+		index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
 
-		skb = fep->tx_skbuff[index];
-		fep->tx_skbuff[index] = NULL;
-		if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+		skb = txq->tx_skbuff[index];
+		txq->tx_skbuff[index] = NULL;
+		if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					bdp->cbd_datlen, DMA_TO_DEVICE);
 		bdp->cbd_bufaddr = 0;
 		if (!skb) {
-			bdp = fec_enet_get_nextdesc(bdp, fep);
+			bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 			continue;
 		}
 
@@ -1169,23 +1222,37 @@ fec_enet_tx(struct net_device *ndev)
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
 
-		fep->dirty_tx = bdp;
+		txq->dirty_tx = bdp;
 
 		/* Update pointer to next buffer descriptor to be transmitted */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
 		if (netif_queue_stopped(ndev)) {
-			entries_free = fec_enet_get_free_txdesc_num(fep);
-			if (entries_free >= fep->tx_wake_threshold)
-				netif_wake_queue(ndev);
+			entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+			if (entries_free >= txq->tx_wake_threshold)
+				netif_tx_wake_queue(nq);
 		}
 	}
 
 	/* ERR006538: Keep the transmitter going */
-	if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
-		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+	if (bdp != txq->cur_tx &&
+	    readl(fep->hwp + FEC_X_DES_ACTIVE(queue_id)) == 0)
+		writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue_id));
+}
+
+static void
+fec_enet_tx(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	u16 queue_id;
+	/* First process class A queue, then Class B and Best Effort queue */
+	for_each_set_bit(queue_id, &fep->work_tx, FEC_ENET_MAX_TX_QS) {
+		clear_bit(queue_id, &fep->work_tx);
+		fec_enet_tx_queue(ndev, queue_id);
+	}
+	return;
 }
 
 /* During a receive, the cur_rx points to the current incoming buffer.
@@ -1194,11 +1261,12 @@ fec_enet_tx(struct net_device *ndev)
  * effectively tossing the packet.
  */
 static int
-fec_enet_rx(struct net_device *ndev, int budget)
+fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_rx_q *rxq;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
@@ -1213,11 +1281,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
 #ifdef CONFIG_M532x
 	flush_cache_all();
 #endif
+	queue_id = FEC_ENET_GET_QUQUE(queue_id);
+	rxq = fep->rx_queue[queue_id];
 
 	/* First, grab all of the stats for the incoming packet.
 	 * These get messed up if we get called due to a busy condition.
 	 */
-	bdp = fep->cur_rx;
+	bdp = rxq->cur_rx;
 
 	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
 
@@ -1231,7 +1301,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		if ((status & BD_ENET_RX_LAST) == 0)
 			netdev_err(ndev, "rcv is not +last\n");
 
-		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
 
 		/* Check for errors. */
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
@@ -1264,8 +1333,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		pkt_len = bdp->cbd_datlen;
 		ndev->stats.rx_bytes += pkt_len;
 
-		index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep);
-		data = fep->rx_skbuff[index]->data;
+		index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep);
+		data = rxq->rx_skbuff[index]->data;
 		dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 
@@ -1280,7 +1349,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 		/* If this is a VLAN packet remove the VLAN Tag */
 		vlan_packet_rcvd = false;
 		if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
-		    fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+			fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
 			/* Push and remove the vlan tag */
 			struct vlan_hdr *vlan_header =
 					(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1308,7 +1377,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
 			skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
 			if (vlan_packet_rcvd)
 				payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
-			skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
+				skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
 						       data + payload_offset,
 						       pkt_len - 4 - (2 * ETH_ALEN));
 
@@ -1357,19 +1426,48 @@ rx_processing_done:
 		}
 
 		/* Update BD pointer to next entry */
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
 
 		/* Doing this here will keep the FEC running while we process
 		 * incoming frames.  On a heavily loaded network, we should be
 		 * able to keep up at the expense of system resources.
 		 */
-		writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+		writel(0, fep->hwp + FEC_R_DES_ACTIVE(queue_id));
 	}
-	fep->cur_rx = bdp;
+	rxq->cur_rx = bdp;
+	return pkt_received;
+}
+
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
+{
+	int     pkt_received = 0;
+	u16	queue_id;
+	struct fec_enet_private *fep = netdev_priv(ndev);
 
+	for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
+		clear_bit(queue_id, &fep->work_rx);
+		pkt_received += fec_enet_rx_queue(ndev,
+					budget - pkt_received, queue_id);
+	}
 	return pkt_received;
 }
 
+static bool
+fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
+{
+	if (int_events == 0)
+		return false;
+
+	if (int_events & FEC_ENET_RXF)
+		fep->work_rx |= (1 << 2);
+
+	if (int_events & FEC_ENET_TXF)
+		fep->work_tx |= (1 << 2);
+
+	return true;
+}
+
 static irqreturn_t
 fec_enet_interrupt(int irq, void *dev_id)
 {
@@ -1381,6 +1479,7 @@ fec_enet_interrupt(int irq, void *dev_id)
 
 	int_events = readl(fep->hwp + FEC_IEVENT);
 	writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT);
+	fec_enet_collect_events(fep, int_events);
 
 	if (int_events & napi_mask) {
 		ret = IRQ_HANDLED;
@@ -2132,25 +2231,29 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 	unsigned int i;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
-
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
-		skb = fep->rx_skbuff[i];
-		fep->rx_skbuff[i] = NULL;
+	struct fec_enet_priv_tx_q *txq;
+	struct fec_enet_priv_rx_q *rxq;
+
+	rxq = fep->rx_queue[0];
+	bdp = rxq->rx_bd_base;
+	for (i = 0; i < rxq->rx_ring_size; i++) {
+		skb = rxq->rx_skbuff[i];
+		rxq->rx_skbuff[i] = NULL;
 		if (skb) {
 			dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 					FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
 			dev_kfree_skb(skb);
 		}
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 	}
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		kfree(fep->tx_bounce[i]);
-		fep->tx_bounce[i] = NULL;
-		skb = fep->tx_skbuff[i];
-		fep->tx_skbuff[i] = NULL;
+	txq = fep->tx_queue[0];
+	bdp = txq->tx_bd_base;
+	for (i = 0; i < txq->tx_ring_size; i++) {
+		kfree(txq->tx_bounce[i]);
+		txq->tx_bounce[i] = NULL;
+		skb = txq->tx_skbuff[i];
+		txq->tx_skbuff[i] = NULL;
 		dev_kfree_skb(skb);
 	}
 }
@@ -2161,9 +2264,12 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 	unsigned int i;
 	struct sk_buff *skb;
 	struct bufdesc	*bdp;
+	struct fec_enet_priv_tx_q *txq;
+	struct fec_enet_priv_rx_q *rxq;
 
-	bdp = fep->rx_bd_base;
-	for (i = 0; i < fep->rx_ring_size; i++) {
+	rxq = fep->rx_queue[0];
+	bdp = rxq->rx_bd_base;
+	for (i = 0; i < rxq->rx_ring_size; i++) {
 		dma_addr_t addr;
 
 		skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
@@ -2179,7 +2285,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 			goto err_alloc;
 		}
 
-		fep->rx_skbuff[i] = skb;
+		rxq->rx_skbuff[i] = skb;
 		bdp->cbd_bufaddr = addr;
 		bdp->cbd_sc = BD_ENET_RX_EMPTY;
 
@@ -2188,17 +2294,18 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 			ebdp->cbd_esc = BD_ENET_RX_INT;
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 	}
 
 	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
+	bdp = fec_enet_get_prevdesc(bdp, fep, 0);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
-	bdp = fep->tx_bd_base;
-	for (i = 0; i < fep->tx_ring_size; i++) {
-		fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
-		if (!fep->tx_bounce[i])
+	txq = fep->tx_queue[0];
+	bdp = txq->tx_bd_base;
+	for (i = 0; i < txq->tx_ring_size; i++) {
+		txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
+		if (!txq->tx_bounce[i])
 			goto err_alloc;
 
 		bdp->cbd_sc = 0;
@@ -2209,11 +2316,11 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
 			ebdp->cbd_esc = BD_ENET_TX_INT;
 		}
 
-		bdp = fec_enet_get_nextdesc(bdp, fep);
+		bdp = fec_enet_get_nextdesc(bdp, fep, 0);
 	}
 
 	/* Set the last buffer to wrap. */
-	bdp = fec_enet_get_prevdesc(bdp, fep);
+	bdp = fec_enet_get_prevdesc(bdp, fep, 0);
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	return 0;
@@ -2252,7 +2359,8 @@ fec_enet_open(struct net_device *ndev)
 	fec_restart(ndev);
 	napi_enable(&fep->napi);
 	phy_start(fep->phy_dev);
-	netif_start_queue(ndev);
+	netif_tx_start_all_queues(ndev);
+
 	return 0;
 }
 
@@ -2426,7 +2534,7 @@ static int fec_set_features(struct net_device *netdev,
 	/* Resume the device after updates */
 	if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
 		fec_restart(netdev);
-		netif_wake_queue(netdev);
+		netif_tx_wake_all_queues(netdev);
 		netif_tx_unlock_bh(netdev);
 		napi_enable(&fep->napi);
 	}
@@ -2434,10 +2542,17 @@ static int fec_set_features(struct net_device *netdev,
 	return 0;
 }
 
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+			  void *accel_priv, select_queue_fallback_t fallback)
+{
+	return skb_tx_hash(ndev, skb);
+}
+
 static const struct net_device_ops fec_netdev_ops = {
 	.ndo_open		= fec_enet_open,
 	.ndo_stop		= fec_enet_close,
 	.ndo_start_xmit		= fec_enet_start_xmit,
+	.ndo_select_queue       = fec_enet_select_queue,
 	.ndo_set_rx_mode	= set_multicast_list,
 	.ndo_change_mtu		= eth_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -2459,39 +2574,55 @@ static int fec_enet_init(struct net_device *ndev)
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	const struct platform_device_id *id_entry =
 				platform_get_device_id(fep->pdev);
+	struct fec_enet_priv_tx_q *txq;
+	struct fec_enet_priv_rx_q *rxq;
 	struct bufdesc *cbd_base;
+	dma_addr_t bd_dma;
 	int bd_size;
 
-	/* init the tx & rx ring size */
-	fep->tx_ring_size = TX_RING_SIZE;
-	fep->rx_ring_size = RX_RING_SIZE;
+	txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+	if (!txq)
+		return -ENOMEM;
+	fep->tx_queue[0] = txq;
+
+	rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
+	if (!rxq) {
+		kfree(txq);
+		return -ENOMEM;
+	}
 
-	fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
-	fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+	fep->rx_queue[0] = rxq;
+
+
+	txq->tx_ring_size = TX_RING_SIZE;
+	rxq->rx_ring_size = RX_RING_SIZE;
+	fep->total_tx_ring_size = txq->tx_ring_size;
+	fep->total_rx_ring_size = rxq->rx_ring_size;
+
+	txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+	txq->tx_wake_threshold = (txq->tx_ring_size - txq->tx_stop_threshold) / 2;
 
 	if (fep->bufdesc_ex)
 		fep->bufdesc_size = sizeof(struct bufdesc_ex);
 	else
 		fep->bufdesc_size = sizeof(struct bufdesc);
-	bd_size = (fep->tx_ring_size + fep->rx_ring_size) *
+	bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *
 			fep->bufdesc_size;
 
 	/* Allocate memory for buffer descriptors. */
-	cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
+	cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
 				      GFP_KERNEL);
 	if (!cbd_base)
 		return -ENOMEM;
 
-	fep->tso_hdrs = dma_alloc_coherent(NULL, fep->tx_ring_size * TSO_HEADER_SIZE,
-						&fep->tso_hdrs_dma, GFP_KERNEL);
-	if (!fep->tso_hdrs) {
-		dma_free_coherent(NULL, bd_size, cbd_base, fep->bd_dma);
+	txq->tso_hdrs = dma_alloc_coherent(NULL, txq->tx_ring_size * TSO_HEADER_SIZE,
+						&txq->tso_hdrs_dma, GFP_KERNEL);
+	if (!txq->tso_hdrs) {
+		dma_free_coherent(NULL, bd_size, cbd_base, bd_dma);
 		return -ENOMEM;
 	}
 
-	memset(cbd_base, 0, PAGE_SIZE);
-
-	fep->netdev = ndev;
+	memset(cbd_base, 0, bd_size);
 
 	/* Get the Ethernet address */
 	fec_get_mac(ndev);
@@ -2499,12 +2630,13 @@ static int fec_enet_init(struct net_device *ndev)
 	fec_set_mac_address(ndev, NULL);
 
 	/* Set receive and transmit descriptor base. */
-	fep->rx_bd_base = cbd_base;
+	rxq->rx_bd_base = cbd_base;
 	if (fep->bufdesc_ex)
-		fep->tx_bd_base = (struct bufdesc *)
-			(((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
+		txq->tx_bd_base = (struct bufdesc *)
+			(((struct bufdesc_ex *)cbd_base) + rxq->rx_ring_size);
 	else
-		fep->tx_bd_base = cbd_base + fep->rx_ring_size;
+		txq->tx_bd_base = cbd_base + rxq->rx_ring_size;
+
 
 	/* The FEC Ethernet specific entries in the device structure */
 	ndev->watchdog_timeo = TX_TIMEOUT;
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH net v2] ipv6: fix rtnl locking in setsockopt for anycast and multicast
From: Cong Wang @ 2014-09-05 19:34 UTC (permalink / raw)
  To: David Miller
  Cc: Hannes Frederic Sowa, Sabrina Dubroca, Tommi Rantala,
	Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
	Patrick McHardy, netdev, linux-kernel@vger.kernel.org, trinity,
	Dave Jones
In-Reply-To: <20140905.122539.670916286627732128.davem@davemloft.net>

On Fri, Sep 5, 2014 at 12:25 PM, David Miller <davem@davemloft.net> wrote:
>
> I thought the retention of RCU locking was reasonable, and that your
> feedback was something I disagreed with.
>
> This is different from ignoring your feedback.

The point is we don't need to backport the patch that far, as I already
mentioned, up to  commit c15b1ccadb323ea
("ipv6: move DAD and addrconf_verify processing to workqueue"),
simply because no one reports any bug.

So we don't have to adjust the patch just for stable in this case.

^ 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