ixgbe: Add X550EM_x dual-speed SFP+ support

This patch adds X550EM_x SFP+ dual-speed support. 82599 fiber link
code was moved from ixgbe_82599.c to ixgbe_common.c for use by
X550EM. SFP MAC link code is added to x550EM.

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:28 -07:00 committed by Jeff Kirsher
parent 56f6ed1ce1
commit 6d373a1bbb
6 changed files with 263 additions and 167 deletions

View File

@ -44,9 +44,8 @@
static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete);
static void
ixgbe_set_hard_rate_select_speed(struct ixgbe_hw *, ixgbe_link_speed);
static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete);
@ -109,6 +108,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
if (hw->phy.multispeed_fiber) {
/* Set up dual speed SFP+ support */
mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
mac->ops.setup_mac_link = ixgbe_setup_mac_link_82599;
mac->ops.set_rate_select_speed =
ixgbe_set_hard_rate_select_speed;
} else {
if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) &&
@ -646,176 +648,32 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
}
/**
* ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg_wait_to_complete: true when waiting for completion is needed
* ixgbe_set_hard_rate_select_speed - Set module link speed
* @hw: pointer to hardware structure
* @speed: link speed to set
*
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete)
* Set module link speed via RS0/RS1 rate select pins.
*/
static void
ixgbe_set_hard_rate_select_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed)
{
s32 status = 0;
ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN;
u32 speedcnt = 0;
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
u32 i = 0;
bool link_up = false;
bool autoneg = false;
/* Mask off requested but non-supported speeds */
status = hw->mac.ops.get_link_capabilities(hw, &link_speed,
&autoneg);
if (status != 0)
return status;
speed &= link_speed;
/*
* Try each speed one by one, highest priority first. We do this in
* software because 10gb fiber doesn't support speed autonegotiation.
*/
if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
speedcnt++;
highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL;
/* If we already have link at this speed, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status != 0)
return status;
if ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up)
goto out;
/* Set the module link speed */
switch (hw->phy.media_type) {
case ixgbe_media_type_fiber:
esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
break;
case ixgbe_media_type_fiber_qsfp:
/* QSFP module automatically detects MAC link speed */
break;
default:
hw_dbg(hw, "Unexpected media type.\n");
break;
}
/* Allow module to change analog characteristics (1G->10G) */
msleep(40);
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_10GB_FULL,
autoneg_wait_to_complete);
if (status != 0)
return status;
/* Flap the tx laser if it has not already been done */
if (hw->mac.ops.flap_tx_laser)
hw->mac.ops.flap_tx_laser(hw);
/*
* Wait for the controller to acquire link. Per IEEE 802.3ap,
* Section 73.10.2, we may have to wait up to 500ms if KR is
* attempted. 82599 uses the same timing for 10g SFI.
*/
for (i = 0; i < 5; i++) {
/* Wait for the link partner to also set speed */
msleep(100);
/* If we have link, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed,
&link_up, false);
if (status != 0)
return status;
if (link_up)
goto out;
}
switch (speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
break;
case IXGBE_LINK_SPEED_1GB_FULL:
esdp_reg &= ~IXGBE_ESDP_SDP5;
esdp_reg |= IXGBE_ESDP_SDP5_DIR;
break;
default:
hw_dbg(hw, "Invalid fixed module speed\n");
return;
}
if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
speedcnt++;
if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN)
highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL;
/* If we already have link at this speed, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status != 0)
return status;
if ((link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up)
goto out;
/* Set the module link speed */
switch (hw->phy.media_type) {
case ixgbe_media_type_fiber:
esdp_reg &= ~IXGBE_ESDP_SDP5;
esdp_reg |= IXGBE_ESDP_SDP5_DIR;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
break;
case ixgbe_media_type_fiber_qsfp:
/* QSFP module automatically detects MAC link speed */
break;
default:
hw_dbg(hw, "Unexpected media type.\n");
break;
}
/* Allow module to change analog characteristics (10G->1G) */
msleep(40);
status = ixgbe_setup_mac_link_82599(hw,
IXGBE_LINK_SPEED_1GB_FULL,
autoneg_wait_to_complete);
if (status != 0)
return status;
/* Flap the tx laser if it has not already been done */
if (hw->mac.ops.flap_tx_laser)
hw->mac.ops.flap_tx_laser(hw);
/* Wait for the link partner to also set speed */
msleep(100);
/* If we have link, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status != 0)
return status;
if (link_up)
goto out;
}
/*
* We didn't get link. Configure back to the highest speed we tried,
* (if there was more than one). We call ourselves back with just the
* single highest speed that the user requested.
*/
if (speedcnt > 1)
status = ixgbe_setup_mac_link_multispeed_fiber(hw,
highest_link_speed,
autoneg_wait_to_complete);
out:
/* Set autoneg_advertised value based on input link speed */
hw->phy.autoneg_advertised = 0;
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
return status;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw);
}
/**

View File

@ -3920,3 +3920,213 @@ bool ixgbe_mng_present(struct ixgbe_hw *hw)
fwsm &= IXGBE_FWSM_MODE_MASK;
return fwsm == IXGBE_FWSM_FW_MODE_PT;
}
/**
* ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
* @hw: pointer to hardware structure
* @speed: new link speed
* @autoneg_wait_to_complete: true when waiting for completion is needed
*
* Set the link speed in the MAC and/or PHY register and restarts link.
*/
s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete)
{
ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN;
s32 status = 0;
u32 speedcnt = 0;
u32 i = 0;
bool autoneg, link_up = false;
/* Mask off requested but non-supported speeds */
status = hw->mac.ops.get_link_capabilities(hw, &link_speed, &autoneg);
if (status)
return status;
speed &= link_speed;
/* Try each speed one by one, highest priority first. We do this in
* software because 10Gb fiber doesn't support speed autonegotiation.
*/
if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
speedcnt++;
highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL;
/* If we already have link at this speed, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status)
return status;
if (link_speed == IXGBE_LINK_SPEED_10GB_FULL && link_up)
goto out;
/* Set the module link speed */
switch (hw->phy.media_type) {
case ixgbe_media_type_fiber:
hw->mac.ops.set_rate_select_speed(hw,
IXGBE_LINK_SPEED_10GB_FULL);
break;
case ixgbe_media_type_fiber_qsfp:
/* QSFP module automatically detects MAC link speed */
break;
default:
hw_dbg(hw, "Unexpected media type\n");
break;
}
/* Allow module to change analog characteristics (1G->10G) */
msleep(40);
status = hw->mac.ops.setup_mac_link(hw,
IXGBE_LINK_SPEED_10GB_FULL,
autoneg_wait_to_complete);
if (status)
return status;
/* Flap the Tx laser if it has not already been done */
if (hw->mac.ops.flap_tx_laser)
hw->mac.ops.flap_tx_laser(hw);
/* Wait for the controller to acquire link. Per IEEE 802.3ap,
* Section 73.10.2, we may have to wait up to 500ms if KR is
* attempted. 82599 uses the same timing for 10g SFI.
*/
for (i = 0; i < 5; i++) {
/* Wait for the link partner to also set speed */
msleep(100);
/* If we have link, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed,
&link_up, false);
if (status)
return status;
if (link_up)
goto out;
}
}
if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
speedcnt++;
if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN)
highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL;
/* If we already have link at this speed, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status)
return status;
if (link_speed == IXGBE_LINK_SPEED_1GB_FULL && link_up)
goto out;
/* Set the module link speed */
switch (hw->phy.media_type) {
case ixgbe_media_type_fiber:
hw->mac.ops.set_rate_select_speed(hw,
IXGBE_LINK_SPEED_1GB_FULL);
break;
case ixgbe_media_type_fiber_qsfp:
/* QSFP module automatically detects link speed */
break;
default:
hw_dbg(hw, "Unexpected media type\n");
break;
}
/* Allow module to change analog characteristics (10G->1G) */
msleep(40);
status = hw->mac.ops.setup_mac_link(hw,
IXGBE_LINK_SPEED_1GB_FULL,
autoneg_wait_to_complete);
if (status)
return status;
/* Flap the Tx laser if it has not already been done */
if (hw->mac.ops.flap_tx_laser)
hw->mac.ops.flap_tx_laser(hw);
/* Wait for the link partner to also set speed */
msleep(100);
/* If we have link, just jump out */
status = hw->mac.ops.check_link(hw, &link_speed, &link_up,
false);
if (status)
return status;
if (link_up)
goto out;
}
/* We didn't get link. Configure back to the highest speed we tried,
* (if there was more than one). We call ourselves back with just the
* single highest speed that the user requested.
*/
if (speedcnt > 1)
status = ixgbe_setup_mac_link_multispeed_fiber(hw,
highest_link_speed,
autoneg_wait_to_complete);
out:
/* Set autoneg_advertised value based on input link speed */
hw->phy.autoneg_advertised = 0;
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
return status;
}
/**
* ixgbe_set_soft_rate_select_speed - Set module link speed
* @hw: pointer to hardware structure
* @speed: link speed to set
*
* Set module link speed via the soft rate select.
*/
void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw,
ixgbe_link_speed speed)
{
s32 status;
u8 rs, eeprom_data;
switch (speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
/* one bit mask same as setting on */
rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
break;
case IXGBE_LINK_SPEED_1GB_FULL:
rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
break;
default:
hw_dbg(hw, "Invalid fixed module speed\n");
return;
}
/* Set RS0 */
status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
&eeprom_data);
if (status) {
hw_dbg(hw, "Failed to read Rx Rate Select RS0\n");
return;
}
eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs;
status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
IXGBE_I2C_EEPROM_DEV_ADDR2,
eeprom_data);
if (status) {
hw_dbg(hw, "Failed to write Rx Rate Select RS0\n");
return;
}
}

View File

@ -135,6 +135,11 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
void ixgbe_disable_rx_generic(struct ixgbe_hw *hw);
void ixgbe_enable_rx_generic(struct ixgbe_hw *hw);
s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg_wait_to_complete);
void ixgbe_set_soft_rate_select_speed(struct ixgbe_hw *hw,
ixgbe_link_speed speed);
#define IXGBE_FAILED_READ_REG 0xffffffffU
#define IXGBE_FAILED_READ_CFG_DWORD 0xffffffffU

View File

@ -66,6 +66,9 @@
#define IXGBE_SFF_1GBASET_CAPABLE 0x8
#define IXGBE_SFF_10GBASESR_CAPABLE 0x10
#define IXGBE_SFF_10GBASELR_CAPABLE 0x20
#define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8
#define IXGBE_SFF_SOFT_RS_SELECT_10G 0x8
#define IXGBE_SFF_SOFT_RS_SELECT_1G 0x0
#define IXGBE_SFF_ADDRESSING_MODE 0x4
#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE 0x1
#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8

View File

@ -3256,9 +3256,11 @@ struct ixgbe_mac_operations {
void (*flap_tx_laser)(struct ixgbe_hw *);
void (*stop_link_on_d3)(struct ixgbe_hw *);
s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool);
s32 (*setup_mac_link)(struct ixgbe_hw *, ixgbe_link_speed, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *,
bool *);
void (*set_rate_select_speed)(struct ixgbe_hw *, ixgbe_link_speed);
/* Packet Buffer Manipulation */
void (*set_rxpba)(struct ixgbe_hw *, int, u32, int);

View File

@ -909,6 +909,20 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
return status;
}
/**
* ixgbe_setup_mac_link_sfp_x550em - Configure the KR PHY for SFP.
* @hw: pointer to hardware structure
*
* Configures the extern PHY and the integrated KR PHY for SFP support.
*/
static s32
ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
__always_unused bool autoneg_wait_to_complete)
{
return ixgbe_setup_ixfi_x550em(hw, &speed);
}
/**
* ixgbe_setup_mac_link_t_X550em - Sets the auto advertised link speed
* @hw: pointer to hardware structure
@ -1003,6 +1017,10 @@ static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
mac->ops.disable_tx_laser = NULL;
mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL;
mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em;
mac->ops.set_rate_select_speed =
ixgbe_set_soft_rate_select_speed;
break;
case ixgbe_media_type_copper:
mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;