ixgbe: cleanup race conditions in link setup
This change makes it so that we perform link setup with interrupts disabled. If the SFP has not been detected previously we will schedule the SFP detection task to run in order to detect link. By doing this we avoid the possibility of interrupts firing in the middle of our link setup during ixgbe_up_complete. In addition this change makes it so that the multi-speed fiber setup and SFP setup are not mutually exclusive. The addresses issues seen in which a link would only come up at 1G on some multi-speed fiber modules. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Tested-by: Ross Brattain <ross.b.brattain@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
7d637bcc8f
commit
73c4b7cdd2
1 changed files with 19 additions and 28 deletions
|
@ -1712,17 +1712,18 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
|
|||
{
|
||||
struct ixgbe_hw *hw = &adapter->hw;
|
||||
|
||||
if (eicr & IXGBE_EICR_GPI_SDP2) {
|
||||
/* Clear the interrupt */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state))
|
||||
schedule_work(&adapter->sfp_config_module_task);
|
||||
}
|
||||
|
||||
if (eicr & IXGBE_EICR_GPI_SDP1) {
|
||||
/* Clear the interrupt */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
|
||||
schedule_work(&adapter->multispeed_fiber_task);
|
||||
} else if (eicr & IXGBE_EICR_GPI_SDP2) {
|
||||
/* Clear the interrupt */
|
||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
|
||||
schedule_work(&adapter->sfp_config_module_task);
|
||||
} else {
|
||||
/* Interrupt isn't for us... */
|
||||
return;
|
||||
if (!test_bit(__IXGBE_DOWN, &adapter->state))
|
||||
schedule_work(&adapter->multispeed_fiber_task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3587,6 +3588,14 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
|
|||
clear_bit(__IXGBE_DOWN, &adapter->state);
|
||||
ixgbe_napi_enable_all(adapter);
|
||||
|
||||
if (ixgbe_is_sfp(hw)) {
|
||||
ixgbe_sfp_link_config(adapter);
|
||||
} else {
|
||||
err = ixgbe_non_sfp_link_config(hw);
|
||||
if (err)
|
||||
e_err(probe, "link_config FAILED %d\n", err);
|
||||
}
|
||||
|
||||
/* clear any pending interrupts, may auto mask */
|
||||
IXGBE_READ_REG(hw, IXGBE_EICR);
|
||||
ixgbe_irq_enable(adapter, true, true);
|
||||
|
@ -3609,26 +3618,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
|
|||
* If we're not hot-pluggable SFP+, we just need to configure link
|
||||
* and bring it up.
|
||||
*/
|
||||
if (hw->phy.type == ixgbe_phy_unknown) {
|
||||
err = hw->phy.ops.identify(hw);
|
||||
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
|
||||
/*
|
||||
* Take the device down and schedule the sfp tasklet
|
||||
* which will unregister_netdev and log it.
|
||||
*/
|
||||
ixgbe_down(adapter);
|
||||
schedule_work(&adapter->sfp_config_module_task);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (ixgbe_is_sfp(hw)) {
|
||||
ixgbe_sfp_link_config(adapter);
|
||||
} else {
|
||||
err = ixgbe_non_sfp_link_config(hw);
|
||||
if (err)
|
||||
e_err(probe, "link_config FAILED %d\n", err);
|
||||
}
|
||||
if (hw->phy.type == ixgbe_phy_unknown)
|
||||
schedule_work(&adapter->sfp_config_module_task);
|
||||
|
||||
/* enable transmits */
|
||||
netif_tx_start_all_queues(adapter->netdev);
|
||||
|
|
Loading…
Reference in a new issue