Commit b7737c9b authored by Yaniv Rosner's avatar Yaniv Rosner Committed by David S. Miller

bnx2x: Split PHY functions

Move the code into PHY oriented functions, and for that a new structure
is defines for each PHY which contain PHY properties and its own
functions. This also enables to encapsulate all PHY specific operations
into the PHY functions. During initialization, the PHYs will be probed
by the "bnx2x_phy_probe" function to detect which PHYs exist on-board,
and configure them accordingly. Note that the ext_phy_reset
implementation was incorporated in the ext_phy_init since it is actually
part of the PHY initialization procedure.
Signed-off-by: default avatarYaniv Rosner <yanivr@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e10bc84d
...@@ -52,39 +52,14 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -52,39 +52,14 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->duplex = -1; cmd->duplex = -1;
} }
if (bp->link_params.switch_cfg == SWITCH_CFG_10G) { if (bp->link_params.num_phys > 0) {
u32 ext_phy_type = if (bp->link_params.phy[bp->link_params.num_phys - 1].
XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); supported & SUPPORTED_FIBRE)
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
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:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
cmd->port = PORT_FIBRE; cmd->port = PORT_FIBRE;
break; else
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
cmd->port = PORT_TP; cmd->port = PORT_TP;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
bp->link_params.ext_phy_config);
break;
default:
DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
bp->link_params.ext_phy_config);
break;
}
} else } else
cmd->port = PORT_TP; DP(NETIF_MSG_LINK, "No media found\n");
cmd->phy_address = bp->mdio.prtad; cmd->phy_address = bp->mdio.prtad;
cmd->transceiver = XCVR_INTERNAL; cmd->transceiver = XCVR_INTERNAL;
......
...@@ -1776,16 +1776,20 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, ...@@ -1776,16 +1776,20 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
bnx2x_restart_autoneg(phy, params, 0); bnx2x_restart_autoneg(phy, params, 0);
DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n");
} }
static u8 bnx2x_link_settings_status(struct link_params *params, static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
struct link_vars *vars, struct link_params *params,
u32 gp_status, struct link_vars *vars)
u8 ext_phy_link_up)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u16 new_line_speed; u16 new_line_speed , gp_status;
u8 rc = 0; u8 rc = 0;
u32 ext_phy_type; u32 ext_phy_type;
vars->link_status = 0; /* Read gp_status */
CL45_RD_OVER_CL22(bp, phy,
MDIO_REG_BANK_GP_STATUS,
MDIO_GP_STATUS_TOP_AN_STATUS1,
&gp_status);
if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n", DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
gp_status); gp_status);
...@@ -1881,23 +1885,6 @@ static u8 bnx2x_link_settings_status(struct link_params *params, ...@@ -1881,23 +1885,6 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
return -EINVAL; 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 (!SINGLE_MEDIA_DIRECT(params) &&
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);
}
vars->line_speed = new_line_speed; vars->line_speed = new_line_speed;
vars->link_status |= LINK_STATUS_SERDES_LINK; vars->link_status |= LINK_STATUS_SERDES_LINK;
ext_phy_type = params->phy[EXT_PHY1].type; ext_phy_type = params->phy[EXT_PHY1].type;
...@@ -2001,7 +1988,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params) ...@@ -2001,7 +1988,7 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
} }
static u8 bnx2x_emac_program(struct link_params *params, static u8 bnx2x_emac_program(struct link_params *params,
u32 line_speed, u32 duplex) struct link_vars *vars)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u8 port = params->port; u8 port = params->port;
...@@ -2013,7 +2000,7 @@ static u8 bnx2x_emac_program(struct link_params *params, ...@@ -2013,7 +2000,7 @@ static u8 bnx2x_emac_program(struct link_params *params,
(EMAC_MODE_25G_MODE | (EMAC_MODE_25G_MODE |
EMAC_MODE_PORT_MII_10M | EMAC_MODE_PORT_MII_10M |
EMAC_MODE_HALF_DUPLEX)); EMAC_MODE_HALF_DUPLEX));
switch (line_speed) { switch (vars->line_speed) {
case SPEED_10: case SPEED_10:
mode |= EMAC_MODE_PORT_MII_10M; mode |= EMAC_MODE_PORT_MII_10M;
break; break;
...@@ -2032,152 +2019,84 @@ static u8 bnx2x_emac_program(struct link_params *params, ...@@ -2032,152 +2019,84 @@ static u8 bnx2x_emac_program(struct link_params *params,
default: default:
/* 10G not valid for EMAC */ /* 10G not valid for EMAC */
DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", line_speed); DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
vars->line_speed);
return -EINVAL; return -EINVAL;
} }
if (duplex == DUPLEX_HALF) if (vars->duplex == DUPLEX_HALF)
mode |= EMAC_MODE_HALF_DUPLEX; mode |= EMAC_MODE_HALF_DUPLEX;
bnx2x_bits_en(bp, bnx2x_bits_en(bp,
GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
mode); mode);
bnx2x_set_led(params, LED_MODE_OPER, line_speed); bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
return 0; return 0;
} }
static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
/*****************************************************************************/ struct link_params *params,
/* External Phy section */ struct link_vars *vars)
/*****************************************************************************/
void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
{ {
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, u8 rc;
MISC_REGISTERS_GPIO_OUTPUT_LOW, port); vars->phy_flags |= PHY_SGMII_FLAG;
msleep(1); bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, bnx2x_set_aer_mmd(params, phy);
MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); rc = bnx2x_reset_unicore(params, phy, 1);
/* reset the SerDes and wait for reset bit return low */
if (rc != 0)
return rc;
bnx2x_set_aer_mmd(params, phy);
return rc;
} }
static void bnx2x_ext_phy_reset(struct bnx2x_phy *phy, static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
struct link_params *params, struct link_params *params,
struct link_vars *vars) struct link_vars *vars)
{ {
struct bnx2x *bp = params->bp; u8 rc;
DP(NETIF_MSG_LINK, "Port %x: bnx2x_ext_phy_reset\n", params->port); vars->phy_flags = PHY_XGXS_FLAG;
/* The PHY reset is controled by GPIO 1 if ((phy->req_line_speed &&
* Give it 1ms of reset pulse ((phy->req_line_speed == SPEED_100) ||
*/ (phy->req_line_speed == SPEED_10))) ||
switch (phy->type) { (!phy->req_line_speed &&
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: (phy->speed_cap_mask >=
DP(NETIF_MSG_LINK, "XGXS Direct\n"); PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
break; (phy->speed_cap_mask <
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: ))
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: vars->phy_flags |= PHY_SGMII_FLAG;
DP(NETIF_MSG_LINK, "XGXS 8705/8706\n"); else
vars->phy_flags &= ~PHY_SGMII_FLAG;
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0xa040);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
bnx2x_cl45_write(bp, phy,
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 */ bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
/* Restore normal power mode*/ bnx2x_set_aer_mmd(params, phy);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, bnx2x_set_master_ln(params, phy);
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
bnx2x_cl45_write(bp, phy, rc = bnx2x_reset_unicore(params, phy, 0);
MDIO_PMA_DEVAD, /* reset the SerDes and wait for reset bit return low */
MDIO_PMA_REG_CTRL, if (rc != 0)
1<<15); return rc;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: bnx2x_set_aer_mmd(params, phy);
DP(NETIF_MSG_LINK, "XGXS 8073\n");
/* Restore normal power mode*/ /* setting the masterLn_def again after the reset */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, bnx2x_set_master_ln(params, phy);
MISC_REGISTERS_GPIO_OUTPUT_HIGH, bnx2x_set_swap_lanes(params, phy);
params->port);
return rc;
}
/*****************************************************************************/
/* External Phy section */
/*****************************************************************************/
void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port)
{
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
params->port);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
/* HW reset */
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_ext_phy_hw_reset(bp, params->port);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL,
1<<15);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
msleep(1); msleep(1);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, MISC_REGISTERS_GPIO_OUTPUT_HIGH, port);
params->port);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
DP(NETIF_MSG_LINK, "XGXS PHY Failure detected\n");
break;
default:
DP(NETIF_MSG_LINK, "BAD phy type 0x%x\n",
phy->type);
break;
}
} }
static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port,
...@@ -2498,11 +2417,13 @@ static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy, ...@@ -2498,11 +2417,13 @@ static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy,
static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, static void bnx2x_sfp_set_transmitter(struct bnx2x *bp,
struct bnx2x_phy *phy, struct bnx2x_phy *phy,
u8 port,
u8 tx_en) u8 tx_en)
{ {
u16 val; u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x\n", tx_en); 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.)*/ /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
...@@ -2946,9 +2867,10 @@ static void bnx2x_8727_power_module(struct bnx2x *bp, ...@@ -2946,9 +2867,10 @@ static void bnx2x_8727_power_module(struct bnx2x *bp,
* In case of NOC feature is disabled and power is up, set GPIO control * In case of NOC feature is disabled and power is up, set GPIO control
* as input to enable listening of over-current indication * as input to enable listening of over-current indication
*/ */
if (phy->flags & FLAGS_NOC)
if (!(params->feature_config_flags & return;
FEATURE_CONFIG_BCM8727_NOC) && is_power_up) if (!(phy->flags &
FLAGS_NOC) && is_power_up)
val = (1<<4); val = (1<<4);
else else
/* /*
...@@ -3022,9 +2944,9 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, ...@@ -3022,9 +2944,9 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
if (rc == 0 || if (rc == 0 ||
(val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
bnx2x_sfp_set_transmitter(bp, phy, 1); bnx2x_sfp_set_transmitter(bp, phy, params->port, 1);
else else
bnx2x_sfp_set_transmitter(bp, phy, 0); bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
return rc; return rc;
} }
...@@ -3068,7 +2990,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) ...@@ -3068,7 +2990,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
/* Disable transmit for this module */ /* Disable transmit for this module */
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
bnx2x_sfp_set_transmitter(bp, phy, 0); bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
} }
} }
...@@ -3233,7 +3155,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, ...@@ -3233,7 +3155,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
CL45_WR_OVER_CL22(bp, phy, CL45_WR_OVER_CL22(bp, phy,
bank, bank,
MDIO_RX0_RX_EQ_BOOST, MDIO_RX0_RX_EQ_BOOST,
params->xgxs_config_rx[i]); phy->rx_preemphasis[i]);
} }
for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3; for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
...@@ -3241,7 +3163,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, ...@@ -3241,7 +3163,7 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
CL45_WR_OVER_CL22(bp, phy, CL45_WR_OVER_CL22(bp, phy,
bank, bank,
MDIO_TX0_TX_DRIVER, MDIO_TX0_TX_DRIVER,
params->xgxs_config_tx[i]); phy->tx_preemphasis[i]);
} }
} }
...@@ -3331,24 +3253,10 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, ...@@ -3331,24 +3253,10 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
} }
} }
static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) static u16 bnx2x_wait_reset_complete(struct bnx2x *bp,
struct bnx2x_phy *phy)
{ {
struct bnx2x *bp = params->bp; u16 cnt, ctrl;
u16 cnt;
u16 ctrl = 0;
u16 val = 0;
u8 rc = 0;
struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
if (vars->phy_flags & PHY_XGXS_FLAG) {
/* Make sure that the soft reset is off (expect for the 8072:
* due to the lock, it will be done inside the specific
* handling)
*/
if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
(phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
(phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
(phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) &&
(phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) {
/* Wait for soft reset to get cleared upto 1 sec */ /* Wait for soft reset to get cleared upto 1 sec */
for (cnt = 0; cnt < 1000; cnt++) { for (cnt = 0; cnt < 1000; cnt++) {
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -3360,13 +3268,22 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3360,13 +3268,22 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
} }
DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n",
ctrl, cnt); ctrl, cnt);
} return 0;
}
switch (phy->type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "init 8705\n");
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
bnx2x_wait_reset_complete(bp, phy);
DP(NETIF_MSG_LINK, "XGXS 8705\n"); DP(NETIF_MSG_LINK, "XGXS 8705\n");
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
...@@ -3388,9 +3305,23 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3388,9 +3305,23 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
/* BCM8705 doesn't have microcode, hence the 0 */ /* BCM8705 doesn't have microcode, hence the 0 */
bnx2x_save_spirom_version(bp, params->port, bnx2x_save_spirom_version(bp, params->port,
params->shmem_base, 0); params->shmem_base, 0);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: return 0;
}
static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
u16 cnt, val;
struct bnx2x *bp = params->bp;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040);
bnx2x_wait_reset_complete(bp, phy);
/* Wait until fw is loaded */ /* Wait until fw is loaded */
for (cnt = 0; cnt < 100; cnt++) { for (cnt = 0; cnt < 100; cnt++) {
bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
...@@ -3416,7 +3347,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3416,7 +3347,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
val &= ~0x7; val &= ~0x7;
/* Set control bits according to /* Set control bits according to
configuation */ configuation */
val |= (params->xgxs_config_rx[i] & val |= (phy->rx_preemphasis[i] &
0x7); 0x7);
DP(NETIF_MSG_LINK, "Setting RX" DP(NETIF_MSG_LINK, "Setting RX"
"Equalizer to BCM8706 reg 0x%x" "Equalizer to BCM8706 reg 0x%x"
...@@ -3479,8 +3410,26 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3479,8 +3410,26 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_save_bcm_spirom_ver(bp, params->port, bnx2x_save_bcm_spirom_ver(bp, params->port,
phy, phy,
params->shmem_base); params->shmem_base);
break; return 0;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: }
static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
bnx2x_wait_reset_complete(bp, phy);
bnx2x_wait_reset_complete(bp, phy);
DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
bnx2x_8726_external_rom_boot(phy, params); bnx2x_8726_external_rom_boot(phy, params);
...@@ -3538,21 +3487,39 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3538,21 +3487,39 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x," DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
"TX_CTRL2 0x%x\n", "TX_CTRL2 0x%x\n",
params->xgxs_config_tx[0], phy->tx_preemphasis[0],
params->xgxs_config_tx[1]); phy->tx_preemphasis[1]);
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TX_CTRL1, MDIO_PMA_REG_8726_TX_CTRL1,
params->xgxs_config_tx[0]); phy->tx_preemphasis[0]);
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TX_CTRL2, MDIO_PMA_REG_8726_TX_CTRL2,
params->xgxs_config_tx[1]); phy->tx_preemphasis[1]);
} }
break; return 0;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: }
static u8 bnx2x_8072_8073_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u16 val = 0;
u8 gpio_port;
DP(NETIF_MSG_LINK, "Init 8073\n");
gpio_port = params->port;
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port);
{ {
u16 tmp1; u16 tmp1;
u16 rx_alarm_ctrl_val; u16 rx_alarm_ctrl_val;
...@@ -3606,7 +3573,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3606,7 +3573,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_807x_force_10G(bp, phy); bnx2x_807x_force_10G(bp, phy);
DP(NETIF_MSG_LINK, DP(NETIF_MSG_LINK,
"Forced speed 10G on 807X\n"); "Forced speed 10G on 807X\n");
break; return 0;
} else { } else {
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
...@@ -3728,21 +3695,25 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3728,21 +3695,25 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
"Advertise 1G=%x, 10G=%x\n", "Advertise 1G=%x, 10G=%x\n",
((val & (1<<5)) > 0), ((val & (1<<5)) > 0),
((val & (1<<7)) > 0)); ((val & (1<<7)) > 0));
break; return 0;
} }
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
{ struct link_params *params,
u16 tmp1; struct link_vars *vars)
{
u16 tmp1, val, mod_abs;
u16 rx_alarm_ctrl_val; u16 rx_alarm_ctrl_val;
u16 lasi_ctrl_val; u16 lasi_ctrl_val;
struct bnx2x *bp = params->bp;
/* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
/* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
u16 mod_abs;
rx_alarm_ctrl_val = (1<<2) | (1<<5) ; rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
lasi_ctrl_val = 0x0004; lasi_ctrl_val = 0x0004;
bnx2x_wait_reset_complete(bp, phy);
DP(NETIF_MSG_LINK, "Initializing BCM8727\n"); DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
/* enable LASI */ /* enable LASI */
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
...@@ -3861,28 +3832,39 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3861,28 +3832,39 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x," DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
"TX_CTRL2 0x%x\n", "TX_CTRL2 0x%x\n",
params->xgxs_config_tx[0], phy->tx_preemphasis[0],
params->xgxs_config_tx[1]); phy->tx_preemphasis[1]);
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TX_CTRL1, MDIO_PMA_REG_8727_TX_CTRL1,
params->xgxs_config_tx[0]); phy->tx_preemphasis[0]);
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TX_CTRL2, MDIO_PMA_REG_8727_TX_CTRL2,
params->xgxs_config_tx[1]); phy->tx_preemphasis[1]);
} }
break; return 0;
} }
static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
u16 fw_ver1, fw_ver2, val;
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n");
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
{
u16 fw_ver1, fw_ver2;
DP(NETIF_MSG_LINK, DP(NETIF_MSG_LINK,
"Setting the SFX7101 LASI indication\n"); "Setting the SFX7101 LASI indication\n");
bnx2x_wait_reset_complete(bp, phy);
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_LASI_CTRL, 0x1); MDIO_PMA_REG_LASI_CTRL, 0x1);
...@@ -3912,10 +3894,14 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3912,10 +3894,14 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_save_spirom_version(params->bp, params->port, bnx2x_save_spirom_version(params->bp, params->port,
params->shmem_base, params->shmem_base,
(u32)(fw_ver1<<16 | fw_ver2)); (u32)(fw_ver1<<16 | fw_ver2));
break; return 0;
} }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823: static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
{ {
/* This phy uses the NIG latch mechanism since link /* This phy uses the NIG latch mechanism since link
indication arrives through its LED4 and not via indication arrives through its LED4 and not via
...@@ -3924,6 +3910,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -3924,6 +3910,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
u16 autoneg_val, an_1000_val, an_10_100_val, temp; u16 autoneg_val, an_1000_val, an_10_100_val, temp;
temp = vars->line_speed; temp = vars->line_speed;
vars->line_speed = SPEED_10000; vars->line_speed = SPEED_10000;
bnx2x_wait_reset_complete(bp, phy);
bnx2x_set_autoneg(phy, params, vars, 0); bnx2x_set_autoneg(phy, params, vars, 0);
bnx2x_program_serdes(phy, params, vars); bnx2x_program_serdes(phy, params, vars);
vars->line_speed = temp; vars->line_speed = temp;
...@@ -4052,24 +4039,49 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -4052,24 +4039,49 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
/* Save spirom version */ /* Save spirom version */
bnx2x_save_8481_spirom_version(phy, params, bnx2x_save_8481_spirom_version(phy, params,
params->shmem_base); params->shmem_base);
break; return 0;
} }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: }
DP(NETIF_MSG_LINK,
"XGXS PHY Failure detected 0x%x\n",
phy->type);
rc = -EINVAL;
break;
default: static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", struct link_params *params,
phy->type); struct link_vars *vars)
break; {
} struct bnx2x *bp = params->bp;
} u16 temp;
return rc; msleep(1);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
msleep(200); /* 100 is not enough */
/**
* BCM84823 requires that XGXS links up first @ 10G for normal
* behavior
*/
temp = vars->line_speed;
vars->line_speed = SPEED_10000;
bnx2x_set_autoneg(phy, params, vars, 0);
bnx2x_program_serdes(phy, params, vars);
vars->line_speed = temp;
return bnx2x_848xx_cmn_config_init(phy, params, vars);
} }
static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
return bnx2x_848xx_cmn_config_init(phy, params, vars);
}
static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
struct link_params *params) struct link_params *params)
{ {
...@@ -4134,7 +4146,7 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, ...@@ -4134,7 +4146,7 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
bnx2x_sfp_set_transmitter(bp, phy, 0); bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
bnx2x_sfp_module_detection(phy, params); bnx2x_sfp_module_detection(phy, params);
...@@ -4148,25 +4160,13 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, ...@@ -4148,25 +4160,13 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
module plugged in/out */ module plugged in/out */
} }
static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy,
static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
struct link_params *params, struct link_params *params,
struct link_vars *vars, struct link_vars *vars)
u8 is_mi_int)
{ {
struct bnx2x *bp = params->bp;
u16 val1 = 0, val2;
u16 rx_sd, pcs_status;
u8 ext_phy_link_up = 0; u8 ext_phy_link_up = 0;
u16 val1, rx_sd;
if (vars->phy_flags & PHY_XGXS_FLAG) { struct bnx2x *bp = params->bp;
switch (phy->type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
DP(NETIF_MSG_LINK, "XGXS Direct\n");
ext_phy_link_up = 1;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
DP(NETIF_MSG_LINK, "XGXS 8705\n"); DP(NETIF_MSG_LINK, "XGXS 8705\n");
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
MDIO_WIS_DEVAD, MDIO_WIS_DEVAD,
...@@ -4194,10 +4194,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4194,10 +4194,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
((val1 & (1<<8)) == 0)); ((val1 & (1<<8)) == 0));
if (ext_phy_link_up) if (ext_phy_link_up)
vars->line_speed = SPEED_10000; vars->line_speed = SPEED_10000;
break; return ext_phy_link_up;
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: struct link_params *params,
struct link_vars *vars)
{
u8 link_up = 0;
u16 val1, val2, rx_sd, pcs_status;
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "XGXS 8706/8726\n"); DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
/* Clear RX Alarm*/ /* Clear RX Alarm*/
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -4233,35 +4239,54 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4233,35 +4239,54 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
* bit 0 of pcs_status are set, or if the autoneg bit * bit 0 of pcs_status are set, or if the autoneg bit
1 is set 1 is set
*/ */
ext_phy_link_up = ((rx_sd & pcs_status & 0x1) || link_up = ((rx_sd & pcs_status & 0x1) ||
(val2 & (1<<1))); (val2 & (1<<1)));
if (ext_phy_link_up) { if (link_up) {
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
/* 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)) {
DP(NETIF_MSG_LINK, "Tx is "
"disabled\n");
ext_phy_link_up = 0;
break;
}
}
if (val2 & (1<<1)) if (val2 & (1<<1))
vars->line_speed = SPEED_1000; vars->line_speed = SPEED_1000;
else else
vars->line_speed = SPEED_10000; vars->line_speed = SPEED_10000;
bnx2x_ext_phy_resolve_fc(phy, params, vars);
return link_up;
} }
break; return 0;
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
{ struct link_params *params,
struct link_vars *vars)
{
return bnx2x_8706_8726_read_status(phy, params, vars);
}
static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u16 val1;
u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars);
if (link_up) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER,
&val1);
if (val1 & (1<<15)) {
DP(NETIF_MSG_LINK, "Tx is disabled\n");
link_up = 0;
vars->line_speed = 0;
}
}
return link_up;
}
static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u8 ext_phy_link_up = 0;
u16 link_status = 0; u16 link_status = 0;
u16 rx_alarm_status; u16 rx_alarm_status, val1;
/* Check the LASI */ /* Check the LASI */
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
...@@ -4288,8 +4313,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4288,8 +4313,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
* If a module is present and there is need to check * If a module is present and there is need to check
* for over current * for over current
*/ */
if (!(params->feature_config_flags & if (!(phy->flags & FLAGS_NOC) &&
FEATURE_CONFIG_BCM8727_NOC) &&
!(rx_alarm_status & (1<<5))) { !(rx_alarm_status & (1<<5))) {
/* Check over-current using 8727 GPIO0 input*/ /* Check over-current using 8727 GPIO0 input*/
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -4328,7 +4352,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4328,7 +4352,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_ALARM, MDIO_PMA_REG_RX_ALARM,
&rx_alarm_status); &rx_alarm_status);
break; return ext_phy_link_up;
} }
} /* Over current check */ } /* Over current check */
...@@ -4351,7 +4375,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4351,7 +4375,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
if (val1 & (1<<15)) { if (val1 & (1<<15)) {
DP(NETIF_MSG_LINK, "Tx is disabled\n"); DP(NETIF_MSG_LINK, "Tx is disabled\n");
ext_phy_link_up = 0; ext_phy_link_up = 0;
break; return ext_phy_link_up;
} }
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -4378,12 +4402,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4378,12 +4402,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
"port %x: External link" "port %x: External link"
" is down\n", params->port); " is down\n", params->port);
} }
break; return ext_phy_link_up;
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
{ struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u8 ext_phy_link_up = 0;
u16 val1, val2;
u16 link_status = 0; u16 link_status = 0;
u16 an1000_status = 0; u16 an1000_status = 0;
...@@ -4456,7 +4484,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4456,7 +4484,7 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
if (bnx2x_8073_xaui_wa(bp, phy) if (bnx2x_8073_xaui_wa(bp, phy)
!= 0) { != 0) {
ext_phy_link_up = 0; ext_phy_link_up = 0;
break; return ext_phy_link_up;
} }
} }
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -4561,9 +4589,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4561,9 +4589,16 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
} }
} }
break; return ext_phy_link_up;
} }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u8 ext_phy_link_up;
u16 val1, val2;
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_LASI_STATUS, &val2); MDIO_PMA_REG_LASI_STATUS, &val2);
...@@ -4597,9 +4632,17 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4597,9 +4632,17 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
val2, val2,
(val2 & (1<<14))); (val2 & (1<<14)));
} }
break; return ext_phy_link_up;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
u16 val1, val2;
u8 ext_phy_link_up = 0;
/* Check 10G-BaseT link status */ /* Check 10G-BaseT link status */
/* Check PMD signal ok */ /* Check PMD signal ok */
bnx2x_cl45_read(bp, phy, bnx2x_cl45_read(bp, phy,
...@@ -4661,26 +4704,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy, ...@@ -4661,26 +4704,9 @@ static u8 bnx2x_ext_phy_is_link_up(struct bnx2x_phy *phy,
(vars->duplex == DUPLEX_FULL)); (vars->duplex == DUPLEX_FULL));
} }
} }
break;
default:
DP(NETIF_MSG_LINK,
"BAD SerDes ext_phy_config 0x%x\n",
phy->type);
ext_phy_link_up = 0;
break;
}
}
/* Set SGMII mode for external phy */
if (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;
}
return ext_phy_link_up; return ext_phy_link_up;
} }
static void bnx2x_link_int_enable(struct link_params *params) static void bnx2x_link_int_enable(struct link_params *params)
{ {
u8 port = params->port; u8 port = params->port;
...@@ -4825,13 +4851,26 @@ static void bnx2x_link_int_ack(struct link_params *params, ...@@ -4825,13 +4851,26 @@ static void bnx2x_link_int_ack(struct link_params *params,
} }
} }
static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
{
if (*len < 5)
return -EINVAL;
str[0] = (spirom_ver & 0xFF);
str[1] = (spirom_ver & 0xFF00) >> 8;
str[2] = (spirom_ver & 0xFF0000) >> 16;
str[3] = (spirom_ver & 0xFF000000) >> 24;
str[4] = '\0';
*len -= 5;
return 0;
}
static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
{ {
u8 *str_ptr = str; u8 *str_ptr = str;
u32 mask = 0xf0000000; u32 mask = 0xf0000000;
u8 shift = 8*4; u8 shift = 8*4;
u8 digit; u8 digit;
if (len < 10) { if (*len < 10) {
/* Need more than 10chars for this format */ /* Need more than 10chars for this format */
*str_ptr = '\0'; *str_ptr = '\0';
return -EINVAL; return -EINVAL;
...@@ -4855,65 +4894,41 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len) ...@@ -4855,65 +4894,41 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
return 0; return 0;
} }
static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
{
u8 status = 0;
u32 spirom_ver;
spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
status = bnx2x_format_ver(spirom_ver, str, len);
return status;
}
static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
{
str[0] = '\0';
(*len)--;
return 0;
}
u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
u8 *version, u16 len) u8 *version, u16 len)
{ {
struct bnx2x *bp; struct bnx2x *bp;
u32 ext_phy_type = 0;
u32 spirom_ver = 0; u32 spirom_ver = 0;
u8 status; u8 status = 0;
u8 *ver_p = version;
if (version == NULL || params == NULL) if (version == NULL || params == NULL)
return -EINVAL; return -EINVAL;
bp = params->bp; bp = params->bp;
spirom_ver = REG_RD(bp, params->shmem_base + /* Extract first external phy*/
offsetof(struct shmem_region,
port_mb[params->port].ext_phy_fw_version));
status = 0;
/* reset the returned value to zero */
ext_phy_type = params->phy[EXT_PHY1].type;
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
if (len < 5)
return -EINVAL;
version[0] = (spirom_ver & 0xFF);
version[1] = (spirom_ver & 0xFF00) >> 8;
version[2] = (spirom_ver & 0xFF0000) >> 16;
version[3] = (spirom_ver & 0xFF000000) >> 24;
version[4] = '\0';
break;
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_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:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
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'; version[0] = '\0';
break; spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr);
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
DP(NETIF_MSG_LINK, "bnx2x_get_ext_phy_fw_version:"
" type is FAILURE!\n");
status = -EINVAL;
break;
default: if (params->phy[EXT_PHY1].format_fw_ver)
break; status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver,
} ver_p,
&len);
return status; return status;
} }
...@@ -4969,47 +4984,21 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy, ...@@ -4969,47 +4984,21 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
} }
} }
static void bnx2x_ext_phy_loopback(struct bnx2x_phy *phy, static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy,
struct link_params *params) struct link_params *params)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
if (params->switch_cfg == SWITCH_CFG_10G) {
/* CL37 Autoneg Enabled */
switch (phy->type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN:
DP(NETIF_MSG_LINK,
"ext_phy_loopback: We should not get here\n");
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
DP(NETIF_MSG_LINK, "ext_phy_loopback: 8705\n");
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n"); DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001);
MDIO_PMA_DEVAD, }
MDIO_PMA_REG_CTRL,
0x0001); static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
break; struct link_params *params)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: {
struct bnx2x *bp = params->bp;
/* SFX7101_XGXS_TEST1 */ /* SFX7101_XGXS_TEST1 */
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_XS_DEVAD, MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
MDIO_XS_SFX7101_XGXS_TEST1,
0x100);
DP(NETIF_MSG_LINK,
"ext_phy_loopback: set ext phy loopback\n");
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
break;
} /* switch external PHY type */
}
} }
/* /*
*------------------------------------------------------------------------ *------------------------------------------------------------------------
...@@ -5204,9 +5193,17 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) ...@@ -5204,9 +5193,17 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars)
MDIO_GP_STATUS_TOP_AN_STATUS1, MDIO_GP_STATUS_TOP_AN_STATUS1,
&gp_status); &gp_status);
/* link is up only if both local phy and external phy are up */ /* link is up only if both local phy and external phy are up */
if ((gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) && if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
bnx2x_ext_phy_is_link_up(&params->phy[EXT_PHY1], params, vars, 1)) u8 ext_phy_link_up = 1;
struct link_vars temp_vars;
if (params->phy[EXT_PHY1].read_status)
ext_phy_link_up &=
params->phy[EXT_PHY1].read_status(
&params->phy[EXT_PHY1],
params, &temp_vars);
if (ext_phy_link_up)
return 0; return 0;
}
return -ESRCH; return -ESRCH;
} }
...@@ -5217,11 +5214,10 @@ static u8 bnx2x_link_initialize(struct link_params *params, ...@@ -5217,11 +5214,10 @@ static u8 bnx2x_link_initialize(struct link_params *params,
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u8 port = params->port; u8 port = params->port;
u8 rc = 0; u8 rc = 0;
u8 non_ext_phy; u8 phy_index, non_ext_phy;
struct bnx2x_phy *ext_phy = &params->phy[EXT_PHY1]; struct bnx2x_phy *ext_phy = &params->phy[EXT_PHY1];
struct bnx2x_phy *int_phy = &params->phy[INT_PHY]; struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
/* Activate the external PHY */ /* Activate the external PHY */
bnx2x_ext_phy_reset(ext_phy, params, vars);
bnx2x_set_aer_mmd(params, int_phy); bnx2x_set_aer_mmd(params, int_phy);
...@@ -5282,7 +5278,12 @@ static u8 bnx2x_link_initialize(struct link_params *params, ...@@ -5282,7 +5278,12 @@ static u8 bnx2x_link_initialize(struct link_params *params,
} }
if (!non_ext_phy) if (!non_ext_phy)
rc |= bnx2x_ext_phy_init(params, vars); for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) {
params->phy[phy_index].config_init(
&params->phy[phy_index],
params, vars);
}
bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
(NIG_STATUS_XGXS0_LINK10G | (NIG_STATUS_XGXS0_LINK10G |
...@@ -5292,6 +5293,35 @@ static u8 bnx2x_link_initialize(struct link_params *params, ...@@ -5292,6 +5293,35 @@ static u8 bnx2x_link_initialize(struct link_params *params,
return rc; return rc;
} }
static void set_phy_vars(struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 actual_phy_idx, phy_index;
for (phy_index = INT_PHY; phy_index < params->num_phys;
phy_index++) {
actual_phy_idx = phy_index;
params->phy[actual_phy_idx].req_flow_ctrl =
params->req_flow_ctrl;
params->phy[actual_phy_idx].req_line_speed =
params->req_line_speed;
params->phy[actual_phy_idx].speed_cap_mask =
params->speed_cap_mask;
params->phy[actual_phy_idx].req_duplex =
params->req_duplex;
DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
" speed_cap_mask %x\n",
params->phy[actual_phy_idx].req_flow_ctrl,
params->phy[actual_phy_idx].req_line_speed,
params->phy[actual_phy_idx].speed_cap_mask);
}
}
u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
...@@ -5307,29 +5337,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5307,29 +5337,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
vars->duplex = DUPLEX_FULL; vars->duplex = DUPLEX_FULL;
vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
vars->mac_type = MAC_TYPE_NONE; vars->mac_type = MAC_TYPE_NONE;
vars->phy_flags = 0;
if (params->switch_cfg == SWITCH_CFG_1G) {
params->phy[INT_PHY].type =
PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT;
vars->phy_flags = PHY_SERDES_FLAG;
} else {
params->phy[INT_PHY].type =
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT;
vars->phy_flags = PHY_XGXS_FLAG;
}
params->phy[INT_PHY].mdio_ctrl =
bnx2x_get_emac_base(bp,
params->phy[INT_PHY].type, params->port);
if (XGXS_EXT_PHY_TYPE(params->ext_phy_config) !=
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
params->phy[EXT_PHY1].type =
XGXS_EXT_PHY_TYPE(params->ext_phy_config);
params->phy[EXT_PHY1].addr =
XGXS_EXT_PHY_ADDR(params->ext_phy_config);
params->phy[EXT_PHY1].mdio_ctrl =
bnx2x_get_emac_base(bp, params->phy[EXT_PHY1].type,
params->port);
}
/* disable attentions */ /* disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
...@@ -5340,6 +5348,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5340,6 +5348,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_emac_init(params, vars); bnx2x_emac_init(params, vars);
if (params->num_phys == 0) {
DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
return -EINVAL;
}
set_phy_vars(params);
DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
if (CHIP_REV_IS_FPGA(bp)) { if (CHIP_REV_IS_FPGA(bp)) {
vars->link_up = 1; vars->link_up = 1;
...@@ -5420,8 +5435,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5420,8 +5435,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
bnx2x_phy_deassert(params, vars->phy_flags); bnx2x_phy_deassert(params, vars->phy_flags);
/* set bmac loopback */ /* set bmac loopback */
bnx2x_emac_enable(params, vars, 1); bnx2x_emac_enable(params, vars, 1);
bnx2x_emac_program(params, vars->line_speed, bnx2x_emac_program(params, vars);
vars->duplex);
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0); params->port*4, 0);
...@@ -5438,8 +5452,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5438,8 +5452,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
val = REG_RD(bp, val = REG_RD(bp,
NIG_REG_XGXS0_CTRL_PHY_ADDR+ NIG_REG_XGXS0_CTRL_PHY_ADDR+
params->port*0x18); params->port*0x18);
params->phy_addr = (u8)val;
params->phy[INT_PHY].addr = (u8)val;
bnx2x_phy_deassert(params, vars->phy_flags); bnx2x_phy_deassert(params, vars->phy_flags);
bnx2x_link_initialize(params, vars); bnx2x_link_initialize(params, vars);
...@@ -5449,13 +5462,21 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5449,13 +5462,21 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
if (params->loopback_mode == LOOPBACK_XGXS_10) { if (params->loopback_mode == LOOPBACK_XGXS_10) {
/* set 10G XGXS loopback */ /* set 10G XGXS loopback */
bnx2x_set_xgxs_loopback(&params->phy[INT_PHY], params->phy[INT_PHY].config_loopback(
params, 1); &params->phy[INT_PHY],
params);
} else { } else {
/* set external phy loopback */ /* set external phy loopback */
bnx2x_ext_phy_loopback(&params->phy[INT_PHY], u8 phy_index;
for (phy_index = EXT_PHY1;
phy_index < params->num_phys; phy_index++) {
if (params->phy[phy_index].config_loopback)
params->phy[phy_index].config_loopback(
&params->phy[phy_index],
params); params);
} }
}
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0); params->port*4, 0);
...@@ -5464,37 +5485,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5464,37 +5485,9 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
} else } else
/* No loopback */ /* No loopback */
{ {
if (params->switch_cfg == SWITCH_CFG_10G)
vars->phy_flags = PHY_XGXS_FLAG;
bnx2x_phy_deassert(params, vars->phy_flags); bnx2x_phy_deassert(params, vars->phy_flags);
switch (params->switch_cfg) {
case SWITCH_CFG_1G:
vars->phy_flags |= PHY_SERDES_FLAG;
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;
}
val = REG_RD(bp,
NIG_REG_SERDES0_CTRL_PHY_ADDR+
params->port*0x10);
params->phy_addr = (u8)val;
break;
case SWITCH_CFG_10G:
vars->phy_flags |= PHY_XGXS_FLAG;
val = REG_RD(bp,
NIG_REG_XGXS0_CTRL_PHY_ADDR+
params->port*0x18);
params->phy_addr = (u8)val;
break;
default:
DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
return -EINVAL;
}
DP(NETIF_MSG_LINK, "Phy address = 0x%x\n", params->phy_addr);
params->phy[INT_PHY].addr = params->phy_addr;
bnx2x_link_initialize(params, vars); bnx2x_link_initialize(params, vars);
msleep(30); msleep(30);
bnx2x_link_int_enable(params); bnx2x_link_int_enable(params);
...@@ -5503,27 +5496,87 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -5503,27 +5496,87 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
} }
static void bnx2x_8726_reset_phy(struct bnx2x *bp, static void bnx2x_8726_link_reset(struct bnx2x_phy *phy,
struct bnx2x_phy *phy) struct link_params *params)
{ {
DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy\n"); struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port);
/* Set serial boot control for external load */ /* Set serial boot control for external load */
bnx2x_cl45_write(bp, phy, bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL, 0x0001); MDIO_PMA_REG_GEN_CTRL, 0x0001);
} }
static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
/* Disable Transmitter */
bnx2x_sfp_set_transmitter(bp, phy, params->port, 0);
}
static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 gpio_port;
gpio_port = params->port;
DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n",
gpio_port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
gpio_port);
}
static void bnx2x_8481_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
bnx2x_cl45_write(params->bp, phy,
MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000);
bnx2x_cl45_write(params->bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1);
}
static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port);
}
static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 gpio_port;
/* HW reset */
gpio_port = params->port;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
gpio_port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
gpio_port);
DP(NETIF_MSG_LINK, "reset external PHY\n");
}
static void bnx2x_int_link_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
/* reset the SerDes/XGXS */
REG_WR(params->bp, GRCBASE_MISC +
MISC_REGISTERS_RESET_REG_3_CLEAR,
(0x1ff << (params->port*16)));
}
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u8 reset_ext_phy) u8 reset_ext_phy)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u8 port = params->port; u8 phy_index, port = params->port;
u32 val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].
config));
DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port); DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
/* disable attentions */ /* disable attentions */
vars->link_status = 0; vars->link_status = 0;
...@@ -5554,57 +5607,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, ...@@ -5554,57 +5607,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
/* clear link led */ /* clear link led */
bnx2x_set_led(params, LED_MODE_OFF, 0); bnx2x_set_led(params, LED_MODE_OFF, 0);
if (reset_ext_phy) { if (reset_ext_phy) {
struct bnx2x_phy *phy = &params->phy[EXT_PHY1]; for (phy_index = EXT_PHY1; phy_index < params->num_phys;
switch (phy->type) { phy_index++) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: if (params->phy[phy_index].link_reset)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: params->phy[phy_index].link_reset(
break; &params->phy[phy_index],
params);
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
{
/* Disable Transmitter */
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
bnx2x_sfp_set_transmitter(bp, phy, 0);
break;
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
"low power mode\n",
port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
{
/* Set soft reset */
bnx2x_8726_reset_phy(bp, phy);
break;
}
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
{
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
params->port);
break;
}
default:
/* HW reset */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port);
DP(NETIF_MSG_LINK, "reset external PHY\n");
} }
} }
/* reset the SerDes/XGXS */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
(0x1ff << (port*16)));
if (params->phy[INT_PHY].link_reset)
params->phy[INT_PHY].link_reset(
&params->phy[INT_PHY], params);
/* reset BigMac */ /* reset BigMac */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
...@@ -5654,7 +5668,7 @@ static u8 bnx2x_update_link_down(struct link_params *params, ...@@ -5654,7 +5668,7 @@ static u8 bnx2x_update_link_down(struct link_params *params,
static u8 bnx2x_update_link_up(struct link_params *params, static u8 bnx2x_update_link_up(struct link_params *params,
struct link_vars *vars, struct link_vars *vars,
u8 link_10g, u32 gp_status) u8 link_10g)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u8 port = params->port; u8 port = params->port;
...@@ -5665,8 +5679,7 @@ static u8 bnx2x_update_link_up(struct link_params *params, ...@@ -5665,8 +5679,7 @@ static u8 bnx2x_update_link_up(struct link_params *params,
bnx2x_bmac_enable(params, vars, 0); bnx2x_bmac_enable(params, vars, 0);
bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000); bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
} else { } else {
rc = bnx2x_emac_program(params, vars->line_speed, rc = bnx2x_emac_program(params, vars);
vars->duplex);
bnx2x_emac_enable(params, vars, 0); bnx2x_emac_enable(params, vars, 0);
...@@ -5689,28 +5702,39 @@ static u8 bnx2x_update_link_up(struct link_params *params, ...@@ -5689,28 +5702,39 @@ static u8 bnx2x_update_link_up(struct link_params *params,
msleep(20); msleep(20);
return rc; return rc;
} }
/* This function should called upon link interrupt */ /**
/* In case vars->link_up, driver needs to * The bnx2x_link_update function should be called upon link
1. Update the pbf * interrupt.
2. Disable drain * Link is considered up as follows:
3. Update the shared memory * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs
4. Indicate link up * to be up
5. Set LEDs * - SINGLE_MEDIA - The link between the 577xx and the external
Otherwise, * phy (XGXS) need to up as well as the external link of the
1. Update shared memory * phy (PHY_EXT1)
2. Reset BigMac * - DUAL_MEDIA - The link between the 577xx and the first
3. Report link down * external phy needs to be up, and at least one of the 2
4. Unset LEDs * external phy link must be up.
*/ */
u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
struct link_vars phy_vars[MAX_PHYS];
u8 port = params->port; u8 port = params->port;
u16 gp_status; u8 link_10g, phy_index;
u8 link_10g; u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
u8 ext_phy_link_up, rc = 0;
struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
u8 is_mi_int = 0; u8 is_mi_int = 0;
u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
u8 active_external_phy = INT_PHY;
vars->link_status = 0;
for (phy_index = INT_PHY; phy_index < params->num_phys;
phy_index++) {
phy_vars[phy_index].flow_ctrl = 0;
phy_vars[phy_index].link_status = 0;
phy_vars[phy_index].line_speed = 0;
phy_vars[phy_index].duplex = DUPLEX_FULL;
phy_vars[phy_index].phy_link_up = 0;
phy_vars[phy_index].link_up = 0;
}
DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
port, (vars->phy_flags & PHY_XGXS_FLAG), port, (vars->phy_flags & PHY_XGXS_FLAG),
...@@ -5731,21 +5755,94 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ...@@ -5731,21 +5755,94 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
/* disable emac */ /* disable emac */
REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0);
/* Check external link change only for non-direct */ /**
ext_phy_link_up = bnx2x_ext_phy_is_link_up(&params->phy[EXT_PHY1], * Step 1:
params, vars, * Check external link change only for external phys, and apply
is_mi_int); * priority selection between them in case the link on both phys
* is up. Note that the instead of the common vars, a temporary
* vars argument is used since each phy may have different link/
* speed/duplex result
*/
for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) {
struct bnx2x_phy *phy = &params->phy[phy_index];
if (!phy->read_status)
continue;
/* Read link status and params of this ext phy */
cur_link_up = phy->read_status(phy, params,
&phy_vars[phy_index]);
if (cur_link_up) {
DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
phy_index);
} else {
DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
phy_index);
continue;
}
/* Read gp_status */ if (!ext_phy_link_up) {
CL45_RD_OVER_CL22(bp, int_phy, ext_phy_link_up = 1;
MDIO_REG_BANK_GP_STATUS, active_external_phy = phy_index;
MDIO_GP_STATUS_TOP_AN_STATUS1, }
&gp_status); }
prev_line_speed = vars->line_speed;
/**
* Step 2:
* Read the status of the internal phy. In case of
* DIRECT_SINGLE_MEDIA board, this link is the external link,
* otherwise this is the link between the 577xx and the first
* external phy
*/
if (params->phy[INT_PHY].read_status)
params->phy[INT_PHY].read_status(
&params->phy[INT_PHY],
params, vars);
/**
* The INT_PHY flow control reside in the vars. This include the
* case where the speed or flow control are not set to AUTO.
* Otherwise, the active external phy flow control result is set
* to the vars. The ext_phy_line_speed is needed to check if the
* speed is different between the internal phy and external phy.
* This case may be result of intermediate link speed change.
*/
if (active_external_phy > INT_PHY) {
vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl;
/**
* Link speed is taken from the XGXS. AN and FC result from
* the external phy.
*/
vars->link_status |= phy_vars[active_external_phy].link_status;
ext_phy_line_speed = phy_vars[active_external_phy].line_speed;
vars->duplex = phy_vars[active_external_phy].duplex;
if (params->phy[active_external_phy].supported &
SUPPORTED_FIBRE)
vars->link_status |= LINK_STATUS_SERDES_LINK;
DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
active_external_phy);
}
DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x,"
" ext_phy_line_speed = %d\n", vars->flow_ctrl,
vars->link_status, ext_phy_line_speed);
/**
* 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
*/
rc = bnx2x_link_settings_status(params, vars, gp_status, if (vars->phy_link_up) {
ext_phy_link_up); if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
if (rc != 0) (ext_phy_line_speed != vars->line_speed)) {
return rc; DP(NETIF_MSG_LINK, "Internal link speed %d is"
" different than the external"
" link speed %d\n", vars->line_speed,
ext_phy_line_speed);
vars->phy_link_up = 0;
} else if (prev_line_speed != vars->line_speed) {
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE
+ params->port*4, 0);
msleep(1);
}
}
/* anything 10 and over uses the bmac */ /* anything 10 and over uses the bmac */
link_10g = ((vars->line_speed == SPEED_10000) || link_10g = ((vars->line_speed == SPEED_10000) ||
...@@ -5757,31 +5854,469 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ...@@ -5757,31 +5854,469 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
bnx2x_link_int_ack(params, vars, link_10g, is_mi_int); 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 * In case external phy link is up, and internal link is down
to be initialized. * (not initialized yet probably after link initialization, it
Note that after link down-up as result of cable plug, * needs to be initialized.
the xgxs link would probably become up again without the need to * Note that after link down-up as result of cable plug, the xgxs
initialize it*/ * link would probably become up again without the need
* initialize it
if ((int_phy->type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) && */
(int_phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) && if (!(SINGLE_MEDIA_DIRECT(params))) {
(int_phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706) && DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d,"
(int_phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) && " init_preceding = %d\n", ext_phy_link_up,
(int_phy->type && !vars->phy_link_up)) vars->phy_link_up,
bnx2x_init_internal_phy(int_phy, params, vars); params->phy[EXT_PHY1].flags &
FLAGS_INIT_XGXS_FIRST);
/* link is up only if both local phy and external phy are up */ if (!(params->phy[EXT_PHY1].flags &
vars->link_up = (ext_phy_link_up && vars->phy_link_up); FLAGS_INIT_XGXS_FIRST)
&& ext_phy_link_up && !vars->phy_link_up) {
vars->line_speed = ext_phy_line_speed;
if (vars->line_speed < SPEED_1000)
vars->phy_flags |= PHY_SGMII_FLAG;
else
vars->phy_flags &= ~PHY_SGMII_FLAG;
bnx2x_init_internal_phy(&params->phy[INT_PHY],
params,
vars);
}
}
/**
* Link is up only if both local phy and external phy (in case of
* non-direct board) are up
*/
vars->link_up = (vars->phy_link_up &&
(ext_phy_link_up ||
SINGLE_MEDIA_DIRECT(params)));
if (vars->link_up) if (vars->link_up)
rc = bnx2x_update_link_up(params, vars, link_10g, gp_status); rc = bnx2x_update_link_up(params, vars, link_10g);
else else
rc = bnx2x_update_link_down(params, vars); rc = bnx2x_update_link_down(params, vars);
return rc; return rc;
} }
static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy,
struct link_params *params)
{
bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, 0);
bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, 1);
}
static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
struct link_params *params) {
u32 swap_val, swap_override;
u8 port;
/**
* The PHY reset is controlled by GPIO 1. Fake the port number
* to cancel the swap done in set_gpio()
*/
struct bnx2x *bp = params->bp;
swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
port = (swap_val && swap_override) ^ 1;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
}
static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy,
struct link_params *params) {
/* Low power mode is controlled by GPIO 2 */
bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
/* The PHY reset is controlled by GPIO 1 */
bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port);
}
/******************************************************************/
/* STATIC PHY DECLARATION */
/******************************************************************/
static struct bnx2x_phy phy_null = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
.addr = 0,
.flags = FLAGS_INIT_XGXS_FIRST,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = 0,
.media_type = ETH_PHY_NOT_PRESENT,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)NULL,
.read_status = (read_status_t)NULL,
.link_reset = (link_reset_t)NULL,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)NULL,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_serdes = {
.type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
.addr = 0xff,
.flags = 0,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_UNSPECIFIED,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_init_serdes,
.read_status = (read_status_t)bnx2x_link_settings_status,
.link_reset = (link_reset_t)bnx2x_int_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)NULL,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_xgxs = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
.addr = 0xff,
.flags = 0,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_UNSPECIFIED,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_init_xgxs,
.read_status = (read_status_t)bnx2x_link_settings_status,
.link_reset = (link_reset_t)bnx2x_int_link_reset,
.config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
.format_fw_ver = (format_fw_ver_t)NULL,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_7101 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
.addr = 0xff,
.flags = FLAGS_FAN_FAILURE_DET_REQ,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_BASE_T,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_7101_config_init,
.read_status = (read_status_t)bnx2x_7101_read_status,
.link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
.config_loopback = (config_loopback_t)bnx2x_7101_config_loopback,
.format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver,
.hw_reset = (hw_reset_t)bnx2x_7101_hw_reset,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8073 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
.addr = 0xff,
.flags = FLAGS_HW_LOCK_REQUIRED,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_UNSPECIFIED,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8072_8073_config_init,
.read_status = (read_status_t)bnx2x_8073_read_status,
.link_reset = (link_reset_t)bnx2x_8073_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8705 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
.addr = 0xff,
.flags = FLAGS_INIT_XGXS_FIRST,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_XFP_FIBER,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8705_config_init,
.read_status = (read_status_t)bnx2x_8705_read_status,
.link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8706 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
.addr = 0xff,
.flags = FLAGS_INIT_XGXS_FIRST,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_SFP_FIBER,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8706_config_init,
.read_status = (read_status_t)bnx2x_8706_read_status,
.link_reset = (link_reset_t)bnx2x_common_ext_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8726 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
.addr = 0xff,
.flags = (FLAGS_HW_LOCK_REQUIRED |
FLAGS_INIT_XGXS_FIRST),
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_SFP_FIBER,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8726_config_init,
.read_status = (read_status_t)bnx2x_8726_read_status,
.link_reset = (link_reset_t)bnx2x_8726_link_reset,
.config_loopback = (config_loopback_t)bnx2x_8726_config_loopback,
.format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8727 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
.addr = 0xff,
.flags = FLAGS_FAN_FAILURE_DET_REQ,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_SFP_FIBER,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8727_config_init,
.read_status = (read_status_t)bnx2x_8727_read_status,
.link_reset = (link_reset_t)bnx2x_8727_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_format_ver,
.hw_reset = (hw_reset_t)bnx2x_8727_hw_reset,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_8481 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
.addr = 0xff,
.flags = FLAGS_FAN_FAILURE_DET_REQ,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_BASE_T,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_8481_config_init,
.read_status = (read_status_t)bnx2x_848xx_read_status,
.link_reset = (link_reset_t)bnx2x_8481_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
.hw_reset = (hw_reset_t)bnx2x_8481_hw_reset,
.set_link_led = (set_link_led_t)NULL
};
static struct bnx2x_phy phy_84823 = {
.type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
.addr = 0xff,
.flags = FLAGS_FAN_FAILURE_DET_REQ,
.def_md_devad = 0,
.reserved = 0,
.rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
.mdio_ctrl = 0,
.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause),
.media_type = ETH_PHY_BASE_T,
.ver_addr = 0,
.req_flow_ctrl = 0,
.req_line_speed = 0,
.speed_cap_mask = 0,
.req_duplex = 0,
.rsrv = 0,
.config_init = (config_init_t)bnx2x_848x3_config_init,
.read_status = (read_status_t)bnx2x_848xx_read_status,
.link_reset = (link_reset_t)bnx2x_848x3_link_reset,
.config_loopback = (config_loopback_t)NULL,
.format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver,
.hw_reset = (hw_reset_t)NULL,
.set_link_led = (set_link_led_t)NULL
};
/*****************************************************************/
/* */
/* Populate the phy according. Main function: bnx2x_populate_phy */
/* */
/*****************************************************************/
static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
struct bnx2x_phy *phy, u8 port,
u8 phy_index)
{
/* Get the 4 lanes xgxs config rx and tx */
u32 rx = 0, tx = 0, i;
for (i = 0; i < 2; i++) {
/**
* INT_PHY and EXT_PHY1 share the same value location in the
* shmem. When num_phys is greater than 1, than this value
* applies only to EXT_PHY1
*/
rx = REG_RD(bp, shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
tx = REG_RD(bp, shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].xgxs_config_tx[i<<1]));
phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff);
phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff);
phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff);
phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff);
}
}
static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base, static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
u8 phy_index, u8 port) u8 phy_index, u8 port)
{ {
...@@ -5799,6 +6334,45 @@ static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base, ...@@ -5799,6 +6334,45 @@ static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
return ext_phy_config; return ext_phy_config;
} }
static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
struct bnx2x_phy *phy)
{
u32 phy_addr;
u32 chip_id;
u32 switch_cfg = (REG_RD(bp, shmem_base +
offsetof(struct shmem_region,
dev_info.port_feature_config[port].link_config)) &
PORT_FEATURE_CONNECTED_SWITCH_MASK);
chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16;
switch (switch_cfg) {
case SWITCH_CFG_1G:
phy_addr = REG_RD(bp,
NIG_REG_SERDES0_CTRL_PHY_ADDR +
port * 0x10);
*phy = phy_serdes;
break;
case SWITCH_CFG_10G:
phy_addr = REG_RD(bp,
NIG_REG_XGXS0_CTRL_PHY_ADDR +
port * 0x18);
*phy = phy_xgxs;
break;
default:
DP(NETIF_MSG_LINK, "Invalid switch_cfg\n");
return -EINVAL;
}
phy->addr = (u8)phy_addr;
phy->mdio_ctrl = bnx2x_get_emac_base(bp,
phy->type,
port);
phy->def_md_devad = DEFAULT_PHY_DEV_ADDR;
DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n",
port, phy->addr, phy->mdio_ctrl);
bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY);
return 0;
}
static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
u8 phy_index, u8 phy_index,
...@@ -5806,12 +6380,52 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, ...@@ -5806,12 +6380,52 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
u8 port, u8 port,
struct bnx2x_phy *phy) struct bnx2x_phy *phy)
{ {
u32 ext_phy_config; u32 ext_phy_config, phy_type;
ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base, ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base,
phy_index, port); phy_index, port);
phy->type = XGXS_EXT_PHY_TYPE(ext_phy_config); phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
/* Select the phy type */
switch (phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
*phy = phy_8073;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
*phy = phy_8705;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
*phy = phy_8706;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
*phy = phy_8726;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
/* BCM8727_NOC => BCM8727 no over current */
*phy = phy_8727;
phy->flags |= FLAGS_NOC;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
*phy = phy_8727;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
*phy = phy_8481;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
*phy = phy_84823;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
*phy = phy_7101;
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
*phy = phy_null;
return -EINVAL;
default:
*phy = phy_null;
return 0;
}
phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config); phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config);
bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index);
phy->mdio_ctrl = bnx2x_get_emac_base(bp, phy->type, port); phy->mdio_ctrl = bnx2x_get_emac_base(bp, phy->type, port);
return 0; return 0;
} }
...@@ -5820,11 +6434,119 @@ static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, ...@@ -5820,11 +6434,119 @@ static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
u8 port, struct bnx2x_phy *phy) u8 port, struct bnx2x_phy *phy)
{ {
u8 status = 0; u8 status = 0;
phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
if (phy_index == INT_PHY)
return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base,
port, phy); port, phy);
return status; return status;
} }
static void bnx2x_phy_def_cfg(struct link_params *params,
struct bnx2x_phy *phy,
u8 actual_phy_idx)
{
struct bnx2x *bp = params->bp;
u32 link_config;
/* Populate the default phy configuration for MF mode */
link_config = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].link_config));
phy->speed_cap_mask = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_hw_config[params->port].speed_capability_mask));
phy->req_duplex = DUPLEX_FULL;
switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) {
case PORT_FEATURE_LINK_SPEED_10M_HALF:
phy->req_duplex = DUPLEX_HALF;
case PORT_FEATURE_LINK_SPEED_10M_FULL:
phy->req_line_speed = SPEED_10;
break;
case PORT_FEATURE_LINK_SPEED_100M_HALF:
phy->req_duplex = DUPLEX_HALF;
case PORT_FEATURE_LINK_SPEED_100M_FULL:
phy->req_line_speed = SPEED_100;
break;
case PORT_FEATURE_LINK_SPEED_1G:
phy->req_line_speed = SPEED_1000;
break;
case PORT_FEATURE_LINK_SPEED_2_5G:
phy->req_line_speed = SPEED_2500;
break;
case PORT_FEATURE_LINK_SPEED_10G_CX4:
phy->req_line_speed = SPEED_10000;
break;
default:
phy->req_line_speed = SPEED_AUTO_NEG;
break;
}
switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) {
case PORT_FEATURE_FLOW_CONTROL_AUTO:
phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO;
break;
case PORT_FEATURE_FLOW_CONTROL_TX:
phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX;
break;
case PORT_FEATURE_FLOW_CONTROL_RX:
phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX;
break;
case PORT_FEATURE_FLOW_CONTROL_BOTH:
phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
break;
default:
phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE;
break;
}
}
u8 bnx2x_phy_probe(struct link_params *params)
{
u8 phy_index, actual_phy_idx, link_cfg_idx;
struct bnx2x *bp = params->bp;
struct bnx2x_phy *phy;
params->num_phys = 0;
DP(NETIF_MSG_LINK, "Begin phy probe\n");
for (phy_index = INT_PHY; phy_index < MAX_PHYS;
phy_index++) {
link_cfg_idx = LINK_CONFIG_IDX(phy_index);
actual_phy_idx = phy_index;
phy = &params->phy[actual_phy_idx];
if (bnx2x_populate_phy(bp, phy_index, params->shmem_base,
params->port,
phy) != 0) {
params->num_phys = 0;
DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n",
phy_index);
for (phy_index = INT_PHY;
phy_index < MAX_PHYS;
phy_index++)
*phy = phy_null;
return -EINVAL;
}
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
break;
bnx2x_phy_def_cfg(params, phy, actual_phy_idx);
params->num_phys++;
}
DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys);
return 0;
}
u32 bnx2x_supported_attr(struct link_params *params, u8 phy_idx)
{
if (phy_idx < params->num_phys)
return params->phy[phy_idx].supported;
return 0;
}
static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{ {
struct bnx2x_phy phy[PORT_MAX]; struct bnx2x_phy phy[PORT_MAX];
......
...@@ -46,6 +46,15 @@ ...@@ -46,6 +46,15 @@
#define SFP_EEPROM_PART_NO_ADDR 0x28 #define SFP_EEPROM_PART_NO_ADDR 0x28
#define SFP_EEPROM_PART_NO_SIZE 16 #define SFP_EEPROM_PART_NO_SIZE 16
#define PWR_FLT_ERR_MSG_LEN 250 #define PWR_FLT_ERR_MSG_LEN 250
#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
(((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
/* Single Media Direct board is the plain 577xx board with CX4/RJ45 jacks */ /* Single Media Direct board is the plain 577xx board with CX4/RJ45 jacks */
#define SINGLE_MEDIA_DIRECT(params) (params->num_phys == 1) #define SINGLE_MEDIA_DIRECT(params) (params->num_phys == 1)
/* Single Media board contains single external phy */ /* Single Media board contains single external phy */
...@@ -58,6 +67,10 @@ ...@@ -58,6 +67,10 @@
#define MAX_PHYS 2 #define MAX_PHYS 2
/* Same configuration is shared between the XGXS and the first external phy */
#define LINK_CONFIG_SIZE (MAX_PHYS - 1)
#define LINK_CONFIG_IDX(_phy_idx) ((_phy_idx == INT_PHY) ? \
0 : (_phy_idx - 1))
/***********************************************************/ /***********************************************************/
/* bnx2x_phy struct */ /* bnx2x_phy struct */
/* Defines the required arguments and function per phy */ /* Defines the required arguments and function per phy */
...@@ -66,13 +79,88 @@ struct link_vars; ...@@ -66,13 +79,88 @@ struct link_vars;
struct link_params; struct link_params;
struct bnx2x_phy; struct bnx2x_phy;
typedef u8 (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params,
struct link_vars *vars);
typedef u8 (*read_status_t)(struct bnx2x_phy *phy, struct link_params *params,
struct link_vars *vars);
typedef void (*link_reset_t)(struct bnx2x_phy *phy,
struct link_params *params);
typedef void (*config_loopback_t)(struct bnx2x_phy *phy,
struct link_params *params);
typedef u8 (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len);
typedef void (*hw_reset_t)(struct bnx2x_phy *phy, struct link_params *params);
typedef void (*set_link_led_t)(struct bnx2x_phy *phy,
struct link_params *params, u8 mode);
struct bnx2x_phy { struct bnx2x_phy {
u32 type; u32 type;
/* Loaded during init */ /* Loaded during init */
u8 addr; u8 addr;
u8 flags;
/* Require HW lock */
#define FLAGS_HW_LOCK_REQUIRED (1<<0)
/* No Over-Current detection */
#define FLAGS_NOC (1<<1)
/* Fan failure detection required */
#define FLAGS_FAN_FAILURE_DET_REQ (1<<2)
/* Initialize first the XGXS and only then the phy itself */
#define FLAGS_INIT_XGXS_FIRST (1<<3)
u8 def_md_devad;
u8 reserved;
/* preemphasis values for the rx side */
u16 rx_preemphasis[4];
/* preemphasis values for the tx side */
u16 tx_preemphasis[4];
/* EMAC address for access MDIO */
u32 mdio_ctrl; u32 mdio_ctrl;
u32 supported;
u32 media_type;
#define ETH_PHY_UNSPECIFIED 0x0
#define ETH_PHY_SFP_FIBER 0x1
#define ETH_PHY_XFP_FIBER 0x2
#define ETH_PHY_DA_TWINAX 0x3
#define ETH_PHY_BASE_T 0x4
#define ETH_PHY_NOT_PRESENT 0xff
/* The address in which version is located*/
u32 ver_addr;
u16 req_flow_ctrl;
u16 req_line_speed;
u32 speed_cap_mask;
u16 req_duplex;
u16 rsrv;
/* Called per phy/port init, and it configures LASI, speed, autoneg,
duplex, flow control negotiation, etc. */
config_init_t config_init;
/* Called due to interrupt. It determines the link, speed */
read_status_t read_status;
/* Called when driver is unloading. Should reset the phy */
link_reset_t link_reset;
/* Set the loopback configuration for the phy */
config_loopback_t config_loopback;
/* Format the given raw number into str up to len */
format_fw_ver_t format_fw_ver;
/* Reset the phy (both ports) */
hw_reset_t hw_reset;
/* Set link led mode (on/off/oper)*/
set_link_led_t set_link_led;
}; };
/* Inputs parameters to the CLC */ /* Inputs parameters to the CLC */
...@@ -106,38 +194,23 @@ struct link_params { ...@@ -106,38 +194,23 @@ struct link_params {
#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH #define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH
#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT #define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT
u16 hw_led_mode; /* part of the hw_config read from the shmem */
/* phy_addr populated by the phy_init function */
u8 phy_addr;
/*u8 reserved1;*/
u32 lane_config; u32 lane_config;
u32 ext_phy_config;
#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
#define XGXS_EXT_PHY_ADDR(ext_phy_config) \
(((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT)
#define SERDES_EXT_PHY_TYPE(ext_phy_config) \
((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
/* Phy register parameter */ /* Phy register parameter */
u32 chip_id; u32 chip_id;
u16 xgxs_config_rx[4]; /* preemphasis values for the rx side */
u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
u32 feature_config_flags; u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) #define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
#define FEATURE_CONFIG_BCM8727_NOC (1<<3)
/* Will be populated during common init */ /* Will be populated during common init */
struct bnx2x_phy phy[MAX_PHYS]; struct bnx2x_phy phy[MAX_PHYS];
/* Will be populated during common init */ /* Will be populated during common init */
u8 num_phys; u8 num_phys;
u8 rsrv;
u16 hw_led_mode; /* part of the hw_config read from the shmem */
/* Device pointer passed to all callback functions */ /* Device pointer passed to all callback functions */
struct bnx2x *bp; struct bnx2x *bp;
}; };
......
...@@ -1960,12 +1960,16 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) ...@@ -1960,12 +1960,16 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
static inline void bnx2x_fan_failure(struct bnx2x *bp) static inline void bnx2x_fan_failure(struct bnx2x *bp)
{ {
int port = BP_PORT(bp); int port = BP_PORT(bp);
u32 ext_phy_config;
/* mark the failure */ /* mark the failure */
bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; ext_phy_config =
bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config, SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
bp->link_params.ext_phy_config); ext_phy_config);
/* log the failure */ /* log the failure */
netdev_err(bp->dev, "Fan Failure on Network Controller has caused" netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
...@@ -1991,7 +1995,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) ...@@ -1991,7 +1995,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
BNX2X_ERR("SPIO5 hw attention\n"); BNX2X_ERR("SPIO5 hw attention\n");
/* Fan failure attention */ /* Fan failure attention */
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { switch (bp->link_params.phy[EXT_PHY1].type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
/* Low power mode is controlled by GPIO 2 */ /* Low power mode is controlled by GPIO 2 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
...@@ -4140,7 +4144,7 @@ static int bnx2x_init_common(struct bnx2x *bp) ...@@ -4140,7 +4144,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
return -EBUSY; return -EBUSY;
} }
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { switch (bp->link_params.phy[EXT_PHY1].type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: 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_BCM8073:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
...@@ -4299,7 +4303,7 @@ static int bnx2x_init_port(struct bnx2x *bp) ...@@ -4299,7 +4303,7 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, MCP_BLOCK, init_stage); bnx2x_init_block(bp, MCP_BLOCK, init_stage);
bnx2x_init_block(bp, DMAE_BLOCK, init_stage); bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { switch (bp->link_params.phy[EXT_PHY1].type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
{ {
u32 swap_val, swap_override, aeu_gpio_mask, offset; u32 swap_val, swap_override, aeu_gpio_mask, offset;
...@@ -4480,7 +4484,7 @@ static int bnx2x_init_func(struct bnx2x *bp) ...@@ -4480,7 +4484,7 @@ static int bnx2x_init_func(struct bnx2x *bp)
/* Reset PCIE errors for debug */ /* Reset PCIE errors for debug */
REG_WR(bp, 0x2114, 0xffffffff); REG_WR(bp, 0x2114, 0xffffffff);
REG_WR(bp, 0x2120, 0xffffffff); REG_WR(bp, 0x2120, 0xffffffff);
bnx2x_phy_probe(&bp->link_params);
return 0; return 0;
} }
...@@ -6065,194 +6069,32 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, ...@@ -6065,194 +6069,32 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
u32 switch_cfg) u32 switch_cfg)
{ {
int port = BP_PORT(bp); int port = BP_PORT(bp);
u32 ext_phy_type; bp->port.supported = 0;
switch (bp->link_params.num_phys) {
switch (switch_cfg) { case 1:
case SWITCH_CFG_1G: bp->port.supported = bp->link_params.phy[INT_PHY].supported;
BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
ext_phy_type =
SERDES_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
switch (ext_phy_type) {
case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_TP |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break; break;
case 2:
case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: bp->port.supported = bp->link_params.phy[EXT_PHY1].supported;
BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_TP |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break; break;
}
default: if (!(bp->port.supported)) {
BNX2X_ERR("NVRAM config error. " BNX2X_ERR("NVRAM config error. BAD phy config."
"BAD SerDes ext_phy_config 0x%x\n", "PHY1 config 0x%x\n",
bp->link_params.ext_phy_config); SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config));
return; return;
} }
switch (switch_cfg) {
case SWITCH_CFG_1G:
bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
port*0x10); port*0x10);
BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
break; break;
case SWITCH_CFG_10G: case SWITCH_CFG_10G:
BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
ext_phy_type =
XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823:
BNX2X_DEV_INFO("ext_phy_type 0x%x (BCM848xx)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_TP |
SUPPORTED_Autoneg |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
BNX2X_ERR("XGXS PHY Failure detected 0x%x\n",
bp->link_params.ext_phy_config);
break;
default:
BNX2X_ERR("NVRAM config error. "
"BAD XGXS ext_phy_config 0x%x\n",
bp->link_params.ext_phy_config);
return;
}
bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
port*0x18); port*0x18);
BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr);
...@@ -6264,8 +6106,6 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, ...@@ -6264,8 +6106,6 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
bp->port.link_config); bp->port.link_config);
return; return;
} }
bp->link_params.phy_addr = bp->port.phy_addr;
/* mask what we support according to speed_cap_mask */ /* mask what we support according to speed_cap_mask */
if (!(bp->link_params.speed_cap_mask & if (!(bp->link_params.speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
...@@ -6309,25 +6149,10 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) ...@@ -6309,25 +6149,10 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
bp->link_params.req_line_speed = SPEED_AUTO_NEG; bp->link_params.req_line_speed = SPEED_AUTO_NEG;
bp->port.advertising = bp->port.supported; bp->port.advertising = bp->port.supported;
} else { } else {
u32 ext_phy_type =
XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
if ((ext_phy_type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
(ext_phy_type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
/* force 10G, no AN */ /* force 10G, no AN */
bp->link_params.req_line_speed = SPEED_10000; bp->link_params.req_line_speed = SPEED_10000;
bp->port.advertising = bp->port.advertising = (ADVERTISED_10000baseT_Full |
(ADVERTISED_10000baseT_Full |
ADVERTISED_FIBRE); ADVERTISED_FIBRE);
break;
}
BNX2X_ERR("NVRAM config error. "
"Invalid link_config 0x%x"
" Autoneg not supported\n",
bp->port.link_config);
return;
} }
break; break;
...@@ -6475,27 +6300,13 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -6475,27 +6300,13 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
int port = BP_PORT(bp); int port = BP_PORT(bp);
u32 val, val2; u32 val, val2;
u32 config; u32 config;
u16 i; u32 ext_phy_type, ext_phy_config;;
u32 ext_phy_type;
bp->link_params.bp = bp; bp->link_params.bp = bp;
bp->link_params.port = port; bp->link_params.port = port;
bp->link_params.lane_config = bp->link_params.lane_config =
SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config); SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
bp->link_params.ext_phy_config =
SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
/* BCM8727_NOC => BCM8727 no over current */
if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
bp->link_params.ext_phy_config &=
~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
bp->link_params.ext_phy_config |=
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
bp->link_params.feature_config_flags |=
FEATURE_CONFIG_BCM8727_NOC;
}
bp->link_params.speed_cap_mask = bp->link_params.speed_cap_mask =
SHMEM_RD(bp, SHMEM_RD(bp,
...@@ -6504,18 +6315,6 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -6504,18 +6315,6 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->port.link_config = bp->port.link_config =
SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
/* Get the 4 lanes xgxs config rx and tx */
for (i = 0; i < 2; i++) {
val = SHMEM_RD(bp,
dev_info.port_hw_config[port].xgxs_config_rx[i<<1]);
bp->link_params.xgxs_config_rx[i << 1] = ((val>>16) & 0xffff);
bp->link_params.xgxs_config_rx[(i << 1) + 1] = (val & 0xffff);
val = SHMEM_RD(bp,
dev_info.port_hw_config[port].xgxs_config_tx[i<<1]);
bp->link_params.xgxs_config_tx[i << 1] = ((val>>16) & 0xffff);
bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
}
/* If the device is capable of WoL, set the default state according /* If the device is capable of WoL, set the default state according
* to the HW * to the HW
...@@ -6524,14 +6323,14 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -6524,14 +6323,14 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->wol = (!(bp->flags & NO_WOL_FLAG) && bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED)); (config & PORT_FEATURE_WOL_ENABLED));
BNX2X_DEV_INFO("lane_config 0x%08x ext_phy_config 0x%08x" BNX2X_DEV_INFO("lane_config 0x%08x"
" speed_cap_mask 0x%08x link_config 0x%08x\n", " speed_cap_mask 0x%08x link_config 0x%08x\n",
bp->link_params.lane_config, bp->link_params.lane_config,
bp->link_params.ext_phy_config,
bp->link_params.speed_cap_mask, bp->port.link_config); bp->link_params.speed_cap_mask, bp->port.link_config);
bp->link_params.switch_cfg |= (bp->port.link_config & bp->link_params.switch_cfg |= (bp->port.link_config &
PORT_FEATURE_CONNECTED_SWITCH_MASK); PORT_FEATURE_CONNECTED_SWITCH_MASK);
bnx2x_phy_probe(&bp->link_params);
bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
bnx2x_link_settings_requested(bp); bnx2x_link_settings_requested(bp);
...@@ -6540,14 +6339,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -6540,14 +6339,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
* If connected directly, work with the internal PHY, otherwise, work * If connected directly, work with the internal PHY, otherwise, work
* with the external PHY * with the external PHY
*/ */
ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); ext_phy_config =
SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
bp->mdio.prtad = bp->link_params.phy_addr; bp->mdio.prtad = bp->port.phy_addr;
else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
bp->mdio.prtad = bp->mdio.prtad =
XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config); XGXS_EXT_PHY_ADDR(ext_phy_config);
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment