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.
|