Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] Eleminate HZ from AX.25 kernel interfaces
From: David S. Miller @ 2006-05-04  6:27 UTC (permalink / raw)
  To: ralf; +Cc: netdev, linux-hams
In-Reply-To: <20060429141244.GA2407@linux-mips.org>

From: Ralf Baechle DL5RB <ralf@linux-mips.org>
Date: Sat, 29 Apr 2006 15:12:44 +0100

> Convert all AX.25 sysctl time values from jiffies to ms as units.
> 
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Applied.

^ permalink raw reply

* Re: [PATCH 2/3] Eleminate HZ from NET/ROM kernel interfaces
From: David S. Miller @ 2006-05-04  6:27 UTC (permalink / raw)
  To: ralf; +Cc: netdev, linux-hams
In-Reply-To: <20060429141613.GA2811@linux-mips.org>

From: Ralf Baechle <ralf@linux-mips.org>
Date: Sat, 29 Apr 2006 15:16:13 +0100

> Convert all NET/ROM sysctl time values from jiffies to ms as units.
> 
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Applied.

^ permalink raw reply

* Re: [PATCH 3/3] Eleminate HZ from ROSE kernel interfaces
From: David S. Miller @ 2006-05-04  6:28 UTC (permalink / raw)
  To: ralf; +Cc: netdev, linux-hams
In-Reply-To: <20060429141924.GA2941@linux-mips.org>

From: Ralf Baechle <ralf@linux-mips.org>
Date: Sat, 29 Apr 2006 15:19:24 +0100

> Convert all ROSE sysctl time values from jiffies to ms as units.
> 
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Applied.

^ permalink raw reply

* Re: [TCP]: Fix sock_orphan dead lock
From: David S. Miller @ 2006-05-04  6:32 UTC (permalink / raw)
  To: herbert; +Cc: mingo, arjan, netdev
In-Reply-To: <20060429131320.GA4145@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sat, 29 Apr 2006 23:13:20 +1000

> On Sat, Apr 29, 2006 at 09:15:07PM +1000, herbert wrote:
> > 
> > Unfortunately this is only true for TCP.  All of the connectionless
> > protocols use the callback lock without the socket lock so it does
> > still serve a purpose.
> > 
> > I'd be happy to see your patch included.
> 
> I've just changed my mind :) Instead of disabling BH on the read_lock
> callers, we can instead move sock_orphan outside bh_lock_sock.
> 
> [TCP]: Fix sock_orphan dead lock

Ok, it took me a while to review this one as verifying such
a set of changes is always tricky, but looks good!

Applied, thanks a lot.

^ permalink raw reply

* Re: [PATCH] DECnet: Fix level1 router hello
From: David S. Miller @ 2006-05-04  6:36 UTC (permalink / raw)
  To: patrick; +Cc: netdev, steve
In-Reply-To: <4450BB03.4050404@tykepenguin.com>

From: Patrick Caulfield <patrick@tykepenguin.com>
Date: Thu, 27 Apr 2006 13:37:23 +0100

> This patch fixes hello messages sent when a node is a level 1 router. Slightly
> contrary to the spec (maybe) VMS ignores hello messages that do not name
> level2 routers that it also knows about.
> 
> So, here we simply name all the routers that the node knows about rather just
> other level1 routers.
> (I hope the patch is clearer than the description. sorry).
> 
> Patrick
> 
> Signed-off-by: Patrick Caulfield <patrick@tykepenguin.com>

Applied, thanks Patrick.

^ permalink raw reply

* Re: RFC: au1000_etc.c phylib rewrite
From: Robin H. Johnson @ 2006-05-04  6:49 UTC (permalink / raw)
  To: Herbert Valerio Riedel; +Cc: linux-mips, netdev
In-Reply-To: <1146674056.31241.18.camel@localhost.localdomain>

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

On Wed, May 03, 2006 at 06:34:16PM +0200, Herbert Valerio Riedel wrote:
> while at it, does anyone happen to know what the phy-addr/MAC assignment
> on the XXS1500 is?
Nope.

> but one thing that seems strange to me; CONFIG_BCM5222_DUAL_PHY doesn't
> seem to be defined anywhere; shouldn't that be at least defined in some
> Kconfig file, especially if the XXS1550 board is supposed to make use of
> it? 
Hmm, I do recall submitting a patch previously that added 
'select BCM5222_DUAL_PHY' for the XXS1500 unit.

-- 
Robin Hugh Johnson
E-Mail     : robbat2@gentoo.org
GnuPG FP   : 11AC BA4F 4778 E3F6 E4ED  F38E B27B 944E 3488 4E85

[-- Attachment #2: Type: application/pgp-signature, Size: 241 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] ipg: redundancy with mii.h
From: David Vrabel @ 2006-05-04  6:52 UTC (permalink / raw)
  To: Francois Romieu; +Cc: Pekka J Enberg, linux-kernel, netdev, david
In-Reply-To: <20060503233558.GA27232@electric-eye.fr.zoreil.com>

Francois Romieu wrote:
> 
>     ipg: remove forward declarations
>     
>     It makes no sense in a new driver.
>     
>     Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>

Ack.

>     ipg: replace #define with enum
>     
>     Added some underscores to improve readability.
>     
>     Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>

Nack.  Register names in code should match those used in the 
documentation (even if they are a bit unreadable).  Though I will 
conceed that the available datasheet doesn't actually describe the 
majority of the registers.

>     ipg: removal of useless #defines
>     
>     IPG_TX_NOTBUSY apart (one occurence in ipg.c), the #defines appear
>     nowhere in the sources.

Ack.

>     ipg: redundancy with mii.h - take II
>     
>     Replace a bunch of #define with their counterpart from mii.h
>     
>     It is applied to the usual MII registers this time.

Ack.


^ permalink raw reply

* [DCCP]: Fix sock_orphan dead lock
From: Herbert Xu @ 2006-05-04  7:17 UTC (permalink / raw)
  To: David S. Miller; +Cc: mingo, arjan, netdev
In-Reply-To: <20060503.233223.24747225.davem@davemloft.net>

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

On Wed, May 03, 2006 at 11:32:23PM -0700, David S. Miller wrote:
> 
> Ok, it took me a while to review this one as verifying such
> a set of changes is always tricky, but looks good!

Thanks.  It took me quite a while to assure myself that it was OK
as well :)

Anyway, the same issue affects DCCP (and SCTP too probably).  Here
is a patch that does the same thing for DCCP.

[DCCP]: Fix sock_orphan dead lock

Calling sock_orphan inside bh_lock_sock in dccp_close can lead to dead
locks.  For example, the inet_diag code holds sk_callback_lock without
disabling BH.  If an inbound packet arrives during that admittedly tiny
window, it will cause a dead lock on bh_lock_sock.  Another possible
path would be through sock_wfree if the network device driver frees the
tx skb in process context with BH enabled.

We can fix this by moving sock_orphan out of bh_lock_sock.

The tricky bit is to work out when we need to destroy the socket
ourselves and when it has already been destroyed by someone else.

By moving sock_orphan before the release_sock we can solve this
problem.  This is because as long as we own the socket lock its
state cannot change.

So we simply record the socket state before the release_sock
and then check the state again after we regain the socket lock.
If the socket state has transitioned to DCCP_CLOSED in the time being,
we know that the socket has been destroyed.  Otherwise the socket is
still ours to keep.

This problem was discoverd by Ingo Molnar using his lock validator.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

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

[-- Attachment #2: dccp-sock-orphan.patch --]
[-- Type: text/plain, Size: 1111 bytes --]

diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 1ff7328..2e0ee83 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -848,6 +848,7 @@
 void dccp_close(struct sock *sk, long timeout)
 {
 	struct sk_buff *skb;
+	int state;
 
 	lock_sock(sk);
 
@@ -882,6 +883,11 @@
 	sk_stream_wait_close(sk, timeout);
 
 adjudge_to_death:
+	state = sk->sk_state;
+	sock_hold(sk);
+	sock_orphan(sk);
+	atomic_inc(sk->sk_prot->orphan_count);
+
 	/*
 	 * It is the last release_sock in its life. It will remove backlog.
 	 */
@@ -894,8 +900,9 @@
 	bh_lock_sock(sk);
 	BUG_TRAP(!sock_owned_by_user(sk));
 
-	sock_hold(sk);
-	sock_orphan(sk);
+	/* Have we already been destroyed by a softirq or backlog? */
+	if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
+		goto out;
 
 	/*
 	 * The last release_sock may have processed the CLOSE or RESET
@@ -915,12 +922,12 @@
 #endif
 	}
 
-	atomic_inc(sk->sk_prot->orphan_count);
 	if (sk->sk_state == DCCP_CLOSED)
 		inet_csk_destroy_sock(sk);
 
 	/* Otherwise, socket is reprieved until protocol close. */
 
+out:
 	bh_unlock_sock(sk);
 	local_bh_enable();
 	sock_put(sk);

^ permalink raw reply related

* Re: [PATCH 1/3] Rough VJ Channel Implementation - vj_core.patch
From: Kelly Daly @ 2006-05-04  7:28 UTC (permalink / raw)
  To: David S. Miller; +Cc: kelly, netdev, rusty
In-Reply-To: <20060426.005949.125174303.davem@davemloft.net>

On Wednesday 26 April 2006 17:59, David S. Miller wrote:
> Next, you can't even begin to work on the protocol channels before you
> do one very important piece of work.  Integration of all of the ipv4
> and ipv6 protocol hash tables into a central code, it's a total
> prerequisite.  Then you modify things to use a generic
> inet_{,listen_}lookup() or inet6_{,listen_}lookup() that takes a
> protocol number as well as saddr/daddr/sport/dport and searches
> from a central table.

Back here again  ;)

Is this on the right track (see patch below)?

K



_____________________


diff -urp davem_orig/include/net/inet_hashtables.h kelly/include/net/inet_hashtables.h
--- davem_orig/include/net/inet_hashtables.h	2006-04-27 00:08:32.000000000 +1000
+++ kelly/include/net/inet_hashtables.h	2006-05-04 14:28:59.000000000 +1000
@@ -418,4 +418,6 @@ static inline struct sock *inet_lookup(s
 
 extern int inet_hash_connect(struct inet_timewait_death_row *death_row,
 			     struct sock *sk);
+
+extern struct inet_hashinfo *inet_hashes[256];
 #endif /* _INET_HASHTABLES_H */
diff -urp davem_orig/include/net/sock.h kelly/include/net/sock.h
--- davem_orig/include/net/sock.h	2006-05-02 13:42:10.000000000 +1000
+++ kelly/include/net/sock.h	2006-05-04 14:28:59.000000000 +1000
@@ -196,6 +196,7 @@ struct sock {
 	unsigned short		sk_type;
 	int			sk_rcvbuf;
 	socket_lock_t		sk_lock;
+	struct netchannel	*sk_channel;
 	wait_queue_head_t	*sk_sleep;
 	struct dst_entry	*sk_dst_cache;
 	struct xfrm_policy	*sk_policy[2];
diff -urp davem_orig/net/core/dev.c kelly/net/core/dev.c
--- davem_orig/net/core/dev.c	2006-04-27 15:49:27.000000000 +1000
+++ kelly/net/core/dev.c	2006-05-04 16:58:49.000000000 +1000
@@ -116,6 +116,7 @@
 #include <net/iw_handler.h>
 #include <asm/current.h>
 #include <linux/audit.h>
+#include <net/inet_hashtables.h>
 
 /*
  *	The list of packet types we will receive (as opposed to discard)
@@ -190,6 +191,8 @@ static inline struct hlist_head *dev_ind
 	return &dev_index_head[ifindex & ((1<<NETDEV_HASHBITS)-1)];
 }
 
+static struct netchannel default_netchannel;
+
 /*
  *	Our notifier list
  */
@@ -1907,6 +1910,37 @@ struct netchannel_buftrailer *__netchann
 }
 EXPORT_SYMBOL_GPL(__netchannel_dequeue);
 
+
+/* Find the channel for a packet, or return default channel. */
+struct netchannel *find_netchannel(const struct netchannel_buftrailer *np)
+{
+	struct sock *sk = NULL;
+	unsigned long dlen = np->netchan_buf_len - np->netchan_buf_offset;
+	void *data = (void *)np - dlen;
+
+	switch (np->netchan_buf_proto) {
+	case __constant_htons(ETH_P_IP): {
+		struct iphdr *ip = data;
+		int iphl = ip->ihl * 4;
+
+		if (dlen >= (iphl + 4) && iphl == sizeof(struct iphdr)) {
+			u16 *ports = (u16 *)(ip + 1);
+
+			if (inet_hashes[ip->protocol]) {
+				sk = inet_lookup(inet_hashes[ip->protocol], 
+						 ip->saddr, ports[0],
+						 ip->daddr, ports[1],
+						 np->netchan_buf_dev->ifindex);
+			}
+			break;
+		}
+	}
+	}
+	if (sk && sk->sk_channel)
+		return sk->sk_channel;
+	return &default_netchannel;
+}
+
 static gifconf_func_t * gifconf_list [NPROTO];
 
 /**
@@ -3421,6 +3455,9 @@ static int __init net_dev_init(void)
 	hotcpu_notifier(dev_cpu_callback, 0);
 	dst_init();
 	dev_mcast_init();
+
+	/* FIXME: This should be attached to thread/threads. */
+	netchannel_init(&default_netchannel, NULL, NULL);
 	rc = 0;
 out:
 	return rc;
diff -urp davem_orig/net/ipv4/inet_hashtables.c kelly/net/ipv4/inet_hashtables.c
--- davem_orig/net/ipv4/inet_hashtables.c	2006-04-27 00:08:33.000000000 +1000
+++ kelly/net/ipv4/inet_hashtables.c	2006-05-04 14:28:59.000000000 +1000
@@ -337,3 +337,5 @@ out:
 }
 
 EXPORT_SYMBOL_GPL(inet_hash_connect);
+
+struct inet_hashinfo *inet_hashes[256];
diff -urp davem_orig/net/ipv4/tcp.c kelly/net/ipv4/tcp.c
--- davem_orig/net/ipv4/tcp.c	2006-04-27 00:08:33.000000000 +1000
+++ kelly/net/ipv4/tcp.c	2006-05-04 14:28:59.000000000 +1000
@@ -2173,6 +2173,7 @@ void __init tcp_init(void)
 	       tcp_hashinfo.ehash_size << 1, tcp_hashinfo.bhash_size);
 
 	tcp_register_congestion_control(&tcp_reno);
+	inet_hashes[IPPROTO_TCP] = &tcp_hashinfo;
 }
 
 EXPORT_SYMBOL(tcp_close);

^ permalink raw reply

* Re: [PATCH wireless-dev] d80211: Add support for user space client MLME
From: Jiri Benc @ 2006-05-04  9:00 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: John W. Linville, netdev, jkmaline
In-Reply-To: <20060503183524.GD10524@instant802.com>

On Wed, 3 May 2006 11:35:24 -0700, Jouni Malinen wrote:
> I think it would be nice to get this in so that both client and AP modes
> can use the same mechanism (user space MLME); hostapd already needs this
> wmaster0ap interface. In other words, if we do not want to see that
> interface by default, we could just add a generic mechanism for
> registering wmaster0ap that both hostapd and wpa_supplicant could use.
> The Host AP driver (driver/net/wireless/hostap) is doing this with
> PRISM2_PARAM_HOSTAPD parameter. I don't care how it's done, but some
> simple mechanism would be preferred.

Ok. So what about PRISM2_HOSTAPD_MGMT_IF ioctl that will add management
interface (if not added yet) and return its ifindex? It would accept a
boolean parameter (like PRISM2_PARAM_HOSTAPD) to add/remove that
interface. If you agree with this, I will make a patch.

Of course, both hostapd and wpa_supplicant needs to be changed for that.
This should not be a problem now as the d80211 stack is not in a common
use yet.

> No, move of MLME to user space should not change this at all. As an
> example, wpa_supplicant supports both cases and the patch I'm working on
> for getting Prism2 (full MAC for client mode) working with d80211 is
> modifying the kernel side to allow this to be done. Both changes are
> touching the same areas in the code, but there is no major change in
> whether fullmac can be supported or not.

So wpa_supplicant needs to know if the card is softmac or fullmac and
behave accordingly, right?

> That is not up-to-date with wireless-dev.git anymore, though. The key
> patch is d80211_fullmac_client.diff which is small enough to include
> here. Please note that this is not yet complete, so consider it more an
> example on what type of changes are needed.

Oh, thanks, now I remember, I have seen that.

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Re: [PATCH 1/3] d80211: get rid of default management interface
From: Jiri Benc @ 2006-05-04  9:02 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev
In-Reply-To: <20060503151128.70354482B3@silver.suse.cz>

On Wed,  3 May 2006 17:11:28 +0200 (CEST), Jiri Benc wrote:
> Default management interface (wmasterXap) confuses users. It is only needed
> for AP mode (and only until the new netlink interface between kernel and
> hostapd is implemented).

Please don't apply this patch.

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Re: [PATCH] bcm43xx-d80211: measure the channel change time
From: Jiri Benc @ 2006-05-04  9:11 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <200605032105.53694.mb@bu3sch.de>

On Wed, 3 May 2006 21:05:53 +0200, Michael Buesch wrote:
> @@ -354,6 +354,33 @@
>  	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
>  }
>  
> +static void bcm43xx_measure_channel_change_time(struct bcm43xx_private *bcm)
> +{
> +	struct bcm43xx_radioinfo *radio;
> +	u64 start, stop;
> +	unsigned long flags;
> +	u8 oldchan, testchan;
> +
> +	/* We (ab)use the bcm43xx TSF timer to measure the time needed
> +	 * to switch channels. This information is handed over to
> +	 * the ieee80211 subsystem.
> +	 * Time is measured in microseconds.
> +	 */
> +
> +	bcm43xx_lock_mmio(bcm, flags);
> +	radio = bcm43xx_current_radio(bcm);
> +	oldchan = radio->channel;
> +	testchan = (oldchan == 6) ? 7 : 6;
> +	bcm43xx_tsf_read(bcm, &start);
> +	bcm43xx_radio_selectchannel(bcm, testchan, 0);
> +	bcm43xx_tsf_read(bcm, &stop);
> +	bcm43xx_radio_selectchannel(bcm, oldchan, 0);
> +	bcm43xx_unlock_mmio(bcm, flags);
> +
> +	assert(stop > start);

I think some safety fallback would be better. Like
if (stop - start < SOME_MIN_VALUE) channel_change_time = SOME_MIN_VALUE
(of course, this won't work because stop and start are unsigned, but you
probably got the idea).

And couldn't TSF counter overflow during the measurement?

> +	bcm->ieee->channel_change_time = stop - start;
> +}
> +
>  static
>  void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
>  			   u16 offset,
> @@ -3706,6 +3733,7 @@

Please, could you use -p parameter when generating diffs for easier
review?

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* RFC: new WIP version of au1000_eth.c phylib conversion (was Re: RFC: au1000_etc.c phylib rewrite)
From: Herbert Valerio Riedel @ 2006-05-04  9:17 UTC (permalink / raw)
  To: Mark Schank
  Cc: ppopov, sshtylyov, linux-mips, jgarzik, netdev, Ralf Baechle,
	Robin H. Johnson
In-Reply-To: <1146674056.31241.18.camel@localhost.localdomain>


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

Hello,

I've tried to adapt the PHY detection code to allow for dynamic runtime
configuration (with fallback to search for the 2nd MAC PHY on the 1st
MAC's MII bus), as well as selectable static PHY configuration through
Kconfig (e.g. for supporting PHYs w/o MII connection)

e.g. for a MIPS BOSPORUS board, one would set something like through
Kconfig (haven't bothered yet, to autoselect this when MIPS_BOSPORUS is
defined):

CONFIG_MIPS_AU1X00_ENET=y
CONFIG_MIPS_AU1X00_ENET_STATIC_PHY_CONFIG=y
CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR=5
CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ON_MAC0=y
CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR=-1

the default dynamic runtime PHY search behaviour is now to find the
lowest phy_addr containing a living PHY (which is not already claimed by
another MAC) on the MAC's current MII bus, and if not found, try again
on the first MAC's MII bus; and if that also fails eth initialization
fails for the given MAC;

...well, if anyone has the time and hardware, testing would be greatly
welcomed :-)

alas, this patch is rather big and I'd like to split it into smaller
pieces, but imho it's an 'all or nothing' thing to convert to the PHY
lib... :-/

 Kconfig      |   31 +
 au1000_eth.c | 1494 ++++++++++-------------------------------------------------
 au1000_eth.h |  132 -----
 3 files changed, 310 insertions(+), 1347 deletions(-)

regards,
hvr

[-- Attachment #1.2: au1000_eth_phylib_conversion.patch --]
[-- Type: text/x-patch, Size: 57310 bytes --]

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1edcc0c..588ddad 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -455,11 +455,42 @@ config MIPS_GT96100ETH
 config MIPS_AU1X00_ENET
 	bool "MIPS AU1000 Ethernet support"
 	depends on NET_ETHERNET && SOC_AU1X00
+	select PHYLIB
 	select CRC32
 	help
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
+config MIPS_AU1X00_ENET_STATIC_PHY_CONFIG
+	bool "Static PHY configuration"
+	depends on MIPS_AU1X00_ENET
+	default n
+	help
+	  Say Y if you need to set a static PHY configuration. If you say N, the
+	  driver will try to autodetect the PHY configuration.
+
+config MIPS_AU1X00_ENET_ETH0_PHY_ADDR
+	int "1st Ethernet's PHY address {-1,0..31}"
+	depends on MIPS_AU1X00_ENET_STATIC_PHY_CONFIG
+	help
+	  Provide the PHY address of the first Dthernet device. 
+	  If the PHY has no PHY address, say "-1".
+
+config MIPS_AU1X00_ENET_ETH1_PHY_ON_MAC0
+	bool "2nd Ethernet's PHY is attached to 1st MAC"
+	depends on MIPS_AU1X00_ENET_STATIC_PHY_CONFIG
+	default n
+	help
+	  Say Y here, if the second Ethernet's PHY is attached to 
+	  the MII bus of the first MAC.
+
+config MIPS_AU1X00_ENET_ETH1_PHY_ADDR
+	int "2nd Ethernet's PHY address {-1,0..31}"
+	depends on MIPS_AU1X00_ENET_STATIC_PHY_CONFIG
+	help
+	  Provide the PHY address of the second Ethernet device. 
+	  If the PHY has no PHY address, say "-1".
+
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
 	depends on NET_ETHERNET && PCI && SGI_IP27
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 0823cb8..8c0b26f 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -9,6 +9,9 @@
  * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de 
  * or riemer@riemer-nt.de: fixed the link beat detection with 
  * ioctls (SIOCGMIIPHY)
+ * Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org>
+ *  converted to use linux-2.6.x's PHY framework 
+ *
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
  *
@@ -53,6 +56,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/crc32.h>
+#include <linux/phy.h>
 #include <asm/mipsregs.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -88,14 +92,13 @@ static int au1000_tx(struct sk_buff *, s
 static int au1000_rx(struct net_device *);
 static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);
 static void au1000_tx_timeout(struct net_device *);
-static int au1000_set_config(struct net_device *dev, struct ifmap *map);
 static void set_rx_mode(struct net_device *);
 static struct net_device_stats *au1000_get_stats(struct net_device *);
-static void au1000_timer(unsigned long);
 static int au1000_ioctl(struct net_device *, struct ifreq *, int);
 static int mdio_read(struct net_device *, int, int);
 static void mdio_write(struct net_device *, int, int, u16);
-static void dump_mii(struct net_device *dev, int phy_id);
+static void au1000_adjust_link(struct net_device *);
+static void enable_mac(struct net_device *, int);
 
 // externs
 extern  void ack_rise_edge_irq(unsigned int);
@@ -135,696 +138,14 @@ static unsigned char au1000_mac_addr[6] 
 
 struct au1000_private *au_macs[NUM_ETH_INTERFACES];
 
-/* FIXME 
- * All of the PHY code really should be detached from the MAC 
- * code.
- */
-
-/* Default advertise */
-#define GENMII_DEFAULT_ADVERTISE \
-	ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
-	ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
-	ADVERTISED_Autoneg
-
-#define GENMII_DEFAULT_FEATURES \
-	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
-	SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
-	SUPPORTED_Autoneg
-
-int bcm_5201_init(struct net_device *dev, int phy_addr)
-{
-	s16 data;
-	
-	/* Stop auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
-	/* Set advertisement to 10/100 and Half/Full duplex
-	 * (full capabilities) */
-	data = mdio_read(dev, phy_addr, MII_ANADV);
-	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
-	mdio_write(dev, phy_addr, MII_ANADV, data);
-	
-	/* Restart auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-	mdio_write(dev, phy_addr, MII_CONTROL, data);
-
-	if (au1000_debug > 4) 
-		dump_mii(dev, phy_addr);
-	return 0;
-}
-
-int bcm_5201_reset(struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int 
-bcm_5201_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	if (!dev) {
-		printk(KERN_ERR "bcm_5201_status error: NULL dev\n");
-		return -1;
-	}
-	aup = (struct au1000_private *) dev->priv;
-
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
-		if (mii_data & MII_AUX_100) {
-			if (mii_data & MII_AUX_FDX) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else  {
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-int lsi_80227_init(struct net_device *dev, int phy_addr)
-{
-	if (au1000_debug > 4)
-		printk("lsi_80227_init\n");
-
-	/* restart auto-negotiation */
-	mdio_write(dev, phy_addr, MII_CONTROL,
-		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO); // | MII_CNTL_FDX);
-	mdelay(1);
-
-	/* set up LEDs to correct display */
-#ifdef CONFIG_MIPS_MTX1
-	mdio_write(dev, phy_addr, 17, 0xff80);
-#else
-	mdio_write(dev, phy_addr, 17, 0xffc0);
-#endif
-
-	if (au1000_debug > 4)
-		dump_mii(dev, phy_addr);
-	return 0;
-}
-
-int lsi_80227_reset(struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-	if (au1000_debug > 4) {
-		printk("lsi_80227_reset\n");
-		dump_mii(dev, phy_addr);
-	}
-
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int
-lsi_80227_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	if (!dev) {
-		printk(KERN_ERR "lsi_80227_status error: NULL dev\n");
-		return -1;
-	}
-	aup = (struct au1000_private *) dev->priv;
-
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_LSI_PHY_STAT);
-		if (mii_data & MII_LSI_PHY_STAT_SPD) {
-			if (mii_data & MII_LSI_PHY_STAT_FDX) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else  {
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-int am79c901_init(struct net_device *dev, int phy_addr)
-{
-	printk("am79c901_init\n");
-	return 0;
-}
-
-int am79c901_reset(struct net_device *dev, int phy_addr)
-{
-	printk("am79c901_reset\n");
-	return 0;
-}
-
-int 
-am79c901_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	return 0;
-}
-
-int am79c874_init(struct net_device *dev, int phy_addr)
-{
-	s16 data;
-
-	/* 79c874 has quit resembled bit assignments to BCM5201 */
-	if (au1000_debug > 4)
-		printk("am79c847_init\n");
-
-	/* Stop auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
-	/* Set advertisement to 10/100 and Half/Full duplex
-	 * (full capabilities) */
-	data = mdio_read(dev, phy_addr, MII_ANADV);
-	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
-	mdio_write(dev, phy_addr, MII_ANADV, data);
-	
-	/* Restart auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-
-	mdio_write(dev, phy_addr, MII_CONTROL, data);
-
-	if (au1000_debug > 4) dump_mii(dev, phy_addr);
-	return 0;
-}
-
-int am79c874_reset(struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-	if (au1000_debug > 4)
-		printk("am79c874_reset\n");
-
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int 
-am79c874_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	// printk("am79c874_status\n");
-	if (!dev) {
-		printk(KERN_ERR "am79c874_status error: NULL dev\n");
-		return -1;
-	}
-
-	aup = (struct au1000_private *) dev->priv;
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_AMD_PHY_STAT);
-		if (mii_data & MII_AMD_PHY_STAT_SPD) {
-			if (mii_data & MII_AMD_PHY_STAT_FDX) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else {
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-int lxt971a_init(struct net_device *dev, int phy_addr)
-{
-	if (au1000_debug > 4)
-		printk("lxt971a_init\n");
-
-	/* restart auto-negotiation */
-	mdio_write(dev, phy_addr, MII_CONTROL,
-		   MII_CNTL_F100 | MII_CNTL_AUTO | MII_CNTL_RST_AUTO | MII_CNTL_FDX);
-
-	/* set up LEDs to correct display */
-	mdio_write(dev, phy_addr, 20, 0x0422);
-
-	if (au1000_debug > 4)
-		dump_mii(dev, phy_addr);
-	return 0;
-}
-
-int lxt971a_reset(struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-	if (au1000_debug > 4) {
-		printk("lxt971a_reset\n");
-		dump_mii(dev, phy_addr);
-	}
-
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int
-lxt971a_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	if (!dev) {
-		printk(KERN_ERR "lxt971a_status error: NULL dev\n");
-		return -1;
-	}
-	aup = (struct au1000_private *) dev->priv;
-
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_INTEL_PHY_STAT);
-		if (mii_data & MII_INTEL_PHY_STAT_SPD) {
-			if (mii_data & MII_INTEL_PHY_STAT_FDX) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else  {
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-int ks8995m_init(struct net_device *dev, int phy_addr)
-{
-	s16 data;
-	
-//	printk("ks8995m_init\n");
-	/* Stop auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
-	/* Set advertisement to 10/100 and Half/Full duplex
-	 * (full capabilities) */
-	data = mdio_read(dev, phy_addr, MII_ANADV);
-	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
-	mdio_write(dev, phy_addr, MII_ANADV, data);
-	
-	/* Restart auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-	mdio_write(dev, phy_addr, MII_CONTROL, data);
-
-	if (au1000_debug > 4) dump_mii(dev, phy_addr);
-
-	return 0;
-}
-
-int ks8995m_reset(struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-//	printk("ks8995m_reset\n");
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int ks8995m_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	if (!dev) {
-		printk(KERN_ERR "ks8995m_status error: NULL dev\n");
-		return -1;
-	}
-	aup = (struct au1000_private *) dev->priv;
-
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, MII_AUX_CNTRL);
-		if (mii_data & MII_AUX_100) {
-			if (mii_data & MII_AUX_FDX) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else  {											
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-int
-smsc_83C185_init (struct net_device *dev, int phy_addr)
-{
-	s16 data;
-
-	if (au1000_debug > 4)
-		printk("smsc_83C185_init\n");
-
-	/* Stop auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, data & ~MII_CNTL_AUTO);
-
-	/* Set advertisement to 10/100 and Half/Full duplex
-	 * (full capabilities) */
-	data = mdio_read(dev, phy_addr, MII_ANADV);
-	data |= MII_NWAY_TX | MII_NWAY_TX_FDX | MII_NWAY_T_FDX | MII_NWAY_T;
-	mdio_write(dev, phy_addr, MII_ANADV, data);
-	
-	/* Restart auto-negotiation */
-	data = mdio_read(dev, phy_addr, MII_CONTROL);
-	data |= MII_CNTL_RST_AUTO | MII_CNTL_AUTO;
-
-	mdio_write(dev, phy_addr, MII_CONTROL, data);
-
-	if (au1000_debug > 4) dump_mii(dev, phy_addr);
-	return 0;
-}
-
-int
-smsc_83C185_reset (struct net_device *dev, int phy_addr)
-{
-	s16 mii_control, timeout;
-	
-	if (au1000_debug > 4)
-		printk("smsc_83C185_reset\n");
-
-	mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-	mdio_write(dev, phy_addr, MII_CONTROL, mii_control | MII_CNTL_RESET);
-	mdelay(1);
-	for (timeout = 100; timeout > 0; --timeout) {
-		mii_control = mdio_read(dev, phy_addr, MII_CONTROL);
-		if ((mii_control & MII_CNTL_RESET) == 0)
-			break;
-		mdelay(1);
-	}
-	if (mii_control & MII_CNTL_RESET) {
-		printk(KERN_ERR "%s PHY reset timeout !\n", dev->name);
-		return -1;
-	}
-	return 0;
-}
-
-int 
-smsc_83C185_status (struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	u16 mii_data;
-	struct au1000_private *aup;
-
-	if (!dev) {
-		printk(KERN_ERR "smsc_83C185_status error: NULL dev\n");
-		return -1;
-	}
-
-	aup = (struct au1000_private *) dev->priv;
-	mii_data = mdio_read(dev, aup->phy_addr, MII_STATUS);
-
-	if (mii_data & MII_STAT_LINK) {
-		*link = 1;
-		mii_data = mdio_read(dev, aup->phy_addr, 0x1f);
-		if (mii_data & (1<<3)) {
-			if (mii_data & (1<<4)) {
-				*speed = IF_PORT_100BASEFX;
-				dev->if_port = IF_PORT_100BASEFX;
-			}
-			else {
-				*speed = IF_PORT_100BASETX;
-				dev->if_port = IF_PORT_100BASETX;
-			}
-		}
-		else {
-			*speed = IF_PORT_10BASET;
-			dev->if_port = IF_PORT_10BASET;
-		}
-	}
-	else {
-		*link = 0;
-		*speed = 0;
-		dev->if_port = IF_PORT_UNKNOWN;
-	}
-	return 0;
-}
-
-
-#ifdef CONFIG_MIPS_BOSPORUS
-int stub_init(struct net_device *dev, int phy_addr)
-{
-	//printk("PHY stub_init\n");
-	return 0;
-}
-
-int stub_reset(struct net_device *dev, int phy_addr)
-{
-	//printk("PHY stub_reset\n");
-	return 0;
-}
-
-int 
-stub_status(struct net_device *dev, int phy_addr, u16 *link, u16 *speed)
-{
-	//printk("PHY stub_status\n");
-	*link = 1;
-	/* hmmm, revisit */
-	*speed = IF_PORT_100BASEFX;
-	dev->if_port = IF_PORT_100BASEFX;
-	return 0;
-}
-#endif
-
-struct phy_ops bcm_5201_ops = {
-	bcm_5201_init,
-	bcm_5201_reset,
-	bcm_5201_status,
-};
-
-struct phy_ops am79c874_ops = {
-	am79c874_init,
-	am79c874_reset,
-	am79c874_status,
-};
-
-struct phy_ops am79c901_ops = {
-	am79c901_init,
-	am79c901_reset,
-	am79c901_status,
-};
-
-struct phy_ops lsi_80227_ops = { 
-	lsi_80227_init,
-	lsi_80227_reset,
-	lsi_80227_status,
-};
-
-struct phy_ops lxt971a_ops = { 
-	lxt971a_init,
-	lxt971a_reset,
-	lxt971a_status,
-};
-
-struct phy_ops ks8995m_ops = {
-	ks8995m_init,
-	ks8995m_reset,
-	ks8995m_status,
-};
-
-struct phy_ops smsc_83C185_ops = {
-	smsc_83C185_init,
-	smsc_83C185_reset,
-	smsc_83C185_status,
-};
-
-#ifdef CONFIG_MIPS_BOSPORUS
-struct phy_ops stub_ops = {
-	stub_init,
-	stub_reset,
-	stub_status,
-};
-#endif
-
-static struct mii_chip_info {
-	const char * name;
-	u16 phy_id0;
-	u16 phy_id1;
-	struct phy_ops *phy_ops;	
-	int dual_phy;
-} mii_chip_table[] = {
-	{"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
-	{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
-	{"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
-	{"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0},
-	{"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
-	{"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
-	{"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
-	{"Intel LXT971A Dual Speed PHY",0x0013,0x78e2, &lxt971a_ops,0},
-	{"Kendin KS8995M 10/100 BaseT PHY",0x0022,0x1450, &ks8995m_ops,0},
-	{"SMSC LAN83C185 10/100 BaseT PHY",0x0007,0xc0a3, &smsc_83C185_ops,0},
-#ifdef CONFIG_MIPS_BOSPORUS
-	{"Stub", 0x1234, 0x5678, &stub_ops },
-#endif
-	{0,},
-};
-
-static int mdio_read(struct net_device *dev, int phy_id, int reg)
+static int mdio_read(struct net_device *dev, int phy_addr, int reg)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	volatile u32 *mii_control_reg;
-	volatile u32 *mii_data_reg;
+	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
+	volatile u32 *const mii_data_reg = &aup->mac->mii_data;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	#ifdef CONFIG_BCM5222_DUAL_PHY
-	/* First time we probe, it's for the mac0 phy.
-	 * Since we haven't determined yet that we have a dual phy,
-	 * aup->mii->mii_control_reg won't be setup and we'll
-	 * default to the else statement.
-	 * By the time we probe for the mac1 phy, the mii_control_reg
-	 * will be setup to be the address of the mac0 phy control since
-	 * both phys are controlled through mac0.
-	 */
-	if (aup->mii && aup->mii->mii_control_reg) {
-		mii_control_reg = aup->mii->mii_control_reg;
-		mii_data_reg = aup->mii->mii_data_reg;
-	}
-	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
-		/* assume both phys are controlled through mac0 */
-		mii_control_reg = au_macs[0]->mii->mii_control_reg;
-		mii_data_reg = au_macs[0]->mii->mii_data_reg;
-	}
-	else 
-	#endif
-	{
-		/* default control and data reg addresses */
-		mii_control_reg = &aup->mac->mii_control;
-		mii_data_reg = &aup->mac->mii_data;
-	}
-
 	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
@@ -835,7 +156,7 @@ static int mdio_read(struct net_device *
 	}
 
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
-		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_READ;
+		MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
 
 	*mii_control_reg = mii_control;
 
@@ -851,32 +172,14 @@ static int mdio_read(struct net_device *
 	return (int)*mii_data_reg;
 }
 
-static void mdio_write(struct net_device *dev, int phy_id, int reg, u16 value)
+static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	volatile u32 *mii_control_reg;
-	volatile u32 *mii_data_reg;
+	volatile u32 *const mii_control_reg = &aup->mac->mii_control;
+	volatile u32 *const mii_data_reg = &aup->mac->mii_data;
 	u32 timedout = 20;
 	u32 mii_control;
 
-	#ifdef CONFIG_BCM5222_DUAL_PHY
-	if (aup->mii && aup->mii->mii_control_reg) {
-		mii_control_reg = aup->mii->mii_control_reg;
-		mii_data_reg = aup->mii->mii_data_reg;
-	}
-	else if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
-		/* assume both phys are controlled through mac0 */
-		mii_control_reg = au_macs[0]->mii->mii_control_reg;
-		mii_data_reg = au_macs[0]->mii->mii_data_reg;
-	}
-	else 
-	#endif
-	{
-		/* default control and data reg addresses */
-		mii_control_reg = &aup->mac->mii_control;
-		mii_data_reg = &aup->mac->mii_data;
-	}
-
 	while (*mii_control_reg & MAC_MII_BUSY) {
 		mdelay(1);
 		if (--timedout == 0) {
@@ -887,165 +190,136 @@ static void mdio_write(struct net_device
 	}
 
 	mii_control = MAC_SET_MII_SELECT_REG(reg) | 
-		MAC_SET_MII_SELECT_PHY(phy_id) | MAC_MII_WRITE;
+		MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
 
 	*mii_data_reg = value;
 	*mii_control_reg = mii_control;
 }
 
-
-static void dump_mii(struct net_device *dev, int phy_id)
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
-	int i, val;
+	struct net_device *const dev = bus->priv; /* beware: bus->phy_map[phy_addr].attached_dev == dev does _NOT_ hold always  */
+	enable_mac(dev, 0); /* make sure MAC associated with this mii_bus is enabled */
+	return mdio_read(dev, phy_addr, regnum);
+}
 
-	for (i = 0; i < 7; i++) {
-		if ((val = mdio_read(dev, phy_id, i)) >= 0)
-			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
-	}
-	for (i = 16; i < 25; i++) {
-		if ((val = mdio_read(dev, phy_id, i)) >= 0)
-			printk("%s: MII Reg %d=%x\n", dev->name, i, val);
-	}
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
+{
+	struct net_device *const dev = bus->priv; /* beware: bus->phy_map[phy_addr].attached_dev == dev does _NOT_ hold always  */
+	enable_mac(dev, 0); /* make sure MAC associated with this mii_bus is enabled */
+	mdio_write(dev, phy_addr, regnum, value);
+	return 0;
 }
 
-static int mii_probe (struct net_device * dev)
+static int mdiobus_reset(struct mii_bus *bus)
 {
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	int phy_addr;
-#ifdef CONFIG_MIPS_BOSPORUS
-	int phy_found=0;
-#endif
+	struct net_device *dev = bus->priv;
 
-	/* search for total of 32 possible mii phy addresses */
-	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
-		u16 mii_status;
-		u16 phy_id0, phy_id1;
-		int i;
+	enable_mac(dev, 0); /* make sure MAC associated with this mii_bus is enabled */
 
-		#ifdef CONFIG_BCM5222_DUAL_PHY
-		/* Mask the already found phy, try next one */
-		if (au_macs[0]->mii && au_macs[0]->mii->mii_control_reg) {
-			if (au_macs[0]->phy_addr == phy_addr)
-				continue;
-		}
-		#endif
+	return 0;
+}
 
-		mii_status = mdio_read(dev, phy_addr, MII_STATUS);
-		if (mii_status == 0xffff || mii_status == 0x0000)
-			/* the mii is not accessable, try next one */
-			continue;
-
-		phy_id0 = mdio_read(dev, phy_addr, MII_PHY_ID0);
-		phy_id1 = mdio_read(dev, phy_addr, MII_PHY_ID1);
-
-		/* search our mii table for the current mii */ 
-		for (i = 0; mii_chip_table[i].phy_id1; i++) {
-			if (phy_id0 == mii_chip_table[i].phy_id0 &&
-			    phy_id1 == mii_chip_table[i].phy_id1) {
-				struct mii_phy * mii_phy = aup->mii;
-
-				printk(KERN_INFO "%s: %s at phy address %d\n",
-				       dev->name, mii_chip_table[i].name, 
-				       phy_addr);
-#ifdef CONFIG_MIPS_BOSPORUS
-				phy_found = 1;
-#endif
-				mii_phy->chip_info = mii_chip_table+i;
-				aup->phy_addr = phy_addr;
-				aup->want_autoneg = 1;
-				aup->phy_ops = mii_chip_table[i].phy_ops;
-				aup->phy_ops->phy_init(dev,phy_addr);
-
-				// Check for dual-phy and then store required 
-				// values and set indicators. We need to do 
-				// this now since mdio_{read,write} need the 
-				// control and data register addresses.
-				#ifdef CONFIG_BCM5222_DUAL_PHY
-				if ( mii_chip_table[i].dual_phy) {
-
-					/* assume both phys are controlled 
-					 * through MAC0. Board specific? */
-					
-					/* sanity check */
-					if (!au_macs[0] || !au_macs[0]->mii)
-						return -1;
-					aup->mii->mii_control_reg = (u32 *)
-						&au_macs[0]->mac->mii_control;
-					aup->mii->mii_data_reg = (u32 *)
-						&au_macs[0]->mac->mii_data;
-				}
-				#endif
-				goto found;
-			}
-		}
+static int mii_probe (struct net_device *dev)
+{
+	struct au1000_private *const aup = (struct au1000_private *) dev->priv;
+	struct phy_device *phydev = NULL;
+	
+#if defined(CONFIG_MIPS_AU1X00_ENET_STATIC_PHY_CONFIG)
+	BUG_ON(aup->mac_id < 0 || aup->mac_id > 1);
+
+	if(aup->mac_id == 0) {
+# if CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR==-1
+		printk (KERN_INFO DRV_NAME ":%s: using PHY-less config\n", dev->name);
+		return 0;
+# elif (CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR>=0) && (CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR<PHY_MAX_ADDR)
+		phydev = aup->mii_bus.phy_map[CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR];
+# else
+#  error Bad value for CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR given
+# endif
+	} else if (aup->mac_id == 1) {
+# if CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR==-1
+		printk (KERN_INFO DRV_NAME ":%s: using PHY-less config\n", dev->name);
+		return 0;
+# elif (CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR>=0) && (CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR<PHY_MAX_ADDR)
+#  if defined(CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ON_MAC0)
+#   if CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR==CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR
+#    error given same static PHY address, and both PHYs are on the same bus
+#   endif
+		phydev = au_macs[0]->mii_bus.phy_map[CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR];
+#  else
+		phydev = aup->mii_bus.phy_map[CONFIG_MIPS_AU1X00_ENET_ETH1_PHY_ADDR];
+#  endif
+# else
+#  error Bad value for CONFIG_MIPS_AU1X00_ENET_ETH0_PHY_ADDR given
+# endif
 	}
-found:
 
-#ifdef CONFIG_MIPS_BOSPORUS
-	/* This is a workaround for the Micrel/Kendin 5 port switch
-	   The second MAC doesn't see a PHY connected... so we need to
-	   trick it into thinking we have one.
-		
-	   If this kernel is run on another Au1500 development board
-	   the stub will be found as well as the actual PHY. However,
-	   the last found PHY will be used... usually at Addr 31 (Db1500).	
-	*/
-	if ( (!phy_found) )
-	{
-		u16 phy_id0, phy_id1;
-		int i;
+#else /* runtime detected PHY configuration */
+	int phy_addr;
 
-		phy_id0 = 0x1234;
-		phy_id1 = 0x5678;
+	/* 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];
+			break; /* found it */
+		}
+
+	/* 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] || !au_macs[0]->mii_bus);
+
+		/* 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 = aup->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 */
 
-		/* search our mii table for the current mii */ 
-		for (i = 0; mii_chip_table[i].phy_id1; i++) {
-			if (phy_id0 == mii_chip_table[i].phy_id0 &&
-			    phy_id1 == mii_chip_table[i].phy_id1) {
-				struct mii_phy * mii_phy;
-
-				printk(KERN_INFO "%s: %s at phy address %d\n",
-				       dev->name, mii_chip_table[i].name, 
-				       phy_addr);
-				mii_phy = kmalloc(sizeof(struct mii_phy), 
-						GFP_KERNEL);
-				if (mii_phy) {
-					mii_phy->chip_info = mii_chip_table+i;
-					aup->phy_addr = phy_addr;
-					mii_phy->next = aup->mii;
-					aup->phy_ops = 
-						mii_chip_table[i].phy_ops;
-					aup->mii = mii_phy;
-					aup->phy_ops->phy_init(dev,phy_addr);
-				} else {
-					printk(KERN_ERR "%s: out of memory\n", 
-							dev->name);
-					return -1;
-				}
-				mii_phy->chip_info = mii_chip_table+i;
-				aup->phy_addr = phy_addr;
-				aup->phy_ops = mii_chip_table[i].phy_ops;
-				aup->phy_ops->phy_init(dev,phy_addr);
-				break;
-			}
+			phydev = tmp_phydev;
+			break; /* found it */
 		}
 	}
-	if (aup->mac_id == 0) {
-		/* the Bosporus phy responds to addresses 0-5 but 
-		 * 5 is the correct one.
-		 */
-		aup->phy_addr = 5;
-	}
-#endif
 
-	if (aup->mii->chip_info == NULL) {
-		printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n",
-				dev->name);
+#endif
+	if (!phydev) {
+		printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
 		return -1;
 	}
 
-	printk(KERN_INFO "%s: Using %s as default\n", 
-			dev->name, aup->mii->chip_info->name);
+	/* now we are supposed to have a proper phydev, to attach to... */
+	BUG_ON(!phydev);
+
+	phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0);
+		
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+		
+	// mask with MAC supported features
+	phydev->supported &= (SUPPORTED_10baseT_Half 
+			      | SUPPORTED_10baseT_Full 
+			      | SUPPORTED_100baseT_Half 
+			      | SUPPORTED_100baseT_Full 
+			      | SUPPORTED_Autoneg 
+			      | SUPPORTED_MII 
+			      | SUPPORTED_TP);
+		
+	phydev->advertising = phydev->supported;
+
+	aup->old_link = 0;
+	aup->old_speed = 0;
+	aup->old_duplex = -1;
+	aup->phy_dev = phydev;
+
+	printk(KERN_INFO "%s: attached %s (mii=%s, irq=%d)\n", 
+	       dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
 
 	return 0;
 }
@@ -1097,6 +371,24 @@ static void hard_stop(struct net_device 
 	au_sync_delay(10);
 }
 
+static void enable_mac(struct net_device *dev, int force_reset)
+{
+	unsigned long flags;
+	struct au1000_private *aup = (struct au1000_private *) dev->priv;
+
+	spin_lock_irqsave(&aup->lock, flags);
+
+	if(force_reset || (!aup->mac_enabled)) {
+		*aup->enable = MAC_EN_CLOCK_ENABLE;
+		au_sync_delay(2);
+		*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
+		au_sync_delay(2);
+
+		aup->mac_enabled = 1;
+	}
+
+	spin_unlock_irqrestore(&aup->lock, flags);
+}
 
 static void reset_mac(struct net_device *dev)
 {
@@ -1109,23 +401,15 @@ static void reset_mac(struct net_device 
 				dev->name, (unsigned)aup);
 
 	spin_lock_irqsave(&aup->lock, flags);
-	if (aup->timer.function == &au1000_timer) {/* check if timer initted */
-		del_timer(&aup->timer);
-	}
+	// fixme, lock miibus
 
 	hard_stop(dev);
-	#ifdef CONFIG_BCM5222_DUAL_PHY
-	if (aup->mac_id != 0) {
-	#endif
-		/* If BCM5222, we can't leave MAC0 in reset because then 
-		 * we can't access the dual phy for ETH1 */
-		*aup->enable = MAC_EN_CLOCK_ENABLE;
-		au_sync_delay(2);
-		*aup->enable = 0;
-		au_sync_delay(2);
-	#ifdef CONFIG_BCM5222_DUAL_PHY
-	}
-	#endif
+
+	*aup->enable = MAC_EN_CLOCK_ENABLE;
+	au_sync_delay(2);
+	*aup->enable = 0;
+	au_sync_delay(2);
+
 	aup->tx_full = 0;
 	for (i = 0; i < NUM_RX_DMA; i++) {
 		/* reset control bits */
@@ -1135,6 +419,9 @@ static void reset_mac(struct net_device 
 		/* reset control bits */
 		aup->tx_dma_ring[i]->buff_stat &= ~0xf;
 	}
+
+	aup->mac_enabled = 0;
+
 	spin_unlock_irqrestore(&aup->lock, flags);
 }
 
@@ -1237,178 +524,26 @@ static int __init au1000_init_module(voi
 	return 0;
 }
 
-static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
-{
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	u16 ctl, adv;
-
-	/* Setup standard advertise */
-	adv = mdio_read(dev, aup->phy_addr, MII_ADVERTISE);
-	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
-	if (advertise & ADVERTISED_10baseT_Half)
-		adv |= ADVERTISE_10HALF;
-	if (advertise & ADVERTISED_10baseT_Full)
-		adv |= ADVERTISE_10FULL;
-	if (advertise & ADVERTISED_100baseT_Half)
-		adv |= ADVERTISE_100HALF;
-	if (advertise & ADVERTISED_100baseT_Full)
-		adv |= ADVERTISE_100FULL;
-	mdio_write(dev, aup->phy_addr, MII_ADVERTISE, adv);
-
-	/* Start/Restart aneg */
-	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
-	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
-
-	return 0;
-}
-
-static int au1000_setup_forced(struct net_device *dev, int speed, int fd)
-{
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	u16 ctl;
-
-	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
-	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);
-
-	/* First reset the PHY */
-	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl | BMCR_RESET);
-
-	/* Select speed & duplex */
-	switch (speed) {
-		case SPEED_10:
-			break;
-		case SPEED_100:
-			ctl |= BMCR_SPEED100;
-			break;
-		case SPEED_1000:
-		default:
-			return -EINVAL;
-	}
-	if (fd == DUPLEX_FULL)
-		ctl |= BMCR_FULLDPLX;
-	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);
-
-	return 0;
-}
-
-
-static void
-au1000_start_link(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	u32 advertise;
-	int autoneg;
-	int forced_speed;
-	int forced_duplex;
-
-	/* Default advertise */
-	advertise = GENMII_DEFAULT_ADVERTISE;
-	autoneg = aup->want_autoneg;
-	forced_speed = SPEED_100;
-	forced_duplex = DUPLEX_FULL;
-
-	/* Setup link parameters */
-	if (cmd) {
-		if (cmd->autoneg == AUTONEG_ENABLE) {
-			advertise = cmd->advertising;
-			autoneg = 1;
-		} else {
-			autoneg = 0;
-
-			forced_speed = cmd->speed;
-			forced_duplex = cmd->duplex;
-		}
-	}
-
-	/* Configure PHY & start aneg */
-	aup->want_autoneg = autoneg;
-	if (autoneg)
-		au1000_setup_aneg(dev, advertise);
-	else
-		au1000_setup_forced(dev, forced_speed, forced_duplex);
-	mod_timer(&aup->timer, jiffies + HZ);
-}
-
 static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	u16 link, speed;
 
-	cmd->supported = GENMII_DEFAULT_FEATURES;
-	cmd->advertising = GENMII_DEFAULT_ADVERTISE;
-	cmd->port = PORT_MII;
-	cmd->transceiver = XCVR_EXTERNAL;
-	cmd->phy_address = aup->phy_addr;
-	spin_lock_irq(&aup->lock);
-	cmd->autoneg = aup->want_autoneg;
-	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
-	if ((speed == IF_PORT_100BASETX) || (speed == IF_PORT_100BASEFX))
-		cmd->speed = SPEED_100;
-	else if (speed == IF_PORT_10BASET)
-		cmd->speed = SPEED_10;
-	if (link && (dev->if_port == IF_PORT_100BASEFX))
-		cmd->duplex = DUPLEX_FULL;
-	else
-		cmd->duplex = DUPLEX_HALF;
-	spin_unlock_irq(&aup->lock);
-	return 0;
-}
+	if (!aup->phy_dev) return -EINVAL; // PHY not controllable
 
-static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-	 struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	  unsigned long features = GENMII_DEFAULT_FEATURES;
-
-	 if (!capable(CAP_NET_ADMIN))
-		 return -EPERM;
-
-	 if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
-		 return -EINVAL;
-	 if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
-		 return -EINVAL;
-	 if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
-		 return -EINVAL;
-	 if (cmd->autoneg == AUTONEG_DISABLE)
-		 switch (cmd->speed) {
-		 case SPEED_10:
-			 if (cmd->duplex == DUPLEX_HALF &&
-				 (features & SUPPORTED_10baseT_Half) == 0)
-				 return -EINVAL;
-			 if (cmd->duplex == DUPLEX_FULL &&
-				 (features & SUPPORTED_10baseT_Full) == 0)
-				 return -EINVAL;
-			 break;
-		 case SPEED_100:
-			 if (cmd->duplex == DUPLEX_HALF &&
-				 (features & SUPPORTED_100baseT_Half) == 0)
-				 return -EINVAL;
-			 if (cmd->duplex == DUPLEX_FULL &&
-				 (features & SUPPORTED_100baseT_Full) == 0)
-				 return -EINVAL;
-			 break;
-		 default:
-			 return -EINVAL;
-		 }
-	 else if ((features & SUPPORTED_Autoneg) == 0)
-		 return -EINVAL;
-
-	 spin_lock_irq(&aup->lock);
-	 au1000_start_link(dev, cmd);
-	 spin_unlock_irq(&aup->lock);
-	 return 0;
+	return phy_ethtool_gset(aup->phy_dev, cmd);
 }
 
-static int au1000_nway_reset(struct net_device *dev)
+static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-
-	if (!aup->want_autoneg)
-		return -EINVAL;
-	spin_lock_irq(&aup->lock);
-	au1000_start_link(dev, NULL);
-	spin_unlock_irq(&aup->lock);
-	return 0;
+	
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	
+	if (!aup->phy_dev) return -EINVAL; // PHY not controllable
+	
+	//spin_lock_irq(&aup->lock); need this?
+	return phy_ethtool_sset(aup->phy_dev, cmd);
 }
 
 static void
@@ -1423,17 +558,11 @@ au1000_get_drvinfo(struct net_device *de
 	info->regdump_len = 0;
 }
 
-static u32 au1000_get_link(struct net_device *dev)
-{
-	return netif_carrier_ok(dev);
-}
-
 static struct ethtool_ops au1000_ethtool_ops = {
 	.get_settings = au1000_get_settings,
 	.set_settings = au1000_set_settings,
 	.get_drvinfo = au1000_get_drvinfo,
-	.nway_reset = au1000_nway_reset,
-	.get_link = au1000_get_link
+	.get_link = ethtool_op_get_link,
 };
 
 static struct net_device *
@@ -1527,24 +656,22 @@ au1000_probe(u32 ioaddr, int irq, int po
 		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
 	}
 
-	/* bring the device out of reset, otherwise probing the mii
-	 * will hang */
-	*aup->enable = MAC_EN_CLOCK_ENABLE;
-	au_sync_delay(2);
-	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | 
-		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
-	au_sync_delay(2);
+	*aup->enable = 0;
+	aup->mac_enabled = 0;
 
-	aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
-	if (!aup->mii) {
-		printk(KERN_ERR "%s: out of memory\n", dev->name);
-		goto err_out;
+	aup->mii_bus.priv = dev;
+	aup->mii_bus.read = mdiobus_read;
+	aup->mii_bus.write = mdiobus_write;
+	aup->mii_bus.reset = mdiobus_reset;
+	aup->mii_bus.name = "au1000_eth_mii";
+	aup->mii_bus.id = aup->mac_id;
+	aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	for(i = 0; i < PHY_MAX_ADDR; ++i) {
+		aup->mii_bus.phy_map[i] = NULL; /* paranoia */
+		aup->mii_bus.irq[i] = PHY_POLL;
 	}
-	aup->mii->next = NULL;
-	aup->mii->chip_info = NULL;
-	aup->mii->status = 0;
-	aup->mii->mii_control_reg = 0;
-	aup->mii->mii_data_reg = 0;
+
+	mdiobus_register(&aup->mii_bus);
 
 	if (mii_probe(dev) != 0) {
 		goto err_out;
@@ -1590,7 +717,6 @@ au1000_probe(u32 ioaddr, int irq, int po
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &au1000_ioctl;
 	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
-	dev->set_config = &au1000_set_config;
 	dev->tx_timeout = au1000_tx_timeout;
 	dev->watchdog_timeo = ETH_TX_TIMEOUT;
 
@@ -1606,7 +732,7 @@ err_out:
 	/* here we should have a valid dev plus aup-> register addresses
 	 * so we can reset the mac properly.*/
 	reset_mac(dev);
-	kfree(aup->mii);
+
 	for (i = 0; i < NUM_RX_DMA; i++) {
 		if (aup->rx_db_inuse[i])
 			ReleaseDB(aup, aup->rx_db_inuse[i]);
@@ -1640,19 +766,14 @@ static int au1000_init(struct net_device
 	u32 flags;
 	int i;
 	u32 control;
-	u16 link, speed;
 
 	if (au1000_debug > 4) 
 		printk("%s: au1000_init\n", dev->name);
 
-	spin_lock_irqsave(&aup->lock, flags);
-
 	/* bring the device out of reset */
-	*aup->enable = MAC_EN_CLOCK_ENABLE;
-        au_sync_delay(2);
-	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | 
-		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
-	au_sync_delay(20);
+	enable_mac(dev, 1);
+
+	spin_lock_irqsave(&aup->lock, flags);
 
 	aup->mac->control = 0;
 	aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
@@ -1668,13 +789,15 @@ static int au1000_init(struct net_device
 	}
 	au_sync();
 
-	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
-	control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
+	control = MAC_RX_ENABLE | MAC_TX_ENABLE; /* fixme: set MAC_DISABLE_OWN_RX when necessary (== !DUPLEX && "normal operation") */
 #ifndef CONFIG_CPU_LITTLE_ENDIAN
 	control |= MAC_BIG_ENDIAN;
 #endif
-	if (link && (dev->if_port == IF_PORT_100BASEFX)) {
-		control |= MAC_FULL_DUPLEX;
+	if (aup->phy_dev) {
+		if (aup->phy_dev->link && aup->phy_dev->duplex) 
+			control |= MAC_FULL_DUPLEX; 
+	} else { /* PHY-less op, assume full-duplex */
+		control |= MAC_FULL_DUPLEX; 
 	}
 
 	aup->mac->control = control;
@@ -1685,57 +808,75 @@ static int au1000_init(struct net_device
 	return 0;
 }
 
-static void au1000_timer(unsigned long data)
+static void
+au1000_adjust_link(struct net_device *dev)
 {
-	struct net_device *dev = (struct net_device *)data;
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	unsigned char if_port;
-	u16 link, speed;
+	struct phy_device *phydev = aup->phy_dev;
+	unsigned long flags;
 
-	if (!dev) {
-		/* fatal error, don't restart the timer */
-		printk(KERN_ERR "au1000_timer error: NULL dev\n");
-		return;
-	}
+	int status_change = 0;
 
-	if_port = dev->if_port;
-	if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) {
-		if (link) {
-			if (!netif_carrier_ok(dev)) {
-				netif_carrier_on(dev);
-				printk(KERN_INFO "%s: link up\n", dev->name);
-			}
-		}
-		else {
-			if (netif_carrier_ok(dev)) {
-				netif_carrier_off(dev);
-				dev->if_port = 0;
-				printk(KERN_INFO "%s: link down\n", dev->name);
-			}
+	BUG_ON(!aup->phy_dev);
+
+	spin_lock_irqsave(&aup->lock, flags);
+
+	if (phydev->link && (aup->old_speed != phydev->speed)) {
+		// speed changed 
+
+		switch(phydev->speed) {
+		case 10:
+		case 100:
+			break;
+		default:
+			printk(KERN_WARNING
+			       "%s: Speed (%d) is not 10/100/1000 ??\n",
+			       dev->name, phydev->speed);
+			break;
 		}
+
+		aup->old_speed = phydev->speed;
+
+		status_change = 1;
 	}
 
-	if (link && (dev->if_port != if_port) && 
-			(dev->if_port != IF_PORT_UNKNOWN)) {
+	if (phydev->link && (aup->old_duplex != phydev->duplex)) {
+		// duplex mode changed
+		
+		/* switching duplex mode requires to disable rx and tx! */
 		hard_stop(dev);
-		if (dev->if_port == IF_PORT_100BASEFX) {
-			printk(KERN_INFO "%s: going to full duplex\n", 
-					dev->name);
+
+		if (phydev->duplex)
 			aup->mac->control |= MAC_FULL_DUPLEX;
-			au_sync_delay(1);
-		}
-		else {
+		else
 			aup->mac->control &= ~MAC_FULL_DUPLEX;
-			au_sync_delay(1);
-		}
+		au_sync_delay(1);
+
 		enable_rx_tx(dev);
+		aup->old_duplex = phydev->duplex;
+
+		status_change = 1;
+	}
+
+	if(phydev->link != aup->old_link) {
+		// link state changed
+
+		if (phydev->link) { // link went up
+			netif_schedule(dev);
+		} else { // link went down
+			aup->old_speed = 0;
+			aup->old_duplex = -1;
+		}
+
+		aup->old_link = phydev->link;
+		status_change = 1;
 	}
 
-	aup->timer.expires = RUN_AT((1*HZ)); 
-	aup->timer.data = (unsigned long)dev;
-	aup->timer.function = &au1000_timer; /* timer handler */
-	add_timer(&aup->timer);
+	spin_unlock_irqrestore(&aup->lock, flags);
 
+	if (status_change) {
+		phy_print_status(phydev);
+	}
 }
 
 static int au1000_open(struct net_device *dev)
@@ -1746,13 +887,6 @@ static int au1000_open(struct net_device
 	if (au1000_debug > 4)
 		printk("%s: open: dev=%p\n", dev->name, dev);
 
-	if ((retval = au1000_init(dev))) {
-		printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
-		free_irq(dev->irq, dev);
-		return retval;
-	}
-	netif_start_queue(dev);
-
 	if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, 
 					dev->name, dev))) {
 		printk(KERN_ERR "%s: unable to get IRQ %d\n", 
@@ -1760,11 +894,16 @@ static int au1000_open(struct net_device
 		return retval;
 	}
 
-	init_timer(&aup->timer); /* used in ioctl() */
-	aup->timer.expires = RUN_AT((3*HZ)); 
-	aup->timer.data = (unsigned long)dev;
-	aup->timer.function = &au1000_timer; /* timer handler */
-	add_timer(&aup->timer);
+	if ((retval = au1000_init(dev))) {
+		printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
+		free_irq(dev->irq, dev);
+		return retval;
+	}
+
+	if (aup->phy_dev)
+		phy_start(aup->phy_dev);
+
+	netif_start_queue(dev);
 
 	if (au1000_debug > 4)
 		printk("%s: open: Initialization done.\n", dev->name);
@@ -1787,6 +926,9 @@ static int au1000_close(struct net_devic
 	/* stop the device */
 	netif_stop_queue(dev);
 
+	if (aup->phy_dev)
+		phy_stop(aup->phy_dev);
+
 	/* disable the interrupt */
 	free_irq(dev->irq, dev);
 	spin_unlock_irqrestore(&aup->lock, flags);
@@ -1805,7 +947,7 @@ static void __exit au1000_cleanup_module
 		if (dev) {
 			aup = (struct au1000_private *) dev->priv;
 			unregister_netdev(dev);
-			kfree(aup->mii);
+
 			for (j = 0; j < NUM_RX_DMA; j++) {
 				if (aup->rx_db_inuse[j])
 					ReleaseDB(aup, aup->rx_db_inuse[j]);
@@ -1830,7 +972,7 @@ static void update_tx_stats(struct net_d
 	struct net_device_stats *ps = &aup->stats;
 
 	if (status & TX_FRAME_ABORTED) {
-		if (dev->if_port == IF_PORT_100BASEFX) {
+		if (!aup->phy_dev || aup->phy_dev->duplex) {
 			if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
 				/* any other tx errors are only valid
 				 * in half duplex mode */
@@ -2104,126 +1246,15 @@ static void set_rx_mode(struct net_devic
 	}
 }
 
-
 static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct au1000_private *aup = (struct au1000_private *)dev->priv;
-	u16 *data = (u16 *)&rq->ifr_ifru;
 
-	switch(cmd) { 
-		case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
-		case SIOCGMIIPHY:
-		        if (!netif_running(dev)) return -EINVAL;
-			data[0] = aup->phy_addr;
-		case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
-		case SIOCGMIIREG:
-			data[3] =  mdio_read(dev, data[0], data[1]); 
-			return 0;
-		case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
-		case SIOCSMIIREG: 
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			mdio_write(dev, data[0], data[1],data[2]);
-			return 0;
-		default:
-			return -EOPNOTSUPP;
-	}
-
-}
+	if (!netif_running(dev)) return -EINVAL;
 
+	if (!aup->phy_dev) return -EINVAL; // PHY not controllable
 
-static int au1000_set_config(struct net_device *dev, struct ifmap *map)
-{
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	u16 control;
-
-	if (au1000_debug > 4)  {
-		printk("%s: set_config called: dev->if_port %d map->port %x\n", 
-				dev->name, dev->if_port, map->port);
-	}
-
-	switch(map->port){
-		case IF_PORT_UNKNOWN: /* use auto here */   
-			printk(KERN_INFO "%s: config phy for aneg\n", 
-					dev->name);
-			dev->if_port = map->port;
-			/* Link Down: the timer will bring it up */
-			netif_carrier_off(dev);
-	
-			/* read current control */
-			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			control &= ~(MII_CNTL_FDX | MII_CNTL_F100);
-
-			/* enable auto negotiation and reset the negotiation */
-			mdio_write(dev, aup->phy_addr, MII_CONTROL, 
-					control | MII_CNTL_AUTO | 
-					MII_CNTL_RST_AUTO);
-
-			break;
-    
-		case IF_PORT_10BASET: /* 10BaseT */         
-			printk(KERN_INFO "%s: config phy for 10BaseT\n", 
-					dev->name);
-			dev->if_port = map->port;
-	
-			/* Link Down: the timer will bring it up */
-			netif_carrier_off(dev);
-
-			/* set Speed to 10Mbps, Half Duplex */
-			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			control &= ~(MII_CNTL_F100 | MII_CNTL_AUTO | 
-					MII_CNTL_FDX);
-	
-			/* disable auto negotiation and force 10M/HD mode*/
-			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
-			break;
-    
-		case IF_PORT_100BASET: /* 100BaseT */
-		case IF_PORT_100BASETX: /* 100BaseTx */ 
-			printk(KERN_INFO "%s: config phy for 100BaseTX\n", 
-					dev->name);
-			dev->if_port = map->port;
-	
-			/* Link Down: the timer will bring it up */
-			netif_carrier_off(dev);
-	
-			/* set Speed to 100Mbps, Half Duplex */
-			/* disable auto negotiation and enable 100MBit Mode */
-			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			control &= ~(MII_CNTL_AUTO | MII_CNTL_FDX);
-			control |= MII_CNTL_F100;
-			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
-			break;
-    
-		case IF_PORT_100BASEFX: /* 100BaseFx */
-			printk(KERN_INFO "%s: config phy for 100BaseFX\n", 
-					dev->name);
-			dev->if_port = map->port;
-	
-			/* Link Down: the timer will bring it up */
-			netif_carrier_off(dev);
-	
-			/* set Speed to 100Mbps, Full Duplex */
-			/* disable auto negotiation and enable 100MBit Mode */
-			control = mdio_read(dev, aup->phy_addr, MII_CONTROL);
-			control &= ~MII_CNTL_AUTO;
-			control |=  MII_CNTL_F100 | MII_CNTL_FDX;
-			mdio_write(dev, aup->phy_addr, MII_CONTROL, control);
-			break;
-		case IF_PORT_10BASE2: /* 10Base2 */
-		case IF_PORT_AUI: /* AUI */
-		/* These Modes are not supported (are they?)*/
-			printk(KERN_ERR "%s: 10Base2/AUI not supported", 
-					dev->name);
-			return -EOPNOTSUPP;
-			break;
-    
-		default:
-			printk(KERN_ERR "%s: Invalid media selected", 
-					dev->name);
-			return -EINVAL;
-	}
-	return 0;
+	return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
 }
 
 static struct net_device_stats *au1000_get_stats(struct net_device *dev)
@@ -2241,3 +1272,14 @@ static struct net_device_stats *au1000_g
 
 module_init(au1000_init_module);
 module_exit(au1000_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index ccb35fa..4ef74db 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -40,120 +40,6 @@
 
 #define MULTICAST_FILTER_LIMIT 64
 
-/* FIXME 
- * The PHY defines should be in a separate file.
- */
-
-/* MII register offsets */
-#define	MII_CONTROL 0x0000
-#define MII_STATUS  0x0001
-#define MII_PHY_ID0 0x0002
-#define	MII_PHY_ID1 0x0003
-#define MII_ANADV   0x0004
-#define MII_ANLPAR  0x0005
-#define MII_AEXP    0x0006
-#define MII_ANEXT   0x0007
-#define MII_LSI_PHY_CONFIG 0x0011
-/* Status register */
-#define MII_LSI_PHY_STAT   0x0012
-#define MII_AMD_PHY_STAT   MII_LSI_PHY_STAT
-#define MII_INTEL_PHY_STAT 0x0011
-
-#define MII_AUX_CNTRL  0x0018
-/* mii registers specific to AMD 79C901 */
-#define	MII_STATUS_SUMMARY = 0x0018
-
-/* MII Control register bit definitions. */
-#define	MII_CNTL_FDX      0x0100
-#define MII_CNTL_RST_AUTO 0x0200
-#define	MII_CNTL_ISOLATE  0x0400
-#define MII_CNTL_PWRDWN   0x0800
-#define	MII_CNTL_AUTO     0x1000
-#define MII_CNTL_F100     0x2000
-#define	MII_CNTL_LPBK     0x4000
-#define MII_CNTL_RESET    0x8000
-
-/* MII Status register bit  */
-#define	MII_STAT_EXT        0x0001 
-#define MII_STAT_JAB        0x0002
-#define	MII_STAT_LINK       0x0004
-#define MII_STAT_CAN_AUTO   0x0008
-#define	MII_STAT_FAULT      0x0010 
-#define MII_STAT_AUTO_DONE  0x0020
-#define	MII_STAT_CAN_T      0x0800
-#define MII_STAT_CAN_T_FDX  0x1000
-#define	MII_STAT_CAN_TX     0x2000 
-#define MII_STAT_CAN_TX_FDX 0x4000
-#define	MII_STAT_CAN_T4     0x8000
-
-
-#define		MII_ID1_OUI_LO		0xFC00	/* low bits of OUI mask */
-#define		MII_ID1_MODEL		0x03F0	/* model number */
-#define		MII_ID1_REV		0x000F	/* model number */
-
-/* MII NWAY Register Bits ...
-   valid for the ANAR (Auto-Negotiation Advertisement) and
-   ANLPAR (Auto-Negotiation Link Partner) registers */
-#define	MII_NWAY_NODE_SEL 0x001f
-#define MII_NWAY_CSMA_CD  0x0001
-#define	MII_NWAY_T	  0x0020
-#define MII_NWAY_T_FDX    0x0040
-#define	MII_NWAY_TX       0x0080
-#define MII_NWAY_TX_FDX   0x0100
-#define	MII_NWAY_T4       0x0200 
-#define MII_NWAY_PAUSE    0x0400 
-#define	MII_NWAY_RF       0x2000 /* Remote Fault */
-#define MII_NWAY_ACK      0x4000 /* Remote Acknowledge */
-#define	MII_NWAY_NP       0x8000 /* Next Page (Enable) */
-
-/* mii stsout register bits */
-#define	MII_STSOUT_LINK_FAIL 0x4000
-#define	MII_STSOUT_SPD       0x0080
-#define MII_STSOUT_DPLX      0x0040
-
-/* mii stsics register bits */
-#define	MII_STSICS_SPD       0x8000
-#define MII_STSICS_DPLX      0x4000
-#define	MII_STSICS_LINKSTS   0x0001
-
-/* mii stssum register bits */
-#define	MII_STSSUM_LINK  0x0008
-#define MII_STSSUM_DPLX  0x0004
-#define	MII_STSSUM_AUTO  0x0002
-#define MII_STSSUM_SPD   0x0001
-
-/* lsi phy status register */
-#define MII_LSI_PHY_STAT_FDX	0x0040
-#define MII_LSI_PHY_STAT_SPD	0x0080
-
-/* amd phy status register */
-#define MII_AMD_PHY_STAT_FDX	0x0800
-#define MII_AMD_PHY_STAT_SPD	0x0400
-
-/* intel phy status register */
-#define MII_INTEL_PHY_STAT_FDX	0x0200
-#define MII_INTEL_PHY_STAT_SPD	0x4000
-
-/* Auxilliary Control/Status Register */
-#define MII_AUX_FDX      0x0001
-#define MII_AUX_100      0x0002
-#define MII_AUX_F100     0x0004
-#define MII_AUX_ANEG     0x0008
-
-typedef struct mii_phy {
-	struct mii_phy * next;
-	struct mii_chip_info * chip_info;
-	u16 status;
-	u32 *mii_control_reg;
-	u32 *mii_data_reg;
-} mii_phy_t;
-
-struct phy_ops {
-	int (*phy_init) (struct net_device *, int);
-	int (*phy_reset) (struct net_device *, int);
-	int (*phy_status) (struct net_device *, int, u16 *, u16 *);
-};
-
 /* 
  * Data Buffer Descriptor. Data buffers must be aligned on 32 byte 
  * boundary for both, receive and transmit.
@@ -200,7 +86,6 @@ typedef struct mac_reg {
 
 
 struct au1000_private {
-	
 	db_dest_t *pDBfree;
 	db_dest_t db[NUM_RX_BUFFS+NUM_TX_BUFFS];
 	volatile rx_dma_t *rx_dma_ring[NUM_RX_DMA];
@@ -213,9 +98,16 @@ struct au1000_private {
 	u32 tx_full;
 
 	int mac_id;
-	mii_phy_t *mii;
-	struct mii_if_info mii_if;
-	struct phy_ops *phy_ops;
+
+	int mac_enabled;       /* whether MAC is currently enabled and running (req. for mdio) */
+
+	int old_link;          /* used by au1000_adjust_link */
+	int old_speed; 
+	int old_duplex;
+
+	int phy_addr;          /* phy address */
+	struct phy_device *phy_dev;
+	struct mii_bus mii_bus;
 	
 	/* These variables are just for quick access to certain regs addresses. */
 	volatile mac_reg_t *mac;  /* mac registers                      */   
@@ -227,11 +119,9 @@ struct au1000_private {
 	u8 *hash_table;
 	u32 hash_mode;
 	u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
-	int phy_addr;          /* phy address */
 	u32 options;           /* User-settable misc. driver options. */
 	u32 drv_flags;
-	int want_autoneg;
+
 	struct net_device_stats stats;
-	struct timer_list timer;
 	spinlock_t lock;       /* Serialise access to device */
 };

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]

^ permalink raw reply related

* [patch 0/2] spidernet: support for bcm5461 and new setting
From: Jens Osterkamp @ 2006-05-04  9:59 UTC (permalink / raw)
  To: jgarzik; +Cc: netdev, arnd.bergmann


The first patch introduces a new PHY BCM5461 as the BCM5421 will be no
longer produced. Besides that it generalizes the way, PHYs are
switched into fiber mode.
The second introduces a new setting that we need to make the driver
work more reliable.

Please apply.

Jens

^ permalink raw reply

* [patch 1/2] spidernet: enable support for bcm5461 ethernet phy
From: Jens Osterkamp @ 2006-05-04  9:59 UTC (permalink / raw)
  To: jgarzik; +Cc: netdev, arndb, utz.bacher
In-Reply-To: <20060504155034.486042000@>

From: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>

A newer board revision changed the type of ethernet phy.
Moreover, this generalizes the way that a phy gets switched
into fiber mode when autodetection is not available.

Signed-off-by: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

---
Index: linus-2.6/drivers/net/sungem_phy.c
===================================================================
--- linus-2.6.orig/drivers/net/sungem_phy.c
+++ linus-2.6/drivers/net/sungem_phy.c
@@ -329,6 +329,30 @@ static int bcm5421_init(struct mii_phy* 
 	return 0;
 }
 
+static int bcm5421_enable_fiber(struct mii_phy* phy)
+{
+	/* enable fiber mode */
+	phy_write(phy, MII_NCONFIG, 0x9020);
+	/* LEDs active in both modes, autosense prio = fiber */
+	phy_write(phy, MII_NCONFIG, 0x945f);
+
+	/* switch off fibre autoneg */
+	phy_write(phy, MII_NCONFIG, 0xfc01);
+	phy_write(phy, 0x0b, 0x0004);
+
+	return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy)
+{
+        phy_write(phy, MII_NCONFIG, 0xfc0c);
+        phy_write(phy, MII_BMCR, 0x4140);
+        phy_write(phy, MII_NCONFIG, 0xfc0b);
+	phy_write(phy, MII_BMCR, 0x0140);
+
+	return 0;
+}
+
 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
 {
 	u16 ctl, adv;
@@ -762,6 +786,7 @@ static struct mii_phy_ops bcm5421_phy_op
 	.setup_forced	= bcm54xx_setup_forced,
 	.poll_link	= genmii_poll_link,
 	.read_link	= bcm54xx_read_link,
+	.enable_fiber   = bcm5421_enable_fiber,
 };
 
 static struct mii_phy_def bcm5421_phy_def = {
@@ -792,6 +817,25 @@ static struct mii_phy_def bcm5421k2_phy_
 	.ops		= &bcm5421k2_phy_ops
 };
 
+static struct mii_phy_ops bcm5461_phy_ops = {
+	.init		= bcm5421_init,
+	.suspend	= generic_suspend,
+	.setup_aneg	= bcm54xx_setup_aneg,
+	.setup_forced	= bcm54xx_setup_forced,
+	.poll_link	= genmii_poll_link,
+	.read_link	= bcm54xx_read_link,
+	.enable_fiber   = bcm5461_enable_fiber,
+};
+
+static struct mii_phy_def bcm5461_phy_def = {
+	.phy_id		= 0x002060c0,
+	.phy_id_mask	= 0xfffffff0,
+	.name		= "BCM5461",
+	.features	= MII_GBIT_FEATURES,
+	.magic_aneg	= 1,
+	.ops		= &bcm5461_phy_ops
+};
+
 /* Broadcom BCM 5462 built-in Vesta */
 static struct mii_phy_ops bcm5462V_phy_ops = {
 	.init		= bcm5421_init,
@@ -857,6 +901,7 @@ static struct mii_phy_def* mii_phy_table
 	&bcm5411_phy_def,
 	&bcm5421_phy_def,
 	&bcm5421k2_phy_def,
+	&bcm5461_phy_def,
 	&bcm5462V_phy_def,
 	&marvell_phy_def,
 	&genmii_phy_def,
Index: linus-2.6/drivers/net/spider_net.c
===================================================================
--- linus-2.6.orig/drivers/net/spider_net.c
+++ linus-2.6/drivers/net/spider_net.c
@@ -1792,15 +1792,7 @@ spider_net_setup_phy(struct spider_net_c
 	if (phy->def->ops->setup_forced)
 		phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
 
-	/* the following two writes could be moved to sungem_phy.c */
-	/* enable fiber mode */
-	spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020);
-	/* LEDs active in both modes, autosense prio = fiber */
-	spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f);
-
-	/* switch off fibre autoneg */
-	spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01);
-	spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004);
+	phy->def->ops->enable_fiber(phy);
 
 	phy->def->ops->read_link(phy);
 	pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
Index: linus-2.6/drivers/net/sungem_phy.h
===================================================================
--- linus-2.6.orig/drivers/net/sungem_phy.h
+++ linus-2.6/drivers/net/sungem_phy.h
@@ -12,6 +12,7 @@ struct mii_phy_ops
 	int		(*setup_forced)(struct mii_phy *phy, int speed, int fd);
 	int		(*poll_link)(struct mii_phy *phy);
 	int		(*read_link)(struct mii_phy *phy);
+	int		(*enable_fiber)(struct mii_phy *phy);
 };
 
 /* Structure used to statically define an mii/gii based PHY */

--


^ permalink raw reply

* [patch 2/2] spidernet: introduce new setting
From: Jens Osterkamp @ 2006-05-04  9:59 UTC (permalink / raw)
  To: jgarzik; +Cc: netdev, arndb, utz.bacher
In-Reply-To: <20060504155034.486042000@>

From: Jens Osterkamp <jens.osterkamp@de.ibm.com>

We found a new chip setting that we need in order
to make the driver work more reliable.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

Index: linux-2.6.17-rc3/drivers/net/spider_net.c
===================================================================
--- linux-2.6.17-rc3.orig/drivers/net/spider_net.c
+++ linux-2.6.17-rc3/drivers/net/spider_net.c
@@ -1652,6 +1652,8 @@ spider_net_enable_card(struct spider_net
 		{ SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE },
 
 		{ SPIDER_NET_GMRWOLCTRL, 0 },
+		{ SPIDER_NET_GTESTMD, 0x10000000 },
+		{ SPIDER_NET_GTTQMSK, 0x00400040 },
 		{ SPIDER_NET_GTESTMD, 0 },
 
 		{ SPIDER_NET_GMACINTEN, 0 },
Index: linux-2.6.17-rc3/drivers/net/spider_net.h
===================================================================
--- linux-2.6.17-rc3.orig/drivers/net/spider_net.h
+++ linux-2.6.17-rc3/drivers/net/spider_net.h
@@ -120,6 +120,8 @@ extern char spider_net_driver_name[];
 #define SPIDER_NET_GMRUAFILnR		0x00000500
 #define SPIDER_NET_GMRUA0FIL15R		0x00000578
 
+#define SPIDER_NET_GTTQMSK		0x00000934
+
 /* RX DMA controller registers, all 0x00000a.. are for DMA controller A,
  * 0x00000b.. for DMA controller B, etc. */
 #define SPIDER_NET_GDADCHA		0x00000a00

--


^ permalink raw reply

* Re: Fwd: r8169 MAC address change problem
From: Francois Romieu @ 2006-05-04 11:08 UTC (permalink / raw)
  To: Stefano Cavallari; +Cc: netdev
In-Reply-To: <bc7b5ef50605040257q2183df4fjeb3a5a0393f4ab0a@mail.gmail.com>

Stefano Cavallari <spiky.kiwi@gmail.com> :
> I sent this to netdev@vger.kernel.org, but I got no replies.

I am subscribed to netdev but the original has not landed in
my mailbox yet.

Can you try the patch available in:
http://bugzilla.kernel.org/show_bug.cgi?id=6032

-- 
Ueimor

^ permalink raw reply

* Re: [PATCH] bcm43xx-d80211: measure the channel change time
From: Johannes Berg @ 2006-05-04 12:22 UTC (permalink / raw)
  To: Jiri Benc; +Cc: Michael Buesch, John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <20060504111140.050c3e2f@griffin.suse.cz>

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

On Thu, 2006-05-04 at 11:11 +0200, Jiri Benc wrote:

> I think some safety fallback would be better. Like
> if (stop - start < SOME_MIN_VALUE) channel_change_time = SOME_MIN_VALUE
> (of course, this won't work because stop and start are unsigned, but you
> probably got the idea).

Probably. And yes, it should still work since stop>start at all times.

> And couldn't TSF counter overflow during the measurement?

Yes, if the card has been up for like 459148 years or has been reset to
an unbelievably high value. Remember, it's a 64 bit counter.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply

* [1/1] connector: export cn_already_initialized.
From: Evgeniy Polyakov @ 2006-05-04 12:24 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Some modules depend on that value, although it was initially introduced
for in-kernel static build.

No in-kernel users require it to be exported, so if you do think it
should not be exported I will force external module changes.

Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>

--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -486,3 +486,4 @@ module_exit(cn_fini);
 EXPORT_SYMBOL_GPL(cn_add_callback);
 EXPORT_SYMBOL_GPL(cn_del_callback);
 EXPORT_SYMBOL_GPL(cn_netlink_send);
+EXPORT_SYMBOL_GPL(cn_already_initialized);


-- 
	Evgeniy Polyakov

^ permalink raw reply

* Re: [PATCH wireless-dev] d80211: Add support for user space client MLME
From: Johannes Berg @ 2006-05-04 12:26 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: Jiri Benc, John W. Linville, netdev, jkmaline
In-Reply-To: <20060503164458.GB10524@instant802.com>

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

On Wed, 2006-05-03 at 09:44 -0700, Jouni Malinen wrote:

> But there is.. I committed changes to the wpa_supplicant devel branch
> for this yesterday. It seems to work fine with net/d80211 and bcm43xx
> with this small patch to d80211 to allow the functionality to be moved
> into user space.

Cool, do you have a list of things that we need to support for it to
work on a 'softmac' based driver (iow removing softmac in favour of
this)?

> I have not yet heard of anyone working with details of converting the
> management frame communication to use netlink.

I have an interest in this, as soon as I can I'll try writing up
something.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply

* Re: [PATCH] bcm43xx-d80211: measure the channel change time
From: Jiri Benc @ 2006-05-04 12:33 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Michael Buesch, John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <1146745340.1137.26.camel@localhost>

On Thu, 04 May 2006 14:22:20 +0200, Johannes Berg wrote:
> Probably. And yes, it should still work since stop>start at all times.

Are you sure you can guarantee that stop > start when these values come
from hardware you don't have specification for?

> Yes, if the card has been up for like 459148 years or has been reset to
> an unbelievably high value. Remember, it's a 64 bit counter.

TSF is set to a value sent by an AP. Is there anything that prevents
that AP to send you e.g. 0xfffffffffffff0?

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* Re: [PATCH] bcm43xx-d80211: measure the channel change time
From: Johannes Berg @ 2006-05-04 12:36 UTC (permalink / raw)
  To: Jiri Benc; +Cc: Michael Buesch, John W. Linville, netdev, bcm43xx-dev
In-Reply-To: <20060504143355.7bbfef35@griffin.suse.cz>

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

On Thu, 2006-05-04 at 14:33 +0200, Jiri Benc wrote:

> TSF is set to a value sent by an AP. Is there anything that prevents
> that AP to send you e.g. 0xfffffffffffff0?

Ah, good point, I didn't think of stupid APs. Yeah, it should handle it
I guess.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] ipg: redundancy with mii.h
From: Pekka Enberg @ 2006-05-04 13:44 UTC (permalink / raw)
  To: Francois Romieu; +Cc: David Vrabel, linux-kernel, netdev, david
In-Reply-To: <20060503233558.GA27232@electric-eye.fr.zoreil.com>

Pekka J Enberg <penberg@cs.Helsinki.FI> :
> [...]
> > maintain the tree, I can send you my patches so you can recreate the full 
> > history. The first steps were produced by quilt on the original 
> > out-of-tree driver, though, so they're probably not helpful.

On Thu, 2006-05-04 at 01:35 +0200, Francois Romieu wrote:
> It will be welcome.

My initial patches are here:

http://www.cs.helsinki.fi/u/penberg/linux/ip1000/

I consider your tree the master now. Please let me know when you have
recreated the history, so I can clone your tree. Thanks.

			Pekka


^ permalink raw reply

* a question on tcp_highspeed.c (in 2.6.16)
From: Xiaoliang (David) Wei @ 2006-05-04 14:03 UTC (permalink / raw)
  To: netdev

Hi gurus,

    I am reading the code of tcp_highspeed.c in the kernel and have a
question on the hstcp_cong_avoid function, specifically the following
AI part (line 136~143 in net/ipv4/tcp_highspeed.c ):

                /* Do additive increase */
                if (tp->snd_cwnd < tp->snd_cwnd_clamp) {
                        tp->snd_cwnd_cnt += ca->ai;
                        if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
                                tp->snd_cwnd++;
                                tp->snd_cwnd_cnt -= tp->snd_cwnd;
                        }
                }

    In this part, when (tp->snd_cwnd_cnt == tp->snd_cwnd),
snd_cwnd_cnt will be -1... snd_cwnd_cnt is defined as u16, will this
small chance of getting -1 becomes a problem?
Shall we change it by reversing the order of the cwnd++ and cwnd_cnt -= cwnd?

    Thanks.

-David

--
Xiaoliang (David) Wei      Graduate Student, CS@Caltech
http://davidwei.org
***********************************************

^ permalink raw reply

* schedule() does not work...
From: benzi vizman @ 2006-05-04 14:59 UTC (permalink / raw)
  To: netdev

Hi,

I try to run the following code in kernel (which is similar to apm() function) but it does not seem to work...

if (smp_processor_id() != cpu) {
      current->cpus_allowed = (1UL << cpu);
      schedule();
      if (smp_processor_id() != cpu) {
          BUG();
      }
}

Any idea why?


Benzi.


^ 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