Netdev List
 help / color / mirror / Atom feed
* Re: [RFC,PATCH] mutex: mutex_is_owner() helper
From: Peter Zijlstra @ 2009-11-09 18:56 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Ingo Molnar, Linus Torvalds, David S. Miller, Linux Netdev List,
	linux kernel, Thomas Gleixner
In-Reply-To: <4AF1B7A7.6030902@gmail.com>

On Wed, 2009-11-04 at 18:19 +0100, Eric Dumazet wrote:
> 
> BTW, I was thinking of a mutex_yield() implementation, but could not
> cook it without hard thinking, maybe you already have some nice
> implementation ?

Why? Yield sets off alarm bells, since 99.9%, and possibly more, of its
uses are wrong.

> int mutex_yield(struct mutex *lock)
> {
>         int ret = 0;
> 
>         if (mutex_needbreak(lock) || should_resched()) {
>                 mutex_unlock(lock); 
>                 __cond_resched();
>                 mutex_lock(lock);
>                 ret = 1;
>         }
>         return ret;
> } 

That reads like it should be called cond_resched_mutex(), except that
the should_resched() thing seems daft (but maybe it makes sense for
silly preemption modes like voluntary).

iirc we actually have something similar in -rt in order to implement the
lock-break for the rt-mutex based spinlocks, we set ->needbreak when a
higher priority task contends -- a policy for regular mutexes might be
'interesting' though.

As to your 'debug' helper that started this thread, doesn't
lockdep_assert_held() work for you?

^ permalink raw reply

* Fix syntax of mdio.txt to match actual syntax.
From: Lennart Sorensen @ 2009-11-09 18:56 UTC (permalink / raw)
  To: linux-kernel; +Cc: Kumar Gala, Len Sorensen, netdev

The syntax in Documentation/powerpc/dts-bindings/gpio/mdio.txt is not
up to date and no longer works.  Fix this as well as actually show how
to represent a PHY on the gpio-bitbang bus.

Tested with 2.6.31 on a RuggedCom RX5000 (mpc8360e based).

Signed-off-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>

diff --git a/Documentation/powerpc/dts-bindings/gpio/mdio.txt b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
index bc95495..7a84f25 100644
--- a/Documentation/powerpc/dts-bindings/gpio/mdio.txt
+++ b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
@@ -14,6 +14,15 @@ mdio {
 	compatible = "virtual,mdio-gpio";
 	#address-cells = <1>;
 	#size-cells = <0>;
-	gpios = <&qe_pio_a 11
-		 &qe_pio_c 6>;
+	gpios = <&qe_pio_a 11 0
+		 &qe_pio_c 6 0>;
+
+	phy0: ethernet-phy@00 {
+		reg = <0x18>;
+		device_type = "ethernet-phy";
+	};
+	phy1: ethernet-phy@01 {
+		reg = <0x0f>;
+		device_type = "ethernet-phy";
+	};
 };

^ permalink raw reply related

* Fix gpio-mdio driver to work for gpio's that return something other than 0 and 1.
From: Lennart Sorensen @ 2009-11-09 19:02 UTC (permalink / raw)
  To: linux-kernel; +Cc: Len Sorensen, netdev, Paulius Zaleckas, Laurent Pinchart

The gpio-mdio driver seems to assume GPIOs return 0 and 1, although that
doesn't seem to be the case.  I see return values of 0 and 0x1000000
for the GPIO I happen to be using.  A simple application of !! solves
that though.

Tested on a RuggedCom RX5000 (mpc8360e based).

Signed-off-by: Lennart Sorensen <lsorense@csclub.uwaterloo.ca>

diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 8659d34..7e76f0c 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -55,7 +55,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl)
 	struct mdio_gpio_info *bitbang =
 		container_of(ctrl, struct mdio_gpio_info, ctrl);
 
-	return gpio_get_value(bitbang->mdio);
+	return !!gpio_get_value(bitbang->mdio);
 }
 
 static void mdio_set(struct mdiobb_ctrl *ctrl, int what)

^ permalink raw reply related

* Re: [PATCH] xfrm: SAD entries do not expire correctly after suspend-resume
From: Herbert Xu @ 2009-11-09 19:23 UTC (permalink / raw)
  To: Yury Polyanskiy; +Cc: netdev, davem, peterz, yoshfuji, tglx, mingo
In-Reply-To: <20091109133153.668bb296@penta.localdomain>

On Mon, Nov 09, 2009 at 01:31:53PM -0500, Yury Polyanskiy wrote:
>
> But why would it be inoperable for hours? 

As I said the other end is buggy and won't allow you to reconnect
when you've just connected successfully.  Eventially it'll timeout
and let you back in but it could take hours.

> In any case, running ntpdate before racoon fixes the problem.

Not if the only trusted time source is over IPsec.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <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: pull request: wireless-next-2.6 2009-11-09
From: David Miller @ 2009-11-09 19:28 UTC (permalink / raw)
  To: linville-2XuSBdqkA4R54TAoqtyWWQ
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20091109183010.GF2805-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>

From: "John W. Linville" <linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
Date: Mon, 9 Nov 2009 13:30:10 -0500

> Another big batch of patches intended for 2.6.33...  Among the usual
> suspects are big updates for ath9k, iwlwifi, wl1271, mwl8k, and (especially)
> rt2x00.  Also included are some patches to move some old pre-802.11
> drivers over to staging, and a number of mac80211 updates.
> 
> Please let me know if there are problems!

Pulled, thanks a lot!
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" 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

* RFC: net: allow to propagate errors through ->ndo_hard_start_xmit()
From: Patrick McHardy @ 2009-11-09 19:41 UTC (permalink / raw)
  To: Linux Netdev List
  Cc: Herbert Xu, Jarek Poplawski, David S. Miller, Stephen Hemminger

[-- Attachment #1: Type: text/plain, Size: 1232 bytes --]

I've updated my patch to propagate error values (errno and NET_XMIT
codes) through ndo_hard_start_xmit() and incorporated the suggestions
made last time, namely:

- move slightly complicated return value check to inline function and
  add a few comments

- fix error handling while in the middle of transmitting GSO skbs

I've also audited the tree once again for invalid return values and
found a single remaining instance in a Wimax driver, I'll take care
of that later.

Two questions remain:

- I'm not sure the error handling in dev_hard_start_xmit() for GSO
  skbs is optimal. When the driver returns an error, it is assumed
  the current segment has been freed. The patch then frees the
  entire GSO skb, including all remaining segments. Alternatively
  it could try to transmit the remaining segments later.

- Stephen recently introduced an enum for the netdev_tx codes, with
  this patch drivers are allowed to return different values.
  The mainly useful part about Stephen's patch IMO is the netdev_tx
  typedef to make it easier to locate ndo_start_xmit() functions
  which are defined in different files than the netdev_ops.
  So we could remove the enum again and simply typedef an int.

Any opinions are welcome :)

[-- Attachment #2: 01.diff --]
[-- Type: text/x-patch, Size: 6261 bytes --]

commit 08a98f11bc1c1452df74c171409218d2243f0818
Author: Patrick McHardy <kaber@trash.net>
Date:   Mon Nov 9 20:33:14 2009 +0100

    net: allow to propagate errors through ->ndo_hard_start_xmit()
    
    Currently the ->ndo_hard_start_xmit() callbacks are only permitted to return
    one of the NETDEV_TX codes. This prevents any kind of error propagation for
    virtual devices, like queue congestion of the underlying device in case of
    layered devices, or unreachability in case of tunnels.
    
    This patches changes the NET_XMIT codes to avoid clashes with the NETDEV_TX
    codes and changes the two callers of dev_hard_start_xmit() to expect either
    errno codes, NET_XMIT codes or NETDEV_TX codes as return value.
    
    In case of qdisc_restart(), all non NETDEV_TX codes are mapped to NETDEV_TX_OK
    since no error propagation is possible when using qdiscs. In case of
    dev_queue_xmit(), the error is propagated upwards.
    
    Signed-off-by: Patrick McHardy <kaber@trash.net>

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 465add6..ab2812c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -63,27 +63,48 @@ struct wireless_dev;
 #define HAVE_FREE_NETDEV		/* free_netdev() */
 #define HAVE_NETDEV_PRIV		/* netdev_priv() */
 
-#define NET_XMIT_SUCCESS	0
-#define NET_XMIT_DROP		1	/* skb dropped			*/
-#define NET_XMIT_CN		2	/* congestion notification	*/
-#define NET_XMIT_POLICED	3	/* skb is shot by police	*/
-#define NET_XMIT_MASK		0xFFFF	/* qdisc flags in net/sch_generic.h */
+/*
+ * Transmit return codes: transmit return codes originate from three different
+ * namespaces:
+ *
+ * - qdisc return codes
+ * - driver transmit return codes
+ * - errno values
+ *
+ * Drivers are allowed to return any one of those in their hard_start_xmit()
+ * function. Real network devices commonly used with qdiscs should only return
+ * the driver transmit return codes though - when qdiscs are used, the actual
+ * transmission happens asynchronously, so the value is not propagated to
+ * higher layers. Virtual network devices transmit synchronously, in this case
+ * the driver transmit return codes are consumed by dev_queue_xmit(), all
+ * others are propagated to higher layers.
+ */
+
+/* qdisc ->enqueue() return codes. */
+#define NET_XMIT_SUCCESS	0x00
+#define NET_XMIT_DROP		0x10	/* skb dropped			*/
+#define NET_XMIT_CN		0x20	/* congestion notification	*/
+#define NET_XMIT_POLICED	0x30	/* skb is shot by police	*/
+#define NET_XMIT_MASK		0xf0	/* qdisc flags in net/sch_generic.h */
 
 /* Backlog congestion levels */
-#define NET_RX_SUCCESS		0   /* keep 'em coming, baby */
-#define NET_RX_DROP		1  /* packet dropped */
+#define NET_RX_SUCCESS		0	/* keep 'em coming, baby */
+#define NET_RX_DROP		1	/* packet dropped */
 
 /* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It
  * indicates that the device will soon be dropping packets, or already drops
  * some packets of the same priority; prompting us to send less aggressively. */
-#define net_xmit_eval(e)	((e) == NET_XMIT_CN? 0 : (e))
+#define net_xmit_eval(e)	((e) == NET_XMIT_CN ? 0 : (e))
 #define net_xmit_errno(e)	((e) != NET_XMIT_CN ? -ENOBUFS : 0)
 
 /* Driver transmit return codes */
+#define NETDEV_TX_MASK		0xf
+
 enum netdev_tx {
-	NETDEV_TX_OK = 0,	/* driver took care of packet */
-	NETDEV_TX_BUSY,		/* driver tx path was busy*/
-	NETDEV_TX_LOCKED = -1,	/* driver tx lock was already taken */
+	__NETDEV_TX_MIN	 = INT_MIN,	/* make sure enum is signed */
+	NETDEV_TX_OK	 = 0,		/* driver took care of packet */
+	NETDEV_TX_BUSY	 = 1,		/* driver tx path was busy*/
+	NETDEV_TX_LOCKED = 2,		/* driver tx lock was already taken */
 };
 typedef enum netdev_tx netdev_tx_t;
 
diff --git a/net/core/dev.c b/net/core/dev.c
index bf629ac..1f5752d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1756,7 +1756,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 			struct netdev_queue *txq)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
-	int rc;
+	int rc = NETDEV_TX_OK;
 
 	if (likely(!skb->next)) {
 		if (!list_empty(&ptype_all))
@@ -1804,6 +1804,8 @@ gso:
 		nskb->next = NULL;
 		rc = ops->ndo_start_xmit(nskb, dev);
 		if (unlikely(rc != NETDEV_TX_OK)) {
+			if (rc & ~NETDEV_TX_MASK)
+				goto out_kfree_gso_skb;
 			nskb->next = skb->next;
 			skb->next = nskb;
 			return rc;
@@ -1813,11 +1815,14 @@ gso:
 			return NETDEV_TX_BUSY;
 	} while (skb->next);
 
-	skb->destructor = DEV_GSO_CB(skb)->destructor;
+	rc = NETDEV_TX_OK;
 
+out_kfree_gso_skb:
+	if (likely(skb->next == NULL))
+		skb->destructor = DEV_GSO_CB(skb)->destructor;
 out_kfree_skb:
 	kfree_skb(skb);
-	return NETDEV_TX_OK;
+	return rc;
 }
 
 static u32 skb_tx_hashrnd;
@@ -1905,6 +1910,23 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
 	return rc;
 }
 
+static inline bool dev_xmit_complete(int rc)
+{
+	/* successful transmission */
+	if (rc == NETDEV_TX_OK)
+		return true;
+
+	/* error while transmitting, driver consumed skb */
+	if (rc < 0)
+		return true;
+
+	/* error while queueing to a different device, driver consumed skb */
+	if (rc & NET_XMIT_MASK)
+		return true;
+
+	return false;
+}
+
 /**
  *	dev_queue_xmit - transmit a buffer
  *	@skb: buffer to transmit
@@ -2002,8 +2024,8 @@ gso:
 			HARD_TX_LOCK(dev, txq, cpu);
 
 			if (!netif_tx_queue_stopped(txq)) {
-				rc = NET_XMIT_SUCCESS;
-				if (!dev_hard_start_xmit(skb, dev, txq)) {
+				rc = dev_hard_start_xmit(skb, dev, txq);
+				if (dev_xmit_complete(rc)) {
 					HARD_TX_UNLOCK(dev, txq);
 					goto out;
 				}
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 4ae6aa5..b13821a 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -120,8 +120,15 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
 
 	HARD_TX_LOCK(dev, txq, smp_processor_id());
 	if (!netif_tx_queue_stopped(txq) &&
-	    !netif_tx_queue_frozen(txq))
+	    !netif_tx_queue_frozen(txq)) {
 		ret = dev_hard_start_xmit(skb, dev, txq);
+
+		/* an error implies that the skb was consumed */
+		if (ret < 0)
+			ret = NETDEV_TX_OK;
+		/* all NET_XMIT codes map to NETDEV_TX_OK */
+		ret &= ~NET_XMIT_MASK;
+	}
 	HARD_TX_UNLOCK(dev, txq);
 
 	spin_lock(root_lock);

^ permalink raw reply related

* Re: RFC: net: allow to propagate errors through ->ndo_hard_start_xmit()
From: Herbert Xu @ 2009-11-09 19:50 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Linux Netdev List, Jarek Poplawski, David S. Miller,
	Stephen Hemminger
In-Reply-To: <4AF87070.6020007@trash.net>

On Mon, Nov 09, 2009 at 08:41:36PM +0100, Patrick McHardy wrote:
> 
> - I'm not sure the error handling in dev_hard_start_xmit() for GSO
>   skbs is optimal. When the driver returns an error, it is assumed
>   the current segment has been freed. The patch then frees the
>   entire GSO skb, including all remaining segments. Alternatively
>   it could try to transmit the remaining segments later.

Well driver errors (not queueing errors) should never happen.
And if they do then they're likely to persist.  So freeing the
rest should be sufficient, unless of course if doing it some
other way is simpler :)

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <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: TC-HTB issue : low throughput
From: Jean Tourrilhes @ 2009-11-09 20:04 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: netdev
In-Reply-To: <4AF60349.8000502@gmail.com>

On Sun, Nov 08, 2009 at 12:31:21AM +0100, Jarek Poplawski wrote:
> Jean Tourrilhes wrote, On 11/07/2009 03:43 AM:
> 
> > Behaviour :
> > ---------
> > 
> > 	If I add classes 1:2 and 1:3 :
> > 	Each host independantly : ~170 Mb/s.
> > 	Both host together, for 10.10.10.38 : ~106 Mb/s ;
> > 	Both host together, for 10.10.10.33 : ~135 Mb/s
> > 
> > 	So, not only performance did drop significantely, but
> > prioritisation did not happen as expected.
> 
> If these eths are vlans (or other virtuals) something like this
> often happens if you forget to set dev's txqueuelen before
> adding classes (or a subqdisc with some 'limit').

	Thanks a lot ! I've just added :
ifconfig eth6.34 txqueuelen 5
	And now I get 450 Mb/s + 133 Mb/s. Not perfect, but much much
better, and probably good enough for now ;-)


> > 	I've noticed that /sbin/tc calculates a very low burst
> > value. This is due to the content of /proc/net/psched. I'm wondering
> > if the burst calculation is what causes the issue here.
> > 	However, I tried with "burst 50kb" and saw no difference...
> 
> There is (probably still) unfixed overflow in tc.
> 
> BTW, v2.6.31 should be more exact (but so much...) for above 100mbit
> scheduling, especially with this patch to iproute2:
> http://marc.info/?l=linux-netdev&m=124453482324409&w=2
> 
> Jarek P.

	Thanks. I'll look into upgrading.
	Regards,

	Jean

^ permalink raw reply

* [PATCH] iproute2: ip route flush bugfix
From: Sven Anders @ 2009-11-09 19:39 UTC (permalink / raw)
  To: netdev


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

Hello!

I experienced an error, if I try to perform a

  ip route flush proto 4

with many routes in a complex environment, it
gave me the following error:

  Failed to send flush request: Success
  Flush terminated

I'm using version 2.6.29.
I check GIT, but there was only the "MSG_PEEK" fix.

I tracked it down to the rtnl_send_check() function
in lib/libnetlink.c.

In this function there is the following for loop:

        for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
             h = NLMSG_NEXT(h, status)) {
                if (h->nlmsg_type == NLMSG_ERROR) {
                        struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
                        if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
                                fprintf(stderr, "ERROR truncated\n");
                        else
                                errno = -err->error;
		}
                return -1;
        }

I think the "return -1;" should be inside the if statement.

I attached a patch for this. The first part of the patch is taken from
one of the late git commits.

Please note me, if the fix is wrong...


Regards
 Sven

PS: This is a repost, because I neither received a confirmation nor a remark, that
    the fix is wrong. Moreover the fix didn't make it in the GIT repository yet...
-- 
 Sven Anders <anders@anduras.de>                 () Ascii Ribbon Campaign
                                                 /\ Support plain text e-mail
 Weidestraße 19 - 30453 Hannover || Höllgasse 28 - 94032 Passau  @  Germany
 Web: http://staff2.anduras.de/anders/kim/ - Tel: +49 (0)170 / 80 911 80

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: iproute-2.6.29-flush.patch --]
[-- Type: text/x-patch; name="iproute-2.6.29-flush.patch", Size: 649 bytes --]

--- iproute2-2.6.29/lib/libnetlink.c.orig	2009-09-23 14:47:03.000000000 +0200
+++ iproute2-2.6.29/lib/libnetlink.c	2009-09-23 14:48:09.000000000 +0200
@@ -122,7 +122,7 @@ int rtnl_send_check(struct rtnl_handle *
 		return status;
 
 	/* Check for errors */
-	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
+	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
 	if (status < 0) {
 		if (errno == EAGAIN)
 			return 0;
@@ -137,8 +137,8 @@ int rtnl_send_check(struct rtnl_handle *
 				fprintf(stderr, "ERROR truncated\n");
 			else 
 				errno = -err->error;
-		}
 		return -1;
+		}
 	}
 
 	return 0;


[-- Attachment #1.3: sven.vcf --]
[-- Type: text/x-vcard, Size: 307 bytes --]

begin:vcard
fn:Sven Anders
n:Anders;Sven
adr;quoted-printable:;;Weidestra=C3=9Fe 19;Hannover;Niedersachsen;30453;Deutschland
email;internet:sven@anduras.de
tel;home:+49 (0)511 / 2123090
tel;cell:+49 (0)170 / 8091180
x-mozilla-html:FALSE
url:http://staff.anduras.de/anders
version:2.1
end:vcard


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

^ permalink raw reply

* Re: [PATCH] iproute2: ip route flush bugfix
From: Eric Dumazet @ 2009-11-09 20:24 UTC (permalink / raw)
  To: Sven Anders; +Cc: netdev, Stephen Hemminger
In-Reply-To: <4AF86FE3.4090005@anduras.de>

Sven Anders a écrit :
> Hello!
> 
> I experienced an error, if I try to perform a
> 
>   ip route flush proto 4
> 
> with many routes in a complex environment, it
> gave me the following error:
> 
>   Failed to send flush request: Success
>   Flush terminated
> 
> I'm using version 2.6.29.
> I check GIT, but there was only the "MSG_PEEK" fix.
> 
> I tracked it down to the rtnl_send_check() function
> in lib/libnetlink.c.
> 
> In this function there is the following for loop:
> 
>         for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
>              h = NLMSG_NEXT(h, status)) {
>                 if (h->nlmsg_type == NLMSG_ERROR) {
>                         struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
>                         if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
>                                 fprintf(stderr, "ERROR truncated\n");
>                         else
>                                 errno = -err->error;
> 		}
>                 return -1;
>         }
> 
> I think the "return -1;" should be inside the if statement.
> 
> I attached a patch for this. The first part of the patch is taken from
> one of the late git commits.
> 
> Please note me, if the fix is wrong...
> 
> 
> Regards
>  Sven
> 
> PS: This is a repost, because I neither received a confirmation nor a remark, that
>     the fix is wrong. Moreover the fix didn't make it in the GIT repository yet...
> 


Yes, I posted a similar patch yesterday :)

http://article.gmane.org/gmane.linux.network/142908

Still waiting an ACK from Stephen


^ permalink raw reply

* [PATCH] e1000e: Add new ID
From: Sven Anders @ 2009-11-09 20:25 UTC (permalink / raw)
  To: netdev


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

Hello!

We use the the 82571EB (QUAD COPPER BP) with the e1000e driver.
We haven't experienced any problems yet.

The patch is trivial, just adding a new PCI ID...

Regards
 Sven Anders

-- 
 Sven Anders <anders@anduras.de>                 () Ascii Ribbon Campaign
                                                 /\ Support plain text e-mail
 ANDURAS service solutions AG
 Innstrasse 71 - 94036 Passau - Germany
 Web: www.anduras.de - Tel: +49 (0)851-4 90 50-0 - Fax: +49 (0)851-4 90 50-55

Those who would give up essential Liberty, to purchase a little
temporary Safety, deserve neither Liberty nor Safety.
  - Benjamin Franklin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: e1000e-Add_ID_01A0.patch --]
[-- Type: text/x-patch; name="e1000e-Add_ID_01A0.patch", Size: 1724 bytes --]

--- linux-2.6.26.2/drivers/net/e1000e/hw.h.orig	2008-09-29 14:20:55.000000000 +0200
+++ linux-2.6.26.2/drivers/net/e1000e/hw.h	2008-09-29 14:26:38.000000000 +0200
@@ -323,6 +323,7 @@
 #define E1000_DEV_ID_82571PT_QUAD_COPPER	0x10D5
 #define E1000_DEV_ID_82571EB_QUAD_FIBER		0x10A5
 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LP	0x10BC
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_BP	0x10A0
 #define E1000_DEV_ID_82571EB_SERDES_DUAL	0x10D9
 #define E1000_DEV_ID_82571EB_SERDES_QUAD	0x10DA
 #define E1000_DEV_ID_82572EI_COPPER		0x107D
--- linux-2.6.26.2/drivers/net/e1000e/netdev.c.orig	2008-09-29 14:27:01.000000000 +0200
+++ linux-2.6.26.2/drivers/net/e1000e/netdev.c	2008-09-29 14:27:29.000000000 +0200
@@ -4560,6 +4560,7 @@
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_BP), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 },
--- linux-2.6.26.2/drivers/net/e1000e/82571.c.orig	2008-09-29 14:27:42.000000000 +0200
+++ linux-2.6.26.2/drivers/net/e1000e/82571.c	2008-09-29 14:28:04.000000000 +0200
@@ -274,6 +274,7 @@
 	case E1000_DEV_ID_82571EB_QUAD_COPPER:
 	case E1000_DEV_ID_82571EB_QUAD_FIBER:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER_BP:
 	case E1000_DEV_ID_82571PT_QUAD_COPPER:
 		adapter->flags |= FLAG_IS_QUAD_PORT;
 		/* mark the first port */

[-- Attachment #1.3: sven.vcf --]
[-- Type: text/x-vcard, Size: 307 bytes --]

begin:vcard
fn:Sven Anders
n:Anders;Sven
adr;quoted-printable:;;Weidestra=C3=9Fe 19;Hannover;Niedersachsen;30453;Deutschland
email;internet:sven@anduras.de
tel;home:+49 (0)511 / 2123090
tel;cell:+49 (0)170 / 8091180
x-mozilla-html:FALSE
url:http://staff.anduras.de/anders
version:2.1
end:vcard


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

^ permalink raw reply

* [PATCH] e1000e: Fix usage under kexec
From: Sven Anders @ 2009-11-09 20:25 UTC (permalink / raw)
  To: netdev


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

Hello!

We're experiencing the following problem:

We start a minimal linux system, prepare the system and start the
final system via kexec.
On two different systems (one with a 82573 and one with a 82574),
the driver cannot initialize the network hardware, because the PHY
is not recognized.

We get the following error:
  e1000e: probe of 0000:02:00.0 failed with error -2

We cannot unload the driver of the first kernel, because it's
compiled in statically.

It's caused by the PHY, because it's already initialized by the
first driver and therefore does not respond correctly. The driver
assumes the PHY to be in 'reset' state, which is done by the BIOS.

We fixed it by adding a

+       /* Reset PHY before initializing it. Allows re-init after kexec. */
+       if (!e1000_check_reset_block(hw))
+         e1000_phy_hw_reset(hw);

to the initialization routine. I'm not sure, if we need the additional
"block" check.
A patch is attached.

Please send a note, if the patch is correct or wrong...

Regards
 Sven Anders

-- 
 Sven Anders <anders@anduras.de>                 () Ascii Ribbon Campaign
                                                 /\ Support plain text e-mail
 ANDURAS service solutions AG
 Innstrasse 71 - 94036 Passau - Germany
 Web: www.anduras.de - Tel: +49 (0)851-4 90 50-0 - Fax: +49 (0)851-4 90 50-55

Those who would give up essential Liberty, to purchase a little
temporary Safety, deserve neither Liberty nor Safety.
  - Benjamin Franklin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: e1000e-kexec.patch --]
[-- Type: text/x-patch; name="e1000e-kexec.patch", Size: 507 bytes --]

--- linux-2.6.29.6/drivers/net/e1000e/82571.c.orig	2009-11-04 00:44:27.000000000 +0100
+++ linux-2.6.29.6/drivers/net/e1000e/82571.c	2009-11-04 00:44:19.000000000 +0100
@@ -107,6 +107,10 @@ static s32 e1000_init_phy_params_82571(s
 		break;
 	}
 
+	/* Reset PHY before initializing it. Allows re-init after kexec. */
+	if (!e1000_check_reset_block(hw))
+	  e1000_phy_hw_reset(hw);
+
 	/* This can only be done after all function pointers are setup. */
 	ret_val = e1000_get_phy_id_82571(hw);
 

[-- Attachment #1.3: sven.vcf --]
[-- Type: text/x-vcard, Size: 307 bytes --]

begin:vcard
fn:Sven Anders
n:Anders;Sven
adr;quoted-printable:;;Weidestra=C3=9Fe 19;Hannover;Niedersachsen;30453;Deutschland
email;internet:sven@anduras.de
tel;home:+49 (0)511 / 2123090
tel;cell:+49 (0)170 / 8091180
x-mozilla-html:FALSE
url:http://staff.anduras.de/anders
version:2.1
end:vcard


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

^ permalink raw reply

* [PATCH net-next-2.6] ipv6: speedup inet6_dump_ifinfo()
From: Eric Dumazet @ 2009-11-09 22:11 UTC (permalink / raw)
  To: David S. Miller; +Cc: Linux Netdev List

When handling large number of netdevice, inet6_dump_ifinfo()
is very slow because it has O(N^2) complexity.

Instead of scanning one single list, we can use the 256 sub lists
of the dev_index hash table, and RCU lookups.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/addrconf.c |   45 ++++++++++++++++++++++++++----------------
 1 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 024bba3..f9f7fd6 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3823,28 +3823,39 @@ nla_put_failure:
 static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
-	int idx, err;
-	int s_idx = cb->args[0];
+	int h, s_h;
+	int idx = 0, err, s_idx;
 	struct net_device *dev;
 	struct inet6_dev *idev;
+	struct hlist_head *head;
+	struct hlist_node *node;
 
-	read_lock(&dev_base_lock);
-	idx = 0;
-	for_each_netdev(net, dev) {
-		if (idx < s_idx)
-			goto cont;
-		if ((idev = in6_dev_get(dev)) == NULL)
-			goto cont;
-		err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
-				cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
-		in6_dev_put(idev);
-		if (err <= 0)
-			break;
+	s_h = cb->args[0];
+	s_idx = cb->args[1];
+
+	rcu_read_lock();
+	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+		idx = 0;
+		head = &net->dev_index_head[h];
+		hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
+			if (idx < s_idx)
+				goto cont;
+			idev = __in6_dev_get(dev);
+			if (!idev)
+				goto cont;
+			if (inet6_fill_ifinfo(skb, idev,
+					      NETLINK_CB(cb->skb).pid,
+					      cb->nlh->nlmsg_seq,
+					      RTM_NEWLINK, NLM_F_MULTI) <= 0)
+				goto out;
 cont:
-		idx++;
+			idx++;
+		}
 	}
-	read_unlock(&dev_base_lock);
-	cb->args[0] = idx;
+out:
+	rcu_read_unlock();
+	cb->args[1] = idx;
+	cb->args[0] = h;
 
 	return skb->len;
 }

^ permalink raw reply related

* [PATCH] IPv6: use ipv6_addr_v4mapped()
From: Brian Haley @ 2009-11-09 22:05 UTC (permalink / raw)
  To: David Miller; +Cc: netdev@vger.kernel.org

Change udp6_portaddr_hash() to use ipv6_addr_v4mapped()
inline instead of ipv6_addr_type().

Signed-off-by: Brian Haley <brian.haley@hp.com>
---

diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 2915e1d..0ed1637 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -89,7 +89,7 @@ static unsigned int udp6_portaddr_hash(struct net *net,
 
 	if (ipv6_addr_any(addr6))
 		hash = jhash_1word(0, mix);
-	else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED)
+	else if (ipv6_addr_v4mapped(addr6))
 		hash = jhash_1word(addr6->s6_addr32[3], mix);
 	else
 		hash = jhash2(addr6->s6_addr32, 4, mix);

^ permalink raw reply related

* Re: [PATCH] IPv6: use ipv6_addr_v4mapped()
From: Eric Dumazet @ 2009-11-09 22:59 UTC (permalink / raw)
  To: Brian Haley; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <4AF89241.7060203@hp.com>

Brian Haley a écrit :
> Change udp6_portaddr_hash() to use ipv6_addr_v4mapped()
> inline instead of ipv6_addr_type().
> 
> Signed-off-by: Brian Haley <brian.haley@hp.com>
> ---
> 
> diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
> index 2915e1d..0ed1637 100644
> --- a/net/ipv6/udp.c
> +++ b/net/ipv6/udp.c
> @@ -89,7 +89,7 @@ static unsigned int udp6_portaddr_hash(struct net *net,
>  
>  	if (ipv6_addr_any(addr6))
>  		hash = jhash_1word(0, mix);
> -	else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED)
> +	else if (ipv6_addr_v4mapped(addr6))
>  		hash = jhash_1word(addr6->s6_addr32[3], mix);
>  	else
>  		hash = jhash2(addr6->s6_addr32, 4, mix);

Indeed, its a bit faster ;)

Acked-by: Eric Dumazet <eric.dumazet@gmail.com>

Thanks Brian


^ permalink raw reply

* Re: [RFC,PATCH] mutex: mutex_is_owner() helper
From: Eric Dumazet @ 2009-11-09 23:21 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Linus Torvalds, David S. Miller, Linux Netdev List,
	linux kernel, Thomas Gleixner
In-Reply-To: <1257792987.4108.364.camel@laptop>

Peter Zijlstra a écrit :
> On Wed, 2009-11-04 at 18:19 +0100, Eric Dumazet wrote:
>> BTW, I was thinking of a mutex_yield() implementation, but could not
>> cook it without hard thinking, maybe you already have some nice
>> implementation ?
> 
> Why? Yield sets off alarm bells, since 99.9%, and possibly more, of its
> uses are wrong.

If I remember well, I had problems doing "modprobe dummy numdummies=30000",
because it creates 30000 netdevices, and thanks to hotplug starts 30000 udev
that all wait that my modprobe is finished... Nice to see load average going
so big by the way :)

I tried following patch without success, because rtnl_unlock()/rtnl_lock()
is too fast (awaken process(es) ha(s/ve) no chance to get the lock, as we
take it immediately after releasing it)

diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 37dcfdc..3de1466 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -138,8 +138,11 @@ static int __init dummy_init_module(void)
 	rtnl_lock();
 	err = __rtnl_link_register(&dummy_link_ops);
 
-	for (i = 0; i < numdummies && !err; i++)
+	for (i = 0; i < numdummies && !err; i++) {
 		err = dummy_init_one();
+		rtnl_unlock();
+		rtnl_lock();
+	}
 	if (err < 0)
 		__rtnl_link_unregister(&dummy_link_ops);
 	rtnl_unlock();



Then I added a msleep(1) between the unlock/lock and got beter results.



diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 37dcfdc..108c4fa 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -138,8 +138,12 @@ static int __init dummy_init_module(void)
 	rtnl_lock();
 	err = __rtnl_link_register(&dummy_link_ops);
 
-	for (i = 0; i < numdummies && !err; i++)
+	for (i = 0; i < numdummies && !err; i++) {
 		err = dummy_init_one();
+		rtnl_unlock();
+		msleep(1);
+		rtnl_lock();
+	}
 	if (err < 0)
 		__rtnl_link_unregister(&dummy_link_ops);
 	rtnl_unlock();

But if hotplug is disabled, this force a useless msleep(1) * 30000 -> this is bit slow

Yes, this code is stupid, but I use it to stress network stack
with insane number of devices, to spot scalability problems.


mutex_yield() could help in this situation.

mutex is said to be FIFO, but its not exactly true : A new comer can take the mutex
even if 10000 threads are waiting on mutex...

I wont mention other problems, because mutex_{try}lock() has no timedwait variant, and
funny code doing :

if (!rtnl_trylock())
	return restart_syscall();

Making 30000 processes running/fighting to get the mutex :(


^ permalink raw reply related

* [PATCH 1/2] alchemy: add au1000-eth platform device
From: Florian Fainelli @ 2009-11-10  0:13 UTC (permalink / raw)
  To: Ralf Baechle, netdev, David Miller; +Cc: linux-mips

(resending per Ralf's request as the patch had some checkpatch errors)

This patch makes the board code register the au1000-eth
platform device. The au1000-eth platform data can be
overriden with the au1xxx_override_eth_cfg function
like it has to be done for the Bosporus board which uses
a different MAC/PHY setup.

Changes from v3:
- declare a static au1000_eth_platform_data structure for bosporus and
initialize it
- remove parenthis and bit shifting on SYS_PF_NI2

Changes from v2:
- declared the au1000-eth second driver instance platform_data
- made the override function generic and pass it the port number too

Changes from v1:
- remove per-board platform.c file
- add an override function to pass custom eth0 platform_data PHY settings

Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 3be14b0..3fbe30c 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -19,6 +19,7 @@
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-au1x00/au1xxx_eth.h>
 
 #define PORT(_base, _irq)					\
 	{							\
@@ -326,6 +327,88 @@ static struct platform_device pbdb_smbus_device = {
 };
 #endif
 
+/* Macro to help defining the Ethernet MAC resources */
+#define MAC_RES(_base, _enable, _irq)			\
+	{						\
+		.start	= CPHYSADDR(_base),		\
+		.end	= CPHYSADDR(_base + 0xffff),	\
+		.flags	= IORESOURCE_MEM,		\
+	},						\
+	{						\
+		.start	= CPHYSADDR(_enable),		\
+		.end	= CPHYSADDR(_enable + 0x3),	\
+		.flags	= IORESOURCE_MEM,		\
+	},						\
+	{						\
+		.start	= _irq,				\
+		.end	= _irq,				\
+		.flags	= IORESOURCE_IRQ		\
+	}
+
+static struct resource au1xxx_eth0_resources[] = {
+#if defined(CONFIG_SOC_AU1000)
+	MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT),
+#elif defined(CONFIG_SOC_AU1100)
+	MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT),
+#elif defined(CONFIG_SOC_AU1550)
+	MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT),
+#elif defined(CONFIG_SOC_AU1500)
+	MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT),
+#endif
+};
+
+static struct resource au1xxx_eth1_resources[] = {
+#if defined(CONFIG_SOC_AU1000)
+	MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT),
+#elif defined(CONFIG_SOC_AU1550)
+	MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT),
+#elif defined(CONFIG_SOC_AU1500)
+	MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT),
+#endif
+};
+
+static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
+	.phy1_search_mac0 = 1,
+};
+
+static struct platform_device au1xxx_eth0_device = {
+	.name		= "au1000-eth",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(au1xxx_eth0_resources),
+	.resource	= au1xxx_eth0_resources,
+	.dev.platform_data = &au1xxx_eth0_platform_data,
+};
+
+#ifndef CONFIG_SOC_AU1100
+static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
+	.phy1_search_mac0 = 1,
+};
+
+static struct platform_device au1xxx_eth1_device = {
+	.name		= "au1000-eth",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(au1xxx_eth1_resources),
+	.resource	= au1xxx_eth1_resources,
+	.dev.platform_data = &au1xxx_eth1_platform_data,
+};
+#endif
+
+void __init au1xxx_override_eth_cfg(unsigned int port,
+			struct au1000_eth_platform_data *eth_data)
+{
+	if (!eth_data || port > 1)
+		return;
+
+	if (port == 0)
+		memcpy(&au1xxx_eth0_platform_data, eth_data,
+			sizeof(struct au1000_eth_platform_data));
+#ifndef CONFIG_SOC_AU1100
+	else
+		memcpy(&au1xxx_eth1_platform_data, eth_data,
+			sizeof(struct au1000_eth_platform_data));
+#endif
+}
+
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1xx0_uart_device,
 	&au1xxx_usb_ohci_device,
@@ -345,6 +428,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
 #ifdef SMBUS_PSC_BASE
 	&pbdb_smbus_device,
 #endif
+	&au1xxx_eth0_device,
 };
 
 static int __init au1xxx_platform_init(void)
@@ -356,6 +440,12 @@ static int __init au1xxx_platform_init(void)
 	for (i = 0; au1x00_uart_data[i].flags; i++)
 		au1x00_uart_data[i].uartclk = uartclk;
 
+#ifndef CONFIG_SOC_AU1100
+	/* Register second MAC if enabled in pinfunc */
+	if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2))
+		platform_device_register(&au1xxx_eth1_device);
+#endif
+
 	return platform_add_devices(au1xxx_platform_devices,
 				    ARRAY_SIZE(au1xxx_platform_devices));
 }
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index 7aee14d..ad26db2 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -32,6 +32,7 @@
 #include <linux/interrupt.h>
 
 #include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_eth.h>
 #include <asm/mach-db1x00/db1x00.h>
 #include <asm/mach-db1x00/bcsr.h>
 
@@ -43,6 +44,18 @@ char irq_tab_alchemy[][5] __initdata = {
 	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
 };
 #endif
+	
+/*
+ * Micrel/Kendin 5 port switch attached to MAC0,
+ * MAC0 is associated with PHY address 5 (== WAN port)
+ * MAC1 is not associated with any PHY, since it's connected directly
+ * to the switch.
+ * no interrupts are used
+ */
+static struct au1000_eth_platform_data eth0_pdata = {
+	.phy_static_config	= 1,
+	.phy_addr		= 5,
+};
 
 #ifdef CONFIG_MIPS_BOSPORUS
 char irq_tab_alchemy[][5] __initdata = {
@@ -50,6 +63,8 @@ char irq_tab_alchemy[][5] __initdata = {
 	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741   */
 	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
 };
+
+
 #endif
 
 #ifdef CONFIG_MIPS_MIRAGE
@@ -103,6 +118,8 @@ void __init board_setup(void)
 	printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
 #endif
 #ifdef CONFIG_MIPS_BOSPORUS
+	au1xxx_override_eth_cfg(0, &eth0_pdata);
+
 	printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
 #endif
 #ifdef CONFIG_MIPS_MIRAGE
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h
new file mode 100644
index 0000000..f30529e
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_eth.h
@@ -0,0 +1,18 @@
+#ifndef __AU1X00_ETH_DATA_H
+#define __AU1X00_ETH_DATA_H
+
+/* Platform specific PHY configuration passed to the MAC driver */
+struct au1000_eth_platform_data {
+	int phy_static_config;
+	int phy_search_highest_addr;
+	int phy1_search_mac0;
+	int phy_addr;
+	int phy_busid;
+	int phy_irq;
+};
+
+void __init au1xxx_override_eth_cfg(unsigned port,
+			struct au1000_eth_platform_data *eth_data);
+
+#endif /* __AU1X00_ETH_DATA_H */
+

^ permalink raw reply related

* [PATCH 2/2] au1000-eth: convert to platform_driver model
From: Florian Fainelli @ 2009-11-10  0:13 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: linux-mips, netdev, David Miller

This patch converts the au1000-eth driver to become a full
platform-driver as it ought to be. We now pass PHY-speficic
configurations through platform_data but for compatibility
the driver still assumes the default settings (search for PHY1 on
MAC0) when no platform_data is passed. Tested on my MTX-1 board.

Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index ce6f1ac..6d5a2cb 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -55,6 +55,7 @@
 #include <linux/delay.h>
 #include <linux/crc32.h>
 #include <linux/phy.h>
+#include <linux/platform_device.h>

 #include <asm/cpu.h>
 #include <asm/mipsregs.h>
@@ -63,6 +64,7 @@
 #include <asm/processor.h>

 #include <au1000.h>
+#include <au1xxx_eth.h>
 #include <prom.h>

 #include "au1000_eth.h"
@@ -112,15 +114,15 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
  *
  * PHY detection algorithm
  *
- * If AU1XXX_PHY_STATIC_CONFIG is undefined, the PHY setup is
+ * If phy_static_config is undefined, the PHY setup is
  * autodetected:
  *
  * mii_probe() first searches the current MAC's MII bus for a PHY,
- * selecting the first (or last, if AU1XXX_PHY_SEARCH_HIGHEST_ADDR is
+ * selecting the first (or last, if phy_search_highest_addr is
  * defined) PHY address not already claimed by another netdev.
  *
  * If nothing was found that way when searching for the 2nd ethernet
- * controller's PHY and AU1XXX_PHY1_SEARCH_ON_MAC0 is defined, then
+ * controller's PHY and phy1_search_mac0 is defined, then
  * the first MII bus is searched as well for an unclaimed PHY; this is
  * needed in case of a dual-PHY accessible only through the MAC0's MII
  * bus.
@@ -129,9 +131,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
  * controller is not registered to the network subsystem.
  */

-/* autodetection defaults */
-#undef  AU1XXX_PHY_SEARCH_HIGHEST_ADDR
-#define AU1XXX_PHY1_SEARCH_ON_MAC0
+/* autodetection defaults: phy1_search_mac0 */

 /* static PHY setup
  *
@@ -148,29 +148,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
  * specific irq-map
  */

-#if defined(CONFIG_MIPS_BOSPORUS)
-/*
- * Micrel/Kendin 5 port switch attached to MAC0,
- * MAC0 is associated with PHY address 5 (== WAN port)
- * MAC1 is not associated with any PHY, since it's connected directly
- * to the switch.
- * no interrupts are used
- */
-# define AU1XXX_PHY_STATIC_CONFIG
-
-# define AU1XXX_PHY0_ADDR  5
-# define AU1XXX_PHY0_BUSID 0
-#  undef AU1XXX_PHY0_IRQ
-
-#  undef AU1XXX_PHY1_ADDR
-#  undef AU1XXX_PHY1_BUSID
-#  undef AU1XXX_PHY1_IRQ
-#endif
-
-#if defined(AU1XXX_PHY0_BUSID) && (AU1XXX_PHY0_BUSID > 0)
-# error MAC0-associated PHY attached 2nd MACs MII bus not supported yet
-#endif
-
 static void enable_mac(struct net_device *dev, int force_reset)
 {
 	unsigned long flags;
@@ -390,67 +367,54 @@ static int mii_probe (struct net_device *dev)
 	struct au1000_private *const aup = netdev_priv(dev);
 	struct phy_device *phydev = NULL;

-#if defined(AU1XXX_PHY_STATIC_CONFIG)
-	BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
+	if (aup->phy_static_config) {
+		BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);

-	if(aup->mac_id == 0) { /* get PHY0 */
-# if defined(AU1XXX_PHY0_ADDR)
-		phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR];
-# else
-		printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
-			dev->name);
-		return 0;
-# endif /* defined(AU1XXX_PHY0_ADDR) */
-	} else if (aup->mac_id == 1) { /* get PHY1 */
-# if defined(AU1XXX_PHY1_ADDR)
-		phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR];
-# else
-		printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
-			dev->name);
+		if (aup->phy_addr)
+			phydev = aup->mii_bus->phy_map[aup->phy_addr];
+		else
+			printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
+				dev->name);
 		return 0;
-# endif /* defined(AU1XXX_PHY1_ADDR) */
-	}
-
-#else /* defined(AU1XXX_PHY_STATIC_CONFIG) */
-	int phy_addr;
-
-	/* find the first (lowest address) PHY on the current MAC's MII bus */
-	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
-		if (aup->mii_bus->phy_map[phy_addr]) {
-			phydev = aup->mii_bus->phy_map[phy_addr];
-# if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR)
-			break; /* break out with first one found */
-# endif
-		}
-
-# if defined(AU1XXX_PHY1_SEARCH_ON_MAC0)
-	/* try harder to find a PHY */
-	if (!phydev && (aup->mac_id == 1)) {
-		/* no PHY found, maybe we have a dual PHY? */
-		printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, "
-			"let's see if it's attached to MAC0...\n");
-
-		BUG_ON(!au_macs[0]);
-
-		/* find the first (lowest address) non-attached PHY on
-		 * the MAC0 MII bus */
-		for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-			struct phy_device *const tmp_phydev =
-				au_macs[0]->mii_bus->phy_map[phy_addr];
-
-			if (!tmp_phydev)
-				continue; /* no PHY here... */
-
-			if (tmp_phydev->attached_dev)
-				continue; /* already claimed by MAC0 */
+	} else {
+		int phy_addr;
+
+		/* find the first (lowest address) PHY on the current MAC's MII bus */
+		for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
+			if (aup->mii_bus->phy_map[phy_addr]) {
+				phydev = aup->mii_bus->phy_map[phy_addr];
+				if (!aup->phy_search_highest_addr)
+					break; /* break out with first one found */
+			}

-			phydev = tmp_phydev;
-			break; /* found it */
+		if (aup->phy1_search_mac0) {
+			/* try harder to find a PHY */
+			if (!phydev && (aup->mac_id == 1)) {
+				/* no PHY found, maybe we have a dual PHY? */
+				printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, "
+					"let's see if it's attached to MAC0...\n");
+
+				/* find the first (lowest address) non-attached PHY on
+				 * the MAC0 MII bus */
+				for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+					if (aup->mac_id == 1)
+						break;
+					struct phy_device *const tmp_phydev =
+							aup->mii_bus->phy_map[phy_addr];
+
+					if (!tmp_phydev)
+						continue; /* no PHY here... */
+
+					if (tmp_phydev->attached_dev)
+						continue; /* already claimed by MAC0 */
+
+					phydev = tmp_phydev;
+					break; /* found it */
+				}
+			}
 		}
 	}
-# endif /* defined(AU1XXX_PHY1_SEARCH_OTHER_BUS) */

-#endif /* defined(AU1XXX_PHY_STATIC_CONFIG) */
 	if (!phydev) {
 		printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
 		return -1;
@@ -578,31 +542,6 @@ setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
 	}
 }

-static struct {
-	u32 base_addr;
-	u32 macen_addr;
-	int irq;
-	struct net_device *dev;
-} iflist[2] = {
-#ifdef CONFIG_SOC_AU1000
-	{AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT},
-	{AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT}
-#endif
-#ifdef CONFIG_SOC_AU1100
-	{AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT}
-#endif
-#ifdef CONFIG_SOC_AU1500
-	{AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT},
-	{AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT}
-#endif
-#ifdef CONFIG_SOC_AU1550
-	{AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT},
-	{AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT}
-#endif
-};
-
-static int num_ifs;
-
 /*
  * ethtool operations
  */
@@ -1058,46 +997,59 @@ static const struct net_device_ops au1000_netdev_ops = {
 	.ndo_change_mtu		= eth_change_mtu,
 };

-static struct net_device * au1000_probe(int port_num)
+static int __devinit au1000_probe(struct platform_device *pdev)
 {
 	static unsigned version_printed = 0;
 	struct au1000_private *aup = NULL;
+	struct au1000_eth_platform_data *pd;
 	struct net_device *dev = NULL;
 	db_dest_t *pDB, *pDBfree;
-	char ethaddr[6];
-	int irq, i, err;
-	u32 base, macen;
+	int irq, i, err = 0;
+	struct resource *base, *macen;
+	DECLARE_MAC_BUF(ethaddr);
+
+	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!base) {
+		printk(KERN_ERR DRV_NAME ": failed to retrieve base register\n");
+		err = -ENODEV;
+		goto out;
+	}

-	if (port_num >= NUM_ETH_INTERFACES)
-		return NULL;
+	macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!macen) {
+		printk(KERN_ERR DRV_NAME ": failed to retrieve MAC Enable register\n");
+		err = -ENODEV;
+		goto out;
+	}

-	base  = CPHYSADDR(iflist[port_num].base_addr );
-	macen = CPHYSADDR(iflist[port_num].macen_addr);
-	irq = iflist[port_num].irq;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		printk(KERN_ERR DRV_NAME ": failed to retrieve IRQ\n");
+		err = -ENODEV;
+		goto out;
+	}

-	if (!request_mem_region( base, MAC_IOSIZE, "Au1x00 ENET") ||
-	    !request_mem_region(macen, 4, "Au1x00 ENET"))
-		return NULL;
+	if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
+		printk(KERN_ERR DRV_NAME ": failed to request memory region for base registers\n");
+		err = -ENXIO;
+		goto out;
+	}

-	if (version_printed++ == 0)
-		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+	if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
+		printk(KERN_ERR DRV_NAME ": failed to request memory region for MAC enable register\n");
+		err = -ENXIO;
+		goto err_request;
+	}

 	dev = alloc_etherdev(sizeof(struct au1000_private));
 	if (!dev) {
 		printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
-		return NULL;
+		err = -ENOMEM;
+		goto err_alloc;
 	}

-	if ((err = register_netdev(dev)) != 0) {
-		printk(KERN_ERR "%s: Cannot register net device, error %d\n",
-				DRV_NAME, err);
-		free_netdev(dev);
-		return NULL;
-	}
-
-	printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
-		dev->name, base, irq);
-
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	platform_set_drvdata(pdev, dev);
 	aup = netdev_priv(dev);

 	spin_lock_init(&aup->lock);
@@ -1108,21 +1060,29 @@ static struct net_device * au1000_probe(int port_num)
 						(NUM_TX_BUFFS + NUM_RX_BUFFS),
 						&aup->dma_addr,	0);
 	if (!aup->vaddr) {
-		free_netdev(dev);
-		release_mem_region( base, MAC_IOSIZE);
-		release_mem_region(macen, 4);
-		return NULL;
+		printk(KERN_ERR DRV_NAME ": failed to allocate data buffers\n");
+		err = -ENOMEM;
+		goto err_vaddr;
 	}

 	/* aup->mac is the base address of the MAC's registers */
-	aup->mac = (volatile mac_reg_t *)iflist[port_num].base_addr;
+	aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
+	if (!aup->mac) {
+		printk(KERN_ERR DRV_NAME ": failed to ioremap MAC registers\n");
+		err = -ENXIO;
+		goto err_remap1;
+	}

-	/* Setup some variables for quick register address access */
-	aup->enable = (volatile u32 *)iflist[port_num].macen_addr;
-	aup->mac_id = port_num;
-	au_macs[port_num] = aup;
+        /* Setup some variables for quick register address access */
+	aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
+	if (!aup->enable) {
+		printk(KERN_ERR DRV_NAME ": failed to ioremap MAC enable register\n");
+		err = -ENXIO;
+		goto err_remap2;
+	}
+	aup->mac_id = pdev->id;

-	if (port_num == 0) {
+	if (pdev->id == 0) {
 		if (prom_get_ethernet_addr(ethaddr) == 0)
 			memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
 		else {
@@ -1132,7 +1092,7 @@ static struct net_device * au1000_probe(int port_num)
 		}

 		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
-	} else if (port_num == 1)
+	} else if (pdev->id == 1)
 		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);

 	/*
@@ -1140,14 +1100,37 @@ static struct net_device * au1000_probe(int port_num)
 	 * to match those that are printed on their stickers
 	 */
 	memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
-	dev->dev_addr[5] += port_num;
+	dev->dev_addr[5] += pdev->id;

 	*aup->enable = 0;
 	aup->mac_enabled = 0;

+	pd = pdev->dev.platform_data;
+	if (!pd) {
+		printk(KERN_INFO DRV_NAME ": no platform_data passed, PHY search on MAC0\n");
+		aup->phy1_search_mac0 = 1;
+	} else {
+		aup->phy_static_config = pd->phy_static_config;
+		aup->phy_search_highest_addr = pd->phy_search_highest_addr;
+		aup->phy1_search_mac0 = pd->phy1_search_mac0;
+		aup->phy_addr = pd->phy_addr;
+		aup->phy_busid = pd->phy_busid;
+		aup->phy_irq = pd->phy_irq;
+	}
+
+	if (aup->phy_busid && aup->phy_busid > 0) {
+		printk(KERN_ERR DRV_NAME ": MAC0-associated PHY attached 2nd MACs MII"
+				"bus not supported yet\n");
+		err = -ENODEV;
+		goto err_mdiobus_alloc;
+	}
+
 	aup->mii_bus = mdiobus_alloc();
-	if (aup->mii_bus == NULL)
-		goto err_out;
+	if (aup->mii_bus == NULL) {
+		printk(KERN_ERR DRV_NAME ": failed to allocate mdiobus structure\n");
+		err = -ENOMEM;
+		goto err_mdiobus_alloc;
+	}

 	aup->mii_bus->priv = dev;
 	aup->mii_bus->read = au1000_mdiobus_read;
@@ -1161,23 +1144,19 @@ static struct net_device * au1000_probe(int port_num)

 	for(i = 0; i < PHY_MAX_ADDR; ++i)
 		aup->mii_bus->irq[i] = PHY_POLL;
-
 	/* if known, set corresponding PHY IRQs */
-#if defined(AU1XXX_PHY_STATIC_CONFIG)
-# if defined(AU1XXX_PHY0_IRQ)
-	if (AU1XXX_PHY0_BUSID == aup->mac_id)
-		aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
-# endif
-# if defined(AU1XXX_PHY1_IRQ)
-	if (AU1XXX_PHY1_BUSID == aup->mac_id)
-		aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
-# endif
-#endif
-	mdiobus_register(aup->mii_bus);
+	if (aup->phy_static_config)
+		if (aup->phy_irq && aup->phy_busid == aup->mac_id)
+			aup->mii_bus->irq[aup->phy_addr] = aup->phy_irq;
+
+	err = mdiobus_register(aup->mii_bus);
+	if (err) {
+		printk(KERN_ERR DRV_NAME " failed to register MDIO bus\n");
+		goto err_mdiobus_reg;
+	}

-	if (mii_probe(dev) != 0) {
+	if (mii_probe(dev) != 0)
 		goto err_out;
-	}

 	pDBfree = NULL;
 	/* setup the data buffer descriptors and attach a buffer to each one */
@@ -1209,7 +1188,7 @@ static struct net_device * au1000_probe(int port_num)
 		aup->tx_db_inuse[i] = pDB;
 	}

-	dev->base_addr = base;
+	dev->base_addr = base->start;
 	dev->irq = irq;
 	dev->netdev_ops = &au1000_netdev_ops;
 	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
@@ -1221,13 +1200,23 @@ static struct net_device * au1000_probe(int port_num)
 	 */
 	reset_mac(dev);

-	return dev;
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR DRV_NAME "%s: Cannot register net device, aborting.\n",
+					dev->name);
+		goto err_out;
+	}
+
+	printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n",
+					dev->name, base->start, irq);
+	if (version_printed++ == 0)
+		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
+
+	return 0;

 err_out:
-	if (aup->mii_bus != NULL) {
+	if (aup->mii_bus != NULL)
 		mdiobus_unregister(aup->mii_bus);
-		mdiobus_free(aup->mii_bus);
-	}

 	/* here we should have a valid dev plus aup-> register addresses
 	 * so we can reset the mac properly.*/
@@ -1241,67 +1230,84 @@ err_out:
 		if (aup->tx_db_inuse[i])
 			ReleaseDB(aup, aup->tx_db_inuse[i]);
 	}
+err_mdiobus_reg:
+	mdiobus_free(aup->mii_bus);
+err_mdiobus_alloc:
+	iounmap(aup->enable);
+err_remap2:
+	iounmap(aup->mac);
+err_remap1:
 	dma_free_noncoherent(NULL, MAX_BUF_SIZE * (NUM_TX_BUFFS + NUM_RX_BUFFS),
 			     (void *)aup->vaddr, aup->dma_addr);
-	unregister_netdev(dev);
+err_vaddr:
 	free_netdev(dev);
-	release_mem_region( base, MAC_IOSIZE);
-	release_mem_region(macen, 4);
-	return NULL;
+err_alloc:
+	release_mem_region(macen->start, resource_size(macen));
+err_request:
+	release_mem_region(base->start, resource_size(base));
+out:
+	return err;
 }

-/*
- * Setup the base address and interrupt of the Au1xxx ethernet macs
- * based on cpu type and whether the interface is enabled in sys_pinfunc
- * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
- */
-static int __init au1000_init_module(void)
+static int __devexit au1000_remove(struct platform_device *pdev)
 {
-	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
-	struct net_device *dev;
-	int i, found_one = 0;
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct au1000_private *aup = netdev_priv(dev);
+	int i;
+	struct resource *base, *macen;

-	num_ifs = NUM_ETH_INTERFACES - ni;
+	platform_set_drvdata(pdev, NULL);
+
+	unregister_netdev(dev);
+	mdiobus_unregister(aup->mii_bus);
+	mdiobus_free(aup->mii_bus);
+
+	for (i = 0; i < NUM_RX_DMA; i++)
+		if (aup->rx_db_inuse[i])
+			ReleaseDB(aup, aup->rx_db_inuse[i]);
+
+	for (i = 0; i < NUM_TX_DMA; i++)
+		if (aup->tx_db_inuse[i])
+			ReleaseDB(aup, aup->tx_db_inuse[i]);
+
+	dma_free_noncoherent(NULL, MAX_BUF_SIZE *
+			(NUM_TX_BUFFS + NUM_RX_BUFFS),
+			(void *)aup->vaddr, aup->dma_addr);
+
+	iounmap(aup->mac);
+	iounmap(aup->enable);
+
+	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(base->start, resource_size(base));
+
+	macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	release_mem_region(macen->start, resource_size(macen));
+
+	free_netdev(dev);

-	for(i = 0; i < num_ifs; i++) {
-		dev = au1000_probe(i);
-		iflist[i].dev = dev;
-		if (dev)
-			found_one++;
-	}
-	if (!found_one)
-		return -ENODEV;
 	return 0;
 }

-static void __exit au1000_cleanup_module(void)
+static struct platform_driver au1000_eth_driver = {
+	.probe  = au1000_probe,
+	.remove = __devexit_p(au1000_remove),
+	.driver = {
+		.name   = "au1000-eth",
+		.owner  = THIS_MODULE,
+	},
+};
+MODULE_ALIAS("platform:au1000-eth");
+
+
+static int __init au1000_init_module(void)
 {
-	int i, j;
-	struct net_device *dev;
-	struct au1000_private *aup;
-
-	for (i = 0; i < num_ifs; i++) {
-		dev = iflist[i].dev;
-		if (dev) {
-			aup = netdev_priv(dev);
-			unregister_netdev(dev);
-			mdiobus_unregister(aup->mii_bus);
-			mdiobus_free(aup->mii_bus);
-			for (j = 0; j < NUM_RX_DMA; j++)
-				if (aup->rx_db_inuse[j])
-					ReleaseDB(aup, aup->rx_db_inuse[j]);
-			for (j = 0; j < NUM_TX_DMA; j++)
-				if (aup->tx_db_inuse[j])
-					ReleaseDB(aup, aup->tx_db_inuse[j]);
-			dma_free_noncoherent(NULL, MAX_BUF_SIZE *
-					     (NUM_TX_BUFFS + NUM_RX_BUFFS),
-					     (void *)aup->vaddr, aup->dma_addr);
-			release_mem_region(dev->base_addr, MAC_IOSIZE);
-			release_mem_region(CPHYSADDR(iflist[i].macen_addr), 4);
-			free_netdev(dev);
-		}
-	}
+	return platform_driver_register(&au1000_eth_driver);
+}
+
+static void __exit au1000_exit_module(void)
+{
+	platform_driver_unregister(&au1000_eth_driver);
 }

 module_init(au1000_init_module);
-module_exit(au1000_cleanup_module);
+module_exit(au1000_exit_module);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 824ecd5..f9d29a2 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -108,6 +108,15 @@ struct au1000_private {
 	struct phy_device *phy_dev;
 	struct mii_bus *mii_bus;

+	/* PHY configuration */
+	int phy_static_config;
+	int phy_search_highest_addr;
+	int phy1_search_mac0;
+
+	int phy_addr;
+	int phy_busid;
+	int phy_irq;
+
 	/* These variables are just for quick access to certain regs addresses. */
 	volatile mac_reg_t *mac;  /* mac registers                      */
 	volatile u32 *enable;     /* address of MAC Enable Register     */

^ permalink raw reply related

* Possible bug: SO_TIMESTAMPING 2.6.30+
From: Marcus D. Leech @ 2009-11-10  0:40 UTC (permalink / raw)
  To: netdev

I've searched both the LKML archives, and the patchsets for kernels 
since 2.6.30 to see if
   this problem has been observed.

I have an Ethernet driver that supports hardware timestamping, and it 
has been working
   swimmingly well for several months using the SO_TIMESTAMPING 
infrastructure that
   Patrick Ohly put in the kernel starting around 2.6.30.

What I've discovered, that really causes me to pull my hair out, is that 
packets that are
   either AF_INET6 or AF_PACKET, *are not* getting Tx (transmit) 
timestamps.  Diving into
   the driver, I've discovered that the sk_buffs associated with these 
packets *dont* have
   the appropriate skb_tx state in the skb:

               shtx = skb_tx(skb);
               if (shtx->hardware)
               {
                        /* Do the timestamping thing */
                }

Now the puzzling thing is that the socket that originates these packets 
has SO_TIMESTAMPING
   turned on, and was created as an AF_INET6 socket, but carries both V4 
and V6 traffic.  The
   V4 traffic skbs  have  shtx->hardware  true appropriately,  but the 
V6 traffic doesn't.  Using
   Wireshark, I can clearly see the V6 packets leaving the interface, so 
it's not like they're
   getting routed somewhere else, and debugging in the driver *clearly* 
shows that V4 packets
   have shtx->hardware, while the V6 ones (from the SAME SOCKET) do not.

I know that Patrick Ohly has essentially moved on from doing the 
SO_TIMESTAMPING stuff, so
   who's maintaining it now?

When I look at the V6 udp code, it seems to call the same udp_sendmsg() 
function that V4
   uses, which appears to support Tx timestamping the way it should.

Any clues anyone?

^ permalink raw reply

* Re: [PATCHv8 3/3] vhost_net: a kernel-level virtio server
From: Rusty Russell @ 2009-11-10  1:08 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, gregory.haskins, s.hetze, Daniel Walker, Eric Dumazet
In-Reply-To: <8f53421d0911082310n1f5f487ew8c2c03d2e1d7ca5c@mail.gmail.com>

On Mon, 9 Nov 2009 05:40:32 pm Michael S. Tsirkin wrote:
> On Mon, Nov 9, 2009 at 8:17 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> > There's something about the 'acked' which rubs me the wrong way.
> > "enabled_features" is perhaps a better term than "acked_features"; "acked"
> > seems more a user point-of-view, "enabled" seems more driver POV?
> 
> Hmm. Are you happy with the ioctl name? If yes I think being consistent
> with that is important.

I think in my original comments I noted that I preferred GET / SET, rather
than GET/ACK.

> > Actually, this looks wrong to me:
> >
> > +       case VHOST_SET_VRING_BASE:
> > ...
> > +               vq->avail_idx = vq->last_avail_idx = s.num;
> >
> > The last_avail_idx is part of the state of the driver.  It needs to be saved
> > and restored over susp/resume.
> 
> 
> Exactly. That's what VHOST_GET/SET_VRING_BASE does.  avail_idx is just a
> cached value for notify on empty, so what this does is clear the value.

Ah, you actually refresh it every time anyway.  Hmm, could you do my poor
brain a favor and either just get_user it in vhost_trigger_irq(), or call
it 'cached_avail_idx' or something?

> >  The only reason it's not in the ring itself
> > is because I figured the other side doesn't need to see it (which is true, but
> > missed debugging opportunities as well as man-in-the-middle issues like this
> > one).  I had a patch which put this field at the end of the ring, I might
> > resurrect it to avoid this problem.  This is backwards compatible with all
> > implementations.  See patch at end.
> 
> Yes, I remember that patch. There seems to be little point though, at
> this stage.

Well, it avoids this ioctl, by exposing all the state.  We may well need it
later, to expand the ring in other ways.

> > I would drop avail_idx altogether: get_user is basically free, and simplifies
> > a lot.  As most state is in the ring, all you need is an ioctl to save/restore
> > the last_avail_idx.
> 
> avail_idx is there for notify on empty: I had this thought that it's
> better to leave the avail cache line alone when we are triggering
> interrupt to avoid bouncing it around if guest is updating it meanwhile
> on another CPU, and I think my testing showed that it helped
> performance, but could be a mistake.  You don't believe this can help?

I believe it could help, but this is YA case where it would have been nice to
have a dumb basic patch and this as a patch on top.  But I am going to ask
you to re-run that measurement, see if it stacks up (because it's an
interesting lesson if it does..)

Thanks!
Rusty.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* [PATCH] check the return value of ndo_select_queue()
From: Changli Gao @ 2009-11-10  1:42 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, xiaosuo, Eric Dumazet

check the return value of ndo_select_queue()

Check the return value of ndo_select_queue(). If the value isn't smaller
than the real_num_tx_queues, print a warning message, and reset it to zero.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
----
net/core/dev.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index b8f74cf..be081a5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1791,13 +1791,25 @@ EXPORT_SYMBOL(skb_tx_hash);
 static struct netdev_queue *dev_pick_tx(struct net_device *dev,
 					struct sk_buff *skb)
 {
-	const struct net_device_ops *ops = dev->netdev_ops;
-	u16 queue_index = 0;
-
-	if (ops->ndo_select_queue)
-		queue_index = ops->ndo_select_queue(dev, skb);
-	else if (dev->real_num_tx_queues > 1)
+	u16 queue_index;
+	u16 (*ndo_select_queue)(struct net_device*, struct sk_buff*);
+	unsigned int real_num_tx_queues = dev->real_num_tx_queues;
+
+	if (real_num_tx_queues == 1) {
+		queue_index = 0;
+	} else if ((ndo_select_queue = dev->netdev_ops->ndo_select_queue)) {
+		queue_index = ndo_select_queue(dev, skb);
+		if (unlikely(queue_index >= real_num_tx_queues)) {
+			if (net_ratelimit())
+				WARN(1, "%s selects TX queue %d, "
+				     "but real number of TX queues is %d\n",
+				     dev->name, queue_index,
+				     real_num_tx_queues);
+			queue_index = 0;
+		}
+	} else {
 		queue_index = skb_tx_hash(dev, skb);
+	}
 
 	skb_set_queue_mapping(skb, queue_index);
 	return netdev_get_tx_queue(dev, queue_index);



^ permalink raw reply related

* Re: [PATCHv9 3/3] vhost_net: a kernel-level virtio server
From: Rusty Russell @ 2009-11-10  2:48 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, gregory.haskins, s.hetze, Daniel Walker, Eric Dumazet
In-Reply-To: <20091109172230.GD4724@redhat.com>

On Tue, 10 Nov 2009 03:52:30 am Michael S. Tsirkin wrote:
> What it is: vhost net is a character device that can be used to reduce
> the number of system calls involved in virtio networking.
> Existing virtio net code is used in the guest without modification.

Thanks, applied.  Will be in tomorrow's linux-next.

Cheers,
Rusty.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* (unknown)
From: MR SMITH @ 2009-11-10  2:53 UTC (permalink / raw)




Do you need A
Business or a Personal Loan? Then your Answer is here. We
offer
loan at 3% as well with a flexible  plan.and customer's convinient terms*

We offer the following;

Hard Money Loans
Business Loan.
Debt Consolidation Loan.
Personal Loan.
Business Expansion Loan.
And Lots more..........

If interested in any of the following, contact us now on
happy_smithloanfirm@hotmail.com   for more infor..


REGARDS


^ permalink raw reply

* Re: [PATCHv9 3/3] vhost_net: a kernel-level virtio server
From: Rusty Russell @ 2009-11-10  3:19 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, gregory.haskins, s.hetze, Daniel Walker, Eric Dumazet
In-Reply-To: <20091109172230.GD4724@redhat.com>

One fix:

vhost: fix TUN=m VHOST_NET=y

	drivers/built-in.o: In function `get_tun_socket':
	net.c:(.text+0x15436e): undefined reference to `tun_get_socket'

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 drivers/vhost/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
--- a/drivers/vhost/Kconfig
+++ b/drivers/vhost/Kconfig
@@ -1,6 +1,6 @@
 config VHOST_NET
 	tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)"
-	depends on NET && EVENTFD && EXPERIMENTAL
+	depends on NET && EVENTFD && TUN && EXPERIMENTAL
 	---help---
 	  This kernel module can be loaded in host kernel to accelerate
 	  guest networking with virtio_net. Not to be confused with virtio_net

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH] check the return value of ndo_select_queue()
From: Eric Dumazet @ 2009-11-10  3:43 UTC (permalink / raw)
  To: xiaosuo; +Cc: David S. Miller, netdev
In-Reply-To: <4AF8C4E9.3030907@gmail.com>

Changli Gao a écrit :
> check the return value of ndo_select_queue()
> 
> Check the return value of ndo_select_queue(). If the value isn't smaller
> than the real_num_tx_queues, print a warning message, and reset it to zero.
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>

Acked-by: Eric Dumazet <eric.dumazet@gmail.com>


^ 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