]> err.no Git - linux-2.6/blobdiff - drivers/net/bnx2x_link.c
bnx2x: Pause settings
[linux-2.6] / drivers / net / bnx2x_link.c
index ff2743db10d9ef69081a0d96762fcefe96d2de51..36fa356c74fab3a52c8a09af3fdb78efe1394f31 100644 (file)
@@ -38,7 +38,6 @@
 #define ETH_MAX_JUMBO_PACKET_SIZE      9600
 #define MDIO_ACCESS_TIMEOUT            1000
 #define BMAC_CONTROL_RX_ENABLE 2
-#define MAX_MTU_SIZE           5000
 
 /***********************************************************/
 /*                       Shortcut definitions              */
@@ -298,11 +297,13 @@ static u8 bnx2x_emac_enable(struct link_params *params,
                                    EMAC_RX_MODE_FLOW_EN);
 
                bnx2x_bits_dis(bp,  emac_base + EMAC_REG_EMAC_TX_MODE,
-                              EMAC_TX_MODE_EXT_PAUSE_EN);
+                            (EMAC_TX_MODE_EXT_PAUSE_EN |
+                             EMAC_TX_MODE_FLOW_EN));
                if (vars->flow_ctrl & FLOW_CTRL_TX)
                        bnx2x_bits_en(bp, emac_base +
                                    EMAC_REG_EMAC_TX_MODE,
-                                     EMAC_TX_MODE_EXT_PAUSE_EN);
+                                  (EMAC_TX_MODE_EXT_PAUSE_EN |
+                                   EMAC_TX_MODE_FLOW_EN));
        }
 
        /* KEEP_VLAN_TAG, promiscuous */
@@ -591,9 +592,9 @@ void bnx2x_link_status_update(struct link_params *params,
                        vars->flow_ctrl &= ~FLOW_CTRL_RX;
 
                if (vars->phy_flags & PHY_XGXS_FLAG) {
-                       if (params->req_line_speed &&
-                           ((params->req_line_speed == SPEED_10) ||
-                            (params->req_line_speed == SPEED_100))) {
+                       if (vars->line_speed &&
+                           ((vars->line_speed == SPEED_10) ||
+                            (vars->line_speed == SPEED_100))) {
                                vars->phy_flags |= PHY_SGMII_FLAG;
                        } else {
                                vars->phy_flags &= ~PHY_SGMII_FLAG;
@@ -670,7 +671,6 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
        u8 port = params->port;
        u32 init_crd, crd;
        u32 count = 1000;
-       u32 pause = 0;
 
        /* disable port */
        REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
@@ -693,33 +693,25 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
                return -EINVAL;
        }
 
-       if (flow_ctrl & FLOW_CTRL_RX)
-               pause = 1;
-       REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause);
-       if (pause) {
+       if (flow_ctrl & FLOW_CTRL_RX ||
+           line_speed == SPEED_10 ||
+           line_speed == SPEED_100 ||
+           line_speed == SPEED_1000 ||
+           line_speed == SPEED_2500) {
+               REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1);
                /* update threshold */
                REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
                /* update init credit */
-               init_crd = 778;         /* (800-18-4) */
+               init_crd = 778;         /* (800-18-4) */
 
        } else {
                u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE +
                              ETH_OVREHEAD)/16;
-
+               REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0);
                /* update threshold */
                REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
                /* update init credit */
                switch (line_speed) {
-               case SPEED_10:
-               case SPEED_100:
-               case SPEED_1000:
-                       init_crd = thresh + 55 - 22;
-                       break;
-
-               case SPEED_2500:
-                       init_crd = thresh + 138 - 22;
-                       break;
-
                case SPEED_10000:
                        init_crd = thresh + 553 - 22;
                        break;
@@ -1114,7 +1106,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
                              MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
 
        /* CL37 Autoneg Enabled */
-       if (params->req_line_speed == SPEED_AUTO_NEG)
+       if (vars->line_speed == SPEED_AUTO_NEG)
                reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
        else /* CL37 Autoneg Disabled */
                reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
@@ -1132,7 +1124,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
                              MDIO_REG_BANK_SERDES_DIGITAL,
                              MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
        reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
-       if (params->req_line_speed == SPEED_AUTO_NEG)
+       if (vars->line_speed == SPEED_AUTO_NEG)
                reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
        else
                reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
@@ -1148,7 +1140,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
                              MDIO_REG_BANK_BAM_NEXT_PAGE,
                              MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
                          &reg_val);
-       if (params->req_line_speed == SPEED_AUTO_NEG) {
+       if (vars->line_speed == SPEED_AUTO_NEG) {
                /* Enable BAM aneg Mode and TetonII aneg Mode */
                reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
                            MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
@@ -1164,7 +1156,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
                              reg_val);
 
        /* Enable Clause 73 Aneg */
-       if ((params->req_line_speed == SPEED_AUTO_NEG) &&
+       if ((vars->line_speed == SPEED_AUTO_NEG) &&
            (SUPPORT_CL73)) {
                /* Enable BAM Station Manager */
 
@@ -1226,7 +1218,8 @@ static void bnx2x_set_autoneg(struct link_params *params,
 }
 
 /* program SerDes, forced speed */
-static void bnx2x_program_serdes(struct link_params *params)
+static void bnx2x_program_serdes(struct link_params *params,
+                              struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 reg_val;
@@ -1248,28 +1241,35 @@ static void bnx2x_program_serdes(struct link_params *params)
 
        /* program speed
           - needed only if the speed is greater than 1G (2.5G or 10G) */
-       if (!((params->req_line_speed == SPEED_1000) ||
-             (params->req_line_speed == SPEED_100) ||
-             (params->req_line_speed == SPEED_10))) {
-               CL45_RD_OVER_CL22(bp, params->port,
+       CL45_RD_OVER_CL22(bp, params->port,
                                      params->phy_addr,
                                      MDIO_REG_BANK_SERDES_DIGITAL,
                                      MDIO_SERDES_DIGITAL_MISC1, &reg_val);
-               /* clearing the speed value before setting the right speed */
-               reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK;
+       /* clearing the speed value before setting the right speed */
+       DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
+
+       reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK |
+                    MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
+
+       if (!((vars->line_speed == SPEED_1000) ||
+             (vars->line_speed == SPEED_100) ||
+             (vars->line_speed == SPEED_10))) {
+
                reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
                            MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
-               if (params->req_line_speed == SPEED_10000)
+               if (vars->line_speed == SPEED_10000)
                        reg_val |=
                                MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
-               if (params->req_line_speed == SPEED_13000)
+               if (vars->line_speed == SPEED_13000)
                        reg_val |=
                                MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
-               CL45_WR_OVER_CL22(bp, params->port,
+       }
+
+       CL45_WR_OVER_CL22(bp, params->port,
                                      params->phy_addr,
                                      MDIO_REG_BANK_SERDES_DIGITAL,
                                      MDIO_SERDES_DIGITAL_MISC1, reg_val);
-       }
+
 }
 
 static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
@@ -1295,48 +1295,49 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params)
                              MDIO_OVER_1G_UP3, 0);
 }
 
-static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
-                                          u32 *ieee_fc)
+static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc)
 {
-       struct bnx2x *bp = params->bp;
-       /* for AN, we are always publishing full duplex */
-       u16 an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
-
+       *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
        /* resolve pause mode and advertisement
         * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
 
        switch (params->req_flow_ctrl) {
        case FLOW_CTRL_AUTO:
-               if (params->mtu <= MAX_MTU_SIZE) {
-                       an_adv |=
+               if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) {
+                       *ieee_fc |=
                             MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
                } else {
-                       an_adv |=
+                       *ieee_fc |=
                       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
                }
                break;
        case FLOW_CTRL_TX:
-               an_adv |=
+               *ieee_fc |=
                       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
                break;
 
        case FLOW_CTRL_RX:
        case FLOW_CTRL_BOTH:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
                break;
 
        case FLOW_CTRL_NONE:
        default:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
                break;
        }
+}
 
-       *ieee_fc = an_adv;
+static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
+                                          u32 ieee_fc)
+{
+       struct bnx2x *bp = params->bp;
+       /* for AN, we are always publishing full duplex */
 
        CL45_WR_OVER_CL22(bp, params->port,
                              params->phy_addr,
                              MDIO_REG_BANK_COMBO_IEEE0,
-                             MDIO_COMBO_IEEE0_AUTO_NEG_ADV, an_adv);
+                             MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc);
 }
 
 static void bnx2x_restart_autoneg(struct link_params *params)
@@ -1382,7 +1383,8 @@ static void bnx2x_restart_autoneg(struct link_params *params)
        }
 }
 
-static void bnx2x_initialize_sgmii_process(struct link_params *params)
+static void bnx2x_initialize_sgmii_process(struct link_params *params,
+                                        struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 control1;
@@ -1406,7 +1408,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params)
                              control1);
 
        /* if forced speed */
-       if (!(params->req_line_speed == SPEED_AUTO_NEG)) {
+       if (!(vars->line_speed == SPEED_AUTO_NEG)) {
                /* set speed, disable autoneg */
                u16 mii_control;
 
@@ -1419,7 +1421,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params)
                                 MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK|
                                 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
 
-               switch (params->req_line_speed) {
+               switch (vars->line_speed) {
                case SPEED_100:
                        mii_control |=
                                MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
@@ -1433,8 +1435,8 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params)
                        break;
                default:
                        /* invalid speed for SGMII */
-                       DP(NETIF_MSG_LINK, "Invalid req_line_speed 0x%x\n",
-                                 params->req_line_speed);
+                       DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
+                                 vars->line_speed);
                        break;
                }
 
@@ -1460,20 +1462,20 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params)
  */
 
 static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
-{
-       switch (pause_result) {                 /* ASYM P ASYM P */
-       case 0xb:                               /*   1  0   1  1 */
+{                                              /*  LD      LP   */
+       switch (pause_result) {                 /* ASYM P ASYM P */
+       case 0xb:                               /*   1  0   1  1 */
                vars->flow_ctrl = FLOW_CTRL_TX;
                break;
 
-       case 0xe:                               /*   1  1   1  0 */
+       case 0xe:                               /*   1  1   1  0 */
                vars->flow_ctrl = FLOW_CTRL_RX;
                break;
 
-       case 0x5:                               /*   0  1   0  1 */
-       case 0x7:                               /*   0  1   1  1 */
-       case 0xd:                               /*   1  1   0  1 */
-       case 0xf:                               /*   1  1   1  1 */
+       case 0x5:                               /*   0  1   0  1 */
+       case 0x7:                               /*   0  1   1  1 */
+       case 0xd:                               /*   1  1   0  1 */
+       case 0xf:                               /*   1  1   1  1 */
                vars->flow_ctrl = FLOW_CTRL_BOTH;
                break;
 
@@ -1487,8 +1489,8 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
 {
        struct bnx2x *bp = params->bp;
        u8 ext_phy_addr;
-       u16 ld_pause;   /* local */
-       u16 lp_pause;   /* link partner */
+       u16 ld_pause;   /* local */
+       u16 lp_pause;   /* link partner */
        u16 an_complete; /* AN complete */
        u16 pause_result;
        u8 ret = 0;
@@ -1531,6 +1533,28 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params,
                DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
                   pause_result);
                bnx2x_pause_resolve(vars, pause_result);
+               if (vars->flow_ctrl == FLOW_CTRL_NONE &&
+                    ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
+                       bnx2x_cl45_read(bp, port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_AN_DEVAD,
+                                     MDIO_AN_REG_CL37_FC_LD, &ld_pause);
+
+                       bnx2x_cl45_read(bp, port,
+                                     ext_phy_type,
+                                     ext_phy_addr,
+                                     MDIO_AN_DEVAD,
+                                     MDIO_AN_REG_CL37_FC_LP, &lp_pause);
+                       pause_result = (ld_pause &
+                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5;
+                       pause_result |= (lp_pause &
+                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
+
+                       bnx2x_pause_resolve(vars, pause_result);
+                       DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
+                                pause_result);
+               }
        }
        return ret;
 }
@@ -1573,13 +1597,10 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
                   (bnx2x_ext_phy_resove_fc(params, vars))) {
                return;
        } else {
-               vars->flow_ctrl = params->req_flow_ctrl;
-               if (vars->flow_ctrl == FLOW_CTRL_AUTO) {
-                       if (params->mtu <= MAX_MTU_SIZE)
-                               vars->flow_ctrl = FLOW_CTRL_BOTH;
-                       else
-                               vars->flow_ctrl = FLOW_CTRL_TX;
-               }
+               if (params->req_flow_ctrl == FLOW_CTRL_AUTO)
+                       vars->flow_ctrl = params->req_fc_auto_adv;
+               else
+                       vars->flow_ctrl = params->req_flow_ctrl;
        }
        DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
 }
@@ -1690,7 +1711,11 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
 
                vars->link_status |= LINK_STATUS_SERDES_LINK;
 
-               if (params->req_line_speed == SPEED_AUTO_NEG) {
+               if ((params->req_line_speed == SPEED_AUTO_NEG) &&
+                   ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
+                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
+                   (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
+                    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) {
                        vars->autoneg = AUTO_NEG_ENABLED;
 
                        if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
@@ -1705,18 +1730,18 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
 
                }
                if (vars->flow_ctrl & FLOW_CTRL_TX)
-                      vars->link_status |=
-                       LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
+                       vars->link_status |=
+                               LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
 
                if (vars->flow_ctrl & FLOW_CTRL_RX)
-                      vars->link_status |=
-                       LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
+                       vars->link_status |=
+                               LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
 
        } else { /* link_down */
                DP(NETIF_MSG_LINK, "phy link down\n");
 
                vars->phy_link_up = 0;
-               vars->line_speed = 0;
+
                vars->duplex = DUPLEX_FULL;
                vars->flow_ctrl = FLOW_CTRL_NONE;
                vars->autoneg = AUTO_NEG_DISABLED;
@@ -2282,13 +2307,16 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params,
                      MDIO_AN_REG_ADV_PAUSE, &val);
 
        val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
+
        /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
 
-       if (vars->ieee_fc &
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
            MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
                val |=  MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
        }
-       if (vars->ieee_fc &
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
            MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
                val |=
                 MDIO_AN_REG_ADV_PAUSE_PAUSE;
@@ -2302,6 +2330,65 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params,
                       MDIO_AN_REG_ADV_PAUSE, val);
 }
 
+
+static void bnx2x_init_internal_phy(struct link_params *params,
+                               struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
+               u16 bank, rx_eq;
+
+               rx_eq = ((params->serdes_config &
+                         PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
+                        PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
+
+               DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
+               for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
+                     bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
+                       CL45_WR_OVER_CL22(bp, port,
+                                             params->phy_addr,
+                                             bank ,
+                                             MDIO_RX0_RX_EQ_BOOST,
+                                             ((rx_eq &
+                               MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
+                               MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
+               }
+
+               /* forced speed requested? */
+               if (vars->line_speed != SPEED_AUTO_NEG) {
+                       DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
+
+                       /* disable autoneg */
+                       bnx2x_set_autoneg(params, vars);
+
+                       /* program speed and duplex */
+                       bnx2x_program_serdes(params, vars);
+
+               } else { /* AN_mode */
+                       DP(NETIF_MSG_LINK, "not SGMII, AN\n");
+
+                       /* AN enabled */
+                       bnx2x_set_brcm_cl37_advertisment(params);
+
+                       /* program duplex & pause advertisement (for aneg) */
+                       bnx2x_set_ieee_aneg_advertisment(params,
+                                                      vars->ieee_fc);
+
+                       /* enable autoneg */
+                       bnx2x_set_autoneg(params, vars);
+
+                       /* enable and restart AN */
+                       bnx2x_restart_autoneg(params);
+               }
+
+       } else { /* SGMII mode */
+               DP(NETIF_MSG_LINK, "SGMII\n");
+
+               bnx2x_initialize_sgmii_process(params, vars);
+       }
+}
+
 static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
@@ -2343,7 +2430,6 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 
                switch (ext_phy_type) {
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
-                       DP(NETIF_MSG_LINK, "XGXS Direct\n");
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
@@ -2419,7 +2505,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                                               ext_phy_type,
                                               ext_phy_addr,
                                               MDIO_AN_DEVAD,
-                                              MDIO_AN_REG_CL37_FD,
+                                              MDIO_AN_REG_CL37_FC_LP,
                                               0x0020);
                                /* Enable CL37 AN */
                                bnx2x_cl45_write(bp, params->port,
@@ -2595,13 +2681,13 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                                       ext_phy_type,
                                       ext_phy_addr,
                                       MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CL37_CL73, 0x040c);
+                                      MDIO_AN_REG_CL37_FC_LD, 0x040c);
                        /* Add support for CL37 (passive mode) II */
                        bnx2x_cl45_write(bp, params->port,
                                       ext_phy_type,
                                       ext_phy_addr,
                                       MDIO_AN_DEVAD,
-                                      MDIO_AN_REG_CL37_FD, 0x20);
+                                      MDIO_AN_REG_CL37_FC_LD, 0x20);
                        /* Add support for CL37 (passive mode) III */
                        bnx2x_cl45_write(bp, params->port,
                                       ext_phy_type,
@@ -2701,10 +2787,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                }
 
        } else { /* SerDes */
-/*             ext_phy_addr = ((bp->ext_phy_config &
-                                PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >>
-                               PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT);
-*/
+
                ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config);
                switch (ext_phy_type) {
                case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
@@ -2726,7 +2809,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
 
 
 static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
-                                 struct link_vars *vars)
+                                struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u32 ext_phy_type;
@@ -2767,6 +2850,8 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                                      MDIO_PMA_REG_RX_SD, &rx_sd);
                        DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
                        ext_phy_link_up = (rx_sd & 0x1);
+                       if (ext_phy_link_up)
+                               vars->line_speed = SPEED_10000;
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
@@ -2810,6 +2895,13 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                         */
                        ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
                                           (val2 & (1<<1)));
+                       if (ext_phy_link_up) {
+                               if (val2 & (1<<1))
+                                       vars->line_speed = SPEED_1000;
+                               else
+                                       vars->line_speed = SPEED_10000;
+                       }
+
                        /* clear LASI indication*/
                        bnx2x_cl45_read(bp, params->port, ext_phy_type,
                                      ext_phy_addr,
@@ -3006,6 +3098,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
                                              MDIO_AN_DEVAD,
                                              MDIO_AN_REG_MASTER_STATUS,
                                              &val2);
+                               vars->line_speed = SPEED_10000;
                                DP(NETIF_MSG_LINK,
                                         "SFX7101 AN status 0x%x->Master=%x\n",
                                          val2,
@@ -3181,7 +3274,8 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
 }
 
 
-static void bnx2x_turn_on_sf(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
+static void bnx2x_turn_on_ef(struct bnx2x *bp, u8 port, u8 ext_phy_addr,
+                          u32 ext_phy_type)
 {
        u32 cnt = 0;
        u16 ctrl = 0;
@@ -3205,7 +3299,7 @@ static void bnx2x_turn_on_sf(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
        for (cnt = 0; cnt < 1000; cnt++) {
                msleep(1);
                bnx2x_cl45_read(bp, port,
-                             PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
+                             ext_phy_type,
                              ext_phy_addr,
                              MDIO_PMA_DEVAD,
                              MDIO_PMA_REG_CTRL,
@@ -3253,7 +3347,8 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
 
                /* Take ext phy out of reset */
                if (!driver_loaded)
-                       bnx2x_turn_on_sf(bp, params->port, ext_phy_addr);
+                       bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
+                                      ext_phy_type);
 
                /*  wait for 1ms */
                msleep(1);
@@ -3281,6 +3376,11 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
        {
+               /* Take ext phy out of reset */
+               if (!driver_loaded)
+                       bnx2x_turn_on_ef(bp, params->port, ext_phy_addr,
+                                      ext_phy_type);
+
                bnx2x_cl45_read(bp, params->port, ext_phy_type,
                              ext_phy_addr,
                              MDIO_PMA_DEVAD,
@@ -3622,7 +3722,8 @@ static u8 bnx2x_link_initialize(struct link_params *params,
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
        u8 rc = 0;
-
+       u8 non_ext_phy;
+       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
        /* Activate the external PHY */
        bnx2x_ext_phy_reset(params, vars);
 
@@ -3644,10 +3745,6 @@ static u8 bnx2x_link_initialize(struct link_params *params,
                bnx2x_set_swap_lanes(params);
        }
 
-       /* Set Parallel Detect */
-       if (params->req_line_speed == SPEED_AUTO_NEG)
-               bnx2x_set_parallel_detection(params, vars->phy_flags);
-
        if (vars->phy_flags & PHY_XGXS_FLAG) {
                if (params->req_line_speed &&
                    ((params->req_line_speed == SPEED_100) ||
@@ -3657,68 +3754,33 @@ static u8 bnx2x_link_initialize(struct link_params *params,
                        vars->phy_flags &= ~PHY_SGMII_FLAG;
                }
        }
+       /* In case of external phy existance, the line speed would be the
+        line speed linked up by the external phy. In case it is direct only,
+         then the line_speed during initialization will be equal to the
+          req_line_speed*/
+       vars->line_speed = params->req_line_speed;
 
-       if (!(vars->phy_flags & PHY_SGMII_FLAG)) {
-               u16 bank, rx_eq;
-
-               rx_eq = ((params->serdes_config &
-                         PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
-                        PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
-
-               DP(NETIF_MSG_LINK, "setting rx eq to 0x%x\n", rx_eq);
-               for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
-                     bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0)) {
-                       CL45_WR_OVER_CL22(bp, port,
-                                             params->phy_addr,
-                                             bank ,
-                                             MDIO_RX0_RX_EQ_BOOST,
-                                             ((rx_eq &
-                               MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
-                               MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
-               }
-
-               /* forced speed requested? */
-               if (params->req_line_speed != SPEED_AUTO_NEG) {
-                       DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
-
-                       /* disable autoneg */
-                       bnx2x_set_autoneg(params, vars);
+       bnx2x_calc_ieee_aneg_adv(params, &vars->ieee_fc);
 
-                       /* program speed and duplex */
-                       bnx2x_program_serdes(params);
-                       vars->ieee_fc =
-                               MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
-
-               } else { /* AN_mode */
-                       DP(NETIF_MSG_LINK, "not SGMII, AN\n");
-
-                       /* AN enabled */
-                       bnx2x_set_brcm_cl37_advertisment(params);
-
-                       /* program duplex & pause advertisement (for aneg) */
-                       bnx2x_set_ieee_aneg_advertisment(params,
-                                                      &vars->ieee_fc);
-
-                       /* enable autoneg */
-                       bnx2x_set_autoneg(params, vars);
-
-                       /* enable and restart AN */
-                       bnx2x_restart_autoneg(params);
-               }
-
-       } else { /* SGMII mode */
-               DP(NETIF_MSG_LINK, "SGMII\n");
-
-               bnx2x_initialize_sgmii_process(params);
+       /* init ext phy and enable link state int */
+       non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
+                      (params->loopback_mode == LOOPBACK_XGXS_10) ||
+                      (params->loopback_mode == LOOPBACK_EXT_PHY));
+
+       if (non_ext_phy ||
+           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) {
+               if (params->req_line_speed == SPEED_AUTO_NEG)
+                       bnx2x_set_parallel_detection(params, vars->phy_flags);
+               bnx2x_init_internal_phy(params, vars);
        }
 
-       /* init ext phy and enable link state int */
-       rc |= bnx2x_ext_phy_init(params, vars);
+       if (!non_ext_phy)
+               rc |= bnx2x_ext_phy_init(params, vars);
 
        bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                      (NIG_STATUS_XGXS0_LINK10G |
-                       NIG_STATUS_XGXS0_LINK_STATUS |
-                       NIG_STATUS_SERDES0_LINK_STATUS));
+                    (NIG_STATUS_XGXS0_LINK10G |
+                     NIG_STATUS_XGXS0_LINK_STATUS |
+                     NIG_STATUS_SERDES0_LINK_STATUS));
 
        return rc;
 
@@ -3734,6 +3796,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
        DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n",
                  params->req_line_speed, params->req_flow_ctrl);
        vars->link_status = 0;
+       vars->phy_link_up = 0;
+       vars->link_up = 0;
+       vars->line_speed = 0;
+       vars->duplex = DUPLEX_FULL;
+       vars->flow_ctrl = FLOW_CTRL_NONE;
+       vars->mac_type = MAC_TYPE_NONE;
+
        if (params->switch_cfg ==  SWITCH_CFG_1G)
                vars->phy_flags = PHY_SERDES_FLAG;
        else
@@ -3894,6 +3963,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                }
 
                bnx2x_link_initialize(params, vars);
+               msleep(30);
                bnx2x_link_int_enable(params);
        }
        return 0;
@@ -3949,33 +4019,13 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
                                       MISC_REGISTERS_GPIO_OUTPUT_LOW);
 
                        DP(NETIF_MSG_LINK, "reset external PHY\n");
-               } else {
-
-                       u8 ext_phy_addr = ((ext_phy_config &
-                                        PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
-                                        PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
-
-                       /* SW reset */
-                       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                                      MDIO_PMA_DEVAD,
-                                      MDIO_PMA_REG_CTRL,
-                                      1<<15);
-
-                       /* Set Low Power Mode */
-                       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
-                                 MDIO_PMA_DEVAD,
-                                 MDIO_PMA_REG_CTRL,
-                                 1<<11);
-
-
-                       if (ext_phy_type ==
-                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
-                               DP(NETIF_MSG_LINK, "Setting 8073 port %d into"
+               } else if (ext_phy_type ==
+                          PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) {
+                               DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
                                         "low power mode\n",
                                         port);
                                bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
                                        MISC_REGISTERS_GPIO_OUTPUT_LOW);
-                       }
                }
        }
        /* reset the SerDes/XGXS */
@@ -3995,6 +4045,73 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
        return 0;
 }
 
+static u8 bnx2x_update_link_down(struct link_params *params,
+                              struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
+       bnx2x_set_led(bp, port, LED_MODE_OFF,
+                   0, params->hw_led_mode,
+                   params->chip_id);
+
+       /* indicate no mac active */
+       vars->mac_type = MAC_TYPE_NONE;
+
+       /* update shared memory */
+       vars->link_status = 0;
+       vars->line_speed = 0;
+       bnx2x_update_mng(params, vars->link_status);
+
+       /* activate nig drain */
+       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+       /* reset BigMac */
+       bnx2x_bmac_rx_disable(bp, params->port);
+       REG_WR(bp, GRCBASE_MISC +
+                  MISC_REGISTERS_RESET_REG_2_CLEAR,
+                  (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+       return 0;
+}
+
+static u8 bnx2x_update_link_up(struct link_params *params,
+                            struct link_vars *vars,
+                            u8 link_10g, u32 gp_status)
+{
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       u8 rc = 0;
+       vars->link_status |= LINK_STATUS_LINK_UP;
+       if (link_10g) {
+               bnx2x_bmac_enable(params, vars, 0);
+               bnx2x_set_led(bp, port, LED_MODE_OPER,
+                           SPEED_10000, params->hw_led_mode,
+                           params->chip_id);
+
+       } else {
+               bnx2x_emac_enable(params, vars, 0);
+               rc = bnx2x_emac_program(params, vars->line_speed,
+                                     vars->duplex);
+
+               /* AN complete? */
+               if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
+                       if (!(vars->phy_flags &
+                             PHY_SGMII_FLAG))
+                               bnx2x_set_sgmii_tx_driver(params);
+               }
+       }
+
+       /* PBF - link up */
+       rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
+                             vars->line_speed);
+
+       /* disable drain */
+       REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+
+       /* update shared memory */
+       bnx2x_update_mng(params, vars->link_status);
+       return rc;
+}
 /* This function should called upon link interrupt */
 /* In case vars->link_up, driver needs to
        1. Update the pbf
@@ -4012,10 +4129,10 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
-       u16 i;
        u16 gp_status;
-       u16 link_10g;
-       u8 rc = 0;
+       u8 link_10g;
+       u8 ext_phy_link_up, rc = 0;
+       u32 ext_phy_type;
 
        DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
         port,
@@ -4031,15 +4148,16 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68));
 
+       ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
 
-       /* avoid fast toggling */
-       for (i = 0; i < 10; i++) {
-               msleep(10);
-               CL45_RD_OVER_CL22(bp, port, params->phy_addr,
-                                     MDIO_REG_BANK_GP_STATUS,
-                                     MDIO_GP_STATUS_TOP_AN_STATUS1,
-                                     &gp_status);
-       }
+       /* Check external link change only for non-direct */
+       ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars);
+
+       /* Read gp_status */
+       CL45_RD_OVER_CL22(bp, port, params->phy_addr,
+                             MDIO_REG_BANK_GP_STATUS,
+                             MDIO_GP_STATUS_TOP_AN_STATUS1,
+                             &gp_status);
 
        rc = bnx2x_link_settings_status(params, vars, gp_status);
        if (rc != 0)
@@ -4055,69 +4173,25 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 
        bnx2x_link_int_ack(params, vars, link_10g);
 
-       /* link is up only if both local phy and external phy are up */
-       vars->link_up = (vars->phy_link_up &&
-                          bnx2x_ext_phy_is_link_up(params, vars));
-
-       if (!vars->phy_link_up &&
-           REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18)) {
-               bnx2x_ext_phy_is_link_up(params, vars); /* Clear interrupt */
-       }
-
-       if (vars->link_up) {
-               vars->link_status |= LINK_STATUS_LINK_UP;
-               if (link_10g) {
-                       bnx2x_bmac_enable(params, vars, 0);
-                       bnx2x_set_led(bp, port, LED_MODE_OPER,
-                                   SPEED_10000, params->hw_led_mode,
-                                   params->chip_id);
-
-               } else {
-                       bnx2x_emac_enable(params, vars, 0);
-                       rc = bnx2x_emac_program(params, vars->line_speed,
-                                             vars->duplex);
-
-                       /* AN complete? */
-                       if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
-                               if (!(vars->phy_flags &
-                                     PHY_SGMII_FLAG))
-                                       bnx2x_set_sgmii_tx_driver(params);
-                       }
-               }
-
-               /* PBF - link up */
-               rc |= bnx2x_pbf_update(params, vars->flow_ctrl,
-                                     vars->line_speed);
-
-               /* disable drain */
-               REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+       /* In case external phy link is up, and internal link is down
+       ( not initialized yet probably after link initialization, it needs
+       to be initialized.
+       Note that after link down-up as result of cable plug,
+       the xgxs link would probably become up again without the need to
+       initialize it*/
 
-               /* update shared memory */
-               bnx2x_update_mng(params, vars->link_status);
-
-       } else { /* link down */
-               DP(NETIF_MSG_LINK, "Port %x: Link is down\n", params->port);
-               bnx2x_set_led(bp, port, LED_MODE_OFF,
-                           0, params->hw_led_mode,
-                           params->chip_id);
-
-               /* indicate no mac active */
-               vars->mac_type = MAC_TYPE_NONE;
+       if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
+           (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
+           (ext_phy_link_up && !vars->phy_link_up))
+               bnx2x_init_internal_phy(params, vars);
 
-               /* update shared memory */
-               vars->link_status = 0;
-               bnx2x_update_mng(params, vars->link_status);
-
-               /* activate nig drain */
-               REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
-
-               /* reset BigMac */
-               bnx2x_bmac_rx_disable(bp, params->port);
-               REG_WR(bp, GRCBASE_MISC +
-                          MISC_REGISTERS_RESET_REG_2_CLEAR,
-                          (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+       /* link is up only if both local phy and external phy are up */
+       vars->link_up = (ext_phy_link_up && vars->phy_link_up);
 
-       }
+       if (vars->link_up)
+               rc = bnx2x_update_link_up(params, vars, link_10g, gp_status);
+       else
+               rc = bnx2x_update_link_down(params, vars);
 
        return rc;
 }
@@ -4508,7 +4582,7 @@ u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
                /* Take ext phy out of reset */
                if (!driver_loaded)
-                       bnx2x_turn_on_sf(bp, port, ext_phy_addr);
+                       bnx2x_turn_on_ef(bp, port, ext_phy_addr, ext_phy_type);
                rc = bnx2x_sfx7101_flash_download(bp, port, ext_phy_addr,
                                                data, size);
                if (!driver_loaded)