I received a private reply from Herbert Valerio Riedel with a patch that falls into category > 3. Split off the MII handling code or, better, reuse the facility already > provided by drivers/net/mii.c. with the permission to forward the patch here. Here comes the code and some comments by him... >>>>>>>>>>>>>>>>>>>>>>>>>>>>>code>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> there's a nasty bug in the code, which triggers a kernel freeze when performing MII ioctl's w/ mii-tool on a device which is down; the following code fixes that, and uses the generic mii ioctl helper in order to use proven code... hope it's welcomed or useful :-) Index: drivers/net/au1000_eth.c =================================================================== --- drivers/net/au1000_eth.c (revision 25) +++ drivers/net/au1000_eth.c (working copy) @@ -91,7 +91,7 @@ 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 mdio_write(struct net_device *, int, int, int); static void dump_mii(struct net_device *dev, int phy_id); // externs @@ -846,7 +846,7 @@ 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_id, int reg, int value) { struct au1000_private *aup = (struct au1000_private *) dev->priv; volatile u32 *mii_control_reg; @@ -951,6 +951,10 @@ aup->phy_ops = mii_chip_table[i].phy_ops; aup->phy_ops->phy_init(dev,phy_addr); + aup->mii_if.phy_id = phy_addr; + aup->mii_if.phy_id_mask = 0x1f; + aup->mii_if.reg_num_mask = 0x1f; + // Check for dual-phy and then store required // values and set indicators. We need to do // this now since mdio_{read,write} need the @@ -1544,6 +1548,10 @@ aup->mii->mii_control_reg = 0; aup->mii->mii_data_reg = 0; + aup->mii_if.dev = dev; + aup->mii_if.mdio_read = mdio_read; + aup->mii_if.mdio_write = mdio_write; + if (mii_probe(dev) != 0) { goto err_out; } @@ -1592,6 +1600,7 @@ dev->tx_timeout = au1000_tx_timeout; dev->watchdog_timeo = ETH_TX_TIMEOUT; + /* * The boot code uses the ethernet controller, so reset it to start * fresh. au1000_init() expects that the device is in reset state. @@ -2127,24 +2136,17 @@ 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; + struct au1000_private *const aup = netdev_priv(dev); + int rc; + unsigned long flags; - switch(cmd) { - case SIOCGMIIPHY: - data[0] = aup->phy_addr; - /* Fall through */ - case SIOCGMIIREG: - data[3] = mdio_read(dev, aup->phy_addr, data[1]); - return 0; - case SIOCSMIIREG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - mdio_write(dev, aup->phy_addr, data[1], data[2]); - return 0; - default: - return -EOPNOTSUPP; - } + if (!netif_running(dev)) + return -EINVAL; + + spin_lock_irqsave(&aup->lock, flags); + rc = generic_mii_ioctl(&aup->mii_if, if_mii(rq), cmd, NULL); + spin_unlock_irqrestore(&aup->lock, flags); + return rc; } Index: drivers/net/au1000_eth.h =================================================================== --- drivers/net/au1000_eth.h (revision 25) +++ drivers/net/au1000_eth.h (working copy) @@ -214,6 +214,7 @@ int mac_id; mii_phy_t *mii; struct phy_ops *phy_ops; + struct mii_if_info mii_if; /* These variables are just for quick access to certain regs addresses. */ volatile mac_reg_t *mac; /* mac registers */ Index: drivers/net/Kconfig =================================================================== --- drivers/net/Kconfig (revision 25) +++ drivers/net/Kconfig (working copy) @@ -467,6 +467,7 @@ bool "MIPS AU1000 Ethernet support" depends on NET_ETHERNET && SOC_AU1X00 select CRC32 + select MII help If you have an Alchemy Semi AU1X00 based system say Y. Otherwise, say N.