|
@@ -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;
|
|
|
}
|
|
@@ -8615,8 +8852,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 |
|
|
@@ -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 ||
|