Skip to content

Commit

Permalink
ixgbe: Update link setup code to better support autonegotiation of speed
Browse files Browse the repository at this point in the history
The current code has some flaws in it when performing autonegotiation,
especially on KX/KX4 links.  This patch updates the code to better handle
the autonegotiation states on link setup.  The patch also removes a redundant
link configuration call on driver load, and moves link configuration to
the ->open() path.

Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Peter P Waskiewicz Jr authored and David S. Miller committed Feb 6, 2009
1 parent bc97114 commit 3201d31
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 80 deletions.
114 changes: 44 additions & 70 deletions drivers/net/ixgbe/ixgbe_82598.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,18 +146,12 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw,
bool *autoneg)
{
s32 status = 0;
s32 autoc_reg;

autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);

if (hw->mac.link_settings_loaded) {
autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
autoc_reg |= hw->mac.link_attach_type;
autoc_reg |= hw->mac.link_mode_select;
}

switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) {
/*
* Determine link capabilities based on the stored value of AUTOC,
* which represents EEPROM defaults.
*/
switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) {
case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
*speed = IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = false;
Expand All @@ -176,9 +170,9 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw,
case IXGBE_AUTOC_LMS_KX4_AN:
case IXGBE_AUTOC_LMS_KX4_AN_1G_AN:
*speed = IXGBE_LINK_SPEED_UNKNOWN;
if (autoc_reg & IXGBE_AUTOC_KX4_SUPP)
if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP)
*speed |= IXGBE_LINK_SPEED_10GB_FULL;
if (autoc_reg & IXGBE_AUTOC_KX_SUPP)
if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP)
*speed |= IXGBE_LINK_SPEED_1GB_FULL;
*autoneg = true;
break;
Expand Down Expand Up @@ -390,27 +384,17 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
u32 i;
s32 status = 0;

autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);

if (hw->mac.link_settings_loaded) {
autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
autoc_reg |= hw->mac.link_attach_type;
autoc_reg |= hw->mac.link_mode_select;

IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
IXGBE_WRITE_FLUSH(hw);
msleep(50);
}

/* Restart link */
autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);

/* Only poll for autoneg to complete if specified to do so */
if (hw->phy.autoneg_wait_to_complete) {
if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN ||
hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
IXGBE_AUTOC_LMS_KX4_AN ||
(autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
links_reg = 0; /* Just in case Autoneg time = 0 */
for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
Expand Down Expand Up @@ -534,37 +518,43 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw,
* Set the link speed in the AUTOC register and restarts link.
**/
static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
ixgbe_link_speed speed, bool autoneg,
bool autoneg_wait_to_complete)
ixgbe_link_speed speed, bool autoneg,
bool autoneg_wait_to_complete)
{
s32 status = 0;
s32 status = 0;
ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
u32 curr_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
u32 autoc = curr_autoc;
u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK;

/* If speed is 10G, then check for CX4 or XAUI. */
if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
(!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4))) {
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
} else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg)) {
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
} else if (autoneg) {
/* BX mode - Autonegotiate 1G */
if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
else /* KX/KX4 mode */
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN;
} else {
/* Check to see if speed passed in is supported. */
ixgbe_get_link_capabilities_82598(hw, &link_capabilities, &autoneg);
speed &= link_capabilities;

if (speed == IXGBE_LINK_SPEED_UNKNOWN)
status = IXGBE_ERR_LINK_SETUP;

/* Set KX4/KX support according to speed requested */
else if (link_mode == IXGBE_AUTOC_LMS_KX4_AN ||
link_mode == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
autoc &= ~IXGBE_AUTOC_KX4_KX_SUPP_MASK;
if (speed & IXGBE_LINK_SPEED_10GB_FULL)
autoc |= IXGBE_AUTOC_KX4_SUPP;
if (speed & IXGBE_LINK_SPEED_1GB_FULL)
autoc |= IXGBE_AUTOC_KX_SUPP;
if (autoc != curr_autoc)
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
}

if (status == 0) {
hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete;

hw->mac.link_settings_loaded = true;
/*
* Setup and restart the link based on the new values in
* ixgbe_hw This will write the AUTOC register based on the new
* stored values
*/
ixgbe_setup_mac_link_82598(hw);
status = ixgbe_setup_mac_link_82598(hw);
}

return status;
Expand All @@ -587,10 +577,6 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
/* Restart autonegotiation on PHY */
status = hw->phy.ops.setup_link(hw);

/* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */
hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;

/* Set up MAC */
ixgbe_setup_mac_link_82598(hw);

Expand All @@ -617,10 +603,6 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw,
status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
autoneg_wait_to_complete);

/* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */
hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;

/* Set up MAC */
ixgbe_setup_mac_link_82598(hw);

Expand Down Expand Up @@ -720,24 +702,16 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);

/*
* AUTOC register which stores link settings gets cleared
* and reloaded from EEPROM after reset. We need to restore
* our stored value from init in case SW changed the attach
* type or speed. If this is the first time and link settings
* have not been stored, store default settings from AUTOC.
* Store the original AUTOC value if it has not been
* stored off yet. Otherwise restore the stored original
* AUTOC value since the reset operation sets back to deaults.
*/
autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
if (hw->mac.link_settings_loaded) {
autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE);
autoc &= ~(IXGBE_AUTOC_LMS_MASK);
autoc |= hw->mac.link_attach_type;
autoc |= hw->mac.link_mode_select;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
} else {
hw->mac.link_attach_type =
(autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
hw->mac.link_settings_loaded = true;
if (hw->mac.orig_link_settings_stored == false) {
hw->mac.orig_autoc = autoc;
hw->mac.orig_link_settings_stored = true;
} else if (autoc != hw->mac.orig_autoc) {
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc);
}

/* Store the permanent mac address */
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/ixgbe/ixgbe_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
/* Clear the VLAN filter table */
hw->mac.ops.clear_vfta(hw);

/* Set up link */
hw->mac.ops.setup_link(hw);

/* Clear statistics registers */
hw->mac.ops.clear_hw_cntrs(hw);

Expand Down
3 changes: 0 additions & 3 deletions drivers/net/ixgbe/ixgbe_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2799,9 +2799,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
hw->fc.send_xon = true;

/* select 10G link by default */
hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;

/* enable itr by default in dynamic mode */
adapter->itr_setting = 1;
adapter->eitr_param = 20000;
Expand Down
9 changes: 5 additions & 4 deletions drivers/net/ixgbe/ixgbe_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@
#define IXGBE_LED_OFF 0xF

/* AUTOC Bit Masks */
#define IXGBE_AUTOC_KX4_KX_SUPP_MASK 0xC0000000
#define IXGBE_AUTOC_KX4_SUPP 0x80000000
#define IXGBE_AUTOC_KX_SUPP 0x40000000
#define IXGBE_AUTOC_PAUSE 0x30000000
Expand Down Expand Up @@ -1456,11 +1457,11 @@ struct ixgbe_mac_info {
u32 max_tx_queues;
u32 max_rx_queues;
u32 max_msix_vectors;
u32 link_attach_type;
u32 link_mode_select;
bool link_settings_loaded;
u32 orig_autoc;
u32 orig_autoc2;
bool orig_link_settings_stored;
bool autoneg;
bool autoneg_failed;
bool autoneg_succeeded;
};

struct ixgbe_phy_info {
Expand Down

0 comments on commit 3201d31

Please sign in to comment.