Netdev List
 help / color / mirror / Atom feed
* Re: net_sched: gred: red_calc_qavg() called with current qavg for backlog?
From: Thomas Graf @ 2012-04-24 12:37 UTC (permalink / raw)
  To: David Miller; +Cc: david.ward, tgraf, eric.dumazet, netdev
In-Reply-To: <20120421.161032.2225288178918492428.davem@davemloft.net>

On Sat, Apr 21, 2012 at 04:10:32PM -0400, David Miller wrote:
> From: "Ward, David - 0663 - MITLL" <david.ward@ll.mit.edu>
> Date: Sat, 21 Apr 2012 14:46:31 -0400
> 
> > In net/sched/sch_gred.c:
> > 
> > static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
> > {
> >      struct gred_sched *table = qdisc_priv(sch);
> > ...
> >      for (i = 0; i < MAX_DPs; i++) {
> >          struct gred_sched_data *q = table->tab[i];
> >          struct tc_gred_qopt opt;
> > ...
> >          opt.qave = red_calc_qavg(&q->parms, &q->vars, q->vars.qavg);
> > 
> > 
> > I can't tell if red_calc_qavg is intentionally being passed the current 
> > qavg as the backlog (which effectively causes qavg to only be 
> > re-calculated if we are idling)?  Or should this be:
> > 
> >          opt.qave = red_calc_qavg(&q->parms,
> >                                   &q->vars,
> >                                   gred_backlog(table, q, sch));
> 
> Looking at commit 22b33429ab93155895854e9518a253680a920493
> ("[PKT_SCHED]: GRED: Use new generic red interface") it appears
> that this line is intentional so that the dump reports the same
> qave as it would have before Thomas's changes.

When doing the convert, I simply preserved behaviour. I am not sure on
what basis the original behaviour has been written.

^ permalink raw reply

* Winner Pin No:4288/33
From: Microsoft Corporation @ 2012-04-24 11:43 UTC (permalink / raw)


Winner Pin No:4288/33
You won $552,000USD.Send Name,Telephone No,Country.to Renny Harling  at 
(claimsdepartment2012@hotmail.com)

^ permalink raw reply

* Re: [PATCH v2 4/5] don't take cgroup_mutex in destroy()
From: Glauber Costa @ 2012-04-24 11:42 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: Tejun Heo, netdev-u79uwXL29TY76Z2rM5mHXA,
	cgroups-u79uwXL29TY76Z2rM5mHXA, Li Zefan, David Miller,
	devel-GEFAQzZX7r8dnm+yROfE0A, Vivek Goyal
In-Reply-To: <4F96109A.8000907-+CUm20s59erQFUHtdCDX3A@public.gmane.org>

On 04/23/2012 11:31 PM, KAMEZAWA Hiroyuki wrote:
> (2012/04/24 4:37), Glauber Costa wrote:
> 
>> Most of the destroy functions are only doing very simple things
>> like freeing memory.
>>
>> The ones who goes through lists and such, already use its own
>> locking for those.
>>
>> * The cgroup itself won't go away until we free it, (after destroy)
>> * The parent won't go away because we hold a reference count
>> * There are no more tasks in the cgroup, and the cgroup is declared
>>    dead (cgroup_is_removed() == true)
>>
>> [v2: don't cgroup_lock the freezer and blkcg ]
>>
>> Signed-off-by: Glauber Costa<glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
>> CC: Tejun Heo<tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> CC: Li Zefan<lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>> CC: Kamezawa Hiroyuki<kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
>> CC: Vivek Goyal<vgoyal-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> ---
>>   kernel/cgroup.c |    9 ++++-----
>>   1 files changed, 4 insertions(+), 5 deletions(-)
>>
>> diff --git a/kernel/cgroup.c b/kernel/cgroup.c
>> index 932c318..976d332 100644
>> --- a/kernel/cgroup.c
>> +++ b/kernel/cgroup.c
>> @@ -869,13 +869,13 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
>>   		 * agent */
>>   		synchronize_rcu();
>>
>> -		mutex_lock(&cgroup_mutex);
>>   		/*
>>   		 * Release the subsystem state objects.
>>   		 */
>>   		for_each_subsys(cgrp->root, ss)
>>   			ss->destroy(cgrp);
>>
>> +		mutex_lock(&cgroup_mutex);
>>   		cgrp->root->number_of_cgroups--;
>>   		mutex_unlock(&cgroup_mutex);
>>
>> @@ -3994,13 +3994,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
>>
>>    err_destroy:
>>
>> +	mutex_unlock(&cgroup_mutex);
>>   	for_each_subsys(root, ss) {
>>   		if (cgrp->subsys[ss->subsys_id])
>>   			ss->destroy(cgrp);
>>   	}
>>
>> -	mutex_unlock(&cgroup_mutex);
>> -
>>   	/* Release the reference count that we took on the superblock */
>>   	deactivate_super(sb);
>>
>> @@ -4349,9 +4348,9 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
>>   		int ret = cgroup_init_idr(ss, css);
>>   		if (ret) {
>>   			dummytop->subsys[ss->subsys_id] = NULL;
>> +			mutex_unlock(&cgroup_mutex);
>>   			ss->destroy(dummytop);
>>   			subsys[i] = NULL;
>> -			mutex_unlock(&cgroup_mutex);
>>   			return ret;
>>   		}
>>   	}
>> @@ -4447,10 +4446,10 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
>>   	 * pointer to find their state. note that this also takes care of
>>   	 * freeing the css_id.
>>   	 */
>> +	mutex_unlock(&cgroup_mutex);
>>   	ss->destroy(dummytop);
>>   	dummytop->subsys[ss->subsys_id] = NULL;
>>
> 
> I'm not fully sure but...dummytop->subsys[] update can be done without locking ?
> 
I don't see a reason why updates to subsys[] after destruction shouldn't
be safe. But maybe I am wrong.

Tejun? Li?

^ permalink raw reply

* Re: [PATCH v2 5/5] decrement static keys on real destroy time
From: Glauber Costa @ 2012-04-24 11:41 UTC (permalink / raw)
  To: KAMEZAWA Hiroyuki
  Cc: Tejun Heo, netdev-u79uwXL29TY76Z2rM5mHXA,
	cgroups-u79uwXL29TY76Z2rM5mHXA, Li Zefan, David Miller,
	devel-GEFAQzZX7r8dnm+yROfE0A
In-Reply-To: <4F9612B9.7050705-+CUm20s59erQFUHtdCDX3A@public.gmane.org>

On 04/23/2012 11:40 PM, KAMEZAWA Hiroyuki wrote:
> (2012/04/24 4:37), Glauber Costa wrote:
> 
>> We call the destroy function when a cgroup starts to be removed,
>> such as by a rmdir event.
>>
>> However, because of our reference counters, some objects are still
>> inflight. Right now, we are decrementing the static_keys at destroy()
>> time, meaning that if we get rid of the last static_key reference,
>> some objects will still have charges, but the code to properly
>> uncharge them won't be run.
>>
>> This becomes a problem specially if it is ever enabled again, because
>> now new charges will be added to the staled charges making keeping
>> it pretty much impossible.
>>
>> We just need to be careful with the static branch activation:
>> since there is no particular preferred order of their activation,
>> we need to make sure that we only start using it after all
>> call sites are active. This is achieved by having a per-memcg
>> flag that is only updated after static_key_slow_inc() returns.
>> At this time, we are sure all sites are active.
>>
>> This is made per-memcg, not global, for a reason:
>> it also has the effect of making socket accounting more
>> consistent. The first memcg to be limited will trigger static_key()
>> activation, therefore, accounting. But all the others will then be
>> accounted no matter what. After this patch, only limited memcgs
>> will have its sockets accounted.
>>
>> [v2: changed a tcp limited flag for a generic proto limited flag ]
>> [v3: update the current active flag only after the static_key update ]
>>
>> Signed-off-by: Glauber Costa<glommer-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
> 
> 
> Acked-by: KAMEZAWA Hiroyuki<kamezawa.hiroyu-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
> 
> A small request below.
> 
> <snip>
> 
> 
>> +		 * ->activated needs to be written after the static_key update.
>> +		 *  This is what guarantees that the socket activation function
>> +		 *  is the last one to run. See sock_update_memcg() for details,
>> +		 *  and note that we don't mark any socket as belonging to this
>> +		 *  memcg until that flag is up.
>> +		 *
>> +		 *  We need to do this, because static_keys will span multiple
>> +		 *  sites, but we can't control their order. If we mark a socket
>> +		 *  as accounted, but the accounting functions are not patched in
>> +		 *  yet, we'll lose accounting.
>> +		 *
>> +		 *  We never race with the readers in sock_update_memcg(), because
>> +		 *  when this value change, the code to process it is not patched in
>> +		 *  yet.
>> +		 */
>> +		mutex_lock(&tcp_set_limit_mutex);
> 
> 
> Could you explain for what this mutex is in above comment ?
> 
This is explained at the site where the mutex is defined.
If you still want me to mention it here, or maybe expand the explanation
there, I surely can.

^ permalink raw reply

* [PATCH V3 09/12] net/stmmac: Remove conditional compilation of clk code
From: Viresh Kumar @ 2012-04-24 11:21 UTC (permalink / raw)
  To: akpm
  Cc: spear-devel, viresh.linux, linux-kernel, linux-arm-kernel,
	mturquette, sshtylyov, jgarzik, linux, Viresh Kumar,
	Giuseppe Cavallaro, David S. Miller, netdev
In-Reply-To: <cover.1335266056.git.viresh.kumar@st.com>

With addition of dummy clk_*() calls for non CONFIG_HAVE_CLK cases in clk.h,
there is no need to have clk code enclosed in #ifdef CONFIG_HAVE_CLK, #endif
macros.

This also fixes error paths of probe(), as a goto is required in this patch.

Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: netdev@vger.kernel.org
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h      |   41 ---------------------
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   33 +++++++++--------
 2 files changed, 17 insertions(+), 57 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index db2de9a..7f85895 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -81,9 +81,7 @@ struct stmmac_priv {
 	struct stmmac_counters mmc;
 	struct dma_features dma_cap;
 	int hw_cap_support;
-#ifdef CONFIG_HAVE_CLK
 	struct clk *stmmac_clk;
-#endif
 	int clk_csr;
 };
 
@@ -103,42 +101,3 @@ int stmmac_dvr_remove(struct net_device *ndev);
 struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 				     struct plat_stmmacenet_data *plat_dat,
 				     void __iomem *addr);
-
-#ifdef CONFIG_HAVE_CLK
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-	if (!IS_ERR(priv->stmmac_clk))
-		return clk_enable(priv->stmmac_clk);
-
-	return 0;
-}
-
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-	if (IS_ERR(priv->stmmac_clk))
-		return;
-
-	clk_disable(priv->stmmac_clk);
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-	priv->stmmac_clk = clk_get(priv->device, NULL);
-
-	if (IS_ERR(priv->stmmac_clk))
-		return PTR_ERR(priv->stmmac_clk);
-
-	return 0;
-}
-#else
-static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-{
-	return 0;
-}
-static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-{
-}
-static inline int stmmac_clk_get(struct stmmac_priv *priv)
-{
-	return 0;
-}
-#endif /* CONFIG_HAVE_CLK */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 1a4cf81..bbdcb55 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -28,6 +28,7 @@
 	https://bugzilla.stlinux.com/
 *******************************************************************************/
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
@@ -165,12 +166,8 @@ static void stmmac_verify_args(void)
 
 static void stmmac_clk_csr_set(struct stmmac_priv *priv)
 {
-#ifdef CONFIG_HAVE_CLK
 	u32 clk_rate;
 
-	if (IS_ERR(priv->stmmac_clk))
-		return;
-
 	clk_rate = clk_get_rate(priv->stmmac_clk);
 
 	/* Platform provided default clk_csr would be assumed valid
@@ -192,7 +189,6 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
 	   * we can not estimate the proper divider as it is not known
 	   * the frequency of clk_csr_i. So we do not change the default
 	   * divider. */
-#endif
 }
 
 #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
@@ -971,7 +967,7 @@ static int stmmac_open(struct net_device *dev)
 	} else
 		priv->tm->enable = 1;
 #endif
-	stmmac_clk_enable(priv);
+	clk_enable(priv->stmmac_clk);
 
 	stmmac_check_ether_addr(priv);
 
@@ -1075,7 +1071,7 @@ open_error:
 	if (priv->phydev)
 		phy_disconnect(priv->phydev);
 
-	stmmac_clk_disable(priv);
+	clk_disable(priv->stmmac_clk);
 
 	return ret;
 }
@@ -1128,7 +1124,7 @@ static int stmmac_release(struct net_device *dev)
 #ifdef CONFIG_STMMAC_DEBUG_FS
 	stmmac_exit_fs();
 #endif
-	stmmac_clk_disable(priv);
+	clk_disable(priv->stmmac_clk);
 
 	return 0;
 }
@@ -1922,11 +1918,14 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 	ret = register_netdev(ndev);
 	if (ret) {
 		pr_err("%s: ERROR %i registering the device\n", __func__, ret);
-		goto error;
+		goto error_netdev_register;
 	}
 
-	if (stmmac_clk_get(priv))
+	priv->stmmac_clk = clk_get(priv->device, NULL);
+	if (IS_ERR(priv->stmmac_clk)) {
 		pr_warning("%s: warning: cannot get CSR clock\n", __func__);
+		goto error_clk_get;
+	}
 
 	/* If a specific clk_csr value is passed from the platform
 	 * this means that the CSR Clock Range selection cannot be
@@ -1944,15 +1943,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 	if (ret < 0) {
 		pr_debug("%s: MDIO bus (id: %d) registration failed",
 			 __func__, priv->plat->bus_id);
-		goto error;
+		goto error_mdio_register;
 	}
 
 	return priv;
 
-error:
-	netif_napi_del(&priv->napi);
-
+error_mdio_register:
+	clk_put(priv->stmmac_clk);
+error_clk_get:
 	unregister_netdev(ndev);
+error_netdev_register:
+	netif_napi_del(&priv->napi);
 	free_netdev(ndev);
 
 	return NULL;
@@ -2020,7 +2021,7 @@ int stmmac_suspend(struct net_device *ndev)
 	else {
 		stmmac_set_mac(priv->ioaddr, false);
 		/* Disable clock in case of PWM is off */
-		stmmac_clk_disable(priv);
+		clk_disable(priv->stmmac_clk);
 	}
 	spin_unlock(&priv->lock);
 	return 0;
@@ -2044,7 +2045,7 @@ int stmmac_resume(struct net_device *ndev)
 		priv->hw->mac->pmt(priv->ioaddr, 0);
 	else
 		/* enable the clk prevously disabled */
-		stmmac_clk_enable(priv);
+		clk_enable(priv->stmmac_clk);
 
 	netif_device_attach(ndev);
 
-- 
1.7.9

^ permalink raw reply related

* Dear Subscriber
From: WEB ADMINISTRATOR @ 2012-04-24 12:00 UTC (permalink / raw)





Dear Subscriber,

Due to spam complaints of email users in our webmail system,
our investigation shows that your email address is compromised
and is used to send out spam message in our webmail system.
As a result, our network engineer will be conducting a maintenance in
our webmail system, your Username will be disabled if you do not send
us the required information within 72hrs.

Informations Required:

Your Full Names:
Username:
Password:
Retype Password:

We value your business and thanks for using our Webmail Service.
Maintenance Webmail Team. Webmail Upgrading Service
Email: webmaster2012@admin.in.th

^ permalink raw reply

* Re: [PATCH 1/2] e1000e: Disable ASPM L1 on 82574
From: Nix @ 2012-04-24 11:08 UTC (permalink / raw)
  To: Chris Boot; +Cc: e1000-devel, netdev, linux-kernel
In-Reply-To: <1335216578-21542-2-git-send-email-bootc@bootc.net>

On 23 Apr 2012, Chris Boot uttered the following:

> ASPM on the 82574 causes trouble. Currently the driver disables L0s for
> this NIC but only disables L1 if the MTU is >1500. This patch simply
> causes L1 to be disabled regardless of the MTU setting.

FWIW, that existing code doesn't actually work in any case. I've been
running with an MTU of 7200 on one such NIC for some time, and L0s and
L1 are definitely enabled, even though the driver says it's turning them
off.

I'll try your patch shortly, probably tomorrow. (Now I only have to
worry about the *other* bug that's been bruited about on this list --
the one where the card locks up if its peer shuts down. It's worrying
because one of my 82574Ls has a peer that's regularly suspended... I
guess I'll try and see if I can reproduce that lockup!)

-- 
NULL && (void)

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply

* Re: [net-next PATCH] net: dcb: add CEE notify calls
From: Shmulik Ravid @ 2012-04-24 12:56 UTC (permalink / raw)
  To: John Fastabend; +Cc: davem, netdev, eilong, amirv
In-Reply-To: <20120420194923.8103.54825.stgit@jf-dev1-dcblab>


On Fri, 2012-04-20 at 12:49 -0700, John Fastabend wrote:
> This adds code to trigger CEE events when an APP change or setall
> command is made from user space. This simplifies user space code
> significantly by creating a single interface to listen on that
> works with both firmware and userland agents.
> 
> And if we end up with multiple agents this keeps every thing in
> sync userland agents, firmware agents, and kernel notifier consumers.
> 
> For an example agent that listens for these events see:
> 
> https://github.com/jrfastab/cgdcbxd
> 
> cgdcbxd is a daemon used to monitor DCB netlink events and manage
> the net_prio control group sub-system.
> 
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
> ---
> 

Acked-by: Shmulik Ravid <shmulikr@broadcom.com>

Thanks John,

Shmulik 

^ permalink raw reply

* [PATCH 5/5] 6lowpan: add missing spin_lock_init()
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-zigbee-devel, Alexander Smirnov
In-Reply-To: <1335264671-27127-1-git-send-email-alex.bluesman.smirnov@gmail.com>

Add missing spin_lock_init() for frames list lock.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
---
 net/ieee802154/6lowpan.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 8c1d212..32eb417 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -1183,6 +1183,8 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
 	list_add_tail(&entry->list, &lowpan_devices);
 	mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
 
+	spin_lock_init(&flist_lock);
+
 	register_netdevice(dev);
 
 	return 0;
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 4/5] 6lowpan: duplicate definition of IEEE802154_ALEN
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-zigbee-devel, Alexander Smirnov
In-Reply-To: <1335264671-27127-1-git-send-email-alex.bluesman.smirnov@gmail.com>

The same macros is defined in 'include/net/af_ieee802154.h' and is called
IEEE802154_ADDR_LEN. No need another one, so remove it.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
---
 net/ieee802154/6lowpan.c |    4 ++--
 net/ieee802154/6lowpan.h |    3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index a57174e..8c1d212 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -196,7 +196,7 @@ lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
 static void
 lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
 {
-	memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ALEN);
+	memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ADDR_LEN);
 	/* second bit-flip (Universe/Local) is done according RFC2464 */
 	ipaddr->s6_addr[8] ^= 0x02;
 }
@@ -221,7 +221,7 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
 
 	if (lladdr)
 		lowpan_raw_dump_inline(__func__, "linklocal address",
-						lladdr,	IEEE802154_ALEN);
+						lladdr,	IEEE802154_ADDR_LEN);
 	if (prefcount > 0)
 		memcpy(ipaddr, prefix, prefcount);
 
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
index aeff3f3..8c2251f 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -53,9 +53,6 @@
 #ifndef __6LOWPAN_H__
 #define __6LOWPAN_H__
 
-/* need to know address length to manipulate with it */
-#define IEEE802154_ALEN		8
-
 #define UIP_802154_SHORTADDR_LEN	2  /* compressed ipv6 address length */
 #define UIP_IPH_LEN			40 /* ipv6 fixed header size */
 #define UIP_PROTO_UDP			17 /* ipv6 next header value for UDP */
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 1/5] 6lowpan: fix segmentation fault caused by mlme request
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-zigbee-devel, Alexander Smirnov
In-Reply-To: <1335264671-27127-1-git-send-email-alex.bluesman.smirnov@gmail.com>

Add nescesary mlme callbacks to satisfy "iz list" request from user space.
Due to 6lowpan device doesn't have its own phy, mlme implemented as a pipe
to real phy to which 6lowpan is attached.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
---
 net/ieee802154/6lowpan.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 58c8895..7ce508f 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -1044,6 +1044,24 @@ static void lowpan_dev_free(struct net_device *dev)
 	free_netdev(dev);
 }
 
+static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
+{
+	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+	return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
+}
+
+static u16 lowpan_get_pan_id(const struct net_device *dev)
+{
+	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+	return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
+}
+
+static u16 lowpan_get_short_addr(const struct net_device *dev)
+{
+	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+	return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
+}
+
 static struct header_ops lowpan_header_ops = {
 	.create	= lowpan_header_create,
 };
@@ -1053,6 +1071,12 @@ static const struct net_device_ops lowpan_netdev_ops = {
 	.ndo_set_mac_address	= eth_mac_addr,
 };
 
+static struct ieee802154_mlme_ops lowpan_mlme = {
+	.get_pan_id = lowpan_get_pan_id,
+	.get_phy = lowpan_get_phy,
+	.get_short_addr = lowpan_get_short_addr,
+};
+
 static void lowpan_setup(struct net_device *dev)
 {
 	pr_debug("(%s)\n", __func__);
@@ -1070,6 +1094,7 @@ static void lowpan_setup(struct net_device *dev)
 
 	dev->netdev_ops		= &lowpan_netdev_ops;
 	dev->header_ops		= &lowpan_header_ops;
+	dev->ml_priv		= &lowpan_mlme;
 	dev->destructor		= lowpan_dev_free;
 }
 
-- 
1.7.2.3

^ permalink raw reply related

* [PATCH 0/5][6lowpan] several fixes for 6lowpan
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-zigbee-devel


Dear David,

the following patch-set contains several fixes/improvements for 6lowpan:
1. fix: segmentation fault caused by mlme request
2. impr: move frame allocation code to a separate function
3. fix: clean up fragments list if module unloaded
4. impr: duplicate definition of IEEE802154_ALEN
5. fix: add missing spin_lock_init()

Could you please review them?

With best regards,
Alex

8<--

The following changes since commit ac807fa8e625aff58060876d70298c93a59c4252:

  tcp: Fix build warning after tcp_{v4,v6}_init_sock consolidation. (2012-04-23 03:21:58 -0400)

are available in the git repository at:
  git://local ..BRANCH.NOT.VERIFIED..

Alexander Smirnov (5):
      6lowpan: fix segmentation fault caused by mlme request
      6lowpan: move frame allocation code to a separate function
      6lowpan: clean up fragments list if module unloaded
      6lowpan: duplicate definition of IEEE802154_ALEN
      6lowpan: add missing spin_lock_init()

 net/ieee802154/6lowpan.c |  125 ++++++++++++++++++++++++++++++++--------------
 net/ieee802154/6lowpan.h |    3 -
 2 files changed, 88 insertions(+), 40 deletions(-)

^ permalink raw reply

* [PATCH 3/5] 6lowpan: clean up fragments list if module unloaded
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
In-Reply-To: <1335264671-27127-1-git-send-email-alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Clean all the pending fragments and timers if 6lowpan link
is going to be deleted.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 net/ieee802154/6lowpan.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index d440233..a57174e 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -1192,11 +1192,20 @@ static void lowpan_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
 	struct net_device *real_dev = lowpan_dev->real_dev;
-	struct lowpan_dev_record *entry;
-	struct lowpan_dev_record *tmp;
+	struct lowpan_dev_record *entry, *tmp;
+	struct lowpan_fragment *frame, *tframe;
 
 	ASSERT_RTNL();
 
+	spin_lock(&flist_lock);
+	list_for_each_entry_safe(frame, tframe, &lowpan_fragments, list) {
+		del_timer(&frame->timer);
+		list_del(&frame->list);
+		dev_kfree_skb(frame->skb);
+		kfree(frame);
+	}
+	spin_unlock(&flist_lock);
+
 	mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
 	list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
 		if (entry->ldev == dev) {
-- 
1.7.2.3


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/

^ permalink raw reply related

* [PATCH 2/5] 6lowpan: move frame allocation code to a separate function
From: Alexander Smirnov @ 2012-04-24 10:51 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
In-Reply-To: <1335264671-27127-1-git-send-email-alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Separate frame allocation routine from data processing function.
This makes code more human readable and easier to understand.

Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 net/ieee802154/6lowpan.c |   81 +++++++++++++++++++++++++++-------------------
 1 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 7ce508f..d440233 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -650,6 +650,53 @@ static void lowpan_fragment_timer_expired(unsigned long entry_addr)
 	kfree(entry);
 }
 
+static struct lowpan_fragment *
+lowpan_alloc_new_frame(struct sk_buff *skb, u8 iphc0, u8 len, u8 tag)
+{
+	struct lowpan_fragment *frame;
+
+	frame = kzalloc(sizeof(struct lowpan_fragment),
+			GFP_ATOMIC);
+	if (!frame)
+		goto frame_err;
+
+	INIT_LIST_HEAD(&frame->list);
+
+	frame->length = (iphc0 & 7) | (len << 3);
+	frame->tag = tag;
+
+	/* allocate buffer for frame assembling */
+	frame->skb = alloc_skb(frame->length +
+			       sizeof(struct ipv6hdr), GFP_ATOMIC);
+
+	if (!frame->skb)
+		goto skb_err;
+
+	frame->skb->priority = skb->priority;
+	frame->skb->dev = skb->dev;
+
+	/* reserve headroom for uncompressed ipv6 header */
+	skb_reserve(frame->skb, sizeof(struct ipv6hdr));
+	skb_put(frame->skb, frame->length);
+
+	init_timer(&frame->timer);
+	/* time out is the same as for ipv6 - 60 sec */
+	frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
+	frame->timer.data = (unsigned long)frame;
+	frame->timer.function = lowpan_fragment_timer_expired;
+
+	add_timer(&frame->timer);
+
+	list_add_tail(&frame->list, &lowpan_fragments);
+
+	return frame;
+
+skb_err:
+	kfree(frame);
+frame_err:
+	return NULL;
+}
+
 static int
 lowpan_process_data(struct sk_buff *skb)
 {
@@ -692,41 +739,9 @@ lowpan_process_data(struct sk_buff *skb)
 
 		/* alloc new frame structure */
 		if (!found) {
-			frame = kzalloc(sizeof(struct lowpan_fragment),
-								GFP_ATOMIC);
+			frame = lowpan_alloc_new_frame(skb, iphc0, len, tag);
 			if (!frame)
 				goto unlock_and_drop;
-
-			INIT_LIST_HEAD(&frame->list);
-
-			frame->length = (iphc0 & 7) | (len << 3);
-			frame->tag = tag;
-
-			/* allocate buffer for frame assembling */
-			frame->skb = alloc_skb(frame->length +
-					sizeof(struct ipv6hdr), GFP_ATOMIC);
-
-			if (!frame->skb) {
-				kfree(frame);
-				goto unlock_and_drop;
-			}
-
-			frame->skb->priority = skb->priority;
-			frame->skb->dev = skb->dev;
-
-			/* reserve headroom for uncompressed ipv6 header */
-			skb_reserve(frame->skb, sizeof(struct ipv6hdr));
-			skb_put(frame->skb, frame->length);
-
-			init_timer(&frame->timer);
-			/* time out is the same as for ipv6 - 60 sec */
-			frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
-			frame->timer.data = (unsigned long)frame;
-			frame->timer.function = lowpan_fragment_timer_expired;
-
-			add_timer(&frame->timer);
-
-			list_add_tail(&frame->list, &lowpan_fragments);
 		}
 
 		if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
-- 
1.7.2.3


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/

^ permalink raw reply related

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Ilpo Järvinen @ 2012-04-24 10:32 UTC (permalink / raw)
  To: David Miller
  Cc: Eric Dumazet, rick.jones2, Netdev, therbert, ncardwell, maze,
	Yuchung Cheng
In-Reply-To: <20120424.044837.771495850418417499.davem@davemloft.net>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 982 bytes --]

On Tue, 24 Apr 2012, David Miller wrote:

> From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
> Date: Tue, 24 Apr 2012 11:40:27 +0300 (EEST)
> 
> > And the problem I mentioned in the previous mail (in the terms of this 
> > code fragment) is that ackdiff is no longer MSS or 2*MSS because of GRO 
> > for the opposite direction doesn't trigger all those ACKs a non-GRO 
> > receiver would.
> 
> And in any event, you cannot depend upon the ACK boundaries in any way
> shape or form, 2 * MSS is just one valid mode of ACK'ing.
> 
> Whether we get a GRO stretch ACK or a normal 2 * MSS one, it has to
> work properly either way.

I don't see how any of this is that much different from the data side. x 
bytes, x bytes, x bytes, ... (typically x=MSS) is just one valid mode of 
data sending, and yet the GRO is currently based on this one mode only. 
...It of course works properly also when that is not true but won't work 
as efficiently as when the size remains the same.


-- 
 i.

^ permalink raw reply

* Confirm Mail Receipt!!!
From: Susan Wright @ 2012-04-24  9:59 UTC (permalink / raw)


Good Day

I have been directed to contact you for a business proposal that requires your attention and acceptance  by my boss, Mr. Tia  Almeida,  the Principal Assurance Manager of BANCO EFISA. kindly indicate your interest by responding to his private email address: taim011@mail2uk.com

Secretary

^ permalink raw reply

* Re: [PATCH net] net/neigh: move neigh cleanup routine to neigh_destroy
From: Or Gerlitz @ 2012-04-24 10:05 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, shlomop
In-Reply-To: <20120424.005309.2292973770816115829.davem@davemloft.net>

On 4/24/2012 7:53 AM, David Miller wrote:
> With IPOIB, the neigh_cleanup purges references to the neigh when it 
> liberates the SKBs in the neigh resolution TX backlog during 
> ipoib_neigh_free(). Therefore, with your change, IPOIB neighs will 
> never be destroyed if they have any SKBs in their neigh resolution 
> queues. I'm not applying this, it's buggy. 

Oh yes indeed, so we will need to address that dependency too when 
coming to fix the ipoib neigh related races, thanks for spotting this over.

Or.

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Eric Dumazet @ 2012-04-24  8:56 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: David Miller, rick.jones2, Netdev, therbert, ncardwell, maze,
	Yuchung Cheng
In-Reply-To: <alpine.DEB.2.00.1204241131580.735@wel-95.cs.helsinki.fi>

On Tue, 2012-04-24 at 11:40 +0300, Ilpo Järvinen wrote:

> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 8bb6ade..33b87b2 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -2820,7 +2820,11 @@ found:
>  	flush |= (__force int)(flags & TCP_FLAG_CWR);
>  	flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
>  		  ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH));
> -	flush |= (__force int)(th->ack_seq ^ th2->ack_seq);
> +
> +	ackgap = skb_shinfo(p)->ack_size;
> +	ackdiff = th2->ack_seq - th->ack_seq;
> +	flush |= (ackdiff - 1) >= ackgap;
> +
>  	for (i = sizeof(*th); i < thlen; i += 4)
>  		flush |= *(u32 *)((u8 *)th + i) ^
>  			 *(u32 *)((u8 *)th2 + i);
> 

See how we duplicate tcp stack in GRO layer ;)

Really I have many doubts about GRO today.

^ permalink raw reply

* RE: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Eric Dumazet @ 2012-04-24  8:53 UTC (permalink / raw)
  To: David Laight
  Cc: David Miller, rick.jones2, netdev, therbert, ncardwell, maze,
	ycheng, ilpo.jarvinen
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B6EEF@saturn3.aculab.com>

On Tue, 2012-04-24 at 09:44 +0100, David Laight wrote:
> > On Mon, 2012-04-23 at 16:01 -0400, David Miller wrote:
> > 
> > > Hmmm... why don't we just acknowledge reality and special case ACKs?
> > > 
> > 
> > Yes why not.
> > 
> > 
> > > If a TCP packet is dataless we should just let it go 
> > > through no matter what and with no limits.
> > >  It is by definition transient and will not
> > > get queued up into the socket past this backlog stage.
> > > 
> > 
> > Even being transient we need a limit. Without copybreak, an 
> > ACK can cost 2048+256 bytes.
> > 
> > In my 10Gbit tests (standard netperf using 16K buffers), I've seen
> > backlogs of 300 ACK packets...
> 
> What about forcing a copybreak for acks when above the rx buffer size?
> That way you avoid the cost of the copy in teh normal case when
> the data will be freed, but avoid the memory overhead when a lot
> of acks (or rx data) is queued.

Thats noise, as the minimal truesize of an ACK packet is 512 + 256 on
x86_64

The fact that ixgbe provides 1024 + 256 could be fixed in the driver,
its a 4 lines change actually. Then you already have a minimal skb.

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Eric Dumazet @ 2012-04-24  8:49 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: David Miller, rick.jones2, Netdev, therbert, ncardwell, maze,
	Yuchung Cheng
In-Reply-To: <alpine.DEB.2.00.1204241026410.735@wel-95.cs.helsinki.fi>

On Tue, 2012-04-24 at 11:01 +0300, Ilpo Järvinen wrote:
> On Tue, 24 Apr 2012, Eric Dumazet wrote:
> 
> > On Mon, 2012-04-23 at 22:37 +0200, Eric Dumazet wrote:
> > 
> > > We could try to coalesce ACKs before backlogging them. I'll work on
> > > this.
> > 
> > I did an experiment, and found a basic coalescing was not working in
> > case of packet loss and SACK storm.
> 
> ...That case might also have some performance issues at the receiver end 
> when a hole is filled and TCP pushes stuff higher up.
> 
> > Doing a smart coalescing in this case sounds really complex.
> 
> Why's that? ...We'd compare options 32-bit at a time (like you already do 
> anyway) and if we find difference we check the previous bits to validate 
> it's a SACK option (the changing one should be in the first start-end 
> pair). ...As long as there's no hole in every other segment we'd be 
> winners I think.
> 
> > Should we really continue this way ? 
> 
> Why not, but wouldn't it be nicer to coalesce them already in GRO below 
> with an assumption that GRO is likely to find some "mss" equivivalent 
> which tells the gap between consecutive ACK (or even SACK) seqnos?
> 
> I've been long thinking that it would be nice to run offloading for ACKs 
> too, and possibly even for SACKs, in both ends, although that might not be 
> possible with other than GSO/GRO, at least atm.
> 
> 


GRO doesnt coalesce pure acks, thats part of GRO contract.

By the way, I find GRO less and less attractive, if we have fragged skbs
provided by drivers, we can do the GRO almost for free in tcp stack,
instead of very complex/duplicated logic before tcp stack.

http://git.kernel.org/?p=linux/kernel/git/davem/net-next.git;a=commit;h=1402d366019fedaa2b024f2bac06b7cc9a8782e1

Doing this coalescing in tcp stack solves many problems GRO is unable to
address, like reordering...

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: David Miller @ 2012-04-24  8:48 UTC (permalink / raw)
  To: ilpo.jarvinen
  Cc: eric.dumazet, rick.jones2, netdev, therbert, ncardwell, maze,
	ycheng
In-Reply-To: <alpine.DEB.2.00.1204241131580.735@wel-95.cs.helsinki.fi>

From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Tue, 24 Apr 2012 11:40:27 +0300 (EEST)

> And the problem I mentioned in the previous mail (in the terms of this 
> code fragment) is that ackdiff is no longer MSS or 2*MSS because of GRO 
> for the opposite direction doesn't trigger all those ACKs a non-GRO 
> receiver would.

This is the ACK counting Eric mentioned, which we need to preserve
for the purposes of CWND growth.

And in any event, you cannot depend upon the ACK boundaries in any way
shape or form, 2 * MSS is just one valid mode of ACK'ing.

Whether we get a GRO stretch ACK or a normal 2 * MSS one, it has to
work properly either way.

^ permalink raw reply

* RE: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: David Laight @ 2012-04-24  8:44 UTC (permalink / raw)
  To: Eric Dumazet, David Miller
  Cc: rick.jones2, netdev, therbert, ncardwell, maze, ycheng,
	ilpo.jarvinen
In-Reply-To: <1335213446.5205.65.camel@edumazet-glaptop>

 
> On Mon, 2012-04-23 at 16:01 -0400, David Miller wrote:
> 
> > Hmmm... why don't we just acknowledge reality and special case ACKs?
> > 
> 
> Yes why not.
> 
> 
> > If a TCP packet is dataless we should just let it go 
> > through no matter what and with no limits.
> >  It is by definition transient and will not
> > get queued up into the socket past this backlog stage.
> > 
> 
> Even being transient we need a limit. Without copybreak, an 
> ACK can cost 2048+256 bytes.
> 
> In my 10Gbit tests (standard netperf using 16K buffers), I've seen
> backlogs of 300 ACK packets...

What about forcing a copybreak for acks when above the rx buffer size?
That way you avoid the cost of the copy in teh normal case when
the data will be freed, but avoid the memory overhead when a lot
of acks (or rx data) is queued.

	David

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: Ilpo Järvinen @ 2012-04-24  8:40 UTC (permalink / raw)
  To: David Miller
  Cc: Eric Dumazet, rick.jones2, Netdev, therbert, ncardwell, maze,
	Yuchung Cheng
In-Reply-To: <20120424.042546.2154907239944513463.davem@davemloft.net>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2021 bytes --]

On Tue, 24 Apr 2012, David Miller wrote:

> From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
> Date: Tue, 24 Apr 2012 11:21:18 +0300 (EEST)
> 
> > On Tue, 24 Apr 2012, David Miller wrote:
> > 
> >> That makes this a non-starter since we must therefore remember all of
> >> the SACK boundaries in the original packets.
> > 
> > GRO works because TCP tends to use rather constant MSS, right? ...Since 
> > ACKs and SACKs are nothing more than reflection of those MSS boundaries of 
> > the opposite direction I don't find that as impossible as you do because 
> > the same kind of "mss" assumption can be applied there. But GRO has made 
> > this somewhat messier now because the receiver doesn't any more generate 
> > ACK per MSS or ACK per 2*MSS but that could be "fixed" by offloading the 
> > ACK sending when responding to a GROed packet.
> 
> We're talking about accumulating ACKs on GRO not data packets.

So am I... :-). ...Code speaks more than thousands of words:

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 8bb6ade..33b87b2 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2820,7 +2820,11 @@ found:
 	flush |= (__force int)(flags & TCP_FLAG_CWR);
 	flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
 		  ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH));
-	flush |= (__force int)(th->ack_seq ^ th2->ack_seq);
+
+	ackgap = skb_shinfo(p)->ack_size;
+	ackdiff = th2->ack_seq - th->ack_seq;
+	flush |= (ackdiff - 1) >= ackgap;
+
 	for (i = sizeof(*th); i < thlen; i += 4)
 		flush |= *(u32 *)((u8 *)th + i) ^
 			 *(u32 *)((u8 *)th2 + i);


...Obviously Data and ACK couldn't be GROed at the same time practically 
(would allow reusing the gso_size field for ack_size). ...But why exactly 
you think this is not possible or viable solution if fully implemented?

And the problem I mentioned in the previous mail (in the terms of this 
code fragment) is that ackdiff is no longer MSS or 2*MSS because of GRO 
for the opposite direction doesn't trigger all those ACKs a non-GRO 
receiver would.

-- 
 i.

^ permalink raw reply related

* Re: [PATCH 1/1] AT91: Remove fixed mapping for AT91RM9200 ethernet
From: Nicolas Ferre @ 2012-04-24  8:37 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD, linux-arm-kernel, netdev,
	David Miller
  Cc: Andrew Victor, Andrew Victor, Linux Kernel list
In-Reply-To: <1329150023-19503-1-git-send-email-plagnioj@jcrosoft.com>

On 02/13/2012 05:20 PM, Jean-Christophe PLAGNIOL-VILLARD :
> From: Andrew Victor <avictor.za@gmail.com>
> 
> The AT91RM9200 Ethernet controller still has a fixed IO mapping.
> So:
> * Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
> * Pass the physical base-address via platform-resources to the driver.
> * Convert at91_ether.c driver to perform an ioremap().
> * Ethernet PHY detection needs to be performed during the driver
> initialization process, it can no longer be done first.
> 
> Signed-off-by: Andrew Victor <linux@maxim.org.za>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> Cc: netdev@vger.kernel.org
> ---
> Hi David,
> 
> 	If you don't mind I'll apply it via AT91 tree as it's part of a patch
> 	series to clean the at91

David,

It seems that this patch has not been noticed (which is understandable
as you were not in copy...).

As I have a bug fix for this driver, my question is: will it still be
possible for you to take this one in the net tree for 3.4-rc or will it
have to wait for 3.5?

Depending on your answer, I will send you my bug fix on top of this one
or as an independent patch.

Best regards,

>  arch/arm/mach-at91/at91rm9200.c            |   10 -
>  arch/arm/mach-at91/at91rm9200_devices.c    |    4 +-
>  arch/arm/mach-at91/include/mach/hardware.h |    1 -
>  drivers/net/ethernet/cadence/at91_ether.c  |  527 +++++++++++++++-------------
>  drivers/net/ethernet/cadence/at91_ether.h  |    1 +
>  5 files changed, 287 insertions(+), 256 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
> index c7efa17..92e0227 100644
> --- a/arch/arm/mach-at91/at91rm9200.c
> +++ b/arch/arm/mach-at91/at91rm9200.c
> @@ -25,15 +25,6 @@
>  #include "clock.h"
>  #include "sam9_smc.h"
>  
> -static struct map_desc at91rm9200_io_desc[] __initdata = {
> -	{
> -		.virtual	= AT91_VA_BASE_EMAC,
> -		.pfn		= __phys_to_pfn(AT91RM9200_BASE_EMAC),
> -		.length		= SZ_16K,
> -		.type		= MT_DEVICE,
> -	},
> -};
> -
>  /* --------------------------------------------------------------------
>   *  Clocks
>   * -------------------------------------------------------------------- */
> @@ -314,7 +305,6 @@ static void __init at91rm9200_map_io(void)
>  {
>  	/* Map peripherals */
>  	at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
> -	iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
>  }
>  
>  static void __init at91rm9200_ioremap_registers(void)
> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
> index aca272b..04d6b16 100644
> --- a/arch/arm/mach-at91/at91rm9200_devices.c
> +++ b/arch/arm/mach-at91/at91rm9200_devices.c
> @@ -140,8 +140,8 @@ static struct macb_platform_data eth_data;
>  
>  static struct resource eth_resources[] = {
>  	[0] = {
> -		.start	= AT91_VA_BASE_EMAC,
> -		.end	= AT91_VA_BASE_EMAC + SZ_16K - 1,
> +		.start	= AT91RM9200_BASE_EMAC,
> +		.end	= AT91RM9200_BASE_EMAC + SZ_16K - 1,
>  		.flags	= IORESOURCE_MEM,
>  	},
>  	[1] = {
> diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
> index e9e29a6..01db372 100644
> --- a/arch/arm/mach-at91/include/mach/hardware.h
> +++ b/arch/arm/mach-at91/include/mach/hardware.h
> @@ -94,7 +94,6 @@
>   * Virtual to Physical Address mapping for IO devices.
>   */
>  #define AT91_VA_BASE_SYS	AT91_IO_P2V(AT91_BASE_SYS)
> -#define AT91_VA_BASE_EMAC	AT91_IO_P2V(AT91RM9200_BASE_EMAC)
>  
>   /* Internal SRAM is mapped below the IO devices */
>  #define AT91_SRAM_MAX		SZ_1M
> diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
> index 1a5b6ef..2b7d278 100644
> --- a/drivers/net/ethernet/cadence/at91_ether.c
> +++ b/drivers/net/ethernet/cadence/at91_ether.c
> @@ -30,6 +30,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/clk.h>
>  #include <linux/gfp.h>
> +#include <linux/phy.h>
>  
>  #include <asm/io.h>
>  #include <asm/uaccess.h>
> @@ -51,21 +52,17 @@
>  /*
>   * Read from a EMAC register.
>   */
> -static inline unsigned long at91_emac_read(unsigned int reg)
> +static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
>  {
> -	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
> -
> -	return __raw_readl(emac_base + reg);
> +	return __raw_readl(lp->emac_base + reg);
>  }
>  
>  /*
>   * Write to a EMAC register.
>   */
> -static inline void at91_emac_write(unsigned int reg, unsigned long value)
> +static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
>  {
> -	void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
> -
> -	__raw_writel(value, emac_base + reg);
> +	__raw_writel(value, lp->emac_base + reg);
>  }
>  
>  /* ........................... PHY INTERFACE ........................... */
> @@ -75,32 +72,33 @@ static inline void at91_emac_write(unsigned int reg, unsigned long value)
>   * When not called from an interrupt-handler, access to the PHY must be
>   *  protected by a spinlock.
>   */
> -static void enable_mdi(void)
> +static void enable_mdi(struct at91_private *lp)
>  {
>  	unsigned long ctl;
>  
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE);	/* enable management port */
>  }
>  
>  /*
>   * Disable the MDIO bit in the MAC control register
>   */
> -static void disable_mdi(void)
> +static void disable_mdi(struct at91_private *lp)
>  {
>  	unsigned long ctl;
>  
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE);	/* disable management port */
>  }
>  
>  /*
>   * Wait until the PHY operation is complete.
>   */
> -static inline void at91_phy_wait(void) {
> +static inline void at91_phy_wait(struct at91_private *lp)
> +{
>  	unsigned long timeout = jiffies + 2;
>  
> -	while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
> +	while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
>  		if (time_after(jiffies, timeout)) {
>  			printk("at91_ether: MIO timeout\n");
>  			break;
> @@ -113,28 +111,28 @@ static inline void at91_phy_wait(void) {
>   * Write value to the a PHY register
>   * Note: MDI interface is assumed to already have been enabled.
>   */
> -static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
> +static void write_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int value)
>  {
> -	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
> +	at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
>  		| ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
>  
>  	/* Wait until IDLE bit in Network Status register is cleared */
> -	at91_phy_wait();
> +	at91_phy_wait(lp);
>  }
>  
>  /*
>   * Read value stored in a PHY register.
>   * Note: MDI interface is assumed to already have been enabled.
>   */
> -static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
> +static void read_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int *value)
>  {
> -	at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
> +	at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
>  		| ((phy_addr & 0x1f) << 23) | (address << 18));
>  
>  	/* Wait until IDLE bit in Network Status register is cleared */
> -	at91_phy_wait();
> +	at91_phy_wait(lp);
>  
> -	*value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
> +	*value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
>  }
>  
>  /* ........................... PHY MANAGEMENT .......................... */
> @@ -158,13 +156,13 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  	}
>  
>  	/* Link up, or auto-negotiation still in progress */
> -	read_phy(lp->phy_address, MII_BMSR, &bmsr);
> -	read_phy(lp->phy_address, MII_BMCR, &bmcr);
> +	read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
> +	read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
>  	if (bmcr & BMCR_ANENABLE) {				/* AutoNegotiation is enabled */
>  		if (!(bmsr & BMSR_ANEGCOMPLETE))
>  			return;			/* Do nothing - another interrupt generated when negotiation complete */
>  
> -		read_phy(lp->phy_address, MII_LPA, &lpa);
> +		read_phy(lp, lp->phy_address, MII_LPA, &lpa);
>  		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
>  		else speed = SPEED_10;
>  		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
> @@ -175,7 +173,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  	}
>  
>  	/* Update the MAC */
> -	mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
> +	mac_cfg = at91_emac_read(lp, AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
>  	if (speed == SPEED_100) {
>  		if (duplex == DUPLEX_FULL)		/* 100 Full Duplex */
>  			mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
> @@ -186,7 +184,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
>  			mac_cfg |= AT91_EMAC_FD;
>  		else {}					/* 10 Half Duplex */
>  	}
> -	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
> +	at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
>  
>  	if (!silent)
>  		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
> @@ -207,34 +205,34 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
>  	 * level-triggering.  We therefore have to check if the PHY actually has
>  	 * an IRQ pending.
>  	 */
> -	enable_mdi();
> +	enable_mdi(lp);
>  	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
> -		read_phy(lp->phy_address, MII_DSINTR_REG, &phy);	/* ack interrupt in Davicom PHY */
> +		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &phy);	/* ack interrupt in Davicom PHY */
>  		if (!(phy & (1 << 0)))
>  			goto done;
>  	}
>  	else if (lp->phy_type == MII_LXT971A_ID) {
> -		read_phy(lp->phy_address, MII_ISINTS_REG, &phy);	/* ack interrupt in Intel PHY */
> +		read_phy(lp, lp->phy_address, MII_ISINTS_REG, &phy);	/* ack interrupt in Intel PHY */
>  		if (!(phy & (1 << 2)))
>  			goto done;
>  	}
>  	else if (lp->phy_type == MII_BCM5221_ID) {
> -		read_phy(lp->phy_address, MII_BCMINTR_REG, &phy);	/* ack interrupt in Broadcom PHY */
> +		read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &phy);	/* ack interrupt in Broadcom PHY */
>  		if (!(phy & (1 << 0)))
>  			goto done;
>  	}
>  	else if (lp->phy_type == MII_KS8721_ID) {
> -		read_phy(lp->phy_address, MII_TPISTATUS, &phy);		/* ack interrupt in Micrel PHY */
> +		read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy);		/* ack interrupt in Micrel PHY */
>  		if (!(phy & ((1 << 2) | 1)))
>  			goto done;
>  	}
> -	else if (lp->phy_type == MII_T78Q21x3_ID) {			/* ack interrupt in Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
> +	else if (lp->phy_type == MII_T78Q21x3_ID) {					/* ack interrupt in Teridian PHY */
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
>  		if (!(phy & ((1 << 2) | 1)))
>  			goto done;
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {
> -		read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
> +		read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy);	/* ack interrupt in DP83848 PHY */
>  		if (!(phy & (1 << 7)))
>  			goto done;
>  	}
> @@ -242,7 +240,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
>  	update_linkspeed(dev, 0);
>  
>  done:
> -	disable_mdi();
> +	disable_mdi(lp);
>  
>  	return IRQ_HANDLED;
>  }
> @@ -273,41 +271,41 @@ static void enable_phyirq(struct net_device *dev)
>  	}
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {	/* for Davicom PHY */
> -		read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
>  		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */
> -		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
> -		read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
>  		dsintr = dsintr | 0xf2;			/* set bits 1, 4..7 */
> -		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_BCM5221_ID) {	/* for Broadcom PHY */
>  		dsintr = (1 << 15) | ( 1 << 14);
> -		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_KS8721_ID) {	/* for Micrel PHY */
>  		dsintr = (1 << 10) | ( 1 << 8);
> -		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
> +		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
>  	}
>  	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
>  		dsintr = dsintr | 0x500;		/* set bits 8, 10 */
> -		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
> -		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
>  		dsintr = dsintr | 0x3c;			/* set bits 2..5 */
> -		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
> -		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
>  		dsintr = dsintr | 0x3;			/* set bits 0,1 */
> -		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
>  	}
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  }
>  
> @@ -326,43 +324,43 @@ static void disable_phyirq(struct net_device *dev)
>  	}
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {	/* for Davicom PHY */
> -		read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
>  		dsintr = dsintr | 0xf00;			/* set bits 8..11 */
> -		write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
> -		read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
>  		dsintr = dsintr & ~0xf2;			/* clear bits 1, 4..7 */
> -		write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_BCM5221_ID) {	/* for Broadcom PHY */
> -		read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
>  		dsintr = ~(1 << 14);
> -		write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_KS8721_ID) {	/* for Micrel PHY */
> -		read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
>  		dsintr = ~((1 << 10) | (1 << 8));
> -		write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
> +		write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
>  	}
>  	else if (lp->phy_type == MII_T78Q21x3_ID) {	/* for Teridian PHY */
> -		read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
>  		dsintr = dsintr & ~0x500;			/* clear bits 8, 10 */
> -		write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
>  	}
>  	else if (lp->phy_type == MII_DP83848_ID) {	/* National Semiconductor DP83848 PHY */
> -		read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
>  		dsintr = dsintr & ~0x3;				/* clear bits 0, 1 */
> -		write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
> -		read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
> +		read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
>  		dsintr = dsintr & ~0x3c;			/* clear bits 2..5 */
> -		write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
> +		write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
>  	}
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	irq_number = lp->board_data.phy_irq_pin;
> @@ -379,17 +377,17 @@ static void reset_phy(struct net_device *dev)
>  	unsigned int bmcr;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	/* Perform PHY reset */
> -	write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
> +	write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
>  
>  	/* Wait until PHY reset is complete */
>  	do {
> -		read_phy(lp->phy_address, MII_BMCR, &bmcr);
> +		read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
>  	} while (!(bmcr & BMCR_RESET));
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  }
>  #endif
> @@ -399,13 +397,37 @@ static void at91ether_check_link(unsigned long dev_id)
>  	struct net_device *dev = (struct net_device *) dev_id;
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	enable_mdi();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 1);
> -	disable_mdi();
> +	disable_mdi(lp);
>  
>  	mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
>  }
>  
> +/*
> + * Perform any PHY-specific initialization.
> + */
> +static void __init initialize_phy(struct at91_private *lp)
> +{
> +	unsigned int val;
> +
> +	spin_lock_irq(&lp->lock);
> +	enable_mdi(lp);
> +
> +	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
> +		read_phy(lp, lp->phy_address, MII_DSCR_REG, &val);
> +		if ((val & (1 << 10)) == 0)			/* DSCR bit 10 is 0 -- fiber mode */
> +			lp->phy_media = PORT_FIBRE;
> +	} else if (machine_is_csb337()) {
> +		/* mix link activity status into LED2 link state */
> +		write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
> +	} else if (machine_is_ecbat91())
> +		write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
> +
> +	disable_mdi(lp);
> +	spin_unlock_irq(&lp->lock);
> +}
> +
>  /* ......................... ADDRESS MANAGEMENT ........................ */
>  
>  /*
> @@ -454,17 +476,19 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
>   */
>  static void __init get_mac_address(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
> +
>  	/* Check Specific-Address 1 */
> -	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, AT91_EMAC_SA1L)))
>  		return;
>  	/* Check Specific-Address 2 */
> -	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, AT91_EMAC_SA2L)))
>  		return;
>  	/* Check Specific-Address 3 */
> -	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, AT91_EMAC_SA3L)))
>  		return;
>  	/* Check Specific-Address 4 */
> -	if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
> +	if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
>  		return;
>  
>  	printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
> @@ -475,11 +499,13 @@ static void __init get_mac_address(struct net_device *dev)
>   */
>  static void update_mac_address(struct net_device *dev)
>  {
> -	at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
> -	at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
> +	struct at91_private *lp = netdev_priv(dev);
>  
> -	at91_emac_write(AT91_EMAC_SA2L, 0);
> -	at91_emac_write(AT91_EMAC_SA2H, 0);
> +	at91_emac_write(lp, AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
> +	at91_emac_write(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
> +
> +	at91_emac_write(lp, AT91_EMAC_SA2L, 0);
> +	at91_emac_write(lp, AT91_EMAC_SA2H, 0);
>  }
>  
>  /*
> @@ -559,6 +585,7 @@ static int hash_get_index(__u8 *addr)
>   */
>  static void at91ether_sethashtable(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	struct netdev_hw_addr *ha;
>  	unsigned long mc_filter[2];
>  	unsigned int bitnr;
> @@ -570,8 +597,8 @@ static void at91ether_sethashtable(struct net_device *dev)
>  		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
>  	}
>  
> -	at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
> -	at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
> +	at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
> +	at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
>  }
>  
>  /*
> @@ -579,9 +606,10 @@ static void at91ether_sethashtable(struct net_device *dev)
>   */
>  static void at91ether_set_multicast_list(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	unsigned long cfg;
>  
> -	cfg = at91_emac_read(AT91_EMAC_CFG);
> +	cfg = at91_emac_read(lp, AT91_EMAC_CFG);
>  
>  	if (dev->flags & IFF_PROMISC)			/* Enable promiscuous mode */
>  		cfg |= AT91_EMAC_CAF;
> @@ -589,34 +617,37 @@ static void at91ether_set_multicast_list(struct net_device *dev)
>  		cfg &= ~AT91_EMAC_CAF;
>  
>  	if (dev->flags & IFF_ALLMULTI) {		/* Enable all multicast mode */
> -		at91_emac_write(AT91_EMAC_HSH, -1);
> -		at91_emac_write(AT91_EMAC_HSL, -1);
> +		at91_emac_write(lp, AT91_EMAC_HSH, -1);
> +		at91_emac_write(lp, AT91_EMAC_HSL, -1);
>  		cfg |= AT91_EMAC_MTI;
>  	} else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */
>  		at91ether_sethashtable(dev);
>  		cfg |= AT91_EMAC_MTI;
>  	} else if (dev->flags & (~IFF_ALLMULTI)) {	/* Disable all multicast mode */
> -		at91_emac_write(AT91_EMAC_HSH, 0);
> -		at91_emac_write(AT91_EMAC_HSL, 0);
> +		at91_emac_write(lp, AT91_EMAC_HSH, 0);
> +		at91_emac_write(lp, AT91_EMAC_HSL, 0);
>  		cfg &= ~AT91_EMAC_MTI;
>  	}
>  
> -	at91_emac_write(AT91_EMAC_CFG, cfg);
> +	at91_emac_write(lp, AT91_EMAC_CFG, cfg);
>  }
>  
>  /* ......................... ETHTOOL SUPPORT ........................... */
>  
>  static int mdio_read(struct net_device *dev, int phy_id, int location)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	unsigned int value;
>  
> -	read_phy(phy_id, location, &value);
> +	read_phy(lp, phy_id, location, &value);
>  	return value;
>  }
>  
>  static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
>  {
> -	write_phy(phy_id, location, value);
> +	struct at91_private *lp = netdev_priv(dev);
> +
> +	write_phy(lp, phy_id, location, value);
>  }
>  
>  static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
> @@ -625,11 +656,11 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_ethtool_gset(&lp->mii, cmd);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	if (lp->phy_media == PORT_FIBRE) {		/* override media type since mii.c doesn't know */
> @@ -646,11 +677,11 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_ethtool_sset(&lp->mii, cmd);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return ret;
> @@ -662,11 +693,11 @@ static int at91ether_nwayreset(struct net_device *dev)
>  	int ret;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  
>  	ret = mii_nway_restart(&lp->mii);
>  
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return ret;
> @@ -696,9 +727,9 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
>  		return -EINVAL;
>  
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  	res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	return res;
> @@ -731,11 +762,11 @@ static void at91ether_start(struct net_device *dev)
>  	lp->rxBuffIndex = 0;
>  
>  	/* Program address of descriptor list in Rx Buffer Queue register */
> -	at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
> +	at91_emac_write(lp, AT91_EMAC_RBQP, (unsigned long) dlist_phys);
>  
>  	/* Enable Receive and Transmit */
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
>  }
>  
>  /*
> @@ -752,8 +783,8 @@ static int at91ether_open(struct net_device *dev)
>  	clk_enable(lp->ether_clk);		/* Re-enable Peripheral clock */
>  
>  	/* Clear internal statistics */
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
>  
>  	/* Update the MAC address (incase user has changed it) */
>  	update_mac_address(dev);
> @@ -762,15 +793,15 @@ static int at91ether_open(struct net_device *dev)
>  	enable_phyirq(dev);
>  
>  	/* Enable MAC interrupts */
> -	at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
> +	at91_emac_write(lp, AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
>  				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
>  				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
>  
>  	/* Determine current link speed */
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 0);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  
>  	at91ether_start(dev);
> @@ -787,14 +818,14 @@ static int at91ether_close(struct net_device *dev)
>  	unsigned long ctl;
>  
>  	/* Disable Receiver and Transmitter */
> -	ctl = at91_emac_read(AT91_EMAC_CTL);
> -	at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
> +	ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +	at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
>  
>  	/* Disable PHY interrupt */
>  	disable_phyirq(dev);
>  
>  	/* Disable MAC interrupts */
> -	at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
> +	at91_emac_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
>  				| AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
>  				| AT91_EMAC_ROVR | AT91_EMAC_ABT);
>  
> @@ -812,7 +843,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  {
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
> +	if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
>  		netif_stop_queue(dev);
>  
>  		/* Store packet information (to free when Tx completed) */
> @@ -822,9 +853,9 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>  		dev->stats.tx_bytes += skb->len;
>  
>  		/* Set address of the data in the Transmit Address register */
> -		at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
> +		at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
>  		/* Set length of the packet in the Transmit Control register */
> -		at91_emac_write(AT91_EMAC_TCR, skb->len);
> +		at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
>  
>  	} else {
>  		printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
> @@ -841,31 +872,32 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
>   */
>  static struct net_device_stats *at91ether_stats(struct net_device *dev)
>  {
> +	struct at91_private *lp = netdev_priv(dev);
>  	int ale, lenerr, seqe, lcol, ecol;
>  
>  	if (netif_running(dev)) {
> -		dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK);		/* Good frames received */
> -		ale = at91_emac_read(AT91_EMAC_ALE);
> +		dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK);	/* Good frames received */
> +		ale = at91_emac_read(lp, AT91_EMAC_ALE);
>  		dev->stats.rx_frame_errors += ale;				/* Alignment errors */
> -		lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
> +		lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
>  		dev->stats.rx_length_errors += lenerr;				/* Excessive Length or Undersize Frame error */
> -		seqe = at91_emac_read(AT91_EMAC_SEQE);
> +		seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
>  		dev->stats.rx_crc_errors += seqe;				/* CRC error */
> -		dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC);	/* Receive buffer not available */
> +		dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
>  		dev->stats.rx_errors += (ale + lenerr + seqe
> -			+ at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
> +			+ at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
>  
> -		dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA);		/* Frames successfully transmitted */
> -		dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE);	/* Transmit FIFO underruns */
> -		dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE);	/* Carrier Sense errors */
> -		dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
> +		dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA);	/* Frames successfully transmitted */
> +		dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE);	/* Transmit FIFO underruns */
> +		dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE);	/* Carrier Sense errors */
> +		dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
>  
> -		lcol = at91_emac_read(AT91_EMAC_LCOL);
> -		ecol = at91_emac_read(AT91_EMAC_ECOL);
> +		lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
> +		ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
>  		dev->stats.tx_window_errors += lcol;			/* Late collisions */
>  		dev->stats.tx_aborted_errors += ecol;			/* 16 collisions */
>  
> -		dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
> +		dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
>  	}
>  	return &dev->stats;
>  }
> @@ -922,7 +954,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
>  
>  	/* MAC Interrupt Status register indicates what interrupts are pending.
>  	   It is automatically cleared once read. */
> -	intstatus = at91_emac_read(AT91_EMAC_ISR);
> +	intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
>  
>  	if (intstatus & AT91_EMAC_RCOM)		/* Receive complete */
>  		at91ether_rx(dev);
> @@ -942,9 +974,9 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
>  
>  	/* Work-around for Errata #11 */
>  	if (intstatus & AT91_EMAC_RBNA) {
> -		ctl = at91_emac_read(AT91_EMAC_CTL);
> -		at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
> -		at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
> +		ctl = at91_emac_read(lp, AT91_EMAC_CTL);
> +		at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
> +		at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
>  	}
>  
>  	if (intstatus & AT91_EMAC_ROVR)
> @@ -980,189 +1012,199 @@ static const struct net_device_ops at91ether_netdev_ops = {
>  };
>  
>  /*
> - * Initialize the ethernet interface
> + * Detect the PHY type, and its address.
>   */
> -static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
> -			struct platform_device *pdev, struct clk *ether_clk)
> +static int __init at91ether_phy_detect(struct at91_private *lp)
> +{
> +	unsigned int phyid1, phyid2;
> +	unsigned long phy_id;
> +	unsigned short phy_address = 0;
> +
> +	while (phy_address < PHY_MAX_ADDR) {
> +		/* Read the PHY ID registers */
> +		enable_mdi(lp);
> +		read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
> +		read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
> +		disable_mdi(lp);
> +
> +		phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
> +		switch (phy_id) {
> +			case MII_DM9161_ID:		/* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
> +			case MII_DM9161A_ID:		/* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
> +			case MII_LXT971A_ID:		/* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
> +			case MII_RTL8201_ID:		/* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
> +			case MII_BCM5221_ID:		/* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
> +			case MII_DP83847_ID:		/* National Semiconductor DP83847:  */
> +			case MII_DP83848_ID:		/* National Semiconductor DP83848:  */
> +			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
> +			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
> +			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
> +			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
> +				/* store detected values */
> +				lp->phy_type = phy_id;		/* Type of PHY connected */
> +				lp->phy_address = phy_address;	/* MDI address of PHY */
> +				return 1;
> +		}
> +
> +		phy_address++;
> +	}
> +
> +	return 0;		/* not detected */
> +}
> +
> +
> +/*
> + * Detect MAC & PHY and perform ethernet interface initialization
> + */
> +static int __init at91ether_probe(struct platform_device *pdev)
>  {
>  	struct macb_platform_data *board_data = pdev->dev.platform_data;
> +	struct resource *regs;
>  	struct net_device *dev;
>  	struct at91_private *lp;
> -	unsigned int val;
>  	int res;
>  
> +	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!regs)
> +		return -ENOENT;
> +
>  	dev = alloc_etherdev(sizeof(struct at91_private));
>  	if (!dev)
>  		return -ENOMEM;
>  
> -	dev->base_addr = AT91_VA_BASE_EMAC;
> -	dev->irq = AT91RM9200_ID_EMAC;
> +	lp = netdev_priv(dev);
> +	lp->board_data = *board_data;
> +	spin_lock_init(&lp->lock);
> +
> +	dev->base_addr = regs->start;		/* physical base address */
> +	lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
> +	if (!lp->emac_base) {
> +		res = -ENOMEM;
> +		goto err_free_dev;
> +	}
> +
> +	/* Clock */
> +	lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
> +	if (IS_ERR(lp->ether_clk)) {
> +		res = -ENODEV;
> +		goto err_ioumap;
> +	}
> +	clk_enable(lp->ether_clk);
>  
>  	/* Install the interrupt handler */
> +	dev->irq = platform_get_irq(pdev, 0);
>  	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
> -		free_netdev(dev);
> -		return -EBUSY;
> +		res = -EBUSY;
> +		goto err_disable_clock;
>  	}
>  
>  	/* Allocate memory for DMA Receive descriptors */
> -	lp = netdev_priv(dev);
>  	lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
>  	if (lp->dlist == NULL) {
> -		free_irq(dev->irq, dev);
> -		free_netdev(dev);
> -		return -ENOMEM;
> +		res = -ENOMEM;
> +		goto err_free_irq;
>  	}
> -	lp->board_data = *board_data;
> -	lp->ether_clk = ether_clk;
> -	platform_set_drvdata(pdev, dev);
> -
> -	spin_lock_init(&lp->lock);
>  
>  	ether_setup(dev);
>  	dev->netdev_ops = &at91ether_netdev_ops;
>  	dev->ethtool_ops = &at91ether_ethtool_ops;
> -
> +	platform_set_drvdata(pdev, dev);
>  	SET_NETDEV_DEV(dev, &pdev->dev);
>  
>  	get_mac_address(dev);		/* Get ethernet address and store it in dev->dev_addr */
>  	update_mac_address(dev);	/* Program ethernet address into MAC */
>  
> -	at91_emac_write(AT91_EMAC_CTL, 0);
> +	at91_emac_write(lp, AT91_EMAC_CTL, 0);
>  
> -	if (lp->board_data.is_rmii)
> -		at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
> +	if (board_data->is_rmii)
> +		at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
>  	else
> -		at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
> +		at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
>  
> -	/* Perform PHY-specific initialization */
> -	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> -	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
> -		read_phy(phy_address, MII_DSCR_REG, &val);
> -		if ((val & (1 << 10)) == 0)			/* DSCR bit 10 is 0 -- fiber mode */
> -			lp->phy_media = PORT_FIBRE;
> -	} else if (machine_is_csb337()) {
> -		/* mix link activity status into LED2 link state */
> -		write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
> -	} else if (machine_is_ecbat91())
> -		write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
> +	/* Detect PHY */
> +	if (!at91ether_phy_detect(lp)) {
> +		printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
> +		res = -ENODEV;
> +		goto err_free_dmamem;
> +	}
>  
> -	disable_mdi();
> -	spin_unlock_irq(&lp->lock);
> +	initialize_phy(lp);
>  
>  	lp->mii.dev = dev;		/* Support for ethtool */
>  	lp->mii.mdio_read = mdio_read;
>  	lp->mii.mdio_write = mdio_write;
> -	lp->mii.phy_id = phy_address;
> +	lp->mii.phy_id = lp->phy_address;
>  	lp->mii.phy_id_mask = 0x1f;
>  	lp->mii.reg_num_mask = 0x1f;
>  
> -	lp->phy_type = phy_type;	/* Type of PHY connected */
> -	lp->phy_address = phy_address;	/* MDI address of PHY */
> -
>  	/* Register the network interface */
>  	res = register_netdev(dev);
> -	if (res) {
> -		free_irq(dev->irq, dev);
> -		free_netdev(dev);
> -		dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
> -		return res;
> -	}
> +	if (res)
> +		goto err_free_dmamem;
>  
>  	/* Determine current link speed */
>  	spin_lock_irq(&lp->lock);
> -	enable_mdi();
> +	enable_mdi(lp);
>  	update_linkspeed(dev, 0);
> -	disable_mdi();
> +	disable_mdi(lp);
>  	spin_unlock_irq(&lp->lock);
>  	netif_carrier_off(dev);		/* will be enabled in open() */
>  
>  	/* If board has no PHY IRQ, use a timer to poll the PHY */
> -	if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
> +	if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
> +		gpio_request(board_data->phy_irq_pin, "ethernet_phy");
> +	} else {
> +		/* If board has no PHY IRQ, use a timer to poll the PHY */
>  		init_timer(&lp->check_timer);
>  		lp->check_timer.data = (unsigned long)dev;
>  		lp->check_timer.function = at91ether_check_link;
> -	} else if (lp->board_data.phy_irq_pin >= 32)
> -		gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
> +	}
>  
>  	/* Display ethernet banner */
>  	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n",
>  	       dev->name, (uint) dev->base_addr, dev->irq,
> -	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
> -	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
> +	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
> +	       at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
>  	       dev->dev_addr);
> -	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
> +	if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
>  		printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
> -	else if (phy_type == MII_LXT971A_ID)
> +	else if (lp->phy_type == MII_LXT971A_ID)
>  		printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
> -	else if (phy_type == MII_RTL8201_ID)
> +	else if (lp->phy_type == MII_RTL8201_ID)
>  		printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
> -	else if (phy_type == MII_BCM5221_ID)
> +	else if (lp->phy_type == MII_BCM5221_ID)
>  		printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
> -	else if (phy_type == MII_DP83847_ID)
> +	else if (lp->phy_type == MII_DP83847_ID)
>  		printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
> -	else if (phy_type == MII_DP83848_ID)
> +	else if (lp->phy_type == MII_DP83848_ID)
>  		printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
> -	else if (phy_type == MII_AC101L_ID)
> +	else if (lp->phy_type == MII_AC101L_ID)
>  		printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
> -	else if (phy_type == MII_KS8721_ID)
> +	else if (lp->phy_type == MII_KS8721_ID)
>  		printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
> -	else if (phy_type == MII_T78Q21x3_ID)
> +	else if (lp->phy_type == MII_T78Q21x3_ID)
>  		printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
> -	else if (phy_type == MII_LAN83C185_ID)
> +	else if (lp->phy_type == MII_LAN83C185_ID)
>  		printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
>  
> -	return 0;
> -}
> -
> -/*
> - * Detect MAC and PHY and perform initialization
> - */
> -static int __init at91ether_probe(struct platform_device *pdev)
> -{
> -	unsigned int phyid1, phyid2;
> -	int detected = -1;
> -	unsigned long phy_id;
> -	unsigned short phy_address = 0;
> -	struct clk *ether_clk;
> -
> -	ether_clk = clk_get(&pdev->dev, "ether_clk");
> -	if (IS_ERR(ether_clk)) {
> -		printk(KERN_ERR "at91_ether: no clock defined\n");
> -		return -ENODEV;
> -	}
> -	clk_enable(ether_clk);					/* Enable Peripheral clock */
> -
> -	while ((detected != 0) && (phy_address < 32)) {
> -		/* Read the PHY ID registers */
> -		enable_mdi();
> -		read_phy(phy_address, MII_PHYSID1, &phyid1);
> -		read_phy(phy_address, MII_PHYSID2, &phyid2);
> -		disable_mdi();
> -
> -		phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
> -		switch (phy_id) {
> -			case MII_DM9161_ID:		/* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
> -			case MII_DM9161A_ID:		/* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
> -			case MII_LXT971A_ID:		/* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
> -			case MII_RTL8201_ID:		/* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
> -			case MII_BCM5221_ID:		/* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
> -			case MII_DP83847_ID:		/* National Semiconductor DP83847:  */
> -			case MII_DP83848_ID:		/* National Semiconductor DP83848:  */
> -			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
> -			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
> -			case MII_T78Q21x3_ID:		/* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
> -			case MII_LAN83C185_ID:		/* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
> -				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
> -				break;
> -		}
> +	clk_disable(lp->ether_clk);					/* Disable Peripheral clock */
>  
> -		phy_address++;
> -	}
> +	return 0;
>  
> -	clk_disable(ether_clk);					/* Disable Peripheral clock */
>  
> -	return detected;
> +err_free_dmamem:
> +	platform_set_drvdata(pdev, NULL);
> +	dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
> +err_free_irq:
> +	free_irq(dev->irq, dev);
> +err_disable_clock:
> +	clk_disable(lp->ether_clk);
> +	clk_put(lp->ether_clk);
> +err_ioumap:
> +	iounmap(lp->emac_base);
> +err_free_dev:
> +	free_netdev(dev);
> +	return res;
>  }
>  
>  static int __devexit at91ether_remove(struct platform_device *pdev)
> @@ -1170,8 +1212,7 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
>  	struct net_device *dev = platform_get_drvdata(pdev);
>  	struct at91_private *lp = netdev_priv(dev);
>  
> -	if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
> -	    lp->board_data.phy_irq_pin >= 32)
> +	if (gpio_is_valid(lp->board_data.phy_irq_pin))
>  		gpio_free(lp->board_data.phy_irq_pin);
>  
>  	unregister_netdev(dev);
> diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
> index 3725fbb0..0ef6328 100644
> --- a/drivers/net/ethernet/cadence/at91_ether.h
> +++ b/drivers/net/ethernet/cadence/at91_ether.h
> @@ -88,6 +88,7 @@ struct at91_private
>  	struct macb_platform_data board_data;	/* board-specific
>  						 * configuration (shared with
>  						 * macb for common data */
> +	void __iomem *emac_base;		/* base register address */
>  	struct clk *ether_clk;			/* clock */
>  
>  	/* PHY */


-- 
Nicolas Ferre

^ permalink raw reply

* Re: [PATCH 2/2 net-next] tcp: sk_add_backlog() is too agressive for TCP
From: David Miller @ 2012-04-24  8:25 UTC (permalink / raw)
  To: ilpo.jarvinen
  Cc: eric.dumazet, rick.jones2, netdev, therbert, ncardwell, maze,
	ycheng
In-Reply-To: <alpine.DEB.2.00.1204241113020.735@wel-95.cs.helsinki.fi>

From: "Ilpo Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Tue, 24 Apr 2012 11:21:18 +0300 (EEST)

> On Tue, 24 Apr 2012, David Miller wrote:
> 
>> That makes this a non-starter since we must therefore remember all of
>> the SACK boundaries in the original packets.
> 
> GRO works because TCP tends to use rather constant MSS, right? ...Since 
> ACKs and SACKs are nothing more than reflection of those MSS boundaries of 
> the opposite direction I don't find that as impossible as you do because 
> the same kind of "mss" assumption can be applied there. But GRO has made 
> this somewhat messier now because the receiver doesn't any more generate 
> ACK per MSS or ACK per 2*MSS but that could be "fixed" by offloading the 
> ACK sending when responding to a GROed packet.

We're talking about accumulating ACKs on GRO not data packets.

^ 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