ixgbe: Add I2C bus mux support

Take control of an I2C mux that selects which SFP is attached to
the I2C bus. The control of the mux is captured in the taking and
releasing of the related semaphore. Because only port 1 can control
the mux, port 1 always leaves the mux set to select port 0.

Signed-off-by: Mark Rustad <mark.d.rustad@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
Mark Rustad 2015-08-08 16:18:53 -07:00 committed by Jeff Kirsher
parent 58e7cd24d4
commit 449e21a924
3 changed files with 122 additions and 39 deletions

View File

@ -1949,6 +1949,7 @@ enum {
#define IXGBE_GSSR_SW_MNG_SM 0x0400 #define IXGBE_GSSR_SW_MNG_SM 0x0400
#define IXGBE_GSSR_SHARED_I2C_SM 0x1806 /* Wait for both phys & I2Cs */ #define IXGBE_GSSR_SHARED_I2C_SM 0x1806 /* Wait for both phys & I2Cs */
#define IXGBE_GSSR_I2C_MASK 0x1800 #define IXGBE_GSSR_I2C_MASK 0x1800
#define IXGBE_GSSR_NVM_PHY_MASK 0xF
/* FW Status register bitmask */ /* FW Status register bitmask */
#define IXGBE_FWSTS_FWRI 0x00000200 /* Firmware Reset Indication */ #define IXGBE_FWSTS_FWRI 0x00000200 /* Firmware Reset Indication */

View File

@ -567,19 +567,25 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw)
**/ **/
s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
{ {
u32 swfw_sync; u32 swmask = mask & IXGBE_GSSR_NVM_PHY_MASK;
u32 swmask = mask; u32 swi2c_mask = mask & IXGBE_GSSR_I2C_MASK;
u32 fwmask = mask << 5; u32 fwmask = swmask << 5;
u32 hwmask = 0;
u32 timeout = 200; u32 timeout = 200;
u32 hwmask = 0;
u32 swfw_sync;
u32 i; u32 i;
if (swmask == IXGBE_GSSR_EEP_SM) if (swmask & IXGBE_GSSR_EEP_SM)
hwmask = IXGBE_GSSR_FLASH_SM; hwmask = IXGBE_GSSR_FLASH_SM;
/* SW only mask does not have FW bit pair */
if (mask & IXGBE_GSSR_SW_MNG_SM)
swmask |= IXGBE_GSSR_SW_MNG_SM;
swmask |= swi2c_mask;
fwmask |= swi2c_mask << 2;
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
/* /* SW NVM semaphore bit is used for access to all
* SW NVM semaphore bit is used for access to all
* SW_FW_SYNC bits (not just NVM) * SW_FW_SYNC bits (not just NVM)
*/ */
if (ixgbe_get_swfw_sync_semaphore(hw)) if (ixgbe_get_swfw_sync_semaphore(hw))
@ -590,40 +596,57 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
swfw_sync |= swmask; swfw_sync |= swmask;
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync); IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw); ixgbe_release_swfw_sync_semaphore(hw);
break; usleep_range(5000, 6000);
} else { return 0;
/* }
* Firmware currently using resource (fwmask), /* Firmware currently using resource (fwmask), hardware
* hardware currently using resource (hwmask), * currently using resource (hwmask), or other software
* or other software thread currently using * thread currently using resource (swmask)
* resource (swmask)
*/ */
ixgbe_release_swfw_sync_semaphore(hw); ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 10000); usleep_range(5000, 10000);
} }
/* Failed to get SW only semaphore */
if (swmask == IXGBE_GSSR_SW_MNG_SM) {
hw_dbg(hw, "Failed to get SW only semaphore\n");
return IXGBE_ERR_SWFW_SYNC;
} }
/* /* If the resource is not released by the FW/HW the SW can assume that
* If the resource is not released by the FW/HW the SW can assume that * the FW/HW malfunctions. In that case the SW should set the SW bit(s)
* the FW/HW malfunctions. In that case the SW should sets the * of the requested resource(s) while ignoring the corresponding FW/HW
* SW bit(s) of the requested resource(s) while ignoring the * bits in the SW_FW_SYNC register.
* corresponding FW/HW bits in the SW_FW_SYNC register.
*/ */
if (i >= timeout) {
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (swfw_sync & (fwmask | hwmask)) {
if (ixgbe_get_swfw_sync_semaphore(hw)) if (ixgbe_get_swfw_sync_semaphore(hw))
return IXGBE_ERR_SWFW_SYNC; return IXGBE_ERR_SWFW_SYNC;
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (swfw_sync & (fwmask | hwmask)) {
swfw_sync |= swmask; swfw_sync |= swmask;
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync); IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw); ixgbe_release_swfw_sync_semaphore(hw);
} usleep_range(5000, 6000);
}
usleep_range(5000, 10000);
return 0; return 0;
} }
/* If the resource is not released by other SW the SW can assume that
* the other SW malfunctions. In that case the SW should clear all SW
* flags that it does not own and then repeat the whole process once
* again.
*/
if (swfw_sync & swmask) {
u32 rmask = IXGBE_GSSR_EEP_SM | IXGBE_GSSR_PHY0_SM |
IXGBE_GSSR_PHY1_SM | IXGBE_GSSR_MAC_CSR_SM;
if (swi2c_mask)
rmask |= IXGBE_GSSR_I2C_MASK;
ixgbe_release_swfw_sync_X540(hw, rmask);
ixgbe_release_swfw_sync_semaphore(hw);
return IXGBE_ERR_SWFW_SYNC;
}
ixgbe_release_swfw_sync_semaphore(hw);
return IXGBE_ERR_SWFW_SYNC;
}
/** /**
* ixgbe_release_swfw_sync_X540 - Release SWFW semaphore * ixgbe_release_swfw_sync_X540 - Release SWFW semaphore
@ -635,9 +658,11 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
**/ **/
void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
{ {
u32 swmask = mask & (IXGBE_GSSR_NVM_PHY_MASK | IXGBE_GSSR_SW_MNG_SM);
u32 swfw_sync; u32 swfw_sync;
u32 swmask = mask;
if (mask & IXGBE_GSSR_I2C_MASK)
swmask |= mask & IXGBE_GSSR_I2C_MASK;
ixgbe_get_swfw_sync_semaphore(hw); ixgbe_get_swfw_sync_semaphore(hw);
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw)); swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
@ -645,7 +670,7 @@ void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync); IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw); ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 10000); usleep_range(5000, 6000);
} }
/** /**

View File

@ -2263,6 +2263,62 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw,
IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (u32)(pfflp >> 32)); IXGBE_WRITE_REG(hw, IXGBE_PFFLPH, (u32)(pfflp >> 32));
} }
/**
* ixgbe_set_mux - Set mux for port 1 access with CS4227
* @hw: pointer to hardware structure
* @state: set mux if 1, clear if 0
*/
static void ixgbe_set_mux(struct ixgbe_hw *hw, u8 state)
{
u32 esdp;
if (!hw->bus.lan_id)
return;
esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (state)
esdp |= IXGBE_ESDP_SDP1;
else
esdp &= ~IXGBE_ESDP_SDP1;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp);
IXGBE_WRITE_FLUSH(hw);
}
/**
* ixgbe_acquire_swfw_sync_X550em - Acquire SWFW semaphore
* @hw: pointer to hardware structure
* @mask: Mask to specify which semaphore to acquire
*
* Acquires the SWFW semaphore and sets the I2C MUX
*/
static s32 ixgbe_acquire_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
{
s32 status;
status = ixgbe_acquire_swfw_sync_X540(hw, mask);
if (status)
return status;
if (mask & IXGBE_GSSR_I2C_MASK)
ixgbe_set_mux(hw, 1);
return 0;
}
/**
* ixgbe_release_swfw_sync_X550em - Release SWFW semaphore
* @hw: pointer to hardware structure
* @mask: Mask to specify which semaphore to release
*
* Releases the SWFW semaphore and sets the I2C MUX
*/
static void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask)
{
if (mask & IXGBE_GSSR_I2C_MASK)
ixgbe_set_mux(hw, 0);
ixgbe_release_swfw_sync_X540(hw, mask);
}
#define X550_COMMON_MAC \ #define X550_COMMON_MAC \
.init_hw = &ixgbe_init_hw_generic, \ .init_hw = &ixgbe_init_hw_generic, \
.start_hw = &ixgbe_start_hw_X540, \ .start_hw = &ixgbe_start_hw_X540, \
@ -2300,8 +2356,6 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw,
&ixgbe_set_source_address_pruning_X550, \ &ixgbe_set_source_address_pruning_X550, \
.set_ethertype_anti_spoofing = \ .set_ethertype_anti_spoofing = \
&ixgbe_set_ethertype_anti_spoofing_X550, \ &ixgbe_set_ethertype_anti_spoofing_X550, \
.acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540, \
.release_swfw_sync = &ixgbe_release_swfw_sync_X540, \
.disable_rx_buff = &ixgbe_disable_rx_buff_generic, \ .disable_rx_buff = &ixgbe_disable_rx_buff_generic, \
.enable_rx_buff = &ixgbe_enable_rx_buff_generic, \ .enable_rx_buff = &ixgbe_enable_rx_buff_generic, \
.get_thermal_sensor_data = NULL, \ .get_thermal_sensor_data = NULL, \
@ -2321,6 +2375,8 @@ static struct ixgbe_mac_operations mac_ops_X550 = {
.get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic,
.get_bus_info = &ixgbe_get_bus_info_generic, .get_bus_info = &ixgbe_get_bus_info_generic,
.setup_sfp = NULL, .setup_sfp = NULL,
.acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540,
.release_swfw_sync = &ixgbe_release_swfw_sync_X540,
}; };
static struct ixgbe_mac_operations mac_ops_X550EM_x = { static struct ixgbe_mac_operations mac_ops_X550EM_x = {
@ -2333,7 +2389,8 @@ static struct ixgbe_mac_operations mac_ops_X550EM_x = {
.get_link_capabilities = &ixgbe_get_link_capabilities_X550em, .get_link_capabilities = &ixgbe_get_link_capabilities_X550em,
.get_bus_info = &ixgbe_get_bus_info_X550em, .get_bus_info = &ixgbe_get_bus_info_X550em,
.setup_sfp = ixgbe_setup_sfp_modules_X550em, .setup_sfp = ixgbe_setup_sfp_modules_X550em,
.acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X550em,
.release_swfw_sync = &ixgbe_release_swfw_sync_X550em,
}; };
#define X550_COMMON_EEP \ #define X550_COMMON_EEP \