Commit 61fac744 authored by Peter Waskiewicz's avatar Peter Waskiewicz Committed by David S. Miller

ixgbe: Power down PHY during driver resets

The PHY laser is still on during driver init.  It's allowing
garbage to hit our FIFO, which eventually can cause the entire
device to die.  Power down the laser while setting up the device,
and re-enable the laser before getting link.
Signed-off-by: default avatarPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 908ba2bf
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_MC_TBL_SIZE 128
#define IXGBE_82599_VFT_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128
void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed, ixgbe_link_speed speed,
...@@ -69,8 +71,14 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) ...@@ -69,8 +71,14 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
if (hw->phy.multispeed_fiber) { if (hw->phy.multispeed_fiber) {
/* Set up dual speed SFP+ support */ /* Set up dual speed SFP+ support */
mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber;
mac->ops.disable_tx_laser =
&ixgbe_disable_tx_laser_multispeed_fiber;
mac->ops.enable_tx_laser =
&ixgbe_enable_tx_laser_multispeed_fiber;
mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber; mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber;
} else { } else {
mac->ops.disable_tx_laser = NULL;
mac->ops.enable_tx_laser = NULL;
mac->ops.flap_tx_laser = NULL; mac->ops.flap_tx_laser = NULL;
if ((mac->ops.get_media_type(hw) == if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) && ixgbe_media_type_backplane) &&
...@@ -415,37 +423,63 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, ...@@ -415,37 +423,63 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
return status; return status;
} }
/** /**
* ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser * ixgbe_disable_tx_laser_multispeed_fiber - Disable Tx laser
* @hw: pointer to hardware structure * @hw: pointer to hardware structure
* *
* When the driver changes the link speeds that it can support, * The base drivers may require better control over SFP+ module
* it sets autotry_restart to true to indicate that we need to * PHY states. This includes selectively shutting down the Tx
* initiate a new autotry session with the link partner. To do * laser on the PHY, effectively halting physical link.
* so, we set the speed then disable and re-enable the tx laser, to
* alert the link partner that it also needs to restart autotry on its
* end. This is consistent with true clause 37 autoneg, which also
* involves a loss of signal.
**/ **/
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{ {
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n");
if (hw->mac.autotry_restart) {
/* Disable tx laser; allow 100us to go dark per spec */ /* Disable tx laser; allow 100us to go dark per spec */
esdp_reg |= IXGBE_ESDP_SDP3; esdp_reg |= IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_FLUSH(hw);
udelay(100); udelay(100);
}
/**
* ixgbe_enable_tx_laser_multispeed_fiber - Enable Tx laser
* @hw: pointer to hardware structure
*
* The base drivers may require better control over SFP+ module
* PHY states. This includes selectively turning on the Tx
* laser on the PHY, effectively starting physical link.
**/
void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
/* Enable tx laser; allow 100ms to light up */ /* Enable tx laser; allow 100ms to light up */
esdp_reg &= ~IXGBE_ESDP_SDP3; esdp_reg &= ~IXGBE_ESDP_SDP3;
IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_FLUSH(hw);
msleep(100); msleep(100);
}
/**
* ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser
* @hw: pointer to hardware structure
*
* When the driver changes the link speeds that it can support,
* it sets autotry_restart to true to indicate that we need to
* initiate a new autotry session with the link partner. To do
* so, we set the speed then disable and re-enable the tx laser, to
* alert the link partner that it also needs to restart autotry on its
* end. This is consistent with true clause 37 autoneg, which also
* involves a loss of signal.
**/
void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
{
hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n");
if (hw->mac.autotry_restart) {
ixgbe_disable_tx_laser_multispeed_fiber(hw);
ixgbe_enable_tx_laser_multispeed_fiber(hw);
hw->mac.autotry_restart = false; hw->mac.autotry_restart = false;
} }
} }
......
...@@ -2982,6 +2982,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ...@@ -2982,6 +2982,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
else else
ixgbe_configure_msi_and_legacy(adapter); ixgbe_configure_msi_and_legacy(adapter);
/* enable the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.enable_tx_laser(hw);
clear_bit(__IXGBE_DOWN, &adapter->state); clear_bit(__IXGBE_DOWN, &adapter->state);
ixgbe_napi_enable_all(adapter); ixgbe_napi_enable_all(adapter);
...@@ -3243,6 +3247,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ...@@ -3243,6 +3247,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* signal that we are down to the interrupt handler */ /* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state); set_bit(__IXGBE_DOWN, &adapter->state);
/* power down the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.disable_tx_laser(hw);
/* disable receive for all VFs and wait one second */ /* disable receive for all VFs and wait one second */
if (adapter->num_vfs) { if (adapter->num_vfs) {
/* ping all the active vfs to let them know we are going down */ /* ping all the active vfs to let them know we are going down */
...@@ -6253,6 +6261,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -6253,6 +6261,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
goto err_eeprom; goto err_eeprom;
} }
/* power down the optics */
if (hw->phy.multispeed_fiber)
hw->mac.ops.disable_tx_laser(hw);
init_timer(&adapter->watchdog_timer); init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = &ixgbe_watchdog; adapter->watchdog_timer.function = &ixgbe_watchdog;
adapter->watchdog_timer.data = (unsigned long)adapter; adapter->watchdog_timer.data = (unsigned long)adapter;
...@@ -6400,16 +6412,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) ...@@ -6400,16 +6412,6 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->sfp_timer); del_timer_sync(&adapter->sfp_timer);
cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->sfp_task); cancel_work_sync(&adapter->sfp_task);
if (adapter->hw.phy.multispeed_fiber) {
struct ixgbe_hw *hw = &adapter->hw;
/*
* Restart clause 37 autoneg, disable and re-enable
* the tx laser, to clear & alert the link partner
* that it needs to restart autotry
*/
hw->mac.autotry_restart = true;
hw->mac.ops.flap_tx_laser(hw);
}
cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->multispeed_fiber_task);
cancel_work_sync(&adapter->sfp_config_module_task); cancel_work_sync(&adapter->sfp_config_module_task);
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
......
...@@ -2398,6 +2398,8 @@ struct ixgbe_mac_operations { ...@@ -2398,6 +2398,8 @@ struct ixgbe_mac_operations {
s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
/* Link */ /* Link */
void (*disable_tx_laser)(struct ixgbe_hw *);
void (*enable_tx_laser)(struct ixgbe_hw *);
void (*flap_tx_laser)(struct ixgbe_hw *); void (*flap_tx_laser)(struct ixgbe_hw *);
s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool);
s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool);
......
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