diff options
author | Yaniv Rosner <yaniv.rosner@broadcom.com> | 2010-09-07 11:41:20 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-07 13:15:42 -0700 |
commit | a22f078867ef362e35c54055878168e6613ff743 (patch) | |
tree | 2cf683f3057b7ed5dcaaaad16192f3a267dcf0f8 /drivers | |
parent | de6eae1f42eae736548f293570fd867bd37c3bdd (diff) |
bnx2x: Add dual-media changes
Add required changes in order to support dual-media boards.
Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/bnx2x/bnx2x.h | 10 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_cmn.c | 14 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_cmn.h | 3 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_ethtool.c | 176 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_hsi.h | 111 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.c | 695 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.h | 62 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_main.c | 354 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_reg.h | 25 |
9 files changed, 1074 insertions, 376 deletions
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index a019c67d299..137187684f2 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -566,13 +566,13 @@ struct bnx2x_common { struct bnx2x_port { u32 pmf; - u32 link_config; + u32 link_config[LINK_CONFIG_SIZE]; - u32 supported; + u32 supported[LINK_CONFIG_SIZE]; /* link settings - missing defines */ #define SUPPORTED_2500baseX_Full (1 << 15) - u32 advertising; + u32 advertising[LINK_CONFIG_SIZE]; /* link settings - missing defines */ #define ADVERTISED_2500baseX_Full (1 << 15) @@ -931,7 +931,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); -u32 bnx2x_fw_command(struct bnx2x *bp, u32 command); +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param); void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr, u32 addr, u32 len); @@ -939,7 +939,7 @@ void bnx2x_calc_fc_adv(struct bnx2x *bp); int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, u32 data_hi, u32 data_lo, int common); void bnx2x_update_coalesce(struct bnx2x *bp); - +int bnx2x_get_link_cfg_idx(struct bnx2x *bp); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) { diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 0e4caf41190..7f1d291eaaa 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1283,7 +1283,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) common blocks should be initialized, otherwise - not */ if (!BP_NOMCP(bp)) { - load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, 0); if (!load_code) { BNX2X_ERR("MCP response failure, aborting\n"); rc = -EBUSY; @@ -1322,9 +1322,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) rc = bnx2x_init_hw(bp, load_code); if (rc) { BNX2X_ERR("HW init failed, aborting\n"); - bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP); - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); goto load_error2; } @@ -1339,7 +1339,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Send LOAD_DONE command to MCP */ if (!BP_NOMCP(bp)) { - load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); if (!load_code) { BNX2X_ERR("MCP response failure, aborting\n"); rc = -EBUSY; @@ -1455,8 +1455,8 @@ load_error4: load_error3: bnx2x_int_disable_sync(bp, 1); if (!BP_NOMCP(bp)) { - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP); - bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); } bp->port.pmf = 0; /* Free SKBs, SGEs, TPA pool and driver internals */ diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 32543c32805..d1e6a8c977d 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -49,10 +49,11 @@ void bnx2x_link_set(struct bnx2x *bp); * Query link status * * @param bp + * @param is_serdes * * @return 0 - link is UP */ -u8 bnx2x_link_test(struct bnx2x *bp); +u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes); /** * Handles link status change diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index dbcfa7a5618..d058f971678 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -29,9 +29,12 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); - - cmd->supported = bp->port.supported; - cmd->advertising = bp->port.advertising; + int cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Dual Media boards present all available port types */ + cmd->supported = bp->port.supported[cfg_idx] | + (bp->port.supported[cfg_idx ^ 1] & + (SUPPORTED_TP | SUPPORTED_FIBRE)); + cmd->advertising = bp->port.advertising[cfg_idx]; if ((bp->state == BNX2X_STATE_OPEN) && !(bp->flags & MF_FUNC_DIS) && @@ -48,22 +51,21 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = vn_max_rate; } } else { - cmd->speed = -1; - cmd->duplex = -1; + cmd->speed = bp->link_params.req_line_speed[cfg_idx]; + cmd->duplex = bp->link_params.req_duplex[cfg_idx]; } - if (bp->link_params.num_phys > 0) { - if (bp->link_params.phy[bp->link_params.num_phys - 1]. - supported & SUPPORTED_FIBRE) - cmd->port = PORT_FIBRE; - else - cmd->port = PORT_TP; - } else - DP(NETIF_MSG_LINK, "No media found\n"); + if (bp->port.supported[cfg_idx] & SUPPORTED_TP) + cmd->port = PORT_TP; + else if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE) + cmd->port = PORT_FIBRE; + else + BNX2X_ERR("XGXS PHY Failure detected\n"); + cmd->phy_address = bp->mdio.prtad; cmd->transceiver = XCVR_INTERNAL; - if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) + if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) cmd->autoneg = AUTONEG_ENABLE; else cmd->autoneg = AUTONEG_DISABLE; @@ -85,7 +87,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); - u32 advertising; + u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config; if (IS_E1HMF(bp)) return 0; @@ -98,26 +100,81 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + cfg_idx = bnx2x_get_link_cfg_idx(bp); + old_multi_phy_config = bp->link_params.multi_phy_config; + switch (cmd->port) { + case PORT_TP: + if (bp->port.supported[cfg_idx] & SUPPORTED_TP) + break; /* no port change */ + + if (!(bp->port.supported[0] & SUPPORTED_TP || + bp->port.supported[1] & SUPPORTED_TP)) { + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + bp->link_params.multi_phy_config &= + ~PORT_HW_CFG_PHY_SELECTION_MASK; + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; + else + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; + break; + case PORT_FIBRE: + if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE) + break; /* no port change */ + + if (!(bp->port.supported[0] & SUPPORTED_FIBRE || + bp->port.supported[1] & SUPPORTED_FIBRE)) { + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + bp->link_params.multi_phy_config &= + ~PORT_HW_CFG_PHY_SELECTION_MASK; + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; + else + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; + break; + default: + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + /* Save new config in case command complete successuly */ + new_multi_phy_config = bp->link_params.multi_phy_config; + /* Get the new cfg_idx */ + cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Restore old config in case command failed */ + bp->link_params.multi_phy_config = old_multi_phy_config; + DP(NETIF_MSG_LINK, "cfg_idx = %x\n", cfg_idx); + if (cmd->autoneg == AUTONEG_ENABLE) { - if (!(bp->port.supported & SUPPORTED_Autoneg)) { + if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { DP(NETIF_MSG_LINK, "Autoneg not supported\n"); return -EINVAL; } /* advertise the requested speed and duplex if supported */ - cmd->advertising &= bp->port.supported; + cmd->advertising &= bp->port.supported[cfg_idx]; - bp->link_params.req_line_speed = SPEED_AUTO_NEG; - bp->link_params.req_duplex = DUPLEX_FULL; - bp->port.advertising |= (ADVERTISED_Autoneg | + bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG; + bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL; + bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg | cmd->advertising); } else { /* forced speed */ /* advertise the requested speed and duplex if supported */ - switch (cmd->speed) { + u32 speed = cmd->speed; + speed |= (cmd->speed_hi << 16); + switch (speed) { case SPEED_10: if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->port.supported & + if (!(bp->port.supported[cfg_idx] & SUPPORTED_10baseT_Full)) { DP(NETIF_MSG_LINK, "10M full not supported\n"); @@ -127,7 +184,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = (ADVERTISED_10baseT_Full | ADVERTISED_TP); } else { - if (!(bp->port.supported & + if (!(bp->port.supported[cfg_idx] & SUPPORTED_10baseT_Half)) { DP(NETIF_MSG_LINK, "10M half not supported\n"); @@ -141,7 +198,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) case SPEED_100: if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->port.supported & + if (!(bp->port.supported[cfg_idx] & SUPPORTED_100baseT_Full)) { DP(NETIF_MSG_LINK, "100M full not supported\n"); @@ -151,7 +208,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = (ADVERTISED_100baseT_Full | ADVERTISED_TP); } else { - if (!(bp->port.supported & + if (!(bp->port.supported[cfg_idx] & SUPPORTED_100baseT_Half)) { DP(NETIF_MSG_LINK, "100M half not supported\n"); @@ -169,7 +226,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) { + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_1000baseT_Full)) { DP(NETIF_MSG_LINK, "1G full not supported\n"); return -EINVAL; } @@ -185,7 +243,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) { + if (!(bp->port.supported[cfg_idx] + & SUPPORTED_2500baseX_Full)) { DP(NETIF_MSG_LINK, "2.5G full not supported\n"); return -EINVAL; @@ -201,7 +260,8 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) { + if (!(bp->port.supported[cfg_idx] + & SUPPORTED_10000baseT_Full)) { DP(NETIF_MSG_LINK, "10G full not supported\n"); return -EINVAL; } @@ -211,20 +271,23 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) break; default: - DP(NETIF_MSG_LINK, "Unsupported speed\n"); + DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed); return -EINVAL; } - bp->link_params.req_line_speed = cmd->speed; - bp->link_params.req_duplex = cmd->duplex; - bp->port.advertising = advertising; + bp->link_params.req_line_speed[cfg_idx] = speed; + bp->link_params.req_duplex[cfg_idx] = cmd->duplex; + bp->port.advertising[cfg_idx] = advertising; } DP(NETIF_MSG_LINK, "req_line_speed %d\n" DP_LEVEL " req_duplex %d advertising 0x%x\n", - bp->link_params.req_line_speed, bp->link_params.req_duplex, - bp->port.advertising); + bp->link_params.req_line_speed[cfg_idx], + bp->link_params.req_duplex[cfg_idx], + bp->port.advertising[cfg_idx]); + /* Set new config */ + bp->link_params.multi_phy_config = new_multi_phy_config; if (netif_running(dev)) { bnx2x_stats_handle(bp, STATS_EVENT_STOP); bnx2x_link_set(bp); @@ -937,10 +1000,9 @@ static void bnx2x_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { struct bnx2x *bp = netdev_priv(dev); - - epause->autoneg = (bp->link_params.req_flow_ctrl == - BNX2X_FLOW_CTRL_AUTO) && - (bp->link_params.req_line_speed == SPEED_AUTO_NEG); + int cfg_idx = bnx2x_get_link_cfg_idx(bp); + epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] == + BNX2X_FLOW_CTRL_AUTO); epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) == BNX2X_FLOW_CTRL_RX); @@ -956,7 +1018,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { struct bnx2x *bp = netdev_priv(dev); - + u32 cfg_idx = bnx2x_get_link_cfg_idx(bp); if (IS_E1HMF(bp)) return 0; @@ -964,29 +1026,31 @@ static int bnx2x_set_pauseparam(struct net_device *dev, DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); - bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; + bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO; if (epause->rx_pause) - bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX; + bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_RX; if (epause->tx_pause) - bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX; + bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_TX; - if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) - bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; + if (bp->link_params.req_flow_ctrl[cfg_idx] == BNX2X_FLOW_CTRL_AUTO) + bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_NONE; if (epause->autoneg) { - if (!(bp->port.supported & SUPPORTED_Autoneg)) { + if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { DP(NETIF_MSG_LINK, "autoneg not supported\n"); return -EINVAL; } - if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) - bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; + if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) { + bp->link_params.req_flow_ctrl[cfg_idx] = + BNX2X_FLOW_CTRL_AUTO; + } } DP(NETIF_MSG_LINK, - "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl); + "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl[cfg_idx]); if (netif_running(dev)) { bnx2x_stats_handle(bp, STATS_EVENT_STOP); @@ -1250,12 +1314,12 @@ test_mem_exit: return rc; } -static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up) +static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes) { int cnt = 1000; if (link_up) - while (bnx2x_link_test(bp) && cnt--) + while (bnx2x_link_test(bp, is_serdes) && cnt--) msleep(10); } @@ -1527,7 +1591,7 @@ static void bnx2x_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) { struct bnx2x *bp = netdev_priv(dev); - + u8 is_serdes; if (bp->recovery_state != BNX2X_RECOVERY_DONE) { printk(KERN_ERR "Handling parity error recovery. Try again later\n"); etest->flags |= ETH_TEST_FL_FAILED; @@ -1542,6 +1606,7 @@ static void bnx2x_self_test(struct net_device *dev, /* offline tests are not supported in MF mode */ if (IS_E1HMF(bp)) etest->flags &= ~ETH_TEST_FL_OFFLINE; + is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0; if (etest->flags & ETH_TEST_FL_OFFLINE) { int port = BP_PORT(bp); @@ -1553,11 +1618,12 @@ static void bnx2x_self_test(struct net_device *dev, /* disable input for TX port IF */ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0); - link_up = (bnx2x_link_test(bp) == 0); + link_up = bp->link_vars.link_up; + bnx2x_nic_unload(bp, UNLOAD_NORMAL); bnx2x_nic_load(bp, LOAD_DIAG); /* wait until link state is restored */ - bnx2x_wait_for_link(bp, link_up); + bnx2x_wait_for_link(bp, link_up, is_serdes); if (bnx2x_test_registers(bp) != 0) { buf[0] = 1; @@ -1578,7 +1644,7 @@ static void bnx2x_self_test(struct net_device *dev, bnx2x_nic_load(bp, LOAD_NORMAL); /* wait until link state is restored */ - bnx2x_wait_for_link(bp, link_up); + bnx2x_wait_for_link(bp, link_up, is_serdes); } if (bnx2x_test_nvram(bp) != 0) { buf[3] = 1; @@ -1589,7 +1655,7 @@ static void bnx2x_self_test(struct net_device *dev, etest->flags |= ETH_TEST_FL_FAILED; } if (bp->port.pmf) - if (bnx2x_link_test(bp) != 0) { + if (bnx2x_link_test(bp, is_serdes) != 0) { buf[5] = 1; etest->flags |= ETH_TEST_FL_FAILED; } diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index f494bc333f5..bab3b2d8cc7 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -238,7 +238,88 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ u16 xgxs_config_tx[4]; /* 0x1A0 */ - u32 Reserved1[64]; /* 0x1A8 */ + u32 Reserved1[57]; /* 0x1A8 */ + u32 speed_capability_mask2; /* 0x28C */ +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK 0x0000FFFF +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT 0 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10M_FULL 0x00000001 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3__ 0x00000002 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3___ 0x00000004 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_100M_FULL 0x00000008 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_1G 0x00000010 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_2_DOT_5G 0x00000020 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10G 0x00000040 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12G 0x00000080 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_12_DOT_5G 0x00000100 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_13G 0x00000200 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_15G 0x00000400 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D3_16G 0x00000800 + +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_MASK 0xFFFF0000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_SHIFT 16 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10M_FULL 0x00010000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0__ 0x00020000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0___ 0x00040000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_100M_FULL 0x00080000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_1G 0x00100000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_2_DOT_5G 0x00200000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10G 0x00400000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12G 0x00800000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_12_DOT_5G 0x01000000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_13G 0x02000000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_15G 0x04000000 +#define PORT_HW_CFG_SPEED_CAPABILITY2_D0_16G 0x08000000 + + /* In the case where two media types (e.g. copper and fiber) are + present and electrically active at the same time, PHY Selection + will determine which of the two PHYs will be designated as the + Active PHY and used for a connection to the network. */ + u32 multi_phy_config; /* 0x290 */ +#define PORT_HW_CFG_PHY_SELECTION_MASK 0x00000007 +#define PORT_HW_CFG_PHY_SELECTION_SHIFT 0 +#define PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT 0x00000000 +#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY 0x00000001 +#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY 0x00000002 +#define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY 0x00000003 +#define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY 0x00000004 + + /* When enabled, all second phy nvram parameters will be swapped + with the first phy parameters */ +#define PORT_HW_CFG_PHY_SWAPPED_MASK 0x00000008 +#define PORT_HW_CFG_PHY_SWAPPED_SHIFT 3 +#define PORT_HW_CFG_PHY_SWAPPED_DISABLED 0x00000000 +#define PORT_HW_CFG_PHY_SWAPPED_ENABLED 0x00000008 + + + /* Address of the second external phy */ + u32 external_phy_config2; /* 0x294 */ +#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_MASK 0x000000FF +#define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_SHIFT 0 + + /* The second XGXS external PHY type */ +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_MASK 0x0000FF00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SHIFT 8 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_DIRECT 0x00000000 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8071 0x00000100 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8072 0x00000200 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8073 0x00000300 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8705 0x00000400 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8706 0x00000500 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8726 0x00000600 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8481 0x00000700 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SFX7101 0x00000800 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727 0x00000900 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727_NOC 0x00000a00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823 0x00000b00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640 0x00000c00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833 0x00000d00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00 + + /* 4 times 16 bits for all 4 lanes. For some external PHYs (such as + 8706, 8726 and 8727) not all 4 values are needed. */ + u16 xgxs_config2_rx[4]; /* 0x296 */ + u16 xgxs_config2_tx[4]; /* 0x2A0 */ u32 lane_config; #define PORT_HW_CFG_LANE_SWAP_CFG_MASK 0x0000ffff @@ -532,10 +613,17 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ #define PORT_FEATURE_FLOW_CONTROL_NONE 0x00000400 /* The default for MCP link configuration, - uses the same defines as link_config */ + uses the same defines as link_config */ u32 mfw_wol_link_cfg; + /* The default for the driver of the second external phy, + uses the same defines as link_config */ + u32 link_config2; /* 0x47C */ - u32 reserved[19]; + /* The default for MCP of the second external phy, + uses the same defines as link_config */ + u32 mfw_wol_link_cfg2; /* 0x480 */ + + u32 Reserved2[17]; /* 0x484 */ }; @@ -703,8 +791,14 @@ struct drv_func_mb { * The optic module verification commands require bootcode * v5.0.6 or later */ -#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000 -#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006 +#define DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL 0xa0000000 +#define REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL 0x00050006 + /* + * The specific optic module verification command requires bootcode + * v5.2.12 or later + */ +#define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL 0xa1000000 +#define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL 0x00050234 #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 @@ -939,7 +1033,12 @@ struct shmem2_region { #define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV 0x00000040 #define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV 0x00000080 #define SHMEM_DCC_SUPPORT_DEFAULT SHMEM_DCC_SUPPORT_NONE - + u32 ext_phy_fw_version2[PORT_MAX]; + /* + * For backwards compatibility, if the mf_cfg_addr does not exist + * (the size filed is smaller than 0xc) the mf_cfg resides at the + * end of struct shmem_region + */ }; diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index e2509aab9f0..57178589897 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -899,6 +899,7 @@ static void bnx2x_xgxs_deassert(struct link_params *params) params->phy[INT_PHY].def_md_devad); } + void bnx2x_link_status_update(struct link_params *params, struct link_vars *vars) { @@ -906,10 +907,6 @@ void bnx2x_link_status_update(struct link_params *params, u8 link_10g; u8 port = params->port; - if (params->switch_cfg == SWITCH_CFG_1G) - vars->phy_flags = PHY_SERDES_FLAG; - else - vars->phy_flags = PHY_XGXS_FLAG; vars->link_status = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, port_mb[port].link_status)); @@ -1880,12 +1877,8 @@ static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "gp_status 0x%x phy_link_up %x line_speed %x\n", gp_status, vars->phy_link_up, vars->line_speed); - DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x" - " autoneg 0x%x\n", - vars->duplex, - vars->flow_ctrl, vars->autoneg); - DP(NETIF_MSG_LINK, "link_status 0x%x\n", vars->link_status); - + DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n", + vars->duplex, vars->flow_ctrl, vars->link_status); return rc; } @@ -2164,45 +2157,43 @@ static void bnx2x_link_int_enable(struct link_params *params) REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); } -static void bnx2x_8481_rearm_latch_signal(struct bnx2x *bp, u8 port, - u8 is_mi_int) +static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port, + u8 exp_mi_int) { - u32 latch_status = 0, is_mi_int_status; - /* Disable the MI INT ( external phy int ) - * by writing 1 to the status register. Link down indication - * is high-active-signal, so in this case we need to write the - * status to clear the XOR + u32 latch_status = 0; + + /** + * Disable the MI INT ( external phy int ) by writing 1 to the + * status register. Link down indication is high-active-signal, + * so in this case we need to write the status to clear the XOR */ /* Read Latched signals */ latch_status = REG_RD(bp, - NIG_REG_LATCH_STATUS_0 + port*8); - is_mi_int_status = REG_RD(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 + port*4); - DP(NETIF_MSG_LINK, "original_signal = 0x%x, nig_status = 0x%x," - "latch_status = 0x%x\n", - is_mi_int, is_mi_int_status, latch_status); + NIG_REG_LATCH_STATUS_0 + port*8); + DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status); /* Handle only those with latched-signal=up.*/ + if (exp_mi_int) + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + else + bnx2x_bits_dis(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + if (latch_status & 1) { - /* For all latched-signal=up,Write original_signal to status */ - if (is_mi_int) - bnx2x_bits_en(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 - + port*4, - NIG_STATUS_EMAC0_MI_INT); - else - bnx2x_bits_dis(bp, - NIG_REG_STATUS_INTERRUPT_PORT0 - + port*4, - NIG_STATUS_EMAC0_MI_INT); + /* For all latched-signal=up : Re-Arm Latch signals */ REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, (latch_status & 0xfffe) | (latch_status & 1)); } + /* For all latched-signal=up,Write original_signal to status */ } static void bnx2x_link_int_ack(struct link_params *params, - struct link_vars *vars, u8 is_10g, - u8 is_mi_int) + struct link_vars *vars, u8 is_10g) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -2213,12 +2204,6 @@ static void bnx2x_link_int_ack(struct link_params *params, (NIG_STATUS_XGXS0_LINK10G | NIG_STATUS_XGXS0_LINK_STATUS | NIG_STATUS_SERDES0_LINK_STATUS)); - if ((params->phy[EXT_PHY1].type - == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) || - (params->phy[EXT_PHY1].type - == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823)) { - bnx2x_8481_rearm_latch_signal(bp, port, is_mi_int); - } if (vars->phy_link_up) { if (is_10g) { /* Disable the 10G link interrupt @@ -2264,30 +2249,39 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len) u32 mask = 0xf0000000; u8 shift = 8*4; u8 digit; + u8 remove_leading_zeros = 1; if (*len < 10) { /* Need more than 10chars for this format */ *str_ptr = '\0'; + (*len)--; return -EINVAL; } while (shift > 0) { shift -= 4; digit = ((num & mask) >> shift); - if (digit < 0xa) + if (digit == 0 && remove_leading_zeros) { + mask = mask >> 4; + continue; + } else if (digit < 0xa) *str_ptr = digit + '0'; else *str_ptr = digit - 0xa + 'a'; + remove_leading_zeros = 0; str_ptr++; + (*len)--; mask = mask >> 4; if (shift == 4*4) { - *str_ptr = ':'; + *str_ptr = '.'; str_ptr++; + (*len)--; + remove_leading_zeros = 1; } } - *str_ptr = '\0'; return 0; } + static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) { str[0] = '\0'; @@ -2302,6 +2296,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, u32 spirom_ver = 0; u8 status = 0; u8 *ver_p = version; + u16 remain_len = len; if (version == NULL || params == NULL) return -EINVAL; bp = params->bp; @@ -2310,10 +2305,28 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, version[0] = '\0'; spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr); - if (params->phy[EXT_PHY1].format_fw_ver) + if (params->phy[EXT_PHY1].format_fw_ver) { status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver, ver_p, - &len); + &remain_len); + ver_p += (len - remain_len); + } + if ((params->num_phys == MAX_PHYS) && + (params->phy[EXT_PHY2].ver_addr != 0)) { + spirom_ver = REG_RD(bp, + params->phy[EXT_PHY2].ver_addr); + if (params->phy[EXT_PHY2].format_fw_ver) { + *ver_p = '/'; + ver_p++; + remain_len--; + status |= params->phy[EXT_PHY2].format_fw_ver( + spirom_ver, + ver_p, + &remain_len); + ver_p = version + (len - remain_len); + } + } + *ver_p = '\0'; return status; } @@ -2550,30 +2563,56 @@ u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed) } -u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars) +/** + * This function comes to reflect the actual link state read DIRECTLY from the + * HW + */ +u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, + u8 is_serdes) { struct bnx2x *bp = params->bp; u16 gp_status = 0, phy_index = 0; + u8 ext_phy_link_up = 0, serdes_phy_type; + struct link_vars temp_vars; CL45_RD_OVER_CL22(bp, ¶ms->phy[INT_PHY], MDIO_REG_BANK_GP_STATUS, MDIO_GP_STATUS_TOP_AN_STATUS1, &gp_status); /* link is up only if both local phy and external phy are up */ - if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { - u8 ext_phy_link_up = 1; - struct link_vars temp_vars; + if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) + return -ESRCH; + + switch (params->num_phys) { + case 1: + /* No external PHY */ + return 0; + case 2: + ext_phy_link_up = params->phy[EXT_PHY1].read_status( + ¶ms->phy[EXT_PHY1], + params, &temp_vars); + break; + case 3: /* Dual Media */ for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { - if (params->phy[phy_index].read_status) - ext_phy_link_up &= + serdes_phy_type = ((params->phy[phy_index].media_type == + ETH_PHY_SFP_FIBER) || + (params->phy[phy_index].media_type == + ETH_PHY_XFP_FIBER)); + + if (is_serdes != serdes_phy_type) + continue; + if (params->phy[phy_index].read_status) { + ext_phy_link_up |= params->phy[phy_index].read_status( ¶ms->phy[phy_index], params, &temp_vars); + } } - if (ext_phy_link_up) - return 0; + break; } + if (ext_phy_link_up) + return 0; return -ESRCH; } @@ -2619,6 +2658,19 @@ static u8 bnx2x_link_initialize(struct link_params *params, if (!non_ext_phy) for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { + /** + * No need to initialize second phy in case of first + * phy only selection. In case of second phy, we do + * need to initialize the first phy, since they are + * connected. + **/ + if (phy_index == EXT_PHY2 && + (bnx2x_phy_selection(params) == + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) { + DP(NETIF_MSG_LINK, "Not initializing" + "second phy\n"); + continue; + } params->phy[phy_index].config_init( ¶ms->phy[phy_index], params, vars); @@ -2816,6 +2868,40 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) if (!ext_phy_link_up) { ext_phy_link_up = 1; active_external_phy = phy_index; + } else { + switch (bnx2x_phy_selection(params)) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + /** + * In this option, the first PHY makes sure to pass the + * traffic through itself only. + * Its not clear how to reset the link on the second phy + **/ + active_external_phy = EXT_PHY1; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + /** + * In this option, the first PHY makes sure to pass the + * traffic through the second PHY. + **/ + active_external_phy = EXT_PHY2; + break; + default: + /** + * Link indication on both PHYs with the following cases |