forcedeth: restart tx/rx
authorAyaz Abdulla <aabdulla@nvidia.com>
Mon, 4 Feb 2008 20:13:59 +0000 (15:13 -0500)
committerJeff Garzik <jeff@garzik.org>
Wed, 6 Feb 2008 11:41:14 +0000 (06:41 -0500)
This patch fixes the issue where the transmitter and receiver must be
restarted when applying new changes to certain registers.

Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/forcedeth.c

index 36342230a6deeb79ea89c5cb011c1724b1040bca..6e47b1103cd27eac6c2f79602abdc4c978caab7f 100644 (file)
@@ -624,6 +624,9 @@ union ring_type {
 #define NV_MSI_X_VECTOR_TX    0x1
 #define NV_MSI_X_VECTOR_OTHER 0x2
 
+#define NV_RESTART_TX         0x1
+#define NV_RESTART_RX         0x2
+
 /* statistics */
 struct nv_ethtool_str {
        char name[ETH_GSTRING_LEN];
@@ -2767,6 +2770,7 @@ static int nv_update_linkspeed(struct net_device *dev)
        int mii_status;
        int retval = 0;
        u32 control_1000, status_1000, phyreg, pause_flags, txreg;
+       u32 txrxFlags = 0;
 
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
@@ -2862,6 +2866,16 @@ set_speed:
        np->duplex = newdup;
        np->linkspeed = newls;
 
+       /* The transmitter and receiver must be restarted for safe update */
+       if (readl(base + NvRegTransmitterControl) & NVREG_XMITCTL_START) {
+               txrxFlags |= NV_RESTART_TX;
+               nv_stop_tx(dev);
+       }
+       if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
+               txrxFlags |= NV_RESTART_RX;
+               nv_stop_rx(dev);
+       }
+
        if (np->gigabit == PHY_GIGABIT) {
                phyreg = readl(base + NvRegRandomSeed);
                phyreg &= ~(0x3FF00);
@@ -2950,6 +2964,11 @@ set_speed:
        }
        nv_update_pause(dev, pause_flags);
 
+       if (txrxFlags & NV_RESTART_TX)
+               nv_start_tx(dev);
+       if (txrxFlags & NV_RESTART_RX)
+               nv_start_rx(dev);
+
        return retval;
 }