Netdev List
 help / color / mirror / Atom feed
* Re: [RFC] ipv6: don't flush routes when setting loopback down
From: David Miller @ 2011-01-23 19:47 UTC (permalink / raw)
  To: shemminger
  Cc: stephen.hemminger, ebiederm, jbohac, brian.haley, netdev,
	maheshkelkar, lorenzo, yoshfuji, stable
In-Reply-To: <20110123192416.73cd7521@s6510>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sun, 23 Jan 2011 19:24:16 +1100

> You are probably so upset because I stepped on code you worked hard
> on.

Frankly, I honestly don't care much at all about ipv6, it's still only
a tiny minuscule fraction of actual usage in this world, even with
ipv4 addresses basically completely depleted right now, and it's also
an over-engineered monster.

> But the IPv6 semantics should not have been different from IPv4
> and the disable_ipv6 flag was a poor API choice as well.

There are no equivalent semantics, because nobody wants to disable
all IPV4 activity and socket protocol operations.  People want it
only for ipv6.

This interface was choosen because this is what users asked for.

They wanted global and per-interface ways to disable IPV6 protocol
activity, so that's what we gave them.

Stephen you don't get it.  The ball is completely in your court
about this, you broke stuff to fix stuff and that's not allowed.

You have also been given months of time to undo the breakage.
Normally I would just immediately revert, so you were given
special allowances because I respect and trust you.

So stop this BS where you say that I'm treating you in an
unfair way.

^ permalink raw reply

* Re: [RFC] ipv6: don't flush routes when setting loopback down
From: David Miller @ 2011-01-23 19:48 UTC (permalink / raw)
  To: shemminger
  Cc: stephen.hemminger, ebiederm, jbohac, brian.haley, netdev,
	maheshkelkar, lorenzo, yoshfuji, stable
In-Reply-To: <20110123192624.5cfe33d0@s6510>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sun, 23 Jan 2011 19:26:24 +1100

> Also for application sanity, Linux should behave the same as BSD

I've heard enough, I'm reverting your changes.  You obviously
don't get what "don't break stuff that was working" means.

^ permalink raw reply

* [PATCH] netconsole: kbuild dependency fix
From: Stanislav Fomichev @ 2011-01-23 19:51 UTC (permalink / raw)
  To: netdev

Hello all,
I'm not sure if it's the right place to send this patch, but I didn't find a better one.

Here is a small fix for netconsole dependency (upon config fs) that I unintentionally found.

Hope you'll find it useful.

This patch is for 2.6.38-rc2.

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0382332..9733da1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3382,6 +3382,7 @@ config NET_FC
 	  "SCSI generic support".
 
 config NETCONSOLE
+	depends on CONFIGFS_FS
 	tristate "Network console logging support"
 	---help---
 	If you want to log kernel messages over the network, enable this.

^ permalink raw reply related

* Re: [stable] [RFC] ipv6: don't flush routes when setting loopback down
From: David Miller @ 2011-01-23 19:57 UTC (permalink / raw)
  To: ebiederm
  Cc: shemminger, w, jbohac, yoshfuji, netdev, stable,
	stephen.hemminger, brian.haley, lorenzo, maheshkelkar
In-Reply-To: <m1k4hv5sue.fsf@fess.ebiederm.org>

From: ebiederm@xmission.com (Eric W. Biederman)
Date: Sun, 23 Jan 2011 11:21:29 -0800

> Stephen Hemminger <shemminger@vyatta.com> writes:
> 
>> I think this fixes the issue with disable_ipv6
> 
> Somehow I doubt deleting the ipv6 state, and removing the per device
> disable_ipv6 flag is going to be backwards compatible.
> 
> echo 0 > /proc/sys/net/ipv6/conf/disable_ipv6
> 
> Won't work.
> 
> What ever other good properties calling NETDEV_UNREGISTER for ipv6
> devices may have.

Don't worry Eric, I'm reverting all of the changes that caused this
problem in the first place.

If Stephen wants his change back in, he'll have to resubmit it in
a working state with all the known regressions dealt with.

^ permalink raw reply

* ipv6 steaming pile of poo...
From: David Miller @ 2011-01-23 20:37 UTC (permalink / raw)
  To: netdev


Thanks to the fact that I let a change causing known regressions live
in the tree for almost a year (don't worry I've learned my lesson):

>From dc2b99f71ef477a31020511876ab4403fb7c4420 Mon Sep 17 00:00:00 2001
From: stephen hemminger <shemminger@vyatta.com>
Date: Mon, 8 Feb 2010 19:48:05 +0000
Subject: [PATCH] IPv6: keep permanent addresses on admin down

We have over a year of follow-up changes to revert if we want to
get rid of this turd.

This means getting rid of all the changes that tried to fix bugs in
the new ipv6 semantics made by Lorenzo Colitti, and the hlist
conversions, and all changes dependent upon those.

But no matter, this has to be done and I don't care if we lost lots
of cleanups and other work as a result of doing this, it just has to
be done.

And this is _why_ we must revert changes causing known regressions
as soon as they are discovered, not months or a year later.  Because
after that much time, undoing the damage becomes that much harder.

So if you folks wonder what I'm working on the next couple of days,
this is it.

^ permalink raw reply

* Re: 2.6.37 regression: adding main interface to a bridge breaks vlan interface RX
From: Jesse Gross @ 2011-01-23 21:29 UTC (permalink / raw)
  To: maciej.rutecki; +Cc: Simon Arlott, netdev, Linux Kernel Mailing List
In-Reply-To: <201101231845.20505.maciej.rutecki@gmail.com>

On Sun, Jan 23, 2011 at 9:45 AM, Maciej Rutecki
<maciej.rutecki@gmail.com> wrote:
> I created a Bugzilla entry at
> https://bugzilla.kernel.org/show_bug.cgi?id=27432
> for your bug report, please add your address to the CC list in there, thanks!

This isn't a bug - the change resolved behavior that varied depending
on what NIC was in use.

^ permalink raw reply

* RE: Using ethernet device as efficient small packet generator
From: juice @ 2011-01-23 21:48 UTC (permalink / raw)
  To: Brandeburg, Jesse, Loke, Chetan, Jon Zhou, Eric Dumazet,
	"Stephen Hemming
In-Reply-To: <alpine.WNT.2.00.1101211400000.5816@JBRANDEB-DESK2.amr.corp.intel.com>


> your computation of Bandwidth (as Ben Greear said) is not accounting for
> the interframe gaps.  Maybe more useful is to note that wire speed 64 byte
> packets is 1.44 Million packets per second.

I am aware of the fact that interframe gap eats away some of the bandwidth
from actual data bytes, and I am taking that into consideration.
My benchmark here is the Spirent AX4000 network analyzer, which can send
and receive full utilization of GE line.

The measurement when sending full line rate from AX4000 are:
  Total bitrate:             761.903 MBits/s
  Packet rate:               1488090 packets/s
  Bandwidth:                 76.19% GE
  Average packet intereval:  0.67 us


> I think you need different hardware (again) as you have saddled yourself
> with a x1 PCIe connected adapter.  This adapter is not well suited to
> small packet traffic because the sheer amount of transactions is effected
> by the added latency due to the x1 connector (vs our dual port 1GbE
> adapters with a x4 connector)
>
> with Core i3/5/7 or newer cpus you should be able to saturate a 1Gb link
> with a single core/queue.  With Core2 era processors you may have some
> difficulty, with anything older than that you won't make it. :-)

The CPU I have on the machine driving the card is a dual-core Xeon:
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 26
model name	: Intel(R) Xeon(R) CPU           W3503  @ 2.40GHz
stepping	: 5
cpu MHz		: 2399.926
cache size	: 4096 KB

I do hope this is enough to go, as it is easier for me to get a better
network adapter than order a new faster machine as I jut got this one
last december :)


> My suggestion is to get one of the igb based adapters, 82576, or 82580
> based that run the igb driver.
>
> If you can't get a hold of those you should be able to easily get 1.1M pps
> from an 82571 adapter.

I will order the 82576 card and try my tests with that.


> you may also want to try reducing the tx descriptor ring count to 128
> using ethtool, and change the ethtool -C rx-usecs 20 setting, try
> 20,30,40,50,60

So this could up my current network card to a little faster?
If I can reach 1.1Mpackets/s, thats about 560Mbits/s. At least it would
get me a little closet to what I am trying to achieve.

Yours, Jussi Ohenoja





^ permalink raw reply

* [PATCH] USB NET KL5KUSB101: Fix mem leak in error path of kaweth_download_firmware()
From: Jesper Juhl @ 2011-01-23 22:19 UTC (permalink / raw)
  To: linux-usb
  Cc: linux-kernel, netdev, Greg Kroah-Hartman, The Zapman,
	Michael Rothwell

We will leak the storage allocated by request_firmware() if the size of 
the firmware is greater than KAWETH_FIRMWARE_BUF_SIZE.
This removes the leak by calling release_firmware() before we return 
-ENOSPC.

Signed-off-by: Jesper Juhl <jj@chaosbits.net>
---
 kaweth.c |    1 +
 1 file changed, 1 insertion(+)

  Compile tested only since I do not have the hardware.

diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 5e98643..7dc8497 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -406,6 +406,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
 
 	if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
 		err("Firmware too big: %zu", fw->size);
+		release_firmware(fw);
 		return -ENOSPC;
 	}
 	data_len = fw->size;


-- 
Jesper Juhl <jj@chaosbits.net>            http://www.chaosbits.net/
Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html
Plain text mails only, please.


^ permalink raw reply related

* Re: ipv6 steaming pile of poo...
From: Stephen Hemminger @ 2011-01-23 23:20 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20110123.123754.246545770.davem@davemloft.net>

On Sun, 23 Jan 2011 12:37:54 -0800 (PST)
David Miller <davem@davemloft.net> wrote:

> 
> Thanks to the fact that I let a change causing known regressions live
> in the tree for almost a year (don't worry I've learned my lesson):
> 
> From dc2b99f71ef477a31020511876ab4403fb7c4420 Mon Sep 17 00:00:00 2001
> From: stephen hemminger <shemminger@vyatta.com>
> Date: Mon, 8 Feb 2010 19:48:05 +0000
> Subject: [PATCH] IPv6: keep permanent addresses on admin down
> 
> We have over a year of follow-up changes to revert if we want to
> get rid of this turd.
> 
> This means getting rid of all the changes that tried to fix bugs in
> the new ipv6 semantics made by Lorenzo Colitti, and the hlist
> conversions, and all changes dependent upon those.
> 
> But no matter, this has to be done and I don't care if we lost lots
> of cleanups and other work as a result of doing this, it just has to
> be done.
> 
> And this is _why_ we must revert changes causing known regressions
> as soon as they are discovered, not months or a year later.  Because
> after that much time, undoing the damage becomes that much harder.
> 
> So if you folks wonder what I'm working on the next couple of days,
> this is it.
> --

Please post the full set of diffs, to allow for putting the bug fixes
back.

^ permalink raw reply

* RE: [net-next 08/12] ixgb: convert to new VLAN model
From: Tantilov, Emil S @ 2011-01-24  0:25 UTC (permalink / raw)
  To: Jesse Gross, Kirsher, Jeffrey T
  Cc: davem@davemloft.net, netdev@vger.kernel.org, gosp@redhat.com,
	bphilips@novell.com, Pieper, Jeffrey E
In-Reply-To: <AANLkTik1rCFRtBWov5f8yfU+4JZnbzLHgcmRC1y_+TDP@mail.gmail.com>

Jesse Gross wrote:
> On Thu, Jan 6, 2011 at 7:29 PM,  <jeffrey.t.kirsher@intel.com> wrote:
>> +static int ixgb_set_flags(struct net_device *netdev, u32 data) +{
>> +       struct ixgb_adapter *adapter = netdev_priv(netdev); +      
>> bool need_reset; +       int rc;
>> +
>> +       /*
>> +        * TX vlan insertion does not work per HW design when Rx
>> stripping is +        * disabled.  Disable txvlan when rxvlan is
>> off. +        */ +       if ((data & ETH_FLAG_RXVLAN) !=
>> (netdev->features & NETIF_F_HW_VLAN_RX)) +               data ^=
>> ETH_FLAG_TXVLAN; 
> 
> Does this really do the right thing?  If the RX vlan setting is
> changed, it will do the opposite of what the user requested for TX
> vlan?
> 
> So if I start with both on (the default) and turn them both off in one
> command (a valid setting), I will get RX off and TX on (an invalid
> setting).
> 
> Why not:
> 
> if (!(data & ETH_FLAG_RXVLAN))
>         data &= ~ETH_FLAG_TXVLAN;

Yeah that works for disabling rxvlan, but what if rxvlan is disabled, and the user attempts to enable txvlan? At least our validation argued that we should make it work both ways. Perhaps something like the following?

	if (!(data & ETH_FLAG_RXVLAN) && 
	   (netdev->features & NETIF_F_HW_VLAN_TX))
		data &= ~ETH_FLAG_TXVLAN;
	else if (data & ETH_FLAG_TXVLAN)
		data |= ETH_FLAG_RXVLAN;

Thanks,
Emil

^ permalink raw reply

* [PATCH v5] ARM: mxs: add initial pm support
From: Shawn Guo @ 2011-01-24  9:05 UTC (permalink / raw)
  To: davem, gerg, baruch, eric, bryan.wu, r64343, B32542,
	u.kleine-koenig
  Cc: Shawn Guo
In-Reply-To: <1294297998-26930-1-git-send-email-shawn.guo@freescale.com>

This is a very initial pm support and basically does nothing.
With this pm support entry, drivers can start testing their own
pm functions.

Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
---
Hi Sascha,

The merging conflict was fixed in this version, and you can pick it
up on imx-for-2.6.39 branch now.

 arch/arm/mach-mxs/Makefile |    1 +
 arch/arm/mach-mxs/pm.c     |   43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-mxs/pm.c

diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index df501a8..6b26f02 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -2,6 +2,7 @@
 obj-y := clock.o devices.o gpio.o icoll.o iomux.o system.o timer.o
 
 obj-$(CONFIG_MXS_OCOTP) += ocotp.o
+obj-$(CONFIG_PM) += pm.o
 
 obj-$(CONFIG_SOC_IMX23) += clock-mx23.o mm-mx23.o
 obj-$(CONFIG_SOC_IMX28) += clock-mx28.o mm-mx28.o
diff --git a/arch/arm/mach-mxs/pm.c b/arch/arm/mach-mxs/pm.c
new file mode 100644
index 0000000..fb042da
--- /dev/null
+++ b/arch/arm/mach-mxs/pm.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/io.h>
+#include <mach/system.h>
+
+static int mxs_suspend_enter(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		arch_idle();
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct platform_suspend_ops mxs_suspend_ops = {
+	.enter = mxs_suspend_enter,
+	.valid = suspend_valid_only_mem,
+};
+
+static int __init mxs_pm_init(void)
+{
+	suspend_set_ops(&mxs_suspend_ops);
+	return 0;
+}
+device_initcall(mxs_pm_init);
-- 
1.7.1



^ permalink raw reply related

* Re: ipv6 steaming pile of poo...
From: David Miller @ 2011-01-24  4:03 UTC (permalink / raw)
  To: shemminger; +Cc: netdev
In-Reply-To: <20110124092043.49b7d34a@s6510>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Mon, 24 Jan 2011 09:20:43 +1000

> Please post the full set of diffs, to allow for putting the bug fixes
> back.

I'm going to do one commit, with the list of commits I'm reverting
in the commit message so people can go back and go through the
history.

^ permalink raw reply

* [PATCH] pch_gbe: Fix the issue that the receiving data is not normal.
From: Toshiharu Okada @ 2011-01-24  4:43 UTC (permalink / raw)
  To: ML netdev; +Cc: LKML, Wang, Qi, Wang, Yong Y, Andrew, Intel OTC, Ewe, Kok Howg

This PCH_GBE driver had an issue that the receiving data is not normal.
This driver had not removed correctly the padding data 
which the DMA include in receiving data. 

This patch fixed this issue.

Signed-off-by: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com>
---
 drivers/net/pch_gbe/pch_gbe_main.c |   21 ++++++++++++---------
 1 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index 03a1d28..1bf2626 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION;
 #define PCH_GBE_SHORT_PKT		64
 #define DSC_INIT16			0xC000
 #define PCH_GBE_DMA_ALIGN		0
+#define PCH_GBE_DMA_PADDING		2
 #define PCH_GBE_WATCHDOG_PERIOD		(1 * HZ)	/* watchdog time */
 #define PCH_GBE_COPYBREAK_DEFAULT	256
 #define PCH_GBE_PCI_BAR			1
@@ -1422,8 +1423,8 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
 			pr_err("Receive CRC Error\n");
 		} else {
 			/* get receive length */
-			/* length convert[-3], padding[-2] */
-			length = (rx_desc->rx_words_eob) - 3 - 2;
+			/* length convert[-3] */
+			length = (rx_desc->rx_words_eob) - 3;
 
 			/* Decide the data conversion method */
 			if (!adapter->rx_csum) {
@@ -1443,12 +1444,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
 			if (skb_copy_flag) {	/* recycle  skb */
 				struct sk_buff *new_skb;
 				new_skb =
-				    netdev_alloc_skb(netdev,
-						     length + NET_IP_ALIGN);
+				    netdev_alloc_skb(netdev, length);
 				if (new_skb) {
 					if (!skb_padding_flag) {
 						skb_reserve(new_skb,
-								NET_IP_ALIGN);
+							PCH_GBE_DMA_PADDING);
 					}
 					memcpy(new_skb->data, skb->data,
 						length);
@@ -1465,12 +1465,15 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
 			}
 			if (skb_padding_flag) {
 				memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN);
-				memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0],
-					ETH_HLEN);
-				skb_reserve(skb, NET_IP_ALIGN);
-
+				memcpy(&skb->data[PCH_GBE_DMA_PADDING],
+				       &tmp_packet[0], ETH_HLEN);
+				skb_reserve(skb, PCH_GBE_DMA_PADDING);
+				/* The length includes padding length */
+				length = length - PCH_GBE_DMA_PADDING;
 			}
 
+			/* The length includes FCS length */
+			length = length - ETH_FCS_LEN;
 			/* update status of driver */
 			adapter->stats.rx_bytes += length;
 			adapter->stats.rx_packets++;
-- 
1.6.2.5

^ permalink raw reply related

* Re: [net-2.6 PATCH 1/2] net: dcbnl: remove redundant DCB_CAP_DCBX_STATIC bit
From: John Fastabend @ 2011-01-24  5:46 UTC (permalink / raw)
  To: Shmulik Ravid; +Cc: davem@davemloft.net, netdev@vger.kernel.org
In-Reply-To: <1295801600.25104.13.camel@lb-tlvb-shmulik.il.broadcom.com>

On 1/23/2011 8:53 AM, Shmulik Ravid wrote:
> 
> On Fri, 2011-01-21 at 18:52 -0800, John Fastabend wrote:
>> On 1/21/2011 6:35 PM, John Fastabend wrote:
>>> Remove redundant DCB_CAP_DCBX_STATIC bit in DCB capabilities
>>>
>>> Setting this bit indicates that no embedded DCBx engine is
>>> present and the hardware can not be configured. This is the
>>> same as having none of the DCB capability flags set or simply
>>> not implementing the dcbnl ops at all.
>>>
>>> This patch removes this bit. The bit has not made a stable
>>> release yet so removing it should not be an issue with
>>> existing apps.
>>>
>>> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
>>> CC: Shmulik Ravid <shmulikr@broadcom.com>
>>> ---
>>>
>>
>> Shmulik, could you ACK this because you added these bits? But
>> I was adding support for this in lldpad and I see no reason that
>> we need these?
>>
> DCB_CAP_DCBX_STATIC means that the embedded engine will turn the user
> configuration into the operational configuration without performing the
> actual negotiation, so it is not equivalent to not having an embedded
> DCBx engine. This is mostly a debug and integration option as it allows
> you to do DCB related or dependent testing and development without
> having a proper DCBx peer.
> 
> On second thought, I'm not sure this option is justified although we
> found it useful during our development. If you think it's not useful
> enough (or not at all) then by all means remove it.

We have an advertise bit in userspace that can be set and cleared to
do something similar for host based agents. I think for pg and application
data you can get the same behavior by setting the device to not willing.

However for PFC it could potentially be useful. But how would the
user set this mode? This is a capabilities bit indicating the device
supports this. Is there a way to subsequently put the device in this
mode?

--John  


> 
> Thanks,
> Shmulik
> 
> 
> 


^ permalink raw reply

* Re: [PATCH v2 14/16] Intel net drivers: convert to ndo_fix_features
From: Jeff Kirsher @ 2011-01-24  7:06 UTC (permalink / raw)
  To: Michał Mirosław; +Cc: netdev, Ben Hutchings
In-Reply-To: <28a1c0f6e1ab9a523ee1e947ca4a013fd5730539.1295734271.git.mirq-linux@rere.qmqm.pl>

2011/1/22 Michał Mirosław <mirq-linux@rere.qmqm.pl>:
> Private rx_csum flags are now duplicate of netdev->features & NETIF_F_RXCSUM.
> Removing this needs deeper surgery.
>
> Since ixgbevf doesn't change hardware state on RX csum enable/disable
> its reset is avoided.
>
> Things noticed:
>  - e1000, e1000e and ixgb have RX csum disabled by default
>  - HW VLAN acceleration probably can be toggled, but it's left as is
>  - the resets on RX csum offload change can probably be avoided
>  - there is A LOT of copy-and-pasted code here
>
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> ---
>  drivers/net/e1000/e1000_ethtool.c  |   69 ------------------------------------
>  drivers/net/e1000/e1000_main.c     |   30 +++++++++++++--
>  drivers/net/e1000e/ethtool.c       |   62 --------------------------------
>  drivers/net/e1000e/netdev.c        |   30 +++++++++++++--
>  drivers/net/igb/igb_ethtool.c      |   67 ----------------------------------
>  drivers/net/igb/igb_main.c         |   33 +++++++++++++----
>  drivers/net/igbvf/ethtool.c        |   57 -----------------------------
>  drivers/net/igbvf/netdev.c         |   25 ++++++++++---
>  drivers/net/ixgb/ixgb.h            |    2 +
>  drivers/net/ixgb/ixgb_ethtool.c    |   59 +------------------------------
>  drivers/net/ixgb/ixgb_main.c       |   31 ++++++++++++++--
>  drivers/net/ixgbe/ixgbe_ethtool.c  |   65 ---------------------------------
>  drivers/net/ixgbe/ixgbe_main.c     |   31 +++++++++++-----
>  drivers/net/ixgbevf/ethtool.c      |   46 ------------------------
>  drivers/net/ixgbevf/ixgbevf_main.c |   26 +++++++++++---
>  15 files changed, 172 insertions(+), 461 deletions(-)
>

I have applied this patch for review and testing to my tree

I have also applied the 1-13 patches just for testing purposes, so
that we can adequately test the changes to the Intel Wired drivers

-- 
Cheers,
Jeff

^ permalink raw reply

* [PATCH] ipv6: Revert 'administrative down' address handling changes.
From: David Miller @ 2011-01-24  7:41 UTC (permalink / raw)
  To: netdev; +Cc: shemminger, ebiederm, brian.haley, lorenzo, herbert


This reverts the following set of commits:

d1ed113f1669390da9898da3beddcc058d938587 ("ipv6: remove duplicate neigh_ifdown")
29ba5fed1bbd09c2cba890798c8f9eaab251401d ("ipv6: don't flush routes when setting loopback down")
9d82ca98f71fd686ef2f3017c5e3e6a4871b6e46 ("ipv6: fix missing in6_ifa_put in addrconf")
2de795707294972f6c34bae9de713e502c431296 ("ipv6: addrconf: don't remove address state on ifdown if the address is being kept")
8595805aafc8b077e01804c9a3668e9aa3510e89 ("IPv6: only notify protocols if address is compeletely gone")
27bdb2abcc5edb3526e25407b74bf17d1872c329 ("IPv6: keep tentative addresses in hash table")
93fa159abe50d3c55c7f83622d3f5c09b6e06f4b ("IPv6: keep route for tentative address")
8f37ada5b5f6bfb4d251a7f510f249cb855b77b3 ("IPv6: fix race between cleanup and add/delete address")
84e8b803f1e16f3a2b8b80f80a63fa2f2f8a9be6 ("IPv6: addrconf notify when address is unavailable")
dc2b99f71ef477a31020511876ab4403fb7c4420 ("IPv6: keep permanent addresses on admin down")

because the core semantic change to ipv6 address handling on ifdown
has broken some things, in particular "disable_ipv6" sysctl handling.

Stephen has made several attempts to get things back in working order,
but nothing has restored disable_ipv6 fully yet.

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

Ok, this is what I came up with.  I tried to avoid stupid things like
reverting cleanups and the list_head/hlist/RCU conversions of the
various ipv6 address lists and hash tables.

Herbert, would you please make sure I didn't accidently undo your DAD
handling fixes.

Eric B. and co., please do some testing to make sure all of your
disable_ipv6 cases are functioning properly with this applied.

Thanks!

 net/ipv6/addrconf.c |   81 +++++++++++++++++++++------------------------------
 1 files changed, 33 insertions(+), 48 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 24a1cf1..fd6782e 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2661,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 	struct net *net = dev_net(dev);
 	struct inet6_dev *idev;
 	struct inet6_ifaddr *ifa;
-	LIST_HEAD(keep_list);
-	int state;
+	int state, i;
 
 	ASSERT_RTNL();
 
-	/* Flush routes if device is being removed or it is not loopback */
-	if (how || !(dev->flags & IFF_LOOPBACK))
-		rt6_ifdown(net, dev);
+	rt6_ifdown(net, dev);
+	neigh_ifdown(&nd_tbl, dev);
 
 	idev = __in6_dev_get(dev);
 	if (idev == NULL)
@@ -2689,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
 	}
 
+	/* Step 2: clear hash table */
+	for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+		struct hlist_head *h = &inet6_addr_lst[i];
+		struct hlist_node *n;
+
+		spin_lock_bh(&addrconf_hash_lock);
+	restart:
+		hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
+			if (ifa->idev == idev) {
+				hlist_del_init_rcu(&ifa->addr_lst);
+				addrconf_del_timer(ifa);
+				goto restart;
+			}
+		}
+		spin_unlock_bh(&addrconf_hash_lock);
+	}
+
 	write_lock_bh(&idev->lock);
 
 	/* Step 2: clear flags for stateless addrconf */
@@ -2722,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 				       struct inet6_ifaddr, if_list);
 		addrconf_del_timer(ifa);
 
-		/* If just doing link down, and address is permanent
-		   and not link-local, then retain it. */
-		if (!how &&
-		    (ifa->flags&IFA_F_PERMANENT) &&
-		    !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
-			list_move_tail(&ifa->if_list, &keep_list);
-
-			/* If not doing DAD on this address, just keep it. */
-			if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
-			    idev->cnf.accept_dad <= 0 ||
-			    (ifa->flags & IFA_F_NODAD))
-				continue;
+		list_del(&ifa->if_list);
 
-			/* If it was tentative already, no need to notify */
-			if (ifa->flags & IFA_F_TENTATIVE)
-				continue;
+		write_unlock_bh(&idev->lock);
 
-			/* Flag it for later restoration when link comes up */
-			ifa->flags |= IFA_F_TENTATIVE;
-			ifa->state = INET6_IFADDR_STATE_DAD;
-		} else {
-			list_del(&ifa->if_list);
-
-			/* clear hash table */
-			spin_lock_bh(&addrconf_hash_lock);
-			hlist_del_init_rcu(&ifa->addr_lst);
-			spin_unlock_bh(&addrconf_hash_lock);
-
-			write_unlock_bh(&idev->lock);
-			spin_lock_bh(&ifa->state_lock);
-			state = ifa->state;
-			ifa->state = INET6_IFADDR_STATE_DEAD;
-			spin_unlock_bh(&ifa->state_lock);
-
-			if (state != INET6_IFADDR_STATE_DEAD) {
-				__ipv6_ifa_notify(RTM_DELADDR, ifa);
-				atomic_notifier_call_chain(&inet6addr_chain,
-							   NETDEV_DOWN, ifa);
-			}
+		spin_lock_bh(&ifa->state_lock);
+		state = ifa->state;
+		ifa->state = INET6_IFADDR_STATE_DEAD;
+		spin_unlock_bh(&ifa->state_lock);
 
-			in6_ifa_put(ifa);
-			write_lock_bh(&idev->lock);
+		if (state != INET6_IFADDR_STATE_DEAD) {
+			__ipv6_ifa_notify(RTM_DELADDR, ifa);
+			atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
 		}
-	}
+		in6_ifa_put(ifa);
 
-	list_splice(&keep_list, &idev->addr_list);
+		write_lock_bh(&idev->lock);
+	}
 
 	write_unlock_bh(&idev->lock);
 
@@ -4156,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 		addrconf_leave_solict(ifp->idev, &ifp->addr);
 		dst_hold(&ifp->rt->dst);
 
-		if (ifp->state == INET6_IFADDR_STATE_DEAD &&
-		    ip6_del_rt(ifp->rt))
+		if (ip6_del_rt(ifp->rt))
 			dst_free(&ifp->rt->dst);
 		break;
 	}
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH v4] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Po-Yu Chuang @ 2011-01-24  8:07 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: netdev, linux-kernel, bhutchings, joe, dilinger, mirqus,
	Po-Yu Chuang
In-Reply-To: <1295600887.2601.5.camel@edumazet-laptop>

Dear Eric,

On Fri, Jan 21, 2011 at 5:08 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Le vendredi 21 janvier 2011 à 15:55 +0800, Po-Yu Chuang a écrit :
> ...
>> +
>> +     dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
>> +
>> +     dev_kfree_skb_irq(skb);
>> +
>> +     ftmac100_txdes_reset(txdes);
>> +
>> +     ftmac100_tx_clean_pointer_advance(priv);
>> +
>> +     priv->tx_pending--;
>> +     netif_wake_queue(netdev);
>> +
>> +     return true;
>> +}
>> +
>
> Thanks to NAPI, you can free skb directly, not queuing it via
> NET_TX_SOFTIRQ softirq, using dev_kfree_skb() instead of
> dev_kfree_skb_irq()

Fixed. Thanks a lot.

best regards,
Po-Yu Chuang

^ permalink raw reply

* RE: Using ethernet device as efficient small packet generator
From: juice @ 2011-01-24  8:10 UTC (permalink / raw)
  To: Brandeburg, Jesse, Loke, Chetan, Jon Zhou, Eric Dumazet,
	"Stephen Hemming
In-Reply-To: <8ad1defdf427ceb7af94fad4d216b006.squirrel@www.liukuma.net>


>> you may also want to try reducing the tx descriptor ring count to 128
>> using ethtool, and change the ethtool -C rx-usecs 20 setting, try
>> 20,30,40,50,60
>
> So this could up my current network card to a little faster?
> If I can reach 1.1Mpackets/s, thats about 560Mbits/s. At least it would
> get me a little closet to what I am trying to achieve.
>

I tried these tunings, and it turns out that I am able to get the best
performance with pktgen when I set the options "ethtool -G eth1 tx 128"
and "ethtool -C eth1 rx-usecs 10". Anything different will lower the TX
performance.

Now I can get these rates:

root@d8labralinux:/var/home/juice/pkt_test# cat /proc/net/pktgen/eth1
Params: count 10000000  min_pkt_size: 60  max_pkt_size: 60
     frags: 0  delay: 0  clone_skb: 1  ifname: eth1
     flows: 0 flowlen: 0
     queue_map_min: 0  queue_map_max: 0
     dst_min: 10.10.11.2  dst_max:
        src_min:   src_max:
     src_mac: 00:1b:21:7c:e5:b1 dst_mac: 00:04:23:08:91:dc
     udp_src_min: 9  udp_src_max: 9  udp_dst_min: 9  udp_dst_max: 9
     src_mac_count: 0  dst_mac_count: 0
     Flags:
Current:
     pkts-sofar: 10000000  errors: 0
     started: 1205660106us  stopped: 1218005650us idle: 804us
     seq_num: 10000001  cur_dst_mac_offset: 0  cur_src_mac_offset: 0
     cur_saddr: 0x0  cur_daddr: 0x20b0a0a
     cur_udp_dst: 9  cur_udp_src: 9
     cur_queue_map: 0
     flows: 0
Result: OK: 12345544(c12344739+d804) nsec, 10000000 (60byte,0frags)
  810008pps 388Mb/sec (388803840bps) errors: 0

AX4000:
  Total bitrate:             414.629 MBits/s
  Packet rate:               809824 packets/s
  Bandwidth:                 41.46% GE
  Average packet intereval:  1.23 us

This is a bit better than the previous maxim of 750064pps / 360Mb/sec
that I was able to achieve without tuning parameters with ethtool, but
still not near the 1.1Mpacks/s that shoud be doable with my card?

Are there other tunings or alternate driver that I could use to get the
best performance out of the card? Basically what puzzles me is the fact
that I can get a lot better performance using larger packets, so that
suggests to me that the bottleneck cannot be the PCIe interface, as I can
push enough data through it. Is there any way of doing larger transfers
on the bus, like grouping many smaller packets together to avoid the
problems caused by so many TX interrupts?

Yours, Jussi Ohenoja




^ permalink raw reply

* Re: [net-next 0/4][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2011-01-24  8:19 UTC (permalink / raw)
  To: David Miller; +Cc: Jeff Kirsher, netdev, gospo, bphilips
In-Reply-To: <1295697376-2984-1-git-send-email-jeffrey.t.kirsher@intel.com>

On Sat, Jan 22, 2011 at 03:56, Jeff Kirsher <jeffrey.t.kirsher@intel.com> wrote:
> The following series contains cleanups for e1000e and addition support
> for the i340 adapter in igb.
>
> The following are changes since commit bb134d2298b49f50cf6d9388410fba96272905dc:
>  net: netif_setup_tc() is static
>
> and are available in the git repository at:
>  master.kernel.org:/pub/scm/linux/kernel/git/jkirsher/net-next-2.6 master
>
> Bruce Allan (2):
>  e1000e: reduce scope of some variables, remove unnecessary ones
>  e1000e: Use kmemdup rather than duplicating its implementation
>
> Carolyn Wyborny (1):
>  igb: Add support for i340 Quad Port Fiber Adapter
>
> Jeff Kirsher (1):
>  e1000e: convert to stats64
>

I have updated my tree to include Flavio's Signed-off-by on the following patch:

e1000e: convert to stats64

-- 
Cheers,
Jeff

^ permalink raw reply

* Re: [PATCH v4] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Po-Yu Chuang @ 2011-01-24  8:26 UTC (permalink / raw)
  To: Michał Mirosław
  Cc: netdev, linux-kernel, bhutchings, eric.dumazet, joe, dilinger,
	Po-Yu Chuang
In-Reply-To: <AANLkTikpu05V92T+YvuHW+jcTH-Bu2t6=HoQn5OR3ZhX@mail.gmail.com>

Dear Michał,

2011/1/21 Michał Mirosław <mirqus@gmail.com>:
> 2011/1/21 Po-Yu Chuang <ratbert.chuang@gmail.com>:
>> From: Po-Yu Chuang <ratbert@faraday-tech.com>
>>
>> FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
>> MII.  This driver has been working on some ARM/NDS32 SoC's including
>> Faraday A320 and Andes AG101.
>>
>> Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
> [...]
>> +static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
>> +{
>> +       /* clear all except end of ring bit */
>> +       txdes->txdes0 = 0;
>> +       txdes->txdes1 &= FTMAC100_TXDES1_EDOTR;
>> +       txdes->txdes2 = 0;
>> +       txdes->txdes3 = 0;
>> +}
>
> This also probably needs cpu_to_le32().

Ah, I missed that. Fixed.

> [...]
>> +static void ftmac100_free_buffers(struct ftmac100 *priv)
>> +{
>> +       int i;
>> +
>> +       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
>> +               struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
>> +               dma_addr_t d = ftmac100_rxdes_get_dma_addr(rxdes);
>> +               void *page = ftmac100_rxdes_get_va(rxdes);
>> +
>> +               if (d)
>> +                       dma_unmap_single(priv->dev, d, PAGE_SIZE,
>> +                                        DMA_FROM_DEVICE);
>> +
>> +               if (page != NULL)
>> +                       free_page((unsigned long)page);
>> +       }
>> +
> [...]
>
>> +static int ftmac100_alloc_buffers(struct ftmac100 *priv)
>> +{
>> +       int i;
>> +
>> +       priv->descs = dma_alloc_coherent(priv->dev,
>> +                                        sizeof(struct ftmac100_descs),
>> +                                        &priv->descs_dma_addr,
>> +                                        GFP_KERNEL | GFP_DMA);
>> +       if (priv->descs == NULL)
>> +               return -ENOMEM;
>> +
>> +       memset(priv->descs, 0, sizeof(struct ftmac100_descs));
>> +
>> +       /* initialize RX ring */
>> +
>> +       ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
>> +
>> +       for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
>> +               struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
>> +               void *page;
>> +               dma_addr_t d;
>> +
>> +               page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
>> +               if (page == NULL)
>> +                       goto err;
>> +
>> +               d = dma_map_single(priv->dev, page, PAGE_SIZE, DMA_FROM_DEVICE);
>> +               if (unlikely(dma_mapping_error(priv->dev, d))) {
>> +                       free_page((unsigned long)page);
>> +                       goto err;
>> +               }
>> +
>> +               /*
>> +                * The hardware enforces a sub-2K maximum packet size, so we
>> +                * put two buffers on every hardware page.
>> +                */
>> +               ftmac100_rxdes_set_va(rxdes, page);
>> +               ftmac100_rxdes_set_va(rxdes + 1, page + PAGE_SIZE / 2);
>> +
>> +               ftmac100_rxdes_set_dma_addr(rxdes, d);
>> +               ftmac100_rxdes_set_dma_addr(rxdes + 1, d + PAGE_SIZE / 2);
>> +
>> +               ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
>> +               ftmac100_rxdes_set_buffer_size(rxdes + 1, RX_BUF_SIZE);
>> +
>> +               ftmac100_rxdes_set_dma_own(rxdes);
>> +               ftmac100_rxdes_set_dma_own(rxdes + 1);
>> +       }
> [...]
>
> Did you test this? This looks like it will result in double free after
> packet RX, as you are giving the same page (referenced once) to two
> distinct RX descriptors, that may be assigned different packets.

Yes, this is tested.

> Since your not implementing any RX offloads, you might just allocate
> fresh skb's with alloc_skb() and store skb pointer in rxdes3. Since

rxdes3 does not store virtual address of an skb.
It stores the address of the buffer allocated while open() and freed
only when stop().
The data in that buffer will be memcpy()ed to an skb allocated in
ftmac100_rx_packet().
No double free happens.

> hardware doesn't touch it, you can skip cpu_to_le32()/le32_to_cpu()
> there (leave a comment, though).

Agree. Thanks.

> Unless this needs to work for ISA devices, you should drop GFP_DMA
> allocation flag.

Ben mentioned about this in the previous mail. I thought that it is OK
to keep GFP_DMA
on ARM platform, but since you point out this flag is for ISA, I will drop it.

best regards,
Po-Yu Chuang

^ permalink raw reply

* RE: Using ethernet device as efficient small packet generator
From: Eric Dumazet @ 2011-01-24  9:18 UTC (permalink / raw)
  To: juice
  Cc: Brandeburg, Jesse, Loke, Chetan, Jon Zhou, Stephen Hemminger,
	netdev@vger.kernel.org
In-Reply-To: <30747065682effddc661b8cd235553d9.squirrel@www.liukuma.net>

Le lundi 24 janvier 2011 à 10:10 +0200, juice a écrit :
> >> you may also want to try reducing the tx descriptor ring count to 128
> >> using ethtool, and change the ethtool -C rx-usecs 20 setting, try
> >> 20,30,40,50,60
> >
> > So this could up my current network card to a little faster?
> > If I can reach 1.1Mpackets/s, thats about 560Mbits/s. At least it would
> > get me a little closet to what I am trying to achieve.
> >
> 
> I tried these tunings, and it turns out that I am able to get the best
> performance with pktgen when I set the options "ethtool -G eth1 tx 128"
> and "ethtool -C eth1 rx-usecs 10". Anything different will lower the TX
> performance.
> 

That (rx-usecs 10) makes no sense.
pktgen sends packets.
You should not receive packets ?

> Now I can get these rates:
> 
> root@d8labralinux:/var/home/juice/pkt_test# cat /proc/net/pktgen/eth1
> Params: count 10000000  min_pkt_size: 60  max_pkt_size: 60
>      frags: 0  delay: 0  clone_skb: 1  ifname: eth1
>      flows: 0 flowlen: 0
>      queue_map_min: 0  queue_map_max: 0
>      dst_min: 10.10.11.2  dst_max:
>         src_min:   src_max:
>      src_mac: 00:1b:21:7c:e5:b1 dst_mac: 00:04:23:08:91:dc
>      udp_src_min: 9  udp_src_max: 9  udp_dst_min: 9  udp_dst_max: 9
>      src_mac_count: 0  dst_mac_count: 0
>      Flags:
> Current:
>      pkts-sofar: 10000000  errors: 0
>      started: 1205660106us  stopped: 1218005650us idle: 804us
>      seq_num: 10000001  cur_dst_mac_offset: 0  cur_src_mac_offset: 0
>      cur_saddr: 0x0  cur_daddr: 0x20b0a0a
>      cur_udp_dst: 9  cur_udp_src: 9
>      cur_queue_map: 0
>      flows: 0
> Result: OK: 12345544(c12344739+d804) nsec, 10000000 (60byte,0frags)
>   810008pps 388Mb/sec (388803840bps) errors: 0
> 
> AX4000:
>   Total bitrate:             414.629 MBits/s
>   Packet rate:               809824 packets/s
>   Bandwidth:                 41.46% GE
>   Average packet intereval:  1.23 us
> 
> This is a bit better than the previous maxim of 750064pps / 360Mb/sec
> that I was able to achieve without tuning parameters with ethtool, but
> still not near the 1.1Mpacks/s that shoud be doable with my card?
> 
> Are there other tunings or alternate driver that I could use to get the
> best performance out of the card? Basically what puzzles me is the fact
> that I can get a lot better performance using larger packets, so that
> suggests to me that the bottleneck cannot be the PCIe interface, as I can
> push enough data through it. Is there any way of doing larger transfers
> on the bus, like grouping many smaller packets together to avoid the
> problems caused by so many TX interrupts?
> 

What matters is not size of packets, but number of transactions (packets
per second)

You need a x4 or x8 connector to get more transactions per second, by an
order of magnitude, not 10% or 15% ;)

TX interrupts are already 'grouped', one for ~50 packets

ethtool -c :

tx-usecs: 72
tx-frames: 53
tx-usecs-irq: 0
tx-frames-irq: 53




^ permalink raw reply

* [PATCH v5] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Po-Yu Chuang @ 2011-01-24 12:39 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, bhutchings, eric.dumazet, joe, dilinger, mirqus,
	Po-Yu Chuang
In-Reply-To: <1295596533-1748-1-git-send-email-ratbert.chuang@gmail.com>

From: Po-Yu Chuang <ratbert@faraday-tech.com>

FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
MII.  This driver has been working on some ARM/NDS32 SoC's including
Faraday A320 and Andes AG101.

Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
---
v2:
always use NAPI
do not use our own net_device_stats structure
don't set trans_start and last_rx
stats.rx_packets and stats.rx_bytes include dropped packets
add missed netif_napi_del()
initialize spinlocks in probe function
remove rx_lock and hw_lock
use netdev_[err/info/dbg] instead of dev_* ones
use netdev_alloc_skb_ip_align()
remove ftmac100_get_stats()
use is_valid_ether_addr() instead of is_zero_ether_addr()
add const to ftmac100_ethtool_ops and ftmac100_netdev_ops
use net_ratelimit() instead of printk_ratelimit()
no explicit inline
use %pM to print MAC address
add comment before wmb
use napi poll() to handle all interrupts

v3:
undo "stats.rx_packets and stats.rx_bytes include dropped packets"
ftmac100_mdio_read() returns 0 if error
fix comment typos
use pr_fmt and pr_info
define INT_MASK_ALL_ENABLED
define MACCR_ENABLE_ALL
do not count length error many times
use bool/true/false
use cpu_to_le32/le32_to_cpu to access descriptors
indent style fix

v4:
should not access skb after netif_receive_skb()
use resource_size()
better way to use cpu_to_le32/le32_to_cpu
use spin_lock() for tx_lock
combine all netdev_info() together in ftmac100_poll()

v5:
use dev_kfree_skb() in ftmac100_tx_complete_packet()
cpu_to_le32/le32_to_cpu usage fix
drop GFP_DMA

 drivers/net/Kconfig    |    9 +
 drivers/net/Makefile   |    1 +
 drivers/net/ftmac100.c | 1212 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac100.h |  180 +++++++
 4 files changed, 1402 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/ftmac100.c
 create mode 100644 drivers/net/ftmac100.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4f1755b..26da0ee 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2014,6 +2014,15 @@ config BCM63XX_ENET
 	  This driver supports the ethernet MACs in the Broadcom 63xx
 	  MIPS chipset family (BCM63XX).
 
+config FTMAC100
+	tristate "Faraday FTMAC100 10/100 Ethernet support"
+	depends on ARM
+	select MII
+	help
+	  This driver supports the FTMAC100 Ethernet controller from
+	  Faraday. It is used on Faraday A320, Andes AG101, AG101P
+	  and some other ARM/NDS32 SoC's.
+
 source "drivers/net/fs_enet/Kconfig"
 
 source "drivers/net/octeon/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..7c21711 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_FTMAC100) += ftmac100.o
 
 obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c
new file mode 100644
index 0000000..18f8036
--- /dev/null
+++ b/drivers/net/ftmac100.c
@@ -0,0 +1,1212 @@
+/*
+ * Faraday FTMAC100 10/100 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/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#include "ftmac100.h"
+
+#define DRV_NAME	"ftmac100"
+#define DRV_VERSION	"0.2"
+
+#define RX_QUEUE_ENTRIES	128	/* must be power of 2 */
+#define TX_QUEUE_ENTRIES	16	/* must be power of 2 */
+
+#define MAX_PKT_SIZE		1518
+#define RX_BUF_SIZE		2044	/* must be smaller than 0x7ff */
+
+/******************************************************************************
+ * private data
+ *****************************************************************************/
+struct ftmac100_descs {
+	struct ftmac100_rxdes	rxdes[RX_QUEUE_ENTRIES];
+	struct ftmac100_txdes	txdes[TX_QUEUE_ENTRIES];
+};
+
+struct ftmac100 {
+	struct resource		*res;
+	void			*base;
+	int			irq;
+
+	struct ftmac100_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_if_info	mii;
+};
+
+/******************************************************************************
+ * internal functions (hardware register access)
+ *****************************************************************************/
+#define INT_MASK_ALL_ENABLED	(FTMAC100_INT_RPKT_FINISH	| \
+				 FTMAC100_INT_NORXBUF		| \
+				 FTMAC100_INT_XPKT_OK		| \
+				 FTMAC100_INT_XPKT_LOST		| \
+				 FTMAC100_INT_RPKT_LOST		| \
+				 FTMAC100_INT_AHB_ERR		| \
+				 FTMAC100_INT_PHYSTS_CHG)
+
+static void ftmac100_enable_all_int(struct ftmac100 *priv)
+{
+	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR);
+}
+
+static void ftmac100_disable_all_int(struct ftmac100 *priv)
+{
+	iowrite32(0, priv->base + FTMAC100_OFFSET_IMR);
+}
+
+static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
+{
+	iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR);
+}
+
+static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
+{
+	iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR);
+}
+
+static void ftmac100_txdma_start_polling(struct ftmac100 *priv)
+{
+	iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD);
+}
+
+static int ftmac100_reset(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	int i;
+
+	/* NOTE: reset clears all registers */
+	iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR);
+
+	for (i = 0; i < 5; i++) {
+		unsigned int maccr;
+
+		maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
+		if (!(maccr & FTMAC100_MACCR_SW_RST)) {
+			/*
+			 * FTMAC100_MACCR_SW_RST cleared does not indicate
+			 * that hardware reset completed (what the f*ck).
+			 * We still need to wait for a while.
+			 */
+			usleep_range(500, 1000);
+			return 0;
+		}
+
+		usleep_range(1000, 10000);
+	}
+
+	netdev_err(netdev, "software reset failed\n");
+	return -EIO;
+}
+
+static void ftmac100_set_mac(struct ftmac100 *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 + FTMAC100_OFFSET_MAC_MADR);
+	iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
+}
+
+#define MACCR_ENABLE_ALL	(FTMAC100_MACCR_XMT_EN	| \
+				 FTMAC100_MACCR_RCV_EN	| \
+				 FTMAC100_MACCR_XDMA_EN	| \
+				 FTMAC100_MACCR_RDMA_EN	| \
+				 FTMAC100_MACCR_CRC_APD	| \
+				 FTMAC100_MACCR_FULLDUP	| \
+				 FTMAC100_MACCR_RX_RUNT	| \
+				 FTMAC100_MACCR_RX_BROADPKT)
+
+static int ftmac100_start_hw(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+
+	if (ftmac100_reset(priv))
+		return -EIO;
+
+	/* setup ring buffer base registers */
+
+	ftmac100_set_rx_ring_base(priv,
+				  priv->descs_dma_addr +
+				  offsetof(struct ftmac100_descs, rxdes));
+	ftmac100_set_tx_ring_base(priv,
+				  priv->descs_dma_addr +
+				  offsetof(struct ftmac100_descs, txdes));
+
+	iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC);
+
+	ftmac100_set_mac(priv, netdev->dev_addr);
+
+	iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR);
+	return 0;
+}
+
+static void ftmac100_stop_hw(struct ftmac100 *priv)
+{
+	iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR);
+}
+
+/******************************************************************************
+ * internal functions (receive descriptor)
+ *****************************************************************************/
+static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS);
+}
+
+static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS);
+}
+
+static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
+}
+
+static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes)
+{
+	/* clear status bits */
+	rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
+}
+
+static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR);
+}
+
+static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR);
+}
+
+static bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL);
+}
+
+static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT);
+}
+
+static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB);
+}
+
+static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RFL);
+}
+
+static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST);
+}
+
+static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes,
+					   unsigned int size)
+{
+	rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR);
+	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size));
+}
+
+static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes)
+{
+	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR);
+}
+
+static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes,
+					dma_addr_t addr)
+{
+	rxdes->rxdes2 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes)
+{
+	return le32_to_cpu(rxdes->rxdes2);
+}
+
+/*
+ * rxdes3 is not used by hardware. We use it to keep track of buffer.
+ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
+ */
+static void ftmac100_rxdes_set_va(struct ftmac100_rxdes *rxdes, void *addr)
+{
+	rxdes->rxdes3 = (unsigned int)addr;
+}
+
+static void *ftmac100_rxdes_get_va(struct ftmac100_rxdes *rxdes)
+{
+	return (void *)rxdes->rxdes3;
+}
+
+/******************************************************************************
+ * internal functions (receive)
+ *****************************************************************************/
+static int ftmac100_next_rx_pointer(int pointer)
+{
+	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
+}
+
+static void ftmac100_rx_pointer_advance(struct ftmac100 *priv)
+{
+	priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer);
+}
+
+static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv)
+{
+	return &priv->descs->rxdes[priv->rx_pointer];
+}
+
+static struct ftmac100_rxdes *
+ftmac100_rx_locate_first_segment(struct ftmac100 *priv)
+{
+	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
+
+	while (!ftmac100_rxdes_owned_by_dma(rxdes)) {
+		if (ftmac100_rxdes_first_segment(rxdes))
+			return rxdes;
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+		ftmac100_rx_pointer_advance(priv);
+		rxdes = ftmac100_current_rxdes(priv);
+	}
+
+	return NULL;
+}
+
+static bool ftmac100_rx_packet_error(struct ftmac100 *priv,
+				     struct ftmac100_rxdes *rxdes)
+{
+	struct net_device *netdev = priv->netdev;
+	bool error = false;
+
+	if (unlikely(ftmac100_rxdes_rx_error(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx err\n");
+
+		netdev->stats.rx_errors++;
+		error = true;
+	}
+
+	if (unlikely(ftmac100_rxdes_crc_error(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx crc err\n");
+
+		netdev->stats.rx_crc_errors++;
+		error = true;
+	}
+
+	if (unlikely(ftmac100_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(ftmac100_rxdes_runt(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx runt\n");
+
+		netdev->stats.rx_length_errors++;
+		error = true;
+	} else if (unlikely(ftmac100_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 ftmac100_rx_drop_packet(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
+	bool done = false;
+
+	if (net_ratelimit())
+		netdev_dbg(netdev, "drop packet %p\n", rxdes);
+
+	do {
+		if (ftmac100_rxdes_last_segment(rxdes))
+			done = true;
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+		ftmac100_rx_pointer_advance(priv);
+		rxdes = ftmac100_current_rxdes(priv);
+	} while (!done && !ftmac100_rxdes_owned_by_dma(rxdes));
+
+	netdev->stats.rx_dropped++;
+}
+
+static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_rxdes *rxdes;
+	struct sk_buff *skb;
+	int length;
+	bool copied = false;
+	bool done = false;
+
+	rxdes = ftmac100_rx_locate_first_segment(priv);
+	if (!rxdes)
+		return false;
+
+	if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) {
+		ftmac100_rx_drop_packet(priv);
+		return true;
+	}
+
+	/* start processing */
+
+	length = ftmac100_rxdes_frame_length(rxdes);
+
+	skb = netdev_alloc_skb_ip_align(netdev, length);
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			netdev_err(netdev, "rx skb alloc failed\n");
+
+		ftmac100_rx_drop_packet(priv);
+		return true;
+	}
+
+	if (unlikely(ftmac100_rxdes_multicast(rxdes)))
+		netdev->stats.multicast++;
+
+	do {
+		dma_addr_t d = ftmac100_rxdes_get_dma_addr(rxdes);
+		void *buf = ftmac100_rxdes_get_va(rxdes);
+		int size;
+
+		size = min(length - copied, RX_BUF_SIZE);
+
+		dma_sync_single_for_cpu(priv->dev, d, RX_BUF_SIZE,
+					DMA_FROM_DEVICE);
+		memcpy(skb_put(skb, size), buf, size);
+
+		copied += size;
+
+		if (ftmac100_rxdes_last_segment(rxdes))
+			done = true;
+
+		dma_sync_single_for_device(priv->dev, d, RX_BUF_SIZE,
+					   DMA_FROM_DEVICE);
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+
+		ftmac100_rx_pointer_advance(priv);
+		rxdes = ftmac100_current_rxdes(priv);
+	} while (!done && copied < length);
+
+	skb->protocol = eth_type_trans(skb, netdev);
+
+	netdev->stats.rx_packets++;
+	netdev->stats.rx_bytes += skb->len;
+
+	/* push packet to protocol stack */
+	netif_receive_skb(skb);
+
+	(*processed)++;
+	return true;
+}
+
+/******************************************************************************
+ * internal functions (transmit descriptor)
+ *****************************************************************************/
+static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
+{
+	/* clear all except end of ring bit */
+	txdes->txdes0 = 0;
+	txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
+	txdes->txdes2 = 0;
+	txdes->txdes3 = 0;
+}
+
+static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
+}
+
+static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes)
+{
+	/*
+	 * Make sure dma own bit will not be set before any other
+	 * descriptor fields.
+	 */
+	wmb();
+	txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
+}
+
+static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL);
+}
+
+static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL);
+}
+
+static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
+}
+
+static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS);
+}
+
+static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS);
+}
+
+static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC);
+}
+
+static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes,
+					   unsigned int len)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len));
+}
+
+static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes,
+					dma_addr_t addr)
+{
+	txdes->txdes2 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes)
+{
+	return le32_to_cpu(txdes->txdes2);
+}
+
+/*
+ * txdes3 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 ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes,
+				   struct sk_buff *skb)
+{
+	txdes->txdes3 = (unsigned int)skb;
+}
+
+static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes)
+{
+	return (struct sk_buff *)txdes->txdes3;
+}
+
+/******************************************************************************
+ * internal functions (transmit)
+ *****************************************************************************/
+static int ftmac100_next_tx_pointer(int pointer)
+{
+	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
+}
+
+static void ftmac100_tx_pointer_advance(struct ftmac100 *priv)
+{
+	priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer);
+}
+
+static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv)
+{
+	priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer);
+}
+
+static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv)
+{
+	return &priv->descs->txdes[priv->tx_pointer];
+}
+
+static struct ftmac100_txdes *
+ftmac100_current_clean_txdes(struct ftmac100 *priv)
+{
+	return &priv->descs->txdes[priv->tx_clean_pointer];
+}
+
+static bool ftmac100_tx_complete_packet(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_txdes *txdes;
+	struct sk_buff *skb;
+	dma_addr_t map;
+
+	if (priv->tx_pending == 0)
+		return false;
+
+	txdes = ftmac100_current_clean_txdes(priv);
+
+	if (ftmac100_txdes_owned_by_dma(txdes))
+		return false;
+
+	skb = ftmac100_txdes_get_skb(txdes);
+	map = ftmac100_txdes_get_dma_addr(txdes);
+
+	if (unlikely(ftmac100_txdes_excessive_collision(txdes) ||
+		     ftmac100_txdes_late_collision(txdes))) {
+		/*
+		 * packet transmitted to ethernet lost due to late collision
+		 * or excessive collision
+		 */
+		netdev->stats.tx_aborted_errors++;
+	} else {
+		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);
+
+	ftmac100_txdes_reset(txdes);
+
+	ftmac100_tx_clean_pointer_advance(priv);
+
+	priv->tx_pending--;
+	netif_wake_queue(netdev);
+
+	return true;
+}
+
+static void ftmac100_tx_complete(struct ftmac100 *priv)
+{
+	spin_lock(&priv->tx_lock);
+	while (ftmac100_tx_complete_packet(priv))
+		;
+	spin_unlock(&priv->tx_lock);
+}
+
+static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
+			 dma_addr_t map)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_txdes *txdes;
+	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+
+	txdes = ftmac100_current_txdes(priv);
+	ftmac100_tx_pointer_advance(priv);
+
+	/* setup TX descriptor */
+
+	spin_lock(&priv->tx_lock);
+	ftmac100_txdes_set_skb(txdes, skb);
+	ftmac100_txdes_set_dma_addr(txdes, map);
+
+	ftmac100_txdes_set_first_segment(txdes);
+	ftmac100_txdes_set_last_segment(txdes);
+	ftmac100_txdes_set_txint(txdes);
+	ftmac100_txdes_set_buffer_size(txdes, len);
+
+	priv->tx_pending++;
+	if (priv->tx_pending == TX_QUEUE_ENTRIES) {
+		if (net_ratelimit())
+			netdev_info(netdev, "tx queue full\n");
+
+		netif_stop_queue(netdev);
+	}
+
+	/* start transmit */
+	ftmac100_txdes_set_dma_own(txdes);
+	spin_unlock(&priv->tx_lock);
+
+	ftmac100_txdma_start_polling(priv);
+
+	return NETDEV_TX_OK;
+}
+
+/******************************************************************************
+ * internal functions (buffer)
+ *****************************************************************************/
+static void ftmac100_free_buffers(struct ftmac100 *priv)
+{
+	int i;
+
+	for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+		dma_addr_t d = ftmac100_rxdes_get_dma_addr(rxdes);
+		void *page = ftmac100_rxdes_get_va(rxdes);
+
+		if (d)
+			dma_unmap_single(priv->dev, d, PAGE_SIZE,
+					 DMA_FROM_DEVICE);
+
+		if (page != NULL)
+			free_page((unsigned long)page);
+	}
+
+	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
+		struct ftmac100_txdes *txdes = &priv->descs->txdes[i];
+		struct sk_buff *skb = ftmac100_txdes_get_skb(txdes);
+
+		if (skb) {
+			dma_addr_t map;
+
+			map = ftmac100_txdes_get_dma_addr(txdes);
+			dma_unmap_single(priv->dev, map, skb_headlen(skb),
+					 DMA_TO_DEVICE);
+			dev_kfree_skb(skb);
+		}
+	}
+
+	dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs),
+			  priv->descs, priv->descs_dma_addr);
+}
+
+static int ftmac100_alloc_buffers(struct ftmac100 *priv)
+{
+	int i;
+
+	priv->descs = dma_alloc_coherent(priv->dev,
+					 sizeof(struct ftmac100_descs),
+					 &priv->descs_dma_addr, GFP_KERNEL);
+	if (priv->descs == NULL)
+		return -ENOMEM;
+
+	memset(priv->descs, 0, sizeof(struct ftmac100_descs));
+
+	/* initialize RX ring */
+
+	ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+
+	for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+		void *page;
+		dma_addr_t d;
+
+		page = (void *)__get_free_page(GFP_KERNEL);
+		if (page == NULL)
+			goto err;
+
+		d = dma_map_single(priv->dev, page, PAGE_SIZE, DMA_FROM_DEVICE);
+		if (unlikely(dma_mapping_error(priv->dev, d))) {
+			free_page((unsigned long)page);
+			goto err;
+		}
+
+		/*
+		 * The hardware enforces a sub-2K maximum packet size, so we
+		 * put two buffers on every hardware page.
+		 */
+		ftmac100_rxdes_set_va(rxdes, page);
+		ftmac100_rxdes_set_va(rxdes + 1, page + PAGE_SIZE / 2);
+
+		ftmac100_rxdes_set_dma_addr(rxdes, d);
+		ftmac100_rxdes_set_dma_addr(rxdes + 1, d + PAGE_SIZE / 2);
+
+		ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
+		ftmac100_rxdes_set_buffer_size(rxdes + 1, RX_BUF_SIZE);
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+		ftmac100_rxdes_set_dma_own(rxdes + 1);
+	}
+
+	/* initialize TX ring */
+
+	ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
+	return 0;
+
+err:
+	ftmac100_free_buffers(priv);
+	return -ENOMEM;
+}
+
+/******************************************************************************
+ * struct mii_if_info functions
+ *****************************************************************************/
+static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	unsigned int phycr;
+	int i;
+
+	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
+		FTMAC100_PHYCR_REGAD(reg) |
+		FTMAC100_PHYCR_MIIRD;
+
+	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
+	for (i = 0; i < 10; i++) {
+		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
+
+		if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
+			return phycr & FTMAC100_PHYCR_MIIRDATA;
+
+		usleep_range(100, 1000);
+	}
+
+	netdev_err(netdev, "mdio read timed out\n");
+	return 0;
+}
+
+static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
+				int data)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	unsigned int phycr;
+	int i;
+
+	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
+		FTMAC100_PHYCR_REGAD(reg) |
+		FTMAC100_PHYCR_MIIWR;
+
+	data = FTMAC100_PHYWDATA_MIIWDATA(data);
+
+	iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA);
+	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
+
+	for (i = 0; i < 10; i++) {
+		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
+
+		if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
+			return;
+
+		usleep_range(100, 1000);
+	}
+
+	netdev_err(netdev, "mdio write timed out\n");
+}
+
+/******************************************************************************
+ * struct ethtool_ops functions
+ *****************************************************************************/
+static void ftmac100_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 ftmac100_get_settings(struct net_device *netdev,
+				 struct ethtool_cmd *cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_ethtool_gset(&priv->mii, cmd);
+}
+
+static int ftmac100_set_settings(struct net_device *netdev,
+				 struct ethtool_cmd *cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_ethtool_sset(&priv->mii, cmd);
+}
+
+static int ftmac100_nway_reset(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_nway_restart(&priv->mii);
+}
+
+static u32 ftmac100_get_link(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_link_ok(&priv->mii);
+}
+
+static const struct ethtool_ops ftmac100_ethtool_ops = {
+	.set_settings		= ftmac100_set_settings,
+	.get_settings		= ftmac100_get_settings,
+	.get_drvinfo		= ftmac100_get_drvinfo,
+	.nway_reset		= ftmac100_nway_reset,
+	.get_link		= ftmac100_get_link,
+};
+
+/******************************************************************************
+ * interrupt handler
+ *****************************************************************************/
+static irqreturn_t ftmac100_interrupt(int irq, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct ftmac100 *priv = netdev_priv(netdev);
+
+	if (likely(netif_running(netdev))) {
+		/* Disable interrupts for polling */
+		ftmac100_disable_all_int(priv);
+		napi_schedule(&priv->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************
+ * struct napi_struct functions
+ *****************************************************************************/
+static int ftmac100_poll(struct napi_struct *napi, int budget)
+{
+	struct ftmac100 *priv = container_of(napi, struct ftmac100, napi);
+	struct net_device *netdev = priv->netdev;
+	unsigned int status;
+	bool completed = true;
+	int rx = 0;
+
+	status = ioread32(priv->base + FTMAC100_OFFSET_ISR);
+
+	if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) {
+		/*
+		 * FTMAC100_INT_RPKT_FINISH:
+		 *	RX DMA has received packets into RX buffer successfully
+		 *
+		 * FTMAC100_INT_NORXBUF:
+		 *	RX buffer unavailable
+		 */
+		bool retry;
+
+		do {
+			retry = ftmac100_rx_packet(priv, &rx);
+		} while (retry && rx < budget);
+
+		if (retry && rx == budget)
+			completed = false;
+	}
+
+	if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) {
+		/*
+		 * FTMAC100_INT_XPKT_OK:
+		 *	packet transmitted to ethernet successfully
+		 *
+		 * FTMAC100_INT_XPKT_LOST:
+		 *	packet transmitted to ethernet lost due to late
+		 *	collision or excessive collision
+		 */
+		ftmac100_tx_complete(priv);
+	}
+
+	if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST |
+		      FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) {
+		if (net_ratelimit())
+			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
+				    status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "",
+				    status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
+				    status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
+				    status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
+
+		if (status & FTMAC100_INT_NORXBUF) {
+			/* RX buffer unavailable */
+			netdev->stats.rx_over_errors++;
+		}
+
+		if (status & FTMAC100_INT_RPKT_LOST) {
+			/* received packet lost due to RX FIFO full */
+			netdev->stats.rx_fifo_errors++;
+		}
+
+		if (status & FTMAC100_INT_PHYSTS_CHG) {
+			/* PHY link status change */
+			mii_check_link(&priv->mii);
+		}
+	}
+
+	if (completed) {
+		/* stop polling */
+		napi_complete(napi);
+		ftmac100_enable_all_int(priv);
+	}
+
+	return rx;
+}
+
+/******************************************************************************
+ * struct net_device_ops functions
+ *****************************************************************************/
+static int ftmac100_open(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	int err;
+
+	err = ftmac100_alloc_buffers(priv);
+	if (err) {
+		netdev_err(netdev, "failed to allocate buffers\n");
+		goto err_alloc;
+	}
+
+	err = request_irq(priv->irq, ftmac100_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 = ftmac100_start_hw(priv);
+	if (err)
+		goto err_hw;
+
+	napi_enable(&priv->napi);
+	netif_start_queue(netdev);
+
+	ftmac100_enable_all_int(priv);
+	return 0;
+
+err_hw:
+	free_irq(priv->irq, netdev);
+err_irq:
+	ftmac100_free_buffers(priv);
+err_alloc:
+	return err;
+}
+
+static int ftmac100_stop(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+
+	ftmac100_disable_all_int(priv);
+	netif_stop_queue(netdev);
+	napi_disable(&priv->napi);
+	ftmac100_stop_hw(priv);
+	free_irq(priv->irq, netdev);
+	ftmac100_free_buffers(priv);
+
+	return 0;
+}
+
+static int ftmac100_hard_start_xmit(struct sk_buff *skb,
+				    struct net_device *netdev)
+{
+	struct ftmac100 *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 ftmac100_xmit(priv, skb, map);
+}
+
+/* optional */
+static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr,
+			     int cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+
+	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
+}
+
+static const struct net_device_ops ftmac100_netdev_ops = {
+	.ndo_open		= ftmac100_open,
+	.ndo_stop		= ftmac100_stop,
+	.ndo_start_xmit		= ftmac100_hard_start_xmit,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= ftmac100_do_ioctl,
+};
+
+/******************************************************************************
+ * struct platform_driver functions
+ *****************************************************************************/
+static int ftmac100_remove(struct platform_device *pdev)
+{
+	struct net_device *netdev;
+	struct ftmac100 *priv;
+
+	netdev = platform_get_drvdata(pdev);
+	if (netdev == NULL)
+		return 0;
+
+	platform_set_drvdata(pdev, NULL);
+
+	priv = netdev_priv(netdev);
+
+	netif_napi_del(&priv->napi);
+	unregister_netdev(netdev);
+
+	if (priv->base != NULL)
+		iounmap(priv->base);
+
+	if (priv->res != NULL)
+		release_resource(priv->res);
+
+	free_netdev(netdev);
+	return 0;
+}
+
+static int ftmac100_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int irq;
+	struct net_device *netdev;
+	struct ftmac100 *priv;
+	int err;
+
+	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(struct ftmac100));
+	if (netdev == NULL) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	SET_ETHTOOL_OPS(netdev, &ftmac100_ethtool_ops);
+	netdev->netdev_ops = &ftmac100_netdev_ops;
+
+	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, ftmac100_poll, 64);
+
+	/* map io memory */
+	priv->res = request_mem_region(res->start, resource_size(res),
+				       dev_name(&pdev->dev));
+	if (priv->res == NULL) {
+		dev_err(&pdev->dev, "Could not reserve memory region\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	priv->base = ioremap(res->start, res->end - res->start);
+	if (priv->base == NULL) {
+		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
+		err = -EIO;
+		goto err_out;
+	}
+
+	priv->irq = irq;
+
+	/* initialize struct mii_if_info */
+
+	priv->mii.phy_id	= 0;
+	priv->mii.phy_id_mask	= 0x1f;
+	priv->mii.reg_num_mask	= 0x1f;
+	priv->mii.dev		= netdev;
+	priv->mii.mdio_read	= ftmac100_mdio_read;
+	priv->mii.mdio_write	= ftmac100_mdio_write;
+
+	/* register network device */
+
+	err = register_netdev(netdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register netdev\n");
+		goto err_out;
+	}
+
+	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_out:
+	ftmac100_remove(pdev);
+	return err;
+}
+
+static struct platform_driver ftmac100_driver = {
+	.probe		= ftmac100_probe,
+	.remove		= ftmac100_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/******************************************************************************
+ * initialization / finalization
+ *****************************************************************************/
+static int __init ftmac100_init(void)
+{
+	pr_info("Loading version " DRV_VERSION " ...\n");
+	return platform_driver_register(&ftmac100_driver);
+}
+
+static void __exit ftmac100_exit(void)
+{
+	platform_driver_unregister(&ftmac100_driver);
+}
+
+module_init(ftmac100_init);
+module_exit(ftmac100_exit);
+
+MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
+MODULE_DESCRIPTION("FTMAC100 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ftmac100.h b/drivers/net/ftmac100.h
new file mode 100644
index 0000000..46a0c47
--- /dev/null
+++ b/drivers/net/ftmac100.h
@@ -0,0 +1,180 @@
+/*
+ * Faraday FTMAC100 10/100 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 __FTMAC100_H
+#define __FTMAC100_H
+
+#define	FTMAC100_OFFSET_ISR		0x00
+#define	FTMAC100_OFFSET_IMR		0x04
+#define	FTMAC100_OFFSET_MAC_MADR	0x08
+#define	FTMAC100_OFFSET_MAC_LADR	0x0c
+#define	FTMAC100_OFFSET_MAHT0		0x10
+#define	FTMAC100_OFFSET_MAHT1		0x14
+#define	FTMAC100_OFFSET_TXPD		0x18
+#define	FTMAC100_OFFSET_RXPD		0x1c
+#define	FTMAC100_OFFSET_TXR_BADR	0x20
+#define	FTMAC100_OFFSET_RXR_BADR	0x24
+#define	FTMAC100_OFFSET_ITC		0x28
+#define	FTMAC100_OFFSET_APTC		0x2c
+#define	FTMAC100_OFFSET_DBLAC		0x30
+#define	FTMAC100_OFFSET_MACCR		0x88
+#define	FTMAC100_OFFSET_MACSR		0x8c
+#define	FTMAC100_OFFSET_PHYCR		0x90
+#define	FTMAC100_OFFSET_PHYWDATA	0x94
+#define	FTMAC100_OFFSET_FCR		0x98
+#define	FTMAC100_OFFSET_BPR		0x9c
+#define	FTMAC100_OFFSET_TS		0xc4
+#define	FTMAC100_OFFSET_DMAFIFOS	0xc8
+#define	FTMAC100_OFFSET_TM		0xcc
+#define	FTMAC100_OFFSET_TX_MCOL_SCOL	0xd4
+#define	FTMAC100_OFFSET_RPF_AEP		0xd8
+#define	FTMAC100_OFFSET_XM_PG		0xdc
+#define	FTMAC100_OFFSET_RUNT_TLCC	0xe0
+#define	FTMAC100_OFFSET_CRCER_FTL	0xe4
+#define	FTMAC100_OFFSET_RLC_RCC		0xe8
+#define	FTMAC100_OFFSET_BROC		0xec
+#define	FTMAC100_OFFSET_MULCA		0xf0
+#define	FTMAC100_OFFSET_RP		0xf4
+#define	FTMAC100_OFFSET_XP		0xf8
+
+/*
+ * Interrupt status register & interrupt mask register
+ */
+#define	FTMAC100_INT_RPKT_FINISH	(1 << 0)
+#define	FTMAC100_INT_NORXBUF		(1 << 1)
+#define	FTMAC100_INT_XPKT_FINISH	(1 << 2)
+#define	FTMAC100_INT_NOTXBUF		(1 << 3)
+#define	FTMAC100_INT_XPKT_OK		(1 << 4)
+#define	FTMAC100_INT_XPKT_LOST		(1 << 5)
+#define	FTMAC100_INT_RPKT_SAV		(1 << 6)
+#define	FTMAC100_INT_RPKT_LOST		(1 << 7)
+#define	FTMAC100_INT_AHB_ERR		(1 << 8)
+#define	FTMAC100_INT_PHYSTS_CHG		(1 << 9)
+
+/*
+ * Interrupt timer control register
+ */
+#define FTMAC100_ITC_RXINT_CNT(x)	(((x) & 0xf) << 0)
+#define FTMAC100_ITC_RXINT_THR(x)	(((x) & 0x7) << 4)
+#define FTMAC100_ITC_RXINT_TIME_SEL	(1 << 7)
+#define FTMAC100_ITC_TXINT_CNT(x)	(((x) & 0xf) << 8)
+#define FTMAC100_ITC_TXINT_THR(x)	(((x) & 0x7) << 12)
+#define FTMAC100_ITC_TXINT_TIME_SEL	(1 << 15)
+
+/*
+ * Automatic polling timer control register
+ */
+#define	FTMAC100_APTC_RXPOLL_CNT(x)	(((x) & 0xf) << 0)
+#define	FTMAC100_APTC_RXPOLL_TIME_SEL	(1 << 4)
+#define	FTMAC100_APTC_TXPOLL_CNT(x)	(((x) & 0xf) << 8)
+#define	FTMAC100_APTC_TXPOLL_TIME_SEL	(1 << 12)
+
+/*
+ * DMA burst length and arbitration control register
+ */
+#define FTMAC100_DBLAC_INCR4_EN		(1 << 0)
+#define FTMAC100_DBLAC_INCR8_EN		(1 << 1)
+#define FTMAC100_DBLAC_INCR16_EN	(1 << 2)
+#define FTMAC100_DBLAC_RXFIFO_LTHR(x)	(((x) & 0x7) << 3)
+#define FTMAC100_DBLAC_RXFIFO_HTHR(x)	(((x) & 0x7) << 6)
+#define FTMAC100_DBLAC_RX_THR_EN	(1 << 9)
+
+/*
+ * MAC control register
+ */
+#define	FTMAC100_MACCR_XDMA_EN		(1 << 0)
+#define	FTMAC100_MACCR_RDMA_EN		(1 << 1)
+#define	FTMAC100_MACCR_SW_RST		(1 << 2)
+#define	FTMAC100_MACCR_LOOP_EN		(1 << 3)
+#define	FTMAC100_MACCR_CRC_DIS		(1 << 4)
+#define	FTMAC100_MACCR_XMT_EN		(1 << 5)
+#define	FTMAC100_MACCR_ENRX_IN_HALFTX	(1 << 6)
+#define	FTMAC100_MACCR_RCV_EN		(1 << 8)
+#define	FTMAC100_MACCR_HT_MULTI_EN	(1 << 9)
+#define	FTMAC100_MACCR_RX_RUNT		(1 << 10)
+#define	FTMAC100_MACCR_RX_FTL		(1 << 11)
+#define	FTMAC100_MACCR_RCV_ALL		(1 << 12)
+#define	FTMAC100_MACCR_CRC_APD		(1 << 14)
+#define	FTMAC100_MACCR_FULLDUP		(1 << 15)
+#define	FTMAC100_MACCR_RX_MULTIPKT	(1 << 16)
+#define	FTMAC100_MACCR_RX_BROADPKT	(1 << 17)
+
+/*
+ * PHY control register
+ */
+#define FTMAC100_PHYCR_MIIRDATA		0xffff
+#define FTMAC100_PHYCR_PHYAD(x)		(((x) & 0x1f) << 16)
+#define FTMAC100_PHYCR_REGAD(x)		(((x) & 0x1f) << 21)
+#define FTMAC100_PHYCR_MIIRD		(1 << 26)
+#define FTMAC100_PHYCR_MIIWR		(1 << 27)
+
+/*
+ * PHY write data register
+ */
+#define FTMAC100_PHYWDATA_MIIWDATA(x)	((x) & 0xffff)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftmac100_txdes {
+	unsigned int	txdes0;
+	unsigned int	txdes1;
+	unsigned int	txdes2;	/* TXBUF_BADR */
+	unsigned int	txdes3;	/* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define	FTMAC100_TXDES0_TXPKT_LATECOL	(1 << 0)
+#define	FTMAC100_TXDES0_TXPKT_EXSCOL	(1 << 1)
+#define	FTMAC100_TXDES0_TXDMA_OWN	(1 << 31)
+
+#define	FTMAC100_TXDES1_TXBUF_SIZE(x)	((x) & 0x7ff)
+#define	FTMAC100_TXDES1_LTS		(1 << 27)
+#define	FTMAC100_TXDES1_FTS		(1 << 28)
+#define	FTMAC100_TXDES1_TX2FIC		(1 << 29)
+#define	FTMAC100_TXDES1_TXIC		(1 << 30)
+#define	FTMAC100_TXDES1_EDOTR		(1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftmac100_rxdes {
+	unsigned int	rxdes0;
+	unsigned int	rxdes1;
+	unsigned int	rxdes2;	/* RXBUF_BADR */
+	unsigned int	rxdes3;	/* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define	FTMAC100_RXDES0_RFL		0x7ff
+#define	FTMAC100_RXDES0_MULTICAST	(1 << 16)
+#define	FTMAC100_RXDES0_BROADCAST	(1 << 17)
+#define	FTMAC100_RXDES0_RX_ERR		(1 << 18)
+#define	FTMAC100_RXDES0_CRC_ERR		(1 << 19)
+#define	FTMAC100_RXDES0_FTL		(1 << 20)
+#define	FTMAC100_RXDES0_RUNT		(1 << 21)
+#define	FTMAC100_RXDES0_RX_ODD_NB	(1 << 22)
+#define	FTMAC100_RXDES0_LRS		(1 << 28)
+#define	FTMAC100_RXDES0_FRS		(1 << 29)
+#define	FTMAC100_RXDES0_RXDMA_OWN	(1 << 31)
+
+#define	FTMAC100_RXDES1_RXBUF_SIZE(x)	((x) & 0x7ff)
+#define	FTMAC100_RXDES1_EDORR		(1 << 31)
+
+#endif /* __FTMAC100_H */
-- 
1.6.3.3

^ permalink raw reply related

* [PATCH] textsearch: doc - fix spelling in lib/textsearch.c.
From: Jesper Dangaard Brouer @ 2011-01-24 12:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, sander.contrib, Jesper Dangaard Brouer

Found the following spelling errors while reading the textsearch code:
  "facitilies"  -> "facilities"
  "continously" -> "continuously"
  "arbitary"    -> "arbitrary"
  "patern"      -> "pattern"
  "occurences"  -> "occurrences"

I'll try to push this patch through DaveM, given the only users
of textsearch is in the net/ tree (nf_conntrack_amanda.c, xt_string.c
and em_text.c)

Signed-off-by: Jesper Sander <sander.contrib@gmail.com>
Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
---

 lib/textsearch.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/textsearch.c b/lib/textsearch.c
index d608331..e0cc014 100644
--- a/lib/textsearch.c
+++ b/lib/textsearch.c
@@ -13,7 +13,7 @@
  *
  * INTRODUCTION
  *
- *   The textsearch infrastructure provides text searching facitilies for
+ *   The textsearch infrastructure provides text searching facilities for
  *   both linear and non-linear data. Individual search algorithms are
  *   implemented in modules and chosen by the user.
  *
@@ -43,7 +43,7 @@
  *       to the algorithm to store persistent variables.
  *   (4) Core eventually resets the search offset and forwards the find()
  *       request to the algorithm.
- *   (5) Algorithm calls get_next_block() provided by the user continously
+ *   (5) Algorithm calls get_next_block() provided by the user continuously
  *       to fetch the data to be searched in block by block.
  *   (6) Algorithm invokes finish() after the last call to get_next_block
  *       to clean up any leftovers from get_next_block. (Optional)
@@ -58,15 +58,15 @@
  *   the pattern to look for and flags. As a flag, you can set TS_IGNORECASE
  *   to perform case insensitive matching. But it might slow down
  *   performance of algorithm, so you should use it at own your risk.
- *   The returned configuration may then be used for an arbitary
+ *   The returned configuration may then be used for an arbitrary
  *   amount of times and even in parallel as long as a separate struct
  *   ts_state variable is provided to every instance.
  *
  *   The actual search is performed by either calling textsearch_find_-
  *   continuous() for linear data or by providing an own get_next_block()
  *   implementation and calling textsearch_find(). Both functions return
- *   the position of the first occurrence of the patern or UINT_MAX if
- *   no match was found. Subsequent occurences can be found by calling
+ *   the position of the first occurrence of the pattern or UINT_MAX if
+ *   no match was found. Subsequent occurrences can be found by calling
  *   textsearch_next() regardless of the linearity of the data.
  *
  *   Once you're done using a configuration it must be given back via


^ permalink raw reply related

* Re: [PATCH v2 1/3] can: at91_can: clean up usage of AT91_MB_RX_FIRST and AT91_MB_RX_NUM
From: Marc Kleine-Budde @ 2011-01-24 12:44 UTC (permalink / raw)
  To: David Miller
  Cc: Socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
	netdev-u79uwXL29TY76Z2rM5mHXA, wg-5Yr1BZd7O62+XT7JhA+gdA
In-Reply-To: <20110121.165409.200115988.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>


[-- Attachment #1.1: Type: text/plain, Size: 1359 bytes --]

On 01/22/2011 01:54 AM, David Miller wrote:
> From: Marc Kleine-Budde <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Date: Mon, 17 Jan 2011 20:50:36 +0100
> 
>> On 01/11/2011 02:21 PM, Marc Kleine-Budde wrote:
>>> This patch cleans up the usage of two macros which specify the mailbox
>>> usage. AT91_MB_RX_FIRST and AT91_MB_RX_NUM define the first and the
>>> number of RX mailboxes. The current driver uses these variables in an
>>> unclean way; assuming that AT91_MB_RX_FIRST is 0;
>>>
>>> This patch cleans up the usage of these macros, no longer assuming
>>> AT91_MB_RX_FIRST == 0.
>>>
>>> Signed-off-by: Marc Kleine-Budde <mkl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
>>
>> Any comments on this?
> 
> I would also seriously like to see these changes get some feedback,
> they've been rotting in patchwork for more than a week.

I've just talked to our customer (the one who noticed the problem in the
first place). They have the patched driver running over the weekend
without problems.

I'm going to resend the series the the Acks.

regards, Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

[-- Attachment #2: Type: text/plain, Size: 188 bytes --]

_______________________________________________
Socketcan-core mailing list
Socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org
https://lists.berlios.de/mailman/listinfo/socketcan-core

^ permalink raw reply

* Re: [net-2.6 PATCH 1/2] net: dcbnl: remove redundant DCB_CAP_DCBX_STATIC bit
From: Shmulik Ravid @ 2011-01-24 15:27 UTC (permalink / raw)
  To: John Fastabend; +Cc: davem@davemloft.net, netdev@vger.kernel.org
In-Reply-To: <4D3D123F.40700@intel.com>


On Sun, 2011-01-23 at 21:46 -0800, John Fastabend wrote:
> On 1/23/2011 8:53 AM, Shmulik Ravid wrote:
> > 
> > On Fri, 2011-01-21 at 18:52 -0800, John Fastabend wrote:
> >> On 1/21/2011 6:35 PM, John Fastabend wrote:
> >>> Remove redundant DCB_CAP_DCBX_STATIC bit in DCB capabilities
> >>>
> >>> Setting this bit indicates that no embedded DCBx engine is
> >>> present and the hardware can not be configured. This is the
> >>> same as having none of the DCB capability flags set or simply
> >>> not implementing the dcbnl ops at all.
> >>>
> >>> This patch removes this bit. The bit has not made a stable
> >>> release yet so removing it should not be an issue with
> >>> existing apps.
> >>>
> >>> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> >>> CC: Shmulik Ravid <shmulikr@broadcom.com>
> >>> ---
> >>>
> >>
> >> Shmulik, could you ACK this because you added these bits? But
> >> I was adding support for this in lldpad and I see no reason that
> >> we need these?
> >>
> > DCB_CAP_DCBX_STATIC means that the embedded engine will turn the user
> > configuration into the operational configuration without performing the
> > actual negotiation, so it is not equivalent to not having an embedded
> > DCBx engine. This is mostly a debug and integration option as it allows
> > you to do DCB related or dependent testing and development without
> > having a proper DCBx peer.
> > 
> > On second thought, I'm not sure this option is justified although we
> > found it useful during our development. If you think it's not useful
> > enough (or not at all) then by all means remove it.
> 
> We have an advertise bit in userspace that can be set and cleared to
> do something similar for host based agents. I think for pg and application
> data you can get the same behavior by setting the device to not willing.
> 
True, but this requires a proper DCBx peer. The STATIC option is a bit
stronger.

> However for PFC it could potentially be useful. But how would the
> user set this mode? This is a capabilities bit indicating the device
> supports this. Is there a way to subsequently put the device in this
> mode?
You can set this mode by specifying this attribute in the set_dcbx
operation. The input to set_dcbx should be a subset of the advertised
dcbx attributes.

Shmulik 




^ 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