From patchwork Fri Nov 20 07:17:49 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenzhuo Lu X-Patchwork-Id: 9006 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 84AAA8E6C; Fri, 20 Nov 2015 08:18:27 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 47E0B8E80 for ; Fri, 20 Nov 2015 08:18:24 +0100 (CET) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP; 19 Nov 2015 23:18:23 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,321,1444719600"; d="scan'208";a="855322475" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by orsmga002.jf.intel.com with ESMTP; 19 Nov 2015 23:18:22 -0800 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id tAK7IKZ7032004; Fri, 20 Nov 2015 15:18:20 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id tAK7IIWn030052; Fri, 20 Nov 2015 15:18:20 +0800 Received: (from wenzhuol@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id tAK7IICO030048; Fri, 20 Nov 2015 15:18:18 +0800 From: Wenzhuo Lu To: dev@dpdk.org Date: Fri, 20 Nov 2015 15:17:49 +0800 Message-Id: <1448003879-29960-9-git-send-email-wenzhuo.lu@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1448003879-29960-1-git-send-email-wenzhuo.lu@intel.com> References: <1448003879-29960-1-git-send-email-wenzhuo.lu@intel.com> Subject: [dpdk-dev] [PATCH 08/17] ixgbe/base: add KR mode support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- 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, ®_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, ®_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, ®_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, ®_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, ®); 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; }