Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/ixgbe/ixgbe_phy.c
/****************************************************************************** | /****************************************************************************** | ||||
Copyright (c) 2001-2013, Intel Corporation | Copyright (c) 2001-2014, Intel Corporation | ||||
All rights reserved. | All rights reserved. | ||||
Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | ||||
Context not available. | |||||
static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); | static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); | ||||
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); | static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); | ||||
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); | static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); | ||||
static bool ixgbe_get_i2c_data(u32 *i2cctl); | static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl); | ||||
static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, | static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, | ||||
u8 *sff8472_data); | u8 *sff8472_data); | ||||
/** | /** | ||||
* ixgbe_out_i2c_byte_ack - Send I2C byte with ack | |||||
* @hw: pointer to the hardware structure | |||||
* @byte: byte to send | |||||
* | |||||
* Returns an error code on error. | |||||
*/ | |||||
static s32 ixgbe_out_i2c_byte_ack(struct ixgbe_hw *hw, u8 byte) | |||||
{ | |||||
s32 status; | |||||
status = ixgbe_clock_out_i2c_byte(hw, byte); | |||||
if (status) | |||||
return status; | |||||
return ixgbe_get_i2c_ack(hw); | |||||
} | |||||
/** | |||||
* ixgbe_in_i2c_byte_ack - Receive an I2C byte and send ack | |||||
* @hw: pointer to the hardware structure | |||||
* @byte: pointer to a u8 to receive the byte | |||||
* | |||||
* Returns an error code on error. | |||||
*/ | |||||
static s32 ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte) | |||||
{ | |||||
s32 status; | |||||
status = ixgbe_clock_in_i2c_byte(hw, byte); | |||||
if (status) | |||||
return status; | |||||
/* ACK */ | |||||
return ixgbe_clock_out_i2c_bit(hw, FALSE); | |||||
} | |||||
/** | |||||
* ixgbe_ones_comp_byte_add - Perform one's complement addition | |||||
* @add1 - addend 1 | |||||
* @add2 - addend 2 | |||||
* | |||||
* Returns one's complement 8-bit sum. | |||||
*/ | |||||
static u8 ixgbe_ones_comp_byte_add(u8 add1, u8 add2) | |||||
{ | |||||
u16 sum = add1 + add2; | |||||
sum = (sum & 0xFF) + (sum >> 8); | |||||
return sum & 0xFF; | |||||
} | |||||
/** | |||||
* ixgbe_read_i2c_combined_generic - Perform I2C read combined operation | |||||
* @hw: pointer to the hardware structure | |||||
* @addr: I2C bus address to read from | |||||
* @reg: I2C device register to read from | |||||
* @val: pointer to location to receive read value | |||||
* | |||||
* Returns an error code on error. | |||||
*/ | |||||
static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, | |||||
u16 reg, u16 *val) | |||||
{ | |||||
u32 swfw_mask = hw->phy.phy_semaphore_mask; | |||||
int max_retry = 10; | |||||
int retry = 0; | |||||
u8 csum_byte; | |||||
u8 high_bits; | |||||
u8 low_bits; | |||||
u8 reg_high; | |||||
u8 csum; | |||||
reg_high = ((reg >> 7) & 0xFE) | 1; /* Indicate read combined */ | |||||
csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); | |||||
csum = ~csum; | |||||
do { | |||||
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) | |||||
return IXGBE_ERR_SWFW_SYNC; | |||||
ixgbe_i2c_start(hw); | |||||
/* Device Address and write indication */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, addr)) | |||||
goto fail; | |||||
/* Write bits 14:8 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, reg_high)) | |||||
goto fail; | |||||
/* Write bits 7:0 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) | |||||
goto fail; | |||||
/* Write csum */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, csum)) | |||||
goto fail; | |||||
/* Re-start condition */ | |||||
ixgbe_i2c_start(hw); | |||||
/* Device Address and read indication */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, addr | 1)) | |||||
goto fail; | |||||
/* Get upper bits */ | |||||
if (ixgbe_in_i2c_byte_ack(hw, &high_bits)) | |||||
goto fail; | |||||
/* Get low bits */ | |||||
if (ixgbe_in_i2c_byte_ack(hw, &low_bits)) | |||||
goto fail; | |||||
/* Get csum */ | |||||
if (ixgbe_clock_in_i2c_byte(hw, &csum_byte)) | |||||
goto fail; | |||||
/* NACK */ | |||||
if (ixgbe_clock_out_i2c_bit(hw, FALSE)) | |||||
goto fail; | |||||
ixgbe_i2c_stop(hw); | |||||
hw->mac.ops.release_swfw_sync(hw, swfw_mask); | |||||
*val = (high_bits << 8) | low_bits; | |||||
return 0; | |||||
fail: | |||||
ixgbe_i2c_bus_clear(hw); | |||||
hw->mac.ops.release_swfw_sync(hw, swfw_mask); | |||||
retry++; | |||||
if (retry < max_retry) | |||||
DEBUGOUT("I2C byte read combined error - Retrying.\n"); | |||||
else | |||||
DEBUGOUT("I2C byte read combined error.\n"); | |||||
} while (retry < max_retry); | |||||
return IXGBE_ERR_I2C; | |||||
} | |||||
/** | |||||
* ixgbe_write_i2c_combined_generic - Perform I2C write combined operation | |||||
* @hw: pointer to the hardware structure | |||||
* @addr: I2C bus address to write to | |||||
* @reg: I2C device register to write to | |||||
* @val: value to write | |||||
* | |||||
* Returns an error code on error. | |||||
*/ | |||||
static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, | |||||
u8 addr, u16 reg, u16 val) | |||||
{ | |||||
int max_retry = 1; | |||||
int retry = 0; | |||||
u8 reg_high; | |||||
u8 csum; | |||||
reg_high = (reg >> 7) & 0xFE; /* Indicate write combined */ | |||||
csum = ixgbe_ones_comp_byte_add(reg_high, reg & 0xFF); | |||||
csum = ixgbe_ones_comp_byte_add(csum, val >> 8); | |||||
csum = ixgbe_ones_comp_byte_add(csum, val & 0xFF); | |||||
csum = ~csum; | |||||
do { | |||||
ixgbe_i2c_start(hw); | |||||
/* Device Address and write indication */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, addr)) | |||||
goto fail; | |||||
/* Write bits 14:8 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, reg_high)) | |||||
goto fail; | |||||
/* Write bits 7:0 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, reg & 0xFF)) | |||||
goto fail; | |||||
/* Write data 15:8 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, val >> 8)) | |||||
goto fail; | |||||
/* Write data 7:0 */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, val & 0xFF)) | |||||
goto fail; | |||||
/* Write csum */ | |||||
if (ixgbe_out_i2c_byte_ack(hw, csum)) | |||||
goto fail; | |||||
ixgbe_i2c_stop(hw); | |||||
return 0; | |||||
fail: | |||||
ixgbe_i2c_bus_clear(hw); | |||||
retry++; | |||||
if (retry < max_retry) | |||||
DEBUGOUT("I2C byte write combined error - Retrying.\n"); | |||||
else | |||||
DEBUGOUT("I2C byte write combined error.\n"); | |||||
} while (retry < max_retry); | |||||
return IXGBE_ERR_I2C; | |||||
} | |||||
/** | |||||
* ixgbe_init_phy_ops_generic - Inits PHY function ptrs | * ixgbe_init_phy_ops_generic - Inits PHY function ptrs | ||||
* @hw: pointer to the hardware structure | * @hw: pointer to the hardware structure | ||||
* | * | ||||
Context not available. | |||||
DEBUGFUNC("ixgbe_init_phy_ops_generic"); | DEBUGFUNC("ixgbe_init_phy_ops_generic"); | ||||
/* PHY */ | /* PHY */ | ||||
phy->ops.identify = &ixgbe_identify_phy_generic; | phy->ops.identify = ixgbe_identify_phy_generic; | ||||
phy->ops.reset = &ixgbe_reset_phy_generic; | phy->ops.reset = ixgbe_reset_phy_generic; | ||||
phy->ops.read_reg = &ixgbe_read_phy_reg_generic; | phy->ops.read_reg = ixgbe_read_phy_reg_generic; | ||||
phy->ops.write_reg = &ixgbe_write_phy_reg_generic; | phy->ops.write_reg = ixgbe_write_phy_reg_generic; | ||||
phy->ops.read_reg_mdi = &ixgbe_read_phy_reg_mdi; | phy->ops.read_reg_mdi = ixgbe_read_phy_reg_mdi; | ||||
phy->ops.write_reg_mdi = &ixgbe_write_phy_reg_mdi; | phy->ops.write_reg_mdi = ixgbe_write_phy_reg_mdi; | ||||
phy->ops.setup_link = &ixgbe_setup_phy_link_generic; | phy->ops.setup_link = ixgbe_setup_phy_link_generic; | ||||
phy->ops.setup_link_speed = &ixgbe_setup_phy_link_speed_generic; | phy->ops.setup_link_speed = ixgbe_setup_phy_link_speed_generic; | ||||
phy->ops.check_link = NULL; | phy->ops.check_link = NULL; | ||||
phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic; | phy->ops.get_firmware_version = ixgbe_get_phy_firmware_version_generic; | ||||
phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_generic; | phy->ops.read_i2c_byte = ixgbe_read_i2c_byte_generic; | ||||
phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_generic; | phy->ops.write_i2c_byte = ixgbe_write_i2c_byte_generic; | ||||
phy->ops.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic; | phy->ops.read_i2c_sff8472 = ixgbe_read_i2c_sff8472_generic; | ||||
phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic; | phy->ops.read_i2c_eeprom = ixgbe_read_i2c_eeprom_generic; | ||||
phy->ops.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic; | phy->ops.write_i2c_eeprom = ixgbe_write_i2c_eeprom_generic; | ||||
phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear; | phy->ops.i2c_bus_clear = ixgbe_i2c_bus_clear; | ||||
phy->ops.identify_sfp = &ixgbe_identify_module_generic; | phy->ops.identify_sfp = ixgbe_identify_module_generic; | ||||
phy->sfp_type = ixgbe_sfp_type_unknown; | phy->sfp_type = ixgbe_sfp_type_unknown; | ||||
phy->ops.check_overtemp = &ixgbe_tn_check_overtemp; | phy->ops.read_i2c_combined = ixgbe_read_i2c_combined_generic; | ||||
phy->ops.write_i2c_combined = ixgbe_write_i2c_combined_generic; | |||||
phy->ops.check_overtemp = ixgbe_tn_check_overtemp; | |||||
return IXGBE_SUCCESS; | return IXGBE_SUCCESS; | ||||
} | } | ||||
Context not available. | |||||
DEBUGFUNC("ixgbe_identify_phy_generic"); | DEBUGFUNC("ixgbe_identify_phy_generic"); | ||||
if (!hw->phy.phy_semaphore_mask) { | |||||
if (hw->bus.lan_id) | |||||
hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; | |||||
else | |||||
hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; | |||||
} | |||||
if (hw->phy.type == ixgbe_phy_unknown) { | if (hw->phy.type == ixgbe_phy_unknown) { | ||||
for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { | for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) { | ||||
if (ixgbe_validate_phy_addr(hw, phy_addr)) { | if (ixgbe_validate_phy_addr(hw, phy_addr)) { | ||||
Context not available. | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* clear value if nothing found */ | |||||
/* Certain media types do not have a phy so an address will not | |||||
* be found and the code will take this path. Caller has to | |||||
* decide if it is an error or not. | |||||
*/ | |||||
if (status != IXGBE_SUCCESS) { | if (status != IXGBE_SUCCESS) { | ||||
hw->phy.addr = 0; | hw->phy.addr = 0; | ||||
ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, | |||||
"Could not identify valid PHY address"); | |||||
} | } | ||||
} else { | } else { | ||||
status = IXGBE_SUCCESS; | status = IXGBE_SUCCESS; | ||||
Context not available. | |||||
} | } | ||||
/** | /** | ||||
* ixgbe_check_reset_blocked - check status of MNG FW veto bit | |||||
* @hw: pointer to the hardware structure | |||||
* | |||||
* This function checks the MMNGC.MNG_VETO bit to see if there are | |||||
* any constraints on link from manageability. For MAC's that don't | |||||
* have this bit just return faluse since the link can not be blocked | |||||
* via this method. | |||||
**/ | |||||
s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw) | |||||
{ | |||||
u32 mmngc; | |||||
DEBUGFUNC("ixgbe_check_reset_blocked"); | |||||
/* If we don't have this bit, it can't be blocking */ | |||||
if (hw->mac.type == ixgbe_mac_82598EB) | |||||
return FALSE; | |||||
mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC); | |||||
if (mmngc & IXGBE_MMNGC_MNG_VETO) { | |||||
ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, | |||||
"MNG_VETO bit detected.\n"); | |||||
return TRUE; | |||||
} | |||||
return FALSE; | |||||
} | |||||
/** | |||||
* ixgbe_validate_phy_addr - Determines phy address is valid | * ixgbe_validate_phy_addr - Determines phy address is valid | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* | * | ||||
Context not available. | |||||
case TN1010_PHY_ID: | case TN1010_PHY_ID: | ||||
phy_type = ixgbe_phy_tn; | phy_type = ixgbe_phy_tn; | ||||
break; | break; | ||||
case X550_PHY_ID: | |||||
case X540_PHY_ID: | case X540_PHY_ID: | ||||
phy_type = ixgbe_phy_aq; | phy_type = ixgbe_phy_aq; | ||||
break; | break; | ||||
Context not available. | |||||
case ATH_PHY_ID: | case ATH_PHY_ID: | ||||
phy_type = ixgbe_phy_nl; | phy_type = ixgbe_phy_nl; | ||||
break; | break; | ||||
case X557_PHY_ID: | |||||
phy_type = ixgbe_phy_x550em_ext_t; | |||||
break; | |||||
default: | default: | ||||
phy_type = ixgbe_phy_unknown; | phy_type = ixgbe_phy_unknown; | ||||
break; | break; | ||||
Context not available. | |||||
(IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) | (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) | ||||
goto out; | goto out; | ||||
/* Blocked by MNG FW so bail */ | |||||
if (ixgbe_check_reset_blocked(hw)) | |||||
goto out; | |||||
/* | /* | ||||
* Perform soft PHY reset to the PHY_XS. | * Perform soft PHY reset to the PHY_XS. | ||||
* This will cause a soft reset to the PHY | * This will cause a soft reset to the PHY | ||||
Context not available. | |||||
u32 device_type, u16 *phy_data) | u32 device_type, u16 *phy_data) | ||||
{ | { | ||||
s32 status; | s32 status; | ||||
u16 gssr; | u32 gssr = hw->phy.phy_semaphore_mask; | ||||
DEBUGFUNC("ixgbe_read_phy_reg_generic"); | DEBUGFUNC("ixgbe_read_phy_reg_generic"); | ||||
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) | |||||
gssr = IXGBE_GSSR_PHY1_SM; | |||||
else | |||||
gssr = IXGBE_GSSR_PHY0_SM; | |||||
if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { | if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { | ||||
status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, | status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, | ||||
phy_data); | phy_data); | ||||
Context not available. | |||||
u32 device_type, u16 phy_data) | u32 device_type, u16 phy_data) | ||||
{ | { | ||||
s32 status; | s32 status; | ||||
u16 gssr; | u32 gssr = hw->phy.phy_semaphore_mask; | ||||
DEBUGFUNC("ixgbe_write_phy_reg_generic"); | DEBUGFUNC("ixgbe_write_phy_reg_generic"); | ||||
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) | |||||
gssr = IXGBE_GSSR_PHY1_SM; | |||||
else | |||||
gssr = IXGBE_GSSR_PHY0_SM; | |||||
if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { | if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { | ||||
status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, | status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, | ||||
phy_data); | phy_data); | ||||
Context not available. | |||||
} | } | ||||
/** | /** | ||||
* ixgbe_setup_phy_link_generic - Set and restart autoneg | * ixgbe_setup_phy_link_generic - Set and restart auto-neg | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* | * | ||||
* Restart autonegotiation and PHY and waits for completion. | * Restart auto-negotiation and PHY and waits for completion. | ||||
**/ | **/ | ||||
s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) | s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) | ||||
{ | { | ||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
u32 time_out; | |||||
u32 max_time_out = 10; | |||||
u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; | u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; | ||||
bool autoneg = FALSE; | bool autoneg = FALSE; | ||||
ixgbe_link_speed speed; | ixgbe_link_speed speed; | ||||
Context not available. | |||||
autoneg_reg); | autoneg_reg); | ||||
} | } | ||||
if (hw->mac.type == ixgbe_mac_X550) { | |||||
if (speed & IXGBE_LINK_SPEED_5GB_FULL) { | |||||
/* Set or unset auto-negotiation 1G advertisement */ | |||||
hw->phy.ops.read_reg(hw, | |||||
IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
&autoneg_reg); | |||||
autoneg_reg &= ~IXGBE_MII_5GBASE_T_ADVERTISE; | |||||
if (hw->phy.autoneg_advertised & | |||||
IXGBE_LINK_SPEED_5GB_FULL) | |||||
autoneg_reg |= IXGBE_MII_5GBASE_T_ADVERTISE; | |||||
hw->phy.ops.write_reg(hw, | |||||
IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
autoneg_reg); | |||||
} | |||||
if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) { | |||||
/* Set or unset auto-negotiation 1G advertisement */ | |||||
hw->phy.ops.read_reg(hw, | |||||
IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
&autoneg_reg); | |||||
autoneg_reg &= ~IXGBE_MII_2_5GBASE_T_ADVERTISE; | |||||
if (hw->phy.autoneg_advertised & | |||||
IXGBE_LINK_SPEED_2_5GB_FULL) | |||||
autoneg_reg |= IXGBE_MII_2_5GBASE_T_ADVERTISE; | |||||
hw->phy.ops.write_reg(hw, | |||||
IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
autoneg_reg); | |||||
} | |||||
} | |||||
if (speed & IXGBE_LINK_SPEED_1GB_FULL) { | if (speed & IXGBE_LINK_SPEED_1GB_FULL) { | ||||
/* Set or unset auto-negotiation 1G advertisement */ | /* Set or unset auto-negotiation 1G advertisement */ | ||||
hw->phy.ops.read_reg(hw, | hw->phy.ops.read_reg(hw, | ||||
Context not available. | |||||
autoneg_reg); | autoneg_reg); | ||||
} | } | ||||
/* Restart PHY autonegotiation and wait for completion */ | /* Blocked by MNG FW so don't reset PHY */ | ||||
if (ixgbe_check_reset_blocked(hw)) | |||||
return status; | |||||
/* Restart PHY auto-negotiation. */ | |||||
hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | ||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); | IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); | ||||
Context not available. | |||||
hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | ||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); | IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); | ||||
/* Wait for autonegotiation to finish */ | |||||
for (time_out = 0; time_out < max_time_out; time_out++) { | |||||
usec_delay(10); | |||||
/* Restart PHY autonegotiation and wait for completion */ | |||||
status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
&autoneg_reg); | |||||
autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; | |||||
if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) | |||||
break; | |||||
} | |||||
if (time_out == max_time_out) { | |||||
status = IXGBE_ERR_LINK_SETUP; | |||||
ERROR_REPORT1(IXGBE_ERROR_POLLING, | |||||
"PHY autonegotiation time out"); | |||||
} | |||||
return status; | return status; | ||||
} | } | ||||
Context not available. | |||||
if (speed & IXGBE_LINK_SPEED_10GB_FULL) | if (speed & IXGBE_LINK_SPEED_10GB_FULL) | ||||
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; | hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; | ||||
if (speed & IXGBE_LINK_SPEED_5GB_FULL) | |||||
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_5GB_FULL; | |||||
if (speed & IXGBE_LINK_SPEED_2_5GB_FULL) | |||||
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; | |||||
if (speed & IXGBE_LINK_SPEED_1GB_FULL) | if (speed & IXGBE_LINK_SPEED_1GB_FULL) | ||||
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; | hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; | ||||
Context not available. | |||||
* @speed: pointer to link speed | * @speed: pointer to link speed | ||||
* @autoneg: boolean auto-negotiation value | * @autoneg: boolean auto-negotiation value | ||||
* | * | ||||
* Determines the link capabilities by reading the AUTOC register. | * Determines the supported link capabilities by reading the PHY auto | ||||
* negotiation register. | |||||
**/ | **/ | ||||
s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, | s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, | ||||
ixgbe_link_speed *speed, | ixgbe_link_speed *speed, | ||||
bool *autoneg) | bool *autoneg) | ||||
{ | { | ||||
s32 status = IXGBE_ERR_LINK_SETUP; | s32 status; | ||||
u16 speed_ability; | u16 speed_ability; | ||||
DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic"); | DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic"); | ||||
Context not available. | |||||
*speed |= IXGBE_LINK_SPEED_100_FULL; | *speed |= IXGBE_LINK_SPEED_100_FULL; | ||||
} | } | ||||
/* Internal PHY does not support 100 Mbps */ | |||||
if (hw->mac.type == ixgbe_mac_X550EM_x) | |||||
*speed &= ~IXGBE_LINK_SPEED_100_FULL; | |||||
if (hw->mac.type == ixgbe_mac_X550) { | |||||
*speed |= IXGBE_LINK_SPEED_2_5GB_FULL; | |||||
*speed |= IXGBE_LINK_SPEED_5GB_FULL; | |||||
} | |||||
return status; | return status; | ||||
} | } | ||||
Context not available. | |||||
} | } | ||||
/** | /** | ||||
* ixgbe_setup_phy_link_tnx - Set and restart autoneg | * ixgbe_setup_phy_link_tnx - Set and restart auto-neg | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* | * | ||||
* Restart autonegotiation and PHY and waits for completion. | * Restart auto-negotiation and PHY and waits for completion. | ||||
**/ | **/ | ||||
s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) | s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) | ||||
{ | { | ||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
u32 time_out; | |||||
u32 max_time_out = 10; | |||||
u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; | u16 autoneg_reg = IXGBE_MII_AUTONEG_REG; | ||||
bool autoneg = FALSE; | bool autoneg = FALSE; | ||||
ixgbe_link_speed speed; | ixgbe_link_speed speed; | ||||
Context not available. | |||||
autoneg_reg); | autoneg_reg); | ||||
} | } | ||||
/* Restart PHY autonegotiation and wait for completion */ | /* Blocked by MNG FW so don't reset PHY */ | ||||
if (ixgbe_check_reset_blocked(hw)) | |||||
return status; | |||||
/* Restart PHY auto-negotiation. */ | |||||
hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | ||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); | IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg); | ||||
Context not available. | |||||
hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL, | ||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); | IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg); | ||||
/* Wait for autonegotiation to finish */ | |||||
for (time_out = 0; time_out < max_time_out; time_out++) { | |||||
usec_delay(10); | |||||
/* Restart PHY autonegotiation and wait for completion */ | |||||
status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, | |||||
IXGBE_MDIO_AUTO_NEG_DEV_TYPE, | |||||
&autoneg_reg); | |||||
autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; | |||||
if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) | |||||
break; | |||||
} | |||||
if (time_out == max_time_out) { | |||||
status = IXGBE_ERR_LINK_SETUP; | |||||
DEBUGOUT("ixgbe_setup_phy_link_tnx: time out"); | |||||
} | |||||
return status; | return status; | ||||
} | } | ||||
Context not available. | |||||
s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, | s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, | ||||
u16 *firmware_version) | u16 *firmware_version) | ||||
{ | { | ||||
s32 status = IXGBE_SUCCESS; | s32 status; | ||||
DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx"); | DEBUGFUNC("ixgbe_get_phy_firmware_version_tnx"); | ||||
Context not available. | |||||
s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw, | s32 ixgbe_get_phy_firmware_version_generic(struct ixgbe_hw *hw, | ||||
u16 *firmware_version) | u16 *firmware_version) | ||||
{ | { | ||||
s32 status = IXGBE_SUCCESS; | s32 status; | ||||
DEBUGFUNC("ixgbe_get_phy_firmware_version_generic"); | DEBUGFUNC("ixgbe_get_phy_firmware_version_generic"); | ||||
Context not available. | |||||
DEBUGFUNC("ixgbe_reset_phy_nl"); | DEBUGFUNC("ixgbe_reset_phy_nl"); | ||||
/* Blocked by MNG FW so bail */ | |||||
if (ixgbe_check_reset_blocked(hw)) | |||||
goto out; | |||||
hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | ||||
IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | ||||
Context not available. | |||||
status = ixgbe_identify_sfp_module_generic(hw); | status = ixgbe_identify_sfp_module_generic(hw); | ||||
break; | break; | ||||
case ixgbe_media_type_fiber_qsfp: | |||||
status = ixgbe_identify_qsfp_module_generic(hw); | |||||
break; | |||||
default: | default: | ||||
hw->phy.sfp_type = ixgbe_sfp_type_not_present; | hw->phy.sfp_type = ixgbe_sfp_type_not_present; | ||||
Context not available. | |||||
goto out; | goto out; | ||||
} | } | ||||
/* LAN ID is needed for I2C access */ | |||||
hw->mac.ops.set_lan_id(hw); | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, | status = hw->phy.ops.read_i2c_eeprom(hw, | ||||
IXGBE_SFF_IDENTIFIER, | IXGBE_SFF_IDENTIFIER, | ||||
&identifier); | &identifier); | ||||
Context not available. | |||||
if (status != IXGBE_SUCCESS) | if (status != IXGBE_SUCCESS) | ||||
goto err_read_i2c_eeprom; | goto err_read_i2c_eeprom; | ||||
/* LAN ID is needed for sfp_type determination */ | |||||
hw->mac.ops.set_lan_id(hw); | |||||
if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { | if (identifier != IXGBE_SFF_IDENTIFIER_SFP) { | ||||
hw->phy.type = ixgbe_phy_sfp_unsupported; | hw->phy.type = ixgbe_phy_sfp_unsupported; | ||||
status = IXGBE_ERR_SFP_NOT_SUPPORTED; | status = IXGBE_ERR_SFP_NOT_SUPPORTED; | ||||
Context not available. | |||||
hw->phy.sfp_type = ixgbe_sfp_type_lr; | hw->phy.sfp_type = ixgbe_sfp_type_lr; | ||||
else | else | ||||
hw->phy.sfp_type = ixgbe_sfp_type_unknown; | hw->phy.sfp_type = ixgbe_sfp_type_unknown; | ||||
} else if (hw->mac.type == ixgbe_mac_82599EB) { | } else { | ||||
if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { | if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { | ||||
if (hw->bus.lan_id == 0) | if (hw->bus.lan_id == 0) | ||||
hw->phy.sfp_type = | hw->phy.sfp_type = | ||||
Context not available. | |||||
return IXGBE_ERR_SFP_NOT_PRESENT; | return IXGBE_ERR_SFP_NOT_PRESENT; | ||||
} | } | ||||
/** | |||||
* ixgbe_get_supported_phy_sfp_layer_generic - Returns physical layer type | |||||
* @hw: pointer to hardware structure | |||||
* | |||||
* Determines physical layer capabilities of the current SFP. | |||||
*/ | |||||
s32 ixgbe_get_supported_phy_sfp_layer_generic(struct ixgbe_hw *hw) | |||||
{ | |||||
u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; | |||||
u8 comp_codes_10g = 0; | |||||
u8 comp_codes_1g = 0; | |||||
DEBUGFUNC("ixgbe_get_supported_phy_sfp_layer_generic"); | |||||
hw->phy.ops.identify_sfp(hw); | |||||
if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) | |||||
return physical_layer; | |||||
switch (hw->phy.type) { | |||||
case ixgbe_phy_sfp_passive_tyco: | |||||
case ixgbe_phy_sfp_passive_unknown: | |||||
case ixgbe_phy_qsfp_passive_unknown: | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; | |||||
break; | |||||
case ixgbe_phy_sfp_ftl_active: | |||||
case ixgbe_phy_sfp_active_unknown: | |||||
case ixgbe_phy_qsfp_active_unknown: | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA; | |||||
break; | |||||
case ixgbe_phy_sfp_avago: | |||||
case ixgbe_phy_sfp_ftl: | |||||
case ixgbe_phy_sfp_intel: | |||||
case ixgbe_phy_sfp_unknown: | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g); | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); | |||||
if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; | |||||
else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; | |||||
else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_T; | |||||
else if (comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_1000BASE_SX; | |||||
break; | |||||
case ixgbe_phy_qsfp_intel: | |||||
case ixgbe_phy_qsfp_unknown: | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_10GBE_COMP, &comp_codes_10g); | |||||
if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; | |||||
else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) | |||||
physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
return physical_layer; | |||||
} | |||||
/** | /** | ||||
* ixgbe_identify_qsfp_module_generic - Identifies QSFP modules | |||||
* @hw: pointer to hardware structure | |||||
* | |||||
* Searches for and identifies the QSFP module and assigns appropriate PHY type | |||||
**/ | |||||
s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw) | |||||
{ | |||||
s32 status = IXGBE_ERR_PHY_ADDR_INVALID; | |||||
u32 vendor_oui = 0; | |||||
enum ixgbe_sfp_type stored_sfp_type = hw->phy.sfp_type; | |||||
u8 identifier = 0; | |||||
u8 comp_codes_1g = 0; | |||||
u8 comp_codes_10g = 0; | |||||
u8 oui_bytes[3] = {0, 0, 0}; | |||||
u16 enforce_sfp = 0; | |||||
u8 connector = 0; | |||||
u8 cable_length = 0; | |||||
u8 device_tech = 0; | |||||
bool active_cable = FALSE; | |||||
DEBUGFUNC("ixgbe_identify_qsfp_module_generic"); | |||||
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) { | |||||
hw->phy.sfp_type = ixgbe_sfp_type_not_present; | |||||
status = IXGBE_ERR_SFP_NOT_PRESENT; | |||||
goto out; | |||||
} | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, | |||||
&identifier); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) { | |||||
hw->phy.type = ixgbe_phy_sfp_unsupported; | |||||
status = IXGBE_ERR_SFP_NOT_SUPPORTED; | |||||
goto out; | |||||
} | |||||
hw->phy.id = identifier; | |||||
/* LAN ID is needed for sfp_type determination */ | |||||
hw->mac.ops.set_lan_id(hw); | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_10GBE_COMP, | |||||
&comp_codes_10g); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_QSFP_1GBE_COMP, | |||||
&comp_codes_1g); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
if (comp_codes_10g & IXGBE_SFF_QSFP_DA_PASSIVE_CABLE) { | |||||
hw->phy.type = ixgbe_phy_qsfp_passive_unknown; | |||||
if (hw->bus.lan_id == 0) | |||||
hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; | |||||
else | |||||
hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1; | |||||
} else if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | | |||||
IXGBE_SFF_10GBASELR_CAPABLE)) { | |||||
if (hw->bus.lan_id == 0) | |||||
hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0; | |||||
else | |||||
hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1; | |||||
} else { | |||||
if (comp_codes_10g & IXGBE_SFF_QSFP_DA_ACTIVE_CABLE) | |||||
active_cable = TRUE; | |||||
if (!active_cable) { | |||||
/* check for active DA cables that pre-date | |||||
* SFF-8436 v3.6 */ | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_CONNECTOR, | |||||
&connector); | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_CABLE_LENGTH, | |||||
&cable_length); | |||||
hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_DEVICE_TECH, | |||||
&device_tech); | |||||
if ((connector == | |||||
IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE) && | |||||
(cable_length > 0) && | |||||
((device_tech >> 4) == | |||||
IXGBE_SFF_QSFP_TRANSMITER_850NM_VCSEL)) | |||||
active_cable = TRUE; | |||||
} | |||||
if (active_cable) { | |||||
hw->phy.type = ixgbe_phy_qsfp_active_unknown; | |||||
if (hw->bus.lan_id == 0) | |||||
hw->phy.sfp_type = | |||||
ixgbe_sfp_type_da_act_lmt_core0; | |||||
else | |||||
hw->phy.sfp_type = | |||||
ixgbe_sfp_type_da_act_lmt_core1; | |||||
} else { | |||||
/* unsupported module type */ | |||||
hw->phy.type = ixgbe_phy_sfp_unsupported; | |||||
status = IXGBE_ERR_SFP_NOT_SUPPORTED; | |||||
goto out; | |||||
} | |||||
} | |||||
if (hw->phy.sfp_type != stored_sfp_type) | |||||
hw->phy.sfp_setup_needed = TRUE; | |||||
/* Determine if the QSFP+ PHY is dual speed or not. */ | |||||
hw->phy.multispeed_fiber = FALSE; | |||||
if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) && | |||||
(comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) || | |||||
((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) && | |||||
(comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE))) | |||||
hw->phy.multispeed_fiber = TRUE; | |||||
/* Determine PHY vendor for optical modules */ | |||||
if (comp_codes_10g & (IXGBE_SFF_10GBASESR_CAPABLE | | |||||
IXGBE_SFF_10GBASELR_CAPABLE)) { | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_VENDOR_OUI_BYTE0, | |||||
&oui_bytes[0]); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_VENDOR_OUI_BYTE1, | |||||
&oui_bytes[1]); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
status = hw->phy.ops.read_i2c_eeprom(hw, | |||||
IXGBE_SFF_QSFP_VENDOR_OUI_BYTE2, | |||||
&oui_bytes[2]); | |||||
if (status != IXGBE_SUCCESS) | |||||
goto err_read_i2c_eeprom; | |||||
vendor_oui = | |||||
((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | | |||||
(oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | | |||||
(oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); | |||||
if (vendor_oui == IXGBE_SFF_VENDOR_OUI_INTEL) | |||||
hw->phy.type = ixgbe_phy_qsfp_intel; | |||||
else | |||||
hw->phy.type = ixgbe_phy_qsfp_unknown; | |||||
ixgbe_get_device_caps(hw, &enforce_sfp); | |||||
if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { | |||||
/* Make sure we're a supported PHY type */ | |||||
if (hw->phy.type == ixgbe_phy_qsfp_intel) { | |||||
status = IXGBE_SUCCESS; | |||||
} else { | |||||
if (hw->allow_unsupported_sfp == TRUE) { | |||||
EWARN(hw, "WARNING: Intel (R) Network " | |||||
"Connections are quality tested " | |||||
"using Intel (R) Ethernet Optics." | |||||
" Using untested modules is not " | |||||
"supported and may cause unstable" | |||||
" operation or damage to the " | |||||
"module or the adapter. Intel " | |||||
"Corporation is not responsible " | |||||
"for any harm caused by using " | |||||
"untested modules.\n", status); | |||||
status = IXGBE_SUCCESS; | |||||
} else { | |||||
DEBUGOUT("QSFP module not supported\n"); | |||||
hw->phy.type = | |||||
ixgbe_phy_sfp_unsupported; | |||||
status = IXGBE_ERR_SFP_NOT_SUPPORTED; | |||||
} | |||||
} | |||||
} else { | |||||
status = IXGBE_SUCCESS; | |||||
} | |||||
} | |||||
out: | |||||
return status; | |||||
err_read_i2c_eeprom: | |||||
hw->phy.sfp_type = ixgbe_sfp_type_not_present; | |||||
hw->phy.id = 0; | |||||
hw->phy.type = ixgbe_phy_unknown; | |||||
return IXGBE_ERR_SFP_NOT_PRESENT; | |||||
} | |||||
/** | |||||
* ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence | * ixgbe_get_sfp_init_sequence_offsets - Provides offset of PHY init sequence | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* @list_offset: offset to the SFP ID list | * @list_offset: offset to the SFP ID list | ||||
Context not available. | |||||
} | } | ||||
/** | /** | ||||
* ixgbe_is_sfp_probe - Returns TRUE if SFP is being detected | |||||
* @hw: pointer to hardware structure | |||||
* @offset: eeprom offset to be read | |||||
* @addr: I2C address to be read | |||||
*/ | |||||
static bool ixgbe_is_sfp_probe(struct ixgbe_hw *hw, u8 offset, u8 addr) | |||||
{ | |||||
if (addr == IXGBE_I2C_EEPROM_DEV_ADDR && | |||||
offset == IXGBE_SFF_IDENTIFIER && | |||||
hw->phy.sfp_type == ixgbe_sfp_type_not_present) | |||||
return TRUE; | |||||
return FALSE; | |||||
} | |||||
/** | |||||
* ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C | * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* @byte_offset: byte offset to read | * @byte_offset: byte offset to read | ||||
Context not available. | |||||
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, | s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, | ||||
u8 dev_addr, u8 *data) | u8 dev_addr, u8 *data) | ||||
{ | { | ||||
s32 status = IXGBE_SUCCESS; | s32 status; | ||||
u32 max_retry = 10; | u32 max_retry = 10; | ||||
u32 retry = 0; | u32 retry = 0; | ||||
u16 swfw_mask = 0; | u32 swfw_mask = hw->phy.phy_semaphore_mask; | ||||
bool nack = 1; | bool nack = 1; | ||||
*data = 0; | *data = 0; | ||||
DEBUGFUNC("ixgbe_read_i2c_byte_generic"); | DEBUGFUNC("ixgbe_read_i2c_byte_generic"); | ||||
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) | if (ixgbe_is_sfp_probe(hw, byte_offset, dev_addr)) | ||||
swfw_mask = IXGBE_GSSR_PHY1_SM; | max_retry = IXGBE_SFP_DETECT_RETRIES; | ||||
else | |||||
swfw_mask = IXGBE_GSSR_PHY0_SM; | |||||
do { | do { | ||||
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) | if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)) | ||||
!= IXGBE_SUCCESS) { | return IXGBE_ERR_SWFW_SYNC; | ||||
status = IXGBE_ERR_SWFW_SYNC; | |||||
goto read_byte_out; | |||||
} | |||||
ixgbe_i2c_start(hw); | ixgbe_i2c_start(hw); | ||||
Context not available. | |||||
goto fail; | goto fail; | ||||
ixgbe_i2c_stop(hw); | ixgbe_i2c_stop(hw); | ||||
break; | hw->mac.ops.release_swfw_sync(hw, swfw_mask); | ||||
return IXGBE_SUCCESS; | |||||
fail: | fail: | ||||
ixgbe_i2c_bus_clear(hw); | ixgbe_i2c_bus_clear(hw); | ||||
Context not available. | |||||
} while (retry < max_retry); | } while (retry < max_retry); | ||||
hw->mac.ops.release_swfw_sync(hw, swfw_mask); | |||||
read_byte_out: | |||||
return status; | return status; | ||||
} | } | ||||
Context not available. | |||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
u32 max_retry = 1; | u32 max_retry = 1; | ||||
u32 retry = 0; | u32 retry = 0; | ||||
u16 swfw_mask = 0; | u32 swfw_mask = hw->phy.phy_semaphore_mask; | ||||
DEBUGFUNC("ixgbe_write_i2c_byte_generic"); | DEBUGFUNC("ixgbe_write_i2c_byte_generic"); | ||||
if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) | |||||
swfw_mask = IXGBE_GSSR_PHY1_SM; | |||||
else | |||||
swfw_mask = IXGBE_GSSR_PHY0_SM; | |||||
if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) { | if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) { | ||||
status = IXGBE_ERR_SWFW_SYNC; | status = IXGBE_ERR_SWFW_SYNC; | ||||
goto write_byte_out; | goto write_byte_out; | ||||
Context not available. | |||||
goto fail; | goto fail; | ||||
ixgbe_i2c_stop(hw); | ixgbe_i2c_stop(hw); | ||||
break; | hw->mac.ops.release_swfw_sync(hw, swfw_mask); | ||||
return IXGBE_SUCCESS; | |||||
fail: | fail: | ||||
ixgbe_i2c_bus_clear(hw); | ixgbe_i2c_bus_clear(hw); | ||||
Context not available. | |||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* | * | ||||
* Sets I2C start condition (High -> Low on SDA while SCL is High) | * Sets I2C start condition (High -> Low on SDA while SCL is High) | ||||
* Set bit-bang mode on X550 hardware. | |||||
**/ | **/ | ||||
static void ixgbe_i2c_start(struct ixgbe_hw *hw) | static void ixgbe_i2c_start(struct ixgbe_hw *hw) | ||||
{ | { | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
DEBUGFUNC("ixgbe_i2c_start"); | DEBUGFUNC("ixgbe_i2c_start"); | ||||
i2cctl |= IXGBE_I2C_BB_EN_BY_MAC(hw); | |||||
/* Start condition must begin with data and clock high */ | /* Start condition must begin with data and clock high */ | ||||
ixgbe_set_i2c_data(hw, &i2cctl, 1); | ixgbe_set_i2c_data(hw, &i2cctl, 1); | ||||
ixgbe_raise_i2c_clk(hw, &i2cctl); | ixgbe_raise_i2c_clk(hw, &i2cctl); | ||||
Context not available. | |||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
* | * | ||||
* Sets I2C stop condition (Low -> High on SDA while SCL is High) | * Sets I2C stop condition (Low -> High on SDA while SCL is High) | ||||
* Disables bit-bang mode and negates data output enable on X550 | |||||
* hardware. | |||||
**/ | **/ | ||||
static void ixgbe_i2c_stop(struct ixgbe_hw *hw) | static void ixgbe_i2c_stop(struct ixgbe_hw *hw) | ||||
{ | { | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | |||||
u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); | |||||
u32 bb_en_bit = IXGBE_I2C_BB_EN_BY_MAC(hw); | |||||
DEBUGFUNC("ixgbe_i2c_stop"); | DEBUGFUNC("ixgbe_i2c_stop"); | ||||
Context not available. | |||||
/* bus free time between stop and start (4.7us)*/ | /* bus free time between stop and start (4.7us)*/ | ||||
usec_delay(IXGBE_I2C_T_BUF); | usec_delay(IXGBE_I2C_T_BUF); | ||||
if (bb_en_bit || data_oe_bit || clk_oe_bit) { | |||||
i2cctl &= ~bb_en_bit; | |||||
i2cctl |= data_oe_bit | clk_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
Context not available. | |||||
DEBUGFUNC("ixgbe_clock_in_i2c_byte"); | DEBUGFUNC("ixgbe_clock_in_i2c_byte"); | ||||
*data = 0; | |||||
for (i = 7; i >= 0; i--) { | for (i = 7; i >= 0; i--) { | ||||
ixgbe_clock_in_i2c_bit(hw, &bit); | ixgbe_clock_in_i2c_bit(hw, &bit); | ||||
*data |= bit << i; | *data |= bit << i; | ||||
Context not available. | |||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
s32 i; | s32 i; | ||||
u32 i2cctl; | u32 i2cctl; | ||||
bool bit = 0; | bool bit; | ||||
DEBUGFUNC("ixgbe_clock_out_i2c_byte"); | DEBUGFUNC("ixgbe_clock_out_i2c_byte"); | ||||
Context not available. | |||||
} | } | ||||
/* Release SDA line (set high) */ | /* Release SDA line (set high) */ | ||||
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
i2cctl |= IXGBE_I2C_DATA_OUT; | i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); | ||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl); | i2cctl |= IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | ||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
return status; | return status; | ||||
Context not available. | |||||
**/ | **/ | ||||
static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) | static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) | ||||
{ | { | ||||
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | |||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
u32 i = 0; | u32 i = 0; | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
u32 timeout = 10; | u32 timeout = 10; | ||||
bool ack = 1; | bool ack = 1; | ||||
DEBUGFUNC("ixgbe_get_i2c_ack"); | DEBUGFUNC("ixgbe_get_i2c_ack"); | ||||
if (data_oe_bit) { | |||||
i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); | |||||
i2cctl |= data_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | |||||
} | |||||
ixgbe_raise_i2c_clk(hw, &i2cctl); | ixgbe_raise_i2c_clk(hw, &i2cctl); | ||||
/* Minimum high period of clock is 4us */ | /* Minimum high period of clock is 4us */ | ||||
usec_delay(IXGBE_I2C_T_HIGH); | usec_delay(IXGBE_I2C_T_HIGH); | ||||
Context not available. | |||||
/* Poll for ACK. Note that ACK in I2C spec is | /* Poll for ACK. Note that ACK in I2C spec is | ||||
* transition from 1 to 0 */ | * transition from 1 to 0 */ | ||||
for (i = 0; i < timeout; i++) { | for (i = 0; i < timeout; i++) { | ||||
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
ack = ixgbe_get_i2c_data(&i2cctl); | ack = ixgbe_get_i2c_data(hw, &i2cctl); | ||||
usec_delay(1); | usec_delay(1); | ||||
if (ack == 0) | if (!ack) | ||||
break; | break; | ||||
} | } | ||||
if (ack == 1) { | if (ack) { | ||||
ERROR_REPORT1(IXGBE_ERROR_POLLING, | DEBUGOUT("I2C ack was not received.\n"); | ||||
"I2C ack was not received.\n"); | |||||
status = IXGBE_ERR_I2C; | status = IXGBE_ERR_I2C; | ||||
} | } | ||||
Context not available. | |||||
**/ | **/ | ||||
static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) | static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data) | ||||
{ | { | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | |||||
DEBUGFUNC("ixgbe_clock_in_i2c_bit"); | DEBUGFUNC("ixgbe_clock_in_i2c_bit"); | ||||
if (data_oe_bit) { | |||||
i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); | |||||
i2cctl |= data_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | |||||
} | |||||
ixgbe_raise_i2c_clk(hw, &i2cctl); | ixgbe_raise_i2c_clk(hw, &i2cctl); | ||||
/* Minimum high period of clock is 4us */ | /* Minimum high period of clock is 4us */ | ||||
usec_delay(IXGBE_I2C_T_HIGH); | usec_delay(IXGBE_I2C_T_HIGH); | ||||
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
*data = ixgbe_get_i2c_data(&i2cctl); | *data = ixgbe_get_i2c_data(hw, &i2cctl); | ||||
ixgbe_lower_i2c_clk(hw, &i2cctl); | ixgbe_lower_i2c_clk(hw, &i2cctl); | ||||
Context not available. | |||||
static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) | static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) | ||||
{ | { | ||||
s32 status; | s32 status; | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
DEBUGFUNC("ixgbe_clock_out_i2c_bit"); | DEBUGFUNC("ixgbe_clock_out_i2c_bit"); | ||||
Context not available. | |||||
return status; | return status; | ||||
} | } | ||||
/** | /** | ||||
* ixgbe_raise_i2c_clk - Raises the I2C SCL clock | * ixgbe_raise_i2c_clk - Raises the I2C SCL clock | ||||
* @hw: pointer to hardware structure | * @hw: pointer to hardware structure | ||||
Context not available. | |||||
* @i2cctl: Current value of I2CCTL register | * @i2cctl: Current value of I2CCTL register | ||||
* | * | ||||
* Raises the I2C clock line '0'->'1' | * Raises the I2C clock line '0'->'1' | ||||
* Negates the I2C clock output enable on X550 hardware. | |||||
**/ | **/ | ||||
static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) | static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) | ||||
{ | { | ||||
u32 clk_oe_bit = IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); | |||||
u32 i = 0; | u32 i = 0; | ||||
u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; | u32 timeout = IXGBE_I2C_CLOCK_STRETCHING_TIMEOUT; | ||||
u32 i2cctl_r = 0; | u32 i2cctl_r = 0; | ||||
Context not available. | |||||
DEBUGFUNC("ixgbe_raise_i2c_clk"); | DEBUGFUNC("ixgbe_raise_i2c_clk"); | ||||
if (clk_oe_bit) { | |||||
*i2cctl |= clk_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | |||||
} | |||||
for (i = 0; i < timeout; i++) { | for (i = 0; i < timeout; i++) { | ||||
*i2cctl |= IXGBE_I2C_CLK_OUT; | *i2cctl |= IXGBE_I2C_CLK_OUT_BY_MAC(hw); | ||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); | IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | ||||
IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
/* SCL rise time (1000ns) */ | /* SCL rise time (1000ns) */ | ||||
usec_delay(IXGBE_I2C_T_RISE); | usec_delay(IXGBE_I2C_T_RISE); | ||||
i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | i2cctl_r = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
if (i2cctl_r & IXGBE_I2C_CLK_IN) | if (i2cctl_r & IXGBE_I2C_CLK_IN_BY_MAC(hw)) | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
Context not available. | |||||
* @i2cctl: Current value of I2CCTL register | * @i2cctl: Current value of I2CCTL register | ||||
* | * | ||||
* Lowers the I2C clock line '1'->'0' | * Lowers the I2C clock line '1'->'0' | ||||
* Asserts the I2C clock output enable on X550 hardware. | |||||
**/ | **/ | ||||
static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) | static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) | ||||
{ | { | ||||
DEBUGFUNC("ixgbe_lower_i2c_clk"); | DEBUGFUNC("ixgbe_lower_i2c_clk"); | ||||
*i2cctl &= ~IXGBE_I2C_CLK_OUT; | *i2cctl &= ~(IXGBE_I2C_CLK_OUT_BY_MAC(hw)); | ||||
*i2cctl &= ~IXGBE_I2C_CLK_OE_N_EN_BY_MAC(hw); | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); | IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | ||||
IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
/* SCL fall time (300ns) */ | /* SCL fall time (300ns) */ | ||||
Context not available. | |||||
* @data: I2C data value (0 or 1) to set | * @data: I2C data value (0 or 1) to set | ||||
* | * | ||||
* Sets the I2C data bit | * Sets the I2C data bit | ||||
* Asserts the I2C data output enable on X550 hardware. | |||||
**/ | **/ | ||||
static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) | static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) | ||||
{ | { | ||||
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | |||||
s32 status = IXGBE_SUCCESS; | s32 status = IXGBE_SUCCESS; | ||||
DEBUGFUNC("ixgbe_set_i2c_data"); | DEBUGFUNC("ixgbe_set_i2c_data"); | ||||
if (data) | if (data) | ||||
*i2cctl |= IXGBE_I2C_DATA_OUT; | *i2cctl |= IXGBE_I2C_DATA_OUT_BY_MAC(hw); | ||||
else | else | ||||
*i2cctl &= ~IXGBE_I2C_DATA_OUT; | *i2cctl &= ~(IXGBE_I2C_DATA_OUT_BY_MAC(hw)); | ||||
*i2cctl &= ~data_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); | IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | ||||
IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ | /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ | ||||
usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); | usec_delay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); | ||||
if (!data) /* Can't verify data in this case */ | |||||
return IXGBE_SUCCESS; | |||||
if (data_oe_bit) { | |||||
*i2cctl |= data_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | |||||
} | |||||
/* Verify data was set correctly */ | /* Verify data was set correctly */ | ||||
*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | ||||
if (data != ixgbe_get_i2c_data(i2cctl)) { | if (data != ixgbe_get_i2c_data(hw, i2cctl)) { | ||||
status = IXGBE_ERR_I2C; | status = IXGBE_ERR_I2C; | ||||
ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, | ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, | ||||
"Error - I2C data was not set to %X.\n", | "Error - I2C data was not set to %X.\n", | ||||
Context not available. | |||||
* @i2cctl: Current value of I2CCTL register | * @i2cctl: Current value of I2CCTL register | ||||
* | * | ||||
* Returns the I2C data bit value | * Returns the I2C data bit value | ||||
* Negates the I2C data output enable on X550 hardware. | |||||
**/ | **/ | ||||
static bool ixgbe_get_i2c_data(u32 *i2cctl) | static bool ixgbe_get_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl) | ||||
{ | { | ||||
u32 data_oe_bit = IXGBE_I2C_DATA_OE_N_EN_BY_MAC(hw); | |||||
bool data; | bool data; | ||||
DEBUGFUNC("ixgbe_get_i2c_data"); | DEBUGFUNC("ixgbe_get_i2c_data"); | ||||
if (*i2cctl & IXGBE_I2C_DATA_IN) | if (data_oe_bit) { | ||||
*i2cctl |= data_oe_bit; | |||||
IXGBE_WRITE_REG(hw, IXGBE_I2CCTL_BY_MAC(hw), *i2cctl); | |||||
IXGBE_WRITE_FLUSH(hw); | |||||
usec_delay(IXGBE_I2C_T_FALL); | |||||
} | |||||
if (*i2cctl & IXGBE_I2C_DATA_IN_BY_MAC(hw)) | |||||
data = 1; | data = 1; | ||||
else | else | ||||
data = 0; | data = 0; | ||||
Context not available. | |||||
**/ | **/ | ||||
void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) | void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) | ||||
{ | { | ||||
u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); | u32 i2cctl; | ||||
u32 i; | u32 i; | ||||
DEBUGFUNC("ixgbe_i2c_bus_clear"); | DEBUGFUNC("ixgbe_i2c_bus_clear"); | ||||
ixgbe_i2c_start(hw); | ixgbe_i2c_start(hw); | ||||
i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL_BY_MAC(hw)); | |||||
ixgbe_set_i2c_data(hw, &i2cctl, 1); | ixgbe_set_i2c_data(hw, &i2cctl, 1); | ||||
Context not available. | |||||
out: | out: | ||||
return status; | return status; | ||||
} | } | ||||
/** | |||||
* ixgbe_set_copper_phy_power - Control power for copper phy | |||||
* @hw: pointer to hardware structure | |||||
* @on: TRUE for on, FALSE for off | |||||
*/ | |||||
s32 ixgbe_set_copper_phy_power(struct ixgbe_hw *hw, bool on) | |||||
{ | |||||
u32 status; | |||||
u16 reg; | |||||
status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL, | |||||
IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, | |||||
®); | |||||
if (status) | |||||
return status; | |||||
if (on) { | |||||
reg &= ~IXGBE_MDIO_PHY_SET_LOW_POWER_MODE; | |||||
} else { | |||||
if (ixgbe_check_reset_blocked(hw)) | |||||
return 0; | |||||
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); | |||||
return status; | |||||
} | |||||
Context not available. |