switch (hw->device_id) {
case IXGBE_DEV_ID_X550EM_X_SFP:
/* set up for CS4227 usage */
- hw->phy.lan_id = IXGBE_READ_REG(hw, IXGBE_STATUS) &
- IXGBE_STATUS_LAN_ID_1;
hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
- if (hw->phy.lan_id) {
+ if (hw->bus.lan_id) {
esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
esdp |= IXGBE_ESDP_SDP1_DIR;
hw->phy.type = ixgbe_phy_x550em_kx4;
break;
case IXGBE_DEV_ID_X550EM_X_KR:
- case IXGBE_DEV_ID_X550EM_X:
hw->phy.type = ixgbe_phy_x550em_kr;
break;
+ case IXGBE_DEV_ID_X550EM_X_1G_T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
+ return ixgbe_identify_phy_generic(hw);
default:
break;
}
mac->ops.disable_sec_rx_path = NULL;
mac->ops.enable_sec_rx_path = NULL;
- /* PCIe bus info not supported in X550EM */
- mac->ops.get_bus_info = NULL;
+ /* X550EM bus type is internal*/
+ hw->bus.type = ixgbe_bus_type_internal;
+ mac->ops.get_bus_info = ixgbe_get_bus_info_X550em;
mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550;
mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550;
ixgbe_get_supported_physical_layer_X550em;
/* PHY */
- phy->ops.init = &ixgbe_init_phy_ops_X550em;
- phy->ops.identify = &ixgbe_identify_phy_x550em;
- phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
- phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
- phy->ops.setup_link = ixgbe_setup_kr_x550em;
+ phy->ops.init = ixgbe_init_phy_ops_X550em;
+ phy->ops.identify = ixgbe_identify_phy_x550em;
+ if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper)
+ phy->ops.set_phy_power = NULL;
/* EEPROM */
hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg);
- } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR ||
- hw->device_id == IXGBE_DEV_ID_X550EM_X) {
+ } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg);
if (status != IXGBE_SUCCESS)
return status;
IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg);
if (status != IXGBE_SUCCESS)
return status;
hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT,
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg);
- } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR ||
- hw->device_id == IXGBE_DEV_ID_X550EM_X) {
+ } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) {
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, &link_reg);
if (status != IXGBE_SUCCESS)
return status;
IXGBE_KRM_LINK_CTRL_1_TETH_EEE_CAP_KX);
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, link_reg);
if (status != IXGBE_SUCCESS)
return status;
break;
}
- if ((command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) != 0) {
+ if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
ERROR_REPORT2(IXGBE_ERROR_POLLING,
break;
}
- if ((command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) != 0) {
+ if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
ERROR_REPORT2(IXGBE_ERROR_POLLING,
/* Detect if there is a copper PHY attached. */
switch (hw->device_id) {
- case IXGBE_DEV_ID_X550EM_X:
case IXGBE_DEV_ID_X550EM_X_KR:
case IXGBE_DEV_ID_X550EM_X_KX4:
media_type = ixgbe_media_type_backplane;
case IXGBE_DEV_ID_X550EM_X_SFP:
media_type = ixgbe_media_type_fiber;
break;
+ case IXGBE_DEV_ID_X550EM_X_1G_T:
+ case IXGBE_DEV_ID_X550EM_X_10G_T:
+ media_type = ixgbe_media_type_copper;
+ break;
default:
media_type = ixgbe_media_type_unknown;
break;
hw->phy.ops.reset = NULL;
/* The CS4227 slice address is the base address + the port-pair reg
- * offset. I.e. Slice 0 = 0x0000 and slice 1 = 0x1000.
+ * offset. I.e. Slice 0 = 0x12B0 and slice 1 = 0x22B0.
*/
- reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->phy.lan_id << 12);
+ reg_slice = IXGBE_CS4227_SPARE24_LSB + (hw->bus.lan_id << 12);
if (setup_linear)
edc_mode = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1;
ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice,
edc_mode);
+ if (ret_val != IXGBE_SUCCESS)
+ ret_val = ixgbe_write_i2c_combined(hw, 0x80, reg_slice,
+ edc_mode);
+
return ret_val;
}
/* Link capabilities are based on SFP */
if (hw->phy.multispeed_fiber)
- *speed |= IXGBE_LINK_SPEED_10GB_FULL |
- IXGBE_LINK_SPEED_1GB_FULL;
+ *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;
+ *speed = IXGBE_LINK_SPEED_10GB_FULL |
+ IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = true;
}
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) {
esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
- phy->lan_id = IXGBE_READ_REG(hw, IXGBE_STATUS) &
- IXGBE_STATUS_LAN_ID_1;
phy->phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
- if (phy->lan_id) {
+
+ if (hw->bus.lan_id) {
esdp &= ~(IXGBE_ESDP_SDP1_NATIVE | IXGBE_ESDP_SDP1);
esdp |= IXGBE_ESDP_SDP1_DIR;
}
/* Set functions pointers based on phy type */
switch (hw->phy.type) {
+ case ixgbe_phy_x550em_kx4:
+ phy->ops.setup_link = ixgbe_setup_kx4_x550em;
+ phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
+ phy->ops.write_reg = ixgbe_write_phy_reg_x550em;
+ break;
case ixgbe_phy_x550em_kr:
phy->ops.setup_link = ixgbe_setup_kr_x550em;
+ phy->ops.read_reg = ixgbe_read_phy_reg_x550em;
+ 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;
break;
default:
break;
if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
return status;
+ /* start the external PHY */
+ if (hw->phy.type == ixgbe_phy_x550em_ext_t) {
+ status = ixgbe_init_ext_t_x550em(hw);
+ if (status)
+ return status;
+ }
+
/* Setup SFP module if there is one present. */
if (hw->phy.sfp_setup_needed) {
status = hw->mac.ops.setup_sfp(hw);
hw->mac.num_rar_entries = 128;
hw->mac.ops.init_rx_addrs(hw);
+
+ return status;
+}
+
+/**
+ * ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
+ * @hw: pointer to hardware structure
+ */
+s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 reg;
+ u32 retries = 1;
+
+ /* TODO: The number of attempts and delay between attempts is undefined */
+ do {
+ /* decrement retries counter and exit if we hit 0 */
+ if (retries < 1) {
+ ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE,
+ "External PHY not yet finished resetting.");
+ return IXGBE_ERR_PHY;
+ }
+ retries--;
+
+ usec_delay(0);
+
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MDIO_TX_VENDOR_ALARMS_3,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ ®);
+
+ if (status != IXGBE_SUCCESS)
+ 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 != IXGBE_SUCCESS)
+ return status;
+
+ reg |= IXGBE_MDIO_PHY_SET_LOW_POWER_MODE;
+
+ status = hw->phy.ops.write_reg(hw,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* Enable the transmitter */
+ status = hw->phy.ops.read_reg(hw,
+ IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ ®);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ reg &= ~IXGBE_MDIO_PMD_GLOBAL_TX_DISABLE;
+
+ status = hw->phy.ops.write_reg(hw,
+ IXGBE_MDIO_PMD_STD_TX_DISABLE_CNTR,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ reg);
+
+ if (status != IXGBE_SUCCESS)
+ return status;
+
+ /* 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 != IXGBE_SUCCESS)
+ 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);
+
return status;
}
u32 reg_val;
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ 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;
/* 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->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
return status;
}
/**
- * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI.
+ * ixgbe_setup_kx4_x550em - Configure the KX4 PHY.
* @hw: pointer to hardware structure
*
- * Configures the integrated KR PHY to use iXFI mode.
+ * Configures the integrated KX4 PHY.
**/
-s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw)
+s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u32 reg_val;
+
+ status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
+ IXGBE_SB_IOSF_TARGET_KX4_PCS0 + hw->bus.lan_id, ®_val);
+ if (status)
+ return status;
+
+ reg_val &= ~(IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4 |
+ IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX);
+
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_ENABLE;
+
+ /* Advertise 10G support. */
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4;
+
+ /* Advertise 1G support. */
+ if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX;
+
+ /* Restart auto-negotiation. */
+ reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_RESTART;
+ status = ixgbe_write_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1,
+ IXGBE_SB_IOSF_TARGET_KX4_PCS0 + hw->bus.lan_id, reg_val);
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode.
+ * @hw: pointer to hardware structure
+ * @speed: the link speed to force
+ *
+ * Configures the integrated KR PHY to use iXFI mode. Used to connect an
+ * internal and external PHY at a specific speed, without autonegotiation.
+ **/
+STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
{
s32 status;
u32 reg_val;
/* Disable AN and force speed to 10G Serial. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
+
reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE;
reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
- reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
+
+ /* Select forced link speed for internal PHY. */
+ switch (*speed) {
+ case IXGBE_LINK_SPEED_10GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
+ break;
+ case IXGBE_LINK_SPEED_1GB_FULL:
+ reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G;
+ break;
+ default:
+ /* Other link speeds are not supported by internal KR PHY. */
+ return IXGBE_ERR_LINK_SETUP;
+ }
+
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Disable training protocol FSM. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_CONV_WO_PROTOCOL;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Disable Flex from training TXFFE. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_4(hw->phy.lan_id),
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_4(hw->phy.lan_id),
+ IXGBE_KRM_DSP_TXFFE_STATE_4(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_5(hw->phy.lan_id),
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CP1_CN1_EN;
reg_val &= ~IXGBE_KRM_DSP_TXFFE_STATE_CO_ADAPT_EN;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_DSP_TXFFE_STATE_5(hw->phy.lan_id),
+ IXGBE_KRM_DSP_TXFFE_STATE_5(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Enable override for coefficients. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_TX_COEFF_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CPLUS1_OVRRD_EN;
reg_val |= IXGBE_KRM_TX_COEFF_CTRL_1_CMINUS1_OVRRD_EN;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_TX_COEFF_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Toggle port SW reset by AN reset. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_AN_RESTART;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
return status;
}
+/**
+ * ixgbe_setup_internal_phy_x550em - Configure integrated KR PHY
+ * @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.
+ *
+ * A return of a non-zero value indicates an error, and the base driver should
+ * not report link up.
+ */
+s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 lasi, autoneg_status, speed;
+ ixgbe_link_speed force_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 (status != IXGBE_SUCCESS)
+ return status;
+
+ /* If there was no change in link status, we can just exit */
+ if (!(lasi & IXGBE_XENPAK_LASI_LINK_STATUS_ALARM))
+ return IXGBE_SUCCESS;
+
+ /* we 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 != IXGBE_SUCCESS)
+ return status;
+
+ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_status);
+ if (status != IXGBE_SUCCESS)
+ 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);
+
+ /* clear everything but the speed and duplex bits */
+ speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK;
+
+ switch (speed) {
+ case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL:
+ force_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ break;
+ case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL:
+ force_speed = IXGBE_LINK_SPEED_1GB_FULL;
+ break;
+ default:
+ /* Internal PHY does not support anything else */
+ return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ }
+
+ return ixgbe_setup_ixfi_x550em(hw, &force_speed);
+}
+
/**
* ixgbe_setup_phy_loopback_x550em - Configure the KR PHY for loopback.
* @hw: pointer to hardware structure
/* Disable AN and force speed to 10G Serial. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK;
reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_LINK_CTRL_1(hw->phy.lan_id),
+ IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Set near-end loopback clocks. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_32B;
reg_val |= IXGBE_KRM_PORT_CAR_GEN_CTRL_NELB_KRPCS;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_PORT_CAR_GEN_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Set loopback enable. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_PMD_DFX_BURNIN(hw->phy.lan_id),
+ IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_PMD_DFX_BURNIN_TX_RX_KR_LB_MASK;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_PMD_DFX_BURNIN(hw->phy.lan_id),
+ IXGBE_KRM_PMD_DFX_BURNIN(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
if (status != IXGBE_SUCCESS)
return status;
/* Training bypass. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val);
if (status != IXGBE_SUCCESS)
return status;
reg_val |= IXGBE_KRM_RX_TRN_LINKUP_CTRL_PROTOCOL_BYPASS;
status = ixgbe_write_iosf_sb_reg_x550(hw,
- IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->phy.lan_id),
+ IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id),
IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val);
return status;
struct ixgbe_hic_read_shadow_ram buffer;
DEBUGFUNC("ixgbe_read_ee_hostif_data_X550");
- buffer.hdr.cmd = FW_READ_SHADOW_RAM_CMD;
- buffer.hdr.buf_len1 = 0;
- buffer.hdr.buf_len2 = FW_READ_SHADOW_RAM_LEN;
- buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
+ buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
/* convert offset from words to bytes */
buffer.address = IXGBE_CPU_TO_BE32(offset * 2);
else
words_to_read = words;
- buffer.hdr.cmd = FW_READ_SHADOW_RAM_CMD;
- buffer.hdr.buf_len1 = 0;
- buffer.hdr.buf_len2 = FW_READ_SHADOW_RAM_LEN;
- buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
+ buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
/* convert offset from words to bytes */
buffer.address = IXGBE_CPU_TO_BE32((offset + current_word) * 2);
DEBUGFUNC("ixgbe_write_ee_hostif_data_X550");
- buffer.hdr.cmd = FW_WRITE_SHADOW_RAM_CMD;
- buffer.hdr.buf_len1 = 0;
- buffer.hdr.buf_len2 = FW_WRITE_SHADOW_RAM_LEN;
- buffer.hdr.checksum = FW_DEFAULT_CHECKSUM;
+ buffer.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD;
+ buffer.hdr.req.buf_lenh = 0;
+ buffer.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN;
+ buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
/* one word */
buffer.length = IXGBE_CPU_TO_BE16(sizeof(u16));
* Returns error status for any failure
*/
STATIC s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
- u16 size, u16 *csum)
+ u16 size, u16 *csum, u16 *buffer,
+ u32 buffer_size)
{
u16 buf[256];
s32 status;
u16 length, bufsz, i, start;
+ u16 *local_buffer;
bufsz = sizeof(buf) / sizeof(buf[0]);
/* Read a chunk at the pointer location */
- status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
- if (status) {
- DEBUGOUT("Failed to read EEPROM image\n");
- return status;
+ if (!buffer) {
+ status = ixgbe_read_ee_hostif_buffer_X550(hw, ptr, bufsz, buf);
+ if (status) {
+ DEBUGOUT("Failed to read EEPROM image\n");
+ return status;
+ }
+ local_buffer = buf;
+ } else {
+ if (buffer_size < ptr)
+ return IXGBE_ERR_PARAM;
+ local_buffer = &buffer[ptr];
}
if (size) {
length = size;
} else {
start = 1;
- length = buf[0];
+ length = local_buffer[0];
/* Skip pointer section if length is invalid. */
if (length == 0xFFFF || length == 0 ||
return IXGBE_SUCCESS;
}
+ if (buffer && ((u32)start + (u32)length > buffer_size))
+ return IXGBE_ERR_PARAM;
+
for (i = start; length; i++, length--) {
- if (i == bufsz) {
+ if (i == bufsz && !buffer) {
ptr += bufsz;
i = 0;
if (length < bufsz)
return status;
}
}
- *csum += buf[i];
+ *csum += local_buffer[i];
}
return IXGBE_SUCCESS;
}
/**
- * ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
+ * ixgbe_calc_checksum_X550 - Calculates and returns the checksum
* @hw: pointer to hardware structure
+ * @buffer: pointer to buffer containing calculated checksum
+ * @buffer_size: size of buffer
*
* Returns a negative error code on error, or the 16-bit checksum
**/
-s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
+s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
{
u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
+ u16 *local_buffer;
s32 status;
u16 checksum = 0;
u16 pointer, i, size;
hw->eeprom.ops.init_params(hw);
- /* Read pointer area */
- status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
- IXGBE_EEPROM_LAST_WORD + 1,
- eeprom_ptrs);
- if (status) {
- DEBUGOUT("Failed to read EEPROM image\n");
- return status;
+ if (!buffer) {
+ /* Read pointer area */
+ status = ixgbe_read_ee_hostif_buffer_X550(hw, 0,
+ IXGBE_EEPROM_LAST_WORD + 1,
+ eeprom_ptrs);
+ if (status) {
+ DEBUGOUT("Failed to read EEPROM image\n");
+ return status;
+ }
+ local_buffer = eeprom_ptrs;
+ } else {
+ if (buffer_size < IXGBE_EEPROM_LAST_WORD)
+ return IXGBE_ERR_PARAM;
+ local_buffer = buffer;
}
/*
*/
for (i = 0; i <= IXGBE_EEPROM_LAST_WORD; i++)
if (i != IXGBE_EEPROM_CHECKSUM)
- checksum += eeprom_ptrs[i];
+ checksum += local_buffer[i];
/*
* Include all data from pointers 0x3, 0x6-0xE. This excludes the
if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
continue;
- pointer = eeprom_ptrs[i];
+ pointer = local_buffer[i];
/* Skip pointer section if the pointer is invalid. */
if (pointer == 0xFFFF || pointer == 0 ||
break;
}
- status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum);
+ status = ixgbe_checksum_ptr_x550(hw, pointer, size, &checksum,
+ buffer, buffer_size);
if (status)
return status;
}
return (s32)checksum;
}
+/**
+ * ixgbe_calc_eeprom_checksum_X550 - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ *
+ * Returns a negative error code on error, or the 16-bit checksum
+ **/
+s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
+{
+ return ixgbe_calc_checksum_X550(hw, NULL, 0);
+}
+
/**
* ixgbe_validate_eeprom_checksum_X550 - Validate EEPROM checksum
* @hw: pointer to hardware structure
s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
{
s32 status = IXGBE_SUCCESS;
- struct ixgbe_hic_hdr2 buffer;
+ union ixgbe_hic_hdr2 buffer;
DEBUGFUNC("ixgbe_update_flash_X550");
- buffer.cmd = FW_SHADOW_RAM_DUMP_CMD;
- buffer.buf_len1 = 0;
- buffer.buf_len2 = FW_SHADOW_RAM_DUMP_LEN;
- buffer.checksum = FW_DEFAULT_CHECKSUM;
+ buffer.req.cmd = FW_SHADOW_RAM_DUMP_CMD;
+ buffer.req.buf_lenh = 0;
+ buffer.req.buf_lenl = FW_SHADOW_RAM_DUMP_LEN;
+ buffer.req.checksum = FW_DEFAULT_CHECKSUM;
status = ixgbe_host_interface_command(hw, (u32 *)&buffer,
sizeof(buffer), false);
u32 ixgbe_get_supported_physical_layer_X550em(struct ixgbe_hw *hw)
{
u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+ u16 ext_ability = 0;
DEBUGFUNC("ixgbe_get_supported_physical_layer_X550em");
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
IXGBE_PHYSICAL_LAYER_1000BASE_KX;
break;
+ case ixgbe_phy_x550em_ext_t:
+ hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_EXT_ABILITY,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &ext_ability);
+ if (ext_ability & IXGBE_MDIO_PHY_10GBASET_ABILITY)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_10GBASE_T;
+ if (ext_ability & IXGBE_MDIO_PHY_1000BASET_ABILITY)
+ physical_layer |= IXGBE_PHYSICAL_LAYER_1000BASE_T;
+ break;
default:
break;
}
return physical_layer;
}
+/**
+ * ixgbe_get_bus_info_x550em - Set PCI bus info
+ * @hw: pointer to hardware structure
+ *
+ * Sets bus link width and speed to unknown because X550em is
+ * not a PCI device.
+ **/
+s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw)
+{
+
+ DEBUGFUNC("ixgbe_get_bus_info_x550em");
+
+ hw->bus.width = ixgbe_bus_width_unknown;
+ hw->bus.speed = ixgbe_bus_speed_unknown;
+
+ return IXGBE_SUCCESS;
+}
+
/**
* ixgbe_disable_rx_x550 - Disable RX unit
*
fw_cmd.hdr.cmd = FW_DISABLE_RXEN_CMD;
fw_cmd.hdr.buf_len = FW_DISABLE_RXEN_LEN;
fw_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
- fw_cmd.port_number = hw->phy.lan_id;
+ fw_cmd.port_number = (u8)hw->bus.lan_id;
status = ixgbe_host_interface_command(hw, (u32 *)&fw_cmd,
sizeof(struct ixgbe_hic_disable_rxen),