/* NOTE: must be first condition checked - *toverifyDCCbitisclearedinanycase!
*/ if (additional_config & NO_LFA_DUE_TO_DCC_MASK) {
DP(NETIF_MSG_LINK, "No LFA due to DCC flap after clp exit\n");
REG_WR(bp, params->lfa_base +
offsetof(struct shmem_lfa, additional_config),
additional_config & ~NO_LFA_DUE_TO_DCC_MASK); return LFA_DCC_LFA_DISABLED;
}
/* Verify that link is up */
link_status = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
port_mb[params->port].link_status)); if (!(link_status & LINK_STATUS_LINK_UP)) return LFA_LINK_DOWN;
/* if loaded after BOOT from SAN, don't flap the link in any case and *relyonlinksetbyprebootdriver
*/ if (params->feature_config_flags & FEATURE_CONFIG_BOOT_FROM_SAN) return0;
/* Verify that loopback mode is not set */ if (params->loopback_mode) return LFA_LOOPBACK_ENABLED;
/* Verify that MFW supports LFA */ if (!params->lfa_base) return LFA_MFW_IS_TOO_OLD;
/* mapping between entry priority to client number (0,1,2 -debug and *managementclients,3-COS0client,4-COSclient)(HIGHEST) *3bitsclientnum. *PRI4|PRI3|PRI2|PRI1|PRI0 *cos1-100cos0-011dbg1-010dbg0-001MCP-000
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688); /* Bitmap of 5bits length. Each bit specifies whether the entry behaves *asstrict.Bits0,1,2-debugandmanagemententries,3- *COS0entry,4-COS1entry. *COS1|COS0|DEBUG1|DEBUG0|MGMT *bit4bit3bit2bit1bit0 *MCPanddebugarestrict
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); /* defines which entries (clients) are subjected to WFQ arbitration */
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0); /* For strict priority entries defines the number of consecutive *slotsforthehighestpriority.
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* mapping between the CREDIT_WEIGHT registers and actual client *numbers
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0);
REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0);
REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0);
REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0);
REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0);
REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0); /* ETS mode disable */
REG_WR(bp, PBF_REG_ETS_ENABLED, 0); /* If ETS mode is enabled (there is no strict priority) defines a WFQ *weightforCOS0/COS1.
*/
REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710);
REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710); /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */
REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680);
REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680); /* Defines the number of consecutive slots for the strict priority */
REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0);
} /****************************************************************************** *Description: *Gettingmin_w_valwillbesetaccordingtolinespeed. *.
******************************************************************************/ static u32 bnx2x_ets_get_min_w_val_nig(conststruct link_vars *vars)
{
u32 min_w_val = 0; /* Calculate min_w_val.*/ if (vars->link_up) { if (vars->line_speed == SPEED_20000)
min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS; else
min_w_val = ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS;
} else
min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS; /* If the link isn't up (static configuration for example ) The *linkwillbeaccordingto20GBPS.
*/ return min_w_val;
} /****************************************************************************** *Description: *Gettingcreditupperboundformmin_w_val. *.
******************************************************************************/ static u32 bnx2x_ets_get_credit_upper_bound(const u32 min_w_val)
{ const u32 credit_upper_bound = (u32)MAXVAL((150 * min_w_val),
MAX_PACKET_SIZE); return credit_upper_bound;
} /****************************************************************************** *Description: *SetcreditupperboundforNIG. *.
******************************************************************************/ staticvoid bnx2x_ets_e3b0_set_credit_upper_bound_nig( conststruct link_params *params, const u32 min_w_val)
{ struct bnx2x *bp = params->bp; const u8 port = params->port; const u32 credit_upper_bound =
bnx2x_ets_get_credit_upper_bound(min_w_val);
REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 :
PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 , 0); /* In 2 port mode port0 has COS0-5 that can be used for WFQ. *In4portmodeport1hasCOS0-2thatcanbeusedforWFQ.
*/ if (!port) {
base_weight = PBF_REG_COS0_WEIGHT_P0;
max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0;
} else {
base_weight = PBF_REG_COS0_WEIGHT_P1;
max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1;
}
for (i = 0; i < max_cos; i++)
REG_WR(bp, base_weight + (0x4 * i), 0);
*total_bw = 0 ; /* Calculate total BW requested */ for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) { if (ets_params->cos[cos_idx].state == bnx2x_cos_state_bw) {
is_bw_cos_exist = 1; if (!ets_params->cos[cos_idx].params.bw_params.bw) {
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW" "was set to 0\n"); /* This is to prevent a state when ramrods *can'tbesent
*/
ets_params->cos[cos_idx].params.bw_params.bw
= 1;
}
*total_bw +=
ets_params->cos[cos_idx].params.bw_params.bw;
}
}
/* Check total BW is valid */ if ((is_bw_cos_exist == 1) && (*total_bw != 100)) { if (*total_bw == 0) {
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config total BW shouldn't be 0\n"); return -EINVAL;
}
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config total BW should be 100\n"); /* We can handle a case whre the BW isn't 100 this can happen *iftheTCarejoined.
*/
} return0;
}
if (pri >= max_num_of_cos) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid " "parameter Illegal strict priority\n"); return -EINVAL;
}
if (sp_pri_to_cos[pri] != DCBX_INVALID_COS) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid " "parameter There can't be two COS's with " "the same strict pri\n"); return -EINVAL;
}
/* Set all the strict priority first */ for (i = 0; i < max_num_of_cos; i++) { if (sp_pri_to_cos[i] != DCBX_INVALID_COS) { if (sp_pri_to_cos[i] >= DCBX_MAX_NUM_COS) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg " "invalid cos entry\n"); return -EINVAL;
}
pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
sp_pri_to_cos[i], pri_set);
pri_bitmask = 1 << sp_pri_to_cos[i]; /* COS is used remove it from bitmap.*/ if (!(pri_bitmask & cos_bit_to_set)) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg " "invalid There can't be two COS's with" " the same strict pri\n"); return -EINVAL;
}
cos_bit_to_set &= ~pri_bitmask;
pri_set++;
}
}
/* Set all the Non strict priority i= COS*/ for (i = 0; i < max_num_of_cos; i++) {
pri_bitmask = 1 << i; /* Check if COS was already used for SP */ if (pri_bitmask & cos_bit_to_set) { /* COS wasn't used for SP */
pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig(
i, pri_set);
pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf(
i, pri_set); /* COS is used remove it from bitmap.*/
cos_bit_to_set &= ~pri_bitmask;
pri_set++;
}
}
if (pri_set != max_num_of_cos) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg not all " "entries were set\n"); return -EINVAL;
}
if (port) { /* Only 6 usable clients*/
REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB,
(u32)pri_cli_nig);
/* Upper bound is set according to current link speed (min_w_val *shouldbethesameforupperboundandCOScreditval).
*/
bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig);
bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf);
for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) { if (bnx2x_cos_state_bw == ets_params->cos[cos_entry].state) {
cos_bw_bitmap |= (1 << cos_entry); /* The function also sets the BW in HW(not the mappin *yet)
*/
bnx2x_status = bnx2x_ets_e3b0_set_cos_bw(
bp, cos_entry, min_w_val_nig, min_w_val_pbf,
total_bw,
ets_params->cos[cos_entry].params.bw_params.bw,
port);
} elseif (bnx2x_cos_state_strict ==
ets_params->cos[cos_entry].state){
cos_sp_bitmap |= (1 << cos_entry);
} else {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config cos state not valid\n"); return -EINVAL;
} if (bnx2x_status) {
DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config set cos bw failed\n"); return bnx2x_status;
}
}
/* Set SP register (which COS has higher priority) */
bnx2x_status = bnx2x_ets_e3b0_sp_set_pri_cli_reg(params,
sp_pri_to_cos);
if (bnx2x_status) {
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config set_pri_cli_reg failed\n"); return bnx2x_status;
}
/* Set client mapping of BW and strict */
bnx2x_status = bnx2x_ets_e3b0_cli_map(params, ets_params,
cos_sp_bitmap,
cos_bw_bitmap);
if (bnx2x_status) {
DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config SP failed\n"); return bnx2x_status;
} return0;
} staticvoid bnx2x_ets_bw_limit_common(conststruct link_params *params)
{ /* ETS disabled configuration */ struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); /* Defines which entries (clients) are subjected to WFQ arbitration *COS00x8 *COS10x10
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18); /* Mapping between the ARB_CREDIT_WEIGHT registers and actual *clientnumbers(WEIGHT_0doesnotactuallyhavetorepresent *client0) *PRI4|PRI3|PRI2|PRI1|PRI0 *cos1-001cos0-000dbg1-100dbg0-011MCP-010
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A);
/* Defines the number of consecutive slots for the strict priority */
REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); /* Bitmap of 5bits length. Each bit specifies whether the entry behaves *asstrict.Bits0,1,2-debugandmanagemententries,3-COS0 *entry,4-COS1entry. *COS1|COS0|DEBUG21|DEBUG0|MGMT *bit4bit3bit2bit1bit0 *MCPanddebugarestrict
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7);
/* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/
REG_WR(bp, PBF_REG_COS0_UPPER_BOUND,
ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
REG_WR(bp, PBF_REG_COS1_UPPER_BOUND,
ETS_BW_LIMIT_CREDIT_UPPER_BOUND);
}
DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n"); /* Bitmap of 5bits length. Each bit specifies whether the entry behaves *asstrict.Bits0,1,2-debugandmanagemententries, *3-COS0entry,4-COS1entry. *COS1|COS0|DEBUG21|DEBUG0|MGMT *bit4bit3bit2bit1bit0 *MCPanddebugarestrict
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F); /* For strict priority entries defines the number of consecutive slots *forthehighestpriority.
*/
REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* ETS mode disable */
REG_WR(bp, PBF_REG_ETS_ENABLED, 0); /* Defines the number of consecutive slots for the strict priority */
REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100);
/* Defines the number of consecutive slots for the strict priority */
REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos);
/* Mapping between entry priority to client number (0,1,2 -debug and *managementclients,3-COS0client,4-COSclient)(HIGHEST) *3bitsclientnum. *PRI4|PRI3|PRI2|PRI1|PRI0 *dbg0-010dbg1-001cos1-100cos0-011MCP-000 *dbg0-010dbg1-001cos0-011cos1-100MCP-000
*/
val = (!strict_cos) ? 0x2318 : 0x22E0;
REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val);
/* No PFC support */ if (!(params->feature_config_flags &
FEATURE_CONFIG_PFC_ENABLED)) {
/* RX flow control - Process pause frame in receive direction
*/ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)
pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN;
/* TX flow control - Send pause packet when buffer is full */ if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)
pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN;
} else {/* PFC support */
pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN |
XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN |
XMAC_PFC_CTRL_HI_REG_RX_PFC_EN |
XMAC_PFC_CTRL_HI_REG_TX_PFC_EN |
XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON; /* Write pause and PFC registers */
REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val);
REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val);
REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val);
pfc1_val &= ~XMAC_PFC_CTRL_HI_REG_FORCE_PFC_XON;
/* This register opens the gate for the UMAC despite its name */
REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN |
UMAC_COMMAND_CONFIG_REG_PAD_EN |
UMAC_COMMAND_CONFIG_REG_SW_RESET |
UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK; switch (vars->line_speed) { case SPEED_10:
val |= (0<<2); break; case SPEED_100:
val |= (1<<2); break; case SPEED_1000:
val |= (2<<2); break; case SPEED_2500:
val |= (3<<2); break; default:
DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n",
vars->line_speed); break;
} if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE;
if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX))
val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE;
if (vars->duplex == DUPLEX_HALF)
val |= UMAC_COMMAND_CONFIG_REG_HD_ENA;
/* In 4-port mode, need to set the mode only once, so if XMAC is *alreadyoutofreset,itmeansthemodehasalreadybeenset, *anditmustnot*resettheXMACagain,sinceitcontrolsboth *portsofthepath
*/
if (((CHIP_NUM(bp) == CHIP_NUM_57840_4_10) ||
(CHIP_NUM(bp) == CHIP_NUM_57840_2_20) ||
(CHIP_NUM(bp) == CHIP_NUM_57840_OBSOLETE)) &&
is_port4mode &&
(REG_RD(bp, MISC_REG_RESET_REG_2) &
MISC_REGISTERS_RESET_REG_2_XMAC)) {
DP(NETIF_MSG_LINK, "XMAC already out of reset in 4-port mode\n"); return;
}
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
MISC_REGISTERS_RESET_REG_2_XMAC); if (is_port4mode) {
DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n");
/* Set the number of ports on the system side to up to 2 */
REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1);
/* Set the number of ports on the Warp Core to 10G */
REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
} else { /* Set the number of ports on the system side to 1 */
REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0); if (max_speed == SPEED_10000) {
DP(NETIF_MSG_LINK, "Init XMAC to 10G x 1 port per path\n"); /* Set the number of ports on the Warp Core to 10G */
REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3);
} else {
DP(NETIF_MSG_LINK, "Init XMAC to 20G x 2 ports per path\n"); /* Set the number of ports on the Warp Core to 20G */
REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1);
}
} /* Soft reset */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
MISC_REGISTERS_RESET_REG_2_XMAC_SOFT);
usleep_range(1000, 2000);
if (REG_RD(bp, MISC_REG_RESET_REG_2) &
MISC_REGISTERS_RESET_REG_2_XMAC) { /* Send an indication to change the state in the NIG back to XON *Clearingthisbitenablesthenextsetofthisbittoget *risingedge
*/
pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI);
REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
(pfc_ctrl & ~(1<<1)));
REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI,
(pfc_ctrl | (1<<1)));
DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port);
val = REG_RD(bp, xmac_base + XMAC_REG_CTRL); if (en)
val |= (XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN); else
val &= ~(XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN);
REG_WR(bp, xmac_base + XMAC_REG_CTRL, val);
}
}
/* Enable TX and RX */
val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN;
/* Set MAC in XLGMII mode for dual-mode */ if ((vars->line_speed == SPEED_20000) &&
(params->phy[INT_PHY].supported &
SUPPORTED_20000baseKR2_Full))
val |= XMAC_CTRL_REG_XLGMII_ALIGN_ENB;
/* Disable the NIG in/out to the bmac */
REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0);
REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
/* Enable the NIG in/out to the emac */
REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1);
val = 0; if ((params->feature_config_flags &
FEATURE_CONFIG_PFC_ENABLED) ||
(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX))
val = 1;
/* Set Time (based unit is 512 bit time) between automatic *re-sendingofPPpacketsamdenableautomaticre-sendof *Per-PriroityPacketaslongaspp_genisassertedand *pp_disableislow.
*/
val = 0x8000; if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
val |= (1<<16); /* enable automatic re-send */
/* mac control */
val = 0x3; /* Enable RX and TX */ if (is_lb) {
val |= 0x4; /* Local loopback */
DP(NETIF_MSG_LINK, "enable bmac loopback\n");
} /* When PFC enabled, Pass pause frames towards the NIG. */ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
val |= ((1<<6)|(1<<5));
if (nig_params) {
u8 i = 0;
pkt_priority_to_cos = nig_params->pkt_priority_to_cos;
for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++)
bnx2x_pfc_nig_rx_priority_mask(bp, i,
nig_params->rx_cos_priority_mask[i], port);
REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 :
NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0,
nig_params->llfc_high_priority_classes);
REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 :
NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0,
nig_params->llfc_low_priority_classes);
}
REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS :
NIG_REG_P0_PKT_PRIORITY_TO_COS,
pkt_priority_to_cos);
}
int bnx2x_update_pfc(struct link_params *params, struct link_vars *vars, struct bnx2x_nig_brb_pfc_port_params *pfc_params)
{ /* The PFC and pause are orthogonal to one another, meaning when *PFCisenabled,thepausearedisabled,andwhenPFCis *disabled,pausearesetaccordingtothepauseresult.
*/
u32 val; struct bnx2x *bp = params->bp;
u8 bmac_loopback = (params->loopback_mode == LOOPBACK_BMAC);
bnx2x_warpcore_enable_AN_KR2(phy, params, vars);
} else { /* Enable Auto-Detect to support 1G over CL37 as well */
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x10);
wc_lane_config = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
shared_hw_config.wc_lane_config));
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_RX0_PCI_CTRL + (lane << 4), &val); /* Force cl48 sync_status LOW to avoid getting stuck in CL73 *parallel-detectloopwhenCL73andCL37areenabled.
*/
val |= 1 << 11;
/* Restore Polarity settings in case it was run over by *previouslinkowner
*/ if (wc_lane_config &
(SHARED_HW_CFG_RX_LANE0_POL_FLIP_ENABLED << lane))
val |= 3 << 2; else
val &= ~(3 << 2);
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_RX0_PCI_CTRL + (lane << 4),
val);
bnx2x_disable_kr2(params, vars, phy);
}
/* Enable Autoneg: only on the main lane */
bnx2x_warpcore_restart_AN_KR(phy, params);
}
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_XGXSBLK1_LANECTRL1, &val16);
val16 ***************java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
,phy ,
-;
*/
bnx2x_set_aer_mmd(params, phy); /* Set speed via PMA/PMD register */
bnx2x_cl45_writebp,phy,MDIO_PMA_DEVAD
MDIO_WC_REG_IEEE0BLK_MIICNTL, x2040;
java.lang.StringIndexOutOfBoundsException: Range [5, 4) out of bounds for length 38
i,0 x00000080;
/* Enable encoded forced speed */(->nst,000000001)
bp ,MDIO_WC_DEVAD,
MDIO_WC_REG_SERDESDIGITAL_MISC2,0x30;
/* Turn TX scramble payload only the 64/66 scrambler */,0 xbf800000java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
(- ,x001c527c;
MDIO_WC_REG_TX66_CONTROL ********java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
/* Turn RX scramble payload only the 64/66 scrambler */ java.lang.StringIndexOutOfBoundsException: Range [37, 35) out of bounds for length 49
java.lang.StringIndexOutOfBoundsException: Range [28, 25) out of bounds for length 49
MDIO_WC_REG_RX66_CONTROL, {11java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 51
/* 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);
/* Should not happen. This function called upon interrupt *triggeredbyGPIO(sinceEPIOcanonlygenerateinterrupts *toMCP). *SoifthisfunctionwascalledandnoneoftheGPIOswasset, *itmeanstheshithitthefan.
*/ if ((cfg_pin < PIN_CFG_GPIO0_P0) ||
(cfg_pin > PIN_CFG_GPIO3_P1)) {
DP(NETIF_MSG_LINK, "No cfg pin %x for module detect indication\n",
cfg_pin); return -EINVAL;
}
if (vars->rx_tx_asic_rst) {
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);
switch (serdes_net_if) { case PORT_HW_CFG_NET_SERDES_IF_KR: /* Do we get link yet? */
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, 0x81d1,
&gp_status1);
lnkup = (gp_status1 >> (8+lane)) & 0x1;/* 1G */ /*10G KR*/
lnkup_kr = (gp_status1 >> (12+lane)) & 0x1;
if (lnkup_kr || lnkup) {
vars->rx_tx_asic_rst = 0;
} else { /* Reset the lane to see if link comes up.*/
bnx2x_warpcore_reset_lane(bp, phy, 1);
bnx2x_warpcore_reset_lane(bp, phy, 0);
cfg_pin = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].e3_sfp_ctrl)) &
PORT_HW_CFG_E3_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);
}
/* Indicate no mac active */
vars->mac_type = MAC_TYPE_NONE; if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG)
vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; if (vars->link_status & LINK_STATUS_SFP_TX_FAULT)
vars->phy_flags |= PHY_SFP_TX_FAULT_FLAG;
}
}
/* Force link UP in non LOOPBACK_EXT loopback mode(s) */ if (params->loopback_mode != LOOPBACK_NONE &&
params->loopback_mode != LOOPBACK_EXT)
vars->link_status |= LINK_STATUS_LINK_UP;
if (bnx2x_eee_has_cap(params))
vars->eee_status = REG_RD(bp, params->shmem2_base +
offsetof(struct shmem2_region,
eee_status[params->port]));
/* Reset the unicore */
CL22_WR_OVER_CL45(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
(mii_control |
MDIO_COMBO_IEEO_MII_CONTROL_RESET)); if (set_serdes)
bnx2x_set_serdes_access(bp, params->port);
/* Wait for the reset to self clear */ for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
udelay(5);
/* The reset erased the previous bank value */
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
&mii_control);
if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
udelay(5); return0;
}
}
netdev_err(bp->dev, "Warning: PHY was not initialized," " Port %d\n",
params->port);
DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n"); return -EINVAL;
}
staticvoid bnx2x_set_swap_lanes(struct link_params *params, struct bnx2x_phy *phy)
{ struct bnx2x *bp = params->bp; /* Each two bits represents a lane number: *Noswapis0123=>0x1bnoneedtoenabletheswap
*/
u16 rx_lane_swap, tx_lane_swap;
/* Program speed *-neededonlyifthespeedisgreaterthan1G(2.5Gor10G)
*/
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_MISC1, ®_val); /* Clearing the speed value before setting the right speed */
DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val);
/* Set extended capabilities */ if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)
val |= MDIO_OVER_1G_UP1_2_5G; if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
val |= MDIO_OVER_1G_UP1_10G;
CL22_WR_OVER_CL45(bp, phy,
MDIO_REG_BANK_OVER_1G,
MDIO_OVER_1G_UP1, val);
switch (vars->line_speed) { case SPEED_100:
mii_control |=
MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100; break; case SPEED_1000:
mii_control |=
MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000; break; case SPEED_10: /* There is nothing to set for 10M */ break; default: /* Invalid speed for SGMII */
DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n",
vars->line_speed); break;
}
/* Setting the full duplex */ if (phy->req_duplex == DUPLEX_FULL)
mii_control |=
MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
CL22_WR_OVER_CL45(bp, phy,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_MII_CONTROL,
mii_control);
} else { /* AN mode */ /* Enable and restart AN */
bnx2x_restart_autoneg(phy, params, 0);
}
}
/* Link management
*/ staticint bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy, struct link_params *params)
{ struct bnx2x *bp = params->bp;
u16 pd_10g, status2_1000x; if (phy->req_line_speed != SPEED_AUTO_NEG) return0;
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
&status2_1000x);
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_SERDES_DIGITAL,
MDIO_SERDES_DIGITAL_A_1000X_STATUS2,
&status2_1000x); if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) {
DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n",
params->port); return1;
}
if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) {
DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n",
params->port); return1;
} return0;
}
/* Resolve from gp_status in case of AN complete and not sgmii */ if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) { /* Update the advertised flow-controled of LD/LP in AN */ if (phy->req_line_speed == SPEED_AUTO_NEG)
bnx2x_update_adv_fc(phy, params, vars, gp_status); /* But set the flow-control result as the requested one */
vars->flow_ctrl = phy->req_flow_ctrl;
} elseif (phy->req_line_speed != SPEED_AUTO_NEG)
vars->flow_ctrl = params->req_fc_auto_adv; elseif ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
(!(vars->phy_flags & PHY_SGMII_FLAG))) { if (bnx2x_direct_parallel_detect_used(phy, params)) {
vars->flow_ctrl = params->req_fc_auto_adv; return;
}
bnx2x_update_adv_fc(phy, params, vars, gp_status);
}
DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl);
}
staticvoid bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, struct link_params *params)
{ struct bnx2x *bp = params->bp;
u16 rx_status, ustat_val, cl37_fsm_received;
DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); /* Step 1: Make sure signal is detected */
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_RX0,
MDIO_RX0_RX_STATUS,
&rx_status); if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) !=
(MDIO_RX0_RX_STATUS_SIGDET)) {
DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." "rx_status(0x80b0) = 0x%x\n", rx_status);
CL22_WR_OVER_CL45(bp, phy,
MDIO_REG_BANK_CL73_IEEEB0,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); return;
} /* Step 2: Check CL73 state machine */
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_USTAT1,
&ustat_val); if ((ustat_val &
(MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) !=
(MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK |
MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) {
DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. " "ustat_val(0x8371) = 0x%x\n", ustat_val); return;
} /* Step 3: Check CL37 Message Pages received to indicate LP *supportsonlyCL37
*/
CL22_RD_OVER_CL45(bp, phy,
MDIO_REG_BANK_REMOTE_PHY,
MDIO_REMOTE_PHY_MISC_RX_STATUS,
&cl37_fsm_received); if ((cl37_fsm_received &
(MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
(MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
DP(NETIF_MSG_LINK, "No CL37 FSM were received. " "misc_rx_status(0x8330) = 0x%x\n",
cl37_fsm_received); return;
} /* The combined cl37/cl73 fsm state information indicating that *weareconnectedtoadevicewhichdoesnotsupportcl73,but *doessupportcl37BAM.Inthiscasewedisablecl73and *restartcl37auto-neg
*/
/* In case of KR link down, start up the recovering procedure */ if ((!link_up) && (phy->media_type == ETH_PHY_KR) &&
(!(phy->flags & FLAGS_WC_DUAL_MODE)))
vars->rx_tx_asic_rst = MAX_KR_LINK_RETRY;
/* Bits [10:7] at lp_up2, positioned at [15:12] */
lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
if (lp_up2 == 0) return;
for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3;
bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) {
CL22_RD_OVER_CL45(bp, phy,
bank,
MDIO_TX0_TX_DRIVER, &tx_driver);
for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3;
bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) {
CL22_WR_OVER_CL45(bp, phy,
bank,
MDIO_RX0_RX_EQ_BOOST,
phy->rx_preemphasis[i]);
}
for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3;
bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) {
CL22_WR_OVER_CL45(bp, phy,
bank,
MDIO_TX0_TX_DRIVER,
phy->tx_preemphasis[i]);
}
}
rc = bnx2x_reset_unicore(params, phy, 0); /* Reset the SerDes and wait for reset bit return low */ if (rc) return rc;
bnx2x_set_aer_mmd(params, phy); /* Setting the masterLn_def again after the reset */ if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
bnx2x_set_master_ln(params, phy);
bnx2x_set_swap_lanes(params, phy);
}
return rc;
}
static u16 bnx2x_wait_reset_complete(struct bnx2x *bp, struct bnx2x_phy *phy, struct link_params *params)
{
u16 cnt, ctrl; /* Wait for soft reset to get cleared up to 1 sec */ for (cnt = 0; cnt < 1000; cnt++) { if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE)
bnx2x_cl22_read(bp, phy,
MDIO_PMA_REG_CTRL, &ctrl); else
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, &ctrl); if (!(ctrl & (1<<15))) break;
usleep_range(1000, 2000);
}
if (cnt == 1000)
netdev_err(bp->dev, "Warning: PHY was not initialized," " Port %d\n",
params->port);
DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt); return cnt;
}
/* Setting the status to report on link up for either XGXS or SerDes */ if (CHIP_IS_E3(bp)) {
mask = NIG_MASK_XGXS0_LINK_STATUS; if (!(SINGLE_MEDIA_DIRECT(params)))
mask |= NIG_MASK_MI_INT;
} elseif (params->switch_cfg == SWITCH_CFG_10G) {
mask = (NIG_MASK_XGXS0_LINK10G |
NIG_MASK_XGXS0_LINK_STATUS);
DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n"); if (!(SINGLE_MEDIA_DIRECT(params)) &&
params->phy[INT_PHY].type !=
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) {
mask |= NIG_MASK_MI_INT;
DP(NETIF_MSG_LINK, "enabled external phy int\n");
}
/* Disable the MI INT ( external phy int ) by writing 1 to the *statusregister.Linkdownindicationishigh-active-signal, *sointhiscaseweneedtowritethestatustocleartheXOR
*/ /* Read Latched signals */
latch_status = REG_RD(bp,
NIG_REG_LATCH_STATUS_0 + port*8);
DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status); /* Handle only those with latched-signal=up.*/ if (exp_mi_int)
bnx2x_bits_en(bp,
NIG_REG_STATUS_INTERRUPT_PORT0
+ port*4,
NIG_STATUS_EMAC0_MI_INT); else
bnx2x_bits_dis(bp,
NIG_REG_STATUS_INTERRUPT_PORT0
+ port*4,
NIG_STATUS_EMAC0_MI_INT);
if (latch_status & 1) {
/* For all latched-signal=up : Re-Arm Latch signals */
REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8,
(latch_status & 0xfffe) | (latch_status & 1));
} /* For all latched-signal=up,Write original_signal to status */
}
staticvoid bnx2x_link_int_ack(struct link_params *params, 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 *changeatatime
*/
bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
(NIG_STATUS_XGXS0_LINK10G |
NIG_STATUS_XGXS0_LINK_STATUS |
NIG_STATUS_SERDES0_LINK_STATUS)); if (vars->phy_link_up) { if (USES_WARPCORE(bp))
mask = NIG_STATUS_XGXS0_LINK_STATUS; else { if (is_10g_plus)
mask = NIG_STATUS_XGXS0_LINK10G; elseif (params->switch_cfg == SWITCH_CFG_10G) { /* Disable the link interrupt by writing 1 to *therelevantlaneinthestatusregister
*/
u32 ser_lane =
((params->lane_config &
PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
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);
}
}
bnx2x_cl45_write(bp, phy */ 5java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 31
(&0))java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
200;
java.lang.StringIndexOutOfBoundsException: Range [34, 24) out of bounds for length 24
x2x_set_aer_mmd,phy;
intget_caps) caps); /* And md_devad */*(tructdevice dev state
int(*tream_read_tstamp)(struct device*, *str_info)java.lang.StringIndexOutOfBoundsException: Index 81 out of bounds for length 81
md_devad);
}
} {
u16 mii_ctrl;
N, XGXS 1G enable)java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
bp ,5
(MDIO_REG_BANK_COMBO_IEEE0 +
(MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
&mii_ctrl);
bnx2x_cl45_write(bp, phy, 5,
(MDIO_REG_BANK_COMBO_IEEE0 +
(MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)),
mii_ctrl |
MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK);
}
}
int bnx2x_set_led(struct link_params *params, struct link_vars *vars, u8 mode, u32 speed)
{
u8 port = params->port;
u16 hw_led_mode = params->hw_led_mode; int rc = 0;
u8 phy_idx;
u32 tmp;
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode);
DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
speed, hw_led_mode); /* In case */ for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) { if (params->phy[phy_idx].set_link_led) {
params->phy[phy_idx].set_link_led(
¶ms->phy[phy_idx], params, mode);
}
}
switch (mode) { case LED_MODE_FRONT_PANEL_OFF: case LED_MODE_OFF:
REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0);
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
SHARED_HW_CFG_LED_MAC1);
case LED_MODE_OPER: /* For all other phys, OPER mode is same as ON, so in case *linkisdown,donothing
*/ if (!vars->link_up) break;
fallthrough; case LED_MODE_ON: if (((params->phy[EXT_PHY1].type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
(params->phy[EXT_PHY1].type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
CHIP_IS_E2(bp) && params->num_phys == 2) { /* This is a work-around for E2+8727 Configurations */ if (mode == LED_MODE_ON ||
speed == SPEED_10000){
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
EMAC_WR(bp, EMAC_REG_EMAC_LED,
(tmp | EMAC_LED_OVERRIDE)); /* Return here without enabling traffic *LEDblinkandsettingrateinONmode. *Inopermode,enablingLEDblink *andsettingrateisneeded.
*/ if (mode == LED_MODE_ON) return rc;
}
} elseif (SINGLE_MEDIA_DIRECT(params)) { /* This is a work-around for HW issue found when link *isupinCL73
*/ if ((!CHIP_IS_E3(bp)) ||
(CHIP_IS_E3(bp) &&
mode == LED_MODE_ON))
REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
/* This function comes to reflect the actual link state read DIRECTLY from the *HW
*/ int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
u8 is_serdes)
{ struct bnx2x *bp = params->bp;
u16 gp_status = 0, phy_index = 0;
u8 ext_phy_link_up = 0, serdes_phy_type; struct link_vars temp_vars; struct bnx2x_phy *int_phy = ¶ms->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) return0;
if (is_serdes != serdes_phy_type) continue; if (params->phy[phy_index].read_status) {
ext_phy_link_up |=
params->phy[phy_index].read_status(
¶ms->phy[phy_index],
params, &temp_vars);
}
} break;
} if (ext_phy_link_up) return0; return -ESRCH;
}
staticint bnx2x_link_initialize(struct link_params *params, struct link_vars *vars)
{
u8 phy_index, non_ext_phy; struct bnx2x *bp = params->bp; /* In case of external phy existence, the line speed would be the *linespeedlinkedupbytheexternalphy.Incaseitisdirect *only,thentheline_speedduringinitializationwillbe *equaltothereq_line_speed
*/
vars->line_speed = params->phy[INT_PHY].req_line_speed;
/* Initialize the internal phy in case this is a direct board *(noexternalphys),orthisboardhasexternalphywhichrequires *tofirst.
*/ if (!USES_WARPCORE(bp))
bnx2x_prepare_xgxs(¶ms->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));
/* Re-read this value in case it was changed inside config_init due to *limitationsofopticmodule
*/
vars->line_speed = params->phy[INT_PHY].req_line_speed;
/* Init external phy*/ if (non_ext_phy) { if (params->phy[INT_PHY].supported &
SUPPORTED_FIBRE)
vars->link_status |= LINK_STATUS_SERDES_LINK;
} else { for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) { /* No need to initialize second phy in case of first *phyonlyselection.Incaseofsecondphy,wedo *needtoinitializethefirstphy,sincetheyare *connected.
*/ if (params->phy[phy_index].supported &
SUPPORTED_FIBRE)
vars->link_status |= LINK_STATUS_SERDES_LINK;
if (phy_index == EXT_PHY2 &&
(bnx2x_phy_selection(params) ==
PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
DP(NETIF_MSG_LINK, "Not initializing second phy\n"); continue;
}
params->phy[phy_index].config_init(
¶ms->phy[phy_index],
params, vars);
}
} /* Reset the interrupt indication after phy was initialized */
bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
params->port*4,
(NIG_STATUS_XGXS0_LINK10G |
NIG_STATUS_XGXS0_LINK_STATUS |
NIG_STATUS_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT)); return0;
}
DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
vars->phy_flags &= ~PHY_PHYSICAL_LINK_FLAG; /* Indicate no mac active */
vars->mac_type = MAC_TYPE_NONE;
/* Step 1: *Checkexternallinkchangeonlyforexternalphys,andapply *priorityselectionbetweenthemincasethelinkonbothphys *isup.Notethatinsteadofthecommonvars,atemporary *varsargumentisusedsinceeachphymayhavedifferentlink/ *speed/duplexresult
*/ for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) { struct bnx2x_phy *phy = ¶ms->phy[phy_index]; if (!phy->read_status) continue; /* Read link status and params of this ext phy */
cur_link_up = phy->read_status(phy, params,
&phy_vars[phy_index]); if (cur_link_up) {
DP(NETIF_MSG_LINK, "phy in index %d link is up\n",
phy_index);
} else {
DP(NETIF_MSG_LINK, "phy in index %d link is down\n",
phy_index); continue;
}
if (!ext_phy_link_up) {
ext_phy_link_up = 1;
active_external_phy = phy_index;
} else { switch (bnx2x_phy_selection(params)) { case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: /* In this option, the first PHY makes sure to pass the *trafficthroughitselfonly. *It'snotclearhowtoresetthelinkonthesecond *phy.
*/
active_external_phy = EXT_PHY1; break; case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: /* In this option, the first PHY makes sure to pass the *trafficthroughthesecondPHY.
*/
active_external_phy = EXT_PHY2; break; default: /* Link indication on both PHYs with the following cases *isinvalid: *-FIRST_PHYmeansthatsecondphywasn'tinitialized, *henceitslinkisexpectedtobedown *-SECOND_PHYmeansthatfirstphyshouldnotbeable *tolinkupbyitself(usingconfiguration) *-DEFAULTshouldbeoverriddenduringinitialization
*/
DP(NETIF_MSG_LINK, "Invalid link indication" "mpc=0x%x. DISABLING LINK !!!\n",
params->multi_phy_config);
ext_phy_link_up = 0; break;
}
}
}
prev_line_speed = vars->line_speed; /* Step 2: *Readthestatusoftheinternalphy.Incaseof *DIRECT_SINGLE_MEDIAboard,thislinkistheexternallink, *otherwisethisisthelinkbetweenthe577xxandthefirst *externalphy
*/ if (params->phy[INT_PHY].read_status)
params->phy[INT_PHY].read_status(
¶ms->phy[INT_PHY],
params, vars); /* The INT_PHY flow control reside in the vars. This include the *casewherethespeedorflowcontrolarenotsettoAUTO. *Otherwise,theactiveexternalphyflowcontrolresultisset *tothevars.Theext_phy_line_speedisneededtocheckifthe *speedisdifferentbetweentheinternalphyandexternalphy. *Thiscasemayberesultofintermediatelinkspeedchange.
*/ if (active_external_phy > INT_PHY) {
vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl; /* Link speed is taken from the XGXS. AN and FC result from *theexternalphy.
*/
vars->link_status |= phy_vars[active_external_phy].link_status;
/* if active_external_phy is first PHY and link is up - disable *disableTXonsecondexternalPHY
*/ if (active_external_phy == EXT_PHY1) { if (params->phy[EXT_PHY2].phy_specific_func) {
DP(NETIF_MSG_LINK, "Disabling TX on EXT_PHY2\n");
params->phy[EXT_PHY2].phy_specific_func(
¶ms->phy[EXT_PHY2],
params, DISABLE_TX);
}
}
for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) { if (params->phy[phy_index].flags &
FLAGS_REARM_LATCH_SIGNAL) {
bnx2x_rearm_latch_signal(bp, port,
phy_index ==
active_external_phy); break;
}
}
DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x," " ext_phy_line_speed = %d\n", vars->flow_ctrl,
vars->link_status, ext_phy_line_speed); /* Upon link speed change set the NIG into drain mode. Comes to *dealswithpossibleFIFOglitchduetoclkchangewhenspeed *isdecreasedwithoutlinkdownindicator
*/
if (vars->phy_link_up) { if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up &&
(ext_phy_line_speed != vars->line_speed)) {
DP(NETIF_MSG_LINK, "Internal link speed %d is" " different than the external" " link speed %d\n", vars->line_speed,
ext_phy_line_speed);
vars->phy_link_up = 0;
} elseif (prev_line_speed != vars->line_speed) {
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
usleep_range(1000, 2000);
}
}
/* Anything 10 and over uses the bmac */
link_10g_plus = (vars->line_speed >= SPEED_10000);
bnx2x_link_int_ack(params, vars, link_10g_plus);
/* In case external phy link is up, and internal link is down *(notinitializedyetprobablyafterlinkinitialization,it *needstobeinitialized. *Notethatafterlinkdown-upasresultofcableplug,thexgxs *linkwouldprobablybecomeupagainwithouttheneed *initializeit
*/ if (!(SINGLE_MEDIA_DIRECT(params))) {
DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d," " init_preceding = %d\n", ext_phy_link_up,
vars->phy_link_up,
params->phy[EXT_PHY1].flags &
FLAGS_INIT_XGXS_FIRST); if (!(params->phy[EXT_PHY1].flags &
FLAGS_INIT_XGXS_FIRST)
&& ext_phy_link_up && !vars->phy_link_up) {
vars->line_speed = ext_phy_line_speed; if (vars->line_speed < SPEED_1000)
vars->phy_flags |= PHY_SGMII_FLAG; else
vars->phy_flags &= ~PHY_SGMII_FLAG;
if (params->phy[INT_PHY].config_init)
params->phy[INT_PHY].config_init(
¶ms->phy[INT_PHY], params,
vars);
}
} /* Link is up only if both local phy and external phy (in case of *non-directboard)areupandnofaultdetectedonactivePHY.
*/
vars->link_up = (vars->phy_link_up &&
(ext_phy_link_up ||
SINGLE_MEDIA_DIRECT(params)) &&
(phy_vars[active_external_phy].fault_detected == 0));
/* Update the PFC configuration in case it was changed */ if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED)
vars->link_status |= LINK_STATUS_PFC_ENABLED; else
vars->link_status &= ~LINK_STATUS_PFC_ENABLED;
if ((prev_link_status ^ vars->link_status) & LINK_STATUS_LINK_UP)
bnx2x_chng_link_count(params, false);
/* Update MCP link status was changed */ if (params->feature_config_flags & FEATURE_CONFIG_BC_SUPPORTS_AFEX)
bnx2x_fw_command(bp, DRV_MSG_CODE_LINK_STATUS_CHANGED, 0);
DP(NETIF_MSG_LINK, "bnx2x_8073_8727_external_rom_boot port %x:" "Download complete. fw version = 0x%x\n",
port, fw_ver1);
return rc;
}
/******************************************************************/ /* BCM8073 PHY SECTION */ /******************************************************************/ staticint bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
{ /* This is only required for 8073A1, version 102 only */
u16 val;
DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
/* Swap polarity if required - Must be done only in non-1G mode */ if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) { /* Configure the 8073 to swap _P and _N of the KR lines */
DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n"); /* 10G Rx/Tx and 1G Tx signal polarity swap */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
(val | (3<<9)));
}
bnx2x_cl45_read(bp, phy,
MDIO_AN_DEVAD,
MDIO_AN_REG_8073_BAM, &val);
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD,
MDIO_AN_REG_8073_BAM, val | 1);
DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
} if (params->loopback_mode == LOOPBACK_EXT) {
bnx2x_807x_force_10G(bp, phy);
DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n"); return;
} else {
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002);
} if (phy->req_line_speed != SPEED_AUTO_NEG) { if (phy->req_line_speed == SPEED_10000) {
val = (1<<7);
} elseif (phy->req_line_speed == SPEED_2500) {
val = (1<<5); /* Note that 2.5G works only when used with 1G *advertisement
*/
} else
val = (1<<5);
} else {
val = 0; if (phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
val |= (1<<7);
/* Note that 2.5G works only when used with 1G advertisement */ if (phy->speed_cap_mask &
(PORT_HW_CFG_SPEED_CAPABILITY_D0_1G |
PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
val |= (1<<5);
DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val);
}
/* Add support for CL37 (passive mode) III */
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000);
/* The SNR will improve about 2db by changing BW and FEE main *tap.Restcommandsareexecutedafterlinkisup *ChangeFFEmaincursorto5inEDCregister
*/ if (bnx2x_8073_is_snr_needed(bp, phy))
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN, 0xFB0C);
/* Enable FEC (Forware Error Correction) Request in the AN */
bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1);
tmp1 |= (1<<15);
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1);
/* Check the link status on 1.1.2 */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2);
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1);
DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x," "an_link_status=0x%x\n", val2, val1, an1000_status);
link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1))); if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) { /* The SNR will improve about 2dbby changing the BW and FEE main *tap.The1stwritetochangeFFEmaintapissetbefore *restartAN.ChangePLLBandwidthinEDCregister
*/
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH, 0x26BC);
/* Change CDR Bandwidth in EDC register */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH, 0x0333);
}
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
&link_status);
/* Bits 0..2 --> speed detected, bits 13..15--> link is down */ if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) {
link_up = 1;
vars->line_speed = SPEED_10000;
DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n",
params->port);
} elseif ((link_status & (1<<1)) && (!(link_status & (1<<14)))) {
link_up = 1;
vars->line_speed = SPEED_2500;
DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n",
params->port);
} elseif ((link_status & (1<<0)) && (!(link_status & (1<<13)))) {
link_up = 1;
vars->line_speed = SPEED_1000;
DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n",
params->port);
} else {
link_up = 0;
DP(NETIF_MSG_LINK, "port %x: External link is down\n",
params->port);
}
if (link_up) { /* Swap polarity if required */ if (params->lane_config &
PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) { /* Configure the 8073 to swap P and N of the KR lines */
bnx2x_cl45_read(bp, phy,
MDIO_XS_DEVAD,
MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1); /* Set bit 3 to invert Rx in 1G mode and clear this bit *whenit`sin10Gmode.
*/ if (vars->line_speed == SPEED_1000) {
DP(NETIF_MSG_LINK, "Swapping 1G polarity for" "the 8073\n");
val1 |= (1<<3);
} else
val1 &= ~(1<<3);
/* Wait up to 500us for command complete status */ for (i = 0; i < 100; i++) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break;
udelay(5);
}
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK, "Got bad status 0x%x when reading from SFP+ EEPROM\n",
(val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); return -EINVAL;
}
/* Read the buffer */ for (i = 0; i < byte_cnt; i++) {
bnx2x_cl45_read(bp, phy,
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, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return0;
usleep_range(1000, 2000);
} return -EINVAL;
}
if (byte_cnt > SFP_EEPROM_PAGE_SIZE) {
DP(NETIF_MSG_LINK, "Reading from eeprom is limited to 0xf\n"); return -EINVAL;
}
/* Set 2-wire transfer rate of SFP+ module EEPROM *to100KhzsincesomeDACs(directattachedcables)do *notworkat400Khz.
*/
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
((dev_addr << 8) | 1));
/* Need to read from 1.8000 to clear it */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
&val);
/* Set the read command byte count */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
((byte_cnt < 2) ? 2 : byte_cnt));
/* Set the read command address */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr); /* Set the destination address */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, 0x8004,
MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
/* Activate read command */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, 0x8002); /* Wait appropriate time for two-wire command to finish before *pollingthestatusregister
*/
usleep_range(1000, 2000);
/* Wait up to 500us for command complete status */ for (i = 0; i < 100; i++) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) break;
udelay(5);
}
if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK, "Got bad status 0x%x when reading from SFP+ EEPROM\n",
(val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); return -EFAULT;
}
/* Read the buffer */ for (i = 0; i < byte_cnt; i++) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
}
for (i = 0; i < 100; i++) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) return0;
usleep_range(1000, 2000);
}
if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n"); if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
*edc_mode = EDC_MODE_ACTIVE_DAC; else
check_limiting_mode = 1;
} else {
*edc_mode = EDC_MODE_PASSIVE_DAC; /* Even in case PASSIVE_DAC indication is not set, *treatitasapassiveDACcable,sincesomecables *don'thavethisindication.
*/ if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
DP(NETIF_MSG_LINK, "Passive Copper cable detected\n");
} else {
DP(NETIF_MSG_LINK, "Unknown copper-cable-type\n");
}
} break;
} case SFP_EEPROM_CON_TYPE_VAL_UNKNOWN: case SFP_EEPROM_CON_TYPE_VAL_LC: case SFP_EEPROM_CON_TYPE_VAL_RJ45:
check_limiting_mode = 1; if (((val[SFP_EEPROM_10G_COMP_CODE_ADDR] &
(SFP_EEPROM_10G_COMP_CODE_SR_MASK |
SFP_EEPROM_10G_COMP_CODE_LR_MASK |
SFP_EEPROM_10G_COMP_CODE_LRM_MASK)) == 0) &&
(val[SFP_EEPROM_1G_COMP_CODE_ADDR] != 0)) {
DP(NETIF_MSG_LINK, "1G SFP module detected\n");
phy->media_type = ETH_PHY_SFP_1G_FIBER; if (phy->req_line_speed != SPEED_1000) {
u8 gport = params->port;
phy->req_line_speed = SPEED_1000; if (!CHIP_IS_E1x(bp)) {
gport = BP_PATH(bp) +
(params->port << 1);
}
netdev_err(bp->dev, "Warning: Link speed was forced to 1000Mbps. Current SFP module in port %d is not compliant with 10G Ethernet\n",
gport);
} if (val[SFP_EEPROM_1G_COMP_CODE_ADDR] &
SFP_EEPROM_1G_COMP_CODE_BASE_T) {
bnx2x_sfp_set_transmitter(params, phy, 0);
msleep(40);
bnx2x_sfp_set_transmitter(params, phy, 1);
}
} else { int idx, cfg_idx = 0;
DP(NETIF_MSG_LINK, "10G Optic module detected\n"); for (idx = INT_PHY; idx < MAX_PHYS; idx++) { if (params->phy[idx].type == phy->type) {
cfg_idx = LINK_CONFIG_IDX(idx); break;
}
}
phy->media_type = ETH_PHY_SFPP_10G_FIBER;
phy->req_line_speed = params->req_line_speed[cfg_idx];
} break; default:
DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
val[SFP_EEPROM_CON_TYPE_ADDR]); return -EINVAL;
}
sync_offset = params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[params->port].media_type);
media_types = REG_RD(bp, sync_offset); /* Update media type for non-PMF sync */ for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { if (&(params->phy[phy_idx]) == phy) {
media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
(PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
media_types |= ((phy->media_type &
PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
(PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx)); break;
}
}
REG_WR(bp, sync_offset, media_types); if (check_limiting_mode) {
u8 options[SFP_EEPROM_OPTIONS_SIZE]; if (bnx2x_read_sfp_module_eeprom(phy,
params,
I2C_DEV_ADDR_A0,
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;
} if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
*edc_mode = EDC_MODE_LINEAR; else
*edc_mode = EDC_MODE_LIMITING;
}
DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode); return0;
} /* This function read the relevant field from the module (SFP+), and verify it *iscompliantwiththisboard
*/ staticint bnx2x_verify_sfp_module(struct bnx2x_phy *phy, struct link_params *params)
{ struct bnx2x *bp = params->bp;
u32 val, cmd;
u32 fw_resp, fw_cmd_param; char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
phy->flags &= ~FLAGS_SFP_NOT_APPROVED;
val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].config)); if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
DP(NETIF_MSG_LINK, "NOT enforcing module verification\n"); return0;
}
if (params->feature_config_flags &
FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) { /* Use specific phy request */
cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL;
} elseif (params->feature_config_flags &
FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) { /* Use first phy request only in case of non-dual media*/ if (DUAL_MEDIA(params)) {
DP(NETIF_MSG_LINK, "FW does not support OPT MDL verification\n"); return -EINVAL;
}
cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL;
} else { /* No support in OPT MDL detection */
DP(NETIF_MSG_LINK, "FW does not support OPT MDL verification\n"); return -EINVAL;
}
{
u8 val; int rc; struct bnx2x *bp = params->bp;
u16 timeout; /* Initialization time after hot-plug may take up to 300ms for *somephystype(e.g.JDSU)
*/
staticvoid bnx2x_8727_power_module(struct bnx2x *bp, struct bnx2x_phy *phy,
u8 is_power_up) { /* Make sure GPIOs are not using for LED mode */
u16 val; /* In the GPIO register, bit 4 is use to determine if the GPIOs are *operatingasINPUTorasOUTPUT.Bit1isforinput,and0for *output *Bits0-1determinetheGPIOsvalueforOUTPUTincasebit4valis0 *Bits8-9determinetheGPIOsvalueforINPUTincasebit4valis1 *wherethe1stbitistheover-current(onlyinput),and2ndbitis *forpower(onlyoutput) * *IncaseofNOCfeatureisdisabledandpowerisup,setGPIOcontrol *asinputtoenablelisteningofover-currentindication
*/ if (phy->flags & FLAGS_NOC) return; if (is_power_up)
val = (1<<4); else /* Set GPIO control to OUTPUT, and set the power bit *toaccordingtotheis_power_up
*/
val = (1<<1);
/* Changing to LRM mode takes quite few seconds. So do it only *ifcurrentmodeislimiting(defaultisLRM)
*/ if (cur_limiting_mode != EDC_MODE_LIMITING) return0;
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
&rom_ver2_val); /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
(rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
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: case EDC_MODE_ACTIVE_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);
/* Restart microcode to re-read the new mode */
bnx2x_warpcore_reset_lane(bp, phy, 1);
bnx2x_warpcore_reset_lane(bp, phy, 0);
}
staticvoid bnx2x_set_limiting_mode(struct link_params *params, struct bnx2x_phy *phy,
u16 edc_mode)
{ switch (phy->type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: 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;
}
}
u32 val = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
port_feature_config[params->port].config)); /* Enabled transmitter by default */
bnx2x_sfp_set_transmitter(params, phy, 1);
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port); /* Power up module */
bnx2x_power_sfp_module(params, phy, 1); if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); return -EINVAL;
} elseif (bnx2x_verify_sfp_module(phy, params) != 0) { /* Check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
rc = -EINVAL; /* Turn on fault module-detected led */
bnx2x_set_sfp_module_fault_led(params,
MISC_REGISTERS_GPIO_HIGH);
/* Check if need to power down the SFP+ module */ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
bnx2x_power_sfp_module(params, phy, 0); return rc;
}
} else { /* Turn off fault module-detected led */
bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
}
/* Check and set limiting mode / LRM mode on 8726. On 8727 it *isdoneautomatically
*/
bnx2x_set_limiting_mode(params, phy, edc_mode);
/* Disable transmit for this module if the module is not approved, and *laserneedstobedisabled.
*/ if ((rc) &&
((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER))
bnx2x_sfp_set_transmitter(params, phy, 0);
return rc;
}
void bnx2x_handle_module_detect_int(struct link_params *params)
{ struct bnx2x *bp = params->bp; struct bnx2x_phy *phy;
u32 gpio_val;
u8 gpio_num, gpio_port; if (CHIP_IS_E3(bp)) {
phy = ¶ms->phy[INT_PHY]; /* Always enable TX laser,will be disabled in case of fault */
bnx2x_sfp_set_transmitter(params, phy, 1);
} else {
phy = ¶ms->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, gpio_num, gpio_port);
/* Call the handling function in case module is detected */ if (gpio_val == 0) {
bnx2x_set_mdio_emac_per_phy(bp, params);
bnx2x_set_aer_mmd(params, phy);
bnx2x_power_sfp_module(params, phy, 1);
bnx2x_set_gpio_int(bp, gpio_num,
MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
gpio_port); if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) {
bnx2x_sfp_module_detection(phy, params); if (CHIP_IS_E3(bp)) {
u16 rx_tx_in_reset; /* In case WC is out of reset, reconfigure the *linkspeedwhiletakingintoaccount1G *modulelimitation.
*/
bnx2x_cl45_read(bp, phy,
MDIO_WC_DEVAD,
MDIO_WC_REG_DIGITAL5_MISC6,
&rx_tx_in_reset); if ((!rx_tx_in_reset) &&
(params->link_flags &
PHY_INITIALIZED)) {
bnx2x_warpcore_reset_lane(bp, phy, 1);
bnx2x_warpcore_config_sfi(phy, params);
bnx2x_warpcore_reset_lane(bp, phy, 0);
}
}
} else {
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
}
} else {
bnx2x_set_gpio_int(bp, gpio_num,
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
gpio_port); /* Module was plugged out. *Disabletransmitforthismodule
*/
phy->media_type = ETH_PHY_NOT_PRESENT;
}
}
/* Wait until fw is loaded */ for (cnt = 0; cnt < 100; cnt++) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val); if (val) break;
usleep_range(10000, 20000);
}
DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt); if ((params->feature_config_flags &
FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
u8 i;
u16 reg; for (i = 0; i < 4; i++) {
reg = MDIO_XS_8706_REG_BANK_RX0 +
i*(MDIO_XS_8706_REG_BANK_RX1 -
MDIO_XS_8706_REG_BANK_RX0);
bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val); /* Clear first 3 bits of the control */
val &= ~0x7; /* Set control bits according to configuration */
val |= (phy->rx_preemphasis[i] & 0x7);
DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706" " reg 0x%x <-- val 0x%x\n", reg, val);
bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val);
}
} /* Force speed */ if (phy->req_line_speed == SPEED_10000) {
DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n");
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_TXCTRL, 0); /* Arm LASI for link and Tx fault. */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 3);
} else { /* Force 1Gbps using autoneg with 1G advertisement */
/* 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(phy, params);
static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy,
struct link_params *params, u8 mode)
{
struct bnx2x *bp = params->bp;
u16 led_mode_bitmask = 0;
u16 gpio_pins_bitmask = 0;
u16 val;
/* Only NOC flavor requires to set the LED specifically */
if (!(phy->flags & FLAGS_NOC))
return;
switch (mode) {
case LED_MODE_FRONT_PANEL_OFF:
case LED_MODE_OFF:
led_mode_bitmask = 0;
gpio_pins_bitmask = 0x03;
break;
case LED_MODE_ON:
led_mode_bitmask = 0;
gpio_pins_bitmask = 0x02;
break;
case LED_MODE_OPER:
led_mode_bitmask = 0x60;
gpio_pins_bitmask = 0x11;
break;
}
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_OPT_CTRL,
&val);
val &= 0xff8f;
val |= led_mode_bitmask;
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_OPT_CTRL,
val);
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_GPIO_CTRL,
&val);
val &= 0xffe0;
val |= gpio_pins_bitmask;
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_GPIO_CTRL,
val);
}
static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
struct link_params *params) {
u32 swap_val, swap_override;
u8 port;
/* The PHY reset is controlled by GPIO 1. Fake the port number
* to cancel the swap done in set_gpio()
*/
struct bnx2x *bp = params->bp;
swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
port = (swap_val && swap_override) ^ 1;
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
}
static void bnx2x_8727_config_speed(struct bnx2x_phy *phy,
struct link_params *params)
{
struct bnx2x *bp = params->bp;
u16 tmp1, val;
/* Set option 1G speed */
if ((phy->req_line_speed == SPEED_1000) ||
(phy->media_type == ETH_PHY_SFP_1G_FIBER)) {
DP(NETIF_MSG_LINK, "Setting 1G force\n");
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD);
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1);
DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
/* Power down the XAUI until link is up in case of dual-media
* and 1G
*/
if (DUAL_MEDIA(params)) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_GP, &val);
val |= (3<<10);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_GP, val);
}
} else if ((phy->req_line_speed == SPEED_AUTO_NEG) &&
((phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) &&
((phy->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) !=
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) {
DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0);
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300);
} else {
/* Since the 8727 has only single reset pin, need to set the 10G
* registers although it is default
*/
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0x0020);
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x0008);
}
}
bnx2x_8727_specific_func(phy, params, PHY_INIT);
/* Initially configure MOD_ABS to interrupt when module is
* presence( bit 8)
*/
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
/* Set EDC off by setting OPTXLOS signal input to low (bit 9).
* When the EDC is off it locks onto a reference clock and avoids
* becoming 'lost'
*/
mod_abs &= ~(1<<8);
if (!(phy->flags & FLAGS_NOC))
mod_abs &= ~(1<<9);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
/* If TX Laser is controlled by GPIO_0, do not let PHY go into low
* power mode, if TX Laser is disabled
*/
tx_en_mode = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[params->port].sfp_ctrl))
& PORT_HW_CFG_TX_LASER_MASK;
/* Module is absent */
DP(NETIF_MSG_LINK,
"MOD_ABS indication show module is absent\n");
phy->media_type = ETH_PHY_NOT_PRESENT;
/* 1. Set mod_abs to detect next module
* presence event
* 2. Set EDC off by setting OPTXLOS signal input to low
* (bit 9).
* When the EDC is off it locks onto a reference clock and
* avoids becoming 'lost'.
*/
mod_abs &= ~(1<<8);
if (!(phy->flags & FLAGS_NOC))
mod_abs &= ~(1<<9);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
/* Clear RX alarm since it stays up as long as
* the mod_abs wasn't changed
*/
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
} else {
/* Module is present */
DP(NETIF_MSG_LINK,
"MOD_ABS indication show module is present\n");
/* First disable transmitter, and if the module is ok, the
* module_detection will enable it
* 1. Set mod_abs to detect next module absent event ( bit 8)
* 2. Restore the default polarity of the OPRXLOS signal and
* this signal will then correctly indicate the presence or
* absence of the Rx signal. (bit 9)
*/
mod_abs |= (1<<8);
if (!(phy->flags & FLAGS_NOC))
mod_abs |= (1<<9);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
/* Clear RX alarm since it stays up as long as the mod_abs
* wasn't changed. This is need to be done before calling the
* module detection, otherwise it will clear* the link update
* alarm
*/
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_LASI_RXSTAT, &rx_alarm_status);
if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
bnx2x_sfp_set_transmitter(params, phy, 0);
if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0)
bnx2x_sfp_module_detection(phy, params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
/* Reconfigure link speed based on module type limitations */
bnx2x_8727_config_speed(phy, params);
}
DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
rx_alarm_status);
/* No need to check link status in case of module plugged in/out */
}
/* If PHY is not initialized, do not check link status */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL,
&lasi_ctrl);
if (!lasi_ctrl)
return 0;
/* Check the LASI on Rx */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT,
&rx_alarm_status);
vars->line_speed = 0;
DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status);
/* If a module is present and there is need to check
* for over current
*/
if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) {
/* Check over-current using 8727 GPIO0 input*/
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL,
&val1);
if ((val1 & (1<<8)) == 0) {
if (!CHIP_IS_E1x(bp))
oc_port = BP_PATH(bp) + (params->port << 1);
DP(NETIF_MSG_LINK,
"8727 Power fault has been detected on port %d\n",
oc_port);
netdev_err(bp->dev, "Error: Power fault on Port %d has "
"been detected and the power to "
"that SFP+ module has been removed "
"to prevent failure of the card. "
"Please remove the SFP+ module and "
"restart the system to clear this "
"error.\n",
oc_port);
/* Disable all RX_ALARMs except for mod_abs */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_LASI_RXCTRL, (1<<5));
/* When module absent bit is set, check module */
if (rx_alarm_status & (1<<5)) {
bnx2x_8727_handle_mod_abs(phy, params);
/* Enable all mod_abs and link detection bits */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL,
((1<<5) | (1<<2)));
}
if ((DUAL_MEDIA(params)) &&
(phy->req_line_speed == SPEED_1000)) {
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_GP, &val1);
/* In case of dual-media board and 1G, power up the XAUI side,
* otherwise power it down. For 10G it is done automatically
*/
if (link_up)
val1 &= ~(3<<10);
else
val1 |= (3<<10);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8727_PCS_GP, val1);
}
return link_up;
}
for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
reg_set[i].val);
if (bnx2x_is_8483x_8485x(phy))
offset = MDIO_PMA_REG_84833_CTL_LED_CTL_1;
else
offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1;
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
val = MDIO_PMA_REG_84858_ALLOW_GPHY_ACT |
MDIO_PMA_REG_84823_LED3_STRETCH_EN;
else
val = MDIO_PMA_REG_84823_LED3_STRETCH_EN;
static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,
struct link_params *params,
u32 action)
{
struct bnx2x *bp = params->bp;
switch (action) {
case PHY_INIT:
if (bnx2x_is_8483x_8485x(phy)) {
/* Save spirom version */
bnx2x_save_848xx_spirom_version(phy, bp, params->port);
}
/* This phy uses the NIG latch mechanism since link indication
* arrives through its LED4 and not via its LASI signal, so we
* get steady signal instead of clear on read
*/
bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, 1 << NIG_LATCH_BC_ENABLE_MI_INT);
if (phy->req_duplex == DUPLEX_FULL)
autoneg_val |= (1<<8);
/* Always write this if this is not 84833/4.
* For 84833/4, write it only when it's a forced speed.
*/
if (!bnx2x_is_8483x_8485x(phy) ||
((autoneg_val & (1<<12)) == 0))
bnx2x_cl45_write(bp, phy,
MDIO_AN_DEVAD,
MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val);
static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy,
struct link_params *params,
u16 fw_cmd,
u16 cmd_args[], int argc)
{
int idx;
u16 val;
struct bnx2x *bp = params->bp;
/* Step 1: Poll the STATUS register to see whether the previous command
* is in progress or the system is busy (CMD_IN_PROGRESS or
* SYSTEM_BUSY). If previous command is in progress or system is busy,
* check again until the previous command finishes execution and the
* system is available for taking command
*/
for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_848xx_CMD_HDLR_STATUS, &val);
if ((val != PHY84858_STATUS_CMD_IN_PROGRESS) &&
(val != PHY84858_STATUS_CMD_SYSTEM_BUSY))
break;
usleep_range(1000, 2000);
}
if (idx >= PHY848xx_CMDHDLR_WAIT) {
DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n");
return -EINVAL;
}
/* Step2: If any parameters are required for the function, write them
* to the required DATA registers
*/
/* Step3: When the firmware is ready for commands, write the 'Command
* code' to the CMD register
*/
bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd);
/* Step4: Once the command has been written, poll the STATUS register
* to check whether the command has completed (CMD_COMPLETED_PASS/
* CMD_FOR_CMDS or CMD_COMPLETED_ERROR).
*/
for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_848xx_CMD_HDLR_STATUS, &val);
if ((val == PHY84858_STATUS_CMD_COMPLETE_PASS) ||
(val == PHY84858_STATUS_CMD_COMPLETE_ERROR))
break;
usleep_range(1000, 2000);
}
if ((idx >= PHY848xx_CMDHDLR_WAIT) ||
(val == PHY84858_STATUS_CMD_COMPLETE_ERROR)) {
DP(NETIF_MSG_LINK, "FW cmd failed.\n");
return -EINVAL;
}
/* Step5: Once the command has completed, read the specficied DATA
* registers for any saved results for the command, if applicable
*/
/* Work around for 84833 LED failure inside RESET status */
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
MDIO_AN_REG_8481_LEGACY_MII_CTRL,
MDIO_AN_REG_8481_MII_CTRL_FORCE_1G);
bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
MDIO_AN_REG_8481_1G_100T_EXT_CTRL,
MIDO_AN_REG_8481_EXT_CTRL_FORCE_LEDS_OFF);
/* Prevent Phy from working in EEE and advertising it */
rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE,
&cmd_args, 1, PHY84833_MB_PROCESS1);
if (rc) {
DP(NETIF_MSG_LINK, "EEE disable failed.\n");
return rc;
}
/* Wait for GPHY to come out of reset */
msleep(50);
if (!bnx2x_is_8483x_8485x(phy)) {
/* BCM84823 requires that XGXS links up first @ 10G for normal
* behavior.
*/
u16 temp;
temp = vars->line_speed;
vars->line_speed = SPEED_10000;
bnx2x_set_autoneg(¶ms->phy[INT_PHY], params, vars, 0);
bnx2x_program_serdes(¶ms->phy[INT_PHY], params, vars);
vars->line_speed = temp;
}
/* Check if this is actually BCM84858 */
if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
u16 hw_rev;
switch (actual_phy_selection) {
case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
/* Do nothing. Essentially this is like the priority copper */
break;
case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER;
break;
case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER;
break;
case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
/* Do nothing here. The first PHY won't be initialized at all */
break;
case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN;
initialize = 0;
break;
}
if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000)
val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
MDIO_CTL_REG_84823_MEDIA, val);
DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
params->multi_phy_config, val);
if (bnx2x_is_8483x_8485x(phy)) {
bnx2x_848xx_pair_swap_cfg(phy, params, vars);
/* Keep AutogrEEEn disabled. */
cmd_args[0] = 0x0;
cmd_args[1] = 0x0;
cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1;
cmd_args[3] = PHY84833_CONSTANT_LATENCY;
rc = bnx2x_848xx_cmd_hdlr(phy, params,
PHY848xx_CMD_SET_EEE_MODE, cmd_args, 4, PHY84833_MB_PROCESS1);
if (rc)
DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
}
if (initialize)
rc = bnx2x_848xx_cmn_config_init(phy, params, vars);
else
bnx2x_save_848xx_spirom_version(phy, bp, params->port);
/* 84833 PHY has a better feature and doesn't need to support this. */
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
u32 cms_enable = REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[params->port].default_cfg)) &
PORT_HW_CFG_ENABLE_CMS_MASK;
bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
MDIO_CTL_REG_84823_USER_CTRL_REG, &val);
if (cms_enable)
val |= MDIO_CTL_REG_84823_USER_CTRL_CMS;
else
val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS;
bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
MDIO_CTL_REG_84823_USER_CTRL_REG, val);
}
if (bnx2x_is_8483x_8485x(phy)) {
/* Bring PHY out of super isolate mode as the final step. */
bnx2x_cl45_read_and_write(bp, phy,
MDIO_CTL_DEVAD,
MDIO_84833_TOP_CFG_XGPHY_STRAP1,
(u16)~MDIO_84833_SUPER_ISOLATE);
}
}
} else {
/* LED 1 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED1_MASK, 0x0);
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
/* LED 2 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED2_MASK, 0x0);
/* LED 3 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED3_MASK, 0x0);
}
}
break;
case LED_MODE_FRONT_PANEL_OFF:
DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
port);
if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
SHARED_HW_CFG_LED_EXTPHY1) {
/* Set LED masks */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED1_MASK, 0x0);
} else {
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED1_MASK, 0x0);
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
/* Disable MI_INT interrupt before setting LED4
* source to constant off.
*/
if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
params->port*4) &
NIG_MASK_MI_INT) {
params->link_flags |=
LINK_FLAGS_INT_DISABLED;
bnx2x_bits_dis(
bp,
NIG_REG_MASK_INTERRUPT_PORT0 +
params->port*4,
NIG_MASK_MI_INT);
}
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_SIGNAL_MASK, 0x0);
}
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
/* LED 2 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED2_MASK, 0x0);
/* LED 3 OFF */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED3_MASK, 0x0);
}
}
break;
case LED_MODE_ON:
DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
SHARED_HW_CFG_LED_EXTPHY1) {
/* Set control reg */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LINK_SIGNAL,
&val);
val &= 0x8000;
val |= 0x2492;
} else {
/* EXTPHY2 LED mode indicate that the 100M/1G/10G LED
* sources are all wired through LED1, rather than only
* 10G in other modes.
*/
val = ((params->hw_led_mode <<
SHARED_HW_CFG_LED_MODE_SHIFT) ==
SHARED_HW_CFG_LED_EXTPHY2) ? 0x98 : 0x80;
/* Tell LED3 to blink on source */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LINK_SIGNAL,
&val);
val &= ~(7<<6);
val |= (1<<6); /* A83B[8:6]= 1 */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LINK_SIGNAL,
val);
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED2_MASK, 0x18);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED3_MASK, 0x06);
}
if (phy->type ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
/* Restore LED4 source to external link,
* and re-enable interrupts.
*/
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_SIGNAL_MASK, 0x40);
if (params->link_flags &
LINK_FLAGS_INT_DISABLED) {
bnx2x_link_int_enable(params);
params->link_flags &=
~LINK_FLAGS_INT_DISABLED;
}
}
}
break;
}
/* This is a workaround for E3+84833 until autoneg
* restart is fixed in f/w
*/
if (CHIP_IS_E3(bp)) {
bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_GP2_STATUS_GP_2_1, &val);
}
}
/* Set up fc */
/* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
fc_val = 0;
if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC)
fc_val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH)
fc_val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
/* Read all advertisement */
bnx2x_cl22_read(bp, phy, 0x09,
&an_1000_val);
rc = bnx2x_eee_initial_config(params, vars, SHMEM_EEE_1G_ADV);
if (rc) {
DP(NETIF_MSG_LINK, "Failed to configure EEE timers\n");
bnx2x_eee_disable(phy, params, vars);
} else if ((params->eee_mode & EEE_MODE_ADV_LPI) &&
(phy->req_duplex == DUPLEX_FULL) &&
(bnx2x_eee_calc_timer(params) ||
!(params->eee_mode & EEE_MODE_ENABLE_LPI))) {
/* Need to advertise EEE only when requested,
* and either no LPI assertion was requested,
* or it was requested and a valid timer was set.
* Also notice full duplex is required for EEE.
*/
bnx2x_eee_advertise(phy, params, vars,
SHMEM_EEE_1G_ADV);
} else {
DP(NETIF_MSG_LINK, "Don't Advertise 1GBase-T EEE\n");
bnx2x_eee_disable(phy, params, vars);
}
} else {
vars->eee_status &= ~SHMEM_EEE_1G_ADV <<
SHMEM_EEE_SUPPORTED_SHIFT;
/* In case of no EPIO routed to reset the GPHY, put it
* in low power mode.
*/
bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800);
/* This works with E3 only, no need to check the chip
* before determining the port.
*/
port = params->port;
cfg_pin = (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].e3_cmn_pin_cfg)) &
PORT_HW_CFG_E3_PHY_RESET_MASK) >>
PORT_HW_CFG_E3_PHY_RESET_SHIFT;
/* Drive pin low to put GPHY in reset. */
bnx2x_set_cfg_pin(bp, cfg_pin, 0);
}
/* Enable master/slave manual mmode and set to master */
/* mii write 9 [bits set 1112] */
bnx2x_cl22_write(bp, phy, 0x09, 3<<11);
/* forced 1G and disable autoneg */
/* set val [mii read 0] */
/* set val [expr $val & [bits clear 61213]] */
/* set val [expr $val | [bits set 68]] */
/* mii write 0 $val */
bnx2x_cl22_read(bp, phy, 0x00, &val);
val &= ~((1<<6) | (1<<12) | (1<<13));
val |= (1<<6) | (1<<8);
bnx2x_cl22_write(bp, phy, 0x00, val);
/* Set external loopback and Tx using 6dB coding */
/* mii write 0x18 7 */
/* set val [mii read 0x18] */
/* mii write 0x18 [expr $val | [bits set 1015]] */
bnx2x_cl22_write(bp, phy, 0x18, 7);
bnx2x_cl22_read(bp, phy, 0x18, &val);
bnx2x_cl22_write(bp, phy, 0x18, val | (1<<10) | (1<<15));
/* This register opens the gate for the UMAC despite its name */
REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1);
/* Maximum Frame Length (RW). Defines a 14-Bit maximum frame
* length used by the MAC receive logic to check frames.
*/
REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710);
}
/* Restore normal power mode*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port);
/* HW reset */
bnx2x_ext_phy_hw_reset(bp, params->port);
bnx2x_wait_reset_complete(bp, phy, params);
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x1);
DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n");
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3));
static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base,
struct bnx2x_phy *phy, u8 port,
u8 phy_index)
{
/* Get the 4 lanes xgxs config rx and tx */
u32 rx = 0, tx = 0, i;
for (i = 0; i < 2; i++) {
/* INT_PHY and EXT_PHY1 share the same value location in
* the shmem. When num_phys is greater than 1, than this value
* applies only to EXT_PHY1
*/
if (phy_index == INT_PHY || phy_index == EXT_PHY1) {
rx = REG_RD(bp, shmem_base +
offsetof(struct shmem_region,
dev_info.port_hw_config[port].xgxs_config_rx[i<<1]));
/* The shmem address of the phy version is located on different
* structures. In case this structure is too old, do not set
* the address
*/
config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region,
dev_info.shared_hw_config.config2));
if (phy_index == EXT_PHY1) {
phy->ver_addr = shmem_base + offsetof(struct shmem_region,
port_mb[port].ext_phy_fw_version);
/* Update media type for non-PMF sync only for the first time
* In case the media type changes afterwards, it will be updated
* using the update_status function
*/
if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
(PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
actual_phy_idx))) == 0) {
media_types |= ((phy->media_type &
PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
(PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
actual_phy_idx));
}
REG_WR(bp, sync_offset, media_types);
void bnx2x_set_rx_filter(struct link_params *params, u8 en)
{
struct bnx2x *bp = params->bp;
u8 val = en * 0x1F;
/* Open / close the gate between the NIG and the BRB */
if (!CHIP_IS_E1x(bp))
val |= en * 0x20;
REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + params->port*4, val);
if (!CHIP_IS_E1(bp)) {
REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + params->port*4,
en*0x3);
}
if (!params->lfa_base)
return;
/* Store the new link parameters */
REG_WR(bp, params->lfa_base +
offsetof(struct shmem_lfa, req_duplex),
params->req_duplex[0] | (params->req_duplex[1] << 16));
usleep_range(10000, 20000);
/* The PHY reset is controlled by GPIO 1
* Hold it as vars low
*/
/* Clear link led */
bnx2x_set_mdio_emac_per_phy(bp, params);
bnx2x_set_led(params, vars, LED_MODE_OFF, 0);
if (reset_ext_phy) {
for (phy_index = EXT_PHY1; phy_index < params->num_phys;
phy_index++) {
if (params->phy[phy_index].link_reset) {
bnx2x_set_aer_mmd(params,
¶ms->phy[phy_index]);
params->phy[phy_index].link_reset(
¶ms->phy[phy_index],
params);
}
if (params->phy[phy_index].flags &
FLAGS_REARM_LATCH_SIGNAL)
clear_latch_ind = 1;
}
}
/* Disable nig ingress interface */
if (!CHIP_IS_E3(bp)) {
/* Reset BigMac */
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
(MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0);
REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0);
} else {
u32 xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
bnx2x_set_xumac_nig(params, 0, 0);
if (REG_RD(bp, MISC_REG_RESET_REG_2) &
MISC_REGISTERS_RESET_REG_2_XMAC)
REG_WR(bp, xmac_base + XMAC_REG_CTRL,
XMAC_CTRL_REG_SOFT_RESET);
}
vars->link_up = 0;
vars->phy_flags = 0;
return 0;
}
int bnx2x_lfa_reset(struct link_params *params,
struct link_vars *vars)
{
struct bnx2x *bp = params->bp;
vars->link_up = 0;
vars->phy_flags = 0;
params->link_flags &= ~PHY_INITIALIZED;
if (!params->lfa_base)
return bnx2x_link_reset(params, vars, 1);
/*
* Activate NIG drain so that during this time the device won't send
* anything while it is unable to response.
*/
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 1);
/*
* Close gracefully the gate from BMAC to NIG such that no half packets
* are passed.
*/
if (!CHIP_IS_E3(bp))
bnx2x_set_bmac_rx(bp, params->chip_id, params->port, 0);
if (CHIP_IS_E3(bp)) {
bnx2x_set_xmac_rxtx(params, 0);
bnx2x_set_umac_rxtx(params, 0);
}
/* Wait 10ms for the pipe to clean up*/
usleep_range(10000, 20000);
/* Clean the NIG-BRB using the network filters in a way that will
* not cut a packet in the middle.
*/
bnx2x_set_rx_filter(params, 0);
/*
* Re-open the gate between the BMAC and the NIG, after verifying the
* gate to the BRB is closed, otherwise packets may arrive to the
* firmware before driver had initialized it. The target is to achieve
* minimum management protocol down time.
*/
if (!CHIP_IS_E3(bp))
bnx2x_set_bmac_rx(bp, params->chip_id, params->port, 1);
/****************************************************************************/
/* Common function */
/****************************************************************************/
static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
u32 shmem_base_path[],
u32 shmem2_base_path[], u8 phy_index,
u32 chip_id)
{
struct bnx2x_phy phy[PORT_MAX];
struct bnx2x_phy *phy_blk[PORT_MAX];
u16 val;
s8 port = 0;
s8 port_of_path = 0;
u32 swap_val, swap_override;
swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
port ^= (swap_val && swap_override);
bnx2x_ext_phy_hw_reset(bp, port);
/* PART1 - Reset both phys */
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_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 */
if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
port_of_path, &phy[port]) != 0) {
DP(NETIF_MSG_LINK, "populate_phy failed\n");
return -EINVAL;
}
/* Disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
port_of_path*4,
(NIG_MASK_XGXS0_LINK_STATUS |
NIG_MASK_XGXS0_LINK10G |
NIG_MASK_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT));
/* Need to take the phy out of low power mode in order
* to write to access its registers
*/
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_HIGH,
port);
/* Toggle Transmitter: Power down and then up with 600ms delay
* between
*/
msleep(600);
/* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
/* Phase2 of POWER_DOWN_RESET */
/* Release bit 10 (Release Tx power down) */
bnx2x_cl45_read(bp, phy_blk[port],
MDIO_PMA_DEVAD,
MDIO_PMA_REG_TX_POWER_DOWN, &val);
/* set GPIO2 back to LOW */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
}
return 0;
}
static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
u32 shmem_base_path[],
u32 shmem2_base_path[], u8 phy_index,
u32 chip_id)
{
u32 val;
s8 port;
struct bnx2x_phy phy;
/* 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_ext_phy_hw_reset(bp, 0);
usleep_range(5000, 10000);
for (port = 0; port < PORT_MAX; port++) {
u32 shmem_base, shmem2_base;
/* In E2, same phy is using for port0 of the two paths */
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,
port, &phy) != 0) {
DP(NETIF_MSG_LINK, "populate phy failed\n");
return -EINVAL;
}
/* Retrieve the reset gpio/port which control the reset.
* Default is GPIO1, PORT1
*/
bnx2x_get_ext_phy_reset_gpio(bp, shmem_base_path[0],
(u8 *)&reset_gpio, (u8 *)&port);
/* Calculate the port based on port swap */
port ^= (swap_val && swap_override);
/* PART1 - Reset both phys */
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_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 */
if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base,
port_of_path, &phy[port]) != 0) {
DP(NETIF_MSG_LINK, "populate phy failed\n");
return -EINVAL;
}
/* disable attentions */
bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
port_of_path*4,
(NIG_MASK_XGXS0_LINK_STATUS |
NIG_MASK_XGXS0_LINK10G |
NIG_MASK_SERDES0_LINK_STATUS |
NIG_MASK_MI_INT));
static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
u32 shmem2_base_path[], u8 phy_index,
u32 ext_phy_type, u32 chip_id)
{
int rc = 0;
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
rc = bnx2x_8073_common_init_phy(bp, shmem_base_path,
shmem2_base_path,
phy_index, chip_id);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
shmem2_base_path,
phy_index, chip_id);
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_path,
shmem2_base_path,
phy_index, chip_id);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858:
/* GPIO3's are linked, and so both need to be toggled
* to obtain required 2us pulse.
*/
rc = bnx2x_84833_common_init_phy(bp, shmem_base_path,
shmem2_base_path,
phy_index, chip_id);
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE:
rc = -EINVAL;
break;
default:
DP(NETIF_MSG_LINK,
"ext_phy 0x%x common init not required\n",
ext_phy_type);
break;
}
if (rc)
netdev_err(bp->dev, "Warning: PHY was not initialized,"
" Port %d\n", 0);
return rc;
}
/* Ignore check if no external input PIN available */
if (bnx2x_get_cfg_pin(bp, cfg_pin, &pin_val) != 0)
return;
if (!pin_val) {
if ((vars->phy_flags & PHY_OVER_CURRENT_FLAG) == 0) {
netdev_err(bp->dev, "Error: Power fault on Port %d has"
" been detected and the power to "
"that SFP+ module has been removed"
" to prevent failure of the card."
" Please remove the SFP+ module and"
" restart the system to clear this"
" error.\n",
params->port);
vars->phy_flags |= PHY_OVER_CURRENT_FLAG;
bnx2x_warpcore_power_module(params, 0);
}
} else
vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG;
}
/* Returns 0 if no change occurred since last check; 1 otherwise. */
static u8 bnx2x_analyze_link_error(struct link_params *params,
struct link_vars *vars, u32 status,
u32 phy_flag, u32 link_flag, u8 notify)
{
struct bnx2x *bp = params->bp;
/* Compare new value with previous value */
u8 led_mode;
u32 old_status = (vars->phy_flags & phy_flag) ? 1 : 0;
/* Do not touch the link in case physical link down */
if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0)
return 1;
/* a. Update shmem->link_status accordingly
* b. Update link_vars->link_up
*/
if (status) {
vars->link_status &= ~LINK_STATUS_LINK_UP;
vars->link_status |= link_flag;
vars->link_up = 0;
vars->phy_flags |= phy_flag;
/* activate nig drain */
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 1);
/* Set LED mode to off since the PHY doesn't know about these
* errors
*/
led_mode = LED_MODE_OFF;
} else {
vars->link_status |= LINK_STATUS_LINK_UP;
vars->link_status &= ~link_flag;
vars->link_up = 1;
vars->phy_flags &= ~phy_flag;
led_mode = LED_MODE_OPER;
/* Clear nig drain */
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
}
bnx2x_sync_link(params, vars);
/* Update the LED according to the link state */
bnx2x_set_led(params, vars, led_mode, SPEED_10000);
/* Update link status in the shared memory */
bnx2x_update_mng(params, vars->link_status);
/* C. Trigger General Attention */
vars->periodic_flags |= PERIODIC_FLAGS_LINK_EVENT;
if (notify)
bnx2x_notify_link_changed(bp);
return 1;
}
/******************************************************************************
* Description:
* This function checks for half opened connection change indication.
* When such change occurs, it calls the bnx2x_analyze_link_error
* to check if Remote Fault is set or cleared. Reception of remote fault
* status message in the MAC indicates that the peer's MAC has detected
* a fault, for example, due to break in the TX side of fiber.
*
******************************************************************************/
static int bnx2x_check_half_open_conn(struct link_params *params,
struct link_vars *vars,
u8 notify)
{
struct bnx2x *bp = params->bp;
u32 lss_status = 0;
u32 mac_base;
/* In case link status is physically up @ 10G do */
if (((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0) ||
(REG_RD(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4)))
return 0;
if (CHIP_IS_E3(bp) &&
(REG_RD(bp, MISC_REG_RESET_REG_2) &
(MISC_REGISTERS_RESET_REG_2_XMAC))) {
/* Check E3 XMAC */
/* Note that link speed cannot be queried here, since it may be
* zero while link is down. In case UMAC is active, LSS will
* simply not be set
*/
mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0;
/* Once KR2 was disabled, wait 5 seconds before checking KR2 recovery
* Since some switches tend to reinit the AN process and clear the
* advertised BP/NP after ~2 seconds causing the KR2 to be disabled
* and recovered many times
*/
if (vars->check_kr2_recovery_cnt > 0) {
vars->check_kr2_recovery_cnt--;
return;
}
sigdet = bnx2x_warpcore_get_sigdet(phy, params);
if (!sigdet) {
if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
bnx2x_kr2_recovery(params, vars, phy);
DP(NETIF_MSG_LINK, "No sigdet\n");
}
return;
}
/* CL73 has not begun yet */
if (base_page == 0) {
if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
bnx2x_kr2_recovery(params, vars, phy);
DP(NETIF_MSG_LINK, "No BP\n");
}
return;
}
/* In case NP bit is not set in the BasePage, or it is set,
* but only KX is advertised, declare this link partner as non-KR2
* device.
*/
not_kr2_device = (((base_page & 0x8000) == 0) ||
(((base_page & 0x8000) &&
((next_page & 0xe0) == 0x20))));
/* In case KR2 is already disabled, check if we need to re-enable it */
if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
if (!not_kr2_device) {
DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page,
next_page);
bnx2x_kr2_recovery(params, vars, phy);
}
return;
}
/* KR2 is enabled, but not KR2 device */
if (not_kr2_device) { /* Disable KR2 on both lanes */
DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page, next_page);
bnx2x_disable_kr2(params, vars, phy); /* Restart AN on leading lane */
bnx2x_warpcore_restart_AN_KR(phy, params); return;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.