From 239d686d494f10ecd83a89ddc4e31f9462ca4901 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Wed, 12 Aug 2009 08:23:04 +0000 Subject: bnx2x: Adding XAUI CL73 autoneg support Adding CL73 support to the built in PHY in the 5771x device. Also supporting fallbacks to CL73 if the link partner does not respond. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x_link.c | 197 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 167 insertions(+), 30 deletions(-) (limited to 'drivers/net/bnx2x_link.c') diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index db4f3c057a19..371310db2eba 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -1151,7 +1151,8 @@ static void bnx2x_set_parallel_detection(struct link_params *params, } static void bnx2x_set_autoneg(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 reg_val; @@ -1181,7 +1182,9 @@ static void bnx2x_set_autoneg(struct link_params *params, params->phy_addr, MDIO_REG_BANK_SERDES_DIGITAL, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); - reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; + reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT); + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE; if (vars->line_speed == SPEED_AUTO_NEG) reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; else @@ -1213,8 +1216,51 @@ static void bnx2x_set_autoneg(struct link_params *params, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, reg_val); - /* CL73 Autoneg Disabled */ - reg_val = 0; + if (enable_cl73) { + /* Enable Cl73 FSM status bits */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_UCTRL, + MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL); + + /* Enable BAM Station Manager*/ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL1, + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); + + /* Merge CL73 and CL37 aneg resolution */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL3, + ®_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + /* Set the CL73 AN speed */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + ®_val); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + reg_val | MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4); + + } + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + + } else /* CL73 Autoneg Disabled */ + reg_val = 0; CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, @@ -1297,7 +1343,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct link_params *params) CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_OVER_1G, - MDIO_OVER_1G_UP3, 0); + MDIO_OVER_1G_UP3, 0x400); } static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) @@ -1345,28 +1391,46 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); } -static void bnx2x_restart_autoneg(struct link_params *params) +static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) { struct bnx2x *bp = params->bp; u16 mii_control; + DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n"); /* Enable and restart BAM/CL37 aneg */ - CL45_RD_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - &mii_control); - DP(NETIF_MSG_LINK, - "bnx2x_restart_autoneg mii_control before = 0x%x\n", - mii_control); - CL45_WR_OVER_CL22(bp, params->port, - params->phy_addr, - MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_MII_CONTROL, - (mii_control | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | - MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + if (enable_cl73) { + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &mii_control); + + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (mii_control | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + } else { + + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + DP(NETIF_MSG_LINK, + "bnx2x_restart_autoneg mii_control before = 0x%x\n", + mii_control); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } } static void bnx2x_initialize_sgmii_process(struct link_params *params, @@ -1438,7 +1502,7 @@ static void bnx2x_initialize_sgmii_process(struct link_params *params, } else { /* AN mode */ /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, 0); } } @@ -1591,7 +1655,73 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl); } - +static void bnx2x_check_fallback_to_cl37(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 rx_status, ustat_val, cl37_fsm_recieved; + DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); + /* Step 1: Make sure signal is detected */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_RX0, + MDIO_RX0_RX_STATUS, + &rx_status); + if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) != + (MDIO_RX0_RX_STATUS_SIGDET)) { + DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." + "rx_status(0x80b0) = 0x%x\n", rx_status); + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); + return; + } + /* Step 2: Check CL73 state machine */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_USTAT1, + &ustat_val); + if ((ustat_val & + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) != + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) { + DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. " + "ustat_val(0x8371) = 0x%x\n", ustat_val); + return; + } + /* Step 3: Check CL37 Message Pages received to indicate LP + supports only CL37 */ + CL45_RD_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_REMOTE_PHY, + MDIO_REMOTE_PHY_MISC_RX_STATUS, + &cl37_fsm_recieved); + if ((cl37_fsm_recieved & + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) { + DP(NETIF_MSG_LINK, "No CL37 FSM were received. " + "misc_rx_status(0x8330) = 0x%x\n", + cl37_fsm_recieved); + return; + } + /* The combined cl37/cl73 fsm state information indicating that we are + connected to a device which does not support cl73, but does support + cl37 BAM. In this case we disable cl73 and restart cl37 auto-neg */ + /* Disable CL73 */ + CL45_WR_OVER_CL22(bp, params->port, + params->phy_addr, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0); + /* Restart CL37 autoneg */ + bnx2x_restart_autoneg(params, 0); + DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); +} static u8 bnx2x_link_settings_status(struct link_params *params, struct link_vars *vars, u32 gp_status, @@ -1755,6 +1885,13 @@ static u8 bnx2x_link_settings_status(struct link_params *params, vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->autoneg = AUTO_NEG_DISABLED; vars->mac_type = MAC_TYPE_NONE; + + if ((params->req_line_speed == SPEED_AUTO_NEG) && + ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT))) { + /* Check signal is detected */ + bnx2x_check_fallback_to_cl37(params); + } } DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x \n", @@ -3425,7 +3562,8 @@ static void bnx2x_8481_set_10G_led_mode(struct link_params *params, static void bnx2x_init_internal_phy(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 enable_cl73) { struct bnx2x *bp = params->bp; if (!(vars->phy_flags & PHY_SGMII_FLAG)) { @@ -3440,7 +3578,7 @@ static void bnx2x_init_internal_phy(struct link_params *params, DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); /* disable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, 0); /* program speed and duplex */ bnx2x_program_serdes(params, vars); @@ -3456,10 +3594,10 @@ static void bnx2x_init_internal_phy(struct link_params *params, vars->ieee_fc); /* enable autoneg */ - bnx2x_set_autoneg(params, vars); + bnx2x_set_autoneg(params, vars, enable_cl73); /* enable and restart AN */ - bnx2x_restart_autoneg(params); + bnx2x_restart_autoneg(params, enable_cl73); } } else { /* SGMII mode */ @@ -5815,11 +5953,10 @@ static u8 bnx2x_link_initialize(struct link_params *params, if (non_ext_phy || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) || (params->loopback_mode == LOOPBACK_EXT_PHY)) { if (params->req_line_speed == SPEED_AUTO_NEG) bnx2x_set_parallel_detection(params, vars->phy_flags); - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, non_ext_phy); } if (!non_ext_phy) @@ -6296,7 +6433,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) && (ext_phy_link_up && !vars->phy_link_up)) - bnx2x_init_internal_phy(params, vars); + bnx2x_init_internal_phy(params, vars, 0); /* link is up only if both local phy and external phy are up */ vars->link_up = (ext_phy_link_up && vars->phy_link_up); -- cgit v1.2.3-59-g8ed1b