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

Reply via email to