bnx2x: Add link retry to 578xx-KR
authorYaniv Rosner <yanivr@broadcom.com>
Thu, 27 Oct 2011 05:09:46 +0000 (05:09 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Oct 2011 20:14:15 +0000 (16:14 -0400)
This fix solves a problem of no link on 578xx-KR by retrying to link up to
four timer using the periodic function.

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>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h

index edc9259..a47db9d 100644 (file)
 
 #define MAX_PACKET_SIZE                                        (9700)
 #define WC_UC_TIMEOUT                                  100
+#define MAX_KR_LINK_RETRY                              4
 
 /**********************************************************/
 /*                     INTERFACE                          */
@@ -3578,6 +3579,11 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        u16 val16 = 0, lane, bam37 = 0;
        struct bnx2x *bp = params->bp;
        DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
+
+       /* Disable Autoneg: re-enable it after adv is done. */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0);
+
        /* Check adding advertisement for 1G KX */
        if (((vars->line_speed == SPEED_AUTO_NEG) &&
             (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
@@ -3619,9 +3625,6 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
                         MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL,
                         0x03f0);
-       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-                        MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
-                        0x383f);
 
        /* Advertised speeds */
        bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
@@ -3648,19 +3651,22 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
        /* Advertise pause */
        bnx2x_ext_phy_set_pause(params, phy, vars);
 
-       /* Enable Autoneg */
-       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
-                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
-
-       /* Over 1G - AN local device user page 1 */
-       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
-                       MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
+       vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
 
        bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
                        MDIO_WC_REG_DIGITAL5_MISC7, &val16);
 
        bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
                         MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100);
+
+       /* Over 1G - AN local device user page 1 */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL3_UP1, 0x1f);
+
+       /* Enable Autoneg */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000);
+
 }
 
 static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
@@ -4129,6 +4135,85 @@ static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
        else
                return 0;
 }
+static int bnx2x_warpcore_get_sigdet(struct bnx2x_phy *phy,
+                                       struct link_params *params)
+{
+       u16 gp2_status_reg0, lane;
+       struct bnx2x *bp = params->bp;
+
+       lane = bnx2x_get_warpcore_lane(phy, params);
+
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_GP2_STATUS_GP_2_0,
+                                &gp2_status_reg0);
+
+       return (gp2_status_reg0 >> (8+lane)) & 0x1;
+}
+
+static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u32 serdes_net_if;
+       u16 gp_status1 = 0, lnkup = 0, lnkup_kr = 0;
+       u16 lane = bnx2x_get_warpcore_lane(phy, params);
+
+       vars->turn_to_run_wc_rt = vars->turn_to_run_wc_rt ? 0 : 1;
+
+       if (!vars->turn_to_run_wc_rt)
+               return;
+
+       /* return if there is no link partner */
+       if (!(bnx2x_warpcore_get_sigdet(phy, params))) {
+               DP(NETIF_MSG_LINK, "bnx2x_warpcore_get_sigdet false\n");
+               return;
+       }
+
+       if (vars->rx_tx_asic_rst) {
+               serdes_net_if = (REG_RD(bp, params->shmem_base +
+                               offsetof(struct shmem_region, dev_info.
+                               port_hw_config[params->port].default_cfg)) &
+                               PORT_HW_CFG_NET_SERDES_IF_MASK);
+
+               switch (serdes_net_if) {
+               case PORT_HW_CFG_NET_SERDES_IF_KR:
+                       /* Do we get link yet? */
+                       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, 0x81d1,
+                                                               &gp_status1);
+                       lnkup = (gp_status1 >> (8+lane)) & 0x1;/* 1G */
+                               /*10G KR*/
+                       lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
+
+                       DP(NETIF_MSG_LINK,
+                               "gp_status1 0x%x\n", gp_status1);
+
+                       if (lnkup_kr || lnkup) {
+                                       vars->rx_tx_asic_rst = 0;
+                                       DP(NETIF_MSG_LINK,
+                                       "link up, rx_tx_asic_rst 0x%x\n",
+                                       vars->rx_tx_asic_rst);
+                       } else {
+                               /*reset the lane to see if link comes up.*/
+                               bnx2x_warpcore_reset_lane(bp, phy, 1);
+                               bnx2x_warpcore_reset_lane(bp, phy, 0);
+
+                               /* restart Autoneg */
+                               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                       MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1200);
+
+                               vars->rx_tx_asic_rst--;
+                               DP(NETIF_MSG_LINK, "0x%x retry left\n",
+                               vars->rx_tx_asic_rst);
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+
+       } /*params->rx_tx_asic_rst*/
+
+}
 
 static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
                                       struct link_params *params,
@@ -12339,11 +12424,6 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 phy_idx;
-       if (!params) {
-               DP(NETIF_MSG_LINK, "Uninitialized params !\n");
-               return;
-       }
-
        for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
                if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
                        bnx2x_set_aer_mmd(params, &params->phy[phy_idx]);
@@ -12352,8 +12432,13 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
                }
        }
 
-       if (CHIP_IS_E3(bp))
+       if (CHIP_IS_E3(bp)) {
+               struct bnx2x_phy *phy = &params->phy[INT_PHY];
+               bnx2x_set_aer_mmd(params, phy);
                bnx2x_check_over_curr(params, vars);
+               bnx2x_warpcore_config_runtime(phy, params, vars);
+       }
+
 }
 
 u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base)
index c12db6d..2a46e63 100644 (file)
@@ -303,6 +303,9 @@ struct link_vars {
 #define PERIODIC_FLAGS_LINK_EVENT      0x0001
 
        u32 aeu_int_mask;
+       u8 rx_tx_asic_rst;
+       u8 turn_to_run_wc_rt;
+       u16 rsrv2;
 };
 
 /***********************************************************/