Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e7e8399 authored by Mintz Yuval's avatar Mintz Yuval Committed by David S. Miller
Browse files

bnx2x: ethtool publishes link partners speed and FC



Following the changes in the ethtool source code, this patch enables
the bnx2x driver to publish the Link partner's capabilities s, when ethtool
is used on an interface which completed autoneg.

Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarYaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e18c56b2
Loading
Loading
Loading
Loading
+37 −2
Original line number Diff line number Diff line
@@ -246,6 +246,34 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
	else
		cmd->autoneg = AUTONEG_DISABLE;

	/* Publish LP advertised speeds and FC */
	if (bp->link_vars.link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
		u32 status = bp->link_vars.link_status;

		cmd->lp_advertising |= ADVERTISED_Autoneg;
		if (status & LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE)
			cmd->lp_advertising |= ADVERTISED_Pause;
		if (status & LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE)
			cmd->lp_advertising |= ADVERTISED_Asym_Pause;

		if (status & LINK_STATUS_LINK_PARTNER_10THD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_10baseT_Half;
		if (status & LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_10baseT_Full;
		if (status & LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_100baseT_Half;
		if (status & LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_100baseT_Full;
		if (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_1000baseT_Half;
		if (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_1000baseT_Full;
		if (status & LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_2500baseX_Full;
		if (status & LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE)
			cmd->lp_advertising |= ADVERTISED_10000baseT_Full;
	}

	cmd->maxtxpkt = 0;
	cmd->maxrxpkt = 0;

@@ -1415,12 +1443,19 @@ static void bnx2x_get_pauseparam(struct net_device *dev,
{
	struct bnx2x *bp = netdev_priv(dev);
	int cfg_idx = bnx2x_get_link_cfg_idx(bp);
	int cfg_reg;

	epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] ==
			   BNX2X_FLOW_CTRL_AUTO);

	epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) ==
	if (!epause->autoneg)
		cfg_reg = bp->link_vars.flow_ctrl;
	else
		cfg_reg = bp->link_params.req_fc_auto_adv;

	epause->rx_pause = ((cfg_reg & BNX2X_FLOW_CTRL_RX) ==
			    BNX2X_FLOW_CTRL_RX);
	epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) ==
	epause->tx_pause = ((cfg_reg & BNX2X_FLOW_CTRL_TX) ==
			    BNX2X_FLOW_CTRL_TX);

	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+229 −75
Original line number Diff line number Diff line
@@ -3638,30 +3638,17 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
		vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
}

static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
static void bnx2x_ext_phy_update_adv_fc(struct bnx2x_phy *phy,
					struct link_params *params,
					struct link_vars *vars)
{
	struct bnx2x *bp = params->bp;
	u16 ld_pause;		/* local */
	u16 lp_pause;		/* link partner */
	u16 pause_result;
	u8 ret = 0;
	/* read twice */

	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;

	if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
		vars->flow_ctrl = phy->req_flow_ctrl;
	else if (phy->req_line_speed != SPEED_AUTO_NEG)
		vars->flow_ctrl = params->req_fc_auto_adv;
	else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
		ret = 1;
	struct bnx2x *bp = params->bp;
	if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) {
			bnx2x_cl22_read(bp, phy,
					0x4, &ld_pause);
			bnx2x_cl22_read(bp, phy,
					0x5, &lp_pause);
		bnx2x_cl22_read(bp, phy, 0x4, &ld_pause);
		bnx2x_cl22_read(bp, phy, 0x5, &lp_pause);
	} else {
		bnx2x_cl45_read(bp, phy,
				MDIO_AN_DEVAD,
@@ -3674,9 +3661,27 @@ static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
			MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
	pause_result |= (lp_pause &
			 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
		DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
		   pause_result);
	DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n", pause_result);
	bnx2x_pause_resolve(vars, pause_result);

}
static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
				   struct link_params *params,
				   struct link_vars *vars)
{
	u8 ret = 0;
	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
	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_ext_phy_update_adv_fc(phy, params, vars);
		/* But set the flow-control result as the requested one */
		vars->flow_ctrl = phy->req_flow_ctrl;
	} else if (phy->req_line_speed != SPEED_AUTO_NEG)
		vars->flow_ctrl = params->req_fc_auto_adv;
	else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
		ret = 1;
		bnx2x_ext_phy_update_adv_fc(phy, params, vars);
	}
	return ret;
}
@@ -5219,29 +5224,15 @@ static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
	return 0;
}

static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
static void bnx2x_update_adv_fc(struct bnx2x_phy *phy,
				struct link_params *params,
				struct link_vars *vars,
				u32 gp_status)
{
	struct bnx2x *bp = params->bp;
	u16 ld_pause;   /* local driver */
	u16 lp_pause;   /* link partner */
	u16 pause_result;

	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;

	/* resolve from gp_status in case of AN complete and not sgmii */
	if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
		vars->flow_ctrl = phy->req_flow_ctrl;
	else if (phy->req_line_speed != SPEED_AUTO_NEG)
		vars->flow_ctrl = params->req_fc_auto_adv;
	else if ((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;
		}
	struct bnx2x *bp = params->bp;
	if ((gp_status &
	     (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE |
	      MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) ==
@@ -5257,13 +5248,10 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
				  MDIO_CL73_IEEEB1_AN_LP_ADV1,
				  &lp_pause);
		pause_result = (ld_pause &
					MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK)
					>> 8;
				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);
				 MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK) >> 10;
		DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n", pause_result);
	} else {
		CL22_RD_OVER_CL45(bp, phy,
				  MDIO_REG_BANK_COMBO_IEEE0,
@@ -5277,10 +5265,36 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
				MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
		pause_result |= (lp_pause &
				 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
			DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n",
				 pause_result);
		DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n", pause_result);
	}
	bnx2x_pause_resolve(vars, pause_result);

}

static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy,
				    struct link_params *params,
				    struct link_vars *vars,
				    u32 gp_status)
{
	struct bnx2x *bp = params->bp;
	vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;

	/* 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;
	} else if (phy->req_line_speed != SPEED_AUTO_NEG)
		vars->flow_ctrl = params->req_fc_auto_adv;
	else if ((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);
}
@@ -5499,6 +5513,33 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
		}
	}

	/* Read LP advertised speeds*/
	if (SINGLE_MEDIA_DIRECT(params) &&
	    (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE)) {
		u16 val;

		CL22_RD_OVER_CL45(bp, phy, MDIO_REG_BANK_CL73_IEEEB1,
				  MDIO_CL73_IEEEB1_AN_LP_ADV2, &val);

		if (val & MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX)
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
		if (val & (MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 |
			   MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;

		CL22_RD_OVER_CL45(bp, phy, MDIO_REG_BANK_OVER_1G,
				  MDIO_OVER_1G_LP_UP1, &val);

		if (val & MDIO_OVER_1G_UP1_2_5G)
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE;
		if (val & (MDIO_OVER_1G_UP1_10G | MDIO_OVER_1G_UP1_10GH))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
	}

	DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x link_status 0x%x\n",
		   vars->duplex, vars->flow_ctrl, vars->link_status);
	return rc;
@@ -5556,6 +5597,34 @@ static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy,
		}
	}

	if ((vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) &&
	    SINGLE_MEDIA_DIRECT(params)) {
		u16 val;

		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
				MDIO_AN_REG_LP_AUTO_NEG2, &val);

		if (val & MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX)
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
		if (val & (MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 |
			   MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;

		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
				MDIO_WC_REG_DIGITAL3_LP_UP1, &val);

		if (val & MDIO_OVER_1G_UP1_2_5G)
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE;
		if (val & (MDIO_OVER_1G_UP1_10G | MDIO_OVER_1G_UP1_10GH))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;

	}


	if (lane < 2) {
		bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD,
				MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed);
@@ -6421,7 +6490,9 @@ static int bnx2x_update_link_down(struct link_params *params,
			       LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
			       LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
			       LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
			       LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
			       LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK |
			       LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE |
			       LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE);
	vars->line_speed = 0;
	bnx2x_update_mng(params, vars->link_status);

@@ -7370,6 +7441,19 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
		bnx2x_8073_resolve_fc(phy, params, vars);
		vars->duplex = DUPLEX_FULL;
	}

	if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
				MDIO_AN_REG_LP_AUTO_NEG2, &val1);

		if (val1 & (1<<5))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
		if (val1 & (1<<7))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
	}

	return link_up;
}

@@ -9951,6 +10035,42 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
		DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n",
			   vars->line_speed);
		bnx2x_ext_phy_resolve_fc(phy, params, vars);

		/* Read LP advertised speeds */
		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
				MDIO_AN_REG_CL37_FC_LP, &val);
		if (val & (1<<5))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10THD_CAPABLE;
		if (val & (1<<6))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE;
		if (val & (1<<7))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE;
		if (val & (1<<8))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE;
		if (val & (1<<9))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_100T4_CAPABLE;

		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
				MDIO_AN_REG_1000T_STATUS, &val);

		if (val & (1<<10))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE;
		if (val & (1<<11))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;

		bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
				MDIO_AN_REG_MASTER_STATUS, &val);

		if (val & (1<<11))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
	}

	return link_up;
@@ -10574,6 +10694,35 @@ static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy,
		}

		bnx2x_ext_phy_resolve_fc(phy, params, vars);

		if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
			/* report LP advertised speeds */
			bnx2x_cl22_read(bp, phy, 0x5, &val);

			if (val & (1<<5))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_10THD_CAPABLE;
			if (val & (1<<6))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE;
			if (val & (1<<7))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE;
			if (val & (1<<8))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE;
			if (val & (1<<9))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_100T4_CAPABLE;

			bnx2x_cl22_read(bp, phy, 0xa, &val);
			if (val & (1<<10))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE;
			if (val & (1<<11))
				vars->link_status |=
				  LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE;
		}
	}
	return link_up;
}
@@ -10702,6 +10851,11 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
			   val2, (val2 & (1<<14)));
		bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
		bnx2x_ext_phy_resolve_fc(phy, params, vars);

		/* read LP advertised speeds */
		if (val2 & (1<<11))
			vars->link_status |=
				LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
	}
	return link_up;
}
+6 −2
Original line number Diff line number Diff line
@@ -6406,6 +6406,7 @@
#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_CL73_IEEEB1_AN_LP_ADV2			0x04

#define MDIO_REG_BANK_RX0				0x80b0
#define MDIO_RX0_RX_STATUS				0x10
@@ -6800,6 +6801,7 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_AN_REG_ADV 		0x0011
#define MDIO_AN_REG_ADV2		0x0012
#define MDIO_AN_REG_LP_AUTO_NEG		0x0013
#define MDIO_AN_REG_LP_AUTO_NEG2	0x0014
#define MDIO_AN_REG_MASTER_STATUS	0x0021
/*bcm*/
#define MDIO_AN_REG_LINK_STATUS 	0x8304
@@ -6807,6 +6809,7 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_AN_REG_CL37_AN		0xffe0
#define MDIO_AN_REG_CL37_FC_LD		0xffe4
#define		MDIO_AN_REG_CL37_FC_LP		0xffe5
#define		MDIO_AN_REG_1000T_STATUS	0xffea

#define MDIO_AN_REG_8073_2_5G		0x8329
#define MDIO_AN_REG_8073_BAM		0x8350
@@ -6971,6 +6974,7 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_WC_REG_SERDESDIGITAL_MISC1			0x8308
#define MDIO_WC_REG_SERDESDIGITAL_MISC2			0x8309
#define MDIO_WC_REG_DIGITAL3_UP1			0x8329
#define MDIO_WC_REG_DIGITAL3_LP_UP1			 0x832c
#define MDIO_WC_REG_DIGITAL4_MISC3			0x833c
#define MDIO_WC_REG_DIGITAL5_MISC6			0x8345
#define MDIO_WC_REG_DIGITAL5_MISC7			0x8349