diff options
Diffstat (limited to 'drivers/net/bnx2x_link.c')
-rw-r--r-- | drivers/net/bnx2x_link.c | 1528 |
1 files changed, 840 insertions, 688 deletions
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 1f17334c8f0..e32d3370862 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -37,6 +37,10 @@ /* Shortcut definitions */ /***********************************************************/ +#define NIG_LATCH_BC_ENABLE_MI_INT 0 + +#define NIG_STATUS_EMAC0_MI_INT \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT #define NIG_STATUS_XGXS0_LINK10G \ NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G #define NIG_STATUS_XGXS0_LINK_STATUS \ @@ -178,6 +182,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) { struct bnx2x *bp = params->bp; u32 emac_base = (params->port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + /* Set Clause 22 */ REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + params->port*0x10, 1); REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000); @@ -190,6 +195,7 @@ static void bnx2x_set_serdes_access(struct link_params *params) static void bnx2x_set_phy_mdio(struct link_params *params, u8 phy_flags) { struct bnx2x *bp = params->bp; + if (phy_flags & PHY_XGXS_FLAG) { REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + params->port*0x18, 0); @@ -393,7 +399,8 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable access for bmac registers */ REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); - } + } else + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); vars->mac_type = MAC_TYPE_EMAC; return 0; @@ -460,7 +467,6 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); - /* set rx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; wb_data[1] = 0; @@ -679,6 +685,7 @@ void bnx2x_link_status_update(struct link_params *params, static void bnx2x_update_mng(struct link_params *params, u32 link_status) { struct bnx2x *bp = params->bp; + REG_WR(bp, params->shmem_base + offsetof(struct shmem_region, port_mb[params->port].link_status), @@ -775,7 +782,6 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed); return -EINVAL; - break; } } REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); @@ -795,6 +801,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port) { u32 emac_base; + switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: @@ -900,7 +907,7 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT)); val |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); + (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); udelay(40); @@ -1017,8 +1024,8 @@ static u8 bnx2x_reset_unicore(struct link_params *params) MDIO_COMBO_IEEE0_MII_CONTROL, (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET)); - - bnx2x_set_serdes_access(params); + if (params->switch_cfg == SWITCH_CFG_1G) + bnx2x_set_serdes_access(params); /* wait for the reset to self clear */ for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { @@ -1147,7 +1154,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; @@ -1177,7 +1185,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 @@ -1209,8 +1219,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, @@ -1225,14 +1278,14 @@ static void bnx2x_program_serdes(struct link_params *params, struct bnx2x *bp = params->bp; u16 reg_val; - /* program duplex, disable autoneg */ - + /* program duplex, disable autoneg and sgmii*/ CL45_RD_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | - MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK); if (params->req_duplex == DUPLEX_FULL) reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; CL45_WR_OVER_CL22(bp, params->port, @@ -1293,10 +1346,10 @@ 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) +static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u16 *ieee_fc) { *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; /* resolve pause mode and advertisement @@ -1330,7 +1383,7 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) } static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, - u32 ieee_fc) + u16 ieee_fc) { struct bnx2x *bp = params->bp; /* for AN, we are always publishing full duplex */ @@ -1338,31 +1391,49 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params, CL45_WR_OVER_CL22(bp, params->port, params->phy_addr, MDIO_REG_BANK_COMBO_IEEE0, - MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (u16)ieee_fc); + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, 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, @@ -1434,7 +1505,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); } } @@ -1466,22 +1537,19 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) } } -static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, +static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 ext_phy_addr; - u16 ld_pause; /* local */ - u16 lp_pause; /* link partner */ - u16 an_complete; /* AN complete */ + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 an_complete; /* AN complete */ u16 pause_result; u8 ret = 0; u32 ext_phy_type; u8 port = params->port; - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read twice */ @@ -1576,7 +1644,7 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); bnx2x_pause_resolve(vars, pause_result); } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && - (bnx2x_ext_phy_resove_fc(params, vars))) { + (bnx2x_ext_phy_resolve_fc(params, vars))) { return; } else { if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) @@ -1587,10 +1655,77 @@ 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) + struct link_vars *vars, + u32 gp_status, + u8 ext_phy_link_up) { struct bnx2x *bp = params->bp; u16 new_line_speed; @@ -1651,7 +1786,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, "link speed unsupported gp_status 0x%x\n", gp_status); return -EINVAL; - break; + case GP_STATUS_10G_KX4: case GP_STATUS_10G_HIG: case GP_STATUS_10G_CX4: @@ -1688,14 +1823,23 @@ static u8 bnx2x_link_settings_status(struct link_params *params, DP(NETIF_MSG_LINK, "link speed unsupported gp_status 0x%x\n", gp_status); - return -EINVAL; - break; + return -EINVAL; } /* Upon link speed change set the NIG into drain mode. Comes to deals with possible FIFO glitch due to clk change when speed is decreased without link down indicator */ if (new_line_speed != vars->line_speed) { + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) != + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT && + ext_phy_link_up) { + DP(NETIF_MSG_LINK, "Internal link speed %d is" + " different than the external" + " link speed %d\n", new_line_speed, + vars->line_speed); + vars->phy_link_up = 0; + return 0; + } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); msleep(1); @@ -1709,9 +1853,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) || - (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481))) { + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) { vars->autoneg = AUTO_NEG_ENABLED; if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { @@ -1742,6 +1884,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", @@ -1846,7 +1995,7 @@ static u8 bnx2x_emac_program(struct link_params *params, /*****************************************************************************/ /* External Phy section */ /*****************************************************************************/ -static void bnx2x_hw_reset(struct bnx2x *bp, u8 port) +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port) { bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); @@ -1860,9 +2009,8 @@ static void bnx2x_ext_phy_reset(struct link_params *params, { struct bnx2x *bp = params->bp; u32 ext_phy_type; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* The PHY reset is controled by GPIO 1 @@ -1885,7 +2033,7 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -1914,16 +2062,17 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); - break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + DP(NETIF_MSG_LINK, "XGXS 8072\n"); + /* Unset Low Power Mode and SW reset */ /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - DP(NETIF_MSG_LINK, "XGXS 8072\n"); bnx2x_cl45_write(bp, params->port, ext_phy_type, ext_phy_addr, @@ -1931,8 +2080,9 @@ static void bnx2x_ext_phy_reset(struct link_params *params, MDIO_PMA_REG_CTRL, 1<<15); break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - { + DP(NETIF_MSG_LINK, "XGXS 8073\n"); /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, @@ -1942,9 +2092,6 @@ static void bnx2x_ext_phy_reset(struct link_params *params, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); - - DP(NETIF_MSG_LINK, "XGXS 8073\n"); - } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: @@ -1956,19 +2103,17 @@ static void bnx2x_ext_phy_reset(struct link_params *params, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); - + bnx2x_ext_phy_hw_reset(bp, params->port); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Restore normal power mode*/ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); bnx2x_cl45_write(bp, params->port, ext_phy_type, @@ -1996,24 +2141,22 @@ static void bnx2x_ext_phy_reset(struct link_params *params, case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: DP(NETIF_MSG_LINK, "SerDes 5482\n"); - bnx2x_hw_reset(bp, params->port); + bnx2x_ext_phy_hw_reset(bp, params->port); break; default: - DP(NETIF_MSG_LINK, - "BAD SerDes ext_phy_config 0x%x\n", + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", params->ext_phy_config); break; } } } - static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, u32 shmem_base, u32 spirom_ver) { - DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x\n", - (u16)(spirom_ver>>16), (u16)spirom_ver); + DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n", + (u16)(spirom_ver>>16), (u16)spirom_ver, port); REG_WR(bp, shmem_base + offsetof(struct shmem_region, port_mb[port].ext_phy_fw_version), @@ -2025,6 +2168,7 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, u32 shmem_base) { u16 fw_ver1, fw_ver2; + bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &fw_ver1); bnx2x_cl45_read(bp, port, ext_phy_type, ext_phy_addr, MDIO_PMA_DEVAD, @@ -2033,13 +2177,116 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, u8 port, (u32)(fw_ver1<<16 | fw_ver2)); } + +static void bnx2x_save_8481_spirom_version(struct bnx2x *bp, u8 port, + u8 ext_phy_addr, u32 shmem_base) +{ + u16 val, fw_ver1, fw_ver2, cnt; + /* For the 32 bits registers in 8481, access via MDIO2ARM interface.*/ + /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0014); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81A, + 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + 0x0300); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA817, + 0x0009); + + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(1)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + + /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA819, 0x0000); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA81A, 0xc200); + bnx2x_cl45_write(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, MDIO_PMA_DEVAD, + 0xA817, 0x000A); + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA818, + &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 8481 phy fw version(2)\n"); + bnx2x_save_spirom_version(bp, port, + shmem_base, 0); + return; + } + + /* lower 16 bits of the register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81B, + &fw_ver1); + /* upper 16 bits of register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, port, + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + ext_phy_addr, + MDIO_PMA_DEVAD, + 0xA81C, + &fw_ver2); + + bnx2x_save_spirom_version(bp, port, + shmem_base, (fw_ver2<<16) | fw_ver1); +} + static void bnx2x_bcm8072_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 200ms after reset */ @@ -2087,9 +2334,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) /* This is only required for 8073A1, version 102 only */ struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val; /* Read 8073 HW revision*/ @@ -2120,9 +2365,7 @@ static u8 bnx2x_8073_is_snr_needed(struct link_params *params) static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) { struct bnx2x *bp = params->bp; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 val, cnt, cnt1 ; bnx2x_cl45_read(bp, params->port, @@ -2178,7 +2421,6 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params) } DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n"); return -EINVAL; - } static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port, @@ -2264,9 +2506,7 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Need to wait 100ms after reset */ @@ -2322,6 +2562,7 @@ static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port, u8 tx_en) { u16 val; + DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n", tx_en, port); /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ @@ -2352,10 +2593,9 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params, u16 val = 0; u16 i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + if (byte_cnt > 16) { DP(NETIF_MSG_LINK, "Reading from eeprom is" " is limited to 0xf\n"); @@ -2436,9 +2676,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params, struct bnx2x *bp = params->bp; u16 val, i; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); if (byte_cnt > 16) { @@ -2569,6 +2807,7 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, case SFP_EEPROM_CON_TYPE_VAL_COPPER: { u8 copper_module_type; + /* Check if its active cable( includes SFP+ module) of passive cable*/ if (bnx2x_read_sfp_module_eeprom(params, @@ -2603,7 +2842,6 @@ static u8 bnx2x_get_edc_mode(struct link_params *params, DP(NETIF_MSG_LINK, "Optic module detected\n"); check_limiting_mode = 1; break; - default: DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n", val); @@ -2691,9 +2929,7 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params, { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u16 cur_limiting_mode; bnx2x_cl45_read(bp, port, @@ -2759,9 +2995,7 @@ static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params, u8 port = params->port; u16 phy_identifier; u16 rom_ver2_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, @@ -2865,9 +3099,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params) struct bnx2x *bp = params->bp; u16 edc_mode; u8 rc = 0; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. @@ -2936,6 +3168,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) struct bnx2x *bp = params->bp; u32 gpio_val; u8 port = params->port; + /* Set valid module led off */ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, MISC_REGISTERS_GPIO_HIGH, @@ -2957,9 +3190,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params) else DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); } else { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); + u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + @@ -2983,9 +3215,7 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Force KR or KX */ @@ -3006,14 +3236,13 @@ static void bnx2x_bcm807x_force_10G(struct link_params *params) MDIO_AN_REG_CTRL, 0x0000); } + static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) { struct bnx2x *bp = params->bp; u8 port = params->port; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3075,12 +3304,9 @@ static void bnx2x_bcm8073_set_xaui_low_power_mode(struct link_params *params) static void bnx2x_8073_set_pause_cl37(struct link_params *params, struct link_vars *vars) { - struct bnx2x *bp = params->bp; u16 cl37_val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); bnx2x_cl45_read(bp, params->port, @@ -3123,9 +3349,7 @@ static void bnx2x_ext_phy_set_pause(struct link_params *params, { struct bnx2x *bp = params->bp; u16 val; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* read modify write pause advertizing */ @@ -3182,10 +3406,136 @@ static void bnx2x_set_preemphasis(struct link_params *params) } } + +static void bnx2x_8481_set_led4(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* PHYC_CTL_LED_CTL */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, 0xa482); + + /* Unmask LED4 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_SIGNAL_MASK, (1<<6)); + /* 'Interrupt Mask' */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFB, 0xFFFD); +} +static void bnx2x_8481_set_legacy_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + + /* LED1 (10G Link): Disable LED1 when 10/100/1000 link */ + /* LED2 (1G/100/10 Link): Enable LED2 when 10/100/1000 link) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_SHADOW, + (1<<15) | (0xd << 10) | (0xc<<4) | 0xe); +} + +static void bnx2x_8481_set_10G_led_mode(struct link_params *params, + u32 ext_phy_type, u8 ext_phy_addr) +{ + struct bnx2x *bp = params->bp; + u16 val1; + + /* LED1 (10G Link) */ + /* Enable continuse based on source 7(10G-link) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 &= ~((1<<0) | (1<<2)); /* Clear bits 0,2*/ + val1 |= (1<<1); /* Set bit 1 */ + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + /* Unmask LED1 for 10G link */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + &val1); + /* Set bit 2 to 0, and bits [1:0] to 10 */ + val1 |= (1<<7); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + val1); + + /* LED2 (1G/100/10G Link) */ + /* Mask LED2 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0); + + /* LED3 (10G/1G/100/10G Activity) */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val1); + /* Enable blink based on source 4(Activity) */ + val1 &= ~((1<<7) | (1<<8)); /* Clear bits 7,8 */ + val1 |= (1<<6); /* Set only bit 6 */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val1); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + &val1); + val1 |= (1<<4); /* Unmask LED3 for 10G link */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + val1); +} + + 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)) { if ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && @@ -3198,7 +3548,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); @@ -3214,10 +3564,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 */ @@ -3236,10 +3586,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) u16 ctrl = 0; u16 val = 0; u8 rc = 0; + if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Make sure that the soft reset is off (expect for the 8072: @@ -3534,14 +3883,12 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_8073_set_pause_cl37(params, vars); if (ext_phy_type == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072){ + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) bnx2x_bcm8072_external_rom_boot(params); - } else { - + else /* In case of 8073 with long xaui lines, don't set the 8073 xaui low power*/ bnx2x_bcm8073_set_xaui_low_power_mode(params); - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -3606,10 +3953,8 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val); - if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { - bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -3943,20 +4288,112 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_save_spirom_version(params->bp, params->port, params->shmem_base, (u32)(fw_ver1<<16 | fw_ver2)); - break; } case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - DP(NETIF_MSG_LINK, - "Setting the BCM8481 LASI control\n"); + /* This phy uses the NIG latch mechanism since link + indication arrives through its LED4 and not via + its LASI signal, so we get steady signal + instead of clear on read */ + bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, + 1 << NIG_LATCH_BC_ENABLE_MI_INT); + + bnx2x_8481_set_led4(params, ext_phy_type, ext_phy_addr); + if (params->req_line_speed == SPEED_AUTO_NEG) { + + u16 autoneg_val, an_1000_val, an_10_100_val; + /* set 1000 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + &an_1000_val); - bnx2x_cl45_write(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_CTRL, 0x1); + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) { + an_1000_val |= (1<<8); + if (params->req_duplex == DUPLEX_FULL) + an_1000_val |= (1<<9); + DP(NETIF_MSG_LINK, "Advertising 1G\n"); + } else + an_1000_val &= ~((1<<8) | (1<<9)); - /* Restart autoneg */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_1000T_CTRL, + an_1000_val); + + /* set 100 speed advertisement */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + &an_10_100_val); + + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) { + an_10_100_val |= (1<<7); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<8); + DP(NETIF_MSG_LINK, + "Advertising 100M\n"); + } else + an_10_100_val &= ~((1<<7) | (1<<8)); + + /* set 10 speed advertisement */ + if (params->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) { + an_10_100_val |= (1<<5); + if (params->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<6); + DP(NETIF_MSG_LINK, "Advertising 10M\n"); + } + else + an_10_100_val &= ~((1<<5) | (1<<6)); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + an_10_100_val); + + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_val); + + /* Disable forced speed */ + autoneg_val &= ~(1<<6|1<<13); + + /* Enable autoneg and restart autoneg + for legacy speeds */ + autoneg_val |= (1<<9|1<<12); + + if (params->req_duplex == DUPLEX_FULL) + autoneg_val |= (1<<8); + else + autoneg_val &= ~(1<<8); + + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_val); + + if (params->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + DP(NETIF_MSG_LINK, "Advertising 10G\n"); + /* Restart autoneg for 10G*/ bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, @@ -3968,12 +4405,81 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ext_phy_addr, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val); + } + } else { + /* Force speed */ + u16 autoneg_ctrl, pma_ctrl; + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_ctrl); - bnx2x_save_bcm_spirom_ver(bp, params->port, - ext_phy_type, - ext_phy_addr, - params->shmem_base); + /* Disable autoneg */ + autoneg_ctrl &= ~(1<<12); + + /* Set 1000 force */ + switch (params->req_line_speed) { + case SPEED_10000: + DP(NETIF_MSG_LINK, + "Unable to set 10G force !\n"); + break; + case SPEED_1000: + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + &pma_ctrl); + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl |= (1<<6); + pma_ctrl &= ~(1<<13); + pma_ctrl |= (1<<6); + DP(NETIF_MSG_LINK, + "Setting 1000M force\n"); + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + pma_ctrl); + break; + case SPEED_100: + autoneg_ctrl |= (1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 100M force\n"); + break; + case SPEED_10: + autoneg_ctrl &= ~(1<<13); + autoneg_ctrl &= ~(1<<6); + DP(NETIF_MSG_LINK, + "Setting 10M force\n"); + break; + } + /* Duplex mode */ + if (params->req_duplex == DUPLEX_FULL) { + autoneg_ctrl |= (1<<8); + DP(NETIF_MSG_LINK, + "Setting full duplex\n"); + } else + autoneg_ctrl &= ~(1<<8); + + /* Update autoneg ctrl and pma ctrl */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, + autoneg_ctrl); + } + + /* Save spirom version */ + bnx2x_save_8481_spirom_version(bp, params->port, + ext_phy_addr, + params->shmem_base); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: DP(NETIF_MSG_LINK, @@ -4013,9 +4519,7 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) { struct bnx2x *bp = params->bp; u16 mod_abs, rx_alarm_status; - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. @@ -4104,7 +4608,8 @@ static void bnx2x_8727_handle_mod_abs(struct link_params *params) static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, - struct link_vars *vars) + struct link_vars *vars, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u32 ext_phy_type; @@ -4113,11 +4618,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, u16 rx_sd, pcs_status; u8 ext_phy_link_up = 0; u8 port = params->port; - if (vars->phy_flags & PHY_XGXS_FLAG) { - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + if (vars->phy_flags & PHY_XGXS_FLAG) { + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: @@ -4224,7 +4727,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, break; } } - if (val2 & (1<<1)) vars->line_speed = SPEED_1000; else @@ -4281,8 +4783,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, if ((val1 & (1<<8)) == 0) { DP(NETIF_MSG_LINK, "8727 Power fault" - " has been detected on port" - " %d\n", params->port); + " has been detected on " + "port %d\n", + params->port); printk(KERN_ERR PFX "Error: Power" " fault on %s Port %d has" " been detected and the" @@ -4389,6 +4892,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, { u16 link_status = 0; u16 an1000_status = 0; + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) { bnx2x_cl45_read(bp, params->port, @@ -4404,7 +4908,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, DP(NETIF_MSG_LINK, "870x LASI status 0x%x->0x%x\n", val1, val2); - } else { /* In 8073, port1 is directed through emac0 and * port0 is directed through emac1 @@ -4534,8 +5037,6 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH, 0x0333); - - } bnx2x_cl45_read(bp, params->port, ext_phy_type, @@ -4647,51 +5148,79 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, } break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: - /* Clear LASI interrupt */ - bnx2x_cl45_read(bp, params->port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_LASI_STATUS, &val1); - DP(NETIF_MSG_LINK, "8481 LASI status reg = 0x%x\n", - val1); - /* Check 10G-BaseT link status */ - /* Check Global PMD signal ok */ + /* Check PMD signal ok */ bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, - &rx_sd); - /* Check PCS block lock */ + ext_phy_addr, + MDIO_AN_DEVAD, + 0xFFFA, + &val1); bnx2x_cl45_read(bp, params->port, ext_phy_type, ext_phy_addr, - MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, - &pcs_status); - DP(NETIF_MSG_LINK, "8481 1.a = 0x%x, 1.20 = 0x%x\n", - rx_sd, pcs_status); - if (rx_sd & pcs_status & 0x1) { + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_PMD_SIGNAL, + &val2); + DP(NETIF_MSG_LINK, "PMD_SIGNAL 1.a811 = 0x%x\n", val2); + + /* Check link 10G */ + if (val2 & (1<<11)) { vars->line_speed = SPEED_10000; ext_phy_link_up = 1; - } else { - - /* Check 1000-BaseT link status */ - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val1); + bnx2x_8481_set_10G_led_mode(params, + ext_phy_type, + ext_phy_addr); + } else { /* Check Legacy speed link */ + u16 legacy_status, legacy_speed; + + /* Enable expansion register 0x42 + (Operation mode status) */ + bnx2x_cl45_write(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, + 0xf42); - bnx2x_cl45_read(bp, params->port, ext_phy_type, - ext_phy_addr, - MDIO_AN_DEVAD, 0xFFE1, - &val2); - DP(NETIF_MSG_LINK, "8481 7.FFE1 =" - "0x%x-->0x%x\n", val1, val2); - if (val2 & (1<<2)) { - vars->line_speed = SPEED_1000; - ext_phy_link_up = 1; + /* Get legacy speed operation status */ + bnx2x_cl45_read(bp, params->port, + ext_phy_type, + ext_phy_addr, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, + &legacy_status); + + DP(NETIF_MSG_LINK, "Legacy speed status" + " = 0x%x\n", legacy_status); + ext_phy_link_up = ((legacy_status & (1<<11)) + == (1<<11)); + if (ext_phy_link_up) { + legacy_speed = (legacy_status & (3<<9)); + if (legacy_speed == (0<<9)) + vars->line_speed = SPEED_10; + else if (legacy_speed == (1<<9)) + vars->line_speed = + SPEED_100; + else if (legacy_speed == (2<<9)) + vars->line_speed = + SPEED_1000; + else /* Should not happen */ + vars->line_speed = 0; + + if (legacy_status & (1<<8)) + vars->duplex = DUPLEX_FULL; + else + vars->duplex = DUPLEX_HALF; + + DP(NETIF_MSG_LINK, "Link is up " + "in %dMbps, is_duplex_full" + "= %d\n", + vars->line_speed, + (vars->duplex == DUPLEX_FULL)); + bnx2x_8481_set_legacy_led_mode(params, + ext_phy_type, + ext_phy_addr); } } - break; default: DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", @@ -4699,6 +5228,13 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ext_phy_link_up = 0; break; } + /* Set SGMII mode for external phy */ + if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + if (vars->line_speed < SPEED_1000) + vars->phy_flags |= PHY_SGMII_FLAG; + else + vars->phy_flags &= ~PHY_SGMII_FLAG; + } } else { /* SerDes */ ext_phy_type = SERDES_EXT_PHY_TYPE(params->ext_phy_config); @@ -4731,6 +5267,7 @@ static void bnx2x_link_int_enable(struct link_params *params) u32 ext_phy_type; u32 mask; struct bnx2x *bp = params->bp; + /* setting the status to report on link up for either XGXS or SerDes */ @@ -4762,10 +5299,10 @@ static void bnx2x_link_int_enable(struct link_params *params) bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, mask); - DP(NETIF_MSG_LINK, "port %x, is_xgxs=%x, int_status 0x%x\n", port, + + DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port, (params->switch_cfg == SWITCH_CFG_10G), REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); - DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n", REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), @@ -4775,12 +5312,47 @@ static void bnx2x_link_int_enable(struct link_params *params) REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); } - +static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port, + u8 is_mi_int) +{ + u32 latch_status = 0, is_mi_int_status; + /* Disable the MI INT ( external phy int ) + * by writing 1 to the status register. Link down indication + * is high-active-signal, so in this case we need to write the + * status to clear the XOR + */ + /* Read Latched signals */ + latch_status = REG_RD(bp, + NIG_REG_LATCH_STATUS_0 + port*8); + is_mi_int_status = REG_RD(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4); + DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x," + "latch_status = 0x%x\n", + is_mi_int, is_mi_int_status, latch_status); + /* Handle only those with latched-signal=up.*/ + if (latch_status & 1) { + /* For all latched-signal=up,Write original_signal to status */ + if (is_mi_int) + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + else + bnx2x_bits_dis(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + /* For all latched-signal=up : Re-Arm Latch signals */ + REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, + (latch_status & 0xfffe) | (latch_status & 1)); + } +} /* * link management */ static void bnx2x_link_int_ack(struct link_params *params, - struct link_vars *vars, u8 is_10g) + struct link_vars *vars, u8 is_10g, + u8 is_mi_int) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -4791,6 +5363,10 @@ static void bnx2x_link_int_ack(struct link_params *params, (NIG_STATUS_XGXS0_LINK10G | NIG_STATUS_XGXS0_LINK_STATUS | NIG_STATUS_SERDES0_LINK_STATUS)); + if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) + == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) { + bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int); + } if (vars->phy_link_up) { if (is_10g) { /* Disable the 10G link interrupt @@ -4810,7 +5386,8 @@ static void bnx2x_link_int_ack(struct link_params *params, PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); - DP(NETIF_MSG_LINK, "1G XGXS phy link up\n"); + DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n", + vars->line_speed); bnx2x_bits_en(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, ((1 << ser_lane) << @@ -4860,66 +5437,13 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) return 0; } - -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; - /* Enable EMAC0 in to enable MDIO */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); - msleep(5); - - /* take ext phy out of reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_HIGH, - port); - - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_HIGH, - port); - - /* wait for 5ms */ - msleep(5); - - for (cnt = 0; cnt < 1000; cnt++) { - msleep(1); - bnx2x_cl45_read(bp, port, - ext_phy_type, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, - &ctrl); - if (!(ctrl & (1<<15))) { - DP(NETIF_MSG_LINK, "Reset completed\n\n"); - break; - } - } -} - -static void bnx2x_turn_off_sf(struct bnx2x *bp, u8 port) -{ - /* put sf to reset */ - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_1, - MISC_REGISTERS_GPIO_LOW, - port); - bnx2x_set_gpio(bp, - MISC_REGISTERS_GPIO_2, - MISC_REGISTERS_GPIO_LOW, - port); -} - u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, u8 *version, u16 len) { struct bnx2x *bp; u32 ext_phy_type = 0; u32 spirom_ver = 0; - u8 status = 0 ; + u8 status; if (version == NULL || params == NULL) return -EINVAL; @@ -4929,6 +5453,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, offsetof(struct shmem_region, port_mb[params->port].ext_phy_fw_version)); + status = 0; /* reset the returned value to zero */ ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); switch (ext_phy_type) { @@ -4947,13 +5472,18 @@ 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: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + status = bnx2x_format_ver(spirom_ver, version, len); + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: + spirom_ver = ((spirom_ver & 0xF80) >> 7) << 16 | + (spirom_ver & 0x7F); status = bnx2x_format_ver(spirom_ver, version, len); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + version[0] = '\0'; break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: @@ -5036,10 +5566,8 @@ static void bnx2x_ext_phy_loopback(struct link_params *params) if (params->switch_cfg == SWITCH_CFG_10G) { ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); + ext_phy_addr = XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* CL37 Autoneg Enabled */ - ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: @@ -5206,6 +5734,7 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 rc = 0; u32 tmp; u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n", speed, hw_led_mode); @@ -5270,7 +5799,7 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) &gp_status); /* link is up only if both local phy and external phy are up */ if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) && - bnx2x_ext_phy_is_link_up(params, vars)) + bnx2x_ext_phy_is_link_up(params, vars, 1)) return 0; return -ESRCH; @@ -5284,6 +5813,7 @@ static u8 bnx2x_link_initialize(struct link_params *params, 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); @@ -5335,11 +5865,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) @@ -5358,11 +5887,11 @@ static u8 bnx2x_link_initialize(struct link_params *params, u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u32 val; - DP(NETIF_MSG_LINK, "Phy Initialization started \n"); - DP(NETIF_MSG_LINK, "req_speed = %d, req_flowctrl=%d\n", - params->req_line_speed, params->req_flow_ctrl); + + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + 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; @@ -5376,7 +5905,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) else vars->phy_flags = PHY_XGXS_FLAG; - /* disable attentions */ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, (NIG_MASK_XGXS0_LINK_STATUS | @@ -5387,6 +5915,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_init(params, vars); if (CHIP_REV_IS_FPGA(bp)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5395,7 +5924,8 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) /* enable on E1.5 FPGA */ if (CHIP_IS_E1H(bp)) { vars->flow_ctrl |= - (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX); + (BNX2X_FLOW_CTRL_TX | + BNX2X_FLOW_CTRL_RX); vars->link_status |= (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | LINK_STATUS_RX_FLOW_CONTROL_ENABLED); @@ -5404,8 +5934,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_enable(params, vars, 0); bnx2x_pbf_update(params, vars->flow_ctrl, vars->line_speed); /* disable drain */ - REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE - + params->port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); /* update shared memory */ bnx2x_update_mng(params, vars->link_status); @@ -5435,6 +5964,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else if (params->loopback_mode == LOOPBACK_BMAC) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5449,7 +5979,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if (params->loopback_mode == LOOPBACK_EMAC) { + vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; @@ -5465,8 +5997,10 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->duplex); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + } else if ((params->loopback_mode == LOOPBACK_XGXS_10) || - (params->loopback_mode == LOOPBACK_EXT_PHY)) { + (params->loopback_mode == LOOPBACK_EXT_PHY)) { + vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -5503,7 +6037,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } else /* No loopback */ { - bnx2x_phy_deassert(params, vars->phy_flags); switch (params->switch_cfg) { case SWITCH_CFG_1G: @@ -5511,8 +6044,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) if ((params->ext_phy_config & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482) { - vars->phy_flags |= - PHY_SGMII_FLAG; + vars->phy_flags |= PHY_SGMII_FLAG; } val = REG_RD(bp, @@ -5533,7 +6065,6 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) default: DP(NETIF_MSG_LINK, "Invalid switch_cfg\n"); return -EINVAL; - break; } DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr); @@ -5558,7 +6089,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr) u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u8 reset_ext_phy) { - struct bnx2x *bp = params->bp; u32 ext_phy_config = params->ext_phy_config; u16 hw_led_mode = params->hw_led_mode; @@ -5571,7 +6101,6 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, config)); /* disable attentions */ - vars->link_status = 0; bnx2x_update_mng(params, vars->link_status); bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, @@ -5609,9 +6138,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, { /* Disable Transmitter */ - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) bnx2x_sfp_set_transmitter(bp, port, @@ -5629,9 +6157,8 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: { - u8 ext_phy_addr = ((params->ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + u8 ext_phy_addr = + XGXS_EXT_PHY_ADDR(params->ext_phy_config); /* Set soft reset */ bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr); break; @@ -5669,6 +6196,7 @@ static u8 bnx2x_update_link_down(struct link_params *params, { 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, @@ -5705,6 +6233,7 @@ static u8 bnx2x_update_link_up(struct link_params *params, 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); @@ -5758,16 +6287,19 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) u8 link_10g; u8 ext_phy_link_up, rc = 0; u32 ext_phy_type; + u8 is_mi_int = 0; DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", - port, - (vars->phy_flags & PHY_XGXS_FLAG), - REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + port, (vars->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + + port*0x18) > 0); DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", - REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), - REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), - REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + is_mi_int, + REG_RD(bp, + NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), @@ -5779,7 +6311,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config); /* Check external link change only for non-direct */ - ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars); + ext_phy_link_up = bnx2x_ext_phy_is_link_up(params, vars, is_mi_int); /* Read gp_status */ CL45_RD_OVER_CL22(bp, port, params->phy_addr, @@ -5787,7 +6319,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) MDIO_GP_STATUS_TOP_AN_STATUS1, &gp_status); - rc = bnx2x_link_settings_status(params, vars, gp_status); + rc = bnx2x_link_settings_status(params, vars, gp_status, + ext_phy_link_up); if (rc != 0) return rc; @@ -5799,7 +6332,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) (vars->line_speed == SPEED_15000) || (vars->line_speed == SPEED_16000)); - bnx2x_link_int_ack(params, vars, link_10g); + bnx2x_link_int_ack(params, vars, link_10g, is_mi_int); /* In case external phy link is up, and internal link is down ( not initialized yet probably after link initialization, it needs @@ -5812,7 +6345,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); @@ -5845,10 +6378,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Need to take the phy out of low power mode in order to write to access its registers */ @@ -5946,17 +6476,22 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) { u8 ext_phy_addr[PORT_MAX]; - s8 port; + s8 port, first_port, i; u32 swap_val, swap_override; DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n"); swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); - bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override)); + bnx2x_ext_phy_hw_reset(bp, 1 ^ (swap_val && swap_override)); msleep(5); + if (swap_val && swap_override) + first_port = PORT_0; + else + first_port = PORT_1; + /* PART1 - Reset both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { /* Extract the ext phy address for the port */ u32 ext_phy_config = REG_RD(bp, shmem_base + offsetof(struct shmem_region, @@ -5969,9 +6504,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) NIG_MASK_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); - ext_phy_addr[port] = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr[port] = XGXS_EXT_PHY_ADDR(ext_phy_config); /* Reset the phy */ bnx2x_cl45_write(bp, port, @@ -5986,7 +6519,7 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) msleep(150); /* PART2 - Download firmware to both phys */ - for (port = PORT_MAX - 1; port >= PORT_0; port--) { + for (i = 0, port = first_port; i < PORT_MAX; i++, port = !port) { u16 fw_ver1; bnx2x_bcm8727_external_rom_boot(bp, port, @@ -5998,16 +6531,13 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base) MDIO_PMA_REG_ROM_VER1, &fw_ver1); if (fw_ver1 == 0 || fw_ver1 == 0x4321) { DP(NETIF_MSG_LINK, - "bnx2x_8073_common_init_phy port %x:" + "bnx2x_8727_common_init_phy port %x:" "Download failed. fw version = 0x%x\n", port, fw_ver1); return -EINVAL; } - } - - return 0; } @@ -6017,6 +6547,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) u8 ext_phy_addr; u32 val; s8 port; + /* Use port1 because of the static port-swap */ /* Enable the module detection interrupt */ val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); @@ -6024,7 +6555,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT))); REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val); - bnx2x_hw_reset(bp, 1); + bnx2x_ext_phy_hw_reset(bp, 1); msleep(5); for (port = 0; port < PORT_MAX; port++) { /* Extract the ext phy address for the port */ @@ -6032,10 +6563,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base) offsetof(struct shmem_region, dev_info.port_hw_config[port].external_phy_config)); - ext_phy_addr = - ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + ext_phy_addr = XGXS_EXT_PHY_ADDR(ext_phy_config); DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n", ext_phy_addr); @@ -6091,9 +6619,7 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) return rc; } - - -static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) { u16 val, cnt; @@ -6123,377 +6649,3 @@ static void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, u8 port, u8 phy_addr) break; } } -#define RESERVED_SIZE 256 -/* max application is 160K bytes - data at end of RAM */ -#define MAX_APP_SIZE (160*1024 - RESERVED_SIZE) - -/* Header is 14 bytes */ -#define HEADER_SIZE 14 -#define DATA_OFFSET HEADER_SIZE - -#define SPI_START_TRANSFER(bp, port, ext_phy_addr) \ - bnx2x_cl45_write(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, \ - ext_phy_addr, \ - MDIO_PCS_DEVAD, \ - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 1) - -/* Programs an image to DSP's flash via the SPI port*/ -static u8 bnx2x_sfx7101_flash_download(struct bnx2x *bp, u8 port, - u8 ext_phy_addr, - char data[], u32 size) -{ - const u16 num_trans = size/4; /* 4 bytes can be sent at a time */ - /* Doesn't include last trans!*/ - const u16 last_trans_size = size%4; /* Num bytes on last trans */ - u16 trans_cnt, byte_cnt; - u32 data_index; - u16 tmp; - u16 code_started = 0; - u16 image_revision1, image_revision2; - u16 cnt; - - DP(NETIF_MSG_LINK, "bnx2x_sfx7101_flash_download file_size=%d\n", size); - /* Going to flash*/ - if ((size-HEADER_SIZE) > MAX_APP_SIZE) { - /* This very often will be the case, because the image is built - with 160Kbytes size whereas the total image size must actually - be 160Kbytes-RESERVED_SIZE */ - DP(NETIF_MSG_LINK, "Warning, file size was %d bytes " - "truncated to %d bytes\n", size, MAX_APP_SIZE); - size = MAX_APP_SIZE+HEADER_SIZE; - } - DP(NETIF_MSG_LINK, "File version is %c%c\n", data[0x14e], data[0x14f]); - DP(NETIF_MSG_LINK, " %c%c\n", data[0x150], data[0x151]); - /* Put the DSP in download mode by setting FLASH_CFG[2] to 1 - and issuing a reset.*/ - - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_HIGH, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Make sure we can access the DSP - And it's in the correct mode (waiting for download) */ - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, &tmp); - - if (tmp != 0x000A) { - DP(NETIF_MSG_LINK, "DSP is not in waiting on download mode. " - "Expected 0x000A, read 0x%04X\n", tmp); - DP(NETIF_MSG_LINK, "Download failed\n"); - return -EINVAL; - } - - /* Mux the SPI interface away from the internal processor */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_MUX, 1); - - /* Reset the SPI port */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, - (1<<MDIO_PCS_REG_7101_SPI_RESET_BIT)); - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_CTRL_ADDR, 0); - - /* Erase the flash */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_BULK_ERASE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - SPI_START_TRANSFER(bp, port, ext_phy_addr); - - /* Wait 10 seconds, the maximum time for the erase to complete */ - DP(NETIF_MSG_LINK, "Erasing flash, this takes 10 seconds...\n"); - for (cnt = 0; cnt < 1000; cnt++) - msleep(10); - - DP(NETIF_MSG_LINK, "Downloading flash, please wait...\n"); - data_index = 0; - for (trans_cnt = 0; trans_cnt < num_trans; trans_cnt++) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - SPI_START_TRANSFER(bp, port, ext_phy_addr); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); - - /* Bits 23-16 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < 4 && data_index < size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - msleep(5); /* Wait 5 ms minimum between transs */ - - /* Let the user know something's going on.*/ - /* a pacifier ever 4K */ - if ((data_index % 1023) == 0) - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - } - - DP(NETIF_MSG_LINK, "\n"); - /* Transfer the last block if there is data remaining */ - if (last_trans_size) { - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_WRITE_ENABLE_CMD); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - 1); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR_PAGE_PROGRAM_CMD); - - /* Bits 23-16 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>16)); - /* Bits 15-8 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - (data_index>>8)); - - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - ((u16)data_index)); - - byte_cnt = 0; - while (byte_cnt < last_trans_size && data_index < size) { - /* Bits 7-0 of address */ - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_FIFO_ADDR, - data[data_index++]); - byte_cnt++; - } - - bnx2x_cl45_write(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_SPI_BYTES_TO_TRANSFER_ADDR, - byte_cnt+4); - - SPI_START_TRANSFER(bp, port, ext_phy_addr); - } - - /* DSP Remove Download Mode */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, - MISC_REGISTERS_GPIO_LOW, port); - - bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr); - - /* wait 0.5 sec to allow it to run */ - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - bnx2x_hw_reset(bp, port); - - for (cnt = 0; cnt < 100; cnt++) - msleep(5); - - /* Check that the code is started. In case the download - checksum failed, the code won't be started. */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PCS_DEVAD, - MDIO_PCS_REG_7101_DSP_ACCESS, - &tmp); - - code_started = (tmp & (1<<4)); - if (!code_started) { - DP(NETIF_MSG_LINK, "Download failed. Please check file.\n"); - return -EINVAL; - } - - /* Verify that the file revision is now equal to the image - revision within the DSP */ - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER1, - &image_revision1); - - bnx2x_cl45_read(bp, port, - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, - ext_phy_addr, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_7101_VER2, - &image_revision2); - - if (data[0x14e] != (image_revision2&0xFF) || - data[0x14f] != ((image_revision2&0xFF00)>>8) || - data[0x150] != (image_revision1&0xFF) || - data[0x151] != ((image_revision1&0xFF00)>>8)) { - DP(NETIF_MSG_LINK, "Download failed.\n"); - return -EINVAL; - } - DP(NETIF_MSG_LINK, "Download %d%%\n", data_index/size); - return 0; -} - -u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, - u8 driver_loaded, char data[], u32 size) -{ - u8 rc = 0; - u32 ext_phy_type; - u8 ext_phy_addr; - ext_phy_addr = ((ext_phy_config & - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> - PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); - - ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); - - switch (ext_phy_type) { - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: - DP(NETIF_MSG_LINK, - "Flash download not supported for this ext phy\n"); - rc = -EINVAL; - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: - /* Take ext phy out of reset */ - if (!driver_loaded) - 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) - bnx2x_turn_off_sf(bp, port); - break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN: - default: - DP(NETIF_MSG_LINK, "Invalid ext phy type\n"); - rc = -EINVAL; - break; - } - return rc; -} - |