Commit 589abe3a authored by Eilon Greenstein's avatar Eilon Greenstein Committed by David S. Miller

bnx2x: Supporting BCM8726 PHY

Also adding the ability to recognize the optic module and disable it if it is
not authorized for safety reasons - since this feature might upset some users
which are willing to take the risk, it is optional and can be disabled by
setting an nvram bit (or a trivial driver patch to set this bit).
This dual port PHY requires special handling if the ports are swapped.
Signed-off-by: default avatarYaniv Rosner <yanivr@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4acac6a5
...@@ -245,7 +245,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ ...@@ -245,7 +245,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073 0x00000300 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073 0x00000300
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 0x00000400 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 0x00000400
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 0x00000500 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 0x00000500
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8276 0x00000600 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
...@@ -299,6 +299,12 @@ struct shared_feat_cfg { /* NVRAM Offset */ ...@@ -299,6 +299,12 @@ struct shared_feat_cfg { /* NVRAM Offset */
u32 config; /* 0x450 */ u32 config; /* 0x450 */
#define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001 #define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001
/* Use the values from options 47 and 48 instead of the HW default
values */
#define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_DISABLED 0x00000000
#define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED 0x00000002
#define SHARED_FEATURE_MF_MODE_DISABLED 0x00000100 #define SHARED_FEATURE_MF_MODE_DISABLED 0x00000100
}; };
...@@ -352,6 +358,11 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ ...@@ -352,6 +358,11 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEATURE_MBA_ENABLED 0x02000000 #define PORT_FEATURE_MBA_ENABLED 0x02000000
#define PORT_FEATURE_MFW_ENABLED 0x04000000 #define PORT_FEATURE_MFW_ENABLED 0x04000000
/* Check the optic vendor via i2c before allowing it to be used by
SW */
#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000
#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000
u32 wol_config; u32 wol_config;
/* Default is used when driver sets to "auto" mode */ /* Default is used when driver sets to "auto" mode */
#define PORT_FEATURE_WOL_DEFAULT_MASK 0x00000003 #define PORT_FEATURE_WOL_DEFAULT_MASK 0x00000003
......
...@@ -139,6 +139,26 @@ ...@@ -139,6 +139,26 @@
#define PHY_SGMII_FLAG 0x2 #define PHY_SGMII_FLAG 0x2
#define PHY_SERDES_FLAG 0x4 #define PHY_SERDES_FLAG 0x4
/* */
#define SFP_EEPROM_CON_TYPE_ADDR 0x2
#define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
#define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
#define SFP_EEPROM_VENDOR_NAME_SIZE 16
#define SFP_EEPROM_OPTIONS_ADDR 0x40
#define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
#define SFP_EEPROM_OPTIONS_SIZE 2
#define SFP_MODULE_TYPE_UNKNOWN 0x0
#define SFP_MODULE_TYPE_LC 0x1
#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
#define SFP_LIMITING_MODE_VALUE 0x0044
/**********************************************************/ /**********************************************************/
/* INTERFACE */ /* INTERFACE */
/**********************************************************/ /**********************************************************/
...@@ -749,12 +769,17 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, ...@@ -749,12 +769,17 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
return 0; return 0;
} }
static u32 bnx2x_get_emac_base(u32 ext_phy_type, u8 port) static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
{ {
u32 emac_base; u32 emac_base;
switch (ext_phy_type) { switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* All MDC/MDIO is directed through single EMAC */
if (REG_RD(bp, NIG_REG_PORT_SWAP))
emac_base = GRCBASE_EMAC0; emac_base = GRCBASE_EMAC0;
else
emac_base = GRCBASE_EMAC1;
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1; emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
...@@ -772,11 +797,12 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type, ...@@ -772,11 +797,12 @@ u8 bnx2x_cl45_write(struct bnx2x *bp, u8 port, u32 ext_phy_type,
{ {
u32 tmp, saved_mode; u32 tmp, saved_mode;
u8 i, rc = 0; u8 i, rc = 0;
u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port); u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
/* set clause 45 mode, slow down the MDIO clock to 2.5MHz /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
* (a value of 49==0x31) and make sure that the AUTO poll is off * (a value of 49==0x31) and make sure that the AUTO poll is off
*/ */
saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL | tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
EMAC_MDIO_MODE_CLOCK_CNT); EMAC_MDIO_MODE_CLOCK_CNT);
...@@ -841,10 +867,11 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type, ...@@ -841,10 +867,11 @@ u8 bnx2x_cl45_read(struct bnx2x *bp, u8 port, u32 ext_phy_type,
u16 i; u16 i;
u8 rc = 0; u8 rc = 0;
u32 mdio_ctrl = bnx2x_get_emac_base(ext_phy_type, port); u32 mdio_ctrl = bnx2x_get_emac_base(bp, ext_phy_type, port);
/* set clause 45 mode, slow down the MDIO clock to 2.5MHz /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
* (a value of 49==0x31) and make sure that the AUTO poll is off * (a value of 49==0x31) and make sure that the AUTO poll is off
*/ */
saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); saved_mode = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL | val = saved_mode & ((EMAC_MDIO_MODE_AUTO_POLL |
EMAC_MDIO_MODE_CLOCK_CNT)); EMAC_MDIO_MODE_CLOCK_CNT));
...@@ -1726,7 +1753,9 @@ static u8 bnx2x_link_settings_status(struct link_params *params, ...@@ -1726,7 +1753,9 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
((XGXS_EXT_PHY_TYPE(params->ext_phy_config) == ((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) || PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
(XGXS_EXT_PHY_TYPE(params->ext_phy_config) == (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705))) { PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
(XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726))) {
vars->autoneg = AUTO_NEG_ENABLED; vars->autoneg = AUTO_NEG_ENABLED;
if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
...@@ -1902,6 +1931,25 @@ static void bnx2x_ext_phy_reset(struct link_params *params, ...@@ -1902,6 +1931,25 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0xa040); MDIO_PMA_REG_CTRL, 0xa040);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
params->port);
bnx2x_cl45_write(bp, params->port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL,
1<<15);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
/* Unset Low Power Mode and SW reset */ /* Unset Low Power Mode and SW reset */
/* Restore normal power mode*/ /* Restore normal power mode*/
...@@ -2198,6 +2246,484 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port, ...@@ -2198,6 +2246,484 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
} }
static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
/* Need to wait 100ms after reset */
msleep(100);
/* Set serial boot control for external load */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0001);
/* Micro controller re-boot */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
/* Set soft reset */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
/* Clear soft reset.
Will automatically reset micro-controller re-boot */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
/* wait for 100ms for microcode load */
msleep(100);
/* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0000);
msleep(200);
}
static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
u8 ext_phy_addr, u8 tx_en)
{
u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
tx_en, port);
/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
bnx2x_cl45_read(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
&val);
if (tx_en)
val &= ~(1<<15);
else
val |= (1<<15);
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
val);
}
static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
u8 byte_cnt, u8 *o_buf) {
struct bnx2x *bp = params->bp;
u16 val, i;
u8 port = params->port;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
if (byte_cnt > 16) {
DP(NETIF_MSG_LINK, "Reading from eeprom is"
" is limited to 0xf\n");
return -EINVAL;
}
/* Set the read command byte count */
bnx2x_cl45_write(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
(byte_cnt | 0xa000));
/* Set the read command address */
bnx2x_cl45_write(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
addr);
/* Activate read command */
bnx2x_cl45_write(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
0x2c0f);
/* Wait up to 500us for command complete status */
for (i = 0; i < 100; i++) {
bnx2x_cl45_read(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
break;
udelay(5);
}
if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK,
"Got bad status 0x%x when reading from SFP+ EEPROM\n",
(val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
return -EINVAL;
}
/* Read the buffer */
for (i = 0; i < byte_cnt; i++) {
bnx2x_cl45_read(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val);
o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK);
}
for (i = 0; i < 100; i++) {
bnx2x_cl45_read(bp, port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
return 0;;
msleep(1);
}
return -EINVAL;
}
static u8 bnx2x_get_sfp_module_type(struct link_params *params,
u8 *module_type)
{
struct bnx2x *bp = params->bp;
u8 val;
*module_type = SFP_MODULE_TYPE_UNKNOWN;
/* First check for copper cable */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_CON_TYPE_ADDR,
1,
&val) != 0) {
DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
return -EINVAL;
}
switch (val) {
case SFP_EEPROM_CON_TYPE_VAL_COPPER:
{
u8 copper_module_type;
/* Check if its active cable( includes SFP+ module)
of passive cable*/
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_FC_TX_TECH_ADDR,
1,
&copper_module_type) !=
0) {
DP(NETIF_MSG_LINK,
"Failed to read copper-cable-type"
" from SFP+ EEPROM\n");
return -EINVAL;
}
if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
*module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
} else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
DP(NETIF_MSG_LINK, "Passive Copper"
" cable detected\n");
*module_type =
SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
} else {
DP(NETIF_MSG_LINK, "Unknown copper-cable-"
"type 0x%x !!!\n", copper_module_type);
return -EINVAL;
}
break;
}
case SFP_EEPROM_CON_TYPE_VAL_LC:
DP(NETIF_MSG_LINK, "Optic module detected\n");
*module_type = SFP_MODULE_TYPE_LC;
break;
default:
DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
val);
return -EINVAL;
}
return 0;
}
/* This function read the relevant field from the module ( SFP+ ),
and verify it is compliant with this board */
static u8 bnx2x_verify_sfp_module(struct link_params *params,
u8 module_type)
{
struct bnx2x *bp = params->bp;
u8 *str_p, *tmp_buf;
u16 i;
#define COMPLIANCE_STR_CNT 6
u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
"FINISAR CORP. ", "Amphenol"};
u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
/* Passive Copper cables are allowed to participate,
since the module is hardwired to the copper cable */
if (!(params->feature_config_flags &
FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
return 0;
}
if (module_type != SFP_MODULE_TYPE_LC) {
DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
return 0;
}
/* In case of non copper cable or Active copper cable,
verify that the SFP+ module is compliant with this board*/
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
buf) != 0) {
DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
" module EEPROM\n");
return -EINVAL;
}
for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
str_p = compliance_str[i];
tmp_buf = buf;
while (*str_p) {
if ((u8)(*tmp_buf) != (u8)(*str_p))
break;
str_p++;
tmp_buf++;
}
if (!(*str_p)) {
DP(NETIF_MSG_LINK, "SFP+ Module verified, "
"index=%x\n", i);
return 0;
}
}
DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
return -EINVAL;
}
static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
u8 module_type)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
u8 options[SFP_EEPROM_OPTIONS_SIZE];
u8 limiting_mode;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_OPTIONS_ADDR,
SFP_EEPROM_OPTIONS_SIZE,
options) != 0) {
DP(NETIF_MSG_LINK, "Failed to read Option field from"
" module EEPROM\n");
return -EINVAL;
}
limiting_mode = !(options[0] &
SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
if (limiting_mode &&
(module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
DP(NETIF_MSG_LINK,
"Module options = 0x%x.Setting LIMITING MODE\n",
options[0]);
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
SFP_LIMITING_MODE_VALUE);
} else { /* LRM mode ( default )*/
u16 cur_limiting_mode;
DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
options[0]);
bnx2x_cl45_read(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
&cur_limiting_mode);
/* Changing to LRM mode takes quite few seconds.
So do it only if current mode is limiting
( default is LRM )*/
if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
return 0;
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_LRM_MODE,
0);
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
0x128);
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL0,
0x4008);
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_LRM_MODE,
0xaaaa);
}
return 0;
}
static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
{
u8 val;
struct bnx2x *bp = params->bp;
u16 timeout;
/* Initialization time after hot-plug may take up to 300ms for some
phys type ( e.g. JDSU ) */
for (timeout = 0; timeout < 60; timeout++) {
if (bnx2x_read_sfp_module_eeprom(params, 1, 1, &val)
== 0) {
DP(NETIF_MSG_LINK, "SFP+ module initialization "
"took %d ms\n", timeout * 5);
return 0;
}
msleep(5);
}
return -EINVAL;
}
static u8 bnx2x_sfp_module_detection(struct link_params *params)
{
struct bnx2x *bp = params->bp;
u8 module_type;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
DP(NETIF_MSG_LINK, "Module detection is not required "
"for this phy\n");
return 0;
}
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port);
if (bnx2x_get_sfp_module_type(params,
&module_type) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
if (!(params->feature_config_flags &
FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
/* In case module detection is disabled, it trys to
link up. The issue that can happen here is LRM /
LIMITING mode which set according to the module-type*/
DP(NETIF_MSG_LINK, "Unable to read module-type."
"Probably due to Bit Stretching."
" Proceeding...\n");
} else {
return -EINVAL;
}
} else if (bnx2x_verify_sfp_module(params, module_type) !=
0) {
/* check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
/* Turn on fault module-detected led */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
return -EINVAL;
}
/* Turn off fault module-detected led */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_LOW,
params->port);
/* Check and set limiting mode / LRM mode */
if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
!= 0) {
DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
return -EINVAL;
}
/* Enable transmit for this module */
bnx2x_bcm8726_set_transmitter(bp, params->port,
ext_phy_addr, 1);
return 0;
}
void bnx2x_handle_module_detect_int(struct link_params *params)
{
struct bnx2x *bp = params->bp;
u32 gpio_val;
u8 port = params->port;
/* Set valid module led off */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
/* Get current gpio val refelecting module plugged in / out*/
gpio_val = bnx2x_get_gpio(bp, MISC_REGISTERS_GPIO_3, port);
/* Call the handling function in case module is detected */
if (gpio_val == 0) {
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
port);
if (bnx2x_wait_for_sfp_module_initialized(params)
== 0)
bnx2x_sfp_module_detection(params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
} else {
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
port);
/* Module was plugged out. */
/* Disable transmit for this module */
bnx2x_bcm8726_set_transmitter(bp, params->port,
ext_phy_addr, 0);
}
}
static void bnx2x_bcm807x_force_10G(struct link_params *params) static void bnx2x_bcm807x_force_10G(struct link_params *params)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
...@@ -2580,7 +3106,68 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -2580,7 +3106,68 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
} }
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
bnx2x_bcm8726_external_rom_boot(params);
/* Need to call module detected on initialization since
the module detection triggered by actual module
insertion might occur before driver is loaded, and when
driver is loaded, it reset all registers, including the
transmitter */
bnx2x_sfp_module_detection(params);
if (params->req_line_speed == SPEED_1000) {
DP(NETIF_MSG_LINK, "Setting 1G force\n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0x40);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_10G_CTRL2, 0xD);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_LASI_CTRL, 0x5);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_ALARM_CTRL,
0x400);
} else if ((params->req_line_speed ==
SPEED_AUTO_NEG) &&
((params->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_AN_DEVAD,
MDIO_AN_REG_ADV, 0x20);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_AN_DEVAD,
MDIO_AN_REG_CL37_CL73, 0x040c);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_AN_DEVAD,
MDIO_AN_REG_CL37_FC_LD, 0x0020);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_AN_DEVAD,
MDIO_AN_REG_CL37_AN, 0x1000);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_AN_DEVAD,
MDIO_AN_REG_CTRL, 0x1200);
/* Enable RX-ALARM control to receive
interrupt for 1G speed change */
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_LASI_CTRL, 0x4);
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_ALARM_CTRL,
0x400);
} else { /* Default 10G. Set only LASI control */
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr, MDIO_PMA_DEVAD,
MDIO_PMA_REG_LASI_CTRL, 1);
}
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
{ {
...@@ -2910,38 +3497,43 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ...@@ -2910,38 +3497,43 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
DP(NETIF_MSG_LINK, "XGXS 8706\n"); case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
DP(NETIF_MSG_LINK, "XGXS 8706/8726\n");
/* Clear RX Alarm*/
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
MDIO_PMA_REG_LASI_STATUS, &val1); &val2);
DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); /* clear LASI indication*/
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
MDIO_PMA_REG_LASI_STATUS, &val1); &val1);
DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1); bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS,
&val2);
DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x-->"
"0x%x\n", val1, val2);
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD,
MDIO_PMA_REG_RX_SD, &rx_sd); &rx_sd);
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_PCS_DEVAD, MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS,
MDIO_PCS_REG_STATUS, &pcs_status); &pcs_status);
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_AN_DEVAD, MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
MDIO_AN_REG_LINK_STATUS, &val2); &val2);
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_AN_DEVAD, MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS,
MDIO_AN_REG_LINK_STATUS, &val2); &val2);
DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x" DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x"
" pcs_status 0x%x 1Gbps link_status 0x%x\n", " pcs_status 0x%x 1Gbps link_status 0x%x\n",
rx_sd, pcs_status, val2); rx_sd, pcs_status, val2);
/* link is up if both bit 0 of pmd_rx_sd and /* link is up if both bit 0 of pmd_rx_sd and
...@@ -2951,19 +3543,31 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, ...@@ -2951,19 +3543,31 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
ext_phy_link_up = ((rx_sd & pcs_status & 0x1) || ext_phy_link_up = ((rx_sd & pcs_status & 0x1) ||
(val2 & (1<<1))); (val2 & (1<<1)));
if (ext_phy_link_up) { if (ext_phy_link_up) {
if (ext_phy_type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
/* If transmitter is disabled,
ignore false link up indication */
bnx2x_cl45_read(bp, params->port,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
&val1);
if (val1 & (1<<15)) {
DP(NETIF_MSG_LINK, "Tx is "
"disabled\n");
ext_phy_link_up = 0;
break;
}
}
if (val2 & (1<<1)) if (val2 & (1<<1))
vars->line_speed = SPEED_1000; vars->line_speed = SPEED_1000;
else else
vars->line_speed = SPEED_10000; vars->line_speed = SPEED_10000;
} }
/* clear LASI indication*/
bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_ALARM, &val2);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
{ {
...@@ -3523,7 +4127,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, ...@@ -3523,7 +4127,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
} }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
bnx2x_cl45_read(bp, params->port, ext_phy_type, bnx2x_cl45_read(bp, params->port, ext_phy_type,
ext_phy_addr, ext_phy_addr,
MDIO_PMA_DEVAD, MDIO_PMA_DEVAD,
...@@ -3636,6 +4240,14 @@ static void bnx2x_ext_phy_loopback(struct link_params *params) ...@@ -3636,6 +4240,14 @@ static void bnx2x_ext_phy_loopback(struct link_params *params)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n"); DP(NETIF_MSG_LINK, "ext_phy_loopback: 8706\n");
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL,
0x0001);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
/* SFX7101_XGXS_TEST1 */ /* SFX7101_XGXS_TEST1 */
bnx2x_cl45_write(bp, params->port, ext_phy_type, bnx2x_cl45_write(bp, params->port, ext_phy_type,
...@@ -3910,7 +4522,8 @@ static u8 bnx2x_link_initialize(struct link_params *params, ...@@ -3910,7 +4522,8 @@ static u8 bnx2x_link_initialize(struct link_params *params,
(params->loopback_mode == LOOPBACK_EXT_PHY)); (params->loopback_mode == LOOPBACK_EXT_PHY));
if (non_ext_phy || if (non_ext_phy ||
(ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705)) { (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
(ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)) {
if (params->req_line_speed == SPEED_AUTO_NEG) if (params->req_line_speed == SPEED_AUTO_NEG)
bnx2x_set_parallel_detection(params, vars->phy_flags); bnx2x_set_parallel_detection(params, vars->phy_flags);
bnx2x_init_internal_phy(params, vars); bnx2x_init_internal_phy(params, vars);
...@@ -4112,7 +4725,23 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) ...@@ -4112,7 +4725,23 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
return 0; return 0;
} }
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars) static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
{
DP(NETIF_MSG_LINK, "bnx2x_8726_reset_phy port %d\n", port);
/* Set serial boot control for external load */
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL, 0x0001);
/* Disable Transmitter */
bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
}
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u8 reset_ext_phy)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
...@@ -4150,28 +4779,37 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars) ...@@ -4150,28 +4779,37 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars)
*/ */
/* clear link led */ /* clear link led */
bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id); bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id);
if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { if (reset_ext_phy) {
if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) && switch (ext_phy_type) {
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
/* HW reset */ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
break;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
MISC_REGISTERS_GPIO_OUTPUT_LOW, DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
"low power mode\n",
port); port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW, MISC_REGISTERS_GPIO_OUTPUT_LOW,
port); port);
break;
DP(NETIF_MSG_LINK, "reset external PHY\n"); case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
} else if (ext_phy_type == {
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { u8 ext_phy_addr = ((params->ext_phy_config &
DP(NETIF_MSG_LINK, "Setting 8073 port %d into " PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
"low power mode\n", PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
/* Set soft reset */
bnx2x_8726_reset_phy(bp, params->port, ext_phy_addr);
break;
}
default:
/* HW reset */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW,
port); port);
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW, MISC_REGISTERS_GPIO_OUTPUT_LOW,
port); port);
DP(NETIF_MSG_LINK, "reset external PHY\n");
} }
} }
/* reset the SerDes/XGXS */ /* reset the SerDes/XGXS */
...@@ -4337,6 +4975,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) ...@@ -4337,6 +4975,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) && if ((ext_phy_type != PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) && (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) &&
(ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) &&
(ext_phy_link_up && !vars->phy_link_up)) (ext_phy_link_up && !vars->phy_link_up))
bnx2x_init_internal_phy(params, vars); bnx2x_init_internal_phy(params, vars);
...@@ -4469,6 +5108,45 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base) ...@@ -4469,6 +5108,45 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
} }
static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{
u8 ext_phy_addr;
u32 val;
s8 port;
/* Use port1 because of the static port-swap */
/* Enable the module detection interrupt */
val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
val |= ((1<<MISC_REGISTERS_GPIO_3)|
(1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
bnx2x_hw_reset(bp, 1);
msleep(5);
for (port = 0; port < PORT_MAX; port++) {
/* Extract the ext phy address for the port */
u32 ext_phy_config = REG_RD(bp, shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].external_phy_config));
ext_phy_addr =
((ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
DP(NETIF_MSG_LINK, "8726_common_init : ext_phy_addr = 0x%x\n",
ext_phy_addr);
bnx2x_8726_reset_phy(bp, port, ext_phy_addr);
/* Set fault module detected LED on */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
port);
}
return 0;
}
u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{ {
u8 rc = 0; u8 rc = 0;
...@@ -4488,6 +5166,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base) ...@@ -4488,6 +5166,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
rc = bnx2x_8073_common_init_phy(bp, shmem_base); rc = bnx2x_8073_common_init_phy(bp, shmem_base);
break; break;
} }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* GPIO1 affects both ports, so there's need to pull
it for single port alone */
rc = bnx2x_8726_common_init_phy(bp, shmem_base);
break;
default: default:
DP(NETIF_MSG_LINK, DP(NETIF_MSG_LINK,
"bnx2x_common_init_phy: ext_phy 0x%x not required\n", "bnx2x_common_init_phy: ext_phy 0x%x not required\n",
......
...@@ -89,6 +89,9 @@ struct link_params { ...@@ -89,6 +89,9 @@ struct link_params {
/* phy_addr populated by the CLC */ /* phy_addr populated by the CLC */
u8 phy_addr; u8 phy_addr;
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0)
/* Device pointer passed to all callback functions */ /* Device pointer passed to all callback functions */
struct bnx2x *bp; struct bnx2x *bp;
}; };
...@@ -125,8 +128,11 @@ struct link_vars { ...@@ -125,8 +128,11 @@ struct link_vars {
/* Initialize the phy */ /* Initialize the phy */
u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output); u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output);
/* Reset the link. Should be called when driver or interface goes down */ /* Reset the link. Should be called when driver or interface goes down
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars); Before calling phy firmware upgrade, the reset_ext_phy should be set
to 0 */
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u8 reset_ext_phy);
/* bnx2x_link_update should be called upon link interrupt */ /* bnx2x_link_update should be called upon link interrupt */
u8 bnx2x_link_update(struct link_params *input, struct link_vars *output); u8 bnx2x_link_update(struct link_params *input, struct link_vars *output);
...@@ -163,6 +169,10 @@ u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value); ...@@ -163,6 +169,10 @@ u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port, u32 led_idx, u32 value);
u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config, u8 bnx2x_flash_download(struct bnx2x *bp, u8 port, u32 ext_phy_config,
u8 driver_loaded, char data[], u32 size); u8 driver_loaded, char data[], u32 size);
/* bnx2x_handle_module_detect_int should be called upon module detection
interrupt */
void bnx2x_handle_module_detect_int(struct link_params *params);
/* Get the actual link status. In case it returns 0, link is up, /* Get the actual link status. In case it returns 0, link is up,
otherwise link is down*/ otherwise link is down*/
u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars); u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
......
...@@ -2112,7 +2112,7 @@ static void bnx2x__link_reset(struct bnx2x *bp) ...@@ -2112,7 +2112,7 @@ static void bnx2x__link_reset(struct bnx2x *bp)
{ {
if (!BP_NOMCP(bp)) { if (!BP_NOMCP(bp)) {
bnx2x_acquire_phy_lock(bp); bnx2x_acquire_phy_lock(bp);
bnx2x_link_reset(&bp->link_params, &bp->link_vars); bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1);
bnx2x_release_phy_lock(bp); bnx2x_release_phy_lock(bp);
} else } else
BNX2X_ERR("Bootcode is missing -not resetting link\n"); BNX2X_ERR("Bootcode is missing -not resetting link\n");
...@@ -2613,6 +2613,13 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) ...@@ -2613,6 +2613,13 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
} }
} }
if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1)) {
bnx2x_acquire_phy_lock(bp);
bnx2x_handle_module_detect_int(&bp->link_params);
bnx2x_release_phy_lock(bp);
}
if (attn & HW_INTERRUT_ASSERT_SET_0) { if (attn & HW_INTERRUT_ASSERT_SET_0) {
val = REG_RD(bp, reg_offset); val = REG_RD(bp, reg_offset);
...@@ -5905,6 +5912,37 @@ static int bnx2x_init_port(struct bnx2x *bp) ...@@ -5905,6 +5912,37 @@ static int bnx2x_init_port(struct bnx2x *bp)
/* Port DMAE comes here */ /* Port DMAE comes here */
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) { switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
{
u32 swap_val, swap_override, aeu_gpio_mask, offset;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INPUT_HI_Z, port);
/* The GPIO should be swapped if the swap register is
set and active */
swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
/* Select function upon port-swap configuration */
if (port == 0) {
offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
aeu_gpio_mask = (swap_val && swap_override) ?
AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
} else {
offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
aeu_gpio_mask = (swap_val && swap_override) ?
AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
}
val = REG_RD(bp, offset);
/* add GPIO3 to group */
val |= aeu_gpio_mask;
REG_WR(bp, offset, val);
}
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
/* add SPIO 5 to group 0 */ /* add SPIO 5 to group 0 */
val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
...@@ -7623,48 +7661,60 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, ...@@ -7623,48 +7661,60 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
SUPPORTED_Asym_Pause); SUPPORTED_Asym_Pause);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n", BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n",
ext_phy_type); ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full | bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause | SUPPORTED_Pause |
SUPPORTED_Asym_Pause); SUPPORTED_Asym_Pause);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n", BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n",
ext_phy_type); ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full | bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause | SUPPORTED_Pause |
SUPPORTED_Asym_Pause); SUPPORTED_Asym_Pause);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n", BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n",
ext_phy_type); ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full | bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE | SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause | SUPPORTED_Pause |
SUPPORTED_Asym_Pause); SUPPORTED_Asym_Pause);
break; break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n", BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n",
ext_phy_type); ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full | bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_2500baseX_Full |
SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE | SUPPORTED_FIBRE |
SUPPORTED_Pause |
SUPPORTED_Asym_Pause);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
BNX2X_DEV_INFO("ext_phy_type 0x%x (8726)\n",
ext_phy_type);
bp->port.supported |= (SUPPORTED_10000baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_Autoneg |
SUPPORTED_FIBRE |
SUPPORTED_Pause | SUPPORTED_Pause |
SUPPORTED_Asym_Pause); SUPPORTED_Asym_Pause);
break; break;
...@@ -7905,6 +7955,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -7905,6 +7955,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
{ {
int port = BP_PORT(bp); int port = BP_PORT(bp);
u32 val, val2; u32 val, val2;
u32 config;
bp->link_params.bp = bp; bp->link_params.bp = bp;
bp->link_params.port = port; bp->link_params.port = port;
...@@ -7923,6 +7974,14 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) ...@@ -7923,6 +7974,14 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->port.link_config = bp->port.link_config =
SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
bp->link_params.feature_config_flags |=
FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
else
bp->link_params.feature_config_flags &=
~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
BNX2X_DEV_INFO("serdes_config 0x%08x lane_config 0x%08x\n" BNX2X_DEV_INFO("serdes_config 0x%08x lane_config 0x%08x\n"
KERN_INFO " ext_phy_config 0x%08x speed_cap_mask 0x%08x" KERN_INFO " ext_phy_config 0x%08x speed_cap_mask 0x%08x"
" link_config 0x%08x\n", " link_config 0x%08x\n",
...@@ -8121,10 +8180,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) ...@@ -8121,10 +8180,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
switch (ext_phy_type) { switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
cmd->port = PORT_FIBRE; cmd->port = PORT_FIBRE;
break; break;
...@@ -8807,7 +8867,7 @@ static int bnx2x_set_eeprom(struct net_device *dev, ...@@ -8807,7 +8867,7 @@ static int bnx2x_set_eeprom(struct net_device *dev,
if ((bp->state == BNX2X_STATE_OPEN) || if ((bp->state == BNX2X_STATE_OPEN) ||
(bp->state == BNX2X_STATE_DISABLED)) { (bp->state == BNX2X_STATE_DISABLED)) {
rc |= bnx2x_link_reset(&bp->link_params, rc |= bnx2x_link_reset(&bp->link_params,
&bp->link_vars); &bp->link_vars, 1);
rc |= bnx2x_phy_init(&bp->link_params, rc |= bnx2x_phy_init(&bp->link_params,
&bp->link_vars); &bp->link_vars);
} }
......
...@@ -5800,9 +5800,25 @@ Theotherbitsarereservedandshouldbezero*/ ...@@ -5800,9 +5800,25 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_ROM_VER2 0xca1a #define MDIO_PMA_REG_ROM_VER2 0xca1a
#define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b #define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b
#define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d #define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d
#define MDIO_PMA_REG_MISC_CTRL0 0xca23
#define MDIO_PMA_REG_LRM_MODE 0xca3f
#define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46 #define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46
#define MDIO_PMA_REG_MISC_CTRL1 0xca85 #define MDIO_PMA_REG_MISC_CTRL1 0xca85
#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000
#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c
#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000
#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004
#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c
#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002
#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
#define MDIO_PMA_REG_8726_TX_CTRL1 0xca01
#define MDIO_PMA_REG_8726_TX_CTRL2 0xca05
#define MDIO_PMA_REG_7101_RESET 0xc000 #define MDIO_PMA_REG_7101_RESET 0xc000
#define MDIO_PMA_REG_7107_LED_CNTL 0xc007 #define MDIO_PMA_REG_7107_LED_CNTL 0xc007
#define MDIO_PMA_REG_7101_VER1 0xc026 #define MDIO_PMA_REG_7101_VER1 0xc026
...@@ -5832,6 +5848,12 @@ Theotherbitsarereservedandshouldbezero*/ ...@@ -5832,6 +5848,12 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_XS_PLL_SEQUENCER 0x8000 #define MDIO_XS_PLL_SEQUENCER 0x8000
#define MDIO_XS_SFX7101_XGXS_TEST1 0xc00a #define MDIO_XS_SFX7101_XGXS_TEST1 0xc00a
#define MDIO_XS_8706_REG_BANK_RX0 0x80bc
#define MDIO_XS_8706_REG_BANK_RX1 0x80cc
#define MDIO_XS_8706_REG_BANK_RX2 0x80dc
#define MDIO_XS_8706_REG_BANK_RX3 0x80ec
#define MDIO_XS_8706_REG_BANK_RXA 0x80fc
#define MDIO_AN_DEVAD 0x7 #define MDIO_AN_DEVAD 0x7
/*ieee*/ /*ieee*/
#define MDIO_AN_REG_CTRL 0x0000 #define MDIO_AN_REG_CTRL 0x0000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment