summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c')
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c472
1 files changed, 349 insertions, 123 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 2091e5dbbcdd..ad95324dc042 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -1,4 +1,4 @@
-/* Copyright 2008-2011 Broadcom Corporation
+/* Copyright 2008-2012 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -35,7 +35,6 @@
#define ETH_MAX_PACKET_SIZE 1500
#define ETH_MAX_JUMBO_PACKET_SIZE 9600
#define MDIO_ACCESS_TIMEOUT 1000
-#define BMAC_CONTROL_RX_ENABLE 2
#define WC_LANE_MAX 4
#define I2C_SWITCH_WIDTH 2
#define I2C_BSC0 0
@@ -1372,7 +1371,14 @@ static void bnx2x_update_pfc_xmac(struct link_params *params,
pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
- XMAC_PFC_CTRL_HI_REG_TX_PFC_EN;
+ XMAC_PFC_CTRL_HI_REG_TX_PFC_EN |
+ XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
+ /* Write pause and PFC registers */
+ REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
+ REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
+ REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
+ pfc1_val &= ~XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
+
}
/* Write pause and PFC registers */
@@ -1612,6 +1618,9 @@ static void bnx2x_umac_enable(struct link_params *params,
if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE;
+ if (vars->duplex == DUPLEX_HALF)
+ val |= UMAC_COMMAND_CONFIG_REG_HD_ENA;
+
REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
udelay(50);
@@ -3635,45 +3644,77 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
}
-static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
- struct link_params *params,
- struct link_vars *vars)
+static void bnx2x_ext_phy_update_adv_fc(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
{
- struct bnx2x *bp = params->bp;
u16 ld_pause; /* local */
u16 lp_pause; /* link partner */
u16 pause_result;
- u8 ret = 0;
- /* read twice */
+ struct bnx2x *bp = params->bp;
+ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) {
+ bnx2x_cl22_read(bp, phy, 0x4, &ld_pause);
+ bnx2x_cl22_read(bp, phy, 0x5, &lp_pause);
+ } else if (CHIP_IS_E3(bp) &&
+ SINGLE_MEDIA_DIRECT(params)) {
+ u8 lane = bnx2x_get_warpcore_lane(phy, params);
+ u16 gp_status, gp_mask;
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_4,
+ &gp_status);
+ gp_mask = (MDIO_WC_REG_GP2_STATUS_GP_2_4_CL73_AN_CMPL |
+ MDIO_WC_REG_GP2_STATUS_GP_2_4_CL37_LP_AN_CAP) <<
+ lane;
+ if ((gp_status & gp_mask) == gp_mask) {
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+ } else {
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_FC_LD, &ld_pause);
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_FC_LP, &lp_pause);
+ ld_pause = ((ld_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
+ << 3);
+ lp_pause = ((lp_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
+ << 3);
+ }
+ } else {
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_AN_DEVAD,
+ MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+ }
+ pause_result = (ld_pause &
+ MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
+ pause_result |= (lp_pause &
+ MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
+ DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n", pause_result);
+ bnx2x_pause_resolve(vars, pause_result);
+}
+static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars)
+{
+ u8 ret = 0;
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
- if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+ if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) {
+ /* Update the advertised flow-controled of LD/LP in AN */
+ if (phy->req_line_speed == SPEED_AUTO_NEG)
+ bnx2x_ext_phy_update_adv_fc(phy, params, vars);
+ /* But set the flow-control result as the requested one */
vars->flow_ctrl = phy->req_flow_ctrl;
- else if (phy->req_line_speed != SPEED_AUTO_NEG)
+ } else if (phy->req_line_speed != SPEED_AUTO_NEG)
vars->flow_ctrl = params->req_fc_auto_adv;
else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
ret = 1;
- if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) {
- bnx2x_cl22_read(bp, phy,
- 0x4, &ld_pause);
- bnx2x_cl22_read(bp, phy,
- 0x5, &lp_pause);
- } else {
- bnx2x_cl45_read(bp, phy,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_ADV_PAUSE, &ld_pause);
- bnx2x_cl45_read(bp, phy,
- MDIO_AN_DEVAD,
- MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
- }
- pause_result = (ld_pause &
- MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
- pause_result |= (lp_pause &
- MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
- DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
- pause_result);
- bnx2x_pause_resolve(vars, pause_result);
+ bnx2x_ext_phy_update_adv_fc(phy, params, vars);
}
return ret;
}
@@ -3691,7 +3732,23 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
u16 val16 = 0, lane, bam37 = 0;
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
-
+ /* Set to default registers that may be overriden by 10G force */
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0);
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0xff);
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0x5555);
+ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+ MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0x0);
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_RX66_CONTROL, 0x7415);
+ bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x6190);
/* Disable Autoneg: re-enable it after adv is done. */
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
@@ -3785,7 +3842,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
/* Enable Autoneg */
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
- MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
+ MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1200);
}
@@ -3937,13 +3994,13 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
} else {
misc1_val |= 0x9;
- tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
- (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
- (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
+ tap_val = ((0x0f << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
+ (0x2b << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
+ (0x02 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
tx_driver_val =
- ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+ ((0x03 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
(0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
+ (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
}
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
@@ -4361,7 +4418,7 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
switch (serdes_net_if) {
case PORT_HW_CFG_NET_SERDES_IF_KR:
/* Enable KR Auto Neg */
- if (params->loopback_mode == LOOPBACK_NONE)
+ if (params->loopback_mode != LOOPBACK_EXT)
bnx2x_warpcore_enable_AN_KR(phy, params, vars);
else {
DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
@@ -5216,22 +5273,69 @@ static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
return 0;
}
+static void bnx2x_update_adv_fc(struct bnx2x_phy *phy,
+ struct link_params *params,
+ struct link_vars *vars,
+ u32 gp_status)
+{
+ u16 ld_pause; /* local driver */
+ u16 lp_pause; /* link partner */
+ u16 pause_result;
+ struct bnx2x *bp = params->bp;
+ if ((gp_status &
+ (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
+ MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
+ (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
+ MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
+
+ CL22_RD_OVER_CL45(bp, phy,
+ MDIO_REG_BANK_CL73_IEEEB1,
+ MDIO_CL73_IEEEB1_AN_ADV1,
+ &ld_pause);
+ CL22_RD_OVER_CL45(bp, phy,
+ MDIO_REG_BANK_CL73_IEEEB1,
+ MDIO_CL73_IEEEB1_AN_LP_ADV1,
+ &lp_pause);
+ pause_result = (ld_pause &
+ MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK) >> 8;
+ pause_result |= (lp_pause &
+ MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK) >> 10;
+ DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n", pause_result);
+ } else {
+ CL22_RD_OVER_CL45(bp, phy,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
+ &ld_pause);
+ CL22_RD_OVER_CL45(bp, phy,
+ MDIO_REG_BANK_COMBO_IEEE0,
+ MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
+ &lp_pause);
+ pause_result = (ld_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
+ pause_result |= (lp_pause &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
+ DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n", pause_result);
+ }
+ bnx2x_pause_resolve(vars, pause_result);
+
+}
+
static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars,
u32 gp_status)
{
struct bnx2x *bp = params->bp;
- u16 ld_pause; /* local driver */
- u16 lp_pause; /* link partner */
- u16 pause_result;
-
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
/* resolve from gp_status in case of AN complete and not sgmii */
- if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+ if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) {
+ /* Update the advertised flow-controled of LD/LP in AN */
+ if (phy->req_line_speed == SPEED_AUTO_NEG)
+ bnx2x_update_adv_fc(phy, params, vars, gp_status);
+ /* But set the flow-control result as the requested one */
vars->flow_ctrl = phy->req_flow_ctrl;
- else if (phy->req_line_speed != SPEED_AUTO_NEG)
+ } else if (phy->req_line_speed != SPEED_AUTO_NEG)
vars->flow_ctrl = params->req_fc_auto_adv;
else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
(!(vars->phy_flags & PHY_SGMII_FLAG))) {
@@ -5239,45 +5343,7 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
vars->flow_ctrl = params->req_fc_auto_adv;
return;
}
- if ((gp_status &
- (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
- MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
- (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
- MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
-
- CL22_RD_OVER_CL45(bp, phy,
- MDIO_REG_BANK_CL73_IEEEB1,
- MDIO_CL73_IEEEB1_AN_ADV1,
- &ld_pause);
- CL22_RD_OVER_CL45(bp, phy,
- MDIO_REG_BANK_CL73_IEEEB1,
- MDIO_CL73_IEEEB1_AN_LP_ADV1,
- &lp_pause);
- pause_result = (ld_pause &
- MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
- >> 8;
- pause_result |= (lp_pause &
- MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
- >> 10;
- DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
- pause_result);
- } else {
- CL22_RD_OVER_CL45(bp, phy,
- MDIO_REG_BANK_COMBO_IEEE0,
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
- &ld_pause);
- CL22_RD_OVER_CL45(bp, phy,
- MDIO_REG_BANK_COMBO_IEEE0,
- MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
- &lp_pause);
- pause_result = (ld_pause &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
- pause_result |= (lp_pause &
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
- DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
- pause_result);
- }
- bnx2x_pause_resolve(vars, pause_result);
+ bnx2x_update_adv_fc(phy, params, vars, gp_status);
}
DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
}
@@ -5496,6 +5562,33 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
}
}
+ /* Read LP advertised speeds*/
+ if (SINGLE_MEDIA_DIRECT(params) &&
+ (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)) {
+ u16 val;
+
+ CL22_RD_OVER_CL45(bp, phy, MDIO_REG_BANK_CL73_IEEEB1,
+ MDIO_CL73_IEEEB1_AN_LP_ADV2, &val);
+
+ if (val & MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX)
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
+ if (val & (MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 |
+ MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+
+ CL22_RD_OVER_CL45(bp, phy, MDIO_REG_BANK_OVER_1G,
+ MDIO_OVER_1G_LP_UP1, &val);
+
+ if (val & MDIO_OVER_1G_UP1_2_5G)
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE;
+ if (val & (MDIO_OVER_1G_UP1_10G | MDIO_OVER_1G_UP1_10GH))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+ }
+
DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n",
vars->duplex, vars->flow_ctrl, vars->link_status);
return rc;
@@ -5553,6 +5646,34 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
}
}
+ if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) &&
+ SINGLE_MEDIA_DIRECT(params)) {
+ u16 val;
+
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_LP_AUTO_NEG2, &val);
+
+ if (val & MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX)
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
+ if (val & (MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 |
+ MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+
+ bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+ MDIO_WC_REG_DIGITAL3_LP_UP1, &val);
+
+ if (val & MDIO_OVER_1G_UP1_2_5G)
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE;
+ if (val & (MDIO_OVER_1G_UP1_10G | MDIO_OVER_1G_UP1_10GH))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+
+ }
+
+
if (lane < 2) {
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
@@ -5970,8 +6091,8 @@ static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
return 0;
}
-int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
- u8 *version, u16 len)
+int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 *version,
+ u16 len)
{
struct bnx2x *bp;
u32 spirom_ver = 0;
@@ -6095,12 +6216,14 @@ int bnx2x_set_led(struct link_params *params,
tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
if (params->phy[EXT_PHY1].type ==
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
- EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp & 0xfff1);
- else {
- EMAC_WR(bp, EMAC_REG_EMAC_LED,
- (tmp | EMAC_LED_OVERRIDE));
- }
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
+ tmp &= ~(EMAC_LED_1000MB_OVERRIDE |
+ EMAC_LED_100MB_OVERRIDE |
+ EMAC_LED_10MB_OVERRIDE);
+ else
+ tmp |= EMAC_LED_OVERRIDE;
+
+ EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp);
break;
case LED_MODE_OPER:
@@ -6155,10 +6278,15 @@ int bnx2x_set_led(struct link_params *params,
hw_led_mode);
} else if ((params->phy[EXT_PHY1].type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
- (mode != LED_MODE_OPER)) {
+ (mode == LED_MODE_ON)) {
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
- EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp | 0x3);
+ EMAC_WR(bp, EMAC_REG_EMAC_LED, tmp |
+ EMAC_LED_OVERRIDE | EMAC_LED_1000MB_OVERRIDE);
+ /* Break here; otherwise, it'll disable the
+ * intended override.
+ */
+ break;
} else
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
hw_led_mode);
@@ -6173,13 +6301,9 @@ int bnx2x_set_led(struct link_params *params,
LED_BLINK_RATE_VAL_E1X_E2);
REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 +
port*4, 1);
- if ((params->phy[EXT_PHY1].type !=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) &&
- (mode != LED_MODE_OPER)) {
- tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
- EMAC_WR(bp, EMAC_REG_EMAC_LED,
- (tmp & (~EMAC_LED_OVERRIDE)));
- }
+ tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+ EMAC_WR(bp, EMAC_REG_EMAC_LED,
+ (tmp & (~EMAC_LED_OVERRIDE)));
if (CHIP_IS_E1(bp) &&
((speed == SPEED_2500) ||
@@ -6418,7 +6542,9 @@ static int bnx2x_update_link_down(struct link_params *params,
LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
- LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
+ LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK |
+ LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE |
+ LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE);
vars->line_speed = 0;
bnx2x_update_mng(params, vars->link_status);
@@ -6770,6 +6896,12 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
SINGLE_MEDIA_DIRECT(params)) &&
(phy_vars[active_external_phy].fault_detected == 0));
+ /* Update the PFC configuration in case it was changed */
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+ vars->link_status |= LINK_STATUS_PFC_ENABLED;
+ else
+ vars->link_status &= ~LINK_STATUS_PFC_ENABLED;
+
if (vars->link_up)
rc = bnx2x_update_link_up(params, vars, link_10g_plus);
else
@@ -7367,6 +7499,19 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
bnx2x_8073_resolve_fc(phy, params, vars);
vars->duplex = DUPLEX_FULL;
}
+
+ if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_LP_AUTO_NEG2, &val1);
+
+ if (val1 & (1<<5))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
+ if (val1 & (1<<7))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
+ }
+
return link_up;
}
@@ -7944,7 +8089,9 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected,"
" Port %d from %s part number %s\n",
params->port, vendor_name, vendor_pn);
- phy->flags |= FLAGS_SFP_NOT_APPROVED;
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG)
+ phy->flags |= FLAGS_SFP_NOT_APPROVED;
return -EINVAL;
}
@@ -9004,6 +9151,12 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
tmp2 &= 0xFFEF;
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+ &tmp2);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
+ (tmp2 & 0x7fff));
}
return 0;
@@ -9184,12 +9337,11 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
((1<<5) | (1<<2)));
}
- DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n");
- bnx2x_8727_specific_func(phy, params, ENABLE_TX);
- /* If transmitter is disabled, ignore false link up indication */
- bnx2x_cl45_read(bp, phy,
- MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1);
- if (val1 & (1<<15)) {
+
+ if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) {
+ DP(NETIF_MSG_LINK, "Enabling 8727 TX laser\n");
+ bnx2x_sfp_set_transmitter(params, phy, 1);
+ } else {
DP(NETIF_MSG_LINK, "Tx is disabled\n");
return 0;
}
@@ -9283,8 +9435,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
- bnx2x_save_spirom_version(bp, port,
- ((fw_ver1 & 0xf000)>>5) | (fw_ver1 & 0x7f),
+ bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff,
phy->ver_addr);
} else {
/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
@@ -9405,13 +9556,8 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
{
struct bnx2x *bp = params->bp;
u16 autoneg_val, an_1000_val, an_10_100_val, an_10g_val;
- u16 tmp_req_line_speed;
- tmp_req_line_speed = phy->req_line_speed;
- if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
- if (phy->req_line_speed == SPEED_10000)
- phy->req_line_speed = SPEED_AUTO_NEG;
- } else {
+ if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
/* Save spirom version */
bnx2x_save_848xx_spirom_version(phy, bp, params->port);
}
@@ -9555,8 +9701,6 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
MDIO_AN_REG_8481_10GBASE_T_AN_CTRL,
1);
- phy->req_line_speed = tmp_req_line_speed;
-
return 0;
}
@@ -9714,6 +9858,15 @@ static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy,
other_shmem_base_addr));
u32 shmem_base_path[2];
+
+ /* Work around for 84833 LED failure inside RESET status */
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_LEGACY_MII_CTRL,
+ MDIO_AN_REG_8481_MII_CTRL_FORCE_1G);
+ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_8481_1G_100T_EXT_CTRL,
+ MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF);
+
shmem_base_path[0] = params->shmem_base;
shmem_base_path[1] = other_shmem_base_addr;
@@ -9948,6 +10101,42 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
vars->line_speed);
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+
+ /* Read LP advertised speeds */
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_FC_LP, &val);
+ if (val & (1<<5))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10THD_CAPABLE;
+ if (val & (1<<6))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE;
+ if (val & (1<<7))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE;
+ if (val & (1<<8))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE;
+ if (val & (1<<9))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100T4_CAPABLE;
+
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_1000T_STATUS, &val);
+
+ if (val & (1<<10))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE;
+ if (val & (1<<11))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
+
+ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+ MDIO_AN_REG_MASTER_STATUS, &val);
+
+ if (val & (1<<11))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
}
return link_up;
@@ -9988,7 +10177,7 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
u8 port;
u16 val16;
- if (!(CHIP_IS_E1(bp)))
+ if (!(CHIP_IS_E1x(bp)))
port = BP_PATH(bp);
else
port = params->port;
@@ -10015,7 +10204,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
u16 val;
u8 port;
- if (!(CHIP_IS_E1(bp)))
+ if (!(CHIP_IS_E1x(bp)))
port = BP_PATH(bp);
else
port = params->port;
@@ -10571,6 +10760,35 @@ static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy,
}
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+
+ if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
+ /* report LP advertised speeds */
+ bnx2x_cl22_read(bp, phy, 0x5, &val);
+
+ if (val & (1<<5))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10THD_CAPABLE;
+ if (val & (1<<6))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE;
+ if (val & (1<<7))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE;
+ if (val & (1<<8))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE;
+ if (val & (1<<9))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_100T4_CAPABLE;
+
+ bnx2x_cl22_read(bp, phy, 0xa, &val);
+ if (val & (1<<10))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE;
+ if (val & (1<<11))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
+ }
}
return link_up;
}
@@ -10699,6 +10917,11 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
val2, (val2 & (1<<14)));
bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+
+ /* read LP advertised speeds */
+ if (val2 & (1<<11))
+ vars->link_status |=
+ LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
}
return link_up;
}
@@ -11900,6 +12123,9 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_emac_init(params, vars);
+ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
+ vars->link_status |= LINK_STATUS_PFC_ENABLED;
+
if (params->num_phys == 0) {
DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
return -EINVAL;
@@ -11979,10 +12205,10 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
* Hold it as vars low
*/
/* clear link led */
+ bnx2x_set_mdio_clk(bp, params->chip_id, port);
bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
if (reset_ext_phy) {
- bnx2x_set_mdio_clk(bp, params->chip_id, port);
for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) {
if (params->phy[phy_index].link_reset) {