Commit 449e21a9 authored by Mark Rustad's avatar Mark Rustad Committed by Jeff Kirsher

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: default avatarMark Rustad <mark.d.rustad@intel.com>
Tested-by: default avatarPhil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 58e7cd24
...@@ -1949,6 +1949,7 @@ enum { ...@@ -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 */
......
...@@ -567,19 +567,25 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) ...@@ -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,39 +596,56 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) ...@@ -590,39 +596,56 @@ 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),
* hardware currently using resource (hwmask),
* or other software thread currently using
* resource (swmask)
*/
ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 10000);
} }
/* Firmware currently using resource (fwmask), hardware
* currently using resource (hwmask), or other software
* thread currently using resource (swmask)
*/
ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 10000);
} }
/* /* Failed to get SW only semaphore */
* If the resource is not released by the FW/HW the SW can assume that if (swmask == IXGBE_GSSR_SW_MNG_SM) {
* the FW/HW malfunctions. In that case the SW should sets the hw_dbg(hw, "Failed to get SW only semaphore\n");
* SW bit(s) of the requested resource(s) while ignoring the return IXGBE_ERR_SWFW_SYNC;
* 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))
return IXGBE_ERR_SWFW_SYNC;
swfw_sync |= swmask; /* If the resource is not released by the FW/HW the SW can assume that
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync); * the FW/HW malfunctions. In that case the SW should set the SW bit(s)
ixgbe_release_swfw_sync_semaphore(hw); * of the requested resource(s) while ignoring the corresponding FW/HW
} * bits in the SW_FW_SYNC register.
*/
if (ixgbe_get_swfw_sync_semaphore(hw))
return IXGBE_ERR_SWFW_SYNC;
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (swfw_sync & (fwmask | hwmask)) {
swfw_sync |= swmask;
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC(hw), swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw);
usleep_range(5000, 6000);
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);
usleep_range(5000, 10000); return IXGBE_ERR_SWFW_SYNC;
return 0;
} }
/** /**
...@@ -635,9 +658,11 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask) ...@@ -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) ...@@ -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);
} }
/** /**
......
...@@ -2263,6 +2263,62 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, ...@@ -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, ...@@ -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 = { ...@@ -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 = { ...@@ -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 \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment