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

Commit 55098c5c authored by Yaniv Rosner's avatar Yaniv Rosner Committed by David S. Miller
Browse files

bnx2x: Add remote-fault link detection



Restore remote-faule detection, which periodically checks for
remote-fault on the MAC layer. In case physical link appear to be
up but fault is set, it will provide a link down indication, and
when the fault is cleared, it will indicate link up again.

Signed-off-by: default avatarYaniv Rosner <yaniv.rosner@broadcom.com>
Signed-off-by: default avatarYuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 30a5de77
Loading
Loading
Loading
Loading
+50 −19
Original line number Diff line number Diff line
@@ -6439,7 +6439,6 @@ static int bnx2x_link_initialize(struct link_params *params,
			NIG_STATUS_XGXS0_LINK_STATUS |
			NIG_STATUS_SERDES0_LINK_STATUS |
			NIG_MASK_MI_INT));
	bnx2x_update_mng(params, vars->link_status);
	return rc;
}

@@ -6524,7 +6523,7 @@ static int bnx2x_update_link_up(struct link_params *params,
				u8 link_10g)
{
	struct bnx2x *bp = params->bp;
	u8 port = params->port;
	u8 phy_idx, port = params->port;
	int rc = 0;

	vars->link_status |= (LINK_STATUS_LINK_UP |
@@ -6588,6 +6587,14 @@ static int bnx2x_update_link_up(struct link_params *params,

	/* update shared memory */
	bnx2x_update_mng(params, vars->link_status);

	/* Check remote fault */
	for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
		if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
			bnx2x_check_half_open_conn(params, vars, 0);
			break;
		}
	}
	msleep(20);
	return rc;
}
@@ -11027,7 +11034,8 @@ static struct bnx2x_phy phy_warpcore = {
	.type		= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
	.addr		= 0xff,
	.def_md_devad	= 0,
	.flags		= FLAGS_HW_LOCK_REQUIRED,
	.flags		= (FLAGS_HW_LOCK_REQUIRED |
			   FLAGS_TX_ERROR_CHECK),
	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.mdio_ctrl	= 0,
@@ -11184,7 +11192,8 @@ static struct bnx2x_phy phy_8726 = {
	.addr		= 0xff,
	.def_md_devad	= 0,
	.flags		= (FLAGS_HW_LOCK_REQUIRED |
			   FLAGS_INIT_XGXS_FIRST),
			   FLAGS_INIT_XGXS_FIRST |
			   FLAGS_TX_ERROR_CHECK),
	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.mdio_ctrl	= 0,
@@ -11215,7 +11224,8 @@ static struct bnx2x_phy phy_8727 = {
	.type		= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
	.addr		= 0xff,
	.def_md_devad	= 0,
	.flags		= FLAGS_FAN_FAILURE_DET_REQ,
	.flags		= (FLAGS_FAN_FAILURE_DET_REQ |
			   FLAGS_TX_ERROR_CHECK),
	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.mdio_ctrl	= 0,
@@ -11280,8 +11290,9 @@ static struct bnx2x_phy phy_84823 = {
	.type		= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
	.addr		= 0xff,
	.def_md_devad	= 0,
	.flags		= FLAGS_FAN_FAILURE_DET_REQ |
			  FLAGS_REARM_LATCH_SIGNAL,
	.flags		= (FLAGS_FAN_FAILURE_DET_REQ |
			   FLAGS_REARM_LATCH_SIGNAL |
			   FLAGS_TX_ERROR_CHECK),
	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.mdio_ctrl	= 0,
@@ -11316,8 +11327,9 @@ static struct bnx2x_phy phy_84833 = {
	.type		= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
	.addr		= 0xff,
	.def_md_devad	= 0,
	.flags		= FLAGS_FAN_FAILURE_DET_REQ |
			    FLAGS_REARM_LATCH_SIGNAL,
	.flags		= (FLAGS_FAN_FAILURE_DET_REQ |
			   FLAGS_REARM_LATCH_SIGNAL |
			   FLAGS_TX_ERROR_CHECK),
	.rx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.tx_preemphasis	= {0xffff, 0xffff, 0xffff, 0xffff},
	.mdio_ctrl	= 0,
@@ -11862,6 +11874,10 @@ int bnx2x_phy_probe(struct link_params *params)
		if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
			break;

		if (params->feature_config_flags &
		    FEATURE_CONFIG_DISABLE_REMOTE_FAULT_DET)
			phy->flags &= ~FLAGS_TX_ERROR_CHECK;

		sync_offset = params->shmem_base +
			offsetof(struct shmem_region,
			dev_info.port_hw_config[params->port].media_type);
@@ -12085,6 +12101,7 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
		bnx2x_link_int_enable(params);
		break;
	}
	bnx2x_update_mng(params, vars->link_status);
	return 0;
}

@@ -12702,7 +12719,8 @@ static void bnx2x_check_over_curr(struct link_params *params,
}

static void bnx2x_analyze_link_error(struct link_params *params,
				     struct link_vars *vars, u32 lss_status)
				     struct link_vars *vars, u32 lss_status,
				     u8 notify)
{
	struct bnx2x *bp = params->bp;
	/* Compare new value with previous value */
@@ -12725,6 +12743,9 @@ static void bnx2x_analyze_link_error(struct link_params *params,
		vars->link_status &= ~LINK_STATUS_LINK_UP;
		vars->link_up = 0;
		vars->phy_flags |= PHY_HALF_OPEN_CONN_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
@@ -12736,7 +12757,11 @@ static void bnx2x_analyze_link_error(struct link_params *params,
		vars->link_up = 1;
		vars->phy_flags &= ~PHY_HALF_OPEN_CONN_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);

@@ -12745,6 +12770,7 @@ static void bnx2x_analyze_link_error(struct link_params *params,

	/* C. Trigger General Attention */
	vars->periodic_flags |= PERIODIC_FLAGS_LINK_EVENT;
	if (notify)
		bnx2x_notify_link_changed(bp);
}

@@ -12757,15 +12783,17 @@ static void bnx2x_analyze_link_error(struct link_params *params,
*	a fault, for example, due to break in the TX side of fiber.
*
******************************************************************************/
static void bnx2x_check_half_open_conn(struct link_params *params,
				       struct link_vars *vars)
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)
		return;
	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) &
@@ -12786,7 +12814,7 @@ static void bnx2x_check_half_open_conn(struct link_params *params,
		if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS))
			lss_status = 1;

		bnx2x_analyze_link_error(params, vars, lss_status);
		bnx2x_analyze_link_error(params, vars, lss_status, notify);
	} else if (REG_RD(bp, MISC_REG_RESET_REG_2) &
		   (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) {
		/* Check E1X / E2 BMAC */
@@ -12803,18 +12831,21 @@ static void bnx2x_check_half_open_conn(struct link_params *params,
		REG_RD_DMAE(bp, mac_base + lss_status_reg, wb_data, 2);
		lss_status = (wb_data[0] > 0);

		bnx2x_analyze_link_error(params, vars, lss_status);
		bnx2x_analyze_link_error(params, vars, lss_status, notify);
	}
	return 0;
}

void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
{
	struct bnx2x *bp = params->bp;
	u16 phy_idx;
	struct bnx2x *bp = params->bp;
	for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
		if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) {
			bnx2x_set_aer_mmd(params, &params->phy[phy_idx]);
			bnx2x_check_half_open_conn(params, vars);
			if (bnx2x_check_half_open_conn(params, vars, 1) !=
			    0)
				DP(NETIF_MSG_LINK, "Fault detection failed\n");
			break;
		}
	}
+3 −0
Original line number Diff line number Diff line
@@ -256,6 +256,7 @@ struct link_params {
#define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY	(1<<3)
#define FEATURE_CONFIG_AUTOGREEEN_ENABLED			(1<<9)
#define FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED		(1<<10)
#define FEATURE_CONFIG_DISABLE_REMOTE_FAULT_DET		(1<<11)
	/* Will be populated during common init */
	struct bnx2x_phy phy[MAX_PHYS];

@@ -495,4 +496,6 @@ int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,

void bnx2x_period_func(struct link_params *params, struct link_vars *vars);

int bnx2x_check_half_open_conn(struct link_params *params,
			       struct link_vars *vars, u8 notify);
#endif /* BNX2X_LINK_H */