This patch allows the ar231x ethernet driver to be controlled from the
userspace "ethtool". I have tested this with ar2315 and ar5312.
Hopefully this sends right, it's my first submission :-p
Signed-off-by: Jonathan Bither <[email protected]>
Index: target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch
===================================================================
--- target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch
(revision 0)
+++ target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch
(revision 0)
@@ -0,0 +1,165 @@
+--- a/drivers/net/ar231x.h
++++ b/drivers/net/ar231x.h
+@@ -22,6 +22,9 @@
+ #include <asm/bootinfo.h>
+ #include <ar231x_platform.h>
+
++#define AR231X_DRV_NAME "ar231x-eth"
++#define AR231X_DRV_VERSION "0.5.1"
++
+ /*
+ * probe link timer - 5 secs
+ */
+@@ -270,7 +273,9 @@
+ struct timer_list link_timer;
+ unsigned short phy; /* merlot phy = 1, samsung phy
= 0x1f */
+ unsigned short mac;
+- unsigned short link; /* 0 - link down, 1 - link up */
++ unsigned int link; /* 0 - link down, 1 - link up */
++ unsigned int speed;
++ int duplex;
+ u16 phyData;
+
+ struct tasklet_struct rx_tasklet;
+--- a/drivers/net/ar231x.c
++++ b/drivers/net/ar231x.c
+@@ -131,8 +131,12 @@
+
+ #ifdef MODULE
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Sameer Dekate <[email protected]>, Imre Kaloz
<[email protected]>, Felix Fietkau <[email protected]>");
++MODULE_VERSION(AR231X_DRV_VERSION);
++MODULE_AUTHOR("Sameer Dekate <[email protected]>");
++MODULE_AUTHOR("Imre Kaloz <[email protected]>");
++MODULE_AUTHOR("Felix Fietkau <[email protected]>");
+ MODULE_DESCRIPTION("AR231x Ethernet driver");
++MODULE_ALIAS("platform:" AR231X_DRV_NAME);
+ #endif
+
+ #define virt_to_phys(x) ((u32)(x) & 0x1fffffff)
+@@ -143,6 +147,10 @@
+ static void rx_tasklet_cleanup(struct net_device *dev);
+ static void ar231x_multicast_list(struct net_device *dev);
+ static void ar231x_tx_timeout(struct net_device *dev);
++static int ar231x_ethtool_get_link(struct net_device *dev);
++static int ar231x_ethtool_get_settings(struct net_device *dev, struct
ethtool_cmd *cmd);
++static int ar231x_ethtool_set_settings(struct net_device *dev, struct
ethtool_cmd *cmd);
++static void ar231x_ethtool_get_drvinfo(struct net_device *dev, struct
ethtool_drvinfo *info);
+
+ static int ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int
regnum);
+ static int ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int
regnum, u16 value);
+@@ -182,6 +190,14 @@
+ #endif
+ };
+
++struct ethtool_ops ar231x_ethtool_ops = {
++ .set_settings = ar231x_ethtool_set_settings,
++ .get_settings = ar231x_ethtool_get_settings,
++ .get_drvinfo = ar231x_ethtool_get_drvinfo,
++ .get_link = ar231x_ethtool_get_link,
++};
++
++
+ int __init ar231x_probe(struct platform_device *pdev)
+ {
+ struct net_device *dev;
+@@ -219,6 +235,7 @@
+
+ dev->features |= NETIF_F_HIGHDMA;
+ dev->netdev_ops = &ar231x_ops;
++ dev->ethtool_ops = &ar231x_ethtool_ops;
+
+ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev);
+ tasklet_disable(&sp->rx_tasklet);
+@@ -400,7 +417,7 @@
+ }
+
+ static struct platform_driver ar231x_driver = {
+- .driver.name = "ar231x-eth",
++ .driver.name = AR231X_DRV_NAME,
+ .probe = ar231x_probe,
+ .remove = __devexit_p(ar231x_remove),
+ };
+@@ -560,13 +577,18 @@
+
+ phyData = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMSR);
+ if (sp->phyData != phyData) {
++ int duplex, speed;
+ if (phyData & BMSR_LSTATUS) {
+- /* link is present, ready link partner ability to
deterine
+- duplexity */
+- int duplex = 0;
+ u16 reg;
+
+ sp->link = 1;
++ /* Retrieve our speed */
++ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
MII_BMSR);
++ speed = (reg & (BMSR_10HALF | BMSR_10FULL)) ? 100 : 10;
++ sp->phy_dev->speed = speed;
++
++ /* link is present, ready link partner ability to
deterine
++ duplexity */
+ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy,
MII_BMCR);
+ if (reg & BMCR_ANENABLE) {
+ /* auto neg enabled */
+@@ -577,6 +599,8 @@
+ duplex = (reg & BMCR_FULLDPLX) ? 1 : 0;
+ }
+
++ sp->duplex = duplex;
++ sp->phy_dev->duplex = duplex;
+ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n",
+ dev->name, (duplex) ? "full" : "half");
+
+@@ -592,7 +616,9 @@
+ mac_control | MAC_CONTROL_DRO) &
~MAC_CONTROL_F);
+ }
+ } else {
+- /* no link */
++ /* no link. If link was up, give warning */
++ if (sp->link)
++ printk(KERN_INFO "%s: link down\n",
sp->dev->name);
+ sp->link = 0;
+ }
+ sp->phyData = phyData;
+@@ -1325,3 +1351,40 @@
+ return 0;
+ }
+
++static int ar231x_ethtool_get_settings(struct net_device *dev, struct
ethtool_cmd *cmd)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct phy_device *phydev = sp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_gset(phydev, cmd);
++}
++
++static int ar231x_ethtool_set_settings(struct net_device *dev, struct
ethtool_cmd *cmd)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct phy_device *phydev = sp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_sset(phydev, cmd);
++}
++
++static void ar231x_ethtool_get_drvinfo(struct net_device *dev, struct
ethtool_drvinfo *info)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ strcpy(info->driver, AR231X_DRV_NAME);
++ strcpy(info->version, AR231X_DRV_VERSION);
++ strcpy(info->bus_info, dev_name(&sp->phy_dev->dev));
++}
++
++static int ar231x_ethtool_get_link(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ return sp->link;
++}
++
Index: target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch
===================================================================
--- target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch (revision 0)
+++ target/linux/atheros/patches-2.6.37/221-ar231x-ethtool-ops.patch (revision 0)
@@ -0,0 +1,165 @@
+--- a/drivers/net/ar231x.h
++++ b/drivers/net/ar231x.h
+@@ -22,6 +22,9 @@
+ #include <asm/bootinfo.h>
+ #include <ar231x_platform.h>
+
++#define AR231X_DRV_NAME "ar231x-eth"
++#define AR231X_DRV_VERSION "0.5.1"
++
+ /*
+ * probe link timer - 5 secs
+ */
+@@ -270,7 +273,9 @@
+ struct timer_list link_timer;
+ unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */
+ unsigned short mac;
+- unsigned short link; /* 0 - link down, 1 - link up */
++ unsigned int link; /* 0 - link down, 1 - link up */
++ unsigned int speed;
++ int duplex;
+ u16 phyData;
+
+ struct tasklet_struct rx_tasklet;
+--- a/drivers/net/ar231x.c
++++ b/drivers/net/ar231x.c
+@@ -131,8 +131,12 @@
+
+ #ifdef MODULE
+ MODULE_LICENSE("GPL");
+-MODULE_AUTHOR("Sameer Dekate <[email protected]>, Imre Kaloz <[email protected]>, Felix Fietkau <[email protected]>");
++MODULE_VERSION(AR231X_DRV_VERSION);
++MODULE_AUTHOR("Sameer Dekate <[email protected]>");
++MODULE_AUTHOR("Imre Kaloz <[email protected]>");
++MODULE_AUTHOR("Felix Fietkau <[email protected]>");
+ MODULE_DESCRIPTION("AR231x Ethernet driver");
++MODULE_ALIAS("platform:" AR231X_DRV_NAME);
+ #endif
+
+ #define virt_to_phys(x) ((u32)(x) & 0x1fffffff)
+@@ -143,6 +147,10 @@
+ static void rx_tasklet_cleanup(struct net_device *dev);
+ static void ar231x_multicast_list(struct net_device *dev);
+ static void ar231x_tx_timeout(struct net_device *dev);
++static int ar231x_ethtool_get_link(struct net_device *dev);
++static int ar231x_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
++static int ar231x_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd);
++static void ar231x_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+
+ static int ar231x_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum);
+ static int ar231x_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value);
+@@ -182,6 +190,14 @@
+ #endif
+ };
+
++struct ethtool_ops ar231x_ethtool_ops = {
++ .set_settings = ar231x_ethtool_set_settings,
++ .get_settings = ar231x_ethtool_get_settings,
++ .get_drvinfo = ar231x_ethtool_get_drvinfo,
++ .get_link = ar231x_ethtool_get_link,
++};
++
++
+ int __init ar231x_probe(struct platform_device *pdev)
+ {
+ struct net_device *dev;
+@@ -219,6 +235,7 @@
+
+ dev->features |= NETIF_F_HIGHDMA;
+ dev->netdev_ops = &ar231x_ops;
++ dev->ethtool_ops = &ar231x_ethtool_ops;
+
+ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev);
+ tasklet_disable(&sp->rx_tasklet);
+@@ -400,7 +417,7 @@
+ }
+
+ static struct platform_driver ar231x_driver = {
+- .driver.name = "ar231x-eth",
++ .driver.name = AR231X_DRV_NAME,
+ .probe = ar231x_probe,
+ .remove = __devexit_p(ar231x_remove),
+ };
+@@ -560,13 +577,18 @@
+
+ phyData = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMSR);
+ if (sp->phyData != phyData) {
++ int duplex, speed;
+ if (phyData & BMSR_LSTATUS) {
+- /* link is present, ready link partner ability to deterine
+- duplexity */
+- int duplex = 0;
+ u16 reg;
+
+ sp->link = 1;
++ /* Retrieve our speed */
++ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMSR);
++ speed = (reg & (BMSR_10HALF | BMSR_10FULL)) ? 100 : 10;
++ sp->phy_dev->speed = speed;
++
++ /* link is present, ready link partner ability to deterine
++ duplexity */
+ reg = ar231x_mdiobus_read(sp->mii_bus, sp->phy, MII_BMCR);
+ if (reg & BMCR_ANENABLE) {
+ /* auto neg enabled */
+@@ -577,6 +599,8 @@
+ duplex = (reg & BMCR_FULLDPLX) ? 1 : 0;
+ }
+
++ sp->duplex = duplex;
++ sp->phy_dev->duplex = duplex;
+ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n",
+ dev->name, (duplex) ? "full" : "half");
+
+@@ -592,7 +616,9 @@
+ mac_control | MAC_CONTROL_DRO) & ~MAC_CONTROL_F);
+ }
+ } else {
+- /* no link */
++ /* no link. If link was up, give warning */
++ if (sp->link)
++ printk(KERN_INFO "%s: link down\n", sp->dev->name);
+ sp->link = 0;
+ }
+ sp->phyData = phyData;
+@@ -1325,3 +1351,40 @@
+ return 0;
+ }
+
++static int ar231x_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct phy_device *phydev = sp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_gset(phydev, cmd);
++}
++
++static int ar231x_ethtool_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ struct phy_device *phydev = sp->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_sset(phydev, cmd);
++}
++
++static void ar231x_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++
++ strcpy(info->driver, AR231X_DRV_NAME);
++ strcpy(info->version, AR231X_DRV_VERSION);
++ strcpy(info->bus_info, dev_name(&sp->phy_dev->dev));
++}
++
++static int ar231x_ethtool_get_link(struct net_device *dev)
++{
++ struct ar231x_private *sp = netdev_priv(dev);
++ return sp->link;
++}
++
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel