bnx2x: Fix CL73 autoneg issues

- Advertise 1G KX4 in CL73 when 1G speed capability is enabled
- Add flow-control negotiation over CL73
- External loopback test on Serdes should be done in FORCE mode, since in
CL73 it is unable to link up with the same core using AUTONEG
- Fix bnx2x_set_led function to support CL73 link leds

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yaniv Rosner 2009-11-05 19:18:07 +02:00 committed by David S. Miller
parent 18afb0a6fa
commit 7846e471b5
4 changed files with 104 additions and 65 deletions

View file

@ -1228,7 +1228,7 @@ static void bnx2x_set_autoneg(struct link_params *params,
params->phy_addr, params->phy_addr,
MDIO_REG_BANK_CL73_USERB0, MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_UCTRL, MDIO_CL73_USERB0_CL73_UCTRL,
MDIO_CL73_USERB0_CL73_UCTRL_USTAT1_MUXSEL); 0xe);
/* Enable BAM Station Manager*/ /* Enable BAM Station Manager*/
CL45_WR_OVER_CL22(bp, params->port, CL45_WR_OVER_CL22(bp, params->port,
@ -1239,29 +1239,25 @@ static void bnx2x_set_autoneg(struct link_params *params,
MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN);
/* Merge CL73 and CL37 aneg resolution */ /* Advertise CL73 link speeds */
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_CL73_USERB0,
MDIO_CL73_USERB0_CL73_BAM_CTRL3,
&reg_val);
if (params->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
/* Set the CL73 AN speed */
CL45_RD_OVER_CL22(bp, params->port, CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr, params->phy_addr,
MDIO_REG_BANK_CL73_IEEEB1, MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV2, MDIO_CL73_IEEEB1_AN_ADV2,
&reg_val); &reg_val);
if (params->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)
reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
if (params->speed_cap_mask &
PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
CL45_WR_OVER_CL22(bp, params->port, CL45_WR_OVER_CL22(bp, params->port,
params->phy_addr, params->phy_addr,
MDIO_REG_BANK_CL73_IEEEB1, MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV2, MDIO_CL73_IEEEB1_AN_ADV2,
reg_val | MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4); reg_val);
}
/* CL73 Autoneg Enabled */ /* CL73 Autoneg Enabled */
reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
@ -1389,12 +1385,23 @@ static void bnx2x_set_ieee_aneg_advertisment(struct link_params *params,
u16 ieee_fc) u16 ieee_fc)
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u16 val;
/* for AN, we are always publishing full duplex */ /* for AN, we are always publishing full duplex */
CL45_WR_OVER_CL22(bp, params->port, CL45_WR_OVER_CL22(bp, params->port,
params->phy_addr, params->phy_addr,
MDIO_REG_BANK_COMBO_IEEE0, MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc);
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV1, &val);
val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH;
val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK);
CL45_WR_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_ADV1, val);
} }
static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73) static void bnx2x_restart_autoneg(struct link_params *params, u8 enable_cl73)
@ -1630,21 +1637,49 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params,
(!(vars->phy_flags & PHY_SGMII_FLAG)) && (!(vars->phy_flags & PHY_SGMII_FLAG)) &&
(XGXS_EXT_PHY_TYPE(params->ext_phy_config) == (XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) { PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
CL45_RD_OVER_CL22(bp, params->port, if ((gp_status &
params->phy_addr, (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
MDIO_REG_BANK_COMBO_IEEE0, MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
MDIO_COMBO_IEEE0_AUTO_NEG_ADV, (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
&ld_pause); MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) {
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr, CL45_RD_OVER_CL22(bp, params->port,
MDIO_REG_BANK_COMBO_IEEE0, params->phy_addr,
MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, MDIO_REG_BANK_CL73_IEEEB1,
&lp_pause); MDIO_CL73_IEEEB1_AN_ADV1,
pause_result = (ld_pause & &ld_pause);
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_CL73_IEEEB1,
MDIO_CL73_IEEEB1_AN_LP_ADV1,
&lp_pause);
pause_result = (ld_pause &
MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
>> 8;
pause_result |= (lp_pause &
MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK)
>> 10;
DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n",
pause_result);
} else {
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
&ld_pause);
CL45_RD_OVER_CL22(bp, params->port,
params->phy_addr,
MDIO_REG_BANK_COMBO_IEEE0,
MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
&lp_pause);
pause_result = (ld_pause &
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
pause_result |= (lp_pause & pause_result |= (lp_pause &
MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
pause_result);
}
bnx2x_pause_resolve(vars, pause_result); bnx2x_pause_resolve(vars, pause_result);
} else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) &&
(bnx2x_ext_phy_resolve_fc(params, vars))) { (bnx2x_ext_phy_resolve_fc(params, vars))) {
@ -1990,8 +2025,7 @@ static u8 bnx2x_emac_program(struct link_params *params,
GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
mode); mode);
bnx2x_set_led(bp, params->port, LED_MODE_OPER, bnx2x_set_led(params, LED_MODE_OPER, line_speed);
line_speed, params->hw_led_mode, params->chip_id);
return 0; return 0;
} }
@ -3547,7 +3581,10 @@ static void bnx2x_init_internal_phy(struct link_params *params,
bnx2x_set_preemphasis(params); bnx2x_set_preemphasis(params);
/* forced speed requested? */ /* forced speed requested? */
if (vars->line_speed != SPEED_AUTO_NEG) { if (vars->line_speed != SPEED_AUTO_NEG ||
((XGXS_EXT_PHY_TYPE(params->ext_phy_config) ==
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
params->loopback_mode == LOOPBACK_EXT)) {
DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
/* disable autoneg */ /* disable autoneg */
@ -5731,13 +5768,15 @@ u8 bnx2x_override_led_value(struct bnx2x *bp, u8 port,
} }
u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed)
u16 hw_led_mode, u32 chip_id)
{ {
u8 port = params->port;
u16 hw_led_mode = params->hw_led_mode;
u8 rc = 0; u8 rc = 0;
u32 tmp; u32 tmp;
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
struct bnx2x *bp = params->bp;
DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); 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", DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n",
speed, hw_led_mode); speed, hw_led_mode);
@ -5752,7 +5791,14 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
break; break;
case LED_MODE_OPER: case LED_MODE_OPER:
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
} else {
REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4,
hw_led_mode);
}
REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 +
port*4, 0); port*4, 0);
/* Set blinking rate to ~15.9Hz */ /* Set blinking rate to ~15.9Hz */
@ -5764,7 +5810,7 @@ u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed,
EMAC_WR(bp, EMAC_REG_EMAC_LED, EMAC_WR(bp, EMAC_REG_EMAC_LED,
(tmp & (~EMAC_LED_OVERRIDE))); (tmp & (~EMAC_LED_OVERRIDE)));
if (!CHIP_IS_E1H(bp) && if (CHIP_IS_E1(bp) &&
((speed == SPEED_2500) || ((speed == SPEED_2500) ||
(speed == SPEED_1000) || (speed == SPEED_1000) ||
(speed == SPEED_100) || (speed == SPEED_100) ||
@ -6033,10 +6079,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0); params->port*4, 0);
bnx2x_set_led(bp, params->port, LED_MODE_OPER, bnx2x_set_led(params, LED_MODE_OPER, vars->line_speed);
vars->line_speed, params->hw_led_mode,
params->chip_id);
} else } else
/* No loopback */ /* No loopback */
{ {
@ -6094,8 +6137,6 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
{ {
struct bnx2x *bp = params->bp; struct bnx2x *bp = params->bp;
u32 ext_phy_config = params->ext_phy_config; u32 ext_phy_config = params->ext_phy_config;
u16 hw_led_mode = params->hw_led_mode;
u32 chip_id = params->chip_id;
u8 port = params->port; u8 port = params->port;
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
u32 val = REG_RD(bp, params->shmem_base + u32 val = REG_RD(bp, params->shmem_base +
@ -6130,7 +6171,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
* Hold it as vars low * Hold it as vars low
*/ */
/* clear link led */ /* clear link led */
bnx2x_set_led(bp, port, LED_MODE_OFF, 0, hw_led_mode, chip_id); bnx2x_set_led(params, LED_MODE_OFF, 0);
if (reset_ext_phy) { if (reset_ext_phy) {
switch (ext_phy_type) { switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
@ -6201,9 +6242,7 @@ static u8 bnx2x_update_link_down(struct link_params *params,
u8 port = params->port; u8 port = params->port;
DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port); DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port);
bnx2x_set_led(bp, port, LED_MODE_OFF, bnx2x_set_led(params, LED_MODE_OFF, 0);
0, params->hw_led_mode,
params->chip_id);
/* indicate no mac active */ /* indicate no mac active */
vars->mac_type = MAC_TYPE_NONE; vars->mac_type = MAC_TYPE_NONE;
@ -6240,10 +6279,7 @@ static u8 bnx2x_update_link_up(struct link_params *params,
vars->link_status |= LINK_STATUS_LINK_UP; vars->link_status |= LINK_STATUS_LINK_UP;
if (link_10g) { if (link_10g) {
bnx2x_bmac_enable(params, vars, 0); bnx2x_bmac_enable(params, vars, 0);
bnx2x_set_led(bp, port, LED_MODE_OPER, bnx2x_set_led(params, LED_MODE_OPER, SPEED_10000);
SPEED_10000, params->hw_led_mode,
params->chip_id);
} else { } else {
bnx2x_emac_enable(params, vars, 0); bnx2x_emac_enable(params, vars, 0);
rc = bnx2x_emac_program(params, vars->line_speed, rc = bnx2x_emac_program(params, vars->line_speed,

View file

@ -178,8 +178,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
Basically, the CLC takes care of the led for the link, but in case one needs Basically, the CLC takes care of the led for the link, but in case one needs
to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to
blink the led, and LED_MODE_OFF to set the led off.*/ blink the led, and LED_MODE_OFF to set the led off.*/
u8 bnx2x_set_led(struct bnx2x *bp, u8 port, u8 mode, u32 speed, u8 bnx2x_set_led(struct link_params *params, u8 mode, u32 speed);
u16 hw_led_mode, u32 chip_id);
#define LED_MODE_OFF 0 #define LED_MODE_OFF 0
#define LED_MODE_OPER 2 #define LED_MODE_OPER 2

View file

@ -10855,7 +10855,6 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
static int bnx2x_phys_id(struct net_device *dev, u32 data) static int bnx2x_phys_id(struct net_device *dev, u32 data)
{ {
struct bnx2x *bp = netdev_priv(dev); struct bnx2x *bp = netdev_priv(dev);
int port = BP_PORT(bp);
int i; int i;
if (!netif_running(dev)) if (!netif_running(dev))
@ -10869,13 +10868,10 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
for (i = 0; i < (data * 2); i++) { for (i = 0; i < (data * 2); i++) {
if ((i % 2) == 0) if ((i % 2) == 0)
bnx2x_set_led(bp, port, LED_MODE_OPER, SPEED_1000, bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
bp->link_params.hw_led_mode, SPEED_1000);
bp->link_params.chip_id);
else else
bnx2x_set_led(bp, port, LED_MODE_OFF, 0, bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
bp->link_params.hw_led_mode,
bp->link_params.chip_id);
msleep_interruptible(500); msleep_interruptible(500);
if (signal_pending(current)) if (signal_pending(current))
@ -10883,10 +10879,8 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
} }
if (bp->link_vars.link_up) if (bp->link_vars.link_up)
bnx2x_set_led(bp, port, LED_MODE_OPER, bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
bp->link_vars.line_speed, bp->link_vars.line_speed);
bp->link_params.hw_led_mode,
bp->link_params.chip_id);
return 0; return 0;
} }

View file

@ -4772,18 +4772,28 @@
#define PCI_ID_VAL2 0x438 #define PCI_ID_VAL2 0x438
#define MDIO_REG_BANK_CL73_IEEEB0 0x0 #define MDIO_REG_BANK_CL73_IEEEB0 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN 0x1000 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN 0x1000
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_MAIN_RST 0x8000 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_MAIN_RST 0x8000
#define MDIO_REG_BANK_CL73_IEEEB1 0x10 #define MDIO_REG_BANK_CL73_IEEEB1 0x10
#define MDIO_CL73_IEEEB1_AN_ADV2 0x01 #define MDIO_CL73_IEEEB1_AN_ADV1 0x00
#define MDIO_CL73_IEEEB1_AN_ADV1_PAUSE 0x0400
#define MDIO_CL73_IEEEB1_AN_ADV1_ASYMMETRIC 0x0800
#define MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH 0x0C00
#define MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK 0x0C00
#define MDIO_CL73_IEEEB1_AN_ADV2 0x01
#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M 0x0000 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M 0x0000
#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX 0x0020 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX 0x0020
#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 0x0040 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 0x0040
#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR 0x0080 #define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR 0x0080
#define MDIO_CL73_IEEEB1_AN_LP_ADV1 0x03
#define MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE 0x0400
#define MDIO_CL73_IEEEB1_AN_LP_ADV1_ASYMMETRIC 0x0800
#define MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_BOTH 0x0C00
#define MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK 0x0C00
#define MDIO_REG_BANK_RX0 0x80b0 #define MDIO_REG_BANK_RX0 0x80b0
#define MDIO_RX0_RX_STATUS 0x10 #define MDIO_RX0_RX_STATUS 0x10