|
@@ -1,7 +1,7 @@
|
|
|
/*******************************************************************************
|
|
|
*
|
|
|
* Intel 10 Gigabit PCI Express Linux driver
|
|
|
- * Copyright(c) 1999 - 2014 Intel Corporation.
|
|
|
+ * Copyright(c) 1999 - 2015 Intel Corporation.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -26,6 +26,22 @@
|
|
|
#include "ixgbe_common.h"
|
|
|
#include "ixgbe_phy.h"
|
|
|
|
|
|
+/** ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ **/
|
|
|
+static void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
|
|
|
+
|
|
|
+ if (hw->bus.lan_id) {
|
|
|
+ esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
|
|
|
+ esdp |= IXGBE_ESDP_SDP1_DIR;
|
|
|
+ }
|
|
|
+ esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
|
|
|
+ IXGBE_WRITE_FLUSH(hw);
|
|
|
+}
|
|
|
+
|
|
|
/** ixgbe_identify_phy_x550em - Get PHY type based on device id
|
|
|
* @hw: pointer to hardware structure
|
|
|
*
|
|
@@ -33,18 +49,11 @@
|
|
|
*/
|
|
|
static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
|
|
|
{
|
|
|
- u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
|
|
|
-
|
|
|
switch (hw->device_id) {
|
|
|
case IXGBE_DEV_ID_X550EM_X_SFP:
|
|
|
/* set up for CS4227 usage */
|
|
|
hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
|
|
|
- if (hw->bus.lan_id) {
|
|
|
- esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
|
|
|
- esdp |= IXGBE_ESDP_SDP1_DIR;
|
|
|
- }
|
|
|
- esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
|
|
|
+ ixgbe_setup_mux_ctl(hw);
|
|
|
|
|
|
return ixgbe_identify_module_generic(hw);
|
|
|
case IXGBE_DEV_ID_X550EM_X_KX4:
|
|
@@ -90,7 +99,7 @@ static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
|
|
|
eeprom->semaphore_delay = 10;
|
|
|
eeprom->type = ixgbe_flash;
|
|
|
|
|
|
- eec = IXGBE_READ_REG(hw, IXGBE_EEC);
|
|
|
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
|
|
|
eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
|
|
|
IXGBE_EEC_SIZE_SHIFT);
|
|
|
eeprom->word_size = 1 << (eeprom_size +
|
|
@@ -704,111 +713,6 @@ static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
|
|
|
- * @hw: pointer to hardware structure
|
|
|
- **/
|
|
|
-static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
|
|
|
-{
|
|
|
- struct ixgbe_mac_info *mac = &hw->mac;
|
|
|
-
|
|
|
- /* CS4227 does not support autoneg, so disable the laser control
|
|
|
- * functions for SFP+ fiber
|
|
|
- */
|
|
|
- if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
|
|
|
- mac->ops.disable_tx_laser = NULL;
|
|
|
- mac->ops.enable_tx_laser = NULL;
|
|
|
- mac->ops.flap_tx_laser = NULL;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/** ixgbe_setup_sfp_modules_X550em - Setup SFP module
|
|
|
- * @hw: pointer to hardware structure
|
|
|
- */
|
|
|
-static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
|
|
|
-{
|
|
|
- bool setup_linear;
|
|
|
- u16 reg_slice, edc_mode;
|
|
|
- s32 ret_val;
|
|
|
-
|
|
|
- switch (hw->phy.sfp_type) {
|
|
|
- case ixgbe_sfp_type_unknown:
|
|
|
- return 0;
|
|
|
- case ixgbe_sfp_type_not_present:
|
|
|
- return IXGBE_ERR_SFP_NOT_PRESENT;
|
|
|
- case ixgbe_sfp_type_da_cu_core0:
|
|
|
- case ixgbe_sfp_type_da_cu_core1:
|
|
|
- setup_linear = true;
|
|
|
- break;
|
|
|
- case ixgbe_sfp_type_srlr_core0:
|
|
|
- case ixgbe_sfp_type_srlr_core1:
|
|
|
- case ixgbe_sfp_type_da_act_lmt_core0:
|
|
|
- case ixgbe_sfp_type_da_act_lmt_core1:
|
|
|
- case ixgbe_sfp_type_1g_sx_core0:
|
|
|
- case ixgbe_sfp_type_1g_sx_core1:
|
|
|
- setup_linear = false;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
|
|
|
- }
|
|
|
-
|
|
|
- ixgbe_init_mac_link_ops_X550em(hw);
|
|
|
- hw->phy.ops.reset = NULL;
|
|
|
-
|
|
|
- /* The CS4227 slice address is the base address + the port-pair reg
|
|
|
- * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
|
|
|
- */
|
|
|
- reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
|
|
|
-
|
|
|
- if (setup_linear)
|
|
|
- edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
|
|
|
- else
|
|
|
- edc_mode = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
|
|
|
-
|
|
|
- /* Configure CS4227 for connection type. */
|
|
|
- ret_val = hw->phy.ops.write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
|
|
|
- edc_mode);
|
|
|
-
|
|
|
- if (ret_val)
|
|
|
- ret_val = hw->phy.ops.write_i2c_combined(hw, 0x80, reg_slice,
|
|
|
- edc_mode);
|
|
|
-
|
|
|
- return ret_val;
|
|
|
-}
|
|
|
-
|
|
|
-/** ixgbe_get_link_capabilities_x550em - Determines link capabilities
|
|
|
- * @hw: pointer to hardware structure
|
|
|
- * @speed: pointer to link speed
|
|
|
- * @autoneg: true when autoneg or autotry is enabled
|
|
|
- **/
|
|
|
-static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
|
|
|
- ixgbe_link_speed *speed,
|
|
|
- bool *autoneg)
|
|
|
-{
|
|
|
- /* SFP */
|
|
|
- if (hw->phy.media_type == ixgbe_media_type_fiber) {
|
|
|
- /* CS4227 SFP must not enable auto-negotiation */
|
|
|
- *autoneg = false;
|
|
|
-
|
|
|
- if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
|
|
|
- hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
|
|
|
- *speed = IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* Link capabilities are based on SFP */
|
|
|
- if (hw->phy.multispeed_fiber)
|
|
|
- *speed = IXGBE_LINK_SPEED_10GB_FULL |
|
|
|
- IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
- else
|
|
|
- *speed = IXGBE_LINK_SPEED_10GB_FULL;
|
|
|
- } else {
|
|
|
- *speed = IXGBE_LINK_SPEED_10GB_FULL |
|
|
|
- IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
- *autoneg = true;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/** ixgbe_write_iosf_sb_reg_x550 - Writes a value to specified register of the
|
|
|
* IOSF device
|
|
|
*
|
|
@@ -891,7 +795,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
|
|
|
}
|
|
|
|
|
|
status = ixgbe_write_iosf_sb_reg_x550(hw,
|
|
|
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
|
|
|
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
|
|
|
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
|
|
|
if (status)
|
|
|
return status;
|
|
@@ -973,6 +877,417 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @speed: new link speed
|
|
|
+ * @autoneg_wait_to_complete: true when waiting for completion is needed
|
|
|
+ *
|
|
|
+ * Setup internal/external PHY link speed based on link speed, then set
|
|
|
+ * external PHY auto advertised link speed.
|
|
|
+ *
|
|
|
+ * Returns error status for any failure
|
|
|
+ **/
|
|
|
+static s32 ixgbe_setup_mac_link_t_X550em(struct ixgbe_hw *hw,
|
|
|
+ ixgbe_link_speed speed,
|
|
|
+ bool autoneg_wait)
|
|
|
+{
|
|
|
+ s32 status;
|
|
|
+ ixgbe_link_speed force_speed;
|
|
|
+
|
|
|
+ /* Setup internal/external PHY link speed to iXFI (10G), unless
|
|
|
+ * only 1G is auto advertised then setup KX link.
|
|
|
+ */
|
|
|
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
|
|
|
+ force_speed = IXGBE_LINK_SPEED_10GB_FULL;
|
|
|
+ else
|
|
|
+ force_speed = IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+
|
|
|
+ /* 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)) {
|
|
|
+ status = ixgbe_setup_ixfi_x550em(hw, &force_speed);
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait);
|
|
|
+}
|
|
|
+
|
|
|
+/** ixgbe_check_link_t_X550em - Determine link and speed status
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @speed: pointer to link speed
|
|
|
+ * @link_up: true when link is up
|
|
|
+ * @link_up_wait_to_complete: bool used to wait for link up or not
|
|
|
+ *
|
|
|
+ * Check that both the MAC and X557 external PHY have link.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw,
|
|
|
+ ixgbe_link_speed *speed,
|
|
|
+ bool *link_up,
|
|
|
+ bool link_up_wait_to_complete)
|
|
|
+{
|
|
|
+ u32 status;
|
|
|
+ u16 autoneg_status;
|
|
|
+
|
|
|
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
|
|
|
+ return IXGBE_ERR_CONFIG;
|
|
|
+
|
|
|
+ status = ixgbe_check_mac_link_generic(hw, speed, link_up,
|
|
|
+ link_up_wait_to_complete);
|
|
|
+
|
|
|
+ /* If check link fails or MAC link is not up, then return */
|
|
|
+ if (status || !(*link_up))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* MAC link is up, so check external PHY link.
|
|
|
+ * Read this twice back to back to indicate current status.
|
|
|
+ */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &autoneg_status);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If external PHY link is not up, then indicate link not up */
|
|
|
+ if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
|
|
|
+ *link_up = false;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ **/
|
|
|
+static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ struct ixgbe_mac_info *mac = &hw->mac;
|
|
|
+
|
|
|
+ switch (mac->ops.get_media_type(hw)) {
|
|
|
+ case ixgbe_media_type_fiber:
|
|
|
+ /* CS4227 does not support autoneg, so disable the laser control
|
|
|
+ * functions for SFP+ fiber
|
|
|
+ */
|
|
|
+ mac->ops.disable_tx_laser = NULL;
|
|
|
+ mac->ops.enable_tx_laser = NULL;
|
|
|
+ mac->ops.flap_tx_laser = NULL;
|
|
|
+ break;
|
|
|
+ case ixgbe_media_type_copper:
|
|
|
+ mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
|
|
|
+ mac->ops.check_link = ixgbe_check_link_t_X550em;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** ixgbe_setup_sfp_modules_X550em - Setup SFP module
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ */
|
|
|
+static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ bool setup_linear;
|
|
|
+ u16 reg_slice, edc_mode;
|
|
|
+ s32 ret_val;
|
|
|
+
|
|
|
+ switch (hw->phy.sfp_type) {
|
|
|
+ case ixgbe_sfp_type_unknown:
|
|
|
+ return 0;
|
|
|
+ case ixgbe_sfp_type_not_present:
|
|
|
+ return IXGBE_ERR_SFP_NOT_PRESENT;
|
|
|
+ case ixgbe_sfp_type_da_cu_core0:
|
|
|
+ case ixgbe_sfp_type_da_cu_core1:
|
|
|
+ setup_linear = true;
|
|
|
+ break;
|
|
|
+ case ixgbe_sfp_type_srlr_core0:
|
|
|
+ case ixgbe_sfp_type_srlr_core1:
|
|
|
+ case ixgbe_sfp_type_da_act_lmt_core0:
|
|
|
+ case ixgbe_sfp_type_da_act_lmt_core1:
|
|
|
+ case ixgbe_sfp_type_1g_sx_core0:
|
|
|
+ case ixgbe_sfp_type_1g_sx_core1:
|
|
|
+ setup_linear = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return IXGBE_ERR_SFP_NOT_SUPPORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ ixgbe_init_mac_link_ops_X550em(hw);
|
|
|
+ hw->phy.ops.reset = NULL;
|
|
|
+
|
|
|
+ /* The CS4227 slice address is the base address + the port-pair reg
|
|
|
+ * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
|
|
|
+ */
|
|
|
+ reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
|
|
|
+
|
|
|
+ if (setup_linear)
|
|
|
+ edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
|
|
|
+ else
|
|
|
+ edc_mode = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1;
|
|
|
+
|
|
|
+ /* Configure CS4227 for connection type. */
|
|
|
+ ret_val = hw->phy.ops.write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
|
|
|
+ edc_mode);
|
|
|
+
|
|
|
+ if (ret_val)
|
|
|
+ ret_val = hw->phy.ops.write_i2c_combined(hw, 0x80, reg_slice,
|
|
|
+ edc_mode);
|
|
|
+
|
|
|
+ return ret_val;
|
|
|
+}
|
|
|
+
|
|
|
+/** ixgbe_get_link_capabilities_x550em - Determines link capabilities
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @speed: pointer to link speed
|
|
|
+ * @autoneg: true when autoneg or autotry is enabled
|
|
|
+ **/
|
|
|
+static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
|
|
|
+ ixgbe_link_speed *speed,
|
|
|
+ bool *autoneg)
|
|
|
+{
|
|
|
+ /* SFP */
|
|
|
+ if (hw->phy.media_type == ixgbe_media_type_fiber) {
|
|
|
+ /* CS4227 SFP must not enable auto-negotiation */
|
|
|
+ *autoneg = false;
|
|
|
+
|
|
|
+ if (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
|
|
|
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
|
|
|
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Link capabilities are based on SFP */
|
|
|
+ if (hw->phy.multispeed_fiber)
|
|
|
+ *speed = IXGBE_LINK_SPEED_10GB_FULL |
|
|
|
+ IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+ else
|
|
|
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
|
|
|
+ } else {
|
|
|
+ *speed = IXGBE_LINK_SPEED_10GB_FULL |
|
|
|
+ IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+ *autoneg = true;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_get_lasi_ext_t_x550em - Determime external Base T PHY interrupt cause
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @lsc: pointer to boolean flag which indicates whether external Base T
|
|
|
+ * PHY interrupt is lsc
|
|
|
+ *
|
|
|
+ * Determime if external Base T PHY interrupt cause is high temperature
|
|
|
+ * failure alarm or link status change.
|
|
|
+ *
|
|
|
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
|
|
|
+ * failure alarm, else return PHY access status.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
|
|
|
+{
|
|
|
+ u32 status;
|
|
|
+ u16 reg;
|
|
|
+
|
|
|
+ *lsc = false;
|
|
|
+
|
|
|
+ /* Vendor alarm triggered */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+
|
|
|
+ if (status || !(reg & IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Vendor Auto-Neg alarm triggered or Global alarm 1 triggered */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_FLAG,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+
|
|
|
+ if (status || !(reg & (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
|
|
|
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT)))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* High temperature failure alarm triggered */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* If high temperature failure, then return over temp error and exit */
|
|
|
+ if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
|
|
|
+ /* power down the PHY in case the PHY FW didn't already */
|
|
|
+ ixgbe_set_copper_phy_power(hw, false);
|
|
|
+ return IXGBE_ERR_OVERTEMP;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Vendor alarm 2 triggered */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_CHIP_STD_INT_FLAG,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
|
|
|
+
|
|
|
+ if (status || !(reg & IXGBE_MDIO_GLOBAL_STD_ALM2_INT))
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* link connect/disconnect event occurred */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Indicate LSC */
|
|
|
+ if (reg & IXGBE_MDIO_AUTO_NEG_VEN_LSC)
|
|
|
+ *lsc = true;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_enable_lasi_ext_t_x550em - Enable external Base T PHY interrupts
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ *
|
|
|
+ * Enable link status change and temperature failure alarm for the external
|
|
|
+ * Base T PHY
|
|
|
+ *
|
|
|
+ * Returns PHY access status
|
|
|
+ **/
|
|
|
+static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ u32 status;
|
|
|
+ u16 reg;
|
|
|
+ bool lsc;
|
|
|
+
|
|
|
+ /* Clear interrupt flags */
|
|
|
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
|
|
|
+
|
|
|
+ /* Enable link status change alarm */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, ®);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ reg |= IXGBE_MDIO_PMA_TX_VEN_LASI_INT_EN;
|
|
|
+
|
|
|
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_PMA_TX_VEN_LASI_INT_MASK,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Enables high temperature failure alarm */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN;
|
|
|
+
|
|
|
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Enable vendor Auto-Neg alarm and Global Interrupt Mask 1 alarm */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ reg |= (IXGBE_MDIO_GLOBAL_AN_VEN_ALM_INT_EN |
|
|
|
+ IXGBE_MDIO_GLOBAL_ALARM_1_INT);
|
|
|
+
|
|
|
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_VEN_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Enable chip-wide vendor alarm */
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ reg |= IXGBE_MDIO_GLOBAL_VEN_ALM_INT_EN;
|
|
|
+
|
|
|
+ status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_CHIP_STD_MASK,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ reg);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ *
|
|
|
+ * Handle external Base T PHY interrupt. If high temperature
|
|
|
+ * failure alarm then return error, else if link status change
|
|
|
+ * then setup internal/external PHY link
|
|
|
+ *
|
|
|
+ * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
|
|
|
+ * failure alarm, else return PHY access status.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ struct ixgbe_phy_info *phy = &hw->phy;
|
|
|
+ bool lsc;
|
|
|
+ u32 status;
|
|
|
+
|
|
|
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ if (lsc)
|
|
|
+ return phy->ops.setup_internal_link(hw);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ixgbe_setup_kr_speed_x550em - Configure the KR PHY for link speed.
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ * @speed: link speed
|
|
|
+ *
|
|
|
+ * Configures the integrated KR PHY.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw,
|
|
|
+ ixgbe_link_speed speed)
|
|
|
+{
|
|
|
+ s32 status;
|
|
|
+ u32 reg_val;
|
|
|
+
|
|
|
+ status = ixgbe_read_iosf_sb_reg_x550(hw,
|
|
|
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
|
|
|
+ IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
|
|
|
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ |
|
|
|
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC);
|
|
|
+ reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
|
|
|
+ IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
|
|
|
+
|
|
|
+ /* Advertise 10G support. */
|
|
|
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
|
|
|
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
|
|
|
+
|
|
|
+ /* Advertise 1G support. */
|
|
|
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
|
|
|
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
|
|
|
+
|
|
|
+ /* Restart auto-negotiation. */
|
|
|
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
|
|
|
+ status = ixgbe_write_iosf_sb_reg_x550(hw,
|
|
|
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
|
|
|
+ IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
/** ixgbe_setup_kx4_x550em - Configure the KX4 PHY.
|
|
|
* @hw: pointer to hardware structure
|
|
|
*
|
|
@@ -1018,85 +1333,82 @@ static s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
|
|
|
**/
|
|
|
static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
|
|
|
{
|
|
|
- s32 status;
|
|
|
- u32 reg_val;
|
|
|
+ return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised);
|
|
|
+}
|
|
|
|
|
|
- status = ixgbe_read_iosf_sb_reg_x550(hw,
|
|
|
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
|
|
|
- IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
|
|
|
- if (status)
|
|
|
- return status;
|
|
|
+/** ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status
|
|
|
+ * @hw: address of hardware structure
|
|
|
+ * @link_up: address of boolean to indicate link status
|
|
|
+ *
|
|
|
+ * Returns error code if unable to get link status.
|
|
|
+ **/
|
|
|
+static s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up)
|
|
|
+{
|
|
|
+ u32 ret;
|
|
|
+ u16 autoneg_status;
|
|
|
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_FEC_REQ;
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_FEC;
|
|
|
- reg_val &= ~(IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR |
|
|
|
- IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX);
|
|
|
+ *link_up = false;
|
|
|
|
|
|
- /* Advertise 10G support. */
|
|
|
- if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KR;
|
|
|
+ /* read this twice back to back to indicate current status */
|
|
|
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &autoneg_status);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- /* Advertise 1G support. */
|
|
|
- if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_CAP_KX;
|
|
|
+ ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
|
|
|
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
+ &autoneg_status);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- /* Restart auto-negotiation. */
|
|
|
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
|
|
|
- status = ixgbe_write_iosf_sb_reg_x550(hw,
|
|
|
- IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
|
|
|
- IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
|
|
|
+ *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS);
|
|
|
|
|
|
- return status;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-/** ixgbe_setup_internal_phy_x550em - Configure integrated KR PHY
|
|
|
+/** ixgbe_setup_internal_phy_t_x550em - Configure KR PHY to X557 link
|
|
|
* @hw: point to hardware structure
|
|
|
*
|
|
|
- * Configures the integrated KR PHY to talk to the external PHY. The base
|
|
|
- * driver will call this function when it gets notification via interrupt from
|
|
|
- * the external PHY. This function forces the internal PHY into iXFI mode at
|
|
|
- * the correct speed.
|
|
|
+ * Configures the link between the integrated KR PHY and the external X557 PHY
|
|
|
+ * The driver will call this function when it gets a link status change
|
|
|
+ * interrupt from the X557 PHY. This function configures the link speed
|
|
|
+ * between the PHYs to match the link speed of the BASE-T link.
|
|
|
*
|
|
|
- * A return of a non-zero value indicates an error, and the base driver should
|
|
|
- * not report link up.
|
|
|
+ * A return of a non-zero value indicates an error, and the base driver should
|
|
|
+ * not report link up.
|
|
|
**/
|
|
|
-static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
|
|
|
+static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
|
|
|
{
|
|
|
- s32 status;
|
|
|
- u16 lasi, autoneg_status, speed;
|
|
|
ixgbe_link_speed force_speed;
|
|
|
+ bool link_up;
|
|
|
+ u32 status;
|
|
|
+ u16 speed;
|
|
|
|
|
|
- /* Verify that the external link status has changed */
|
|
|
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_XENPAK_LASI_STATUS,
|
|
|
- IXGBE_MDIO_PMA_PMD_DEV_TYPE, &lasi);
|
|
|
+ if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
|
|
|
+ return IXGBE_ERR_CONFIG;
|
|
|
+
|
|
|
+ /* If link is not up, then there is no setup necessary so return */
|
|
|
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
|
|
|
if (status)
|
|
|
return status;
|
|
|
|
|
|
- /* If there was no change in link status, we can just exit */
|
|
|
- if (!(lasi & IXGBE_XENPAK_LASI_LINK_STATUS_ALARM))
|
|
|
+ if (!link_up)
|
|
|
return 0;
|
|
|
|
|
|
- /* we read this twice back to back to indicate current status */
|
|
|
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
|
|
|
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
|
|
|
IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
- &autoneg_status);
|
|
|
+ &speed);
|
|
|
if (status)
|
|
|
return status;
|
|
|
|
|
|
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
|
|
|
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
- &autoneg_status);
|
|
|
+ /* If link is not still up, then no setup is necessary so return */
|
|
|
+ status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up);
|
|
|
if (status)
|
|
|
return status;
|
|
|
|
|
|
- /* If link is not up return an error indicating treat link as down */
|
|
|
- if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS))
|
|
|
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
|
|
|
-
|
|
|
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT,
|
|
|
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
|
|
|
- &speed);
|
|
|
+ if (!link_up)
|
|
|
+ return 0;
|
|
|
|
|
|
/* clear everything but the speed and duplex bits */
|
|
|
speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
|
|
@@ -1116,6 +1428,22 @@ static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
|
|
|
return ixgbe_setup_ixfi_x550em(hw, &force_speed);
|
|
|
}
|
|
|
|
|
|
+/** ixgbe_reset_phy_t_X550em - Performs X557 PHY reset and enables LASI
|
|
|
+ * @hw: pointer to hardware structure
|
|
|
+ **/
|
|
|
+static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ s32 status;
|
|
|
+
|
|
|
+ status = ixgbe_reset_phy_generic(hw);
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ /* Configure Link Status Alarm and Temperature Threshold interrupts */
|
|
|
+ return ixgbe_enable_lasi_ext_t_x550em(hw);
|
|
|
+}
|
|
|
+
|
|
|
/** ixgbe_init_phy_ops_X550em - PHY/SFP specific init
|
|
|
* @hw: pointer to hardware structure
|
|
|
*
|
|
@@ -1126,25 +1454,32 @@ static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
|
|
|
static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
|
|
|
{
|
|
|
struct ixgbe_phy_info *phy = &hw->phy;
|
|
|
+ ixgbe_link_speed speed;
|
|
|
s32 ret_val;
|
|
|
- u32 esdp;
|
|
|
|
|
|
- if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
|
|
|
- esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
|
|
|
- phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
|
|
|
+ hw->mac.ops.set_lan_id(hw);
|
|
|
|
|
|
- if (hw->bus.lan_id) {
|
|
|
- esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
|
|
|
- esdp |= IXGBE_ESDP_SDP1_DIR;
|
|
|
+ if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) {
|
|
|
+ phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
|
|
|
+ ixgbe_setup_mux_ctl(hw);
|
|
|
+
|
|
|
+ /* Save NW management interface connected on board. This is used
|
|
|
+ * 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);
|
|
|
}
|
|
|
- esdp &= ~(IXGBE_ESDP_SDP0_NATIVE | IXGBE_ESDP_SDP0_DIR);
|
|
|
- IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
|
|
|
}
|
|
|
|
|
|
/* Identify the PHY or SFP module */
|
|
|
ret_val = phy->ops.identify(hw);
|
|
|
|
|
|
- /* Setup function pointers based on detected SFP module and speeds */
|
|
|
+ /* Setup function pointers based on detected hardware */
|
|
|
ixgbe_init_mac_link_ops_X550em(hw);
|
|
|
if (phy->sfp_type != ixgbe_sfp_type_unknown)
|
|
|
phy->ops.reset = NULL;
|
|
@@ -1162,11 +1497,30 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
|
|
|
phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
|
|
|
break;
|
|
|
case ixgbe_phy_x550em_ext_t:
|
|
|
- phy->ops.setup_internal_link = ixgbe_setup_internal_phy_x550em;
|
|
|
+ /* Save NW management interface connected on board. This is used
|
|
|
+ * to determine internal PHY mode
|
|
|
+ */
|
|
|
+ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL);
|
|
|
+
|
|
|
+ /* If internal link mode is XFI, then setup iXFI internal link,
|
|
|
+ * else setup KR now.
|
|
|
+ */
|
|
|
+ if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) {
|
|
|
+ phy->ops.setup_internal_link =
|
|
|
+ ixgbe_setup_internal_phy_t_x550em;
|
|
|
+ } else {
|
|
|
+ speed = IXGBE_LINK_SPEED_10GB_FULL |
|
|
|
+ IXGBE_LINK_SPEED_1GB_FULL;
|
|
|
+ ret_val = ixgbe_setup_kr_speed_x550em(hw, speed);
|
|
|
+ }
|
|
|
+
|
|
|
+ phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em;
|
|
|
+ phy->ops.reset = ixgbe_reset_phy_t_X550em;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
return ret_val;
|
|
|
}
|
|
|
|
|
@@ -1207,65 +1561,35 @@ static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
|
|
|
{
|
|
|
s32 status;
|
|
|
u16 reg;
|
|
|
- u32 retries = 2;
|
|
|
-
|
|
|
- do {
|
|
|
- /* decrement retries counter and exit if we hit 0 */
|
|
|
- if (retries < 1) {
|
|
|
- hw_dbg(hw, "External PHY not yet finished resetting.");
|
|
|
- return IXGBE_ERR_PHY;
|
|
|
- }
|
|
|
- retries--;
|
|
|
-
|
|
|
- status = hw->phy.ops.read_reg(hw,
|
|
|
- IXGBE_MDIO_TX_VENDOR_ALARMS_3,
|
|
|
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
|
|
|
- ®);
|
|
|
- if (status)
|
|
|
- return status;
|
|
|
-
|
|
|
- /* Verify PHY FW reset has completed */
|
|
|
- } while ((reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) != 1);
|
|
|
-
|
|
|
- /* Set port to low power mode */
|
|
|
- status = hw->phy.ops.read_reg(hw,
|
|
|
- IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
|
|
|
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
- ®);
|
|
|
- if (status)
|
|
|
- return status;
|
|
|
|
|
|
- /* Enable the transmitter */
|
|
|
status = hw->phy.ops.read_reg(hw,
|
|
|
- IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
|
|
|
+ IXGBE_MDIO_TX_VENDOR_ALARMS_3,
|
|
|
IXGBE_MDIO_PMA_PMD_DEV_TYPE,
|
|
|
®);
|
|
|
if (status)
|
|
|
return status;
|
|
|
|
|
|
- reg &= ~IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE;
|
|
|
+ /* If PHY FW reset completed bit is set then this is the first
|
|
|
+ * SW instance after a power on so the PHY FW must be un-stalled.
|
|
|
+ */
|
|
|
+ if (reg & IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK) {
|
|
|
+ status = hw->phy.ops.read_reg(hw,
|
|
|
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ ®);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
|
|
|
- status = hw->phy.ops.write_reg(hw,
|
|
|
- IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
|
|
|
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
|
|
|
- reg);
|
|
|
- if (status)
|
|
|
- return status;
|
|
|
+ reg &= ~IXGBE_MDIO_POWER_UP_STALL;
|
|
|
|
|
|
- /* Un-stall the PHY FW */
|
|
|
- status = hw->phy.ops.read_reg(hw,
|
|
|
- IXGBE_MDIO_GLOBAL_RES_PR_10,
|
|
|
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
- ®);
|
|
|
- if (status)
|
|
|
- return status;
|
|
|
-
|
|
|
- reg &= ~IXGBE_MDIO_POWER_UP_STALL;
|
|
|
+ status = hw->phy.ops.write_reg(hw,
|
|
|
+ IXGBE_MDIO_GLOBAL_RES_PR_10,
|
|
|
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
+ reg);
|
|
|
+ if (status)
|
|
|
+ return status;
|
|
|
+ }
|
|
|
|
|
|
- status = hw->phy.ops.write_reg(hw,
|
|
|
- IXGBE_MDIO_GLOBAL_RES_PR_10,
|
|
|
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
|
|
|
- reg);
|
|
|
return status;
|
|
|
}
|
|
|
|
|
@@ -1282,6 +1606,7 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
|
|
|
s32 status;
|
|
|
u32 ctrl = 0;
|
|
|
u32 i;
|
|
|
+ u32 hlreg0;
|
|
|
bool link_up = false;
|
|
|
|
|
|
/* Call adapter stop to disable Tx/Rx and clear interrupts */
|
|
@@ -1366,6 +1691,15 @@ mac_reset_top:
|
|
|
hw->mac.num_rar_entries = 128;
|
|
|
hw->mac.ops.init_rx_addrs(hw);
|
|
|
|
|
|
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) {
|
|
|
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
|
|
|
+ hlreg0 &= ~IXGBE_HLREG0_MDCSPD;
|
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP)
|
|
|
+ ixgbe_setup_mux_ctl(hw);
|
|
|
+
|
|
|
return status;
|
|
|
}
|
|
|
|
|
@@ -1518,6 +1852,10 @@ static struct ixgbe_eeprom_operations eeprom_ops_X550EM_x = {
|
|
|
.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic, \
|
|
|
.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic, \
|
|
|
.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic, \
|
|
|
+ .read_reg = &ixgbe_read_phy_reg_generic, \
|
|
|
+ .write_reg = &ixgbe_write_phy_reg_generic, \
|
|
|
+ .setup_link = &ixgbe_setup_phy_link_generic, \
|
|
|
+ .set_phy_power = &ixgbe_set_copper_phy_power, \
|
|
|
.check_overtemp = &ixgbe_tn_check_overtemp, \
|
|
|
.get_firmware_version = &ixgbe_get_phy_firmware_version_generic,
|
|
|
|
|
@@ -1525,9 +1863,6 @@ static struct ixgbe_phy_operations phy_ops_X550 = {
|
|
|
X550_COMMON_PHY
|
|
|
.init = NULL,
|
|
|
.identify = &ixgbe_identify_phy_generic,
|
|
|
- .read_reg = &ixgbe_read_phy_reg_generic,
|
|
|
- .write_reg = &ixgbe_write_phy_reg_generic,
|
|
|
- .setup_link = &ixgbe_setup_phy_link_generic,
|
|
|
.read_i2c_combined = &ixgbe_read_i2c_combined_generic,
|
|
|
.write_i2c_combined = &ixgbe_write_i2c_combined_generic,
|
|
|
};
|
|
@@ -1536,9 +1871,14 @@ static struct ixgbe_phy_operations phy_ops_X550EM_x = {
|
|
|
X550_COMMON_PHY
|
|
|
.init = &ixgbe_init_phy_ops_X550em,
|
|
|
.identify = &ixgbe_identify_phy_x550em,
|
|
|
- .read_reg = NULL, /* defined later */
|
|
|
- .write_reg = NULL, /* defined later */
|
|
|
- .setup_link = NULL, /* defined later */
|
|
|
+};
|
|
|
+
|
|
|
+static const u32 ixgbe_mvals_X550[IXGBE_MVALS_IDX_LIMIT] = {
|
|
|
+ IXGBE_MVALS_INIT(X550)
|
|
|
+};
|
|
|
+
|
|
|
+static const u32 ixgbe_mvals_X550EM_x[IXGBE_MVALS_IDX_LIMIT] = {
|
|
|
+ IXGBE_MVALS_INIT(X550EM_x)
|
|
|
};
|
|
|
|
|
|
struct ixgbe_info ixgbe_X550_info = {
|
|
@@ -1548,6 +1888,7 @@ struct ixgbe_info ixgbe_X550_info = {
|
|
|
.eeprom_ops = &eeprom_ops_X550,
|
|
|
.phy_ops = &phy_ops_X550,
|
|
|
.mbx_ops = &mbx_ops_generic,
|
|
|
+ .mvals = ixgbe_mvals_X550,
|
|
|
};
|
|
|
|
|
|
struct ixgbe_info ixgbe_X550EM_x_info = {
|
|
@@ -1557,4 +1898,5 @@ struct ixgbe_info ixgbe_X550EM_x_info = {
|
|
|
.eeprom_ops = &eeprom_ops_X550EM_x,
|
|
|
.phy_ops = &phy_ops_X550EM_x,
|
|
|
.mbx_ops = &mbx_ops_generic,
|
|
|
+ .mvals = ixgbe_mvals_X550EM_x,
|
|
|
};
|