]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
bnx2x: Add Warpcore support for 578xx
authorYaniv Rosner <yanivr@broadcom.com>
Tue, 14 Jun 2011 01:34:12 +0000 (01:34 +0000)
committerDavid S. Miller <davem@conan.davemloft.net>
Wed, 15 Jun 2011 14:56:57 +0000 (10:56 -0400)
Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@conan.davemloft.net>
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_link.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h

index 873463966a0e155a51095e445115668931063801..b777d2c9633f7ae95862e38f58d8b1cb77b39bde 100644 (file)
 #define ETH_MAX_JUMBO_PACKET_SIZE      9600
 #define MDIO_ACCESS_TIMEOUT            1000
 #define BMAC_CONTROL_RX_ENABLE         2
+#define WC_LANE_MAX                    4
+#define I2C_SWITCH_WIDTH               2
+#define I2C_BSC0                       0
+#define I2C_BSC1                       1
+#define I2C_WA_RETRY_CNT               3
+#define MCPR_IMC_COMMAND_READ_OP       1
+#define MCPR_IMC_COMMAND_WRITE_OP      2
 
 /***********************************************************/
 /*                     Shortcut definitions               */
 #define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
 #define GP_STATUS_10G_KX4 \
                        MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
-
+#define        GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR
+#define        GP_STATUS_10G_XFI   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI
+#define        GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS
+#define        GP_STATUS_10G_SFI   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI
 #define LINK_10THD             LINK_STATUS_SPEED_AND_DUPLEX_10THD
 #define LINK_10TFD             LINK_STATUS_SPEED_AND_DUPLEX_10TFD
 #define LINK_100TXHD           LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
 #define LINK_2500XFD           LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
 #define LINK_10GTFD            LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
 #define LINK_10GXFD            LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
-
-#define PHY_XGXS_FLAG                  0x1
-#define PHY_SGMII_FLAG                 0x2
-#define PHY_SERDES_FLAG                        0x4
-
+#define LINK_20GTFD            LINK_STATUS_SPEED_AND_DUPLEX_20GTFD
+#define LINK_20GXFD            LINK_STATUS_SPEED_AND_DUPLEX_20GXFD
 /* */
 #define SFP_EEPROM_CON_TYPE_ADDR               0x2
        #define SFP_EEPROM_CON_TYPE_VAL_LC      0x7
 #define ETS_E3B0_PBF_MIN_W_VAL                         (10000)
 
 #define MAX_PACKET_SIZE                                        (9700)
+#define WC_UC_TIMEOUT                                  100
 
 /**********************************************************/
 /*                     INTERFACE                          */
@@ -282,6 +290,47 @@ static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
        return val;
 }
 
+/******************************************************************/
+/*                     EPIO/GPIO section                         */
+/******************************************************************/
+static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en)
+{
+       u32 epio_mask, gp_output, gp_oenable;
+
+       /* Sanity check */
+       if (epio_pin > 31) {
+               DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin);
+               return;
+       }
+       DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en);
+       epio_mask = 1 << epio_pin;
+       /* Set this EPIO to output */
+       gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS);
+       if (en)
+               gp_output |= epio_mask;
+       else
+               gp_output &= ~epio_mask;
+
+       REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output);
+
+       /* Set the value for this EPIO */
+       gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE);
+       REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask);
+}
+
+static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val)
+{
+       if (pin_cfg == PIN_CFG_NA)
+               return;
+       if (pin_cfg >= PIN_CFG_EPIO0) {
+               bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val);
+       } else {
+               u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3;
+               u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2;
+               bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port);
+       }
+}
+
 /******************************************************************/
 /*                             ETS section                       */
 /******************************************************************/
@@ -607,7 +656,10 @@ static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
        mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
        mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
                  EMAC_MDIO_MODE_CLOCK_CNT);
-       mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+       if (USES_WARPCORE(bp))
+               mode |= (74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+       else
+               mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
 
        mode |= (EMAC_MDIO_MODE_CLAUSE_45);
        REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
@@ -729,7 +781,7 @@ static void bnx2x_umac_enable(struct link_params *params,
        /* Enable RX and TX */
        val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN;
        val |= UMAC_COMMAND_CONFIG_REG_TX_ENA |
-              UMAC_COMMAND_CONFIG_REG_RX_ENA;
+               UMAC_COMMAND_CONFIG_REG_RX_ENA;
        REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val);
        udelay(50);
 
@@ -1649,7 +1701,7 @@ int bnx2x_update_pfc(struct link_params *params,
        else {
                val = REG_RD(bp, MISC_REG_RESET_REG_2);
                if ((val &
-                   (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
+                    (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))
                    == 0) {
                        DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n");
                        bnx2x_emac_enable(params, vars, 0);
@@ -1940,18 +1992,6 @@ static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
                case SPEED_10000:
                        init_crd = thresh + 553 - 22;
                        break;
-
-               case SPEED_12000:
-                       init_crd = thresh + 664 - 22;
-                       break;
-
-               case SPEED_13000:
-                       init_crd = thresh + 742 - 22;
-                       break;
-
-               case SPEED_16000:
-                       init_crd = thresh + 778 - 22;
-                       break;
                default:
                        DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
                                  line_speed);
@@ -2073,6 +2113,14 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
                        rc = -EFAULT;
                }
        }
+       /* Work around for E3 A0 */
+       if (phy->flags & FLAGS_MDC_MDIO_WA) {
+               phy->flags ^= FLAGS_DUMMY_READ;
+               if (phy->flags & FLAGS_DUMMY_READ) {
+                       u16 temp_val;
+                       bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
+               }
+       }
 
        return rc;
 }
@@ -2128,11 +2176,149 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
                        rc = -EFAULT;
                }
        }
+       /* Work around for E3 A0 */
+       if (phy->flags & FLAGS_MDC_MDIO_WA) {
+               phy->flags ^= FLAGS_DUMMY_READ;
+               if (phy->flags & FLAGS_DUMMY_READ) {
+                       u16 temp_val;
+                       bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val);
+               }
+       }
+
+       return rc;
+}
 
 
+/******************************************************************/
+/*                     BSC access functions from E3              */
+/******************************************************************/
+static void bnx2x_bsc_module_sel(struct link_params *params)
+{
+       int idx;
+       u32 board_cfg, sfp_ctrl;
+       u32 i2c_pins[I2C_SWITCH_WIDTH], i2c_val[I2C_SWITCH_WIDTH];
+       struct bnx2x *bp = params->bp;
+       u8 port = params->port;
+       /* Read I2C output PINs */
+       board_cfg = REG_RD(bp, params->shmem_base +
+                          offsetof(struct shmem_region,
+                                   dev_info.shared_hw_config.board));
+       i2c_pins[I2C_BSC0] = board_cfg & SHARED_HW_CFG_E3_I2C_MUX0_MASK;
+       i2c_pins[I2C_BSC1] = (board_cfg & SHARED_HW_CFG_E3_I2C_MUX1_MASK) >>
+                       SHARED_HW_CFG_E3_I2C_MUX1_SHIFT;
+
+       /* Read I2C output value */
+       sfp_ctrl = REG_RD(bp, params->shmem_base +
+                         offsetof(struct shmem_region,
+                                dev_info.port_hw_config[port].e3_cmn_pin_cfg));
+       i2c_val[I2C_BSC0] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX0_MASK) > 0;
+       i2c_val[I2C_BSC1] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX1_MASK) > 0;
+       DP(NETIF_MSG_LINK, "Setting BSC switch\n");
+       for (idx = 0; idx < I2C_SWITCH_WIDTH; idx++)
+               bnx2x_set_cfg_pin(bp, i2c_pins[idx], i2c_val[idx]);
+}
+
+static int bnx2x_bsc_read(struct link_params *params,
+                         struct bnx2x_phy *phy,
+                         u8 sl_devid,
+                         u16 sl_addr,
+                         u8 lc_addr,
+                         u8 xfer_cnt,
+                         u32 *data_array)
+{
+       u32 val, i;
+       int rc = 0;
+       struct bnx2x *bp = params->bp;
+
+       if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) {
+               DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid);
+               return -EINVAL;
+       }
+
+       if (xfer_cnt > 16) {
+               DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n",
+                                       xfer_cnt);
+               return -EINVAL;
+       }
+       bnx2x_bsc_module_sel(params);
+
+       xfer_cnt = 16 - lc_addr;
+
+       /* enable the engine */
+       val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
+       val |= MCPR_IMC_COMMAND_ENABLE;
+       REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
+
+       /* program slave device ID */
+       val = (sl_devid << 16) | sl_addr;
+       REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val);
+
+       /* start xfer with 0 byte to update the address pointer ???*/
+       val = (MCPR_IMC_COMMAND_ENABLE) |
+             (MCPR_IMC_COMMAND_WRITE_OP <<
+               MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
+               (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0);
+       REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
+
+       /* poll for completion */
+       i = 0;
+       val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
+       while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
+               udelay(10);
+               val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
+               if (i++ > 1000) {
+                       DP(NETIF_MSG_LINK, "wr 0 byte timed out after %d try\n",
+                                                               i);
+                       rc = -EFAULT;
+                       break;
+               }
+       }
+       if (rc == -EFAULT)
+               return rc;
+
+       /* start xfer with read op */
+       val = (MCPR_IMC_COMMAND_ENABLE) |
+               (MCPR_IMC_COMMAND_READ_OP <<
+               MCPR_IMC_COMMAND_OPERATION_BITSHIFT) |
+               (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) |
+                 (xfer_cnt);
+       REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val);
+
+       /* poll for completion */
+       i = 0;
+       val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
+       while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) {
+               udelay(10);
+               val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND);
+               if (i++ > 1000) {
+                       DP(NETIF_MSG_LINK, "rd op timed out after %d try\n", i);
+                       rc = -EFAULT;
+                       break;
+               }
+       }
+       if (rc == -EFAULT)
+               return rc;
+
+       for (i = (lc_addr >> 2); i < 4; i++) {
+               data_array[i] = REG_RD(bp, (MCP_REG_MCPR_IMC_DATAREG0 + i*4));
+#ifdef __BIG_ENDIAN
+               data_array[i] = ((data_array[i] & 0x000000ff) << 24) |
+                               ((data_array[i] & 0x0000ff00) << 8) |
+                               ((data_array[i] & 0x00ff0000) >> 8) |
+                               ((data_array[i] & 0xff000000) >> 24);
+#endif
+       }
        return rc;
 }
 
+static void bnx2x_cl45_read_or_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+                                    u8 devad, u16 reg, u16 or_val)
+{
+       u16 val;
+       bnx2x_cl45_read(bp, phy, devad, reg, &val);
+       bnx2x_cl45_write(bp, phy, devad, reg, val | or_val);
+}
+
 int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
                   u8 devad, u16 reg, u16 *ret_val)
 {
@@ -2168,6 +2354,59 @@ int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
        }
        return -EINVAL;
 }
+static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy,
+                                 struct link_params *params)
+{
+       u8 lane = 0;
+       struct bnx2x *bp = params->bp;
+       u32 path_swap, path_swap_ovr;
+       u8 path, port;
+
+       path = BP_PATH(bp);
+       port = params->port;
+
+       if (bnx2x_is_4_port_mode(bp)) {
+               u32 port_swap, port_swap_ovr;
+
+               /*figure out path swap value */
+               path_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP_OVWR);
+               if (path_swap_ovr & 0x1)
+                       path_swap = (path_swap_ovr & 0x2);
+               else
+                       path_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP);
+
+               if (path_swap)
+                       path = path ^ 1;
+
+               /*figure out port swap value */
+               port_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP_OVWR);
+               if (port_swap_ovr & 0x1)
+                       port_swap = (port_swap_ovr & 0x2);
+               else
+                       port_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP);
+
+               if (port_swap)
+                       port = port ^ 1;
+
+               lane = (port<<1) + path;
+       } else { /* two port mode - no port swap */
+
+               /*figure out path swap value */
+               path_swap_ovr =
+                       REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP_OVWR);
+               if (path_swap_ovr & 0x1) {
+                       path_swap = (path_swap_ovr & 0x2);
+               } else {
+                       path_swap =
+                               REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP);
+               }
+               if (path_swap)
+                       path = path ^ 1;
+
+               lane = path << 1 ;
+       }
+       return lane;
+}
 
 static void bnx2x_set_aer_mmd(struct link_params *params,
                              struct bnx2x_phy *phy)
@@ -2182,7 +2421,18 @@ static void bnx2x_set_aer_mmd(struct link_params *params,
        offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
                (phy->addr + ser_lane) : 0;
 
-       if (CHIP_IS_E2(bp))
+       if (USES_WARPCORE(bp)) {
+               aer_val = bnx2x_get_warpcore_lane(phy, params);
+               /*
+                * In Dual-lane mode, two lanes are joined together,
+                * so in order to configure them, the AER broadcast method is
+                * used here.
+                * 0x200 is the broadcast address for lanes 0,1
+                * 0x201 is the broadcast address for lanes 2,3
+                */
+               if (phy->flags & FLAGS_WC_DUAL_MODE)
+                       aer_val = (aer_val >> 1) | 0x200;
+       } else if (CHIP_IS_E2(bp))
                aer_val = 0x3800 + offset - 1;
        else
                aer_val = 0x3800 + offset;
@@ -2415,6 +2665,778 @@ static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
        }
        return ret;
 }
+/******************************************************************/
+/*                     Warpcore section                          */
+/******************************************************************/
+/* The init_internal_warpcore should mirror the xgxs,
+ * i.e. reset the lane (if needed), set aer for the
+ * init configuration, and set/clear SGMII flag. Internal
+ * phy init is done purely in phy_init stage.
+ */
+static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
+                                       struct link_params *params,
+                                       struct link_vars *vars) {
+       u16 val16 = 0, lane;
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n");
+       /* Check adding advertisement for 1G KX */
+       if (((vars->line_speed == SPEED_AUTO_NEG) &&
+            (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
+           (vars->line_speed == SPEED_1000)) {
+               u16 sd_digital;
+               val16 |= (1<<5);
+
+               /* Enable CL37 1G Parallel Detect */
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
+                                (sd_digital | 0x1));
+
+               DP(NETIF_MSG_LINK, "Advertize 1G\n");
+       }
+       if (((vars->line_speed == SPEED_AUTO_NEG) &&
+            (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
+           (vars->line_speed ==  SPEED_10000)) {
+               /* Check adding advertisement for 10G KR */
+               val16 |= (1<<7);
+               /* Enable 10G Parallel Detect */
+               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                               MDIO_WC_REG_PAR_DET_10G_CTRL, 1);
+
+               DP(NETIF_MSG_LINK, "Advertize 10G\n");
+       }
+
+       /* Set Transmit PMD settings */
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                     MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
+                    ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+                     (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
+                     (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL,
+                        0x03f0);
+       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,
+                        MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16);
+
+       /* 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);
+
+       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);
+}
+
+static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val;
+
+       /* Disable Autoneg */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7);
+
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_PAR_DET_10G_CTRL, 0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00);
+
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL3_UP1, 0x1);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL5_MISC7, 0xa);
+
+       /* Disable CL36 PCS Tx */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0);
+
+       /* Double Wide Single Data Rate @ pll rate */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF);
+
+       /* Leave cl72 training enable, needed for KR */
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+               MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150,
+               0x2);
+
+       /* Leave CL72 enabled */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
+                        &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL,
+                        val | 0x3800);
+
+       /* Set speed via PMA/PMD register */
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
+
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0xB);
+
+       /*Enable encoded forced speed */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x30);
+
+       /* Turn TX scramble payload only the 64/66 scrambler */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX66_CONTROL, 0x9);
+
+       /* Turn RX scramble payload only the 64/66 scrambler */
+       bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
+                                MDIO_WC_REG_RX66_CONTROL, 0xF9);
+
+       /* set and clear loopback to cause a reset to 64/66 decoder */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0);
+
+}
+
+static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      u8 is_xfi)
+{
+       struct bnx2x *bp = params->bp;
+       u16 misc1_val, tap_val, tx_driver_val, lane, val;
+       /* Hold rxSeqStart */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000));
+
+       /* Hold tx_fifo_reset */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1));
+
+       /* Disable CL73 AN */
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
+
+       /* Disable 100FX Enable and Auto-Detect */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_FX100_CTRL1, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA));
+
+       /* Disable 100FX Idle detect */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_FX100_CTRL3, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_FX100_CTRL3, (val | 0x0080));
+
+       /* Set Block address to Remote PHY & Clear forced_speed[5] */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL4_MISC3, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL4_MISC3, (val & 0xFF7F));
+
+       /* Turn off auto-detect & fiber mode */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
+                        (val & 0xFFEE));
+
+       /* Set filter_force_link, disable_false_link and parallel_detect */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
+                        ((val | 0x0006) & 0xFFFE));
+
+       /* Set XFI / SFI */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_MISC1, &misc1_val);
+
+       misc1_val &= ~(0x1f);
+
+       if (is_xfi) {
+               misc1_val |= 0x5;
+               tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
+                          (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
+                          (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
+               tx_driver_val =
+                     ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+                      (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
+                      (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
+
+       } else {
+               misc1_val |= 0x9;
+               tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
+                          (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
+                          (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
+               tx_driver_val =
+                     ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+                      (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
+                      (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
+       }
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
+
+       /* Set Transmit PMD settings */
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX_FIR_TAP,
+                        tap_val | MDIO_WC_REG_TX_FIR_TAP_ENABLE);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
+                        tx_driver_val);
+
+       /* Enable fiber mode, enable and invert sig_det */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd);
+
+       /* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL4_MISC3, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080);
+
+       /* 10G XFI Full Duplex */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100);
+
+       /* Release tx_fifo_reset */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, val & 0xFFFE);
+
+       /* Release rxSeqStart */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val & 0x7FFF));
+}
+
+static void bnx2x_warpcore_set_20G_KR2(struct bnx2x *bp,
+                                      struct bnx2x_phy *phy)
+{
+       DP(NETIF_MSG_LINK, "KR2 still not supported !!!\n");
+}
+
+static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp,
+                                        struct bnx2x_phy *phy,
+                                        u16 lane)
+{
+       /* Rx0 anaRxControl1G */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX0_ANARXCONTROL1G, 0x90);
+
+       /* Rx2 anaRxControl1G */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX2_ANARXCONTROL1G, 0x90);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW0, 0xE070);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW1, 0xC0D0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW2, 0xA0B0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW3, 0x8090);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW0_MASK, 0xF0F0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW1_MASK, 0xF0F0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW2_MASK, 0xF0F0);
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_SCW3_MASK, 0xF0F0);
+
+       /* Serdes Digital Misc1 */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6008);
+
+       /* Serdes Digital4 Misc3 */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL4_MISC3, 0x8088);
+
+       /* Set Transmit PMD settings */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX_FIR_TAP,
+                       ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
+                        (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
+                        (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) |
+                        MDIO_WC_REG_TX_FIR_TAP_ENABLE));
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                     MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
+                    ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
+                     (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
+                     (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
+}
+
+static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
+                                          struct link_params *params,
+                                          u8 fiber_mode)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val16, digctrl_kx1, digctrl_kx2;
+       u8 lane;
+
+       lane = bnx2x_get_warpcore_lane(phy, params);
+
+       /* Clear XFI clock comp in non-10G single lane mode. */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_RX66_CONTROL, &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_CONTROL, val16 & ~(3<<13));
+
+       if (phy->req_line_speed == SPEED_AUTO_NEG) {
+               /* SGMII Autoneg */
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                                MDIO_WC_REG_COMBO_IEEE0_MIICTRL,
+                                val16 | 0x1000);
+               DP(NETIF_MSG_LINK, "set SGMII AUTONEG\n");
+       } else {
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+               val16 &= 0xcfbf;
+               switch (phy->req_line_speed) {
+               case SPEED_10:
+                       break;
+               case SPEED_100:
+                       val16 |= 0x2000;
+                       break;
+               case SPEED_1000:
+                       val16 |= 0x0040;
+                       break;
+               default:
+                       DP(NETIF_MSG_LINK, "Speed not supported: 0x%x"
+                                          "\n", phy->req_line_speed);
+                       return;
+               }
+
+               if (phy->req_duplex == DUPLEX_FULL)
+                       val16 |= 0x0100;
+
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16);
+
+               DP(NETIF_MSG_LINK, "set SGMII force speed %d\n",
+                              phy->req_line_speed);
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+               DP(NETIF_MSG_LINK, "  (readback) %x\n", val16);
+       }
+
+       /* SGMII Slave mode and disable signal detect */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &digctrl_kx1);
+       if (fiber_mode)
+               digctrl_kx1 = 1;
+       else
+               digctrl_kx1 &= 0xff4a;
+
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
+                       digctrl_kx1);
+
+       /* Turn off parallel detect */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &digctrl_kx2);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
+                       (digctrl_kx2 & ~(1<<2)));
+
+       /* Re-enable parallel detect */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2,
+                       (digctrl_kx2 | (1<<2)));
+
+       /* Enable autodet */
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1,
+                       (digctrl_kx1 | 0x10));
+}
+
+static void bnx2x_warpcore_reset_lane(struct bnx2x *bp,
+                                     struct bnx2x_phy *phy,
+                                     u8 reset)
+{
+       u16 val;
+       /* Take lane out of reset after configuration is finished */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_DIGITAL5_MISC6, &val);
+       if (reset)
+               val |= 0xC000;
+       else
+               val &= 0x3FFF;
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL5_MISC6, val);
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL5_MISC6, &val);
+}
+
+
+       /* Clear SFI/XFI link settings registers */
+static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     u16 lane)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val16;
+
+       /* Set XFI clock comp as default. */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_RX66_CONTROL, &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13));
+
+       bnx2x_warpcore_reset_lane(bp, phy, 1);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_FX100_CTRL1, 0x014a);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_FX100_CTRL3, 0x0800);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_DIGITAL4_MISC3, 0x8008);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000);
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX_FIR_TAP, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140);
+       bnx2x_warpcore_reset_lane(bp, phy, 0);
+}
+
+static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp,
+                                               u32 chip_id,
+                                               u32 shmem_base, u8 port,
+                                               u8 *gpio_num, u8 *gpio_port)
+{
+       u32 cfg_pin;
+       *gpio_num = 0;
+       *gpio_port = 0;
+       if (CHIP_IS_E3(bp)) {
+               cfg_pin = (REG_RD(bp, shmem_base +
+                               offsetof(struct shmem_region,
+                               dev_info.port_hw_config[port].e3_sfp_ctrl)) &
+                               PORT_HW_CFG_E3_MOD_ABS_MASK) >>
+                               PORT_HW_CFG_E3_MOD_ABS_SHIFT;
+
+               /*
+                * Should not happen. This function called upon interrupt
+                * triggered by GPIO ( since EPIO can only generate interrupts
+                * to MCP).
+                * So if this function was called and none of the GPIOs was set,
+                * it means the shit hit the fan.
+                */
+               if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
+                   (cfg_pin > PIN_CFG_GPIO3_P1)) {
+                       DP(NETIF_MSG_LINK, "ERROR: Invalid cfg pin %x for "
+                                          "module detect indication\n",
+                                      cfg_pin);
+                       return -EINVAL;
+               }
+
+               *gpio_num = (cfg_pin - PIN_CFG_GPIO0_P0) & 0x3;
+               *gpio_port = (cfg_pin - PIN_CFG_GPIO0_P0) >> 2;
+       } else {
+               *gpio_num = MISC_REGISTERS_GPIO_3;
+               *gpio_port = port;
+       }
+       DP(NETIF_MSG_LINK, "MOD_ABS int GPIO%d_P%d\n", *gpio_num, *gpio_port);
+       return 0;
+}
+
+static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy,
+                                      struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u8 gpio_num, gpio_port;
+       u32 gpio_val;
+       if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id,
+                                     params->shmem_base, params->port,
+                                     &gpio_num, &gpio_port) != 0)
+               return 0;
+       gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
+
+       /* Call the handling function in case module is detected */
+       if (gpio_val == 0)
+               return 1;
+       else
+               return 0;
+}
+
+static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u32 serdes_net_if;
+       u8 fiber_mode;
+       u16 lane = bnx2x_get_warpcore_lane(phy, params);
+       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);
+       DP(NETIF_MSG_LINK, "Begin Warpcore init, link_speed %d, "
+                          "serdes_net_if = 0x%x\n",
+                      vars->line_speed, serdes_net_if);
+       bnx2x_set_aer_mmd(params, phy);
+
+       vars->phy_flags |= PHY_XGXS_FLAG;
+       if ((serdes_net_if == PORT_HW_CFG_NET_SERDES_IF_SGMII) ||
+           (phy->req_line_speed &&
+            ((phy->req_line_speed == SPEED_100) ||
+             (phy->req_line_speed == SPEED_10)))) {
+               vars->phy_flags |= PHY_SGMII_FLAG;
+               DP(NETIF_MSG_LINK, "Setting SGMII mode\n");
+               bnx2x_warpcore_clear_regs(phy, params, lane);
+               bnx2x_warpcore_set_sgmii_speed(phy, params, 0);
+       } else {
+               switch (serdes_net_if) {
+               case PORT_HW_CFG_NET_SERDES_IF_KR:
+                       /* Enable KR Auto Neg */
+                       if (params->loopback_mode == LOOPBACK_NONE)
+                               bnx2x_warpcore_enable_AN_KR(phy, params, vars);
+                       else {
+                               DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n");
+                               bnx2x_warpcore_set_10G_KR(phy, params, vars);
+                       }
+                       break;
+
+               case PORT_HW_CFG_NET_SERDES_IF_XFI:
+                       bnx2x_warpcore_clear_regs(phy, params, lane);
+                       if (vars->line_speed == SPEED_10000) {
+                               DP(NETIF_MSG_LINK, "Setting 10G XFI\n");
+                               bnx2x_warpcore_set_10G_XFI(phy, params, 1);
+                       } else {
+                               if (SINGLE_MEDIA_DIRECT(params)) {
+                                       DP(NETIF_MSG_LINK, "1G Fiber\n");
+                                       fiber_mode = 1;
+                               } else {
+                                       DP(NETIF_MSG_LINK, "10/100/1G SGMII\n");
+                                       fiber_mode = 0;
+                               }
+                               bnx2x_warpcore_set_sgmii_speed(phy,
+                                                               params,
+                                                               fiber_mode);
+                       }
+
+                       break;
+
+               case PORT_HW_CFG_NET_SERDES_IF_SFI:
+
+                       bnx2x_warpcore_clear_regs(phy, params, lane);
+                       if (vars->line_speed == SPEED_10000) {
+                               DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
+                               bnx2x_warpcore_set_10G_XFI(phy, params, 0);
+                       } else if (vars->line_speed == SPEED_1000) {
+                               DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
+                               bnx2x_warpcore_set_sgmii_speed(phy, params, 1);
+                       }
+                       /* Issue Module detection */
+                       if (bnx2x_is_sfp_module_plugged(phy, params))
+                               bnx2x_sfp_module_detection(phy, params);
+                       break;
+
+               case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
+                       if (vars->line_speed != SPEED_20000) {
+                               DP(NETIF_MSG_LINK, "Speed not supported yet\n");
+                               return;
+                       }
+                       DP(NETIF_MSG_LINK, "Setting 20G DXGXS\n");
+                       bnx2x_warpcore_set_20G_DXGXS(bp, phy, lane);
+                       /* Issue Module detection */
+
+                       bnx2x_sfp_module_detection(phy, params);
+                       break;
+
+               case PORT_HW_CFG_NET_SERDES_IF_KR2:
+                       if (vars->line_speed != SPEED_20000) {
+                               DP(NETIF_MSG_LINK, "Speed not supported yet\n");
+                               return;
+                       }
+                       DP(NETIF_MSG_LINK, "Setting 20G KR2\n");
+                       bnx2x_warpcore_set_20G_KR2(bp, phy);
+                       break;
+
+               default:
+                       DP(NETIF_MSG_LINK, "Unsupported Serdes Net Interface "
+                                          "0x%x\n", serdes_net_if);
+                       return;
+               }
+       }
+
+       /* Take lane out of reset after configuration is finished */
+       bnx2x_warpcore_reset_lane(bp, phy, 0);
+       DP(NETIF_MSG_LINK, "Exit config init\n");
+}
+
+static void bnx2x_sfp_e3_set_transmitter(struct link_params *params,
+                                        struct bnx2x_phy *phy,
+                                        u8 tx_en)
+{
+       struct bnx2x *bp = params->bp;
+       u32 cfg_pin;
+       u8 port = params->port;
+
+       cfg_pin = REG_RD(bp, params->shmem_base +
+                               offsetof(struct shmem_region,
+                               dev_info.port_hw_config[port].e3_sfp_ctrl)) &
+                               PORT_HW_CFG_TX_LASER_MASK;
+       /* Set the !tx_en since this pin is DISABLE_TX_LASER */
+       DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en);
+       /* For 20G, the expected pin to be used is 3 pins after the current */
+
+       bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1);
+       if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)
+               bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1);
+}
+
+static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy,
+                                     struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val16;
+       bnx2x_sfp_e3_set_transmitter(params, phy, 0);
+       bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
+       bnx2x_set_aer_mmd(params, phy);
+       /* Global register */
+       bnx2x_warpcore_reset_lane(bp, phy, 1);
+
+       /* Clear loopback settings (if any) */
+       /* 10G & 20G */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 &
+                        0xBFFF);
+
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 & 0xfffe);
+
+       /* Update those 1-copy registers */
+       CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
+                         MDIO_AER_BLOCK_AER_REG, 0);
+               /* Enable 1G MDIO (1-copy) */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
+                       &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
+                        val16 & ~0x10);
+
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_XGXSBLK1_LANECTRL2,
+                        val16 & 0xff00);
+
+}
+
+static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy,
+                                       struct link_params *params)
+{
+       struct bnx2x *bp = params->bp;
+       u16 val16;
+       u32 lane;
+       DP(NETIF_MSG_LINK, "Setting Warpcore loopback type %x, speed %d\n",
+                      params->loopback_mode, phy->req_line_speed);
+
+       if (phy->req_line_speed < SPEED_10000) {
+               /* 10/100/1000 */
+
+               /* Update those 1-copy registers */
+               CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
+                                 MDIO_AER_BLOCK_AER_REG, 0);
+               /* Enable 1G MDIO (1-copy) */
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
+                               &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_XGXSBLK0_XGXSCONTROL,
+                               val16 | 0x10);
+               /* Set 1G loopback based on lane (1-copy) */
+               lane = bnx2x_get_warpcore_lane(phy, params);
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_XGXSBLK1_LANECTRL2,
+                               val16 | (1<<lane));
+
+               /* Switch back to 4-copy registers */
+               bnx2x_set_aer_mmd(params, phy);
+               /* Global loopback, not recommended. */
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
+                               0x4000);
+       } else {
+               /* 10G & 20G */
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 |
+                                0x4000);
+
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16);
+               bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 | 0x1);
+       }
+}
+
+
 void bnx2x_link_status_update(struct link_params *params,
                              struct link_vars *vars)
 {
@@ -2470,7 +3492,9 @@ void bnx2x_link_status_update(struct link_params *params,
                        case LINK_10GTFD:
                                vars->line_speed = SPEED_10000;
                                break;
-
+                       case LINK_20GTFD:
+                               vars->line_speed = SPEED_20000;
+                               break;
                        default:
                                break;
                }
@@ -2491,7 +3515,10 @@ void bnx2x_link_status_update(struct link_params *params,
                } else {
                        vars->phy_flags &= ~PHY_SGMII_FLAG;
                }
-
+               if (vars->line_speed &&
+                   USES_WARPCORE(bp) &&
+                   (vars->line_speed == SPEED_1000))
+                       vars->phy_flags |= PHY_SGMII_FLAG;
                /* anything 10 and over uses the bmac */
                link_10g_plus = (vars->line_speed >= SPEED_10000);
 
@@ -2499,12 +3526,12 @@ void bnx2x_link_status_update(struct link_params *params,
                        if (USES_WARPCORE(bp))
                                vars->mac_type = MAC_TYPE_XMAC;
                        else
-                       vars->mac_type = MAC_TYPE_BMAC;
+                               vars->mac_type = MAC_TYPE_BMAC;
                } else {
                        if (USES_WARPCORE(bp))
                                vars->mac_type = MAC_TYPE_UMAC;
-               else
-                       vars->mac_type = MAC_TYPE_EMAC;
+                       else
+                               vars->mac_type = MAC_TYPE_EMAC;
                }
        } else { /* link down */
                DP(NETIF_MSG_LINK, "phy link down\n");
@@ -2860,9 +3887,6 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy,
                if (vars->line_speed == SPEED_10000)
                        reg_val |=
                                MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
-               if (vars->line_speed == SPEED_13000)
-                       reg_val |=
-                               MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G;
        }
 
        CL22_WR_OVER_CL45(bp, phy,
@@ -3212,45 +4236,25 @@ static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
                vars->link_status |=
                        LINK_STATUS_PARALLEL_DETECTION_USED;
 }
-
-static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
-                                     struct link_params *params,
-                                     struct link_vars *vars)
+static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy,
+                                    struct link_params *params,
+                                     struct link_vars *vars,
+                                     u16 is_link_up,
+                                     u16 speed_mask,
+                                     u16 is_duplex)
 {
        struct bnx2x *bp = params->bp;
-       u16 new_line_speed, gp_status;
-       int rc = 0;
-
-       /* Read gp_status */
-       CL22_RD_OVER_CL45(bp, phy,
-                         MDIO_REG_BANK_GP_STATUS,
-                         MDIO_GP_STATUS_TOP_AN_STATUS1,
-                         &gp_status);
-
        if (phy->req_line_speed == SPEED_AUTO_NEG)
                vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
-       if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
-               DP(NETIF_MSG_LINK, "phy link up gp_status=0x%x\n",
-                        gp_status);
+       if (is_link_up) {
+               DP(NETIF_MSG_LINK, "phy link up\n");
 
                vars->phy_link_up = 1;
                vars->link_status |= LINK_STATUS_LINK_UP;
 
-               if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
-                       vars->duplex = DUPLEX_FULL;
-               else
-                       vars->duplex = DUPLEX_HALF;
-
-               if (SINGLE_MEDIA_DIRECT(params)) {
-                       bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
-                       if (phy->req_line_speed == SPEED_AUTO_NEG)
-                               bnx2x_xgxs_an_resolve(phy, params, vars,
-                                                     gp_status);
-               }
-
-               switch (gp_status & GP_STATUS_SPEED_MASK) {
+               switch (speed_mask) {
                case GP_STATUS_10M:
-                       new_line_speed = SPEED_10;
+                       vars->line_speed = SPEED_10;
                        if (vars->duplex == DUPLEX_FULL)
                                vars->link_status |= LINK_10TFD;
                        else
@@ -3258,7 +4262,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
                        break;
 
                case GP_STATUS_100M:
-                       new_line_speed = SPEED_100;
+                       vars->line_speed = SPEED_100;
                        if (vars->duplex == DUPLEX_FULL)
                                vars->link_status |= LINK_100TXFD;
                        else
@@ -3267,7 +4271,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
 
                case GP_STATUS_1G:
                case GP_STATUS_1G_KX:
-                       new_line_speed = SPEED_1000;
+                       vars->line_speed = SPEED_1000;
                        if (vars->duplex == DUPLEX_FULL)
                                vars->link_status |= LINK_1000TFD;
                        else
@@ -3275,7 +4279,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
                        break;
 
                case GP_STATUS_2_5G:
-                       new_line_speed = SPEED_2500;
+                       vars->line_speed = SPEED_2500;
                        if (vars->duplex == DUPLEX_FULL)
                                vars->link_status |= LINK_2500TFD;
                        else
@@ -3286,25 +4290,28 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
                case GP_STATUS_6G:
                        DP(NETIF_MSG_LINK,
                                 "link speed unsupported  gp_status 0x%x\n",
-                                 gp_status);
+                                 speed_mask);
                        return -EINVAL;
 
                case GP_STATUS_10G_KX4:
                case GP_STATUS_10G_HIG:
                case GP_STATUS_10G_CX4:
-                       new_line_speed = SPEED_10000;
+               case GP_STATUS_10G_KR:
+               case GP_STATUS_10G_SFI:
+               case GP_STATUS_10G_XFI:
+                       vars->line_speed = SPEED_10000;
                        vars->link_status |= LINK_10GTFD;
                        break;
-
+               case GP_STATUS_20G_DXGXS:
+                       vars->line_speed = SPEED_20000;
+                       vars->link_status |= LINK_20GTFD;
+                       break;
                default:
                        DP(NETIF_MSG_LINK,
                                  "link speed unsupported gp_status 0x%x\n",
-                                 gp_status);
+                                 speed_mask);
                        return -EINVAL;
                }
-
-               vars->line_speed = new_line_speed;
-
        } else { /* link_down */
                DP(NETIF_MSG_LINK, "phy link down\n");
 
@@ -3313,7 +4320,47 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
                vars->duplex = DUPLEX_FULL;
                vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
                vars->mac_type = MAC_TYPE_NONE;
+       }
+       DP(NETIF_MSG_LINK, " phy_link_up %x line_speed %d\n",
+                   vars->phy_link_up, vars->line_speed);
+       return 0;
+}
+
+static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     struct link_vars *vars)
+{
+
+       struct bnx2x *bp = params->bp;
+
+       u16 gp_status, duplex = DUPLEX_HALF, link_up = 0, speed_mask;
+       int rc = 0;
+
+       /* Read gp_status */
+       CL22_RD_OVER_CL45(bp, phy,
+                         MDIO_REG_BANK_GP_STATUS,
+                         MDIO_GP_STATUS_TOP_AN_STATUS1,
+                         &gp_status);
+       if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
+               duplex = DUPLEX_FULL;
+       if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)
+               link_up = 1;
+       speed_mask = gp_status & GP_STATUS_SPEED_MASK;
+       DP(NETIF_MSG_LINK, "gp_status 0x%x, is_link_up %d, speed_mask 0x%x\n",
+                      gp_status, link_up, speed_mask);
+       rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, speed_mask,
+                                        duplex);
+       if (rc == -EINVAL)
+               return rc;
 
+       if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
+               if (SINGLE_MEDIA_DIRECT(params)) {
+                       bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status);
+                       if (phy->req_line_speed == SPEED_AUTO_NEG)
+                               bnx2x_xgxs_an_resolve(phy, params, vars,
+                                                     gp_status);
+               }
+       } else { /* link_down */
                if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
                    SINGLE_MEDIA_DIRECT(params)) {
                        /* Check signal is detected */
@@ -3321,13 +4368,86 @@ static int 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 link_status 0x%x\n",
                   vars->duplex, vars->flow_ctrl, vars->link_status);
        return rc;
 }
 
+static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
+                                    struct link_params *params,
+                                    struct link_vars *vars)
+{
+
+       struct bnx2x *bp = params->bp;
+
+       u8 lane;
+       u16 gp_status1, gp_speed, link_up, duplex = DUPLEX_FULL;
+       int rc = 0;
+       lane = bnx2x_get_warpcore_lane(phy, params);
+       /* Read gp_status */
+       if (phy->req_line_speed > SPEED_10000) {
+               u16 temp_link_up;
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               1, &temp_link_up);
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               1, &link_up);
+               DP(NETIF_MSG_LINK, "PCS RX link status = 0x%x-->0x%x\n",
+                              temp_link_up, link_up);
+               link_up &= (1<<2);
+               if (link_up)
+                       bnx2x_ext_phy_resolve_fc(phy, params, vars);
+       } else {
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_GP2_STATUS_GP_2_1, &gp_status1);
+               DP(NETIF_MSG_LINK, "0x81d1 = 0x%x\n", gp_status1);
+               /* Check for either KR or generic link up. */
+               gp_status1 = ((gp_status1 >> 8) & 0xf) |
+                       ((gp_status1 >> 12) & 0xf);
+               link_up = gp_status1 & (1 << lane);
+               if (link_up && SINGLE_MEDIA_DIRECT(params)) {
+                       u16 pd, gp_status4;
+                       if (phy->req_line_speed == SPEED_AUTO_NEG) {
+                               /* Check Autoneg complete */
+                               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                                               MDIO_WC_REG_GP2_STATUS_GP_2_4,
+                                               &gp_status4);
+                               if (gp_status4 & ((1<<12)<<lane))
+                                       vars->link_status |=
+                                       LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+
+                               /* Check parallel detect used */
+                               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                                               MDIO_WC_REG_PAR_DET_10G_STATUS,
+                                               &pd);
+                               if (pd & (1<<15))
+                                       vars->link_status |=
+                                       LINK_STATUS_PARALLEL_DETECTION_USED;
+                       }
+                       bnx2x_ext_phy_resolve_fc(phy, params, vars);
+               }
+       }
+
+       if (lane < 2) {
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
+       } else {
+               bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                               MDIO_WC_REG_GP2_STATUS_GP_2_3, &gp_speed);
+       }
+       DP(NETIF_MSG_LINK, "lane %d gp_speed 0x%x\n", lane, gp_speed);
+
+       if ((lane & 1) == 0)
+               gp_speed <<= 8;
+       gp_speed &= 0x3f00;
+
+
+       rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed,
+                                        duplex);
+
+       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;
+}
 static void bnx2x_set_gmii_tx_driver(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
@@ -3555,7 +4675,11 @@ static void bnx2x_link_int_enable(struct link_params *params)
        struct bnx2x *bp = params->bp;
 
        /* Setting the status to report on link up for either XGXS or SerDes */
-       if (params->switch_cfg == SWITCH_CFG_10G) {
+       if (CHIP_IS_E3(bp)) {
+               mask = NIG_MASK_XGXS0_LINK_STATUS;
+               if (!(SINGLE_MEDIA_DIRECT(params)))
+                       mask |= NIG_MASK_MI_INT;
+       } else if (params->switch_cfg == SWITCH_CFG_10G) {
                mask = (NIG_MASK_XGXS0_LINK10G |
                        NIG_MASK_XGXS0_LINK_STATUS);
                DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
@@ -3628,11 +4752,11 @@ static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port,
 }
 
 static void bnx2x_link_int_ack(struct link_params *params,
-                              struct link_vars *vars, u8 is_10g)
+                              struct link_vars *vars, u8 is_10g_plus)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
-
+       u32 mask;
        /*
         * First reset all status we assume only one line will be
         * change at a time
@@ -3642,43 +4766,30 @@ static void bnx2x_link_int_ack(struct link_params *params,
                        NIG_STATUS_XGXS0_LINK_STATUS |
                        NIG_STATUS_SERDES0_LINK_STATUS));
        if (vars->phy_link_up) {
-               if (is_10g) {
-                       /*
-                        * Disable the 10G link interrupt by writing 1 to the
-                        * status register
-                        */
-                       DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_STATUS_XGXS0_LINK10G);
-
-               } else if (params->switch_cfg == SWITCH_CFG_10G) {
-                       /*
-                        * Disable the link interrupt by writing 1 to the
-                        * relevant lane in the status register
-                        */
-                       u32 ser_lane = ((params->lane_config &
+               if (USES_WARPCORE(bp))
+                       mask = NIG_STATUS_XGXS0_LINK_STATUS;
+               else {
+                       if (is_10g_plus)
+                               mask = NIG_STATUS_XGXS0_LINK10G;
+                       else if (params->switch_cfg == SWITCH_CFG_10G) {
+                               /*
+                                * Disable the link interrupt by writing 1 to
+                                * the relevant lane in the status register
+                                */
+                               u32 ser_lane =
+                                       ((params->lane_config &
                                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
                                    PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
-
-                       DP(NETIF_MSG_LINK, "%d speed XGXS phy link up\n",
-                                vars->line_speed);
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     ((1 << ser_lane) <<
-                                      NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
-
-               } else { /* SerDes */
-                       DP(NETIF_MSG_LINK, "SerDes phy link up\n");
-                       /*
-                        * Disable the link interrupt by writing 1 to the status
-                        * register
-                        */
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_STATUS_SERDES0_LINK_STATUS);
+                               mask = ((1 << ser_lane) <<
+                                      NIG_STATUS_XGXS0_LINK_STATUS_SIZE);
+                       } else
+                               mask = NIG_STATUS_SERDES0_LINK_STATUS;
                }
-
+               DP(NETIF_MSG_LINK, "Ack link up interrupt with mask 0x%x\n",
+                              mask);
+               bnx2x_bits_en(bp,
+                             NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+                             mask);
        }
 }
 
@@ -3775,15 +4886,18 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
 
        if (phy->req_line_speed != SPEED_1000) {
-               u32 md_devad;
+               u32 md_devad = 0;
 
                DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
 
-               /* change the uni_phy_addr in the nig */
-               md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
-                                      port*0x18));
+               if (!CHIP_IS_E3(bp)) {
+                       /* change the uni_phy_addr in the nig */
+                       md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD +
+                                              port*0x18));
 
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+                       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+                              0x5);
+               }
 
                bnx2x_cl45_write(bp, phy,
                                 5,
@@ -3800,8 +4914,11 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
                /* set aer mmd back */
                bnx2x_set_aer_mmd(params, phy);
 
-               /* and md_devad */
-               REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
+               if (!CHIP_IS_E3(bp)) {
+                       /* and md_devad */
+                       REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18,
+                              md_devad);
+               }
        } else {
                u16 mii_ctrl;
                DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
@@ -3875,7 +4992,9 @@ int bnx2x_set_led(struct link_params *params,
                                        (tmp | EMAC_LED_OVERRIDE));
                                return rc;
                        }
-               } else if (SINGLE_MEDIA_DIRECT(params)) {
+               } else if (SINGLE_MEDIA_DIRECT(params) &&
+                          (CHIP_IS_E1x(bp) ||
+                           CHIP_IS_E2(bp))) {
                        /*
                         * This is a work-around for HW issue found when link
                         * is up in CL73
@@ -3934,14 +5053,42 @@ int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
        u16 gp_status = 0, phy_index = 0;
        u8 ext_phy_link_up = 0, serdes_phy_type;
        struct link_vars temp_vars;
-
-       CL22_RD_OVER_CL45(bp, &params->phy[INT_PHY],
+       struct bnx2x_phy *int_phy = &params->phy[INT_PHY];
+
+       if (CHIP_IS_E3(bp)) {
+               u16 link_up;
+               if (params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)]
+                   > SPEED_10000) {
+                       /* Check 20G link */
+                       bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
+                                       1, &link_up);
+                       bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
+                                       1, &link_up);
+                       link_up &= (1<<2);
+               } else {
+                       /* Check 10G link and below*/
+                       u8 lane = bnx2x_get_warpcore_lane(int_phy, params);
+                       bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD,
+                                       MDIO_WC_REG_GP2_STATUS_GP_2_1,
+                                       &gp_status);
+                       gp_status = ((gp_status >> 8) & 0xf) |
+                               ((gp_status >> 12) & 0xf);
+                       link_up = gp_status & (1 << lane);
+               }
+               if (!link_up)
+                       return -ESRCH;
+       } else {
+               CL22_RD_OVER_CL45(bp, 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))
                return -ESRCH;
+       }
+       /* In XGXS loopback mode, do not check external PHY */
+       if (params->loopback_mode == LOOPBACK_XGXS)
+               return 0;
 
        switch (params->num_phys) {
        case 1:
@@ -3997,8 +5144,8 @@ static int bnx2x_link_initialize(struct link_params *params,
         * (no external phys), or this board has external phy which requires
         * to first.
         */
-
-       bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
+       if (!USES_WARPCORE(bp))
+               bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
        /* init ext phy and enable link state int */
        non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
                       (params->loopback_mode == LOOPBACK_XGXS));
@@ -4007,7 +5154,9 @@ static int bnx2x_link_initialize(struct link_params *params,
            (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) ||
            (params->loopback_mode == LOOPBACK_EXT_PHY)) {
                struct bnx2x_phy *phy = &params->phy[INT_PHY];
-               if (vars->line_speed == SPEED_AUTO_NEG)
+               if (vars->line_speed == SPEED_AUTO_NEG &&
+                   (CHIP_IS_E1x(bp) ||
+                    CHIP_IS_E2(bp)))
                        bnx2x_set_parallel_detection(phy, params);
                        if (params->phy[INT_PHY].config_init)
                                params->phy[INT_PHY].config_init(phy,
@@ -4203,7 +5352,7 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
        struct bnx2x *bp = params->bp;
        struct link_vars phy_vars[MAX_PHYS];
        u8 port = params->port;
-       u8 link_10g, phy_index;
+       u8 link_10g_plus, phy_index;
        u8 ext_phy_link_up = 0, cur_link_up;
        int rc = 0;
        u8 is_mi_int = 0;
@@ -4221,6 +5370,9 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
                phy_vars[phy_index].fault_detected = 0;
        }
 
+       if (USES_WARPCORE(bp))
+               bnx2x_set_aer_mmd(params, &params->phy[INT_PHY]);
+
        DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
                 port, (vars->phy_flags & PHY_XGXS_FLAG),
                 REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4));
@@ -4392,14 +5544,9 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
        }
 
        /* anything 10 and over uses the bmac */
-       link_10g = ((vars->line_speed == SPEED_10000) ||
-                   (vars->line_speed == SPEED_12000) ||
-                   (vars->line_speed == SPEED_12500) ||
-                   (vars->line_speed == SPEED_13000) ||
-                   (vars->line_speed == SPEED_15000) ||
-                   (vars->line_speed == SPEED_16000));
+       link_10g_plus = (vars->line_speed >= SPEED_10000);
 
-       bnx2x_link_int_ack(params, vars, link_10g);
+       bnx2x_link_int_ack(params, vars, link_10g_plus);
 
        /*
         * In case external phy link is up, and internal link is down
@@ -4440,7 +5587,7 @@ int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
                         (phy_vars[active_external_phy].fault_detected == 0));
 
        if (vars->link_up)
-               rc = bnx2x_update_link_up(params, vars, link_10g);
+               rc = bnx2x_update_link_up(params, vars, link_10g_plus);
        else
                rc = bnx2x_update_link_down(params, vars);
 
@@ -5135,9 +6282,10 @@ static u8 bnx2x_get_gpio_port(struct link_params *params)
        swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
        return gpio_port ^ (swap_val && swap_override);
 }
-static void bnx2x_sfp_set_transmitter(struct link_params *params,
-                                     struct bnx2x_phy *phy,
-                                     u8 tx_en)
+
+static void bnx2x_sfp_e1e2_set_transmitter(struct link_params *params,
+                                          struct bnx2x_phy *phy,
+                                          u8 tx_en)
 {
        u16 val;
        u8 port = params->port;
@@ -5192,6 +6340,18 @@ static void bnx2x_sfp_set_transmitter(struct link_params *params,
        }
 }
 
+static void bnx2x_sfp_set_transmitter(struct link_params *params,
+                                     struct bnx2x_phy *phy,
+                                     u8 tx_en)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "Setting SFP+ transmitter to %d\n", tx_en);
+       if (CHIP_IS_E3(bp))
+               bnx2x_sfp_e3_set_transmitter(params, phy, tx_en);
+       else
+               bnx2x_sfp_e1e2_set_transmitter(params, phy, tx_en);
+}
+
 static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
                                             struct link_params *params,
                                             u16 addr, u8 byte_cnt, u8 *o_buf)
@@ -5258,6 +6418,42 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
        return -EINVAL;
 }
 
+static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                                struct link_params *params,
+                                                u16 addr, u8 byte_cnt,
+                                                u8 *o_buf)
+{
+       int rc = 0;
+       u8 i, j = 0, cnt = 0;
+       u32 data_array[4];
+       u16 addr32;
+       struct bnx2x *bp = params->bp;
+       /*DP(NETIF_MSG_LINK, "bnx2x_direct_read_sfp_module_eeprom:"
+                                       " addr %d, cnt %d\n",
+                                       addr, byte_cnt);*/
+       if (byte_cnt > 16) {
+               DP(NETIF_MSG_LINK, "Reading from eeprom is"
+                           " is limited to 16 bytes\n");
+               return -EINVAL;
+       }
+
+       /* 4 byte aligned address */
+       addr32 = addr & (~0x3);
+       do {
+               rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
+                                   data_array);
+       } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
+
+       if (rc == 0) {
+               for (i = (addr - addr32); i < byte_cnt + (addr - addr32); i++) {
+                       o_buf[j] = *((u8 *)data_array + i);
+                       j++;
+               }
+       }
+
+       return rc;
+}
+
 static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
                                             struct link_params *params,
                                             u16 addr, u8 byte_cnt, u8 *o_buf)
@@ -5360,6 +6556,10 @@ int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
                rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
                                                       byte_cnt, o_buf);
        break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+               rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
+                                                          byte_cnt, o_buf);
+       break;
        }
        return rc;
 }
@@ -5573,8 +6773,8 @@ static void bnx2x_8727_power_module(struct bnx2x *bp,
         * In the GPIO register, bit 4 is use to determine if the GPIOs are
         * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
         * output
-        * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
-        * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+        * Bits 0-1 determine the GPIOs value for OUTPUT in case bit 4 val is 0
+        * Bits 8-9 determine the GPIOs value for INPUT in case bit 4 val is 1
         * where the 1st bit is the over-current(only input), and 2nd bit is
         * for power( only output )
         *
@@ -5703,7 +6903,7 @@ static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
        }
 }
 
-static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
+static void bnx2x_set_e1e2_module_fault_led(struct link_params *params,
                                           u8 gpio_mode)
 {
        struct bnx2x *bp = params->bp;
@@ -5735,6 +6935,58 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
        }
 }
 
+static void bnx2x_set_e3_module_fault_led(struct link_params *params,
+                                         u8 gpio_mode)
+{
+       u32 pin_cfg;
+       u8 port = params->port;
+       struct bnx2x *bp = params->bp;
+       pin_cfg = (REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region,
+                                 dev_info.port_hw_config[port].e3_sfp_ctrl)) &
+               PORT_HW_CFG_E3_FAULT_MDL_LED_MASK) >>
+               PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT;
+       DP(NETIF_MSG_LINK, "Setting Fault LED to %d using pin cfg %d\n",
+                      gpio_mode, pin_cfg);
+       bnx2x_set_cfg_pin(bp, pin_cfg, gpio_mode);
+}
+
+static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
+                                          u8 gpio_mode)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "Setting SFP+ module fault LED to %d\n", gpio_mode);
+       if (CHIP_IS_E3(bp)) {
+               /*
+                * Low ==> if SFP+ module is supported otherwise
+                * High ==> if SFP+ module is not on the approved vendor list
+                */
+               bnx2x_set_e3_module_fault_led(params, gpio_mode);
+       } else
+               bnx2x_set_e1e2_module_fault_led(params, gpio_mode);
+}
+
+static void bnx2x_warpcore_power_module(struct link_params *params,
+                                       struct bnx2x_phy *phy,
+                                       u8 power)
+{
+       u32 pin_cfg;
+       struct bnx2x *bp = params->bp;
+
+       pin_cfg = (REG_RD(bp, params->shmem_base +
+                         offsetof(struct shmem_region,
+                       dev_info.port_hw_config[params->port].e3_sfp_ctrl)) &
+                       PORT_HW_CFG_E3_PWR_DIS_MASK) >>
+                       PORT_HW_CFG_E3_PWR_DIS_SHIFT;
+       DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n",
+                      power, pin_cfg);
+       /*
+        * Low ==> corresponding SFP+ module is powered
+        * high ==> the SFP+ module is powered down
+        */
+       bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1);
+}
+
 static void bnx2x_power_sfp_module(struct link_params *params,
                                   struct bnx2x_phy *phy,
                                   u8 power)
@@ -5747,9 +6999,47 @@ static void bnx2x_power_sfp_module(struct link_params *params,
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
                bnx2x_8727_power_module(params->bp, phy, power);
                break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+               bnx2x_warpcore_power_module(params, phy, power);
+               break;
+       default:
+               break;
+       }
+}
+static void bnx2x_warpcore_set_limiting_mode(struct link_params *params,
+                                            struct bnx2x_phy *phy,
+                                            u16 edc_mode)
+{
+       u16 val = 0;
+       u16 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
+       struct bnx2x *bp = params->bp;
+
+       u8 lane = bnx2x_get_warpcore_lane(phy, params);
+       /* This is a global register which controls all lanes */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
+       val &= ~(0xf << (lane << 2));
+
+       switch (edc_mode) {
+       case EDC_MODE_LINEAR:
+       case EDC_MODE_LIMITING:
+               mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT;
+               break;
+       case EDC_MODE_PASSIVE_DAC:
+               mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC;
+               break;
        default:
                break;
        }
+
+       val |= (mode << (lane << 2));
+       bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
+                        MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, val);
+       /* A must read */
+       bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
+                       MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val);
+
+
 }
 
 static void bnx2x_set_limiting_mode(struct link_params *params,
@@ -5764,6 +7054,9 @@ static void bnx2x_set_limiting_mode(struct link_params *params,
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
                bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
                break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+               bnx2x_warpcore_set_limiting_mode(params, phy, edc_mode);
+               break;
        }
 }
 
@@ -5828,23 +7121,33 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
 void bnx2x_handle_module_detect_int(struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       struct bnx2x_phy *phy = &params->phy[EXT_PHY1];
+       struct bnx2x_phy *phy;
        u32 gpio_val;
-       u8 port = params->port;
+       u8 gpio_num, gpio_port;
+       if (CHIP_IS_E3(bp))
+               phy = &params->phy[INT_PHY];
+       else
+               phy = &params->phy[EXT_PHY1];
+
+       if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base,
+                                     params->port, &gpio_num, &gpio_port) ==
+           -EINVAL) {
+               DP(NETIF_MSG_LINK, "Failed to get MOD_ABS interrupt config\n");
+               return;
+       }
 
        /* Set valid module led off */
        bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH);
 
        /* Get current gpio val reflecting module plugged in / out*/
-       gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
+       gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port);
 
        /* Call the handling function in case module is detected */
        if (gpio_val == 0) {
                bnx2x_power_sfp_module(params, phy, 1);
-               bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
+               bnx2x_set_gpio_int(bp, gpio_num,
                                   MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
-                                  port);
-
+                                  gpio_port);
                if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
                        bnx2x_sfp_module_detection(phy, params);
                else
@@ -5855,9 +7158,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                                          port_feature_config[params->port].
                                          config));
 
-               bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
+               bnx2x_set_gpio_int(bp, gpio_num,
                                   MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
-                                  port);
+                                  gpio_port);
                /*
                 * Module was plugged out.
                 * Disable transmit for this module
@@ -7762,6 +9065,43 @@ static struct bnx2x_phy phy_xgxs = {
        .set_link_led   = (set_link_led_t)NULL,
        .phy_specific_func = (phy_specific_func_t)NULL
 };
+static struct bnx2x_phy phy_warpcore = {
+       .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
+       .addr           = 0xff,
+       .def_md_devad   = 0,
+       .flags          = FLAGS_HW_LOCK_REQUIRED,
+       .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_20000baseKR2_Full |
+                            SUPPORTED_20000baseMLD2_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_warpcore_config_init,
+       .read_status    = (read_status_t)bnx2x_warpcore_read_status,
+       .link_reset     = (link_reset_t)bnx2x_warpcore_link_reset,
+       .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback,
+       .format_fw_ver  = (format_fw_ver_t)NULL,
+       .hw_reset       = (hw_reset_t)NULL,
+       .set_link_led   = (set_link_led_t)NULL,
+       .phy_specific_func = (phy_specific_func_t)NULL
+};
+
 
 static struct bnx2x_phy phy_7101 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
@@ -8126,22 +9466,105 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
                        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:
+       DP(NETIF_MSG_LINK, ":chip_id = 0x%x\n", chip_id);
+       if (USES_WARPCORE(bp)) {
+               u32 serdes_net_if;
                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;
+                                 MISC_REG_WC0_CTRL_PHY_ADDR);
+               *phy = phy_warpcore;
+               if (REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR) == 0x3)
+                       phy->flags |= FLAGS_4_PORT_MODE;
+               else
+                       phy->flags &= ~FLAGS_4_PORT_MODE;
+                       /* Check Dual mode */
+               serdes_net_if = (REG_RD(bp, shmem_base +
+                                       offsetof(struct shmem_region, dev_info.
+                                       port_hw_config[port].default_cfg)) &
+                                PORT_HW_CFG_NET_SERDES_IF_MASK);
+               /*
+                * Set the appropriate supported and flags indications per
+                * interface type of the chip
+                */
+               switch (serdes_net_if) {
+               case PORT_HW_CFG_NET_SERDES_IF_SGMII:
+                       phy->supported &= (SUPPORTED_10baseT_Half |
+                                          SUPPORTED_10baseT_Full |
+                                          SUPPORTED_100baseT_Half |
+                                          SUPPORTED_100baseT_Full |
+                                          SUPPORTED_1000baseT_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Autoneg |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
+                       phy->media_type = ETH_PHY_BASE_T;
+                       break;
+               case PORT_HW_CFG_NET_SERDES_IF_XFI:
+                       phy->media_type = ETH_PHY_XFP_FIBER;
+                       break;
+               case PORT_HW_CFG_NET_SERDES_IF_SFI:
+                       phy->supported &= (SUPPORTED_1000baseT_Full |
+                                          SUPPORTED_10000baseT_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
+                       phy->media_type = ETH_PHY_SFP_FIBER;
+                       break;
+               case PORT_HW_CFG_NET_SERDES_IF_KR:
+                       phy->media_type = ETH_PHY_KR;
+                       phy->supported &= (SUPPORTED_1000baseT_Full |
+                                          SUPPORTED_10000baseT_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Autoneg |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
+                       break;
+               case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
+                       phy->media_type = ETH_PHY_KR;
+                       phy->flags |= FLAGS_WC_DUAL_MODE;
+                       phy->supported &= (SUPPORTED_20000baseMLD2_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
+                       break;
+               case PORT_HW_CFG_NET_SERDES_IF_KR2:
+                       phy->media_type = ETH_PHY_KR;
+                       phy->flags |= FLAGS_WC_DUAL_MODE;
+                       phy->supported &= (SUPPORTED_20000baseKR2_Full |
+                                          SUPPORTED_FIBRE |
+                                          SUPPORTED_Pause |
+                                          SUPPORTED_Asym_Pause);
+                       break;
+               default:
+                       DP(NETIF_MSG_LINK, "Unknown WC interface type 0x%x\n",
+                                      serdes_net_if);
+                       break;
+               }
+
+               /*
+                * Enable MDC/MDIO work-around for E3 A0 since free running MDC
+                * was not set as expected. For B0, ECO will be enabled so there
+                * won't be an issue there
+                */
+               if (CHIP_REV(bp) == CHIP_REV_Ax)
+                       phy->flags |= FLAGS_MDC_MDIO_WA;
+       } else {
+               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,
@@ -8509,7 +9932,13 @@ void bnx2x_init_xmac_loopback(struct link_params *params,
         * Set WC to loopback mode since link is required to provide clock
         * to the XMAC in 20G mode
         */
-
+       if (vars->line_speed == SPEED_20000) {
+               bnx2x_set_aer_mmd(params, &params->phy[0]);
+               bnx2x_warpcore_reset_lane(bp, &params->phy[0], 0);
+               params->phy[INT_PHY].config_loopback(
+                       &params->phy[INT_PHY],
+                       params);
+       }
        bnx2x_xmac_enable(params, vars, 1);
        REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
 }
@@ -8718,6 +10147,7 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
        }
        vars->link_up = 0;
+       vars->phy_flags = 0;
        return 0;
 }
 
@@ -8743,14 +10173,14 @@ static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
                /* In E2, same phy is using for port0 of the two paths */
-               if (CHIP_IS_E2(bp)) {
-                       shmem_base = shmem_base_path[port];
-                       shmem2_base = shmem2_base_path[port];
-                       port_of_path = 0;
-               } else {
+               if (CHIP_IS_E1x(bp)) {
                        shmem_base = shmem_base_path[0];
                        shmem2_base = shmem2_base_path[0];
                        port_of_path = port;
+               } else {
+                       shmem_base = shmem_base_path[port];
+                       shmem2_base = shmem2_base_path[port];
+                       port_of_path = 0;
                }
 
                /* Extract the ext phy address for the port */
@@ -8794,10 +10224,10 @@ static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
 
        /* PART2 - Download firmware to both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
-               if (CHIP_IS_E2(bp))
-                       port_of_path = 0;
-               else
+               if (CHIP_IS_E1x(bp))
                        port_of_path = port;
+               else
+                       port_of_path = 0;
 
                DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
                           phy_blk[port]->addr);
@@ -8871,12 +10301,12 @@ static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
                u32 shmem_base, shmem2_base;
 
                /* In E2, same phy is using for port0 of the two paths */
-               if (CHIP_IS_E2(bp)) {
-                       shmem_base = shmem_base_path[port];
-                       shmem2_base = shmem2_base_path[port];
-               } else {
+               if (CHIP_IS_E1x(bp)) {
                        shmem_base = shmem_base_path[0];
                        shmem2_base = shmem2_base_path[0];
+               } else {
+                       shmem_base = shmem_base_path[port];
+                       shmem2_base = shmem2_base_path[port];
                }
                /* Extract the ext phy address for the port */
                if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
@@ -8985,14 +10415,14 @@ static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
                u32 shmem_base, shmem2_base;
 
                /* In E2, same phy is using for port0 of the two paths */
-               if (CHIP_IS_E2(bp)) {
-                       shmem_base = shmem_base_path[port];
-                       shmem2_base = shmem2_base_path[port];
-                       port_of_path = 0;
-               } else {
+               if (CHIP_IS_E1x(bp)) {
                        shmem_base = shmem_base_path[0];
                        shmem2_base = shmem2_base_path[0];
                        port_of_path = port;
+               } else {
+                       shmem_base = shmem_base_path[port];
+                       shmem2_base = shmem2_base_path[port];
+                       port_of_path = 0;
                }
 
                /* Extract the ext phy address for the port */
@@ -9027,10 +10457,10 @@ static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
        }
        /* PART2 - Download firmware to both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
-               if (CHIP_IS_E2(bp))
-                       port_of_path = 0;
-               else
+               if (CHIP_IS_E1x(bp))
                        port_of_path = port;
+               else
+                       port_of_path = 0;
                DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
                           phy_blk[port]->addr);
                if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
@@ -9091,13 +10521,17 @@ int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
                          u32 shmem2_base_path[], u32 chip_id)
 {
        int rc = 0;
-       u32 phy_ver;
-       u8 phy_index;
+       u32 phy_ver, val;
+       u8 phy_index = 0;
        u32 ext_phy_type, ext_phy_config;
        bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
        bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
        DP(NETIF_MSG_LINK, "Begin common phy init\n");
-
+       if (CHIP_IS_E3(bp)) {
+               /* Enable EPIO */
+               val = REG_RD(bp, MISC_REG_GEN_PURP_HWG);
+               REG_WR(bp, MISC_REG_GEN_PURP_HWG, val | 1);
+       }
        /* Check if common init was already done */
        phy_ver = REG_RD(bp, shmem_base_path[0] +
                         offsetof(struct shmem_region,
@@ -9183,8 +10617,14 @@ void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
        u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
        u32 val;
        u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
-
-       {
+       if (CHIP_IS_E3(bp)) {
+               if (bnx2x_get_mod_abs_int_cfg(bp, chip_id,
+                                             shmem_base,
+                                             port,
+                                             &gpio_num,
+                                             &gpio_port) != 0)
+                       return;
+       } else {
                struct bnx2x_phy phy;
                for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
                      phy_index++) {
index 12602f18fae828786c1af9646c3f8348fde12b4c..82bc021bdf07e66577044a37ab87cefdbdd07624 100644 (file)
 #define BNX2X_FLOW_CTRL_BOTH           PORT_FEATURE_FLOW_CONTROL_BOTH
 #define BNX2X_FLOW_CTRL_NONE           PORT_FEATURE_FLOW_CONTROL_NONE
 
+#define NET_SERDES_IF_XFI              1
+#define NET_SERDES_IF_SFI              2
+#define NET_SERDES_IF_KR               3
+#define NET_SERDES_IF_DXGXS    4
+
 #define SPEED_AUTO_NEG         0
-#define SPEED_12000            12000
-#define SPEED_12500            12500
-#define SPEED_13000            13000
-#define SPEED_15000            15000
-#define SPEED_16000            16000
+#define SPEED_20000            20000
 
 #define SFP_EEPROM_VENDOR_NAME_ADDR            0x14
 #define SFP_EEPROM_VENDOR_NAME_SIZE            16
 #define SFP_EEPROM_VENDOR_OUI_SIZE             3
 #define SFP_EEPROM_PART_NO_ADDR                        0x28
 #define SFP_EEPROM_PART_NO_SIZE                        16
+#define SFP_EEPROM_REVISION_ADDR               0x38
+#define SFP_EEPROM_REVISION_SIZE               4
+#define SFP_EEPROM_SERIAL_ADDR                 0x44
+#define SFP_EEPROM_SERIAL_SIZE                 16
+#define SFP_EEPROM_DATE_ADDR                   0x54 /* ASCII YYMMDD */
+#define SFP_EEPROM_DATE_SIZE                   6
 #define PWR_FLT_ERR_MSG_LEN                    250
 
 #define XGXS_EXT_PHY_TYPE(ext_phy_config) \
 #define SINGLE_MEDIA(params)           (params->num_phys == 2)
 /* Dual Media board contains two external phy with different media */
 #define DUAL_MEDIA(params)             (params->num_phys == 3)
+
+#define FW_PARAM_PHY_ADDR_MASK         0x000000FF
+#define FW_PARAM_PHY_TYPE_MASK         0x0000FF00
+#define FW_PARAM_MDIO_CTRL_MASK                0xFFFF0000
 #define FW_PARAM_MDIO_CTRL_OFFSET              16
+#define FW_PARAM_PHY_ADDR(fw_param) (fw_param & \
+                                          FW_PARAM_PHY_ADDR_MASK)
+#define FW_PARAM_PHY_TYPE(fw_param) (fw_param & \
+                                          FW_PARAM_PHY_TYPE_MASK)
+#define FW_PARAM_MDIO_CTRL(fw_param) ((fw_param & \
+                                           FW_PARAM_MDIO_CTRL_MASK) >> \
+                                           FW_PARAM_MDIO_CTRL_OFFSET)
 #define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \
        (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET)
 
@@ -121,9 +139,12 @@ struct bnx2x_phy {
 #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)
+#define FLAGS_WC_DUAL_MODE             (1<<4)
 #define FLAGS_4_PORT_MODE              (1<<5)
 #define FLAGS_REARM_LATCH_SIGNAL       (1<<6)
 #define FLAGS_SFP_NOT_APPROVED         (1<<7)
+#define FLAGS_MDC_MDIO_WA              (1<<8)
+#define FLAGS_DUMMY_READ               (1<<9)
 
        /* preemphasis values for the rx side */
        u16 rx_preemphasis[4];
@@ -142,8 +163,8 @@ struct bnx2x_phy {
 #define        ETH_PHY_XFP_FIBER   0x2
 #define        ETH_PHY_DA_TWINAX   0x3
 #define        ETH_PHY_BASE_T      0x4
-#define        ETH_PHY_KR          0xf0
-#define        ETH_PHY_CX4         0xf1
+#define        ETH_PHY_KR          0xf0
+#define        ETH_PHY_CX4         0xf1
 #define        ETH_PHY_NOT_PRESENT 0xff
 
        /* The address in which version is located*/
@@ -248,6 +269,8 @@ struct link_params {
 /* Output parameters */
 struct link_vars {
        u8 phy_flags;
+#define PHY_XGXS_FLAG                  (1<<0)
+#define PHY_SGMII_FLAG                 (1<<1)
 
        u8 mac_type;
 #define MAC_TYPE_NONE          0
@@ -414,4 +437,7 @@ void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
 void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
                            u32 chip_id, u32 shmem_base, u32 shmem2_base,
                            u8 port);
+
+int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+                              struct link_params *params);
 #endif /* BNX2X_LINK_H */
index 6237e4aba82f18828e21a433c4cee36e46cde616..0dddba9532c1c5ecaca7b7f74549dc39628cbfd8 100644 (file)
@@ -8586,7 +8586,10 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                                return;
                        }
                        break;
+               case PORT_FEATURE_LINK_SPEED_20G:
+                       bp->link_params.req_line_speed[idx] = SPEED_20000;
 
+                       break;
                default:
                        BNX2X_ERR("NVRAM config error. "
                                  "BAD link speed link_config 0x%x\n",
index 65f3b12607664083a8bb92a0ec5d791af298d8a1..23c89a863a584fcd4736e3aeb45516ad384a8c61 100644 (file)
 #define IGU_REG_WRITE_DONE_PENDING                              0x130480
 #define MCP_A_REG_MCPR_SCRATCH                                  0x3a0000
 #define MCP_REG_MCPR_CPU_PROGRAM_COUNTER                        0x8501c
+#define MCP_REG_MCPR_GP_INPUTS                                  0x800c0
+#define MCP_REG_MCPR_GP_OENABLE                                         0x800c8
+#define MCP_REG_MCPR_GP_OUTPUTS                                         0x800c4
+#define MCP_REG_MCPR_IMC_COMMAND                                0x85900
+#define MCP_REG_MCPR_IMC_DATAREG0                               0x85920
+#define MCP_REG_MCPR_IMC_SLAVE_CONTROL                          0x85904
+#define MCP_REG_MCPR_CPU_PROGRAM_COUNTER                        0x8501c
 #define MCP_REG_MCPR_NVM_ACCESS_ENABLE                          0x86424
 #define MCP_REG_MCPR_NVM_ADDR                                   0x8640c
 #define MCP_REG_MCPR_NVM_CFG4                                   0x8642c
 /* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0
    only. */
 #define MISC_REG_E1HMF_MODE                                     0xa5f8
+/* [R 1] Status of four port mode path swap input pin. */
+#define MISC_REG_FOUR_PORT_PATH_SWAP                            0xa75c
+/* [RW 2] 4 port path swap overwrite.[0] - Overwrite control; if it is 0 -
+   the path_swap output is equal to 4 port mode path swap input pin; if it
+   is 1 - the path_swap output is equal to bit[1] of this register; [1] -
+   Overwrite value. If bit[0] of this register is 1 this is the value that
+   receives the path_swap output. Reset on Hard reset. */
+#define MISC_REG_FOUR_PORT_PATH_SWAP_OVWR                       0xa738
+/* [R 1] Status of 4 port mode port swap input pin. */
+#define MISC_REG_FOUR_PORT_PORT_SWAP                            0xa754
+/* [RW 2] 4 port port swap overwrite.[0] - Overwrite control; if it is 0 -
+   the port_swap output is equal to 4 port mode port swap input pin; if it
+   is 1 - the port_swap output is equal to bit[1] of this register; [1] -
+   Overwrite value. If bit[0] of this register is 1 this is the value that
+   receives the port_swap output. Reset on Hard reset. */
+#define MISC_REG_FOUR_PORT_PORT_SWAP_OVWR                       0xa734
 /* [RW 32] Debug only: spare RW register reset by core reset */
 #define MISC_REG_GENERIC_CR_0                                   0xa460
 #define MISC_REG_GENERIC_CR_1                                   0xa464
 /* [RW 32] Debug only: spare RW register reset by por reset */
 #define MISC_REG_GENERIC_POR_1                                  0xa474
+/* [RW 32] Bit[0]: EPIO MODE SEL: Setting this bit to 1 will allow SW/FW to
+   use all of the 32 Extended GPIO pins. Without setting this bit; an EPIO
+   can not be configured as an output. Each output has its output enable in
+   the MCP register space; but this bit needs to be set to make use of that.
+   Bit[3:1] spare. Bit[4]: WCVTMON_PWRDN: Powerdown for Warpcore VTMON. When
+   set to 1 - Powerdown. Bit[5]: WCVTMON_RESETB: Reset for Warpcore VTMON.
+   When set to 0 - vTMON is in reset. Bit[6]: setting this bit will change
+   the i/o to an output and will drive the TimeSync output. Bit[31:7]:
+   spare. Global register. Reset by hard reset. */
+#define MISC_REG_GEN_PURP_HWG                                   0xa9a0
 /* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of
    these bits is written as a '1'; the corresponding SPIO bit will turn off
    it's drivers and become an input. This is the reset state of all GPIO
    in this register. address 0 - timer 1; address 1 - timer 2, ...  address 7 -
    timer 8 */
 #define MISC_REG_SW_TIMER_VAL                                   0xa5c0
+/* [R 1] Status of two port mode path swap input pin. */
+#define MISC_REG_TWO_PORT_PATH_SWAP                             0xa758
+/* [RW 2] 2 port swap overwrite.[0] - Overwrite control; if it is 0 - the
+   path_swap output is equal to 2 port mode path swap input pin; if it is 1
+   - the path_swap output is equal to bit[1] of this register; [1] -
+   Overwrite value. If bit[0] of this register is 1 this is the value that
+   receives the path_swap output. Reset on Hard reset. */
+#define MISC_REG_TWO_PORT_PATH_SWAP_OVWR                        0xa72c
 /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
    loaded; 0-prepare; -unprepare */
 #define MISC_REG_UNPREPARED                                     0xa424
 /* [RC 32] Parity register #0 read clear */
 #define NIG_REG_NIG_PRTY_STS_CLR_0                              0x183c0
 #define NIG_REG_NIG_PRTY_STS_CLR_1                              0x183d0
+#define MCPR_IMC_COMMAND_ENABLE                                         (1L<<31)
+#define MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT                    16
+#define MCPR_IMC_COMMAND_OPERATION_BITSHIFT                     28
+#define MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT              8
 /* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic
  * Ethernet header. */
 #define NIG_REG_P0_HDRS_AFTER_BASIC                             0x18038
 #define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G         0x0C00
 #define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX       0x0D00
 #define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4     0x0E00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR      0x0F00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI     0x1B00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS   0x1E00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI     0x1F00
 
 
 #define MDIO_REG_BANK_10G_PARALLEL_DETECT              0x8130
@@ -6574,6 +6623,120 @@ Theotherbitsarereservedandshouldbezero*/
 #define PHY84833_CMD_CLEAR_COMPLETE                    0x0080
 #define PHY84833_CMD_OPEN_OVERRIDE                     0xa5a5
 
+/* Warpcore clause 45 addressing */
+#define MDIO_WC_DEVAD                                  0x3
+#define MDIO_WC_REG_IEEE0BLK_MIICNTL                   0x0
+#define MDIO_WC_REG_IEEE0BLK_AUTONEGNP                 0x7
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT0      0x10
+#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1      0x11
+#define MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150  0x96
+#define MDIO_WC_REG_XGXSBLK0_XGXSCONTROL               0x8000
+#define MDIO_WC_REG_XGXSBLK0_MISCCONTROL1              0x800e
+#define MDIO_WC_REG_XGXSBLK1_DESKEW                    0x8010
+#define MDIO_WC_REG_XGXSBLK1_LANECTRL0                 0x8015
+#define MDIO_WC_REG_XGXSBLK1_LANECTRL1                 0x8016
+#define MDIO_WC_REG_XGXSBLK1_LANECTRL2                 0x8017
+#define MDIO_WC_REG_TX0_ANA_CTRL0                      0x8061
+#define MDIO_WC_REG_TX1_ANA_CTRL0                      0x8071
+#define MDIO_WC_REG_TX2_ANA_CTRL0                      0x8081
+#define MDIO_WC_REG_TX3_ANA_CTRL0                      0x8091
+#define MDIO_WC_REG_TX0_TX_DRIVER                      0x8067
+#define MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET           0x04
+#define MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_MASK                     0x00f0
+#define MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET               0x08
+#define MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_MASK                         0x0f00
+#define MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET           0x0c
+#define MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_MASK                     0x7000
+#define MDIO_WC_REG_TX1_TX_DRIVER                      0x8077
+#define MDIO_WC_REG_TX2_TX_DRIVER                      0x8087
+#define MDIO_WC_REG_TX3_TX_DRIVER                      0x8097
+#define MDIO_WC_REG_RX0_ANARXCONTROL1G                 0x80b9
+#define MDIO_WC_REG_RX2_ANARXCONTROL1G                 0x80d9
+#define MDIO_WC_REG_RX0_PCI_CTRL                       0x80ba
+#define MDIO_WC_REG_RX1_PCI_CTRL                       0x80ca
+#define MDIO_WC_REG_RX2_PCI_CTRL                       0x80da
+#define MDIO_WC_REG_RX3_PCI_CTRL                       0x80ea
+#define MDIO_WC_REG_XGXSBLK2_UNICORE_MODE_10G          0x8104
+#define MDIO_WC_REG_XGXS_STATUS3                       0x8129
+#define MDIO_WC_REG_PAR_DET_10G_STATUS                 0x8130
+#define MDIO_WC_REG_PAR_DET_10G_CTRL                   0x8131
+#define MDIO_WC_REG_XGXS_X2_CONTROL2                   0x8141
+#define MDIO_WC_REG_XGXS_RX_LN_SWAP1                   0x816B
+#define MDIO_WC_REG_XGXS_TX_LN_SWAP1                   0x8169
+#define MDIO_WC_REG_GP2_STATUS_GP_2_0                  0x81d0
+#define MDIO_WC_REG_GP2_STATUS_GP_2_1                  0x81d1
+#define MDIO_WC_REG_GP2_STATUS_GP_2_2                  0x81d2
+#define MDIO_WC_REG_GP2_STATUS_GP_2_3                  0x81d3
+#define MDIO_WC_REG_GP2_STATUS_GP_2_4                  0x81d4
+#define MDIO_WC_REG_UC_INFO_B0_DEAD_TRAP               0x81EE
+#define MDIO_WC_REG_UC_INFO_B1_VERSION                 0x81F0
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE           0x81F2
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_LANE0_OFFSET   0x0
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT       0x0
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_OPT_LR            0x1
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC       0x2
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_XLAUI     0x3
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_LONG_CH_6G            0x4
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_LANE1_OFFSET   0x4
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_LANE2_OFFSET   0x8
+#define MDIO_WC_REG_UC_INFO_B1_FIRMWARE_LANE3_OFFSET   0xc
+#define MDIO_WC_REG_UC_INFO_B1_CRC                     0x81FE
+#define MDIO_WC_REG_DSC_SMC                            0x8213
+#define MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0              0x821e
+#define MDIO_WC_REG_TX_FIR_TAP                         0x82e2
+#define MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET          0x00
+#define MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_MASK                    0x000f
+#define MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET         0x04
+#define MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_MASK           0x03f0
+#define MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET         0x0a
+#define MDIO_WC_REG_TX_FIR_TAP_POST_TAP_MASK           0x7c00
+#define MDIO_WC_REG_TX_FIR_TAP_ENABLE          0x8000
+#define MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL     0x82e3
+#define MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL       0x82e6
+#define MDIO_WC_REG_CL72_USERB0_CL72_BR_DEF_CTRL       0x82e7
+#define MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL      0x82e8
+#define MDIO_WC_REG_CL72_USERB0_CL72_MISC4_CONTROL     0x82ec
+#define MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1                0x8300
+#define MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2                0x8301
+#define MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3                0x8302
+#define MDIO_WC_REG_SERDESDIGITAL_STATUS1000X1         0x8304
+#define MDIO_WC_REG_SERDESDIGITAL_MISC1                        0x8308
+#define MDIO_WC_REG_SERDESDIGITAL_MISC2                        0x8309
+#define MDIO_WC_REG_DIGITAL3_UP1                       0x8329
+#define MDIO_WC_REG_DIGITAL4_MISC3                     0x833c
+#define MDIO_WC_REG_DIGITAL5_MISC6                     0x8345
+#define MDIO_WC_REG_DIGITAL5_MISC7                     0x8349
+#define MDIO_WC_REG_DIGITAL5_ACTUAL_SPEED              0x834e
+#define MDIO_WC_REG_CL49_USERB0_CTRL                   0x8368
+#define MDIO_WC_REG_TX66_CONTROL                       0x83b0
+#define MDIO_WC_REG_RX66_CONTROL                       0x83c0
+#define MDIO_WC_REG_RX66_SCW0                          0x83c2
+#define MDIO_WC_REG_RX66_SCW1                          0x83c3
+#define MDIO_WC_REG_RX66_SCW2                          0x83c4
+#define MDIO_WC_REG_RX66_SCW3                          0x83c5
+#define MDIO_WC_REG_RX66_SCW0_MASK                     0x83c6
+#define MDIO_WC_REG_RX66_SCW1_MASK                     0x83c7
+#define MDIO_WC_REG_RX66_SCW2_MASK                     0x83c8
+#define MDIO_WC_REG_RX66_SCW3_MASK                     0x83c9
+#define MDIO_WC_REG_FX100_CTRL1                                0x8400
+#define MDIO_WC_REG_FX100_CTRL3                                0x8402
+
+#define MDIO_WC_REG_MICROBLK_CMD                       0xffc2
+#define MDIO_WC_REG_MICROBLK_DL_STATUS                 0xffc5
+#define MDIO_WC_REG_MICROBLK_CMD3                      0xffcc
+
+#define MDIO_WC_REG_AERBLK_AER                         0xffde
+#define MDIO_WC_REG_COMBO_IEEE0_MIICTRL                        0xffe0
+#define MDIO_WC_REG_COMBO_IEEE0_MIIISTAT               0xffe1
+
+#define MDIO_WC0_XGXS_BLK2_LANE_RESET                  0x810A
+#define MDIO_WC0_XGXS_BLK2_LANE_RESET_RX_BITSHIFT      0
+#define MDIO_WC0_XGXS_BLK2_LANE_RESET_TX_BITSHIFT      4
+
+#define MDIO_WC0_XGXS_BLK6_XGXS_X2_CONTROL2            0x8141
+
+#define DIGITAL5_ACTUAL_SPEED_TX_MASK                  0x003f
+
 #define IGU_FUNC_BASE                  0x0400
 
 #define IGU_ADDR_MSIX                  0x0000