Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[sfrench/cifs-2.6.git] / drivers / net / tg3.c
index 4942f7d18937b9cbbe94fd37607c2d331bb11c70..f9ef8bd8b11edbbc8c56bd72c5c28e9419f05654 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.86"
-#define DRV_MODULE_RELDATE     "November 9, 2007"
+#define DRV_MODULE_VERSION     "3.88"
+#define DRV_MODULE_RELDATE     "March 20, 2008"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -1602,68 +1602,113 @@ static void tg3_link_report(struct tg3 *tp)
                       (tp->link_config.active_duplex == DUPLEX_FULL ?
                        "full" : "half"));
 
-               printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
-                      "%s for RX.\n",
+               printk(KERN_INFO PFX
+                      "%s: Flow control is %s for TX and %s for RX.\n",
                       tp->dev->name,
-                      (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
-                      (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+                      "on" : "off",
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+                      "on" : "off");
        }
 }
 
-static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
 {
-       u32 new_tg3_flags = 0;
-       u32 old_rx_mode = tp->rx_mode;
-       u32 old_tx_mode = tp->tx_mode;
+       u16 miireg;
 
-       if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_PAUSE_CAP;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_PAUSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+       else
+               miireg = 0;
 
-               /* Convert 1000BaseX flow control bits to 1000BaseT
-                * bits before resolving flow control.
-                */
-               if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
-                       local_adv &= ~(ADVERTISE_PAUSE_CAP |
-                                      ADVERTISE_PAUSE_ASYM);
-                       remote_adv &= ~(LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
-                       if (local_adv & ADVERTISE_1000XPAUSE)
-                               local_adv |= ADVERTISE_PAUSE_CAP;
-                       if (local_adv & ADVERTISE_1000XPSE_ASYM)
-                               local_adv |= ADVERTISE_PAUSE_ASYM;
-                       if (remote_adv & LPA_1000XPAUSE)
-                               remote_adv |= LPA_PAUSE_CAP;
-                       if (remote_adv & LPA_1000XPAUSE_ASYM)
-                               remote_adv |= LPA_PAUSE_ASYM;
-               }
-
-               if (local_adv & ADVERTISE_PAUSE_CAP) {
-                       if (local_adv & ADVERTISE_PAUSE_ASYM) {
-                               if (remote_adv & LPA_PAUSE_CAP)
-                                       new_tg3_flags |=
-                                               (TG3_FLAG_RX_PAUSE |
-                                               TG3_FLAG_TX_PAUSE);
-                               else if (remote_adv & LPA_PAUSE_ASYM)
-                                       new_tg3_flags |=
-                                               (TG3_FLAG_RX_PAUSE);
-                       } else {
-                               if (remote_adv & LPA_PAUSE_CAP)
-                                       new_tg3_flags |=
-                                               (TG3_FLAG_RX_PAUSE |
-                                               TG3_FLAG_TX_PAUSE);
-                       }
-               } else if (local_adv & ADVERTISE_PAUSE_ASYM) {
-                       if ((remote_adv & LPA_PAUSE_CAP) &&
-                       (remote_adv & LPA_PAUSE_ASYM))
-                               new_tg3_flags |= TG3_FLAG_TX_PAUSE;
+       return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+       u16 miireg;
+
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_1000XPAUSE;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_1000XPSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+       else
+               miireg = 0;
+
+       return miireg;
+}
+
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_PAUSE_CAP) {
+               if (lcladv & ADVERTISE_PAUSE_ASYM) {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_PAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
                }
+       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
 
-               tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
-               tp->tg3_flags |= new_tg3_flags;
+       return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_1000XPAUSE) {
+               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               }
+       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
+
+       return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
+{
+       u8 new_tg3_flags = 0;
+       u32 old_rx_mode = tp->rx_mode;
+       u32 old_tx_mode = tp->tx_mode;
+
+       if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+           (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+               if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+                       new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
+                                                                  remote_adv);
+               else
+                       new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
+                                                                  remote_adv);
        } else {
-               new_tg3_flags = tp->tg3_flags;
+               new_tg3_flags = tp->link_config.flowctrl;
        }
 
-       if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
+       tp->link_config.active_flowctrl = new_tg3_flags;
+
+       if (new_tg3_flags & TG3_FLOW_CTRL_RX)
                tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
        else
                tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
@@ -1672,7 +1717,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
                tw32_f(MAC_RX_MODE, tp->rx_mode);
        }
 
-       if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+       if (new_tg3_flags & TG3_FLOW_CTRL_TX)
                tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
        else
                tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
@@ -1752,7 +1797,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                                ~(ADVERTISED_1000baseT_Half |
                                  ADVERTISED_1000baseT_Full);
 
-               new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+               new_adv = ADVERTISE_CSMA;
                if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
                        new_adv |= ADVERTISE_10HALF;
                if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
@@ -1761,6 +1806,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        new_adv |= ADVERTISE_100HALF;
                if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
                        new_adv |= ADVERTISE_100FULL;
+
+               new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
                tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
                if (tp->link_config.advertising &
@@ -1780,9 +1828,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        tg3_writephy(tp, MII_TG3_CTRL, 0);
                }
        } else {
+               new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+               new_adv |= ADVERTISE_CSMA;
+
                /* Asking for a specific link mode. */
                if (tp->link_config.speed == SPEED_1000) {
-                       new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
                        tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
                        if (tp->link_config.duplex == DUPLEX_FULL)
@@ -1793,11 +1843,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                            tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
                                new_adv |= (MII_TG3_CTRL_AS_MASTER |
                                            MII_TG3_CTRL_ENABLE_AS_MASTER);
-                       tg3_writephy(tp, MII_TG3_CTRL, new_adv);
                } else {
-                       tg3_writephy(tp, MII_TG3_CTRL, 0);
-
-                       new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
                        if (tp->link_config.speed == SPEED_100) {
                                if (tp->link_config.duplex == DUPLEX_FULL)
                                        new_adv |= ADVERTISE_100FULL;
@@ -1810,7 +1856,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                                        new_adv |= ADVERTISE_10HALF;
                        }
                        tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+                       new_adv = 0;
                }
+
+               tg3_writephy(tp, MII_TG3_CTRL, new_adv);
        }
 
        if (tp->link_config.autoneg == AUTONEG_DISABLE &&
@@ -1926,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
        return 1;
 }
 
+static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
+{
+       u32 curadv, reqadv;
+
+       if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
+               return 1;
+
+       curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+       reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
+       if (tp->link_config.active_duplex == DUPLEX_FULL) {
+               if (curadv != reqadv)
+                       return 0;
+
+               if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
+                       tg3_readphy(tp, MII_LPA, rmtadv);
+       } else {
+               /* Reprogram the advertisement register, even if it
+                * does not affect the current link.  If the link
+                * gets renegotiated in the future, we can save an
+                * additional renegotiation cycle by advertising
+                * it correctly in the first place.
+                */
+               if (curadv != reqadv) {
+                       *lcladv &= ~(ADVERTISE_PAUSE_CAP |
+                                    ADVERTISE_PAUSE_ASYM);
+                       tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
+               }
+       }
+
+       return 1;
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 {
        int current_link_up;
        u32 bmsr, dummy;
+       u32 lcl_adv, rmt_adv;
        u16 current_speed;
        u8 current_duplex;
        int i, err;
@@ -2072,56 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
                        udelay(10);
                }
 
-               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-                       if (bmcr & BMCR_ANENABLE) {
-                               current_link_up = 1;
+               lcl_adv = 0;
+               rmt_adv = 0;
 
-                               /* Force autoneg restart if we are exiting
-                                * low power mode.
-                                */
-                               if (!tg3_copper_is_advertising_all(tp,
-                                               tp->link_config.advertising))
-                                       current_link_up = 0;
-                       } else {
-                               current_link_up = 0;
+               tp->link_config.active_speed = current_speed;
+               tp->link_config.active_duplex = current_duplex;
+
+               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+                       if ((bmcr & BMCR_ANENABLE) &&
+                           tg3_copper_is_advertising_all(tp,
+                                               tp->link_config.advertising)) {
+                               if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
+                                                                 &rmt_adv))
+                                       current_link_up = 1;
                        }
                } else {
                        if (!(bmcr & BMCR_ANENABLE) &&
                            tp->link_config.speed == current_speed &&
-                           tp->link_config.duplex == current_duplex) {
+                           tp->link_config.duplex == current_duplex &&
+                           tp->link_config.flowctrl ==
+                           tp->link_config.active_flowctrl) {
                                current_link_up = 1;
-                       } else {
-                               current_link_up = 0;
                        }
                }
 
-               tp->link_config.active_speed = current_speed;
-               tp->link_config.active_duplex = current_duplex;
+               if (current_link_up == 1 &&
+                   tp->link_config.active_duplex == DUPLEX_FULL)
+                       tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
        }
 
-       if (current_link_up == 1 &&
-           (tp->link_config.active_duplex == DUPLEX_FULL) &&
-           (tp->link_config.autoneg == AUTONEG_ENABLE)) {
-               u32 local_adv, remote_adv;
-
-               if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
-                       local_adv = 0;
-               local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
-
-               if (tg3_readphy(tp, MII_LPA, &remote_adv))
-                       remote_adv = 0;
-
-               remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
-               /* If we are not advertising full pause capability,
-                * something is wrong.  Bring the link down and reconfigure.
-                */
-               if (local_adv != ADVERTISE_PAUSE_CAP) {
-                       current_link_up = 0;
-               } else {
-                       tg3_setup_flow_control(tp, local_adv, remote_adv);
-               }
-       }
 relink:
        if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
                u32 tmp;
@@ -2270,6 +2333,7 @@ struct tg3_fiber_aneginfo {
 static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                                   struct tg3_fiber_aneginfo *ap)
 {
+       u16 flowctrl;
        unsigned long delta;
        u32 rx_cfg_reg;
        int ret;
@@ -2369,7 +2433,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 
        case ANEG_STATE_ABILITY_DETECT_INIT:
                ap->flags &= ~(MR_TOGGLE_TX);
-               ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+               ap->txconfig = ANEG_CFG_FD;
+               flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               if (flowctrl & ADVERTISE_1000XPAUSE)
+                       ap->txconfig |= ANEG_CFG_PS1;
+               if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+                       ap->txconfig |= ANEG_CFG_PS2;
                tw32(MAC_TX_AUTO_NEG, ap->txconfig);
                tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
                tw32_f(MAC_MODE, tp->mac_mode);
@@ -2515,7 +2584,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
        return ret;
 }
 
-static int fiber_autoneg(struct tg3 *tp, u32 *flags)
+static int fiber_autoneg(struct tg3 *tp, u32 *txflags, u32 *rxflags)
 {
        int res = 0;
        struct tg3_fiber_aneginfo aninfo;
@@ -2549,7 +2618,8 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags)
        tw32_f(MAC_MODE, tp->mac_mode);
        udelay(40);
 
-       *flags = aninfo.flags;
+       *txflags = aninfo.txconfig;
+       *rxflags = aninfo.flags;
 
        if (status == ANEG_DONE &&
            (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
@@ -2611,6 +2681,7 @@ static void tg3_init_bcm8002(struct tg3 *tp)
 
 static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 {
+       u16 flowctrl;
        u32 sg_dig_ctrl, sg_dig_status;
        u32 serdes_cfg, expected_sg_dig_ctrl;
        int workaround, port_a;
@@ -2636,7 +2707,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
        sg_dig_ctrl = tr32(SG_DIG_CTRL);
 
        if (tp->link_config.autoneg != AUTONEG_ENABLE) {
-               if (sg_dig_ctrl & (1 << 31)) {
+               if (sg_dig_ctrl & SG_DIG_USING_HW_AUTONEG) {
                        if (workaround) {
                                u32 val = serdes_cfg;
 
@@ -2646,7 +2717,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
                                        val |= 0x4010000;
                                tw32_f(MAC_SERDES_CFG, val);
                        }
-                       tw32_f(SG_DIG_CTRL, 0x01388400);
+
+                       tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
                }
                if (mac_status & MAC_STATUS_PCS_SYNCED) {
                        tg3_setup_flow_control(tp, 0, 0);
@@ -2656,13 +2728,13 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
        }
 
        /* Want auto-negotiation.  */
-       expected_sg_dig_ctrl = 0x81388400;
+       expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP;
 
-       /* Pause capability */
-       expected_sg_dig_ctrl |= (1 << 11);
-
-       /* Asymettric pause */
-       expected_sg_dig_ctrl |= (1 << 12);
+       flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+       if (flowctrl & ADVERTISE_1000XPAUSE)
+               expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
+       if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+               expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
 
        if (sg_dig_ctrl != expected_sg_dig_ctrl) {
                if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
@@ -2677,7 +2749,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 restart_autoneg:
                if (workaround)
                        tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
-               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | SG_DIG_SOFT_RESET);
                udelay(5);
                tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
@@ -2688,22 +2760,25 @@ restart_autoneg:
                sg_dig_status = tr32(SG_DIG_STATUS);
                mac_status = tr32(MAC_STATUS);
 
-               if ((sg_dig_status & (1 << 1)) &&
+               if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) &&
                    (mac_status & MAC_STATUS_PCS_SYNCED)) {
-                       u32 local_adv, remote_adv;
+                       u32 local_adv = 0, remote_adv = 0;
+
+                       if (sg_dig_ctrl & SG_DIG_PAUSE_CAP)
+                               local_adv |= ADVERTISE_1000XPAUSE;
+                       if (sg_dig_ctrl & SG_DIG_ASYM_PAUSE)
+                               local_adv |= ADVERTISE_1000XPSE_ASYM;
 
-                       local_adv = ADVERTISE_PAUSE_CAP;
-                       remote_adv = 0;
-                       if (sg_dig_status & (1 << 19))
-                               remote_adv |= LPA_PAUSE_CAP;
-                       if (sg_dig_status & (1 << 20))
-                               remote_adv |= LPA_PAUSE_ASYM;
+                       if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
+                               remote_adv |= LPA_1000XPAUSE;
+                       if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE_ASYM;
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
                        current_link_up = 1;
                        tp->serdes_counter = 0;
                        tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
-               } else if (!(sg_dig_status & (1 << 1))) {
+               } else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
                        if (tp->serdes_counter)
                                tp->serdes_counter--;
                        else {
@@ -2718,7 +2793,7 @@ restart_autoneg:
                                        tw32_f(MAC_SERDES_CFG, val);
                                }
 
-                               tw32_f(SG_DIG_CTRL, 0x01388400);
+                               tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
                                udelay(40);
 
                                /* Link parallel detection - link is up */
@@ -2754,18 +2829,21 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
                goto out;
 
        if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-               u32 flags;
+               u32 txflags, rxflags;
                int i;
 
-               if (fiber_autoneg(tp, &flags)) {
-                       u32 local_adv, remote_adv;
+               if (fiber_autoneg(tp, &txflags, &rxflags)) {
+                       u32 local_adv = 0, remote_adv = 0;
+
+                       if (txflags & ANEG_CFG_PS1)
+                               local_adv |= ADVERTISE_1000XPAUSE;
+                       if (txflags & ANEG_CFG_PS2)
+                               local_adv |= ADVERTISE_1000XPSE_ASYM;
 
-                       local_adv = ADVERTISE_PAUSE_CAP;
-                       remote_adv = 0;
-                       if (flags & MR_LP_ADV_SYM_PAUSE)
-                               remote_adv |= LPA_PAUSE_CAP;
-                       if (flags & MR_LP_ADV_ASYM_PAUSE)
-                               remote_adv |= LPA_PAUSE_ASYM;
+                       if (rxflags & MR_LP_ADV_SYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE;
+                       if (rxflags & MR_LP_ADV_ASYM_PAUSE)
+                               remote_adv |= LPA_1000XPAUSE_ASYM;
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
 
@@ -2789,6 +2867,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
                    !(mac_status & MAC_STATUS_RCVD_CFG))
                        current_link_up = 1;
        } else {
+               tg3_setup_flow_control(tp, 0, 0);
+
                /* Forcing 1000FD link up. */
                current_link_up = 1;
 
@@ -2812,9 +2892,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
        int current_link_up;
        int i;
 
-       orig_pause_cfg =
-               (tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-                                 TG3_FLAG_TX_PAUSE));
+       orig_pause_cfg = tp->link_config.active_flowctrl;
        orig_active_speed = tp->link_config.active_speed;
        orig_active_duplex = tp->link_config.active_duplex;
 
@@ -2903,9 +2981,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                        netif_carrier_off(tp->dev);
                tg3_link_report(tp);
        } else {
-               u32 now_pause_cfg =
-                       tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-                                        TG3_FLAG_TX_PAUSE);
+               u32 now_pause_cfg = tp->link_config.active_flowctrl;
                if (orig_pause_cfg != now_pause_cfg ||
                    orig_active_speed != tp->link_config.active_speed ||
                    orig_active_duplex != tp->link_config.active_duplex)
@@ -2921,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
        u32 bmsr, bmcr;
        u16 current_speed;
        u8 current_duplex;
+       u32 local_adv, remote_adv;
 
        tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
        tw32_f(MAC_MODE, tp->mac_mode);
@@ -2954,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
        err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
        if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
-           (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+           (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+            tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
                /* do nothing, just check for link up at the end */
        } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
                u32 adv, new_adv;
@@ -2965,8 +3043,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                  ADVERTISE_1000XPSE_ASYM |
                                  ADVERTISE_SLCT);
 
-               /* Always advertise symmetric PAUSE just like copper */
-               new_adv |= ADVERTISE_1000XPAUSE;
+               new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
 
                if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
                        new_adv |= ADVERTISE_1000XHALF;
@@ -3037,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                else
                        current_duplex = DUPLEX_HALF;
 
+               local_adv = 0;
+               remote_adv = 0;
+
                if (bmcr & BMCR_ANENABLE) {
-                       u32 local_adv, remote_adv, common;
+                       u32 common;
 
                        err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
                        err |= tg3_readphy(tp, MII_LPA, &remote_adv);
@@ -3049,15 +3129,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                        current_duplex = DUPLEX_FULL;
                                else
                                        current_duplex = DUPLEX_HALF;
-
-                               tg3_setup_flow_control(tp, local_adv,
-                                                      remote_adv);
                        }
                        else
                                current_link_up = 0;
                }
        }
 
+       if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+               tg3_setup_flow_control(tp, local_adv, remote_adv);
+
        tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
        if (tp->link_config.active_duplex == DUPLEX_HALF)
                tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
@@ -8189,6 +8269,7 @@ static int tg3_get_eeprom_len(struct net_device *dev)
 }
 
 static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
+static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val);
 static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val);
 
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
@@ -8196,7 +8277,8 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct tg3 *tp = netdev_priv(dev);
        int ret;
        u8  *pd;
-       u32 i, offset, len, val, b_offset, b_count;
+       u32 i, offset, len, b_offset, b_count;
+       __le32 val;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8215,10 +8297,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        /* i.e. offset=1 len=2 */
                        b_count = len;
                }
-               ret = tg3_nvram_read(tp, offset-b_offset, &val);
+               ret = tg3_nvram_read_le(tp, offset-b_offset, &val);
                if (ret)
                        return ret;
-               val = cpu_to_le32(val);
                memcpy(data, ((char*)&val) + b_offset, b_count);
                len -= b_count;
                offset += b_count;
@@ -8228,12 +8309,11 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        /* read bytes upto the last 4 byte boundary */
        pd = &data[eeprom->len];
        for (i = 0; i < (len - (len & 3)); i += 4) {
-               ret = tg3_nvram_read(tp, offset + i, &val);
+               ret = tg3_nvram_read_le(tp, offset + i, &val);
                if (ret) {
                        eeprom->len += i;
                        return ret;
                }
-               val = cpu_to_le32(val);
                memcpy(pd + i, &val, 4);
        }
        eeprom->len += i;
@@ -8243,11 +8323,10 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                pd = &data[eeprom->len];
                b_count = len & 3;
                b_offset = offset + len - b_count;
-               ret = tg3_nvram_read(tp, b_offset, &val);
+               ret = tg3_nvram_read_le(tp, b_offset, &val);
                if (ret)
                        return ret;
-               val = cpu_to_le32(val);
-               memcpy(pd, ((char*)&val), b_count);
+               memcpy(pd, &val, b_count);
                eeprom->len += b_count;
        }
        return 0;
@@ -8259,8 +8338,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
        struct tg3 *tp = netdev_priv(dev);
        int ret;
-       u32 offset, len, b_offset, odd_len, start, end;
+       u32 offset, len, b_offset, odd_len;
        u8 *buf;
+       __le32 start, end;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8273,10 +8353,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        if ((b_offset = (offset & 3))) {
                /* adjustments to start on required 4 byte boundary */
-               ret = tg3_nvram_read(tp, offset-b_offset, &start);
+               ret = tg3_nvram_read_le(tp, offset-b_offset, &start);
                if (ret)
                        return ret;
-               start = cpu_to_le32(start);
                len += b_offset;
                offset &= ~3;
                if (len < 4)
@@ -8288,10 +8367,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                /* adjustments to end on required 4 byte boundary */
                odd_len = 1;
                len = (len + 3) & ~3;
-               ret = tg3_nvram_read(tp, offset+len-4, &end);
+               ret = tg3_nvram_read_le(tp, offset+len-4, &end);
                if (ret)
                        return ret;
-               end = cpu_to_le32(end);
        }
 
        buf = data;
@@ -8571,8 +8649,16 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
        struct tg3 *tp = netdev_priv(dev);
 
        epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
-       epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
-       epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
+
+       if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX)
+               epause->rx_pause = 1;
+       else
+               epause->rx_pause = 0;
+
+       if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX)
+               epause->tx_pause = 1;
+       else
+               epause->tx_pause = 0;
 }
 
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8592,13 +8678,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
        else
                tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
        if (epause->rx_pause)
-               tp->tg3_flags |= TG3_FLAG_RX_PAUSE;
+               tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
        else
-               tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE;
+               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
        if (epause->tx_pause)
-               tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
+               tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
        else
-               tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
+               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -8695,7 +8781,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data)
                return -EAGAIN;
 
        if (data == 0)
-               data = 2;
+               data = UINT_MAX / 2;
 
        for (i = 0; i < (data * 2); i++) {
                if ((i % 2) == 0)
@@ -8734,7 +8820,8 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 
 static int tg3_test_nvram(struct tg3 *tp)
 {
-       u32 *buf, csum, magic;
+       u32 csum, magic;
+       __le32 *buf;
        int i, j, k, err = 0, size;
 
        if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
@@ -8771,21 +8858,19 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        err = -EIO;
        for (i = 0, j = 0; i < size; i += 4, j++) {
-               u32 val;
-
-               if ((err = tg3_nvram_read(tp, i, &val)) != 0)
+               if ((err = tg3_nvram_read_le(tp, i, &buf[j])) != 0)
                        break;
-               buf[j] = cpu_to_le32(val);
        }
        if (i < size)
                goto out;
 
        /* Selfboot format */
-       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
+       magic = swab32(le32_to_cpu(buf[0]));
+       if ((magic & TG3_EEPROM_MAGIC_FW_MSK) ==
            TG3_EEPROM_MAGIC_FW) {
                u8 *buf8 = (u8 *) buf, csum8 = 0;
 
-               if ((cpu_to_be32(buf[0]) & TG3_EEPROM_SB_REVISION_MASK) ==
+               if ((magic & TG3_EEPROM_SB_REVISION_MASK) ==
                    TG3_EEPROM_SB_REVISION_2) {
                        /* For rev 2, the csum doesn't include the MBA. */
                        for (i = 0; i < TG3_EEPROM_SB_F1R2_MBA_OFF; i++)
@@ -8806,7 +8891,7 @@ static int tg3_test_nvram(struct tg3 *tp)
                goto out;
        }
 
-       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
+       if ((magic & TG3_EEPROM_MAGIC_HW_MSK) ==
            TG3_EEPROM_MAGIC_HW) {
                u8 data[NVRAM_SELFBOOT_DATA_SIZE];
                u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
@@ -8852,12 +8937,12 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
-       if(csum != cpu_to_le32(buf[0x10/4]))
+       if(csum != le32_to_cpu(buf[0x10/4]))
                goto out;
 
        /* Manufacturing block starts at offset 0x74, checksum at 0xfc */
        csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
-       if (csum != cpu_to_le32(buf[0xfc/4]))
+       if (csum != le32_to_cpu(buf[0xfc/4]))
                 goto out;
 
        err = 0;
@@ -10171,6 +10256,15 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        return ret;
 }
 
+static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val)
+{
+       u32 v;
+       int res = tg3_nvram_read(tp, offset, &v);
+       if (!res)
+               *val = cpu_to_le32(v);
+       return res;
+}
+
 static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val)
 {
        int err;
@@ -10188,13 +10282,14 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
        u32 val;
 
        for (i = 0; i < len; i += 4) {
-               u32 addr, data;
+               u32 addr;
+               __le32 data;
 
                addr = offset + i;
 
                memcpy(&data, buf + i, 4);
 
-               tw32(GRC_EEPROM_DATA, cpu_to_le32(data));
+               tw32(GRC_EEPROM_DATA, le32_to_cpu(data));
 
                val = tr32(GRC_EEPROM_ADDR);
                tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
@@ -10244,8 +10339,8 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                phy_addr = offset & ~pagemask;
 
                for (j = 0; j < pagesize; j += 4) {
-                       if ((ret = tg3_nvram_read(tp, phy_addr + j,
-                                               (u32 *) (tmp + j))))
+                       if ((ret = tg3_nvram_read_le(tp, phy_addr + j,
+                                               (__le32 *) (tmp + j))))
                                break;
                }
                if (ret)
@@ -10289,10 +10384,11 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                        break;
 
                for (j = 0; j < pagesize; j += 4) {
-                       u32 data;
+                       __be32 data;
 
-                       data = *((u32 *) (tmp + j));
-                       tw32(NVRAM_WRDATA, cpu_to_be32(data));
+                       data = *((__be32 *) (tmp + j));
+                       /* swab32(le32_to_cpu(data)), actually */
+                       tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                        tw32(NVRAM_ADDR, phy_addr + j);
 
@@ -10326,10 +10422,11 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
        int i, ret = 0;
 
        for (i = 0; i < len; i += 4, offset += 4) {
-               u32 data, page_off, phy_addr, nvram_cmd;
+               u32 page_off, phy_addr, nvram_cmd;
+               __be32 data;
 
                memcpy(&data, buf + i, 4);
-               tw32(NVRAM_WRDATA, cpu_to_be32(data));
+               tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                page_off = offset % tp->nvram_pagesize;
 
@@ -10831,6 +10928,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                vpd_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_VPD);
                for (i = 0; i < 256; i += 4) {
                        u32 tmp, j = 0;
+                       __le32 v;
                        u16 tmp16;
 
                        pci_write_config_word(tp->pdev, vpd_cap + PCI_VPD_ADDR,
@@ -10847,8 +10945,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
 
                        pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
                                              &tmp);
-                       tmp = cpu_to_le32(tmp);
-                       memcpy(&vpd_data[i], &tmp, 4);
+                       v = cpu_to_le32(tmp);
+                       memcpy(&vpd_data[i], &v, 4);
                }
        }
 
@@ -10941,11 +11039,11 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 
        offset = offset + ver_offset - start;
        for (i = 0; i < 16; i += 4) {
-               if (tg3_nvram_read(tp, offset + i, &val))
+               __le32 v;
+               if (tg3_nvram_read_le(tp, offset + i, &v))
                        return;
 
-               val = le32_to_cpu(val);
-               memcpy(tp->fw_ver + i, &val, 4);
+               memcpy(tp->fw_ver + i, &v, 4);
        }
 
        if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
@@ -10983,19 +11081,19 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
        tp->fw_ver[bcnt++] = ' ';
 
        for (i = 0; i < 4; i++) {
-               if (tg3_nvram_read(tp, offset, &val))
+               __le32 v;
+               if (tg3_nvram_read_le(tp, offset, &v))
                        return;
 
-               val = le32_to_cpu(val);
-               offset += sizeof(val);
+               offset += sizeof(v);
 
-               if (bcnt > TG3_VER_SIZE - sizeof(val)) {
-                       memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
+               if (bcnt > TG3_VER_SIZE - sizeof(v)) {
+                       memcpy(&tp->fw_ver[bcnt], &v, TG3_VER_SIZE - bcnt);
                        break;
                }
 
-               memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
-               bcnt += sizeof(val);
+               memcpy(&tp->fw_ver[bcnt], &v, sizeof(v));
+               bcnt += sizeof(v);
        }
 
        tp->fw_ver[TG3_VER_SIZE - 1] = 0;
@@ -11743,7 +11841,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
        }
 
        if (!is_valid_ether_addr(&dev->dev_addr[0])) {
-#ifdef CONFIG_SPARC64
+#ifdef CONFIG_SPARC
                if (!tg3_get_default_macaddr_sparc(tp))
                        return 0;
 #endif
@@ -12351,9 +12449,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        unsigned long tg3reg_base, tg3reg_len;
        struct net_device *dev;
        struct tg3 *tp;
-       int i, err, pm_cap;
+       int err, pm_cap;
        char str[40];
        u64 dma_mask, persist_dma_mask;
+       DECLARE_MAC_BUF(mac);
 
        if (tg3_version_printed++ == 0)
                printk(KERN_INFO "%s", version);
@@ -12576,7 +12675,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                tg3reg_len = pci_resource_len(pdev, 2);
 
                tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
-               if (tp->aperegs == 0UL) {
+               if (!tp->aperegs) {
                        printk(KERN_ERR PFX "Cannot map APE registers, "
                               "aborting.\n");
                        err = -ENOMEM;
@@ -12620,6 +12719,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        /* flow control autonegotiation is default behavior */
        tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+       tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
 
        tg3_init_coal(tp);
 
@@ -12632,7 +12732,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                goto err_out_apeunmap;
        }
 
-       printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
+       printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] "
+              "(%s) %s Ethernet %s\n",
               dev->name,
               tp->board_part_number,
               tp->pci_chip_rev_id,
@@ -12640,11 +12741,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
               tg3_bus_string(tp, str),
               ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
                ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
-                "10/100/1000Base-T")));
-
-       for (i = 0; i < 6; i++)
-               printk("%2.2x%c", dev->dev_addr[i],
-                      i == 5 ? '\n' : ':');
+                "10/100/1000Base-T")),
+              print_mac(mac, dev->dev_addr));
 
        printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
               "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n",