- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / drivers / net / tsi108_eth.c
index 35d15e8..6f33f84 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -297,18 +298,11 @@ static void tsi108_check_phy(struct net_device *dev)
        u32 speed;
        unsigned long flags;
 
-       /* Do a dummy read, as for some reason the first read
-        * after a link becomes up returns link down, even if
-        * it's been a while since the link came up.
-        */
-
        spin_lock_irqsave(&phy_lock, flags);
 
        if (!data->phy_ok)
                goto out;
 
-       tsi108_read_mii(data, MII_BMSR);
-
        duplex = mii_check_media(&data->mii_if, netif_msg_link(data), data->init_media);
        data->init_media = 0;
 
@@ -345,22 +339,21 @@ static void tsi108_check_phy(struct net_device *dev)
 
                        TSI_WRITE(TSI108_MAC_CFG2, mac_cfg2_reg);
                        TSI_WRITE(TSI108_EC_PORTCTRL, portctrl_reg);
+               }
 
-                       if (data->link_up == 0) {
-                               /* The manual says it can take 3-4 usecs for the speed change
-                                * to take effect.
-                                */
-                               udelay(5);
+               if (data->link_up == 0) {
+                       /* The manual says it can take 3-4 usecs for the speed change
+                        * to take effect.
+                        */
+                       udelay(5);
 
-                               spin_lock(&data->txlock);
-                               if (is_valid_ether_addr(dev->dev_addr) && data->txfree)
-                                       netif_wake_queue(dev);
+                       spin_lock(&data->txlock);
+                       if (is_valid_ether_addr(dev->dev_addr) && data->txfree)
+                               netif_wake_queue(dev);
 
-                               data->link_up = 1;
-                               spin_unlock(&data->txlock);
-                       }
+                       data->link_up = 1;
+                       spin_unlock(&data->txlock);
                }
-
        } else {
                if (data->link_up == 1) {
                        netif_stop_queue(dev);
@@ -1274,12 +1267,11 @@ static void tsi108_init_phy(struct net_device *dev)
         * PHY_STAT register before the link up status bit is set.
         */
 
-       data->link_up = 1;
+       data->link_up = 0;
 
        while (!((phyval = tsi108_read_mii(data, MII_BMSR)) &
                 BMSR_LSTATUS)) {
                if (i++ > (MII_READ_DELAY / 10)) {
-                       data->link_up = 0;
                        break;
                }
                spin_unlock_irqrestore(&phy_lock, flags);
@@ -1287,6 +1279,7 @@ static void tsi108_init_phy(struct net_device *dev)
                spin_lock_irqsave(&phy_lock, flags);
        }
 
+       data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
        printk(KERN_DEBUG "PHY_STAT reg contains %08x\n", phyval);
        data->phy_ok = 1;
        data->init_media = 1;
@@ -1527,12 +1520,46 @@ static void tsi108_init_mac(struct net_device *dev)
        TSI_WRITE(TSI108_EC_INTMASK, ~0);
 }
 
+static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tsi108_prv_data *data = netdev_priv(dev);
+       unsigned long flags;
+       int rc;
+       
+       spin_lock_irqsave(&data->txlock, flags);
+       rc = mii_ethtool_gset(&data->mii_if, cmd);
+       spin_unlock_irqrestore(&data->txlock, flags);
+
+       return rc;
+}
+
+static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct tsi108_prv_data *data = netdev_priv(dev);
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&data->txlock, flags);
+       rc = mii_ethtool_sset(&data->mii_if, cmd);
+       spin_unlock_irqrestore(&data->txlock, flags);
+       
+       return rc;
+}
+
 static int tsi108_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct tsi108_prv_data *data = netdev_priv(dev);
+       if (!netif_running(dev))
+               return -EINVAL;
        return generic_mii_ioctl(&data->mii_if, if_mii(rq), cmd, NULL);
 }
 
+static const struct ethtool_ops tsi108_ethtool_ops = {
+       .get_link       = ethtool_op_get_link,
+       .get_settings   = tsi108_get_settings,
+       .set_settings   = tsi108_set_settings,
+};
+
 static int
 tsi108_init_one(struct platform_device *pdev)
 {
@@ -1584,7 +1611,6 @@ tsi108_init_one(struct platform_device *pdev)
        data->mii_if.phy_id = einfo->phy;
        data->mii_if.phy_id_mask = 0x1f;
        data->mii_if.reg_num_mask = 0x1f;
-       data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
 
        data->phy = einfo->phy;
        data->phy_type = einfo->phy_type;
@@ -1598,6 +1624,7 @@ tsi108_init_one(struct platform_device *pdev)
        dev->get_stats = tsi108_get_stats;
        netif_napi_add(dev, &data->napi, tsi108_poll, 64);
        dev->do_ioctl = tsi108_do_ioctl;
+       dev->ethtool_ops = &tsi108_ethtool_ops;
 
        /* Apparently, the Linux networking code won't use scatter-gather
         * if the hardware doesn't do checksums.  However, it's faster
@@ -1629,6 +1656,7 @@ tsi108_init_one(struct platform_device *pdev)
                goto register_fail;
        }
 
+       platform_set_drvdata(pdev, dev);
        printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n",
               dev->name, print_mac(mac, dev->dev_addr));
 #ifdef DEBUG