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

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

bnx2x: 1G sfp+ module handling



Automatically lower requested link speed to 1G in case 1G SFP+
module is detected.

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 a351d497
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -187,7 +187,8 @@ static int bnx2x_get_port_type(struct bnx2x *bp)
	int port_type;
	u32 phy_idx = bnx2x_get_cur_phy_idx(bp);
	switch (bp->link_params.phy[phy_idx].media_type) {
	case ETH_PHY_SFP_FIBER:
	case ETH_PHY_SFPP_10G_FIBER:
	case ETH_PHY_SFP_1G_FIBER:
	case ETH_PHY_XFP_FIBER:
	case ETH_PHY_KR:
	case ETH_PHY_CX4:
@@ -220,6 +221,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
		(bp->port.supported[cfg_idx ^ 1] &
		 (SUPPORTED_TP | SUPPORTED_FIBRE));
	cmd->advertising = bp->port.advertising[cfg_idx];
	if (bp->link_params.phy[bnx2x_get_cur_phy_idx(bp)].media_type ==
	    ETH_PHY_SFP_1G_FIBER) {
		cmd->supported &= ~(SUPPORTED_10000baseT_Full);
		cmd->advertising &= ~(ADVERTISED_10000baseT_Full);
	}

	if ((bp->state == BNX2X_STATE_OPEN) && (bp->link_vars.link_up)) {
		if (!(bp->flags & MF_FUNC_DIS)) {
@@ -295,7 +301,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct bnx2x *bp = netdev_priv(dev);
	u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config;
	u32 speed;
	u32 speed, phy_idx;

	if (IS_MF_SD(bp))
		return 0;
@@ -550,9 +556,11 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
				   "10G half not supported\n");
				return -EINVAL;
			}

			phy_idx = bnx2x_get_cur_phy_idx(bp);
			if (!(bp->port.supported[cfg_idx]
			      & SUPPORTED_10000baseT_Full)) {
			      & SUPPORTED_10000baseT_Full) ||
			    (bp->link_params.phy[phy_idx].media_type ==
			     ETH_PHY_SFP_1G_FIBER)) {
				DP(BNX2X_MSG_ETHTOOL,
				   "10G full not supported\n");
				return -EINVAL;
+130 −72
Original line number Diff line number Diff line
@@ -4373,6 +4373,23 @@ static void bnx2x_warpcore_config_runtime(struct bnx2x_phy *phy,
	} /*params->rx_tx_asic_rst*/

}
static void bnx2x_warpcore_config_sfi(struct bnx2x_phy *phy,
				      struct link_params *params)
{
	u16 lane = bnx2x_get_warpcore_lane(phy, params);
	struct bnx2x *bp = params->bp;
	bnx2x_warpcore_clear_regs(phy, params, lane);
	if ((params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)] ==
	     SPEED_10000) &&
	    (phy->media_type != ETH_PHY_SFP_1G_FIBER)) {
		DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
		bnx2x_warpcore_set_10G_XFI(phy, params, 0);
	} else {
		DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
		bnx2x_warpcore_set_sgmii_speed(phy, params, 1, 0);
	}
}

static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
				       struct link_params *params,
				       struct link_vars *vars)
@@ -4433,19 +4450,11 @@ static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy,
			break;

		case PORT_HW_CFG_NET_SERDES_IF_SFI:

			bnx2x_warpcore_clear_regs(phy, params, lane);
			if (vars->line_speed == SPEED_10000) {
				DP(NETIF_MSG_LINK, "Setting 10G SFI\n");
				bnx2x_warpcore_set_10G_XFI(phy, params, 0);
			} else if (vars->line_speed == SPEED_1000) {
				DP(NETIF_MSG_LINK, "Setting 1G Fiber\n");
				bnx2x_warpcore_set_sgmii_speed(
						phy, params, 1, 0);
			}
			/* Issue Module detection */
			if (bnx2x_is_sfp_module_plugged(phy, params))
				bnx2x_sfp_module_detection(phy, params);

			bnx2x_warpcore_config_sfi(phy, params);
			break;

		case PORT_HW_CFG_NET_SERDES_IF_DXGXS:
@@ -6354,7 +6363,9 @@ int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
		for (phy_index = EXT_PHY1; phy_index < params->num_phys;
		      phy_index++) {
			serdes_phy_type = ((params->phy[phy_index].media_type ==
					    ETH_PHY_SFP_FIBER) ||
					    ETH_PHY_SFPP_10G_FIBER) ||
					   (params->phy[phy_index].media_type ==
					    ETH_PHY_SFP_1G_FIBER) ||
					   (params->phy[phy_index].media_type ==
					    ETH_PHY_XFP_FIBER) ||
					   (params->phy[phy_index].media_type ==
@@ -7891,7 +7902,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
{
	struct bnx2x *bp = params->bp;
	u32 sync_offset = 0, phy_idx, media_types;
	u8 val, check_limiting_mode = 0;
	u8 val[2], check_limiting_mode = 0;
	*edc_mode = EDC_MODE_LIMITING;

	phy->media_type = ETH_PHY_UNSPECIFIED;
@@ -7899,13 +7910,13 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
	if (bnx2x_read_sfp_module_eeprom(phy,
					 params,
					 SFP_EEPROM_CON_TYPE_ADDR,
					 1,
					 &val) != 0) {
					 2,
					 (u8 *)val) != 0) {
		DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
		return -EINVAL;
	}

	switch (val) {
	switch (val[0]) {
	case SFP_EEPROM_CON_TYPE_VAL_COPPER:
	{
		u8 copper_module_type;
@@ -7943,13 +7954,29 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
		break;
	}
	case SFP_EEPROM_CON_TYPE_VAL_LC:
		phy->media_type = ETH_PHY_SFP_FIBER;
		DP(NETIF_MSG_LINK, "Optic module detected\n");
		check_limiting_mode = 1;
		if ((val[1] & (SFP_EEPROM_COMP_CODE_SR_MASK |
			       SFP_EEPROM_COMP_CODE_LR_MASK |
			       SFP_EEPROM_COMP_CODE_LRM_MASK)) == 0) {
			DP(NETIF_MSG_LINK, "1G Optic module detected\n");
			phy->media_type = ETH_PHY_SFP_1G_FIBER;
			phy->req_line_speed = SPEED_1000;
		} 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);
			 val[0]);
		return -EINVAL;
	}
	sync_offset = params->shmem_base +
@@ -8479,14 +8506,34 @@ void bnx2x_handle_module_detect_int(struct link_params *params)

	/* Call the handling function in case module is detected */
	if (gpio_val == 0) {
		bnx2x_set_mdio_clk(bp, params->chip_id, params->port);
		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)
		if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) {
			bnx2x_sfp_module_detection(phy, params);
		else
			if (CHIP_IS_E3(bp)) {
				u16 rx_tx_in_reset;
				/* In case WC is out of reset, reconfigure the
				 * link speed while taking into account 1G
				 * module limitation.
				 */
				bnx2x_cl45_read(bp, phy,
						MDIO_WC_DEVAD,
						MDIO_WC_REG_DIGITAL5_MISC6,
						&rx_tx_in_reset);
				if (!rx_tx_in_reset) {
					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 {
		u32 val = REG_RD(bp, params->shmem_base +
				 offsetof(struct shmem_region, dev_info.
@@ -8938,6 +8985,63 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
		       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);
	}
}

static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
				  struct link_params *params,
				  struct link_vars *vars)
@@ -9007,56 +9111,7 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
	bnx2x_cl45_read(bp, phy,
			MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1);

	/* Set option 1G speed */
	if (phy->req_line_speed == SPEED_1000) {
		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_config_speed(phy, params);
	/* Set 2-wire transfer rate of SFP+ module EEPROM
	 * to 100Khz since some DACs(direct attached cables) do
	 * not work at 400Khz.
@@ -9183,6 +9238,9 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
			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",
@@ -11327,7 +11385,7 @@ static struct bnx2x_phy phy_8706 = {
			   SUPPORTED_FIBRE |
			   SUPPORTED_Pause |
			   SUPPORTED_Asym_Pause),
	.media_type	= ETH_PHY_SFP_FIBER,
	.media_type	= ETH_PHY_SFPP_10G_FIBER,
	.ver_addr	= 0,
	.req_flow_ctrl	= 0,
	.req_line_speed	= 0,
@@ -11666,7 +11724,7 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
					   SUPPORTED_FIBRE |
					   SUPPORTED_Pause |
					   SUPPORTED_Asym_Pause);
			phy->media_type = ETH_PHY_SFP_FIBER;
			phy->media_type = ETH_PHY_SFPP_10G_FIBER;
			break;
		case PORT_HW_CFG_NET_SERDES_IF_KR:
			phy->media_type = ETH_PHY_KR;
+9 −8
Original line number Diff line number Diff line
@@ -169,10 +169,11 @@ struct bnx2x_phy {

	u32 media_type;
#define	ETH_PHY_UNSPECIFIED	0x0
#define	ETH_PHY_SFP_FIBER   0x1
#define	ETH_PHY_SFPP_10G_FIBER	0x1
#define	ETH_PHY_XFP_FIBER		0x2
#define	ETH_PHY_DA_TWINAX		0x3
#define	ETH_PHY_BASE_T		0x4
#define	ETH_PHY_SFP_1G_FIBER	0x5
#define	ETH_PHY_KR		0xf0
#define	ETH_PHY_CX4		0xf1
#define	ETH_PHY_NOT_PRESENT	0xff