Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] usbnet: rx_submit() should return an error code.
From: David Miller @ 2010-08-10  7:18 UTC (permalink / raw)
  To: ellyjones; +Cc: oneukum, stern, netdev, linux-usb, jglasgow
In-Reply-To: <AANLkTimubaXzLjROeaNB0dV09thKfpLDyaEA-t_yzyV1@mail.gmail.com>

From: Elly Jones <ellyjones@google.com>
Date: Mon, 9 Aug 2010 18:37:50 -0400

> This patch makes rx_submit() return an error code, and makes some call sites
> that care check the return value. This is important because it lets us properly
> handle cases where the device isn't ready to handle URB submissions (e.g., when
> it is autosuspended under some drivers); previously, we would attempt and fail
> to submit URBs and reschedule ourselves to try and fail again. This patch is
> against Linus's 2.6 repo commit 45d7f32c7a43cbb9592886d38190e379e2eb2226.
> 
> Signed-Off-By: Elizabeth Jones <ellyjones@google.com>

What gets kevent() running again to run the rx_submit() calls when the
device comes back from being suspended?

^ permalink raw reply

* Re: [PATCH] usbnet: rx_submit() should return an error code.
From: Oliver Neukum @ 2010-08-10  7:42 UTC (permalink / raw)
  To: David Miller
  Cc: ellyjones-hpIqsD4AKlfQT0dZR+AlfA,
	stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz,
	netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
	jglasgow-hpIqsD4AKlfQT0dZR+AlfA
In-Reply-To: <20100810.001855.179947437.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

Am Dienstag, 10. August 2010, 09:18:55 schrieb David Miller:
> From: Elly Jones <ellyjones-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> Date: Mon, 9 Aug 2010 18:37:50 -0400
> 
> > This patch makes rx_submit() return an error code, and makes some call sites
> > that care check the return value. This is important because it lets us properly
> > handle cases where the device isn't ready to handle URB submissions (e.g., when
> > it is autosuspended under some drivers); previously, we would attempt and fail
> > to submit URBs and reschedule ourselves to try and fail again. This patch is
> > against Linus's 2.6 repo commit 45d7f32c7a43cbb9592886d38190e379e2eb2226.
> > 
> > Signed-Off-By: Elizabeth Jones <ellyjones-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
> 
> What gets kevent() running again to run the rx_submit() calls when the
> device comes back from being suspended?
> 

usbnet_resume() schedules usbnet_bh() which will take care of that.

	Regards
		Oliver
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [patch 1/2 v2] qlcnic: clean up qlcnic_init_pci_info()
From: Dan Carpenter @ 2010-08-10  7:47 UTC (permalink / raw)
  To: Amit Kumar Salecha
  Cc: Anirban Chakraborty, linux-driver, David S. Miller,
	Sucheta Chakraborty, netdev, kernel-janitors

In the original code we allocated memory conditionally and freed it in
the error handling unconditionally.  It turns out that this function is
only called during initialization and "adapter->npars" and
"adapter->eswitch" are always NULL at the start of the function.  I
removed those checks.

Also since I was cleaning things, I changed the error handling for
qlcnic_get_pci_info() and pulled everything in an indent level.

Signed-off-by: Dan Carpenter <error27@gmail.com>
---
V2:  fixed a typo.  I set eswitch to NULL twice instead of npars by
mistake.

diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index b9615bd..6b8df55 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -477,44 +477,45 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 	int i, ret = 0, err;
 	u8 pfn;
 
-	if (!adapter->npars)
-		adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
+	adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
 				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
 	if (!adapter->npars)
 		return -ENOMEM;
 
-	if (!adapter->eswitch)
-		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+	adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
 				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
 	if (!adapter->eswitch) {
 		err = -ENOMEM;
-		goto err_eswitch;
+		goto err_npars;
 	}
 
 	ret = qlcnic_get_pci_info(adapter, pci_info);
-	if (!ret) {
-		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-			pfn = pci_info[i].id;
-			if (pfn > QLCNIC_MAX_PCI_FUNC)
-				return QL_STATUS_INVALID_PARAM;
-			adapter->npars[pfn].active = pci_info[i].active;
-			adapter->npars[pfn].type = pci_info[i].type;
-			adapter->npars[pfn].phy_port = pci_info[i].default_port;
-			adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
-			adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
-			adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
-		}
-
-		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
-			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+	if (ret)
+		goto err_eswitch;
 
-		return ret;
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+		pfn = pci_info[i].id;
+		if (pfn > QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+		adapter->npars[pfn].active = pci_info[i].active;
+		adapter->npars[pfn].type = pci_info[i].type;
+		adapter->npars[pfn].phy_port = pci_info[i].default_port;
+		adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+		adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
+		adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
 	}
 
+	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+		adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+
+	return 0;
+
+err_eswitch:
 	kfree(adapter->eswitch);
 	adapter->eswitch = NULL;
-err_eswitch:
+err_npars:
 	kfree(adapter->npars);
+	adapter->npars = NULL;
 
 	return ret;
 }

^ permalink raw reply related

* [patch 2/2 v2] qlcnic: using too much stack
From: Dan Carpenter @ 2010-08-10  7:49 UTC (permalink / raw)
  To: Amit Kumar Salecha
  Cc: Anirban Chakraborty, linux-driver, David S. Miller,
	Sucheta Chakraborty, netdev, kernel-janitors

qlcnic_pci_info structs are 128 bytes so an array of 8 uses 1024 bytes.
That's a lot if you run with 4K stacks.  I allocated them with kcalloc()
instead.

Signed-off-by: Dan Carpenter <error27@gmail.com>
---
V2:  No change.  I had to respin because of the 1/1 patch.

diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 6b8df55..bf6d87a 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -473,14 +473,20 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
 static int
 qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
-	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
 	int i, ret = 0, err;
 	u8 pfn;
 
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
 	adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
 				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
-	if (!adapter->npars)
-		return -ENOMEM;
+	if (!adapter->npars) {
+		err = -ENOMEM;
+		goto err_pci_info;
+	}
 
 	adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
 				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
@@ -508,6 +514,7 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 	for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
 		adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
 
+	kfree(pci_info);
 	return 0;
 
 err_eswitch:
@@ -516,6 +523,8 @@ err_eswitch:
 err_npars:
 	kfree(adapter->npars);
 	adapter->npars = NULL;
+err_pci_info:
+	kfree(pci_info);
 
 	return ret;
 }
@@ -3362,15 +3371,21 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 	struct device *dev = container_of(kobj, struct device, kobj);
 	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
 	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
-	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info *pci_info;
 	int i, ret;
 
 	if (size != sizeof(pci_cfg))
 		return QL_STATUS_INVALID_PARAM;
 
+	pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+	if (!pci_info)
+		return -ENOMEM;
+
 	ret = qlcnic_get_pci_info(adapter, pci_info);
-	if (ret)
+	if (ret) {
+		kfree(pci_info);
 		return ret;
+	}
 
 	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
 		pci_cfg[i].pci_func = pci_info[i].id;
@@ -3381,8 +3396,8 @@ qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
 		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
 	}
 	memcpy(buf, &pci_cfg, size);
+	kfree(pci_info);
 	return size;
-
 }
 static struct bin_attribute bin_attr_npar_config = {
 	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},

^ permalink raw reply related

* RE: Is it a possible bug in dev_gro_receive()?
From: Xin, Xiaohui @ 2010-08-10  8:11 UTC (permalink / raw)
  To: Jarek Poplawski
  Cc: netdev@vger.kernel.org, herbert@gondor.apana.org.au,
	davem@davemloft.net
In-Reply-To: <20100803064515.GA6430@ff.dom.local>

Jarek,
Seems community agree with your patch more.
So may you send out your patch then? Thanks!
Some of my related patches still need this fix.

Thanks
Xiaohui

>-----Original Message-----
>From: Jarek Poplawski [mailto:jarkao2@gmail.com]
>Sent: Tuesday, August 03, 2010 2:45 PM
>To: Xin, Xiaohui
>Cc: netdev@vger.kernel.org; herbert@gondor.apana.org.au; davem@davemloft.net
>Subject: Re: Is it a possible bug in dev_gro_receive()?
>
>On Tue, Aug 03, 2010 at 10:33:24AM +0800, Xin, Xiaohui wrote:
>> >-----Original Message-----
>> >From: Jarek Poplawski [mailto:jarkao2@gmail.com]
>> >Sent: Monday, August 02, 2010 6:29 PM
>> >To: Xin, Xiaohui
>> >Cc: netdev@vger.kernel.org; herbert@gondor.apana.org.au; davem@davemloft.net
>> >Subject: Re: Is it a possible bug in dev_gro_receive()?
>> >
>> >Xin Xiaohui wrote:
>> >> I looked into the code dev_gro_receive(), found the code here:
>> >> if the frags[0] is pulled to 0, then the page will be released,
>> >> and memmove() frags left.
>> >> Is that right? I'm not sure if memmove do right or not, but
>> >> frags[0].size is never set after memove at least. what I think
>> >> a simple way is not to do anything if we found frags[0].size == 0.
>> >> The patch is as followed.
>> >>
>> >> Or am I missing something here?
>> >
>> >I think, you're right, but fixing memmove looks nicer to me:
>> >
>> > -	--skb_shinfo(skb)->nr_frags);
>> > +	--skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
>> >
>> >Jarek P.
>>
>> Is there a little hurt of performance to do memmove() if skb_shinfo(skb)->nr_frags is
>large?
>> We're now working on the zero-copy patches based on napi_gro_frags() interface, and in
>> this case, we have found a lot of skbs which frags[0] is pulled to 0. And after the memmove
>is
>> fixed, each frags[x].size is needed to modify too.
>> So I think don't do anything is better. Or is there any side effect with a null page in the
>stack?
>
>Even if it's better, generally you should separate fixes from
>optimizations. On the other hand, it was expected to be "unlikely" by
>design, so you should probably explain more why it has to be changed
>here too.
>
>Thanks,
>Jarek P.
>
>>
>> Thanks
>> Xiaohui
>> >
>> >>
>> >> ---
>> >>  net/core/dev.c |    7 -------
>> >>  1 files changed, 0 insertions(+), 7 deletions(-)
>> >>
>> >> diff --git a/net/core/dev.c b/net/core/dev.c
>> >> index 264137f..28cdbbf 100644
>> >> --- a/net/core/dev.c
>> >> +++ b/net/core/dev.c
>> >> @@ -2730,13 +2730,6 @@ pull:
>> >>
>> >>  		skb_shinfo(skb)->frags[0].page_offset += grow;
>> >>  		skb_shinfo(skb)->frags[0].size -= grow;
>> >> -
>> >> -		if (unlikely(!skb_shinfo(skb)->frags[0].size)) {
>> >> -			put_page(skb_shinfo(skb)->frags[0].page);
>> >> -			memmove(skb_shinfo(skb)->frags,
>> >> -				skb_shinfo(skb)->frags + 1,
>> >> -				--skb_shinfo(skb)->nr_frags);
>> >> -		}
>> >>  	}
>> >>
>> >>  ok:
>> >
>> >
>>

^ permalink raw reply

* Re: [RFC] [PATCH] Don't destroy TCP sockets twice
From: Andi Kleen @ 2010-08-10  8:30 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Andi Kleen, netdev
In-Reply-To: <20100809213002.GA23736@gondor.apana.org.au>

On Mon, Aug 09, 2010 at 05:30:02PM -0400, Herbert Xu wrote:
> Andi Kleen <andi@firstfloor.org> wrote:
> > 
> > While working on something else I noticed that tcp_v4/6_destroy_sock()
> > can get called twice on a socket. This happens because when a reset or
> > similar happens tcp_done destroys the connection socket state, and 
> > then eventually when the socket is released it is destroyed again. 
> 
> I'm still having problems understanding why you're getting a call
> to send a FIN after tcp_done.  This shouldn't happen at all because
> tcp_done moves the socket to the TCP_CLOSE state, where FINs should
> not be sent.
> 
> Can you clarify on how we can reproduce this problem in the
>  upstream kernel?

This simple patch demonstrates double destroy. I have patches for showing
the more complicated case too, but they're much more ugly.

-Andi

diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index a778ee0..bfbb06b 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -459,6 +459,8 @@ struct tcp_sock {
 	 * contains related tcp_cookie_transactions fields.
 	 */
 	struct tcp_cookie_values  *cookie_values;
+
+	int destroyed;
 };
 
 static inline struct tcp_sock *tcp_sk(const struct sock *sk)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0207662..25bf80a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1919,6 +1919,9 @@ void tcp_v4_destroy_sock(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
 
+	BUG_ON(tp->destroyed != 0);
+	tp->destroyed = 1;
+
 	tcp_clear_xmit_timers(sk);
 
 	tcp_cleanup_congestion_control(sk);
-- 
ak@linux.intel.com -- Speaking for myself only.

^ permalink raw reply related

* Re: [patch 1/2 v2] qlcnic: clean up qlcnic_init_pci_info()
From: David Miller @ 2010-08-10  8:34 UTC (permalink / raw)
  To: error27
  Cc: amit.salecha, anirban.chakraborty, linux-driver,
	sucheta.chakraborty, netdev, kernel-janitors
In-Reply-To: <20100810074756.GF18431@bicker>

From: Dan Carpenter <error27@gmail.com>
Date: Tue, 10 Aug 2010 09:47:56 +0200

> In the original code we allocated memory conditionally and freed it in
> the error handling unconditionally.  It turns out that this function is
> only called during initialization and "adapter->npars" and
> "adapter->eswitch" are always NULL at the start of the function.  I
> removed those checks.
> 
> Also since I was cleaning things, I changed the error handling for
> qlcnic_get_pci_info() and pulled everything in an indent level.
> 
> Signed-off-by: Dan Carpenter <error27@gmail.com>

Applied.

^ permalink raw reply

* Re: [patch 2/2 v2] qlcnic: using too much stack
From: David Miller @ 2010-08-10  8:34 UTC (permalink / raw)
  To: error27
  Cc: amit.salecha, anirban.chakraborty, linux-driver,
	sucheta.chakraborty, netdev, kernel-janitors
In-Reply-To: <20100810074936.GG18431@bicker>

From: Dan Carpenter <error27@gmail.com>
Date: Tue, 10 Aug 2010 09:49:36 +0200

> qlcnic_pci_info structs are 128 bytes so an array of 8 uses 1024 bytes.
> That's a lot if you run with 4K stacks.  I allocated them with kcalloc()
> instead.
> 
> Signed-off-by: Dan Carpenter <error27@gmail.com>

Applied.

^ permalink raw reply

* Re: Is it a possible bug in dev_gro_receive()?
From: Jarek Poplawski @ 2010-08-10  8:34 UTC (permalink / raw)
  To: Xin, Xiaohui
  Cc: netdev@vger.kernel.org, herbert@gondor.apana.org.au,
	davem@davemloft.net
In-Reply-To: <F2E9EB7348B8264F86B6AB8151CE2D7920AD46E911@shsmsx502.ccr.corp.intel.com>

On Tue, Aug 10, 2010 at 04:11:54PM +0800, Xin, Xiaohui wrote:
> Jarek,
> Seems community agree with your patch more.
> So may you send out your patch then? Thanks!
> Some of my related patches still need this fix.

Hmm... But there was no my patch. Only a tiny, cosmetical suggestion
to your patch. I'd be glad if you add some credit or my "Acked-by",
of course. But if you really have a big problem, e.g. you don't like
my suggestion, please confirm.

Thanks,
Jarek P.

> 
> Thanks
> Xiaohui
> 
> >-----Original Message-----
> >From: Jarek Poplawski [mailto:jarkao2@gmail.com]
> >Sent: Tuesday, August 03, 2010 2:45 PM
> >To: Xin, Xiaohui
> >Cc: netdev@vger.kernel.org; herbert@gondor.apana.org.au; davem@davemloft.net
> >Subject: Re: Is it a possible bug in dev_gro_receive()?
> >
> >On Tue, Aug 03, 2010 at 10:33:24AM +0800, Xin, Xiaohui wrote:
> >> >-----Original Message-----
> >> >From: Jarek Poplawski [mailto:jarkao2@gmail.com]
> >> >Sent: Monday, August 02, 2010 6:29 PM
> >> >To: Xin, Xiaohui
> >> >Cc: netdev@vger.kernel.org; herbert@gondor.apana.org.au; davem@davemloft.net
> >> >Subject: Re: Is it a possible bug in dev_gro_receive()?
> >> >
> >> >Xin Xiaohui wrote:
> >> >> I looked into the code dev_gro_receive(), found the code here:
> >> >> if the frags[0] is pulled to 0, then the page will be released,
> >> >> and memmove() frags left.
> >> >> Is that right? I'm not sure if memmove do right or not, but
> >> >> frags[0].size is never set after memove at least. what I think
> >> >> a simple way is not to do anything if we found frags[0].size == 0.
> >> >> The patch is as followed.
> >> >>
> >> >> Or am I missing something here?
> >> >
> >> >I think, you're right, but fixing memmove looks nicer to me:
> >> >
> >> > -	--skb_shinfo(skb)->nr_frags);
> >> > +	--skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
> >> >
> >> >Jarek P.
> >>
> >> Is there a little hurt of performance to do memmove() if skb_shinfo(skb)->nr_frags is
> >large?
> >> We're now working on the zero-copy patches based on napi_gro_frags() interface, and in
> >> this case, we have found a lot of skbs which frags[0] is pulled to 0. And after the memmove
> >is
> >> fixed, each frags[x].size is needed to modify too.
> >> So I think don't do anything is better. Or is there any side effect with a null page in the
> >stack?
> >
> >Even if it's better, generally you should separate fixes from
> >optimizations. On the other hand, it was expected to be "unlikely" by
> >design, so you should probably explain more why it has to be changed
> >here too.
> >
> >Thanks,
> >Jarek P.
> >
> >>
> >> Thanks
> >> Xiaohui
> >> >
> >> >>
> >> >> ---
> >> >>  net/core/dev.c |    7 -------
> >> >>  1 files changed, 0 insertions(+), 7 deletions(-)
> >> >>
> >> >> diff --git a/net/core/dev.c b/net/core/dev.c
> >> >> index 264137f..28cdbbf 100644
> >> >> --- a/net/core/dev.c
> >> >> +++ b/net/core/dev.c
> >> >> @@ -2730,13 +2730,6 @@ pull:
> >> >>
> >> >>  		skb_shinfo(skb)->frags[0].page_offset += grow;
> >> >>  		skb_shinfo(skb)->frags[0].size -= grow;
> >> >> -
> >> >> -		if (unlikely(!skb_shinfo(skb)->frags[0].size)) {
> >> >> -			put_page(skb_shinfo(skb)->frags[0].page);
> >> >> -			memmove(skb_shinfo(skb)->frags,
> >> >> -				skb_shinfo(skb)->frags + 1,
> >> >> -				--skb_shinfo(skb)->nr_frags);
> >> >> -		}
> >> >>  	}
> >> >>
> >> >>  ok:
> >> >
> >> >
> >>

^ permalink raw reply

* RE: [PATCH] [Bug 16494] NFS client over TCP hangs due to packet loss
From: Andy Chittenden @ 2010-08-10  8:40 UTC (permalink / raw)
  To: 'Trond Myklebust'
  Cc: 'Andrew Morton', 'David Miller',
	kuznet-v/Mj1YrvjDBInbfyfbPRSQ, pekkas-UjJjq++bwZ7HOG6cAo2yLw,
	jmorris-gx6/JNMH7DfYtjvyW6yDsg, yoshfuji-VfPWfsRibaP+Ru+s062T9g,
	kaber-dcUjhNyLwpNeoWH0uzbU5w, eric.dumazet-Re5JQEeQqe8AvxtiuMwx3w,
	William.Allen.Simpson-Re5JQEeQqe8AvxtiuMwx3w,
	gilad-f4XOiQkOAtcdH0auuBZGHA,
	ilpo.jarvinen-pxSi+dnQzZMxHbG02/KK1g,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-nfs-u79uwXL29TY76Z2rM5mHXA, 'J. Bruce Fields',
	'Neil Brown', 'Chuck Lever',
	'Benny Halevy', 'Alexandros Batsakis',
	'Joe Perches', Andy Chittenden
In-Reply-To: <1281372927.8950.3.camel-rJ7iovZKK19ZJLDQqaL3InhyD016LWXt@public.gmane.org>

> On Mon, 2010-08-09 at 10:27 +0100, Andy Chittenden wrote:
> > A weekend run with that patch applied to 2.6.34.2 was successful. As
> nobody has objected, what's the next step to getting it applied to the
> official source trees?
> 
> Please resend me a version with a cleaned up changelog entry. I can
> then
> push it as a bugfix.
> 
> Cheers
>   Trond

Thanks. I think this sums it up:

SUNRPC: fix NFS client over TCP hangs due to packet loss (Bug 16494)

When reusing a TCP connection, ensure that it's aborted if a previous shutdown attempt has been made on that connection so that the RPC over TCP recovery mechanism succeeds.

# diff -up /home/company/software/src/linux-2.6.34.2/net/sunrpc/xprtsock.c net/sunrpc/xprtsock.c 
--- /home/company/software/src/linux-2.6.34.2/net/sunrpc/xprtsock.c     2010-08-02 18:30:51.000000000 +0100
+++ net/sunrpc/xprtsock.c       2010-08-06 08:09:08.000000000 +0100
@@ -1322,10 +1322,11 @@ static void xs_tcp_state_change(struct s
        if (!(xprt = xprt_from_sock(sk)))
                goto out;
        dprintk("RPC:       xs_tcp_state_change client %p...\n", xprt);
-       dprintk("RPC:       state %x conn %d dead %d zapped %d\n",
+       dprintk("RPC:       state %x conn %d dead %d zapped %d sk_shutdown %d\n",
                        sk->sk_state, xprt_connected(xprt),
                        sock_flag(sk, SOCK_DEAD),
-                       sock_flag(sk, SOCK_ZAPPED));
+                       sock_flag(sk, SOCK_ZAPPED),
+                       sk->sk_shutdown);
 
        switch (sk->sk_state) {
        case TCP_ESTABLISHED:
@@ -1796,10 +1797,25 @@ static void xs_tcp_reuse_connection(stru
 {
        unsigned int state = transport->inet->sk_state;
 
-       if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED)
-               return;
-       if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT))
-               return;
+       if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED) {
+               /* we don't need to abort the connection if the socket
+                * hasn't undergone a shutdown
+                */
+               if (transport->inet->sk_shutdown == 0)
+                       return;
+               dprintk("RPC:       %s: TCP_CLOSEd and sk_shutdown set to %d\n",
+                       __func__, transport->inet->sk_shutdown);
+       }
+       if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT)) {
+               /* we don't need to abort the connection if the socket
+                * hasn't undergone a shutdown
+                */
+               if (transport->inet->sk_shutdown == 0)
+                       return;
+               dprintk("RPC:       %s: ESTABLISHED/SYN_SENT "
+                               "sk_shutdown set to %d\n",
+                               __func__, transport->inet->sk_shutdown);
+       }
        xs_abort_connection(xprt, transport);
 }

Signed-off-by: Andy Chittenden <andyc.bluearc-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] usbnet: rx_submit() should return an error code.
From: David Miller @ 2010-08-10  8:41 UTC (permalink / raw)
  To: oneukum; +Cc: ellyjones, stern, netdev, linux-usb, jglasgow
In-Reply-To: <201008100942.05887.oneukum@suse.de>

From: Oliver Neukum <oneukum@suse.de>
Date: Tue, 10 Aug 2010 09:42:05 +0200

> Am Dienstag, 10. August 2010, 09:18:55 schrieb David Miller:
>> From: Elly Jones <ellyjones@google.com>
>> Date: Mon, 9 Aug 2010 18:37:50 -0400
>> 
>> > This patch makes rx_submit() return an error code, and makes some call sites
>> > that care check the return value. This is important because it lets us properly
>> > handle cases where the device isn't ready to handle URB submissions (e.g., when
>> > it is autosuspended under some drivers); previously, we would attempt and fail
>> > to submit URBs and reschedule ourselves to try and fail again. This patch is
>> > against Linus's 2.6 repo commit 45d7f32c7a43cbb9592886d38190e379e2eb2226.
>> > 
>> > Signed-Off-By: Elizabeth Jones <ellyjones@google.com>
>> 
>> What gets kevent() running again to run the rx_submit() calls when the
>> device comes back from being suspended?
>> 
> 
> usbnet_resume() schedules usbnet_bh() which will take care of that.

That makes sense, I've applied Elizabeth's patch.

But Elizabeth, your patch was severely corrupted by your email client.
Long lines were split up into two, etc.  This corrupts the patch and
makes it unusable for us.  Please make sure that you have fixed your
email client setup for the next patch you submit.

Thanks.

^ permalink raw reply

* Re: [PATCH 1/2] pkt_sched: sch_sfq: Add dummy unbind_tcf and put handles. Was: [PATCH] sfq: add dummy bind/unbind handles
From: David Miller @ 2010-08-10  8:41 UTC (permalink / raw)
  To: jarkao2; +Cc: franchoze, shemminger, netdev
In-Reply-To: <20100809221817.GA18629@del.dom.local>

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Tue, 10 Aug 2010 00:18:17 +0200

> Add dummy .unbind_tcf and .put qdisc class ops for easier verification.
> (All other schedulers have it like this.)
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH 2/2] pkt_sched: Add some basic qdisc class ops verification. Was: [PATCH] sfq: add dummy bind/unbind handles
From: David Miller @ 2010-08-10  8:41 UTC (permalink / raw)
  To: jarkao2; +Cc: franchoze, shemminger, netdev
In-Reply-To: <20100809221848.GB18629@del.dom.local>

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Tue, 10 Aug 2010 00:18:48 +0200

> Verify in register_qdisc() some basic qdisc class handlers are present.
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

Applied.

^ permalink raw reply

* Re: [PATCH 06/18 v2] isdn: avm: call disable_pci_device() if pci_probe() failed
From: David Miller @ 2010-08-10  8:42 UTC (permalink / raw)
  To: segooon; +Cc: kernel-janitors, isdn, adobriyan, tilman, tj, netdev
In-Reply-To: <1281383439-13988-1-git-send-email-segooon@gmail.com>

From: Kulikov Vasiliy <segooon@gmail.com>
Date: Mon,  9 Aug 2010 23:50:37 +0400

> Driver should call disable_pci_device() if it returns from pci_probe()
> with error.
> 
> Signed-off-by: Kulikov Vasiliy <segooon@gmail.com>

Applied, but please fix the template you're using for the commit
message header and the message itself, because in all of your
patches you've transposed "disable" and "pci" in "pci_disable_device()"

So I have to fix it up two times in every patch I apply of your's.

Thanks.

^ permalink raw reply

* Re: [PATCH 07/18 v2] isdn: avm: call disable_pci_device() if pci_probe() failed
From: David Miller @ 2010-08-10  8:43 UTC (permalink / raw)
  To: segooon; +Cc: kernel-janitors, isdn, adobriyan, tilman, netdev
In-Reply-To: <1281383448-14050-1-git-send-email-segooon@gmail.com>

From: Kulikov Vasiliy <segooon@gmail.com>
Date: Mon,  9 Aug 2010 23:50:47 +0400

> Driver should call disable_pci_device() if it returns from pci_probe()
> with error.
> 
> Signed-off-by: Kulikov Vasiliy <segooon@gmail.com>

Applied, but as previously mentioned disable_pci_device() is wrong.

^ permalink raw reply

* Re: [PATCH 09/18 v2] isdn: mISDN: call disable_pci_device() if pci_probe() failed
From: David Miller @ 2010-08-10  8:43 UTC (permalink / raw)
  To: segooon
  Cc: kernel-janitors, isdn, akpm, u.kleine-koenig, peterhuewe, tj,
	netdev
In-Reply-To: <1281383456-14119-1-git-send-email-segooon@gmail.com>

From: Kulikov Vasiliy <segooon@gmail.com>
Date: Mon,  9 Aug 2010 23:50:53 +0400

> Driver should call disable_pci_device() if it returns from pci_probe()
> with error.
> 
> Signed-off-by: Kulikov Vasiliy <segooon@gmail.com>

Also applied, and likewise disable_pci_device() needed to be fixed up.

^ permalink raw reply

* Re: [net-next] net: Use NET_XMIT_SUCCESS where possible.
From: David Miller @ 2010-08-10  8:45 UTC (permalink / raw)
  To: greearb; +Cc: netdev
In-Reply-To: <1281379438-2709-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>
Date: Mon,  9 Aug 2010 11:43:58 -0700

> This is based on work originally done by Patric McHardy.
> 
> Signed-off-by: Ben Greear <greearb@candelatech.com>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH v2]  net: add Fast Ethernet driver for PXA168.
From: Sachin Sanap @ 2010-08-10  8:30 UTC (permalink / raw)
  To: Philip Rakity
  Cc: Lennert Buytenhek, netdev@vger.kernel.org, Ashish Karkare,
	Prabhanjan Sarnaik, eric.y.miao@gmail.com, Mark Brown
In-Reply-To: <FE9BFA4C-11AB-46B9-A514-EB62467A1BB7@marvell.com>

>From 97021af9bc8cb3f4ea9eacaee45e5c9f5d85c9c3 Mon Sep 17 00:00:00 2001
From: Sachin Sanap <ssanap@marvell.com>
Date: Sat, 7 Aug 2010 01:38:46 +0530
Subject: [PATCH] net: add Fast Ethernet driver for PXA168.

Signed-off-by: Sachin Sanap <ssanap@marvell.com>
---
V2:
* Modified the code for endian-cleanness.addr_table_entry variables are now
  declared as __le32 and appropriate cpu_to_le32/le32_to_cpu conversions 
  are used. Code is parsed through sparse with zero errors/warnings.But 
  its not tested on actual Big-endian configuration.

* Modified the hash calculation function and made it more readable, also added
  comments wherever required.

* Moved the pxa168_eth.h file in include/linux.

* Removed the TX_DONE_INTERVAL constant and now the tx done interval is fired
  on every (tx_ring_size / 4).

* Headroom in SKB for 802.11 not included in the patch since that varies based
  on 802.11 a/b/g/n.

* MISC changes:
  * Added comments as to why (init) call back is required.
  * Changed the speed,duplex and phy_addr to int type.
  * "config PXA168_ETH" now "depends on CPU_PXA168".
  * Removed the Marvell OUI and added random_ether_addr.
  * Removed the address alignment code since dma_alloc_coherent already aligns
    it.
  * Misc coding style changes.

 drivers/net/Kconfig        |   10 +
 drivers/net/Makefile       |    1 +
 drivers/net/pxa168_eth.c   | 1569 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pxa168_eth.h |   20 +
 4 files changed, 1600 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/pxa168_eth.c
 create mode 100644 include/linux/pxa168_eth.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd..78cd7e8 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -927,6 +927,16 @@ config SMC91X
 	  The module will be called smc91x.  If you want to compile it as a
 	  module, say M here and read <file:Documentation/kbuild/modules.txt>.
 
+config PXA168_ETH
+	tristate "Marvell pxa168 ethernet support"
+	depends on CPU_PXA168
+	select PHYLIB
+	help
+	  This driver supports the pxa168 Ethernet ports.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called pxa168_eth.
+
 config NET_NETX
 	tristate "NetX Ethernet support"
 	select MII
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512a..a42d437 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -244,6 +244,7 @@ obj-$(CONFIG_MYRI10GE) += myri10ge/
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
 obj-$(CONFIG_SMSC911X) += smsc911x.o
+obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
 obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o
diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c
new file mode 100644
index 0000000..f5a65c8
--- /dev/null
+++ b/drivers/net/pxa168_eth.c
@@ -0,0 +1,1569 @@
+/*
+ * PXA168 ethernet driver.
+ * Most of the code is derived from mv643xx ethernet driver.
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *		Sachin Sanap <ssanap@marvell.com>
+ *		Philip Rakity <prakity@marvell.com>
+ *		Mark Brown <markb@marvell.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/etherdevice.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <linux/pxa168_eth.h>
+
+#define DRIVER_NAME	"pxa168-eth"
+#define DRIVER_VERSION	"0.3"
+
+/*
+ * Registers
+ */
+
+#define PHY_ADDRESS		0x0000
+#define SMI			0x0010
+#define PORT_CONFIG		0x0400
+#define PORT_CONFIG_EXT		0x0408
+#define PORT_COMMAND		0x0410
+#define PORT_STATUS		0x0418
+#define HTPR			0x0428
+#define SDMA_CONFIG		0x0440
+#define SDMA_CMD		0x0448
+#define INT_CAUSE		0x0450
+#define INT_W_CLEAR		0x0454
+#define INT_MASK		0x0458
+#define ETH_F_RX_DESC_0		0x0480
+#define ETH_C_RX_DESC_0		0x04A0
+#define ETH_C_TX_DESC_1		0x04E4
+
+/* smi register */
+#define SMI_BUSY		(1 << 28)	/* 0 - Write, 1 - Read  */
+#define SMI_R_VALID		(1 << 27)	/* 0 - Write, 1 - Read  */
+#define SMI_OP_W		(0 << 26)	/* Write operation      */
+#define SMI_OP_R		(1 << 26)	/* Read operation */
+
+#define PHY_WAIT_ITERATIONS	500
+
+#define PXA168_ETH_PHY_ADDR_DEFAULT	0
+/* RX & TX descriptor command */
+#define BUF_OWNED_BY_DMA	(1 << 31)
+
+/* RX descriptor status */
+#define RX_EN_INT		(1 << 23)
+#define RX_FIRST_DESC		(1 << 17)
+#define RX_LAST_DESC		(1 << 16)
+#define RX_ERROR		(1 << 15)
+
+/* TX descriptor command */
+#define TX_EN_INT		(1 << 23)
+#define TX_GEN_CRC		(1 << 22)
+#define TX_ZERO_PADDING		(1 << 18)
+#define TX_FIRST_DESC		(1 << 17)
+#define TX_LAST_DESC		(1 << 16)
+#define TX_ERROR		(1 << 15)
+
+/* SDMA_CMD */
+#define SDMA_CMD_AT		(1 << 31)
+#define SDMA_CMD_TXDL		(1 << 24)
+#define SDMA_CMD_TXDH		(1 << 23)
+#define SDMA_CMD_AR		(1 << 15)
+#define SDMA_CMD_ERD		(1 << 7)
+
+/* Bit definitions of the Port Config Reg */
+#define PCR_HS			(1 << 12)
+#define PCR_EN			(1 << 7)
+#define PCR_PM			(1 << 0)
+
+/* Bit definitions of the Port Config Extend Reg */
+#define PCXR_2BSM		(1 << 28)
+#define PCXR_DSCP_EN		(1 << 21)
+#define PCXR_MFL_1518		(0 << 14)
+#define PCXR_MFL_1536		(1 << 14)
+#define PCXR_MFL_2048		(2 << 14)
+#define PCXR_MFL_64K		(3 << 14)
+#define PCXR_FLP		(1 << 11)
+#define PCXR_PRIO_TX_OFF	3
+#define PCXR_TX_HIGH_PRI	(7 << PCXR_PRIO_TX_OFF)
+
+/* Bit definitions of the SDMA Config Reg */
+#define SDCR_BSZ_OFF		12
+#define SDCR_BSZ8		(3 << SDCR_BSZ_OFF)
+#define SDCR_BSZ4		(2 << SDCR_BSZ_OFF)
+#define SDCR_BSZ2		(1 << SDCR_BSZ_OFF)
+#define SDCR_BSZ1		(0 << SDCR_BSZ_OFF)
+#define SDCR_BLMR		(1 << 6)
+#define SDCR_BLMT		(1 << 7)
+#define SDCR_RIFB		(1 << 9)
+#define SDCR_RC_OFF		2
+#define SDCR_RC_MAX_RETRANS	(0xf << SDCR_RC_OFF)
+
+/*
+ * Bit definitions of the Interrupt Cause Reg
+ * and Interrupt MASK Reg is the same
+ */
+#define ICR_RXBUF		(1 << 0)
+#define ICR_TXBUF_H		(1 << 2)
+#define ICR_TXBUF_L		(1 << 3)
+#define ICR_TXEND_H		(1 << 6)
+#define ICR_TXEND_L		(1 << 7)
+#define ICR_RXERR		(1 << 8)
+#define ICR_TXERR_H		(1 << 10)
+#define ICR_TXERR_L		(1 << 11)
+#define ICR_TX_UDR		(1 << 13)
+#define ICR_MII_CH		(1 << 28)
+
+#define ALL_INTS (ICR_TXBUF_H  | ICR_TXBUF_L  | ICR_TX_UDR |\
+				ICR_TXERR_H  | ICR_TXERR_L |\
+				ICR_TXEND_H  | ICR_TXEND_L |\
+				ICR_RXBUF | ICR_RXERR  | ICR_MII_CH)
+
+#define ETH_HW_IP_ALIGN		2	/* hw aligns IP header */
+#define ETH_DATA_LEN		1500
+#define MAX_PKT_SIZE		1518
+
+#define NUM_RX_DESCS		64
+#define NUM_TX_DESCS		64
+#define MAX_DESCS_PER_HIGH	(60)
+#define TX_DESC_COUNT_LOW	(10)
+
+#define HASH_ADD		0
+#define HASH_DELETE		1
+#define HASH_ADDR_TABLE_SIZE	0x4000	/* 16K (1/2K address - PCR_HS == 1) */
+#define HOP_NUMBER		12
+
+/* Bit definitions for Port status */
+#define PORT_SPEED_100		(1 << 0)
+#define FULL_DUPLEX		(1 << 1)
+#define FLOW_CONTROL_ENABLED	(1 << 2)
+#define LINK_UP			(1 << 3)
+
+/* Bit definitions for work to be done */
+#define WORK_LINK		(1 << 0)
+#define WORK_TX_DONE		(1 << 1)
+
+struct rx_desc {
+	u32 cmd_sts;		/* Descriptor command status            */
+	u16 byte_cnt;		/* Descriptor buffer byte count         */
+	u16 buf_size;		/* Buffer size                          */
+	u32 buf_ptr;		/* Descriptor buffer pointer            */
+	u32 next_desc_ptr;	/* Next descriptor pointer              */
+};
+
+struct tx_desc {
+	u32 cmd_sts;		/* Command/status field                 */
+	u16 reserved;
+	u16 byte_cnt;		/* buffer byte count                    */
+	u32 buf_ptr;		/* pointer to buffer for this descriptor */
+	u32 next_desc_ptr;	/* Pointer to next descriptor           */
+};
+
+struct pxa168_eth_private {
+	int rx_resource_err;	/* Rx ring resource error flag */
+
+	/* Next available and first returning Rx resource */
+	int rx_curr_desc_q, rx_used_desc_q;
+
+	/* Next available and first returning Tx resource */
+	int tx_curr_desc_q, tx_used_desc_q;
+
+	struct rx_desc *p_rx_desc_area;
+	dma_addr_t rx_desc_dma;
+	int rx_desc_area_size;
+	struct sk_buff **rx_skb;
+
+	struct tx_desc *p_tx_desc_area;
+	dma_addr_t tx_desc_dma;
+	int tx_desc_area_size;
+	struct sk_buff **tx_skb;
+
+	struct work_struct tx_timeout_task;
+
+	struct net_device *dev;
+	struct napi_struct napi;
+	u8 work_todo;
+
+	struct net_device_stats stats;
+	/* Size of Tx Ring per queue */
+	int tx_ring_size;
+	/* Number of tx descriptors in use */
+	int tx_desc_count;
+	/* Size of Rx Ring per queue */
+	int rx_ring_size;
+	/* Number of rx descriptors in use */
+	int rx_desc_count;
+
+	/*
+	 * Used in case RX Ring is empty, which can occur when
+	 * system does not have resources (skb's)
+	 */
+	struct timer_list timeout;
+	struct mii_bus *smi_bus;
+	struct phy_device *phy;
+
+	/* clock */
+	struct clk *clk;
+	struct pxa168_eth_platform_data *pd;
+	/*
+	 * Ethernet controller base address.
+	 */
+	void __iomem *base;
+
+	/* Pointer to the hardware address filter table */
+	void *htpr;
+	dma_addr_t htpr_dma;
+};
+
+struct addr_table_entry {
+	__le32 lo;
+	__le32 hi;
+};
+
+/* Bit fields of a Hash Table Entry */
+enum hash_table_entry {
+	HASH_ENTRY_VALID = 1,
+	SKIP = 2,
+	HASH_ENTRY_RECEIVE_DISCARD = 4,
+	HASH_ENTRY_RECEIVE_DISCARD_BIT = 2
+};
+
+static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
+static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd);
+static int pxa168_init_hw(struct pxa168_eth_private *pep);
+static void eth_port_reset(struct net_device *dev);
+static void eth_port_start(struct net_device *dev);
+static int pxa168_eth_open(struct net_device *dev);
+static int pxa168_eth_stop(struct net_device *dev);
+static int ethernet_phy_setup(struct net_device *dev);
+
+static inline u32 rdl(struct pxa168_eth_private *pep, int offset)
+{
+	return readl(pep->base + offset);
+}
+
+static inline void wrl(struct pxa168_eth_private *pep, int offset, u32 data)
+{
+	writel(data, pep->base + offset);
+}
+
+static void abort_dma(struct pxa168_eth_private *pep)
+{
+	int delay;
+	int max_retries = 40;
+
+	do {
+		wrl(pep, SDMA_CMD, SDMA_CMD_AR | SDMA_CMD_AT);
+		udelay(100);
+
+		delay = 10;
+		while ((rdl(pep, SDMA_CMD) & (SDMA_CMD_AR | SDMA_CMD_AT))
+		       && delay-- > 0) {
+			udelay(10);
+		}
+	} while (max_retries-- > 0 && delay <= 0);
+
+	if (max_retries <= 0)
+		printk(KERN_ERR "%s : DMA Stuck\n", __func__);
+}
+
+static int ethernet_phy_get(struct pxa168_eth_private *pep)
+{
+	unsigned int reg_data;
+
+	reg_data = rdl(pep, PHY_ADDRESS);
+
+	return reg_data & 0x1f;
+}
+
+static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr)
+{
+	u32 reg_data;
+
+	reg_data = rdl(pep, PHY_ADDRESS);
+	reg_data &= ~(0x1f);
+	reg_data |= phy_addr & 0x1f;
+	wrl(pep, PHY_ADDRESS, reg_data);
+}
+
+static void ethernet_phy_reset(struct pxa168_eth_private *pep)
+{
+	int data;
+
+	data = phy_read(pep->phy, MII_BMCR);
+	if (data < 0)
+		return;
+
+	data |= BMCR_RESET;
+	if (phy_write(pep->phy, MII_BMCR, data) < 0)
+		return;
+
+	do {
+		data = phy_read(pep->phy, MII_BMCR);
+	} while (data >= 0 && data & BMCR_RESET);
+}
+
+static void rxq_refill(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct rx_desc *p_used_rx_desc;
+	int used_rx_desc;
+
+	while (pep->rx_desc_count < pep->rx_ring_size) {
+		skb = dev_alloc_skb(MAX_PKT_SIZE + ETH_HW_IP_ALIGN);
+		if (!skb)
+			break;
+		pep->rx_desc_count++;
+		/* Get 'used' Rx descriptor */
+		used_rx_desc = pep->rx_used_desc_q;
+		p_used_rx_desc = &pep->p_rx_desc_area[used_rx_desc];
+		p_used_rx_desc->buf_ptr = dma_map_single(NULL,
+							 skb->data,
+							 MAX_PKT_SIZE +
+							 ETH_HW_IP_ALIGN,
+							 DMA_FROM_DEVICE);
+		p_used_rx_desc->buf_size = MAX_PKT_SIZE + ETH_HW_IP_ALIGN;
+		pep->rx_skb[used_rx_desc] = skb;
+
+		/* Return the descriptor to DMA ownership */
+		wmb();
+		p_used_rx_desc->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT;
+		wmb();
+
+		/* Move the used descriptor pointer to the next descriptor */
+		pep->rx_used_desc_q = (used_rx_desc + 1) % pep->rx_ring_size;
+
+		/* Any Rx return cancels the Rx resource error status */
+		pep->rx_resource_err = 0;
+
+		skb_reserve(skb, ETH_HW_IP_ALIGN);
+	}
+
+	/*
+	 * If RX ring is empty of SKB, set a timer to try allocating
+	 * again at a later time.
+	 */
+	if (pep->rx_desc_count == 0) {
+		pep->timeout.expires = jiffies + (HZ / 10);
+		add_timer(&pep->timeout);
+	}
+}
+
+static inline void rxq_refill_timer_wrapper(unsigned long data)
+{
+	struct pxa168_eth_private *pep = (void *)data;
+	napi_schedule(&pep->napi);
+}
+
+static inline u8 flip_8_bits(u8 x)
+{
+	return (((x) & 0x01) << 3) | (((x) & 0x002) << 1)
+	    | (((x) & 0x04) >> 1) | (((x) & 0x008) >> 3)
+	    | (((x) & 0x10) << 3) | (((x) & 0x20) << 1)
+	    | (((x) & 0x40) >> 1) | (((x) & 0x80) >> 3);
+}
+
+static void nibble_swap_every_byte(unsigned char *mac_addr)
+{
+	int i;
+	for (i = 0; i < ETH_ALEN; i++) {
+		mac_addr[i] = ((mac_addr[i] & 0x0f) << 4) |
+				((mac_addr[i] & 0xf0) >> 4);
+	}
+}
+
+static void inverse_every_nibble(unsigned char *mac_addr)
+{
+	int i;
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_addr[i] = flip_8_bits(mac_addr[i]);
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * This function will calculate the hash function of the address.
+ * Inputs
+ * mac_addr_orig    - MAC address.
+ * Outputs
+ * return the calculated entry.
+ */
+static u32 hash_function(unsigned char *mac_addr_orig)
+{
+	u32 hash_result;
+	u32 addr0;
+	u32 addr1;
+	u32 addr2;
+	u32 addr3;
+	unsigned char mac_addr[ETH_ALEN];
+
+	/* Make a copy of MAC address since we are going to performe bit
+	 * operations on it
+	 */
+	memcpy(mac_addr, mac_addr_orig, ETH_ALEN);
+
+	nibble_swap_every_byte(mac_addr);
+	inverse_every_nibble(mac_addr);
+
+	addr0 = (mac_addr[5] >> 2) & 0x03f;
+	addr1 = (mac_addr[5] & 0x003) | (((mac_addr[4] & 0x7f)) << 2);
+	addr2 = ((mac_addr[4] & 0x80) >> 7) | mac_addr[3] << 1;
+	addr3 = (mac_addr[2] & 0x0ff) | ((mac_addr[1] & 1) << 8);
+
+	hash_result = (addr0 << 9) | (addr1 ^ addr2 ^ addr3);
+	hash_result = hash_result & 0x07ff;
+	return hash_result;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * This function will add/del an entry to the address table.
+ * Inputs
+ * pep - ETHERNET .
+ * mac_addr - MAC address.
+ * skip - if 1, skip this address.Used in case of deleting an entry which is a
+ *	  part of chain in the hash table.We cant just delete the entry since
+ *	  that will break the chain.We need to defragment the tables time to
+ *	  time.
+ * rd   - 0 Discard packet upon match.
+ *	- 1 Receive packet upon match.
+ * Outputs
+ * address table entry is added/deleted.
+ * 0 if success.
+ * -ENOSPC if table full
+ */
+static int add_del_hash_entry(struct pxa168_eth_private *pep,
+			      unsigned char *mac_addr,
+			      u32 rd, u32 skip, int del)
+{
+	struct addr_table_entry *entry, *start;
+	u32 new_high;
+	u32 new_low;
+	u32 i;
+
+	new_low = (((mac_addr[1] >> 4) & 0xf) << 15)
+	    | (((mac_addr[1] >> 0) & 0xf) << 11)
+	    | (((mac_addr[0] >> 4) & 0xf) << 7)
+	    | (((mac_addr[0] >> 0) & 0xf) << 3)
+	    | (((mac_addr[3] >> 4) & 0x1) << 31)
+	    | (((mac_addr[3] >> 0) & 0xf) << 27)
+	    | (((mac_addr[2] >> 4) & 0xf) << 23)
+	    | (((mac_addr[2] >> 0) & 0xf) << 19)
+	    | (skip << SKIP) | (rd << HASH_ENTRY_RECEIVE_DISCARD_BIT)
+	    | HASH_ENTRY_VALID;
+
+	new_high = (((mac_addr[5] >> 4) & 0xf) << 15)
+	    | (((mac_addr[5] >> 0) & 0xf) << 11)
+	    | (((mac_addr[4] >> 4) & 0xf) << 7)
+	    | (((mac_addr[4] >> 0) & 0xf) << 3)
+	    | (((mac_addr[3] >> 5) & 0x7) << 0);
+
+	/*
+	 * Pick the appropriate table, start scanning for free/reusable
+	 * entries at the index obtained by hashing the specified MAC address
+	 */
+	start = (struct addr_table_entry *)(pep->htpr);
+	entry = start + hash_function(mac_addr);
+	for (i = 0; i < HOP_NUMBER; i++) {
+		if (!(le32_to_cpu(entry->lo) & HASH_ENTRY_VALID)) {
+			break;
+		} else {
+			/* if same address put in same position */
+			if (((le32_to_cpu(entry->lo) & 0xfffffff8) ==
+				(new_low & 0xfffffff8)) &&
+				(le32_to_cpu(entry->hi) == new_high)) {
+				break;
+			}
+		}
+		if (entry == start + 0x7ff)
+			entry = start;
+		else
+			entry++;
+	}
+
+	if (((le32_to_cpu(entry->lo) & 0xfffffff8) != (new_low & 0xfffffff8)) &&
+	    (le32_to_cpu(entry->hi) != new_high) && del)
+		return 0;
+
+	if (i == HOP_NUMBER) {
+		if (!del) {
+			printk(KERN_INFO "%s: table section is full\n",
+			       __FILE__);
+			return -ENOSPC;
+		} else
+			return 0;
+	}
+
+	/*
+	 * Update the selected entry
+	 */
+	if (del) {
+		entry->hi = 0;
+		entry->lo = 0;
+	} else {
+		entry->hi = cpu_to_le32(new_high);
+		entry->lo = cpu_to_le32(new_low);
+	}
+
+	return 0;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ *  Create an addressTable entry from MAC address info
+ *  found in the specifed net_device struct
+ *
+ *  Input : pointer to ethernet interface network device structure
+ *  Output : N/A
+ */
+static void update_hash_table_mac_address(struct pxa168_eth_private *pep,
+					  unsigned char *oaddr,
+					  unsigned char *addr)
+{
+	/* Delete old entry */
+	if (oaddr)
+		add_del_hash_entry(pep, oaddr, 1, 0, HASH_DELETE);
+	/* Add new entry */
+	add_del_hash_entry(pep, addr, 1, 0, HASH_ADD);
+}
+
+static int init_hash_table(struct pxa168_eth_private *pep)
+{
+	/*
+	 * Hardware expects CPU to build a hash table based on a predefined
+	 * hash function and populate it based on hardware address. The
+	 * location of the hash table is identified by 32-bit pointer stored
+	 * in HTPR internal register. Two possible sizes exists for the hash
+	 * table 8kB (256kB of DRAM required (4 x 64 kB banks)) and 1/2kB
+	 * (16kB of DRAM required (4 x 4 kB banks)).We currently only support
+	 * 1/2kB.
+	 */
+	/* TODO: Add support for 8kB hash table and alternative hash
+	 * function.Driver can dynamically switch to them if the 1/2kB hash
+	 * table is full.
+	 */
+	if (pep->htpr == NULL) {
+		pep->htpr = dma_alloc_coherent(NULL,
+					      HASH_ADDR_TABLE_SIZE,
+					      &pep->htpr_dma, GFP_KERNEL);
+		if (pep->htpr == NULL)
+			return -ENOMEM;
+	}
+	memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE);
+	wrl(pep, HTPR, pep->htpr_dma);
+	return 0;
+}
+
+static void pxa168_eth_set_rx_mode(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct netdev_hw_addr *ha;
+	u32 val;
+
+	val = rdl(pep, PORT_CONFIG);
+	if (dev->flags & IFF_PROMISC)
+		val |= PCR_PM;
+	else
+		val &= ~PCR_PM;
+	wrl(pep, PORT_CONFIG, val);
+	netdev_for_each_mc_addr(ha, dev)
+	    update_hash_table_mac_address(pep, NULL, ha->addr);
+}
+
+static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sa = addr;
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	unsigned char oldMac[ETH_ALEN];
+
+	if (!is_valid_ether_addr(sa->sa_data))
+		return -EINVAL;
+	memcpy(oldMac, dev->dev_addr, ETH_ALEN);
+	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
+	netif_addr_lock_bh(dev);
+	update_hash_table_mac_address(pep, oldMac, dev->dev_addr);
+	netif_addr_unlock_bh(dev);
+	return 0;
+}
+
+static void eth_port_start(struct net_device *dev)
+{
+	unsigned int val = 0;
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	int tx_curr_desc, rx_curr_desc;
+
+	/* Perform PHY reset, if there is a PHY. */
+	if (pep->phy != NULL) {
+		struct ethtool_cmd cmd;
+
+		pxa168_get_settings(pep->dev, &cmd);
+		ethernet_phy_reset(pep);
+		pxa168_set_settings(pep->dev, &cmd);
+	}
+
+	/* Assignment of Tx CTRP of given queue */
+	tx_curr_desc = pep->tx_curr_desc_q;
+	wrl(pep, ETH_C_TX_DESC_1,
+	    (u32) ((struct tx_desc *)pep->tx_desc_dma + tx_curr_desc));
+
+	/* Assignment of Rx CRDP of given queue */
+	rx_curr_desc = pep->rx_curr_desc_q;
+	wrl(pep, ETH_C_RX_DESC_0,
+	    (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc));
+
+	wrl(pep, ETH_F_RX_DESC_0,
+	    (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc));
+
+	/* Clear all interrupts */
+	wrl(pep, INT_CAUSE, 0);
+
+	/* Enable all interrupts for receive, transmit and error. */
+	wrl(pep, INT_MASK, ALL_INTS);
+
+	val = rdl(pep, PORT_CONFIG);
+	val |= PCR_EN;
+	wrl(pep, PORT_CONFIG, val);
+
+	/* Start RX DMA engine */
+	val = rdl(pep, SDMA_CMD);
+	val |= SDMA_CMD_ERD;
+	wrl(pep, SDMA_CMD, val);
+}
+
+static void eth_port_reset(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	unsigned int val = 0;
+
+	/* Stop all interrupts for receive, transmit and error. */
+	wrl(pep, INT_MASK, 0);
+
+	/* Clear all interrupts */
+	wrl(pep, INT_CAUSE, 0);
+
+	/* Stop RX DMA */
+	val = rdl(pep, SDMA_CMD);
+	val &= ~SDMA_CMD_ERD;	/* abort dma command */
+
+	/* Abort any transmit and receive operations and put DMA
+	 * in idle state.
+	 */
+	abort_dma(pep);
+
+	/* Disable port */
+	val = rdl(pep, PORT_CONFIG);
+	val &= ~PCR_EN;
+	wrl(pep, PORT_CONFIG, val);
+}
+
+/*
+ * txq_reclaim - Free the tx desc data for completed descriptors
+ * If force is non-zero, frees uncompleted descriptors as well
+ */
+static int txq_reclaim(struct net_device *dev, int force)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct tx_desc *desc;
+	u32 cmd_sts;
+	struct sk_buff *skb;
+	int tx_index;
+	dma_addr_t addr;
+	int count;
+	int released = 0;
+
+	netif_tx_lock(dev);
+
+	pep->work_todo &= ~(WORK_TX_DONE);
+	while (pep->tx_desc_count > 0) {
+		tx_index = pep->tx_used_desc_q;
+		desc = &pep->p_tx_desc_area[tx_index];
+		cmd_sts = desc->cmd_sts;
+		if (!force && (cmd_sts & BUF_OWNED_BY_DMA)) {
+			if (released > 0) {
+				goto txq_reclaim_end;
+			} else {
+				released = -1;
+				goto txq_reclaim_end;
+			}
+		}
+		pep->tx_used_desc_q = (tx_index + 1) % pep->tx_ring_size;
+		pep->tx_desc_count--;
+		addr = desc->buf_ptr;
+		count = desc->byte_cnt;
+		skb = pep->tx_skb[tx_index];
+		if (skb)
+			pep->tx_skb[tx_index] = NULL;
+
+		if (cmd_sts & TX_ERROR) {
+			if (net_ratelimit())
+				printk(KERN_ERR "%s: Error in TX\n", dev->name);
+			dev->stats.tx_errors++;
+		}
+		dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE);
+		if (skb)
+			dev_kfree_skb_irq(skb);
+		released++;
+	}
+txq_reclaim_end:
+	netif_tx_unlock(dev);
+	return released;
+}
+
+static void pxa168_eth_tx_timeout(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	printk(KERN_INFO "%s: TX timeout  desc_count %d\n",
+	       dev->name, pep->tx_desc_count);
+
+	schedule_work(&pep->tx_timeout_task);
+}
+
+static void pxa168_eth_tx_timeout_task(struct work_struct *work)
+{
+	struct pxa168_eth_private *pep = container_of(work,
+						 struct pxa168_eth_private,
+						 tx_timeout_task);
+	struct net_device *dev = pep->dev;
+	pxa168_eth_stop(dev);
+	pxa168_eth_open(dev);
+}
+
+static int rxq_process(struct net_device *dev, int budget)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	unsigned int received_packets = 0;
+	struct sk_buff *skb;
+
+	while (budget-- > 0) {
+
+		int rx_next_curr_desc, rx_curr_desc, rx_used_desc;
+		struct rx_desc *rx_desc;
+		unsigned int cmd_sts;
+
+		/* Do not process Rx ring in case of Rx ring resource error */
+		if (pep->rx_resource_err)
+			break;
+		rx_curr_desc = pep->rx_curr_desc_q;
+		rx_used_desc = pep->rx_used_desc_q;
+		rx_desc = &pep->p_rx_desc_area[rx_curr_desc];
+		cmd_sts = rx_desc->cmd_sts;
+		rmb();
+		if (cmd_sts & (BUF_OWNED_BY_DMA))
+			break;
+		skb = pep->rx_skb[rx_curr_desc];
+		pep->rx_skb[rx_curr_desc] = NULL;
+
+		rx_next_curr_desc = (rx_curr_desc + 1) % pep->rx_ring_size;
+		pep->rx_curr_desc_q = rx_next_curr_desc;
+
+		/* Rx descriptors exhausted. */
+		/* Set the Rx ring resource error flag */
+		if (rx_next_curr_desc == rx_used_desc)
+			pep->rx_resource_err = 1;
+		pep->rx_desc_count--;
+		dma_unmap_single(NULL, rx_desc->buf_ptr,
+				 MAX_PKT_SIZE + ETH_HW_IP_ALIGN,
+				 DMA_FROM_DEVICE);
+		received_packets++;
+		/*
+		 * Update statistics.
+		 * Note byte count includes 4 byte CRC count
+		 */
+		stats->rx_packets++;
+		stats->rx_bytes += rx_desc->byte_cnt;
+		/*
+		 * In case received a packet without first / last bits on OR
+		 * the error summary bit is on, the packets needs to be droped.
+		 */
+		if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
+		     (RX_FIRST_DESC | RX_LAST_DESC))
+		    || (cmd_sts & RX_ERROR)) {
+
+			stats->rx_dropped++;
+			if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) !=
+			    (RX_FIRST_DESC | RX_LAST_DESC)) {
+				if (net_ratelimit())
+					printk(KERN_ERR
+					       "%s: Rx pkt on multiple desc\n",
+					       dev->name);
+			}
+			if (cmd_sts & RX_ERROR)
+				stats->rx_errors++;
+			dev_kfree_skb_irq(skb);
+		} else {
+			/*
+			 * The -4 is for the CRC in the trailer of the
+			 * received packet
+			 */
+			skb_put(skb, rx_desc->byte_cnt - 4);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_receive_skb(skb);
+		}
+		dev->last_rx = jiffies;
+	}
+	/* Fill RX ring with skb's */
+	rxq_refill(dev);
+	return received_packets;
+}
+
+static int pxa168_eth_collect_events(struct pxa168_eth_private *pep,
+				     struct net_device *dev)
+{
+	u32 icr;
+	int ret = 0;
+
+	icr = rdl(pep, INT_CAUSE);
+	if (0x00 == icr)
+		return IRQ_NONE;
+
+	wrl(pep, INT_CAUSE, icr ^ 0xffffffff);
+	if (icr & (ICR_TXBUF_H | ICR_TXBUF_L)) {
+		pep->work_todo |= WORK_TX_DONE;
+		ret = 1;
+	}
+	if (icr & ICR_RXBUF)
+		ret = 1;
+	if (icr & ICR_MII_CH) {
+		pep->work_todo |= WORK_LINK;
+		ret = 1;
+	}
+	return ret;
+}
+
+static void handle_link_event(struct pxa168_eth_private *pep)
+{
+	struct net_device *dev = pep->dev;
+	u32 port_status;
+	int speed;
+	int duplex;
+	int fc;
+
+	port_status = rdl(pep, PORT_STATUS);
+	if (!(port_status & LINK_UP)) {
+		if (netif_carrier_ok(dev)) {
+			printk(KERN_INFO "%s: link down\n", dev->name);
+			netif_carrier_off(dev);
+			txq_reclaim(dev, 1);
+		}
+		return;
+	}
+	if (port_status & PORT_SPEED_100)
+		speed = 100;
+	else
+		speed = 10;
+
+	duplex = (port_status & FULL_DUPLEX) ? 1 : 0;
+	fc = (port_status & FLOW_CONTROL_ENABLED) ? 1 : 0;
+	printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
+	       "flow control %sabled\n", dev->name,
+	       speed, duplex ? "full" : "half", fc ? "en" : "dis");
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+}
+
+static irqreturn_t pxa168_eth_int_handler(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	if (unlikely(!pxa168_eth_collect_events(pep, dev)))
+		return IRQ_NONE;
+	/* Disable interrupts */
+	wrl(pep, INT_MASK, 0);
+	napi_schedule(&pep->napi);
+	return IRQ_HANDLED;
+}
+
+static int set_port_config_ext(struct pxa168_eth_private *pep, int mtu)
+{
+	int mtu_size;
+
+	if ((mtu > ETH_DATA_LEN) || (mtu < 64))
+		return -EINVAL;
+
+	mtu_size = PCXR_MFL_1518;
+	/* Extended Port Configuration */
+	wrl(pep,
+	    PORT_CONFIG_EXT, PCXR_2BSM | /* Two byte suffix aligns IP hdr */
+	    PCXR_DSCP_EN |		 /* Enable DSCP in IP */
+	    mtu_size | PCXR_FLP |	 /* do not force link pass */
+	    PCXR_TX_HIGH_PRI);		 /* Transmit - high priority queue */
+
+	(pep->dev)->mtu = mtu;
+	return 0;
+}
+
+static int pxa168_init_hw(struct pxa168_eth_private *pep)
+{
+	int err = 0;
+
+	/* Disable interrupts */
+	wrl(pep, INT_MASK, 0);
+	wrl(pep, INT_CAUSE, 0);
+	/* Write to ICR to clear interrupts. */
+	wrl(pep, INT_W_CLEAR, 0);
+	/* Abort any transmit and receive operations and put DMA
+	 * in idle state.
+	 */
+	abort_dma(pep);
+	/* Initialize address hash table */
+	err = init_hash_table(pep);
+	if (err)
+		return err;
+	/* SDMA configuration */
+	wrl(pep, SDMA_CONFIG, SDCR_BSZ8 |	/* Burst size = 32 bytes */
+	    SDCR_RIFB |				/* Rx interrupt on frame */
+	    SDCR_BLMT |				/* Little endian transmit */
+	    SDCR_BLMR |				/* Little endian receive */
+	    SDCR_RC_MAX_RETRANS);		/* Max retransmit count */
+	/* Port Configuration */
+	wrl(pep, PORT_CONFIG, PCR_HS);		/* Hash size is 1/2kb */
+	set_port_config_ext(pep, (pep->dev)->mtu);
+	return err;
+}
+
+static int rxq_init(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct rx_desc *p_rx_desc;
+	int size = 0, i = 0;
+	int rx_desc_num = pep->rx_ring_size;
+
+	/* Allocate RX skb rings */
+	pep->rx_skb = kmalloc(sizeof(*pep->rx_skb) * pep->rx_ring_size,
+			     GFP_KERNEL);
+	if (!pep->rx_skb) {
+		printk(KERN_ERR "%s: Cannot alloc RX skb ring\n", dev->name);
+		return -ENOMEM;
+	}
+	/* Allocate RX ring */
+	pep->rx_desc_count = 0;
+	size = pep->rx_ring_size * sizeof(struct rx_desc);
+	pep->rx_desc_area_size = size;
+	pep->p_rx_desc_area = dma_alloc_coherent(NULL, size,
+						&pep->rx_desc_dma, GFP_KERNEL);
+	if (!pep->p_rx_desc_area) {
+		printk(KERN_ERR "%s: Cannot alloc RX ring (size %d bytes)\n",
+		       dev->name, size);
+		goto out;
+	}
+	memset((void *)pep->p_rx_desc_area, 0, size);
+	/* initialize the next_desc_ptr links in the Rx descriptors ring */
+	p_rx_desc = (struct rx_desc *)pep->p_rx_desc_area;
+	for (i = 0; i < rx_desc_num; i++) {
+		p_rx_desc[i].next_desc_ptr = pep->rx_desc_dma +
+		    ((i + 1) % rx_desc_num) * sizeof(struct rx_desc);
+	}
+	/* Save Rx desc pointer to driver struct. */
+	pep->rx_curr_desc_q = 0;
+	pep->rx_used_desc_q = 0;
+	pep->rx_desc_area_size = rx_desc_num * sizeof(struct rx_desc);
+	return 0;
+out:
+	kfree(pep->rx_skb);
+	return -ENOMEM;
+}
+
+static void rxq_deinit(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	int curr;
+
+	/* Free preallocated skb's on RX rings */
+	for (curr = 0; pep->rx_desc_count && curr < pep->rx_ring_size; curr++) {
+		if (pep->rx_skb[curr]) {
+			dev_kfree_skb(pep->rx_skb[curr]);
+			pep->rx_desc_count--;
+		}
+	}
+	if (pep->rx_desc_count)
+		printk(KERN_ERR
+		       "Error in freeing Rx Ring. %d skb's still\n",
+		       pep->rx_desc_count);
+	/* Free RX ring */
+	if (pep->p_rx_desc_area)
+		dma_free_coherent(NULL, pep->rx_desc_area_size,
+				  pep->p_rx_desc_area, pep->rx_desc_dma);
+	kfree(pep->rx_skb);
+}
+
+static int txq_init(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct tx_desc *p_tx_desc;
+	int size = 0, i = 0;
+	int tx_desc_num = pep->tx_ring_size;
+
+	pep->tx_skb = kmalloc(sizeof(*pep->tx_skb) * pep->tx_ring_size,
+			     GFP_KERNEL);
+	if (!pep->tx_skb) {
+		printk(KERN_ERR "%s: Cannot alloc TX skb ring\n", dev->name);
+		return -ENOMEM;
+	}
+	/* Allocate TX ring */
+	pep->tx_desc_count = 0;
+	size = pep->tx_ring_size * sizeof(struct tx_desc);
+	pep->tx_desc_area_size = size;
+	pep->p_tx_desc_area = dma_alloc_coherent(NULL, size,
+						&pep->tx_desc_dma, GFP_KERNEL);
+	if (!pep->p_tx_desc_area) {
+		printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
+		       dev->name, size);
+		goto out;
+	}
+	memset((void *)pep->p_tx_desc_area, 0, pep->tx_desc_area_size);
+	/* Initialize the next_desc_ptr links in the Tx descriptors ring */
+	p_tx_desc = (struct tx_desc *)pep->p_tx_desc_area;
+	for (i = 0; i < tx_desc_num; i++) {
+		p_tx_desc[i].next_desc_ptr = pep->tx_desc_dma +
+		    ((i + 1) % tx_desc_num) * sizeof(struct tx_desc);
+	}
+	pep->tx_curr_desc_q = 0;
+	pep->tx_used_desc_q = 0;
+	pep->tx_desc_area_size = tx_desc_num * sizeof(struct tx_desc);
+	return 0;
+out:
+	kfree(pep->tx_skb);
+	return -ENOMEM;
+}
+
+static void txq_deinit(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	/* Free outstanding skb's on TX ring */
+	txq_reclaim(dev, 1);
+	BUG_ON(pep->tx_used_desc_q != pep->tx_curr_desc_q);
+	/* Free TX ring */
+	if (pep->p_tx_desc_area)
+		dma_free_coherent(NULL, pep->tx_desc_area_size,
+				  pep->p_tx_desc_area, pep->tx_desc_dma);
+	kfree(pep->tx_skb);
+}
+
+static int pxa168_eth_open(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	int err;
+
+	err = request_irq(dev->irq, pxa168_eth_int_handler,
+			  IRQF_DISABLED , dev->name, dev);
+	if (err) {
+		dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n");
+		return -EAGAIN;
+	}
+	pep->rx_resource_err = 0;
+	err = rxq_init(dev);
+	if (err != 0)
+		goto out_free_irq;
+	err = txq_init(dev);
+	if (err != 0)
+		goto out_free_rx_skb;
+	pep->rx_used_desc_q = 0;
+	pep->rx_curr_desc_q = 0;
+
+	/* Fill RX ring with skb's */
+	rxq_refill(dev);
+	pep->rx_used_desc_q = 0;
+	pep->rx_curr_desc_q = 0;
+	netif_carrier_off(dev);
+	eth_port_start(dev);
+	napi_enable(&pep->napi);
+	return 0;
+out_free_rx_skb:
+	rxq_deinit(dev);
+out_free_irq:
+	free_irq(dev->irq, dev);
+	return err;
+}
+
+static int pxa168_eth_stop(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	eth_port_reset(dev);
+
+	/* Disable interrupts */
+	wrl(pep, INT_MASK, 0);
+	wrl(pep, INT_CAUSE, 0);
+	/* Write to ICR to clear interrupts. */
+	wrl(pep, INT_W_CLEAR, 0);
+	napi_disable(&pep->napi);
+	del_timer_sync(&pep->timeout);
+	netif_carrier_off(dev);
+	free_irq(dev->irq, dev);
+	rxq_deinit(dev);
+	txq_deinit(dev);
+	return 0;
+}
+
+static int eth_alloc_tx_desc_index(struct pxa168_eth_private *pep)
+{
+	int tx_desc_curr;
+
+	tx_desc_curr = pep->tx_curr_desc_q;
+	pep->tx_curr_desc_q = (tx_desc_curr + 1) % pep->tx_ring_size;
+	BUG_ON(pep->tx_curr_desc_q == pep->tx_used_desc_q);
+	pep->tx_desc_count++;
+	return tx_desc_curr;
+}
+
+static void eth_tx_submit_descs_for_skb(struct pxa168_eth_private *pep,
+					struct sk_buff *skb)
+{
+	int tx_index;
+	struct tx_desc *desc;
+	int length;
+
+	tx_index = eth_alloc_tx_desc_index(pep);
+	desc = &pep->p_tx_desc_area[tx_index];
+	length = skb->len;
+	pep->tx_skb[tx_index] = skb;
+	desc->byte_cnt = length;
+	desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
+	wmb();
+	desc->cmd_sts = BUF_OWNED_BY_DMA | TX_GEN_CRC | TX_FIRST_DESC |
+			TX_ZERO_PADDING | TX_LAST_DESC;
+	if (unlikely(!(pep->tx_desc_count % (pep->tx_ring_size / 4))))
+		desc->cmd_sts |= TX_EN_INT;
+	wmb();
+	wrl(pep, SDMA_CMD, SDMA_CMD_TXDH | SDMA_CMD_ERD);
+}
+
+static int pxa168_rx_poll(struct napi_struct *napi, int budget)
+{
+	struct pxa168_eth_private *pep =
+	    container_of(napi, struct pxa168_eth_private, napi);
+	struct net_device *dev = pep->dev;
+	int work_done = 0;
+
+	if (unlikely(pep->work_todo & WORK_LINK)) {
+		pep->work_todo &= ~(WORK_LINK);
+		handle_link_event(pep);
+	}
+	/*
+	 * We call txq_reclaim every time since in NAPI interupts are disabled
+	 * and due to this we miss the TX_DONE interrupt,which is not updated in
+	 * interrupt status register.
+	 */
+	txq_reclaim(dev, 0);
+	if (netif_queue_stopped(dev)
+	    && pep->tx_ring_size - pep->tx_desc_count > 1) {
+		netif_wake_queue(dev);
+	}
+	work_done = rxq_process(dev, budget);
+	if (work_done < budget) {
+		napi_complete(napi);
+		wrl(pep, INT_MASK, ALL_INTS);
+	}
+	return work_done;
+}
+
+static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+
+	eth_tx_submit_descs_for_skb(pep, skb);
+	stats->tx_bytes += skb->len;
+	stats->tx_packets++;
+	dev->trans_start = jiffies;
+	if (pep->tx_ring_size - pep->tx_desc_count <= 1) {
+		/* We handled the current skb, but now we are out of space.*/
+		netif_stop_queue(dev);
+	}
+	return NETDEV_TX_OK;
+}
+
+static int pxa168_smi_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+	int val;
+	struct pxa168_eth_private *pep = bus->priv;
+	int i = 0;
+
+	/* wait for the SMI register to become available */
+	for (i = 0; (val = rdl(pep, SMI)) & SMI_BUSY; i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk(KERN_ERR
+			       "pxa168 PHY timeout, val=0x%x\n", val);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+	wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) | SMI_OP_R);
+	/* now wait for the data to be valid */
+	for (i = 0; !((val = rdl(pep, SMI)) & SMI_R_VALID); i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk(KERN_ERR
+			       "pxa168 PHY RD timeout, val=0x%x\n", val);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+	return val & 0xffff;
+}
+
+static int pxa168_smi_write(struct mii_bus *bus, int phy_addr, int regnum,
+			    u16 value)
+{
+	struct pxa168_eth_private *pep = bus->priv;
+	int i;
+
+	/* wait for the SMI register to become available */
+	for (i = 0; rdl(pep, SMI) & SMI_BUSY; i++) {
+		if (i == PHY_WAIT_ITERATIONS) {
+			printk(KERN_ERR "pxa168 PHY busy timeout.\n");
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+	wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) |
+	    SMI_OP_W | (value & 0xffff));
+
+	return 0;
+}
+
+static int pxa168_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr,
+			       int cmd)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	if (pep->phy != NULL)
+		return phy_mii_ioctl(pep->phy, if_mii(ifr), cmd);
+	return -EOPNOTSUPP;
+}
+
+static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr)
+{
+	struct mii_bus *bus = pep->smi_bus;
+	struct phy_device *phydev;
+	int start;
+	int num;
+	int i;
+
+	if (phy_addr == PXA168_ETH_PHY_ADDR_DEFAULT) {
+		/* Scan entire range */
+		start = ethernet_phy_get(pep);
+		num = 32;
+	} else {
+		/* Use phy addr specific to platform */
+		start = phy_addr & 0x1f;
+		num = 1;
+	}
+	phydev = NULL;
+	for (i = 0; i < num; i++) {
+		int addr = (start + i) & 0x1f;
+		if (bus->phy_map[addr] == NULL)
+			mdiobus_scan(bus, addr);
+
+		if (phydev == NULL) {
+			phydev = bus->phy_map[addr];
+			if (phydev != NULL)
+				ethernet_phy_set_addr(pep, addr);
+		}
+	}
+
+	return phydev;
+}
+
+static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex)
+{
+	struct phy_device *phy = pep->phy;
+	ethernet_phy_reset(pep);
+
+	phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII);
+
+	if (speed == 0) {
+		phy->autoneg = AUTONEG_ENABLE;
+		phy->speed = 0;
+		phy->duplex = 0;
+		phy->supported &= PHY_BASIC_FEATURES;
+		phy->advertising = phy->supported | ADVERTISED_Autoneg;
+	} else {
+		phy->autoneg = AUTONEG_DISABLE;
+		phy->advertising = 0;
+		phy->speed = speed;
+		phy->duplex = duplex;
+	}
+	phy_start_aneg(phy);
+}
+
+static int ethernet_phy_setup(struct net_device *dev)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	if (pep->pd != NULL) {
+		if (pep->pd->init)
+			pep->pd->init();
+	}
+	pep->phy = phy_scan(pep, pep->pd->phy_addr & 0x1f);
+	if (pep->phy != NULL)
+		phy_init(pep, pep->pd->speed, pep->pd->duplex);
+	update_hash_table_mac_address(pep, NULL, dev->dev_addr);
+	return 0;
+}
+
+static int get_random_mac_addr(struct net_device *dev)
+{
+	printk(KERN_INFO "%s:Using random mac address\n", dev->name);
+	random_ether_addr(dev->dev_addr);
+	return 0;
+}
+
+static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+	int err;
+
+	err = phy_read_status(pep->phy);
+	if (err == 0)
+		err = phy_ethtool_gset(pep->phy, cmd);
+	return err;
+}
+
+static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	return phy_ethtool_sset(pep->phy, cmd);
+}
+
+static void pxa168_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	strncpy(info->driver, DRIVER_NAME, 32);
+	strncpy(info->version, DRIVER_VERSION, 32);
+	strncpy(info->fw_version, "N/A", 32);
+	strncpy(info->bus_info, "N/A", 32);
+}
+
+static u32 pxa168_get_link(struct net_device *dev)
+{
+	return !!netif_carrier_ok(dev);
+}
+
+static const struct ethtool_ops pxa168_ethtool_ops = {
+	.get_settings = pxa168_get_settings,
+	.set_settings = pxa168_set_settings,
+	.get_drvinfo = pxa168_get_drvinfo,
+	.get_link = pxa168_get_link,
+};
+
+static const struct net_device_ops pxa168_eth_netdev_ops = {
+	.ndo_open = pxa168_eth_open,
+	.ndo_stop = pxa168_eth_stop,
+	.ndo_start_xmit = pxa168_eth_start_xmit,
+	.ndo_set_rx_mode = pxa168_eth_set_rx_mode,
+	.ndo_set_mac_address = pxa168_eth_set_mac_address,
+	.ndo_validate_addr = eth_validate_addr,
+	.ndo_do_ioctl = pxa168_eth_do_ioctl,
+	.ndo_change_mtu = eth_change_mtu,
+	.ndo_tx_timeout = pxa168_eth_tx_timeout,
+};
+
+static int pxa168_eth_probe(struct platform_device *pdev)
+{
+	struct pxa168_eth_private *pep = NULL;
+	struct net_device *dev = NULL;
+	struct resource *res;
+	struct clk *clk;
+	int err;
+
+	printk(KERN_NOTICE "PXA168 10/100 Ethernet Driver\n");
+
+	clk = clk_get(&pdev->dev, "MFUCLK");
+	if (IS_ERR(clk)) {
+		printk(KERN_ERR "fast Ethernet failed to get clock\n");
+		return -ENODEV;
+	}
+	clk_enable(clk);
+
+	dev = alloc_etherdev(sizeof(struct pxa168_eth_private));
+	if (!dev) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	platform_set_drvdata(pdev, dev);
+	pep = netdev_priv(dev);
+	pep->dev = dev;
+	pep->clk = clk;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		err = -ENODEV;
+		goto out;
+	}
+	pep->base = ioremap(res->start, res->end - res->start + 1);
+	if (pep->base == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	BUG_ON(!res);
+	dev->irq = res->start;
+	dev->netdev_ops = &pxa168_eth_netdev_ops;
+	dev->watchdog_timeo = 2 * HZ;
+	dev->base_addr = 0;
+	SET_ETHTOOL_OPS(dev, &pxa168_ethtool_ops);
+
+	INIT_WORK(&pep->tx_timeout_task, pxa168_eth_tx_timeout_task);
+
+	pep->rx_ring_size = NUM_RX_DESCS;
+	pep->tx_ring_size = NUM_TX_DESCS;
+	get_random_mac_addr(dev);
+	pep->pd = pdev->dev.platform_data;
+	netif_napi_add(dev, &pep->napi, pxa168_rx_poll, pep->rx_ring_size);
+
+	memset(&pep->timeout, 0, sizeof(struct timer_list));
+	init_timer(&pep->timeout);
+	pep->timeout.function = rxq_refill_timer_wrapper;
+	pep->timeout.data = (unsigned long)pep;
+
+	pep->smi_bus = mdiobus_alloc();
+	if (pep->smi_bus == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pep->smi_bus->priv = pep;
+	pep->smi_bus->name = "pxa168_eth smi";
+	pep->smi_bus->read = pxa168_smi_read;
+	pep->smi_bus->write = pxa168_smi_write;
+	snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id);
+	pep->smi_bus->parent = &pdev->dev;
+	pep->smi_bus->phy_mask = 0xffffffff;
+	if (mdiobus_register(pep->smi_bus) < 0) {
+		err = -ENOMEM;
+		goto out;
+	}
+	pxa168_init_hw(pep);
+	err = ethernet_phy_setup(dev);
+	if (err)
+		goto out;
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	err = register_netdev(dev);
+	if (err)
+		goto out;
+	return 0;
+out:
+	if (pep->clk) {
+		clk_disable(pep->clk);
+		clk_put(pep->clk);
+		pep->clk = NULL;
+	}
+	if (pep->base) {
+		iounmap(pep->base);
+		pep->base = NULL;
+	}
+	if (dev)
+		free_netdev(dev);
+	return err;
+}
+
+static int pxa168_eth_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct pxa168_eth_private *pep = netdev_priv(dev);
+
+	if (pep->htpr) {
+		dma_free_coherent(NULL, HASH_ADDR_TABLE_SIZE + 7,
+				  pep->htpr, pep->htpr_dma);
+		pep->htpr = NULL;
+	}
+	if (pep->clk) {
+		clk_disable(pep->clk);
+		clk_put(pep->clk);
+		pep->clk = NULL;
+	}
+	if (pep->phy != NULL)
+		phy_detach(pep->phy);
+
+	iounmap(pep->base);
+	pep->base = NULL;
+	unregister_netdev(dev);
+	flush_scheduled_work();
+	free_netdev(dev);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static void pxa168_eth_shutdown(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	eth_port_reset(dev);
+}
+
+#ifdef CONFIG_PM
+static int pxa168_eth_resume(struct platform_device *pdev)
+{
+	return -ENOSYS;
+}
+
+static int pxa168_eth_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return -ENOSYS;
+}
+
+#else
+#define pxa168_eth_resume NULL
+#define pxa168_eth_suspend NULL
+#endif
+
+static struct platform_driver pxa168_eth_driver = {
+	.probe = pxa168_eth_probe,
+	.remove = pxa168_eth_remove,
+	.shutdown = pxa168_eth_shutdown,
+	.resume = pxa168_eth_resume,
+	.suspend = pxa168_eth_suspend,
+	.driver = {
+		   .name = DRIVER_NAME,
+		   },
+};
+
+static int __init pxa168_init_module(void)
+{
+	return platform_driver_register(&pxa168_eth_driver);
+}
+
+static void __exit pxa168_cleanup_module(void)
+{
+	platform_driver_unregister(&pxa168_eth_driver);
+}
+
+module_init(pxa168_init_module);
+module_exit(pxa168_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ethernet driver for Marvell PXA168");
+MODULE_ALIAS("platform:pxa168_eth");
diff --git a/include/linux/pxa168_eth.h b/include/linux/pxa168_eth.h
new file mode 100644
index 0000000..152981c
--- /dev/null
+++ b/include/linux/pxa168_eth.h
@@ -0,0 +1,20 @@
+/*
+ *pxa168 ethernet platform device data definition file.
+ */
+#ifndef __LINUX_PXA168_ETH_H
+#define __LINUX_PXA168_ETH_H
+
+struct pxa168_eth_platform_data {
+	int	phy_addr;
+
+	/* If speed is 0, then speed and duplex are autonegotiated. */
+	int	speed;		/* 0, SPEED_10, SPEED_100 */
+	int	duplex;		/* DUPLEX_HALF or DUPLEX_FULL */
+
+	/* init callback is used for board specific initialization
+	 * e.g on Aspenite its used to initialize the PHY transceiver.
+	 */
+	int (*init)(void);
+};
+
+#endif /* __LINUX_PXA168_ETH_H */
-- 
1.5.3.3




^ permalink raw reply related

* Re: [net-next] net: More verbose message for too-many-orphans.
From: David Miller @ 2010-08-10  8:48 UTC (permalink / raw)
  To: greearb; +Cc: netdev
In-Reply-To: <1281380402-14608-1-git-send-email-greearb@candelatech.com>

From: Ben Greear <greearb@candelatech.com>
Date: Mon,  9 Aug 2010 12:00:02 -0700

> The original message doesn't give much clue as to what
> is actually going wrong or how to fix it.
> 
> Signed-off-by: Ben Greear <greearb@candelatech.com>

Dumping a bunch of values obtainable via sysctl is pointless.

The only non-sysctl value you're dumping is 'orphans' and based upon
the sysctl values you can determine whether it made the check inside
of tcp_too_many_orphans() trigger, and in what way.

I'm not applying this, sorry.

^ permalink raw reply

* Re: Missing device binding relating to tcp_v4_send_reset?
From: David Miller @ 2010-08-10  8:48 UTC (permalink / raw)
  To: greearb; +Cc: netdev, kaber
In-Reply-To: <4C603EF2.9010902@candelatech.com>

From: Ben Greear <greearb@candelatech.com>
Date: Mon, 09 Aug 2010 10:46:26 -0700

> This snippet is from some patches Patrick did for me some time
> back.  I think the rest of his work has been merged upstream, but
> this patch was not.  I'm honestly not sure if it's needed or not,
> but we've been running with it for at least a year or so and it's
> been working fine for us.

There is no reason at all to force a reply to a packet to
go out of the same interface as the packet which triggered
that reply arrived upon.

^ permalink raw reply

* [PATCH] iputils: firewall mark option in tracepath/tracepath6
From: Антон Д. @ 2010-08-10  9:17 UTC (permalink / raw)
  To: netdev

diff --git a/tracepath.c b/tracepath.c
index 81c22e9..6675f14 100644
--- a/tracepath.c
+++ b/tracepath.c
@@ -42,6 +42,7 @@ __u16 base_port;

 const int overhead = 28;
 int mtu = 65535;
+int mark = 0;
 int hops_to = -1;
 int hops_from = -1;
 int no_resolve = 0;
@@ -285,7 +286,7 @@ static void usage(void) __attribute((noreturn));

 static void usage(void)
 {
-	fprintf(stderr, "Usage: tracepath [-n] [-b] [-l <len>]
<destination>[/<port>]\n");
+	fprintf(stderr, "Usage: tracepath [-n] [-b] [-l <len>] [-m <mark>]
<destination>[/<port>]\n");
 	exit(-1);
 }

@@ -299,7 +300,7 @@ main(int argc, char **argv)
 	char *p;
 	int ch;

-	while ((ch = getopt(argc, argv, "nbh?l:")) != EOF) {
+	while ((ch = getopt(argc, argv, "nbh?l:m:")) != EOF) {
 		switch(ch) {
 		case 'n':
 			no_resolve = 1;
@@ -313,6 +314,9 @@ main(int argc, char **argv)
 				exit(1);
 			}
 			break;
+		case 'm':
+		  	mark = atoi(optarg);
+		  	break;
 		default:
 			usage();
 		}
@@ -345,6 +349,12 @@ main(int argc, char **argv)
 	}
 	memcpy(&target.sin_addr, he->h_addr, 4);

+	if (mark) {
+		if (setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) == -1) {
+			fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
+		}
+	}
+
 	on = IP_PMTUDISC_PROBE;
 	if (setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &on, sizeof(on)) &&
 	    (on = IP_PMTUDISC_DO,
diff --git a/tracepath6.c b/tracepath6.c
index 5cc7424..5d08c62 100644
--- a/tracepath6.c
+++ b/tracepath6.c
@@ -52,6 +52,7 @@ socklen_t targetlen;
 __u16 base_port;

 int overhead = 48;
+int mark = 0;
 int mtu = 128000;
 int hops_to = -1;
 int hops_from = -1;
@@ -359,7 +360,7 @@ static void usage(void) __attribute((noreturn));

 static void usage(void)
 {
-	fprintf(stderr, "Usage: tracepath6 [-n] [-b] [-l <len>]
<destination>[/<port>]\n");
+	fprintf(stderr, "Usage: tracepath6 [-n] [-b] [-l <len>] [-m <mark>]
<destination>[/<port>]\n");
 	exit(-1);
 }

@@ -375,7 +376,7 @@ int main(int argc, char **argv)
 	int gai;
 	char pbuf[NI_MAXSERV];

-	while ((ch = getopt(argc, argv, "nbh?l:")) != EOF) {
+	while ((ch = getopt(argc, argv, "nbh?l:m:")) != EOF) {
 		switch(ch) {
 		case 'n':
 			no_resolve = 1;
@@ -389,6 +390,9 @@ int main(int argc, char **argv)
 				exit(1);
 			}
 			break;
+		case 'm':
+			mark = atoi(optarg);
+			break;
 		default:
 			usage();
 		}
@@ -439,6 +443,12 @@ int main(int argc, char **argv)
 	}
 	freeaddrinfo(ai0);

+	if (mark) {
+		if (setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) == -1) {
+			fprintf(stderr, "Warning: Failed to set mark %d\n", mark);
+		}
+	}
+
 	switch (family) {
 	case AF_INET6:
 		mtu = 128000;

^ permalink raw reply related

* Re: [RFC PATCH 2/2] igb/ixgbe: add code to trigger function reset if reset_devices is set
From: Kenji Kaneshige @ 2010-08-10  9:31 UTC (permalink / raw)
  To: David Woodhouse
  Cc: David Miller, jeffrey.t.kirsher, jbarnes, netdev, linux-pci,
	alexander.h.duyck
In-Reply-To: <1281025664.8720.28.camel@localhost>

(2010/08/06 1:27), David Woodhouse wrote:
> On Sun, 2010-08-01 at 01:15 -0700, David Miller wrote:
>> From: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
>> Date: Fri, 30 Jul 2010 17:59:12 -0700
>>
>>> From: Alexander Duyck<alexander.h.duyck@intel.com>
>>>
>>> This change makes it so that both igb and ixgbe can trigger a full pcie
>>> function reset if the reset_devices kernel parameter is defined.  The main
>>> reason for adding this is that kdump can cause serious issues when the
>>> kdump kernel resets the IOMMU while DMA transactions are still occurring.
>>>
>>> Signed-off-by: Alexander Duyck<alexander.h.duyck@intel.com>
>>> Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
>>
>> I tend to disagree with the essence of this change.
>>
>> Which is that we should add workaround after workaround for things
>> that aren't functioning properly in kdump and kexec.
>>
>> They should have a pass that shuts devices down properly, so that this
>> kind of stuff doesn't need to happen in the kernel we then boot into.
>
> For a normal kexec, arguably true.
>
> But in the kdump case, the original kernel has *crashed* and we really
> don't have that option -- we need to jump *straight* to the new kernel
> and have it reset the hardware.
>
> The device driver really *ought* to be able to reset the hardware from
> whatever state it's in when the new kernel starts up. Anything less is
> broken, and reminds me of those crappy drivers that only work after a
> soft-reboot from Windows.
>
> Most drivers *do* quite happily initialise their device and reliably get
> it into a known state; it's just that this particular hardware goes into
> a *particularly* stroppy fit when it gets a DMA master abort (which is
> what happens when the IOMMU stops it from scribbling into memory after
> the new kernel has taken over).
>
>> What happens on non-PCIE systems then?  Do they just lose when this
>> happens?
>
> If they have a device that's this broken, and the driver can't get it
> into a working state any other way, then yes -- I don't see any way to
> *avoid* them losing.

What about asserting secondary RST# on the bridge?
It would not work for devices on the root bus though.

Thanks,
Kenji Kaneshige

^ permalink raw reply

* Re: [RFC] [PATCH] Don't destroy TCP sockets twice
From: Herbert Xu @ 2010-08-10 10:24 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev
In-Reply-To: <20100810083040.GB6801@basil.fritz.box>

On Tue, Aug 10, 2010 at 10:30:40AM +0200, Andi Kleen wrote:
. 
> This simple patch demonstrates double destroy. I have patches for showing
> the more complicated case too, but they're much more ugly.

Andi, I know you're seeing the problem, but I need to udnerstand
why, and this patch doesn't really answer the why part :)

So did you figure out why was calling it first (I presume you
know who called it the second time since you've got the back
trace)?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [RFC] [PATCH] Don't destroy TCP sockets twice
From: Andi Kleen @ 2010-08-10 10:32 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Andi Kleen, netdev
In-Reply-To: <20100810102421.GA28030@gondor.apana.org.au>

On Tue, Aug 10, 2010 at 06:24:21AM -0400, Herbert Xu wrote:
> On Tue, Aug 10, 2010 at 10:30:40AM +0200, Andi Kleen wrote:
> . 
> > This simple patch demonstrates double destroy. I have patches for showing
> > the more complicated case too, but they're much more ugly.
> 
> Andi, I know you're seeing the problem, but I need to udnerstand
> why, and this patch doesn't really answer the why part :)
> 
> So did you figure out why was calling it first (I presume you
> know who called it the second time since you've got the back
> trace)?

Yes I stored the backtrace of the first caller in the ugly debug
patches and dumped that on the second destroy. It was tcp_done the 
first time.

Also did the same for tcp_sk() and there it was the fin sending.

I agree that tcp_close() should skip it in theory but I saw
it anyways :/

-Andi

^ permalink raw reply

* Re: [RFC] [PATCH] Don't destroy TCP sockets twice
From: Herbert Xu @ 2010-08-10 10:39 UTC (permalink / raw)
  To: Andi Kleen; +Cc: netdev
In-Reply-To: <20100810103206.GC6801@basil.fritz.box>

On Tue, Aug 10, 2010 at 12:32:06PM +0200, Andi Kleen wrote:
>
> Yes I stored the backtrace of the first caller in the ugly debug
> patches and dumped that on the second destroy. It was tcp_done the 
> first time.
> 
> Also did the same for tcp_sk() and there it was the fin sending.
> 
> I agree that tcp_close() should skip it in theory but I saw
> it anyways :/

So I presume the second caller was tcp_close? That means we have
a serious bug in our stack, as if the socket is already in the
CLOSE state then tcp_close should have short-circuited.

This means that something is changing the TCP socket state after
going into CLOSE.  Can you try adding your debug backtrace patch to
tcp_set_state to see if anybody is indeed changing the socket
state after going into CLOSE (and more importantly who is changing
it)?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ 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