[dpdk-dev] [PATCH 08/17] ixgbe/base: add KR mode support

Wenzhuo Lu wenzhuo.lu at intel.com
Fri Nov 20 08:17:49 CET 2015


KR auto-neg mode is what we will be using going forward. The SW
interface for this mode is different than what was used for iXFI.

While debugging, it was determined that the ucode diagnostic was
no longer needed. This code has been removed to simplify the init
flow.

A subtle semaphore error in the CS4227 reset flow was fixed.

Signed-off-by: Wenzhuo Lu <wenzhuo.lu at intel.com>
---
 drivers/net/ixgbe/base/ixgbe_phy.h  |  11 +-
 drivers/net/ixgbe/base/ixgbe_x550.c | 295 +++++++++++++++---------------------
 2 files changed, 133 insertions(+), 173 deletions(-)

diff --git a/drivers/net/ixgbe/base/ixgbe_phy.h b/drivers/net/ixgbe/base/ixgbe_phy.h
index 1f07c1e..afed7bd 100644
--- a/drivers/net/ixgbe/base/ixgbe_phy.h
+++ b/drivers/net/ixgbe/base/ixgbe_phy.h
@@ -91,18 +91,23 @@ POSSIBILITY OF SUCH DAMAGE.
 #define IXGBE_CS4227_GLOBAL_ID_LSB	0
 #define IXGBE_CS4227_SCRATCH		2
 #define IXGBE_CS4227_GLOBAL_ID_VALUE	0x03E5
-#define IXGBE_CS4227_SCRATCH_VALUE	0x5aa5
-#define IXGBE_CS4227_RETRIES		5
+#define IXGBE_CS4227_RESET_PENDING	0x1357
+#define IXGBE_CS4227_RESET_COMPLETE	0x5AA5
+#define IXGBE_CS4227_RETRIES		15
+#define IXGBE_CS4227_EFUSE_STATUS	0x0181
 #define IXGBE_CS4227_LINE_SPARE22_MSB	0x12AD	/* Reg to program speed */
 #define IXGBE_CS4227_LINE_SPARE24_LSB	0x12B0	/* Reg to program EDC */
 #define IXGBE_CS4227_HOST_SPARE22_MSB	0x1AAD	/* Reg to program speed */
 #define IXGBE_CS4227_HOST_SPARE24_LSB	0x1AB0	/* Reg to program EDC */
+#define IXGBE_CS4227_EEPROM_STATUS	0x5001
+#define IXGBE_CS4227_EEPROM_LOAD_OK	0x0001
 #define IXGBE_CS4227_SPEED_1G		0x8000
 #define IXGBE_CS4227_SPEED_10G		0
 #define IXGBE_CS4227_EDC_MODE_CX1	0x0002
 #define IXGBE_CS4227_EDC_MODE_SR	0x0004
+#define IXGBE_CS4227_EDC_MODE_DIAG	0x0008
 #define IXGBE_CS4227_RESET_HOLD		500	/* microseconds */
-#define IXGBE_CS4227_RESET_DELAY	500	/* milliseconds */
+#define IXGBE_CS4227_RESET_DELAY	450	/* milliseconds */
 #define IXGBE_CS4227_CHECK_DELAY	30	/* milliseconds */
 #define IXGBE_PE			0xE0	/* Port expander address */
 #define IXGBE_PE_OUTPUT			1	/* Output register offset */
diff --git a/drivers/net/ixgbe/base/ixgbe_x550.c b/drivers/net/ixgbe/base/ixgbe_x550.c
index f6139df..d6630f9 100644
--- a/drivers/net/ixgbe/base/ixgbe_x550.c
+++ b/drivers/net/ixgbe/base/ixgbe_x550.c
@@ -114,132 +114,6 @@ STATIC s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value)
 }
 
 /**
- * ixgbe_get_cs4227_status - Return CS4227 status
- * @hw: pointer to hardware structure
- *
- * Performs a diagnostic on the CS4227 chip. Returns an error if it is
- * not operating correctly.
- * This function assumes that the caller has acquired the proper semaphore.
- **/
-STATIC s32 ixgbe_get_cs4227_status(struct ixgbe_hw *hw)
-{
-	s32 status;
-	u16 value = 0;
-	u16 reg_slice, reg_val;
-	u8 retry;
-
-	/* Check register reads. */
-	for (retry = 0; retry < IXGBE_CS4227_RETRIES; ++retry) {
-		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_GLOBAL_ID_LSB,
-					   &value);
-		if (status != IXGBE_SUCCESS)
-			return status;
-		if (value == IXGBE_CS4227_GLOBAL_ID_VALUE)
-			break;
-		msec_delay(IXGBE_CS4227_CHECK_DELAY);
-	}
-	if (value != IXGBE_CS4227_GLOBAL_ID_VALUE)
-		return IXGBE_ERR_PHY;
-
-	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
-	if (status != IXGBE_SUCCESS)
-		return status;
-
-	/* If this is the first time after power-on, check the ucode.
-	 * Otherwise, this will disrupt link on all ports. Because we
-	 * can only do this the first time, we must check all ports,
-	 * not just our own.
-	 * While we are at it, set the LINE side to 10G SR, which is
-	 * what it needs to be regardless of the actual link.
-	 */
-	if (value != IXGBE_CS4227_SCRATCH_VALUE) {
-		reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB;
-		reg_val = IXGBE_CS4227_SPEED_10G;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB;
-		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB;
-		reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + (1 << 12);
-		reg_val = IXGBE_CS4227_SPEED_10G;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12);
-		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12);
-		reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
-		status = ixgbe_write_cs4227(hw, reg_slice, reg_val);
-		if (status != IXGBE_SUCCESS)
-			return status;
-
-		msec_delay(10);
-	}
-
-	/* Verify that the ucode is operational on all ports. */
-	reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB;
-	reg_val = 0xFFFF;
-	status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	if (reg_val != 0)
-		return IXGBE_ERR_PHY;
-
-	reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB;
-	reg_val = 0xFFFF;
-	status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	if (reg_val != 0)
-		return IXGBE_ERR_PHY;
-
-	reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12);
-	reg_val = 0xFFFF;
-	status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	if (reg_val != 0)
-		return IXGBE_ERR_PHY;
-
-	reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12);
-	reg_val = 0xFFFF;
-	status = ixgbe_read_cs4227(hw, reg_slice, &reg_val);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	if (reg_val != 0)
-		return IXGBE_ERR_PHY;
-
-	/* Set scratch indicating that the diagnostic was successful. */
-	status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
-				    IXGBE_CS4227_SCRATCH_VALUE);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
-	if (status != IXGBE_SUCCESS)
-		return status;
-	if (value != IXGBE_CS4227_SCRATCH_VALUE)
-		return IXGBE_ERR_PHY;
-
-	return IXGBE_SUCCESS;
-}
-
-/**
  * ixgbe_read_pe - Read register from port expander
  * @hw: pointer to hardware structure
  * @reg: register number to read
@@ -281,13 +155,17 @@ STATIC s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value)
  * ixgbe_reset_cs4227 - Reset CS4227 using port expander
  * @hw: pointer to hardware structure
  *
+ * This function assumes that the caller has acquired the proper semaphore.
  * Returns error code
  **/
 STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
 {
 	s32 status;
+	u32 retry;
+	u16 value;
 	u8 reg;
 
+	/* Trigger hard reset. */
 	status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, &reg);
 	if (status != IXGBE_SUCCESS)
 		return status;
@@ -322,7 +200,29 @@ STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
 	if (status != IXGBE_SUCCESS)
 		return status;
 
+	/* Wait for the reset to complete. */
 	msec_delay(IXGBE_CS4227_RESET_DELAY);
+	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
+		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EFUSE_STATUS,
+					   &value);
+		if (status == IXGBE_SUCCESS &&
+		    value == IXGBE_CS4227_EEPROM_LOAD_OK)
+			break;
+		msec_delay(IXGBE_CS4227_CHECK_DELAY);
+	}
+	if (retry == IXGBE_CS4227_RETRIES) {
+		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+			"CS4227 reset did not complete.");
+		return IXGBE_ERR_PHY;
+	}
+
+	status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value);
+	if (status != IXGBE_SUCCESS ||
+	    !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) {
+		ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+			"CS4227 EEPROM did not load successfully.");
+		return IXGBE_ERR_PHY;
+	}
 
 	return IXGBE_SUCCESS;
 }
@@ -333,29 +233,75 @@ STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
  **/
 STATIC void ixgbe_check_cs4227(struct ixgbe_hw *hw)
 {
+	s32 status = IXGBE_SUCCESS;
 	u32 swfw_mask = hw->phy.phy_semaphore_mask;
-	s32 status;
+	u16 value = 0;
 	u8 retry;
 
 	for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) {
 		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
 		if (status != IXGBE_SUCCESS) {
 			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
-				      "semaphore failed with %d\n", status);
-			return;
+				"semaphore failed with %d", status);
+			msec_delay(IXGBE_CS4227_CHECK_DELAY);
+			continue;
 		}
-		status = ixgbe_get_cs4227_status(hw);
-		if (status == IXGBE_SUCCESS) {
-			hw->mac.ops.release_swfw_sync(hw, swfw_mask);
-			msec_delay(hw->eeprom.semaphore_delay);
+
+		/* Get status of reset flow. */
+		status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value);
+
+		if (status == IXGBE_SUCCESS &&
+		    value == IXGBE_CS4227_RESET_COMPLETE)
+			goto out;
+
+		if (status != IXGBE_SUCCESS ||
+		    value != IXGBE_CS4227_RESET_PENDING)
+			break;
+
+		/* Reset is pending. Wait and check again. */
+		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+		msec_delay(IXGBE_CS4227_CHECK_DELAY);
+	}
+
+	/* If still pending, assume other instance failed. */
+	if (retry == IXGBE_CS4227_RETRIES) {
+		status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
+		if (status != IXGBE_SUCCESS) {
+			ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+				      "semaphore failed with %d", status);
 			return;
 		}
-		ixgbe_reset_cs4227(hw);
-		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
-		msec_delay(hw->eeprom.semaphore_delay);
 	}
-	ERROR_REPORT2(IXGBE_ERROR_CAUTION,
-		      "Unable to initialize CS4227, err=%d\n", status);
+
+	/* Reset the CS4227. */
+	status = ixgbe_reset_cs4227(hw);
+	if (status != IXGBE_SUCCESS) {
+		ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE,
+			"CS4227 reset failed: %d", status);
+		goto out;
+	}
+
+	/* Reset takes so long, temporarily release semaphore in case the
+	 * other driver instance is waiting for the reset indication.
+	 */
+	ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
+			   IXGBE_CS4227_RESET_PENDING);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+	msec_delay(10);
+	status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
+	if (status != IXGBE_SUCCESS) {
+		ERROR_REPORT2(IXGBE_ERROR_CAUTION,
+			"semaphore failed with %d", status);
+		return;
+	}
+
+	/* Record completion for next time. */
+	status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH,
+		IXGBE_CS4227_RESET_COMPLETE);
+
+out:
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
+	msec_delay(hw->eeprom.semaphore_delay);
 }
 
 /**
@@ -1506,14 +1452,6 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
 		 * to determine internal PHY mode.
 		 */
 		phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
-
-		/* If internal PHY mode is KR, then initialize KR link */
-		if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) {
-			speed = IXGBE_LINK_SPEED_10GB_FULL |
-				IXGBE_LINK_SPEED_1GB_FULL;
-			ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
-		}
-
 		phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em;
 	}
 
@@ -1772,36 +1710,53 @@ s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
 	if (ret_val != IXGBE_SUCCESS)
 		return ret_val;
 
-	/* Configure CS4227 LINE side to 10G SR. */
-	reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + (hw->bus.lan_id << 12);
-	reg_val = IXGBE_CS4227_SPEED_10G;
-	ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
-		reg_val);
+	if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
+		/* Configure CS4227 LINE side to 10G SR. */
+		reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB +
+			    (hw->bus.lan_id << 12);
+		reg_val = IXGBE_CS4227_SPEED_10G;
+		ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+						   reg_val);
 
-	reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (hw->bus.lan_id << 12);
-	reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
-	ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
-		reg_val);
+		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB +
+			    (hw->bus.lan_id << 12);
+		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+		ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+						   reg_val);
 
-	/* Configure CS4227 for HOST connection rate then type. */
-	reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB + (hw->bus.lan_id << 12);
-	reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ?
+		/* Configure CS4227 for HOST connection rate then type. */
+		reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB +
+			    (hw->bus.lan_id << 12);
+		reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ?
 		IXGBE_CS4227_SPEED_10G : IXGBE_CS4227_SPEED_1G;
-	ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
-					   reg_val);
+		ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+						   reg_val);
 
-	reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (hw->bus.lan_id << 12);
-	if (setup_linear)
-		reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
-	else
-		reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
-	ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
-					   reg_val);
+		reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB +
+			    (hw->bus.lan_id << 12);
+		if (setup_linear)
+			reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+		else
+			reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+		ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+						   reg_val);
 
-	/* If internal link mode is XFI, then setup XFI internal link. */
-	if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))
+		/* Setup XFI internal link. */
 		ret_val = ixgbe_setup_ixfi_x550em(hw, &speed);
-
+	} else {
+		/* Configure internal PHY for KR/KX. */
+		ixgbe_setup_kr_speed_x550em(hw, speed);
+
+		/* Configure CS4227 LINE side to proper mode. */
+		reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB +
+			    (hw->bus.lan_id << 12);
+		if (setup_linear)
+			reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
+		else
+			reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
+		ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
+						   reg_val);
+	}
 	return ret_val;
 }
 
-- 
1.9.3



More information about the dev mailing list