]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/tg3.c
[PATCH] IB: Add handling for ABORT and STOP RMPP MADs.
[linux-2.6-omap-h63xx.git] / drivers / net / tg3.c
index 04d8b18e2912af41a6896e2addd4539b0b239e35..6d4ab1e333b55a6579baa4362501a873f86899c2 100644 (file)
@@ -66,8 +66,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.33"
-#define DRV_MODULE_RELDATE     "July 5, 2005"
+#define DRV_MODULE_VERSION     "3.37"
+#define DRV_MODULE_RELDATE     "August 25, 2005"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -1100,7 +1100,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
                tp->link_config.orig_autoneg = tp->link_config.autoneg;
        }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
                tp->link_config.speed = SPEED_10;
                tp->link_config.duplex = DUPLEX_HALF;
                tp->link_config.autoneg = AUTONEG_ENABLE;
@@ -1247,6 +1247,25 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
        u32 old_tx_mode = tp->tx_mode;
 
        if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+
+               /* 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)
@@ -2507,12 +2526,226 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
        return 0;
 }
 
+static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
+{
+       int current_link_up, err = 0;
+       u32 bmsr, bmcr;
+       u16 current_speed;
+       u8 current_duplex;
+
+       tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+       tw32_f(MAC_MODE, tp->mac_mode);
+       udelay(40);
+
+       tw32(MAC_EVENT, 0);
+
+       tw32_f(MAC_STATUS,
+            (MAC_STATUS_SYNC_CHANGED |
+             MAC_STATUS_CFG_CHANGED |
+             MAC_STATUS_MI_COMPLETION |
+             MAC_STATUS_LNKSTATE_CHANGED));
+       udelay(40);
+
+       if (force_reset)
+               tg3_phy_reset(tp);
+
+       current_link_up = 0;
+       current_speed = SPEED_INVALID;
+       current_duplex = DUPLEX_INVALID;
+
+       err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+       err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+
+       err |= tg3_readphy(tp, MII_BMCR, &bmcr);
+
+       if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
+           (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+               /* do nothing, just check for link up at the end */
+       } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+               u32 adv, new_adv;
+
+               err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
+               new_adv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
+                                 ADVERTISE_1000XPAUSE |
+                                 ADVERTISE_1000XPSE_ASYM |
+                                 ADVERTISE_SLCT);
+
+               /* Always advertise symmetric PAUSE just like copper */
+               new_adv |= ADVERTISE_1000XPAUSE;
+
+               if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
+                       new_adv |= ADVERTISE_1000XHALF;
+               if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
+                       new_adv |= ADVERTISE_1000XFULL;
+
+               if ((new_adv != adv) || !(bmcr & BMCR_ANENABLE)) {
+                       tg3_writephy(tp, MII_ADVERTISE, new_adv);
+                       bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
+                       tg3_writephy(tp, MII_BMCR, bmcr);
+
+                       tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+                       tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+                       tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+
+                       return err;
+               }
+       } else {
+               u32 new_bmcr;
+
+               bmcr &= ~BMCR_SPEED1000;
+               new_bmcr = bmcr & ~(BMCR_ANENABLE | BMCR_FULLDPLX);
+
+               if (tp->link_config.duplex == DUPLEX_FULL)
+                       new_bmcr |= BMCR_FULLDPLX;
+
+               if (new_bmcr != bmcr) {
+                       /* BMCR_SPEED1000 is a reserved bit that needs
+                        * to be set on write.
+                        */
+                       new_bmcr |= BMCR_SPEED1000;
+
+                       /* Force a linkdown */
+                       if (netif_carrier_ok(tp->dev)) {
+                               u32 adv;
+
+                               err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
+                               adv &= ~(ADVERTISE_1000XFULL |
+                                        ADVERTISE_1000XHALF |
+                                        ADVERTISE_SLCT);
+                               tg3_writephy(tp, MII_ADVERTISE, adv);
+                               tg3_writephy(tp, MII_BMCR, bmcr |
+                                                          BMCR_ANRESTART |
+                                                          BMCR_ANENABLE);
+                               udelay(10);
+                               netif_carrier_off(tp->dev);
+                       }
+                       tg3_writephy(tp, MII_BMCR, new_bmcr);
+                       bmcr = new_bmcr;
+                       err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+                       err |= tg3_readphy(tp, MII_BMSR, &bmsr);
+                       tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+               }
+       }
+
+       if (bmsr & BMSR_LSTATUS) {
+               current_speed = SPEED_1000;
+               current_link_up = 1;
+               if (bmcr & BMCR_FULLDPLX)
+                       current_duplex = DUPLEX_FULL;
+               else
+                       current_duplex = DUPLEX_HALF;
+
+               if (bmcr & BMCR_ANENABLE) {
+                       u32 local_adv, remote_adv, common;
+
+                       err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
+                       err |= tg3_readphy(tp, MII_LPA, &remote_adv);
+                       common = local_adv & remote_adv;
+                       if (common & (ADVERTISE_1000XHALF |
+                                     ADVERTISE_1000XFULL)) {
+                               if (common & ADVERTISE_1000XFULL)
+                                       current_duplex = DUPLEX_FULL;
+                               else
+                                       current_duplex = DUPLEX_HALF;
+
+                               tg3_setup_flow_control(tp, local_adv,
+                                                      remote_adv);
+                       }
+                       else
+                               current_link_up = 0;
+               }
+       }
+
+       tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
+       if (tp->link_config.active_duplex == DUPLEX_HALF)
+               tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
+
+       tw32_f(MAC_MODE, tp->mac_mode);
+       udelay(40);
+
+       tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+
+       tp->link_config.active_speed = current_speed;
+       tp->link_config.active_duplex = current_duplex;
+
+       if (current_link_up != netif_carrier_ok(tp->dev)) {
+               if (current_link_up)
+                       netif_carrier_on(tp->dev);
+               else {
+                       netif_carrier_off(tp->dev);
+                       tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+               }
+               tg3_link_report(tp);
+       }
+       return err;
+}
+
+static void tg3_serdes_parallel_detect(struct tg3 *tp)
+{
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) {
+               /* Give autoneg time to complete. */
+               tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+               return;
+       }
+       if (!netif_carrier_ok(tp->dev) &&
+           (tp->link_config.autoneg == AUTONEG_ENABLE)) {
+               u32 bmcr;
+
+               tg3_readphy(tp, MII_BMCR, &bmcr);
+               if (bmcr & BMCR_ANENABLE) {
+                       u32 phy1, phy2;
+
+                       /* Select shadow register 0x1f */
+                       tg3_writephy(tp, 0x1c, 0x7c00);
+                       tg3_readphy(tp, 0x1c, &phy1);
+
+                       /* Select expansion interrupt status register */
+                       tg3_writephy(tp, 0x17, 0x0f01);
+                       tg3_readphy(tp, 0x15, &phy2);
+                       tg3_readphy(tp, 0x15, &phy2);
+
+                       if ((phy1 & 0x10) && !(phy2 & 0x20)) {
+                               /* We have signal detect and not receiving
+                                * config code words, link is up by parallel
+                                * detection.
+                                */
+
+                               bmcr &= ~BMCR_ANENABLE;
+                               bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
+                               tg3_writephy(tp, MII_BMCR, bmcr);
+                               tp->tg3_flags2 |= TG3_FLG2_PARALLEL_DETECT;
+                       }
+               }
+       }
+       else if (netif_carrier_ok(tp->dev) &&
+                (tp->link_config.autoneg == AUTONEG_ENABLE) &&
+                (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+               u32 phy2;
+
+               /* Select expansion interrupt status register */
+               tg3_writephy(tp, 0x17, 0x0f01);
+               tg3_readphy(tp, 0x15, &phy2);
+               if (phy2 & 0x20) {
+                       u32 bmcr;
+
+                       /* Config code words received, turn on autoneg. */
+                       tg3_readphy(tp, MII_BMCR, &bmcr);
+                       tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANENABLE);
+
+                       tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
+
+               }
+       }
+}
+
 static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 {
        int err;
 
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                err = tg3_setup_fiber_phy(tp, force_reset);
+       } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+               err = tg3_setup_fiber_mii_phy(tp, force_reset);
        } else {
                err = tg3_setup_copper_phy(tp, force_reset);
        }
@@ -4127,6 +4360,9 @@ static int tg3_chip_reset(struct tg3 *tp)
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
                tw32_f(MAC_MODE, tp->mac_mode);
+       } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+               tp->mac_mode = MAC_MODE_PORT_MODE_GMII;
+               tw32_f(MAC_MODE, tp->mac_mode);
        } else
                tw32_f(MAC_MODE, 0);
        udelay(40);
@@ -5911,7 +6147,8 @@ static void tg3_timer(unsigned long __opaque)
                                udelay(40);
                                tg3_setup_phy(tp, 0);
                        }
-               }
+               } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+                       tg3_serdes_parallel_detect(tp);
 
                tp->timer_counter = tp->timer_multiplier;
        }
@@ -7628,8 +7865,6 @@ static int tg3_test_loopback(struct tg3 *tp)
 
        err = -EIO;
 
-       tg3_abort_hw(tp, 1);
-
        tg3_reset_hw(tp);
 
        mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
@@ -8615,8 +8850,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        eeprom_phy_id = 0;
 
                tp->phy_id = eeprom_phy_id;
-               if (eeprom_phy_serdes)
-                       tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+               if (eeprom_phy_serdes) {
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
+                               tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
+                       else
+                               tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+               }
 
                if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
                        led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
@@ -8729,6 +8968,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                tp->phy_id = hw_phy_id;
                if (hw_phy_id_masked == PHY_ID_BCM8002)
                        tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+               else
+                       tp->tg3_flags2 &= ~TG3_FLG2_PHY_SERDES;
        } else {
                if (tp->phy_id != PHY_ID_INVALID) {
                        /* Do nothing, phy ID already set up in
@@ -8751,7 +8992,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                }
        }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+       if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
            !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
                u32 bmsr, adv_reg, tg3_ctrl;
 
@@ -8804,7 +9045,7 @@ skip_phy_reset:
                err = tg3_init_5401phy_dsp(tp);
        }
 
-       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+       if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
                tp->link_config.advertising =
                        (ADVERTISED_1000baseT_Half |
                         ADVERTISED_1000baseT_Full |
@@ -9153,7 +9394,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
            ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
             (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
-            (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)))
+            (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+           (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
                tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
 
        if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
@@ -10179,6 +10421,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_coal(tp);
 
+       /* Now that we have fully setup the chip, save away a snapshot
+        * of the PCI config space.  We need to restore this after
+        * GRC_MISC_CFG core clock resets and some resume events.
+        */
+       pci_save_state(tp->pdev);
+
        err = register_netdev(dev);
        if (err) {
                printk(KERN_ERR PFX "Cannot register net device, "
@@ -10188,12 +10436,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        pci_set_drvdata(pdev, dev);
 
-       /* Now that we have fully setup the chip, save away a snapshot
-        * of the PCI config space.  We need to restore this after
-        * GRC_MISC_CFG core clock resets and some resume events.
-        */
-       pci_save_state(tp->pdev);
-
        printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ",
               dev->name,
               tp->board_part_number,