* Re: source route ignored in favor of local interface
From: Joe Buehler @ 2011-06-09 16:27 UTC (permalink / raw)
To: Ben Greear; +Cc: Chris Friesen, netdev
In-Reply-To: <4D6E928D.6030806@candelatech.com>
Ben Greear wrote:
> You can do this on more modern kernels (2.6.36 and later definately
> works..not sure
> about earlier).
>
> ip rule add pref 512 lookup local
> ip rule del pref 0 lookup local
>
The kernel change for this in later kernels was simple enough -- there
is a flag that prevents deletion of the "local" table rule, just remove
the flag. Here is a patch for 2.6.24.7. The patch for 2.6.27.7 (I am
using both versions) is almost the same.
--- old/net/ipv4/fib_rules.c 2008-01-24 17:58:37.000000000 -0500
+++ new/net/ipv4/fib_rules.c 2011-06-08 14:01:19.000000000 -0400
@@ -297,7 +297,7 @@
int err;
err = fib_default_rule_add(&fib4_rules_ops, 0,
- RT_TABLE_LOCAL, FIB_RULE_PERMANENT);
+ RT_TABLE_LOCAL, 0);
if (err < 0)
return err;
err = fib_default_rule_add(&fib4_rules_ops, 0x7FFE,
--- old/net/ipv6/fib6_rules.c 2008-01-24 17:58:37.000000000 -0500
+++ new/net/ipv6/fib6_rules.c 2011-06-08 14:01:34.000000000 -0400
@@ -256,7 +256,7 @@
int err;
err = fib_default_rule_add(&fib6_rules_ops, 0,
- RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
+ RT6_TABLE_LOCAL, 0);
if (err < 0)
return err;
err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
Joe Buehler
^ permalink raw reply
* Re: [PATCH] netfilter: fix looped (broad|multi)cast's MAC handling.
From: Patrick McHardy @ 2011-06-09 16:08 UTC (permalink / raw)
To: Nicolas Cavallari; +Cc: fw, netfilter-devel, netdev, Nicolas Cavallari
In-Reply-To: <1307626748-10992-2-git-send-email-cavallar@lri.fr>
On 09.06.2011 15:39, Nicolas Cavallari wrote:
> By default, when broadcast or multicast packet are sent from a local
> application, they are sent to the interface then looped by the kernel
> to other local applications, going throught netfilter hooks in the process.
>
> These looped packet have their MAC header removed from the skb by the kernel
> looping code.
> This confuse various netfilter's netlink queue, netlink log and the
> legacy ip_queue, because they try to extract a hardware
> address from these packets, but extracts a part of the IP header instead.
>
> This patch prevent NFQUEUE, NFLOG and ip_QUEUE to include a MAC header
> if there is none in the packet.
Please add a Signed-off-by: line to your patch so I can apply it.
Thanks!
^ permalink raw reply
* Re: [PATCH net-2.6.23] Per-datagram TTL and TOS via sendmsg()
From: Miljanovic, Nebojsa (Neb) @ 2011-06-09 15:48 UTC (permalink / raw)
To: netdev@vger.kernel.org
(re-submitting to the mailing list since I did not use plain text the first time around)
Hello David,
is there any way to get this old PATCH accepted. I am finding it very useful since the only other way to control TOS/DSCP is via socket option. However, socket wide TOS/DSCP is not always practical. Having ability for applications to control TOS/DSCP on per-datagram basis is so much more powerful.
http://marc.info/?l=linux-netdev&m=118388241201593
Thanks,
Neb Miljanovic
Alcatel-Lucent
^ permalink raw reply
* TCP keepalives ignored by kernel when the contain timestamps
From: Charles Bearden @ 2011-06-09 15:26 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: text/plain, Size: 2719 bytes --]
I have come across a case that looks like it might be a kernel bug. It appears
that tcp keepalives sent by a remote system are ignored when they contain tcp
timestamps, but are ACKed when they don't. When they are ignored, the remote
system resets the connection after a number of retries.
I have replicated this problem on both Ubuntu 10.04 with a 2.6.32-32-server
kernel (x86_64) and CentOS 5.6 with a 2.6.18-238.12.1.el5 kernel. I'm sorry that
I haven't had a chance to try to replicate the bug with a newer kernel, though a
co-worker has looked through changelogs for more recent kernels and didn't find
anything that looked relevant.
From either of these hosts I run an application that connects to a remote host
for 2-3 minutes, and that for most of that time sends no application data back
and forth. After 30 seconds of no data from the Linux host, the remote host
sends a garden variety keepalive. When the remote host includes tcp timestamps
in the keepalives, they are ignored by the Linux host, and the remote host
resets the connection after 10 unACKed keepalives. When timestamps are absent
from the keepalives, the Linux host ACKs each one, and all is copacetic.
Text output of a tcpdump trace of a connection that fails:
http://pastebin.com/v6CpteJ9
Text output of a tcpdump trace of a connection that succeeds:
http://pastebin.com/KVLb3Mzh
More details, in case you think they are relevant:
My application creates a JDBC connection to a remote MS SQL Server and
executes a statement that does not return a result set, and so it doesn't
need to pass application data back and forth while it executes. The
statement takes 2 or 3 minutes to complete. I connect to two different
remote hosts: a Win2003 machine, and a Win2008R2 machine. The Win2003
machine doesn't put timestamps in its keep-alives, so the application
completes successfully when connecting to that host. If tcp timestamps
are enabled on the Linux host, the Win2008 host includes them in its
keepalives, and they are unACKed, so the connection is reset; if they
are disabled on the Linux host, the Win2008 host doesn't include them in
the keepalives, and the application completes successfully. I use (as
you might expect) sysctl to disable tcp timestamps on the Linux hosts.
I have dumps for all permutations of CentOS/Ubuntu, Win200[38], and +/-
timestamps on the Linux side, and I will post them if the developers think that
they would be useful.
Thanks,
Chuck Bearden
Programmer Analyst IV
The University of Texas Health Science Center at Houston
School of Biomedical Informatics
Email: Charles.F.Bearden@uth.tmc.edu
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5168 bytes --]
^ permalink raw reply
* Re: [PATCH 3/5 net-next] cnic: Randomize initial TCP port for iSCSI connections
From: Stephen Hemminger @ 2011-06-09 15:27 UTC (permalink / raw)
To: Michael Chan; +Cc: davem, netdev, Eddie Wai
In-Reply-To: <1307597376-5379-3-git-send-email-mchan@broadcom.com>
On Wed, 8 Jun 2011 22:29:34 -0700
"Michael Chan" <mchan@broadcom.com> wrote:
> static int cnic_cm_alloc_mem(struct cnic_dev *dev)
> {
> struct cnic_local *cp = dev->cnic_priv;
> + u32 port_id;
>
> cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
> GFP_KERNEL);
> if (!cp->csk_tbl)
> return -ENOMEM;
>
> + get_random_bytes(&port_id, sizeof(port_id));
I think random32() or it's alias net_random() would be sufficient
for your needs here.
^ permalink raw reply
* Re: [PATCH 1/2] tun: reserves space for network in skb
From: Stephen Hemminger @ 2011-06-09 14:16 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20110609.000914.359816474597759076.davem@davemloft.net>
> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Wed, 08 Jun 2011 17:33:07 -0700
>
> > The tun driver allocates skb's to hold data from user and then
> > passes the data into the network stack as received data. Most
> > network devices
> > allocate the receive skb with routines like dev_alloc_skb() that
> > reserves additional space for use by network protocol stack but tun
> > does not.
> >
> > Because of the lack of padding, when the packet is passed through
> > bridge netfilter a new skb has to be allocated.
> >
> > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>
> Netconf must be coming up soon, Stephen Hemminger is submitting
> patches again :-)
12 hours on plane + 8 hours in airports tend to get the
trivial patch backlog moving again.
^ permalink raw reply
* [PATCH] netfilter: fix looped (broad|multi)cast's MAC handling.
From: Nicolas Cavallari @ 2011-06-09 13:39 UTC (permalink / raw)
To: fw, kaber, netfilter-devel, netdev; +Cc: Nicolas Cavallari
In-Reply-To: <1307626748-10992-1-git-send-email-cavallar@lri.fr>
By default, when broadcast or multicast packet are sent from a local
application, they are sent to the interface then looped by the kernel
to other local applications, going throught netfilter hooks in the process.
These looped packet have their MAC header removed from the skb by the kernel
looping code.
This confuse various netfilter's netlink queue, netlink log and the
legacy ip_queue, because they try to extract a hardware
address from these packets, but extracts a part of the IP header instead.
This patch prevent NFQUEUE, NFLOG and ip_QUEUE to include a MAC header
if there is none in the packet.
---
net/ipv4/netfilter/ip_queue.c | 3 ++-
net/ipv6/netfilter/ip6_queue.c | 3 ++-
net/netfilter/nfnetlink_log.c | 3 ++-
net/netfilter/nfnetlink_queue.c | 3 ++-
4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index f7f9bd7..5c9b9d9 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -203,7 +203,8 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
else
pmsg->outdev_name[0] = '\0';
- if (entry->indev && entry->skb->dev) {
+ if (entry->indev && entry->skb->dev &&
+ entry->skb->mac_header != entry->skb->network_header) {
pmsg->hw_type = entry->skb->dev->type;
pmsg->hw_addrlen = dev_parse_header(entry->skb,
pmsg->hw_addr);
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 065fe40..2493948 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -204,7 +204,8 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
else
pmsg->outdev_name[0] = '\0';
- if (entry->indev && entry->skb->dev) {
+ if (entry->indev && entry->skb->dev &&
+ entry->skb->mac_header != entry->skb->network_header) {
pmsg->hw_type = entry->skb->dev->type;
pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr);
}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e0ee010..2e7ccbb 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -456,7 +456,8 @@ __build_packet_message(struct nfulnl_instance *inst,
if (skb->mark)
NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark));
- if (indev && skb->dev) {
+ if (indev && skb->dev &&
+ skb->mac_header != skb->network_header) {
struct nfulnl_msg_packet_hw phw;
int len = dev_parse_header(skb, phw.hw_addr);
if (len > 0) {
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b83123f..fdd2faf 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -335,7 +335,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
if (entskb->mark)
NLA_PUT_BE32(skb, NFQA_MARK, htonl(entskb->mark));
- if (indev && entskb->dev) {
+ if (indev && entskb->dev &&
+ entskb->mac_header != entskb->network_header) {
struct nfqnl_msg_packet_hw phw;
int len = dev_parse_header(entskb, phw.hw_addr);
if (len) {
--
1.7.5.3
^ permalink raw reply related
* Re: [PATCH] netfilter: fix looped (broad|multi)cast's bogus MACs in NFQUEUE
From: Nicolas Cavallari @ 2011-06-09 13:39 UTC (permalink / raw)
To: fw, kaber, netfilter-devel, netdev
In-Reply-To: <20110608153032.GA26912@Chamillionaire.breakpoint.cc>
> nfnetlink_log has the same problem.
I also figured from source that ip_queue has the same problem too, so
the next patch fixes that too.
^ permalink raw reply
* Re: [PATCH 10/14] netvm: Set PF_MEMALLOC as appropriate during SKB processing
From: Mel Gorman @ 2011-06-09 12:56 UTC (permalink / raw)
To: Micha? Miros?aw
Cc: Andrew Morton, Linux-MM, Linux-Netdev, LKML, David Miller,
Neil Brown, Peter Zijlstra
In-Reply-To: <BANLkTi=8jx8B8fR_+Z76UoTe_jhG9G-Tyw@mail.gmail.com>
On Thu, Jun 09, 2011 at 02:28:24PM +0200, Micha? Miros?aw wrote:
> 2011/6/9 Mel Gorman <mgorman@suse.de>:
> > On Thu, Jun 09, 2011 at 12:21:31PM +0200, Micha? Miros?aw wrote:
> >> 2011/6/9 Mel Gorman <mgorman@suse.de>:
> >> [...]
> >> > +/*
> >> > + * Limit which protocols can use the PFMEMALLOC reserves to those that are
> >> > + * expected to be used for communication with swap.
> >> > + */
> >> > +static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
> >> > +{
> >> > + switch (skb->protocol) {
> >> > + case __constant_htons(ETH_P_ARP):
> >> > + case __constant_htons(ETH_P_IP):
> >> > + case __constant_htons(ETH_P_IPV6):
> >> > + case __constant_htons(ETH_P_8021Q):
> >> > + return true;
> >> > + default:
> >> > + return false;
> >> > + }
> >> > +}
> >>
> >> This is not needed and wrong. Whatever list there will be, it's going
> >> to always miss some obscure setup (or not that obscure, like
> >> ATAoverEthernet).
> >>
> >
> > NBD is updated in the series to set the socket information
> > appropriately but the same cannot be said of AoE. The necessary
> > changes have been made IPv4 and IPv6 to handle pfmemalloc sockets
> > but the same cannot be necessarily said for the other protocols. Yes,
> > the check could be removed but leaving it there makes a clear statement
> > on what scenario can be reasonably expected to work.
>
> Ok. Then the comment before skb_pfmemalloc_protocol() is misleading.
> It should say that this is a list of protocols which implement the
> required special handling of PFMEMALLOC skbs.
>
That's a very reasonable suggestion. My thinking behind that comment
was a backwards because I only "expected" protocols that implemented
the special handling to be used for swap :/
Thanks.
--
Mel Gorman
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 10/14] netvm: Set PF_MEMALLOC as appropriate during SKB processing
From: Michał Mirosław @ 2011-06-09 12:28 UTC (permalink / raw)
To: Mel Gorman
Cc: Andrew Morton, Linux-MM, Linux-Netdev, LKML, David Miller,
Neil Brown, Peter Zijlstra
In-Reply-To: <20110609113505.GR5247@suse.de>
2011/6/9 Mel Gorman <mgorman@suse.de>:
> On Thu, Jun 09, 2011 at 12:21:31PM +0200, Micha? Miros?aw wrote:
>> 2011/6/9 Mel Gorman <mgorman@suse.de>:
>> [...]
>> > +/*
>> > + * Limit which protocols can use the PFMEMALLOC reserves to those that are
>> > + * expected to be used for communication with swap.
>> > + */
>> > +static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
>> > +{
>> > + switch (skb->protocol) {
>> > + case __constant_htons(ETH_P_ARP):
>> > + case __constant_htons(ETH_P_IP):
>> > + case __constant_htons(ETH_P_IPV6):
>> > + case __constant_htons(ETH_P_8021Q):
>> > + return true;
>> > + default:
>> > + return false;
>> > + }
>> > +}
>>
>> This is not needed and wrong. Whatever list there will be, it's going
>> to always miss some obscure setup (or not that obscure, like
>> ATAoverEthernet).
>>
>
> NBD is updated in the series to set the socket information
> appropriately but the same cannot be said of AoE. The necessary
> changes have been made IPv4 and IPv6 to handle pfmemalloc sockets
> but the same cannot be necessarily said for the other protocols. Yes,
> the check could be removed but leaving it there makes a clear statement
> on what scenario can be reasonably expected to work.
Ok. Then the comment before skb_pfmemalloc_protocol() is misleading.
It should say that this is a list of protocols which implement the
required special handling of PFMEMALLOC skbs.
Best Regards,
Michał Mirosław
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 10/14] netvm: Set PF_MEMALLOC as appropriate during SKB processing
From: Mel Gorman @ 2011-06-09 11:35 UTC (permalink / raw)
To: Micha? Miros?aw
Cc: Andrew Morton, Linux-MM, Linux-Netdev, LKML, David Miller,
Neil Brown, Peter Zijlstra
In-Reply-To: <BANLkTimUE9yb-DegdUk0BbbOGWoUhEBrqw@mail.gmail.com>
On Thu, Jun 09, 2011 at 12:21:31PM +0200, Micha? Miros?aw wrote:
> 2011/6/9 Mel Gorman <mgorman@suse.de>:
> [...]
> > +/*
> > + * Limit which protocols can use the PFMEMALLOC reserves to those that are
> > + * expected to be used for communication with swap.
> > + */
> > +static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
> > +{
> > + switch (skb->protocol) {
> > + case __constant_htons(ETH_P_ARP):
> > + case __constant_htons(ETH_P_IP):
> > + case __constant_htons(ETH_P_IPV6):
> > + case __constant_htons(ETH_P_8021Q):
> > + return true;
> > + default:
> > + return false;
> > + }
> > +}
>
> This is not needed and wrong. Whatever list there will be, it's going
> to always miss some obscure setup (or not that obscure, like
> ATAoverEthernet).
>
NBD is updated in the series to set the socket information
appropriately but the same cannot be said of AoE. The necessary
changes have been made IPv4 and IPv6 to handle pfmemalloc sockets
but the same cannot be necessarily said for the other protocols. Yes,
the check could be removed but leaving it there makes a clear statement
on what scenario can be reasonably expected to work.
--
Mel Gorman
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 1/3] vlan: Do not support clearing VLAN_FLAG_REORDER_HDR
From: Jiri Pirko @ 2011-06-09 11:00 UTC (permalink / raw)
To: Eric W. Biederman
Cc: David Miller, Nicolas de Pesloüan, Changli Gao, netdev,
shemminger, kaber, fubar, eric.dumazet, andy, Jesse Gross
In-Reply-To: <m1ei3qjzix.fsf_-_@fess.ebiederm.org>
How about to drop this patch and silently ignore the flag? That would
feel the same for user who is setting it.
Sun, May 22, 2011 at 09:39:18PM CEST, ebiederm@xmission.com wrote:
>
>Simplify the vlan handling code by not supporing clearing of
>VLAN_FLAG_REORDER_HDR. Which means we always make the vlan handling
>code strip the vlan header from the packets, and always insert the vlan
>header when transmitting packets.
>
>Not stripping the vlan header has alwasy been broken in combination with
>vlan hardware accelleration. Now that we are making everything look
>like accelerated vlan handling not stripping the vlan header is always
>broken.
>
>I don't think anyone actually cares so simply stop supporting the broken
>case.
>
>Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
>---
> net/8021q/vlan_dev.c | 3 +--
> net/8021q/vlan_netlink.c | 4 +---
> 2 files changed, 2 insertions(+), 5 deletions(-)
>
>diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
>index f247f5b..20629fe 100644
>--- a/net/8021q/vlan_dev.c
>+++ b/net/8021q/vlan_dev.c
>@@ -242,8 +242,7 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
> struct vlan_dev_info *vlan = vlan_dev_info(dev);
> u32 old_flags = vlan->flags;
>
>- if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
>- VLAN_FLAG_LOOSE_BINDING))
>+ if (mask & ~(VLAN_FLAG_GVRP | VLAN_FLAG_LOOSE_BINDING))
> return -EINVAL;
>
> vlan->flags = (old_flags & ~mask) | (flags & mask);
>diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
>index be9a5c1..a638a4c 100644
>--- a/net/8021q/vlan_netlink.c
>+++ b/net/8021q/vlan_netlink.c
>@@ -59,9 +59,7 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
> }
> if (data[IFLA_VLAN_FLAGS]) {
> flags = nla_data(data[IFLA_VLAN_FLAGS]);
>- if ((flags->flags & flags->mask) &
>- ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
>- VLAN_FLAG_LOOSE_BINDING))
>+ if (flags->mask & ~(VLAN_FLAG_GVRP | VLAN_FLAG_LOOSE_BINDING))
> return -EINVAL;
> }
>
>--
>1.7.5.1.217.g4e3aa
>
^ permalink raw reply
* Re: [PATCH 3/3] vlan: Simplify the code now that VLAN_FLAG_REORDER_HDR is always set
From: Jiri Pirko @ 2011-06-09 10:59 UTC (permalink / raw)
To: Eric W. Biederman
Cc: David Miller, Nicolas de Pesloüan, Changli Gao, netdev,
shemminger, kaber, fubar, eric.dumazet, andy, Jesse Gross
In-Reply-To: <m1y61yiktf.fsf_-_@fess.ebiederm.org>
Sun, May 22, 2011 at 09:42:20PM CEST, ebiederm@xmission.com wrote:
>
>Now that we no longer support clearing VLAN_FLAG_REORDER_HDR remove the
>code that was needed to cope with the case when it was cleared.
>
>Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
>---
> net/8021q/vlan_dev.c | 45 +++++----------------------------------------
> 1 files changed, 5 insertions(+), 40 deletions(-)
>
>diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
>index 20629fe..2b3ca1e 100644
>--- a/net/8021q/vlan_dev.c
>+++ b/net/8021q/vlan_dev.c
>@@ -96,63 +96,28 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
> const void *daddr, const void *saddr,
> unsigned int len)
> {
>- struct vlan_hdr *vhdr;
>- unsigned int vhdrlen = 0;
>- u16 vlan_tci = 0;
> int rc;
>
>- if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
>- vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
>-
>- vlan_tci = vlan_dev_info(dev)->vlan_id;
>- vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
>- vhdr->h_vlan_TCI = htons(vlan_tci);
>-
>- /*
>- * Set the protocol type. For a packet of type ETH_P_802_3/2 we
>- * put the length in here instead.
>- */
>- if (type != ETH_P_802_3 && type != ETH_P_802_2)
>- vhdr->h_vlan_encapsulated_proto = htons(type);
>- else
>- vhdr->h_vlan_encapsulated_proto = htons(len);
>-
>- skb->protocol = htons(ETH_P_8021Q);
>- type = ETH_P_8021Q;
>- vhdrlen = VLAN_HLEN;
>- }
>-
> /* Before delegating work to the lower layer, enter our MAC-address */
> if (saddr == NULL)
> saddr = dev->dev_addr;
>
> /* Now make the underlying real hard header */
> dev = vlan_dev_info(dev)->real_dev;
>- rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
>- if (rc > 0)
>- rc += vhdrlen;
>+ rc = dev_hard_header(skb, dev, type, daddr, saddr, len);
> return rc;
> }
>
> static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
> struct net_device *dev)
> {
>- struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
> unsigned int len;
>+ u16 vlan_tci;
> int ret;
>
>- /* Handle non-VLAN frames if they are sent to us, for example by DHCP.
>- *
>- * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
>- * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
>- */
>- if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
this should stay here.
>- vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) {
>- u16 vlan_tci;
>- vlan_tci = vlan_dev_info(dev)->vlan_id;
>- vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
>- skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
>- }
>+ vlan_tci = vlan_dev_info(dev)->vlan_id;
>+ vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
>+ skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
>
> skb_set_dev(skb, vlan_dev_info(dev)->real_dev);
> len = skb->len;
>--
>1.7.5.1.217.g4e3aa
>
^ permalink raw reply
* Re: [PATCH 5/5 net-next] cnic, bnx2: Check iSCSI support early in bnx2_init_one()
From: Neil Horman @ 2011-06-09 10:42 UTC (permalink / raw)
To: Michael Chan; +Cc: davem, netdev
In-Reply-To: <1307597376-5379-5-git-send-email-mchan@broadcom.com>
On Wed, Jun 08, 2011 at 10:29:36PM -0700, Michael Chan wrote:
> Based on earlier patch from Neil Horman <nhorman@tuxdriver.com>
>
> If iSCSI is not supported on a bnx2 device, bnx2_cnic_probe() will
> return NULL and the cnic device will not be visible to bnx2i. This
> will prevent bnx2i from registering and then unregistering during
> cnic_start() and cause the warning message:
>
> bnx2 0003:01:00.1: eth1: Failed waiting for ULP up call to complete
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Cc: Neil Horman <nhorman@tuxdriver.com>
Thank you Michael. This also lets you eliminate some dead code in bnx2i_start
now, since cdev->max_iscsi_conn will never be zero.
Regards
Neil
>
^ permalink raw reply
* Re: [PATCH 10/14] netvm: Set PF_MEMALLOC as appropriate during SKB processing
From: Michał Mirosław @ 2011-06-09 10:21 UTC (permalink / raw)
To: Mel Gorman
Cc: Andrew Morton, Linux-MM, Linux-Netdev, LKML, David Miller,
Neil Brown, Peter Zijlstra
In-Reply-To: <1307606573-24704-11-git-send-email-mgorman@suse.de>
2011/6/9 Mel Gorman <mgorman@suse.de>:
[...]
> +/*
> + * Limit which protocols can use the PFMEMALLOC reserves to those that are
> + * expected to be used for communication with swap.
> + */
> +static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
> +{
> + switch (skb->protocol) {
> + case __constant_htons(ETH_P_ARP):
> + case __constant_htons(ETH_P_IP):
> + case __constant_htons(ETH_P_IPV6):
> + case __constant_htons(ETH_P_8021Q):
> + return true;
> + default:
> + return false;
> + }
> +}
This is not needed and wrong. Whatever list there will be, it's going
to always miss some obscure setup (or not that obscure, like
ATAoverEthernet).
Best Regards,
Michał Mirosław
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [PATCH v3] net: add Faraday FTGMAC100 Gigabit Ethernet driver
From: Po-Yu Chuang @ 2011-06-09 9:32 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, eric.dumazet, Po-Yu Chuang
In-Reply-To: <1300355238-1619-1-git-send-email-ratbert.chuang@gmail.com>
From: Po-Yu Chuang <ratbert@faraday-tech.com>
FTGMAC100 Ethernet Media Access Controller supports 10/100/1000 Mbps
and MII/GMII. This driver has been working on some ARM/NDS32 SoC's
including Faraday A369 and Andes AG102.
Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
---
Sorry for the long delay.
v2:
fix checkpatch.pl found error
use GFP_ATOMIC allocations where needed
v3:
use resource_size()
use napi_gro_receive()
fix scheduling while atomic
drivers/net/Kconfig | 9 +
drivers/net/Makefile | 1 +
drivers/net/ftgmac100.c | 1365 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/ftgmac100.h | 246 +++++++++
4 files changed, 1621 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/ftgmac100.c
create mode 100644 drivers/net/ftgmac100.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6b12274..b9da914 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2560,6 +2560,15 @@ config PCH_GBE
to Gigabit Ethernet.
This driver enables Gigabit Ethernet function.
+config FTGMAC100
+ tristate "Faraday FTGMAC100 Gigabit Ethernet support"
+ depends on ARM
+ select PHYLIB
+ help
+ This driver supports the FTGMAC100 Gigabit Ethernet controller
+ from Faraday. It is used on Faraday A369, Andes AG102 and some
+ other ARM/NDS32 SoC's.
+
endif # NETDEV_1000
#
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7c21711..a349b26 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -147,6 +147,7 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_AX88796) += ax88796.o
obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_FTGMAC100) += ftgmac100.o
obj-$(CONFIG_FTMAC100) += ftmac100.o
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
new file mode 100644
index 0000000..54709af
--- /dev/null
+++ b/drivers/net/ftgmac100.c
@@ -0,0 +1,1365 @@
+/*
+ * Faraday FTGMAC100 Gigabit Ethernet
+ *
+ * (C) Copyright 2009-2011 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <net/ip.h>
+
+#include "ftgmac100.h"
+
+#define DRV_NAME "ftgmac100"
+#define DRV_VERSION "0.7"
+
+#define RX_QUEUE_ENTRIES 256 /* must be power of 2 */
+#define TX_QUEUE_ENTRIES 512 /* must be power of 2 */
+
+#define MAX_PKT_SIZE 1518
+#define RX_BUF_SIZE PAGE_SIZE /* must be smaller than 0x3fff */
+
+/******************************************************************************
+ * private data
+ *****************************************************************************/
+struct ftgmac100_descs {
+ struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
+ struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES];
+};
+
+struct ftgmac100 {
+ struct resource *res;
+ void __iomem *base;
+ int irq;
+
+ struct ftgmac100_descs *descs;
+ dma_addr_t descs_dma_addr;
+
+ unsigned int rx_pointer;
+ unsigned int tx_clean_pointer;
+ unsigned int tx_pointer;
+ unsigned int tx_pending;
+
+ spinlock_t tx_lock;
+
+ struct net_device *netdev;
+ struct device *dev;
+ struct napi_struct napi;
+
+ struct mii_bus *mii_bus;
+ int phy_irq[PHY_MAX_ADDR];
+ struct phy_device *phydev;
+ int old_speed;
+};
+
+static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
+ struct ftgmac100_rxdes *rxdes, gfp_t gfp);
+
+/******************************************************************************
+ * internal functions (hardware register access)
+ *****************************************************************************/
+#define INT_MASK_ALL_ENABLED (FTGMAC100_INT_RPKT_LOST | \
+ FTGMAC100_INT_XPKT_ETH | \
+ FTGMAC100_INT_XPKT_LOST | \
+ FTGMAC100_INT_AHB_ERR | \
+ FTGMAC100_INT_PHYSTS_CHG | \
+ FTGMAC100_INT_RPKT_BUF | \
+ FTGMAC100_INT_NO_RXBUF)
+
+static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
+{
+ iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
+}
+
+static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
+ unsigned int size)
+{
+ size = FTGMAC100_RBSR_SIZE(size);
+ iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
+}
+
+static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
+ dma_addr_t addr)
+{
+ iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
+}
+
+static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
+{
+ iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
+}
+
+static int ftgmac100_reset_hw(struct ftgmac100 *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ int i;
+
+ /* NOTE: reset clears all registers */
+ iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR);
+ for (i = 0; i < 5; i++) {
+ unsigned int maccr;
+
+ maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
+ if (!(maccr & FTGMAC100_MACCR_SW_RST))
+ return 0;
+
+ udelay(1000);
+ }
+
+ netdev_err(netdev, "software reset failed\n");
+ return -EIO;
+}
+
+static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
+{
+ unsigned int maddr = mac[0] << 8 | mac[1];
+ unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+
+ iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
+ iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
+}
+
+static void ftgmac100_init_hw(struct ftgmac100 *priv)
+{
+ /* setup ring buffer base registers */
+ ftgmac100_set_rx_ring_base(priv,
+ priv->descs_dma_addr +
+ offsetof(struct ftgmac100_descs, rxdes));
+ ftgmac100_set_normal_prio_tx_ring_base(priv,
+ priv->descs_dma_addr +
+ offsetof(struct ftgmac100_descs, txdes));
+
+ ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);
+
+ iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);
+
+ ftgmac100_set_mac(priv, priv->netdev->dev_addr);
+}
+
+#define MACCR_ENABLE_ALL (FTGMAC100_MACCR_TXDMA_EN | \
+ FTGMAC100_MACCR_RXDMA_EN | \
+ FTGMAC100_MACCR_TXMAC_EN | \
+ FTGMAC100_MACCR_RXMAC_EN | \
+ FTGMAC100_MACCR_FULLDUP | \
+ FTGMAC100_MACCR_CRC_APD | \
+ FTGMAC100_MACCR_RX_RUNT | \
+ FTGMAC100_MACCR_RX_BROADPKT)
+
+static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed)
+{
+ int maccr = MACCR_ENABLE_ALL;
+
+ switch (speed) {
+ default:
+ case 10:
+ break;
+
+ case 100:
+ maccr |= FTGMAC100_MACCR_FAST_MODE;
+ break;
+
+ case 1000:
+ maccr |= FTGMAC100_MACCR_GIGA_MODE;
+ break;
+ }
+
+ iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
+}
+
+static void ftgmac100_stop_hw(struct ftgmac100 *priv)
+{
+ iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
+}
+
+/******************************************************************************
+ * internal functions (receive descriptor)
+ *****************************************************************************/
+static bool ftgmac100_rxdes_first_segment(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FRS);
+}
+
+static bool ftgmac100_rxdes_last_segment(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_LRS);
+}
+
+static bool ftgmac100_rxdes_packet_ready(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY);
+}
+
+static void ftgmac100_rxdes_set_dma_own(struct ftgmac100_rxdes *rxdes)
+{
+ /* clear status bits */
+ rxdes->rxdes0 &= cpu_to_le32(FTGMAC100_RXDES0_EDORR);
+}
+
+static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
+}
+
+static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
+}
+
+static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FTL);
+}
+
+static bool ftgmac100_rxdes_runt(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RUNT);
+}
+
+static bool ftgmac100_rxdes_odd_nibble(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ODD_NB);
+}
+
+static unsigned int ftgmac100_rxdes_data_length(struct ftgmac100_rxdes *rxdes)
+{
+ return le32_to_cpu(rxdes->rxdes0) & FTGMAC100_RXDES0_VDBC;
+}
+
+static bool ftgmac100_rxdes_multicast(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_MULTICAST);
+}
+
+static void ftgmac100_rxdes_set_end_of_ring(struct ftgmac100_rxdes *rxdes)
+{
+ rxdes->rxdes0 |= cpu_to_le32(FTGMAC100_RXDES0_EDORR);
+}
+
+static void ftgmac100_rxdes_set_dma_addr(struct ftgmac100_rxdes *rxdes,
+ dma_addr_t addr)
+{
+ rxdes->rxdes3 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftgmac100_rxdes_get_dma_addr(struct ftgmac100_rxdes *rxdes)
+{
+ return le32_to_cpu(rxdes->rxdes3);
+}
+
+static bool ftgmac100_rxdes_is_tcp(struct ftgmac100_rxdes *rxdes)
+{
+ return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
+ cpu_to_le32(FTGMAC100_RXDES1_PROT_TCPIP);
+}
+
+static bool ftgmac100_rxdes_is_udp(struct ftgmac100_rxdes *rxdes)
+{
+ return (rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_PROT_MASK)) ==
+ cpu_to_le32(FTGMAC100_RXDES1_PROT_UDPIP);
+}
+
+static bool ftgmac100_rxdes_tcpcs_err(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_TCP_CHKSUM_ERR);
+}
+
+static bool ftgmac100_rxdes_udpcs_err(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_UDP_CHKSUM_ERR);
+}
+
+static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes)
+{
+ return rxdes->rxdes1 & cpu_to_le32(FTGMAC100_RXDES1_IP_CHKSUM_ERR);
+}
+
+/*
+ * rxdes2 is not used by hardware. We use it to keep track of page.
+ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
+ */
+static void ftgmac100_rxdes_set_page(struct ftgmac100_rxdes *rxdes, struct page *page)
+{
+ rxdes->rxdes2 = (unsigned int)page;
+}
+
+static struct page *ftgmac100_rxdes_get_page(struct ftgmac100_rxdes *rxdes)
+{
+ return (struct page *)rxdes->rxdes2;
+}
+
+/******************************************************************************
+ * internal functions (receive)
+ *****************************************************************************/
+static int ftgmac100_next_rx_pointer(int pointer)
+{
+ return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
+}
+
+static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv)
+{
+ priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer);
+}
+
+static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv)
+{
+ return &priv->descs->rxdes[priv->rx_pointer];
+}
+
+static struct ftgmac100_rxdes *
+ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
+{
+ struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
+
+ while (ftgmac100_rxdes_packet_ready(rxdes)) {
+ if (ftgmac100_rxdes_first_segment(rxdes))
+ return rxdes;
+
+ ftgmac100_rxdes_set_dma_own(rxdes);
+ ftgmac100_rx_pointer_advance(priv);
+ rxdes = ftgmac100_current_rxdes(priv);
+ }
+
+ return NULL;
+}
+
+static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv,
+ struct ftgmac100_rxdes *rxdes)
+{
+ struct net_device *netdev = priv->netdev;
+ bool error = false;
+
+ if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx err\n");
+
+ netdev->stats.rx_errors++;
+ error = true;
+ }
+
+ if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx crc err\n");
+
+ netdev->stats.rx_crc_errors++;
+ error = true;
+ } else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx IP checksum err\n");
+
+ error = true;
+ }
+
+ if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx frame too long\n");
+
+ netdev->stats.rx_length_errors++;
+ error = true;
+ } else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx runt\n");
+
+ netdev->stats.rx_length_errors++;
+ error = true;
+ } else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
+ if (net_ratelimit())
+ netdev_info(netdev, "rx odd nibble\n");
+
+ netdev->stats.rx_length_errors++;
+ error = true;
+ }
+
+ return error;
+}
+
+static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
+ bool done = false;
+
+ if (net_ratelimit())
+ netdev_dbg(netdev, "drop packet %p\n", rxdes);
+
+ do {
+ if (ftgmac100_rxdes_last_segment(rxdes))
+ done = true;
+
+ ftgmac100_rxdes_set_dma_own(rxdes);
+ ftgmac100_rx_pointer_advance(priv);
+ rxdes = ftgmac100_current_rxdes(priv);
+ } while (!done && ftgmac100_rxdes_packet_ready(rxdes));
+
+ netdev->stats.rx_dropped++;
+}
+
+static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
+{
+ struct net_device *netdev = priv->netdev;
+ struct ftgmac100_rxdes *rxdes;
+ struct sk_buff *skb;
+ bool done = false;
+
+ rxdes = ftgmac100_rx_locate_first_segment(priv);
+ if (!rxdes)
+ return false;
+
+ if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) {
+ ftgmac100_rx_drop_packet(priv);
+ return true;
+ }
+
+ /* start processing */
+ skb = netdev_alloc_skb_ip_align(netdev, 128);
+ if (unlikely(!skb)) {
+ if (net_ratelimit())
+ netdev_err(netdev, "rx skb alloc failed\n");
+
+ ftgmac100_rx_drop_packet(priv);
+ return true;
+ }
+
+ if (unlikely(ftgmac100_rxdes_multicast(rxdes)))
+ netdev->stats.multicast++;
+
+ /*
+ * It seems that HW does checksum incorrectly with fragmented packets,
+ * so we are conservative here - if HW checksum error, let software do
+ * the checksum again.
+ */
+ if ((ftgmac100_rxdes_is_tcp(rxdes) && !ftgmac100_rxdes_tcpcs_err(rxdes)) ||
+ (ftgmac100_rxdes_is_udp(rxdes) && !ftgmac100_rxdes_udpcs_err(rxdes)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ do {
+ dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
+ struct page *page = ftgmac100_rxdes_get_page(rxdes);
+ unsigned int size;
+
+ dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+ size = ftgmac100_rxdes_data_length(rxdes);
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
+
+ skb->len += size;
+ skb->data_len += size;
+ skb->truesize += size;
+
+ if (ftgmac100_rxdes_last_segment(rxdes))
+ done = true;
+
+ ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
+
+ ftgmac100_rx_pointer_advance(priv);
+ rxdes = ftgmac100_current_rxdes(priv);
+ } while (!done);
+
+ __pskb_pull_tail(skb, min(skb->len, 64U));
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += skb->len;
+
+ /* push packet to protocol stack */
+ napi_gro_receive(&priv->napi, skb);
+
+ (*processed)++;
+ return true;
+}
+
+/******************************************************************************
+ * internal functions (transmit descriptor)
+ *****************************************************************************/
+static void ftgmac100_txdes_reset(struct ftgmac100_txdes *txdes)
+{
+ /* clear all except end of ring bit */
+ txdes->txdes0 &= cpu_to_le32(FTGMAC100_TXDES0_EDOTR);
+ txdes->txdes1 = 0;
+ txdes->txdes2 = 0;
+ txdes->txdes3 = 0;
+}
+
+static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
+{
+ return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
+}
+
+static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
+{
+ /*
+ * Make sure dma own bit will not be set before any other
+ * descriptor fields.
+ */
+ wmb();
+ txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
+}
+
+static void ftgmac100_txdes_set_end_of_ring(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_EDOTR);
+}
+
+static void ftgmac100_txdes_set_first_segment(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_FTS);
+}
+
+static void ftgmac100_txdes_set_last_segment(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_LTS);
+}
+
+static void ftgmac100_txdes_set_buffer_size(struct ftgmac100_txdes *txdes,
+ unsigned int len)
+{
+ txdes->txdes0 |= cpu_to_le32(FTGMAC100_TXDES0_TXBUF_SIZE(len));
+}
+
+static void ftgmac100_txdes_set_txint(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TXIC);
+}
+
+static void ftgmac100_txdes_set_tcpcs(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_TCP_CHKSUM);
+}
+
+static void ftgmac100_txdes_set_udpcs(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_UDP_CHKSUM);
+}
+
+static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
+{
+ txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
+}
+
+static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
+ dma_addr_t addr)
+{
+ txdes->txdes3 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftgmac100_txdes_get_dma_addr(struct ftgmac100_txdes *txdes)
+{
+ return le32_to_cpu(txdes->txdes3);
+}
+
+/*
+ * txdes2 is not used by hardware. We use it to keep track of socket buffer.
+ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
+ */
+static void ftgmac100_txdes_set_skb(struct ftgmac100_txdes *txdes,
+ struct sk_buff *skb)
+{
+ txdes->txdes2 = (unsigned int)skb;
+}
+
+static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes)
+{
+ return (struct sk_buff *)txdes->txdes2;
+}
+
+/******************************************************************************
+ * internal functions (transmit)
+ *****************************************************************************/
+static int ftgmac100_next_tx_pointer(int pointer)
+{
+ return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
+}
+
+static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv)
+{
+ priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer);
+}
+
+static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv)
+{
+ priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer);
+}
+
+static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv)
+{
+ return &priv->descs->txdes[priv->tx_pointer];
+}
+
+static struct ftgmac100_txdes *
+ftgmac100_current_clean_txdes(struct ftgmac100 *priv)
+{
+ return &priv->descs->txdes[priv->tx_clean_pointer];
+}
+
+static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ struct ftgmac100_txdes *txdes;
+ struct sk_buff *skb;
+ dma_addr_t map;
+
+ if (priv->tx_pending == 0)
+ return false;
+
+ txdes = ftgmac100_current_clean_txdes(priv);
+
+ if (ftgmac100_txdes_owned_by_dma(txdes))
+ return false;
+
+ skb = ftgmac100_txdes_get_skb(txdes);
+ map = ftgmac100_txdes_get_dma_addr(txdes);
+
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
+
+ dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+
+ dev_kfree_skb(skb);
+
+ ftgmac100_txdes_reset(txdes);
+
+ ftgmac100_tx_clean_pointer_advance(priv);
+
+ spin_lock(&priv->tx_lock);
+ priv->tx_pending--;
+ spin_unlock(&priv->tx_lock);
+ netif_wake_queue(netdev);
+
+ return true;
+}
+
+static void ftgmac100_tx_complete(struct ftgmac100 *priv)
+{
+ while (ftgmac100_tx_complete_packet(priv))
+ ;
+}
+
+static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
+ dma_addr_t map)
+{
+ struct net_device *netdev = priv->netdev;
+ struct ftgmac100_txdes *txdes;
+ unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+
+ txdes = ftgmac100_current_txdes(priv);
+ ftgmac100_tx_pointer_advance(priv);
+
+ /* setup TX descriptor */
+ ftgmac100_txdes_set_skb(txdes, skb);
+ ftgmac100_txdes_set_dma_addr(txdes, map);
+ ftgmac100_txdes_set_buffer_size(txdes, len);
+
+ ftgmac100_txdes_set_first_segment(txdes);
+ ftgmac100_txdes_set_last_segment(txdes);
+ ftgmac100_txdes_set_txint(txdes);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ __be16 protocol = skb->protocol;
+
+ if (protocol == cpu_to_be16(ETH_P_IP)) {
+ u8 ip_proto = ip_hdr(skb)->protocol;
+
+ ftgmac100_txdes_set_ipcs(txdes);
+ if (ip_proto == IPPROTO_TCP)
+ ftgmac100_txdes_set_tcpcs(txdes);
+ else if (ip_proto == IPPROTO_UDP)
+ ftgmac100_txdes_set_udpcs(txdes);
+ }
+ }
+
+ spin_lock(&priv->tx_lock);
+ priv->tx_pending++;
+ if (priv->tx_pending == TX_QUEUE_ENTRIES)
+ netif_stop_queue(netdev);
+
+ /* start transmit */
+ ftgmac100_txdes_set_dma_own(txdes);
+ spin_unlock(&priv->tx_lock);
+
+ ftgmac100_txdma_normal_prio_start_polling(priv);
+
+ return NETDEV_TX_OK;
+}
+
+/******************************************************************************
+ * internal functions (buffer)
+ *****************************************************************************/
+static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
+ struct ftgmac100_rxdes *rxdes, gfp_t gfp)
+{
+ struct net_device *netdev = priv->netdev;
+ struct page *page;
+ dma_addr_t map;
+
+ page = alloc_page(gfp);
+ if (!page) {
+ if (net_ratelimit())
+ netdev_err(netdev, "failed to allocate rx page\n");
+ return -ENOMEM;
+ }
+
+ map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(priv->dev, map))) {
+ if (net_ratelimit())
+ netdev_err(netdev, "failed to map rx page\n");
+ __free_page(page);
+ return -ENOMEM;
+ }
+
+ ftgmac100_rxdes_set_page(rxdes, page);
+ ftgmac100_rxdes_set_dma_addr(rxdes, map);
+ ftgmac100_rxdes_set_dma_own(rxdes);
+ return 0;
+}
+
+static void ftgmac100_free_buffers(struct ftgmac100 *priv)
+{
+ int i;
+
+ for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+ struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+ struct page *page = ftgmac100_rxdes_get_page(rxdes);
+ dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
+
+ if (!page)
+ continue;
+
+ dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+ __free_page(page);
+ }
+
+ for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
+ struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
+ struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
+ dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
+
+ if (!skb)
+ continue;
+
+ dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+ dev_kfree_skb(skb);
+ }
+
+ dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
+ priv->descs, priv->descs_dma_addr);
+}
+
+static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
+{
+ int i;
+
+ priv->descs = dma_alloc_coherent(priv->dev,
+ sizeof(struct ftgmac100_descs),
+ &priv->descs_dma_addr, GFP_KERNEL);
+ if (!priv->descs)
+ return -ENOMEM;
+
+ memset(priv->descs, 0, sizeof(struct ftgmac100_descs));
+
+ /* initialize RX ring */
+ ftgmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+
+ for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+ struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+
+ if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
+ goto err;
+ }
+
+ /* initialize TX ring */
+ ftgmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
+ return 0;
+
+err:
+ ftgmac100_free_buffers(priv);
+ return -ENOMEM;
+}
+
+/******************************************************************************
+ * internal functions (mdio)
+ *****************************************************************************/
+static void ftgmac100_adjust_link(struct net_device *netdev)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+ struct phy_device *phydev = priv->phydev;
+ int ier;
+
+ if (phydev->speed == priv->old_speed)
+ return;
+
+ priv->old_speed = phydev->speed;
+
+ ier = ioread32(priv->base + FTGMAC100_OFFSET_IER);
+
+ /* disable all interrupts */
+ iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+
+ netif_stop_queue(netdev);
+ ftgmac100_stop_hw(priv);
+
+ netif_start_queue(netdev);
+ ftgmac100_init_hw(priv);
+ ftgmac100_start_hw(priv, phydev->speed);
+
+ /* re-enable interrupts */
+ iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER);
+}
+
+static int ftgmac100_mii_probe(struct ftgmac100 *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ struct phy_device *phydev = NULL;
+ int i;
+
+ /* search for connect PHY device */
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *tmp = priv->mii_bus->phy_map[i];
+
+ if (tmp) {
+ phydev = tmp;
+ break;
+ }
+ }
+
+ /* now we are supposed to have a proper phydev, to attach to... */
+ if (!phydev) {
+ netdev_info(netdev, "%s: no PHY found\n", netdev->name);
+ return -ENODEV;
+ }
+
+ phydev = phy_connect(netdev, dev_name(&phydev->dev),
+ &ftgmac100_adjust_link, 0,
+ PHY_INTERFACE_MODE_GMII);
+
+ if (IS_ERR(phydev)) {
+ netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
+ return PTR_ERR(phydev);
+ }
+
+ priv->phydev = phydev;
+ return 0;
+}
+
+/******************************************************************************
+ * struct mii_bus functions
+ *****************************************************************************/
+static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+ struct net_device *netdev = bus->priv;
+ struct ftgmac100 *priv = netdev_priv(netdev);
+ unsigned int phycr;
+ int i;
+
+ phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ /* preserve MDC cycle threshold */
+ phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
+
+ phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
+ FTGMAC100_PHYCR_REGAD(regnum) |
+ FTGMAC100_PHYCR_MIIRD;
+
+ iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ for (i = 0; i < 10; i++) {
+ phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
+ int data;
+
+ data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
+ return FTGMAC100_PHYDATA_MIIRDATA(data);
+ }
+
+ udelay(100);
+ }
+
+ netdev_err(netdev, "mdio read timed out\n");
+ return -EIO;
+}
+
+static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ int regnum, u16 value)
+{
+ struct net_device *netdev = bus->priv;
+ struct ftgmac100 *priv = netdev_priv(netdev);
+ unsigned int phycr;
+ int data;
+ int i;
+
+ phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ /* preserve MDC cycle threshold */
+ phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
+
+ phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
+ FTGMAC100_PHYCR_REGAD(regnum) |
+ FTGMAC100_PHYCR_MIIWR;
+
+ data = FTGMAC100_PHYDATA_MIIWDATA(value);
+
+ iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
+ iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ for (i = 0; i < 10; i++) {
+ phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+
+ if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
+ return 0;
+
+ udelay(100);
+ }
+
+ netdev_err(netdev, "mdio write timed out\n");
+ return -EIO;
+}
+
+static int ftgmac100_mdiobus_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+/******************************************************************************
+ * struct ethtool_ops functions
+ *****************************************************************************/
+static void ftgmac100_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, dev_name(&netdev->dev));
+}
+
+static int ftgmac100_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int ftgmac100_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *cmd)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static const struct ethtool_ops ftgmac100_ethtool_ops = {
+ .set_settings = ftgmac100_set_settings,
+ .get_settings = ftgmac100_get_settings,
+ .get_drvinfo = ftgmac100_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+
+/******************************************************************************
+ * interrupt handler
+ *****************************************************************************/
+static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
+{
+ struct net_device *netdev = dev_id;
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ if (likely(netif_running(netdev))) {
+ /* Disable interrupts for polling */
+ iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+ napi_schedule(&priv->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/******************************************************************************
+ * struct napi_struct functions
+ *****************************************************************************/
+static int ftgmac100_poll(struct napi_struct *napi, int budget)
+{
+ struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
+ struct net_device *netdev = priv->netdev;
+ unsigned int status;
+ bool completed = true;
+ int rx = 0;
+
+ status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
+ iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
+
+ if (status & (FTGMAC100_INT_RPKT_BUF | FTGMAC100_INT_NO_RXBUF)) {
+ /*
+ * FTGMAC100_INT_RPKT_BUF:
+ * RX DMA has received packets into RX buffer successfully
+ *
+ * FTGMAC100_INT_NO_RXBUF:
+ * RX buffer unavailable
+ */
+ bool retry;
+
+ do {
+ retry = ftgmac100_rx_packet(priv, &rx);
+ } while (retry && rx < budget);
+
+ if (retry && rx == budget)
+ completed = false;
+ }
+
+ if (status & (FTGMAC100_INT_XPKT_ETH | FTGMAC100_INT_XPKT_LOST)) {
+ /*
+ * FTGMAC100_INT_XPKT_ETH:
+ * packet transmitted to ethernet successfully
+ *
+ * FTGMAC100_INT_XPKT_LOST:
+ * packet transmitted to ethernet lost due to late
+ * collision or excessive collision
+ */
+ ftgmac100_tx_complete(priv);
+ }
+
+ if (status & (FTGMAC100_INT_NO_RXBUF | FTGMAC100_INT_RPKT_LOST |
+ FTGMAC100_INT_AHB_ERR | FTGMAC100_INT_PHYSTS_CHG)) {
+ if (net_ratelimit())
+ netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
+ status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "",
+ status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
+ status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
+ status & FTGMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
+
+ if (status & FTGMAC100_INT_NO_RXBUF) {
+ /* RX buffer unavailable */
+ netdev->stats.rx_over_errors++;
+ }
+
+ if (status & FTGMAC100_INT_RPKT_LOST) {
+ /* received packet lost due to RX FIFO full */
+ netdev->stats.rx_fifo_errors++;
+ }
+ }
+
+ if (completed) {
+ napi_complete(napi);
+
+ /* enable all interrupts */
+ iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC100_OFFSET_IER);
+ }
+
+ return rx;
+}
+
+/******************************************************************************
+ * struct net_device_ops functions
+ *****************************************************************************/
+static int ftgmac100_open(struct net_device *netdev)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+ int err;
+
+ err = ftgmac100_alloc_buffers(priv);
+ if (err) {
+ netdev_err(netdev, "failed to allocate buffers\n");
+ goto err_alloc;
+ }
+
+ err = request_irq(priv->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
+ if (err) {
+ netdev_err(netdev, "failed to request irq %d\n", priv->irq);
+ goto err_irq;
+ }
+
+ priv->rx_pointer = 0;
+ priv->tx_clean_pointer = 0;
+ priv->tx_pointer = 0;
+ priv->tx_pending = 0;
+
+ err = ftgmac100_reset_hw(priv);
+ if (err)
+ goto err_hw;
+
+ ftgmac100_init_hw(priv);
+ ftgmac100_start_hw(priv, 10);
+
+ phy_start(priv->phydev);
+
+ napi_enable(&priv->napi);
+ netif_start_queue(netdev);
+
+ /* enable all interrupts */
+ iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC100_OFFSET_IER);
+ return 0;
+
+err_hw:
+ free_irq(priv->irq, netdev);
+err_irq:
+ ftgmac100_free_buffers(priv);
+err_alloc:
+ return err;
+}
+
+static int ftgmac100_stop(struct net_device *netdev)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ /* disable all interrupts */
+ iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+
+ netif_stop_queue(netdev);
+ napi_disable(&priv->napi);
+ phy_stop(priv->phydev);
+
+ ftgmac100_stop_hw(priv);
+ free_irq(priv->irq, netdev);
+ ftgmac100_free_buffers(priv);
+
+ return 0;
+}
+
+static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+ dma_addr_t map;
+
+ if (unlikely(skb->len > MAX_PKT_SIZE)) {
+ if (net_ratelimit())
+ netdev_dbg(netdev, "tx packet too big\n");
+
+ netdev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(priv->dev, map))) {
+ /* drop packet */
+ if (net_ratelimit())
+ netdev_err(netdev, "map socket buffer failed\n");
+
+ netdev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ return ftgmac100_xmit(priv, skb, map);
+}
+
+/* optional */
+static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct ftgmac100 *priv = netdev_priv(netdev);
+
+ return phy_mii_ioctl(priv->phydev, ifr, cmd);
+}
+
+static const struct net_device_ops ftgmac100_netdev_ops = {
+ .ndo_open = ftgmac100_open,
+ .ndo_stop = ftgmac100_stop,
+ .ndo_start_xmit = ftgmac100_hard_start_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = ftgmac100_do_ioctl,
+};
+
+/******************************************************************************
+ * struct platform_driver functions
+ *****************************************************************************/
+static int ftgmac100_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int irq;
+ struct net_device *netdev;
+ struct ftgmac100 *priv;
+ int err;
+ int i;
+
+ if (!pdev)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* setup net_device */
+ netdev = alloc_etherdev(sizeof(*priv));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ SET_ETHTOOL_OPS(netdev, &ftgmac100_ethtool_ops);
+ netdev->netdev_ops = &ftgmac100_netdev_ops;
+ netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO;
+
+ platform_set_drvdata(pdev, netdev);
+
+ /* setup private data */
+ priv = netdev_priv(netdev);
+ priv->netdev = netdev;
+ priv->dev = &pdev->dev;
+
+ spin_lock_init(&priv->tx_lock);
+
+ /* initialize NAPI */
+ netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
+
+ /* map io memory */
+ priv->res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!priv->res) {
+ dev_err(&pdev->dev, "Could not reserve memory region\n");
+ err = -ENOMEM;
+ goto err_req_mem;
+ }
+
+ priv->base = ioremap(res->start, resource_size(res));
+ if (!priv->base) {
+ dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
+ err = -EIO;
+ goto err_ioremap;
+ }
+
+ priv->irq = irq;
+
+ /* initialize mdio bus */
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ err = -EIO;
+ goto err_alloc_mdiobus;
+ }
+
+ priv->mii_bus->name = "ftgmac100_mdio";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "ftgmac100_mii");
+
+ priv->mii_bus->priv = netdev;
+ priv->mii_bus->read = ftgmac100_mdiobus_read;
+ priv->mii_bus->write = ftgmac100_mdiobus_write;
+ priv->mii_bus->reset = ftgmac100_mdiobus_reset;
+ priv->mii_bus->irq = priv->phy_irq;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ priv->mii_bus->irq[i] = PHY_POLL;
+
+ err = mdiobus_register(priv->mii_bus);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+ goto err_register_mdiobus;
+ }
+
+ err = ftgmac100_mii_probe(priv);
+ if (err) {
+ dev_err(&pdev->dev, "MII Probe failed!\n");
+ goto err_mii_probe;
+ }
+
+ /* register network device */
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register netdev\n");
+ goto err_register_netdev;
+ }
+
+ netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ random_ether_addr(netdev->dev_addr);
+ netdev_info(netdev, "generated random MAC address %pM\n",
+ netdev->dev_addr);
+ }
+
+ return 0;
+
+err_register_netdev:
+ phy_disconnect(priv->phydev);
+err_mii_probe:
+ mdiobus_unregister(priv->mii_bus);
+err_register_mdiobus:
+ mdiobus_free(priv->mii_bus);
+err_alloc_mdiobus:
+ iounmap(priv->base);
+err_ioremap:
+ release_resource(priv->res);
+err_req_mem:
+ netif_napi_del(&priv->napi);
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+err_alloc_etherdev:
+ return err;
+}
+
+static int __exit ftgmac100_remove(struct platform_device *pdev)
+{
+ struct net_device *netdev;
+ struct ftgmac100 *priv;
+
+ netdev = platform_get_drvdata(pdev);
+ priv = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mii_bus);
+ mdiobus_free(priv->mii_bus);
+
+ iounmap(priv->base);
+ release_resource(priv->res);
+
+ netif_napi_del(&priv->napi);
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+ return 0;
+}
+
+static struct platform_driver ftgmac100_driver = {
+ .probe = ftgmac100_probe,
+ .remove = __exit_p(ftgmac100_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/******************************************************************************
+ * initialization / finalization
+ *****************************************************************************/
+static int __init ftgmac100_init(void)
+{
+ pr_info("Loading version " DRV_VERSION " ...\n");
+ return platform_driver_register(&ftgmac100_driver);
+}
+
+static void __exit ftgmac100_exit(void)
+{
+ platform_driver_unregister(&ftgmac100_driver);
+}
+
+module_init(ftgmac100_init);
+module_exit(ftgmac100_exit);
+
+MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
+MODULE_DESCRIPTION("FTGMAC100 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ftgmac100.h b/drivers/net/ftgmac100.h
new file mode 100644
index 0000000..13408d4
--- /dev/null
+++ b/drivers/net/ftgmac100.h
@@ -0,0 +1,246 @@
+/*
+ * Faraday FTGMAC100 Gigabit Ethernet
+ *
+ * (C) Copyright 2009-2011 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FTGMAC100_H
+#define __FTGMAC100_H
+
+#define FTGMAC100_OFFSET_ISR 0x00
+#define FTGMAC100_OFFSET_IER 0x04
+#define FTGMAC100_OFFSET_MAC_MADR 0x08
+#define FTGMAC100_OFFSET_MAC_LADR 0x0c
+#define FTGMAC100_OFFSET_MAHT0 0x10
+#define FTGMAC100_OFFSET_MAHT1 0x14
+#define FTGMAC100_OFFSET_NPTXPD 0x18
+#define FTGMAC100_OFFSET_RXPD 0x1c
+#define FTGMAC100_OFFSET_NPTXR_BADR 0x20
+#define FTGMAC100_OFFSET_RXR_BADR 0x24
+#define FTGMAC100_OFFSET_HPTXPD 0x28
+#define FTGMAC100_OFFSET_HPTXR_BADR 0x2c
+#define FTGMAC100_OFFSET_ITC 0x30
+#define FTGMAC100_OFFSET_APTC 0x34
+#define FTGMAC100_OFFSET_DBLAC 0x38
+#define FTGMAC100_OFFSET_DMAFIFOS 0x3c
+#define FTGMAC100_OFFSET_REVR 0x40
+#define FTGMAC100_OFFSET_FEAR 0x44
+#define FTGMAC100_OFFSET_TPAFCR 0x48
+#define FTGMAC100_OFFSET_RBSR 0x4c
+#define FTGMAC100_OFFSET_MACCR 0x50
+#define FTGMAC100_OFFSET_MACSR 0x54
+#define FTGMAC100_OFFSET_TM 0x58
+#define FTGMAC100_OFFSET_PHYCR 0x60
+#define FTGMAC100_OFFSET_PHYDATA 0x64
+#define FTGMAC100_OFFSET_FCR 0x68
+#define FTGMAC100_OFFSET_BPR 0x6c
+#define FTGMAC100_OFFSET_WOLCR 0x70
+#define FTGMAC100_OFFSET_WOLSR 0x74
+#define FTGMAC100_OFFSET_WFCRC 0x78
+#define FTGMAC100_OFFSET_WFBM1 0x80
+#define FTGMAC100_OFFSET_WFBM2 0x84
+#define FTGMAC100_OFFSET_WFBM3 0x88
+#define FTGMAC100_OFFSET_WFBM4 0x8c
+#define FTGMAC100_OFFSET_NPTXR_PTR 0x90
+#define FTGMAC100_OFFSET_HPTXR_PTR 0x94
+#define FTGMAC100_OFFSET_RXR_PTR 0x98
+#define FTGMAC100_OFFSET_TX 0xa0
+#define FTGMAC100_OFFSET_TX_MCOL_SCOL 0xa4
+#define FTGMAC100_OFFSET_TX_ECOL_FAIL 0xa8
+#define FTGMAC100_OFFSET_TX_LCOL_UND 0xac
+#define FTGMAC100_OFFSET_RX 0xb0
+#define FTGMAC100_OFFSET_RX_BC 0xb4
+#define FTGMAC100_OFFSET_RX_MC 0xb8
+#define FTGMAC100_OFFSET_RX_PF_AEP 0xbc
+#define FTGMAC100_OFFSET_RX_RUNT 0xc0
+#define FTGMAC100_OFFSET_RX_CRCER_FTL 0xc4
+#define FTGMAC100_OFFSET_RX_COL_LOST 0xc8
+
+/*
+ * Interrupt status register & interrupt enable register
+ */
+#define FTGMAC100_INT_RPKT_BUF (1 << 0)
+#define FTGMAC100_INT_RPKT_FIFO (1 << 1)
+#define FTGMAC100_INT_NO_RXBUF (1 << 2)
+#define FTGMAC100_INT_RPKT_LOST (1 << 3)
+#define FTGMAC100_INT_XPKT_ETH (1 << 4)
+#define FTGMAC100_INT_XPKT_FIFO (1 << 5)
+#define FTGMAC100_INT_NO_NPTXBUF (1 << 6)
+#define FTGMAC100_INT_XPKT_LOST (1 << 7)
+#define FTGMAC100_INT_AHB_ERR (1 << 8)
+#define FTGMAC100_INT_PHYSTS_CHG (1 << 9)
+#define FTGMAC100_INT_NO_HPTXBUF (1 << 10)
+
+/*
+ * Interrupt timer control register
+ */
+#define FTGMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0)
+#define FTGMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4)
+#define FTGMAC100_ITC_RXINT_TIME_SEL (1 << 7)
+#define FTGMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8)
+#define FTGMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12)
+#define FTGMAC100_ITC_TXINT_TIME_SEL (1 << 15)
+
+/*
+ * Automatic polling timer control register
+ */
+#define FTGMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0)
+#define FTGMAC100_APTC_RXPOLL_TIME_SEL (1 << 4)
+#define FTGMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8)
+#define FTGMAC100_APTC_TXPOLL_TIME_SEL (1 << 12)
+
+/*
+ * DMA burst length and arbitration control register
+ */
+#define FTGMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 0)
+#define FTGMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 3)
+#define FTGMAC100_DBLAC_RX_THR_EN (1 << 6)
+#define FTGMAC100_DBLAC_RXBURST_SIZE(x) (((x) & 0x3) << 8)
+#define FTGMAC100_DBLAC_TXBURST_SIZE(x) (((x) & 0x3) << 10)
+#define FTGMAC100_DBLAC_RXDES_SIZE(x) (((x) & 0xf) << 12)
+#define FTGMAC100_DBLAC_TXDES_SIZE(x) (((x) & 0xf) << 16)
+#define FTGMAC100_DBLAC_IFG_CNT(x) (((x) & 0x7) << 20)
+#define FTGMAC100_DBLAC_IFG_INC (1 << 23)
+
+/*
+ * DMA FIFO status register
+ */
+#define FTGMAC100_DMAFIFOS_RXDMA1_SM(dmafifos) ((dmafifos) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXDMA2_SM(dmafifos) (((dmafifos) >> 4) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXDMA3_SM(dmafifos) (((dmafifos) >> 8) & 0x7)
+#define FTGMAC100_DMAFIFOS_TXDMA1_SM(dmafifos) (((dmafifos) >> 12) & 0xf)
+#define FTGMAC100_DMAFIFOS_TXDMA2_SM(dmafifos) (((dmafifos) >> 16) & 0x3)
+#define FTGMAC100_DMAFIFOS_TXDMA3_SM(dmafifos) (((dmafifos) >> 18) & 0xf)
+#define FTGMAC100_DMAFIFOS_RXFIFO_EMPTY (1 << 26)
+#define FTGMAC100_DMAFIFOS_TXFIFO_EMPTY (1 << 27)
+#define FTGMAC100_DMAFIFOS_RXDMA_GRANT (1 << 28)
+#define FTGMAC100_DMAFIFOS_TXDMA_GRANT (1 << 29)
+#define FTGMAC100_DMAFIFOS_RXDMA_REQ (1 << 30)
+#define FTGMAC100_DMAFIFOS_TXDMA_REQ (1 << 31)
+
+/*
+ * Receive buffer size register
+ */
+#define FTGMAC100_RBSR_SIZE(x) ((x) & 0x3fff)
+
+/*
+ * MAC control register
+ */
+#define FTGMAC100_MACCR_TXDMA_EN (1 << 0)
+#define FTGMAC100_MACCR_RXDMA_EN (1 << 1)
+#define FTGMAC100_MACCR_TXMAC_EN (1 << 2)
+#define FTGMAC100_MACCR_RXMAC_EN (1 << 3)
+#define FTGMAC100_MACCR_RM_VLAN (1 << 4)
+#define FTGMAC100_MACCR_HPTXR_EN (1 << 5)
+#define FTGMAC100_MACCR_LOOP_EN (1 << 6)
+#define FTGMAC100_MACCR_ENRX_IN_HALFTX (1 << 7)
+#define FTGMAC100_MACCR_FULLDUP (1 << 8)
+#define FTGMAC100_MACCR_GIGA_MODE (1 << 9)
+#define FTGMAC100_MACCR_CRC_APD (1 << 10)
+#define FTGMAC100_MACCR_RX_RUNT (1 << 12)
+#define FTGMAC100_MACCR_JUMBO_LF (1 << 13)
+#define FTGMAC100_MACCR_RX_ALL (1 << 14)
+#define FTGMAC100_MACCR_HT_MULTI_EN (1 << 15)
+#define FTGMAC100_MACCR_RX_MULTIPKT (1 << 16)
+#define FTGMAC100_MACCR_RX_BROADPKT (1 << 17)
+#define FTGMAC100_MACCR_DISCARD_CRCERR (1 << 18)
+#define FTGMAC100_MACCR_FAST_MODE (1 << 19)
+#define FTGMAC100_MACCR_SW_RST (1 << 31)
+
+/*
+ * PHY control register
+ */
+#define FTGMAC100_PHYCR_MDC_CYCTHR_MASK 0x3f
+#define FTGMAC100_PHYCR_MDC_CYCTHR(x) ((x) & 0x3f)
+#define FTGMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16)
+#define FTGMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21)
+#define FTGMAC100_PHYCR_MIIRD (1 << 26)
+#define FTGMAC100_PHYCR_MIIWR (1 << 27)
+
+/*
+ * PHY data register
+ */
+#define FTGMAC100_PHYDATA_MIIWDATA(x) ((x) & 0xffff)
+#define FTGMAC100_PHYDATA_MIIRDATA(phydata) (((phydata) >> 16) & 0xffff)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftgmac100_txdes {
+ unsigned int txdes0;
+ unsigned int txdes1;
+ unsigned int txdes2; /* not used by HW */
+ unsigned int txdes3; /* TXBUF_BADR */
+} __attribute__ ((aligned(16)));
+
+#define FTGMAC100_TXDES0_TXBUF_SIZE(x) ((x) & 0x3fff)
+#define FTGMAC100_TXDES0_EDOTR (1 << 15)
+#define FTGMAC100_TXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_TXDES0_LTS (1 << 28)
+#define FTGMAC100_TXDES0_FTS (1 << 29)
+#define FTGMAC100_TXDES0_TXDMA_OWN (1 << 31)
+
+#define FTGMAC100_TXDES1_VLANTAG_CI(x) ((x) & 0xffff)
+#define FTGMAC100_TXDES1_INS_VLANTAG (1 << 16)
+#define FTGMAC100_TXDES1_TCP_CHKSUM (1 << 17)
+#define FTGMAC100_TXDES1_UDP_CHKSUM (1 << 18)
+#define FTGMAC100_TXDES1_IP_CHKSUM (1 << 19)
+#define FTGMAC100_TXDES1_LLC (1 << 22)
+#define FTGMAC100_TXDES1_TX2FIC (1 << 30)
+#define FTGMAC100_TXDES1_TXIC (1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftgmac100_rxdes {
+ unsigned int rxdes0;
+ unsigned int rxdes1;
+ unsigned int rxdes2; /* not used by HW */
+ unsigned int rxdes3; /* RXBUF_BADR */
+} __attribute__ ((aligned(16)));
+
+#define FTGMAC100_RXDES0_VDBC 0x3fff
+#define FTGMAC100_RXDES0_EDORR (1 << 15)
+#define FTGMAC100_RXDES0_MULTICAST (1 << 16)
+#define FTGMAC100_RXDES0_BROADCAST (1 << 17)
+#define FTGMAC100_RXDES0_RX_ERR (1 << 18)
+#define FTGMAC100_RXDES0_CRC_ERR (1 << 19)
+#define FTGMAC100_RXDES0_FTL (1 << 20)
+#define FTGMAC100_RXDES0_RUNT (1 << 21)
+#define FTGMAC100_RXDES0_RX_ODD_NB (1 << 22)
+#define FTGMAC100_RXDES0_FIFO_FULL (1 << 23)
+#define FTGMAC100_RXDES0_PAUSE_OPCODE (1 << 24)
+#define FTGMAC100_RXDES0_PAUSE_FRAME (1 << 25)
+#define FTGMAC100_RXDES0_LRS (1 << 28)
+#define FTGMAC100_RXDES0_FRS (1 << 29)
+#define FTGMAC100_RXDES0_RXPKT_RDY (1 << 31)
+
+#define FTGMAC100_RXDES1_VLANTAG_CI 0xffff
+#define FTGMAC100_RXDES1_PROT_MASK (0x3 << 20)
+#define FTGMAC100_RXDES1_PROT_NONIP (0x0 << 20)
+#define FTGMAC100_RXDES1_PROT_IP (0x1 << 20)
+#define FTGMAC100_RXDES1_PROT_TCPIP (0x2 << 20)
+#define FTGMAC100_RXDES1_PROT_UDPIP (0x3 << 20)
+#define FTGMAC100_RXDES1_LLC (1 << 22)
+#define FTGMAC100_RXDES1_DF (1 << 23)
+#define FTGMAC100_RXDES1_VLANTAG_AVAIL (1 << 24)
+#define FTGMAC100_RXDES1_TCP_CHKSUM_ERR (1 << 25)
+#define FTGMAC100_RXDES1_UDP_CHKSUM_ERR (1 << 26)
+#define FTGMAC100_RXDES1_IP_CHKSUM_ERR (1 << 27)
+
+#endif /* __FTGMAC100_H */
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH] net: emaclite: Add missing linux/interrupt.h header
From: Michal Simek @ 2011-06-09 8:56 UTC (permalink / raw)
To: David Miller; +Cc: linux-kernel, netdev
In-Reply-To: <20110609.012944.602872260942727070.davem@davemloft.net>
David Miller wrote:
> From: Michal Simek <monstr@monstr.eu>
> Date: Thu, 9 Jun 2011 10:15:33 +0200
>
>> Log:
>> drivers/net/xilinx_emaclite.c: In function 'xemaclite_open':
>> drivers/net/xilinx_emaclite.c:961: error: implicit declaration of function 'request_irq'
>> drivers/net/xilinx_emaclite.c: In function 'xemaclite_close':
>> drivers/net/xilinx_emaclite.c:995: error: implicit declaration of function 'free_irq'
>> make[2]: *** [drivers/net/xilinx_emaclite.o] Error 1
>> make[1]: *** [drivers/net] Error 2
>> make: *** [drivers] Error 2
>>
>> Signed-off-by: Michal Simek <monstr@monstr.eu>
>
> This is only relevant for the -next tree, you should specify that when
> submitting patches otherwise the maintainer not apply the patch where
> it actually belongs.
sorry for that. Yes, it is for -next tree.
Michal
--
Michal Simek, Ing. (M.Eng)
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel 2.6 Microblaze Linux - http://www.monstr.eu/fdt/
Microblaze U-BOOT custodian
^ permalink raw reply
* Re: [PATCH] net: emaclite: Add missing linux/interrupt.h header
From: David Miller @ 2011-06-09 8:29 UTC (permalink / raw)
To: monstr; +Cc: linux-kernel, netdev
In-Reply-To: <1307607333-24612-1-git-send-email-monstr@monstr.eu>
From: Michal Simek <monstr@monstr.eu>
Date: Thu, 9 Jun 2011 10:15:33 +0200
> Log:
> drivers/net/xilinx_emaclite.c: In function 'xemaclite_open':
> drivers/net/xilinx_emaclite.c:961: error: implicit declaration of function 'request_irq'
> drivers/net/xilinx_emaclite.c: In function 'xemaclite_close':
> drivers/net/xilinx_emaclite.c:995: error: implicit declaration of function 'free_irq'
> make[2]: *** [drivers/net/xilinx_emaclite.o] Error 1
> make[1]: *** [drivers/net] Error 2
> make: *** [drivers] Error 2
>
> Signed-off-by: Michal Simek <monstr@monstr.eu>
This is only relevant for the -next tree, you should specify that when
submitting patches otherwise the maintainer not apply the patch where
it actually belongs.
Applied, thanks.
^ permalink raw reply
* [PATCH] net: emaclite: Add missing linux/interrupt.h header
From: Michal Simek @ 2011-06-09 8:15 UTC (permalink / raw)
To: davem; +Cc: linux-kernel, netdev, Michal Simek
Log:
drivers/net/xilinx_emaclite.c: In function 'xemaclite_open':
drivers/net/xilinx_emaclite.c:961: error: implicit declaration of function 'request_irq'
drivers/net/xilinx_emaclite.c: In function 'xemaclite_close':
drivers/net/xilinx_emaclite.c:995: error: implicit declaration of function 'free_irq'
make[2]: *** [drivers/net/xilinx_emaclite.o] Error 1
make[1]: *** [drivers/net] Error 2
make: *** [drivers] Error 2
Signed-off-by: Michal Simek <monstr@monstr.eu>
---
drivers/net/xilinx_emaclite.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index 372572c..9cb4cdc 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -26,6 +26,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/phy.h>
+#include <linux/interrupt.h>
#define DRIVER_NAME "xilinx_emaclite"
--
1.5.5.6
^ permalink raw reply related
* Re: [net-next 00/12][pull request] Intel Wired LAN Driver Update
From: Jeff Kirsher @ 2011-06-09 8:14 UTC (permalink / raw)
To: David Miller; +Cc: netdev@vger.kernel.org, gospo@redhat.com
In-Reply-To: <20110609.005821.841607202181194646.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 727 bytes --]
On Thu, 2011-06-09 at 00:58 -0700, David Miller wrote:
> From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Date: Thu, 09 Jun 2011 00:53:14 -0700
>
> > Just did, I saw that I did not have enabled and I got the same issue. I
> > am looking into now, and will check to make sure there were no other
> > netlink_dump_start() references missed as well.
>
> Ummm, you're not doing "allmodconfig" builds for validation?
>
> I guarentee you have much more powerful computers than I do and I
> do allmodconfig/allyesconfig builds across the board during my work.
>
> And if you're touching global code, you should too :-)
Looks like after a thorough search, the infiniband instance was the only
instance missed.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: [net-next 00/12][pull request] Intel Wired LAN Driver Update
From: Jeff Kirsher @ 2011-06-09 8:06 UTC (permalink / raw)
To: David Miller; +Cc: netdev@vger.kernel.org, gospo@redhat.com
In-Reply-To: <20110609.005821.841607202181194646.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 983 bytes --]
On Thu, 2011-06-09 at 00:58 -0700, David Miller wrote:
> From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Date: Thu, 09 Jun 2011 00:53:14 -0700
>
> > Just did, I saw that I did not have enabled and I got the same issue. I
> > am looking into now, and will check to make sure there were no other
> > netlink_dump_start() references missed as well.
>
> Ummm, you're not doing "allmodconfig" builds for validation?
>
> I guarentee you have much more powerful computers than I do and I
> do allmodconfig/allyesconfig builds across the board during my work.
>
> And if you're touching global code, you should too :-)
Don't worry, I will be having a talk with validation, because my
understanding was that yes, we were doing allmodconfig compile testing
(along with several other's like allyesconfig and randomconfig). I do a
sanity check compile before sending anything out, but my config just
makes sure that all the Intel LAN drivers (and DCB) are enabled.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* [PATCH 13/14] mm: Throttle direct reclaimers if PF_MEMALLOC reserves are low and swap is backed by network storage
From: Mel Gorman @ 2011-06-09 8:02 UTC (permalink / raw)
To: Andrew Morton
Cc: Linux-MM, Linux-Netdev, LKML, David Miller, Neil Brown,
Peter Zijlstra, Mel Gorman
In-Reply-To: <1307606573-24704-1-git-send-email-mgorman@suse.de>
If swap is backed by network storage such as NBD, there is a risk that a
large number of reclaimers can hang the system by consuming all
PF_MEMALLOC reserves. To avoid these hangs, the administrator must tune
min_free_kbytes in advance. This patch will throttle direct reclaimers
if half the PF_MEMALLOC reserves are in use as the system is at risk of
hanging.
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
include/linux/mmzone.h | 1 +
mm/page_alloc.c | 1 +
mm/vmscan.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index c928dac..5b32906 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -633,6 +633,7 @@ typedef struct pglist_data {
range, including holes */
int node_id;
wait_queue_head_t kswapd_wait;
+ wait_queue_head_t pfmemalloc_wait;
struct task_struct *kswapd;
int kswapd_max_order;
enum zone_type classzone_idx;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ac779f5..00eea0f 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4288,6 +4288,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
pgdat_resize_init(pgdat);
pgdat->nr_zones = 0;
init_waitqueue_head(&pgdat->kswapd_wait);
+ init_waitqueue_head(&pgdat->pfmemalloc_wait);
pgdat->kswapd_max_order = 0;
pgdat_page_cgroup_init(pgdat);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index faa0a08..fe95e4f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2154,6 +2154,45 @@ out:
return 0;
}
+static bool pfmemalloc_watermark_ok(pg_data_t *pgdat, int high_zoneidx)
+{
+ struct zone *zone;
+ unsigned long pfmemalloc_reserve = 0;
+ unsigned long free_pages = 0;
+ int i;
+
+ for (i = 0; i <= high_zoneidx; i++) {
+ zone = &pgdat->node_zones[i];
+ pfmemalloc_reserve += min_wmark_pages(zone);
+ free_pages += zone_page_state(zone, NR_FREE_PAGES);
+ }
+
+ return (free_pages > pfmemalloc_reserve / 2) ? true : false;
+}
+
+/*
+ * Throttle direct reclaimers if backing storage is backed by the network
+ * and the PFMEMALLOC reserve for the preferred node is getting dangerously
+ * depleted. kswapd will continue to make progress and wake the processes
+ * when the low watermark is reached
+ */
+static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
+ nodemask_t *nodemask)
+{
+ struct zone *zone;
+ int high_zoneidx = gfp_zone(gfp_mask);
+ DEFINE_WAIT(wait);
+
+ /* Check if the pfmemalloc reserves are ok */
+ first_zones_zonelist(zonelist, high_zoneidx, NULL, &zone);
+ if (pfmemalloc_watermark_ok(zone->zone_pgdat, high_zoneidx))
+ return;
+
+ /* Throttle */
+ wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
+ pfmemalloc_watermark_ok(zone->zone_pgdat, high_zoneidx));
+}
+
unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
gfp_t gfp_mask, nodemask_t *nodemask)
{
@@ -2173,6 +2212,15 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
.gfp_mask = sc.gfp_mask,
};
+ throttle_direct_reclaim(gfp_mask, zonelist, nodemask);
+
+ /*
+ * Do not enter reclaim if fatal signal is pending. 1 is returned so
+ * that the page allocator does not consider triggering OOM
+ */
+ if (fatal_signal_pending(current))
+ return 1;
+
trace_mm_vmscan_direct_reclaim_begin(order,
sc.may_writepage,
gfp_mask);
@@ -2541,6 +2589,12 @@ loop_again:
}
}
+
+ /* Wake throttled direct reclaimers if low watermark is met */
+ if (waitqueue_active(&pgdat->pfmemalloc_wait) &&
+ pfmemalloc_watermark_ok(pgdat, MAX_NR_ZONES - 1))
+ wake_up_interruptible(&pgdat->pfmemalloc_wait);
+
if (all_zones_ok || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))
break; /* kswapd: all done */
/*
--
1.7.3.4
^ permalink raw reply related
* [PATCH 14/14] mm: Account for the number of times direct reclaimers get throttled
From: Mel Gorman @ 2011-06-09 8:02 UTC (permalink / raw)
To: Andrew Morton
Cc: Linux-MM, Linux-Netdev, LKML, David Miller, Neil Brown,
Peter Zijlstra, Mel Gorman
In-Reply-To: <1307606573-24704-1-git-send-email-mgorman@suse.de>
Under significant pressure when writing back to network-backed storage,
direct reclaimers may get throttled. This is expected to be a
short-lived event and the processes get woken up again but processes do
get stalled. This patch counts how many times such stalling occurs. It's
up to the administrator whether to reduce these stalls by increasing
min_free_kbytes.
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
include/linux/vm_event_item.h | 1 +
mm/vmscan.c | 1 +
mm/vmstat.c | 1 +
3 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h
index 03b90cdc..652e5f3 100644
--- a/include/linux/vm_event_item.h
+++ b/include/linux/vm_event_item.h
@@ -29,6 +29,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
FOR_ALL_ZONES(PGSTEAL),
FOR_ALL_ZONES(PGSCAN_KSWAPD),
FOR_ALL_ZONES(PGSCAN_DIRECT),
+ PGSCAN_DIRECT_THROTTLE,
#ifdef CONFIG_NUMA
PGSCAN_ZONE_RECLAIM_FAILED,
#endif
diff --git a/mm/vmscan.c b/mm/vmscan.c
index fe95e4f..f75a5f2 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2189,6 +2189,7 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
return;
/* Throttle */
+ count_vm_event(PGSCAN_DIRECT_THROTTLE);
wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
pfmemalloc_watermark_ok(zone->zone_pgdat, high_zoneidx));
}
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 20c18b7..0ab4a3d 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -740,6 +740,7 @@ const char * const vmstat_text[] = {
TEXTS_FOR_ZONES("pgsteal")
TEXTS_FOR_ZONES("pgscan_kswapd")
TEXTS_FOR_ZONES("pgscan_direct")
+ "pgscan_direct_throttle",
#ifdef CONFIG_NUMA
"zone_reclaim_failed",
--
1.7.3.4
^ permalink raw reply related
* [PATCH 12/14] nbd: Set SOCK_MEMALLOC for access to PFMEMALLOC reserves
From: Mel Gorman @ 2011-06-09 8:02 UTC (permalink / raw)
To: Andrew Morton
Cc: Linux-MM, Linux-Netdev, LKML, David Miller, Neil Brown,
Peter Zijlstra, Mel Gorman
In-Reply-To: <1307606573-24704-1-git-send-email-mgorman@suse.de>
Set SOCK_MEMALLOC on the NBD socket to allow access to PFMEMALLOC
reserves so pages backed by NBD, particularly if swap related,
can be cleaned to prevent the machine being deadlocked. It is
still possible that the PFMEMALLOC reserves get depleted resulting
in deadlock but this can be resolved by the administrator by
increasing min_free_kbytes.
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
drivers/block/nbd.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index f533f33..ca7cd81 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -156,6 +156,7 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
struct msghdr msg;
struct kvec iov;
sigset_t blocked, oldset;
+ unsigned long pflags = current->flags;
if (unlikely(!sock)) {
printk(KERN_ERR "%s: Attempted %s on closed socket in sock_xmit\n",
@@ -168,8 +169,9 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
siginitsetinv(&blocked, sigmask(SIGKILL));
sigprocmask(SIG_SETMASK, &blocked, &oldset);
+ current->flags |= PF_MEMALLOC;
do {
- sock->sk->sk_allocation = GFP_NOIO;
+ sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC;
iov.iov_base = buf;
iov.iov_len = size;
msg.msg_name = NULL;
@@ -215,6 +217,7 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
} while (size > 0);
sigprocmask(SIG_SETMASK, &oldset, NULL);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
return result;
}
@@ -405,6 +408,8 @@ static int nbd_do_it(struct nbd_device *lo)
BUG_ON(lo->magic != LO_MAGIC);
+ sk_set_memalloc(lo->sock->sk);
+
lo->pid = current->pid;
ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
if (ret) {
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 11/14] mm: Micro-optimise slab to avoid a function call
From: Mel Gorman @ 2011-06-09 8:02 UTC (permalink / raw)
To: Andrew Morton
Cc: Linux-MM, Linux-Netdev, LKML, David Miller, Neil Brown,
Peter Zijlstra, Mel Gorman
In-Reply-To: <1307606573-24704-1-git-send-email-mgorman@suse.de>
Getting and putting objects in SLAB currently requires a function call
but the bulk of the work is related to PFMEMALLOC reserves which are
only consumed when network-backed storage is critical. Use an inline
function to determine if the function call is required.
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
mm/slab.c | 28 ++++++++++++++++++++++++++--
1 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/mm/slab.c b/mm/slab.c
index 708da2f..3f49768 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -117,6 +117,8 @@
#include <linux/memory.h>
#include <linux/prefetch.h>
+#include <net/sock.h>
+
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
@@ -945,7 +947,7 @@ static void check_ac_pfmemalloc(struct kmem_cache *cachep,
ac->pfmemalloc = false;
}
-static void *ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
+static void *__ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
gfp_t flags, bool force_refill)
{
int i;
@@ -992,7 +994,20 @@ static void *ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
return objp;
}
-static void ac_put_obj(struct kmem_cache *cachep, struct array_cache *ac,
+static inline void *ac_get_obj(struct kmem_cache *cachep,
+ struct array_cache *ac, gfp_t flags, bool force_refill)
+{
+ void *objp;
+
+ if (unlikely(sk_memalloc_socks()))
+ objp = __ac_get_obj(cachep, ac, flags, force_refill);
+ else
+ objp = ac->entry[--ac->avail];
+
+ return objp;
+}
+
+static void *__ac_put_obj(struct kmem_cache *cachep, struct array_cache *ac,
void *objp)
{
struct slab *slabp;
@@ -1005,6 +1020,15 @@ static void ac_put_obj(struct kmem_cache *cachep, struct array_cache *ac,
set_obj_pfmemalloc(&objp);
}
+ return objp;
+}
+
+static inline void ac_put_obj(struct kmem_cache *cachep, struct array_cache *ac,
+ void *objp)
+{
+ if (unlikely(sk_memalloc_socks()))
+ objp = __ac_put_obj(cachep, ac, objp);
+
ac->entry[ac->avail++] = objp;
}
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox