Commit 7086400d authored by Alexander Duyck's avatar Alexander Duyck Committed by Jeff Kirsher

ixgbe: Combine SFP and multi-speed fiber task into single service task

This change is meant to address several race conditions with multi-speed
fiber SFP+ modules in 82599 adapters.  Specifically issues have been seen
in which both the SFP configuration and the multi-speed fiber configuration
are running simultaneously which will result in the device getting into an
erroneous link down state.
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Tested-by: default avatarEvan Swanson <evan.swanson@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent e606bfe7
...@@ -367,19 +367,20 @@ struct ixgbe_adapter { ...@@ -367,19 +367,20 @@ struct ixgbe_adapter {
#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19)
#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) #define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20)
#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22)
#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) #define IXGBE_FLAG_NEED_LINK_CONFIG (u32)(1 << 23)
#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) #define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 24)
#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 25)
#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) #define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 26)
#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 27)
#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) #define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 28)
#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) #define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 29)
#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30)
u32 flags2; u32 flags2;
#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1)
#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) #define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1)
#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) #define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2)
#define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4)
#define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5)
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u16 bd_number; u16 bd_number;
...@@ -455,13 +456,11 @@ struct ixgbe_adapter { ...@@ -455,13 +456,11 @@ struct ixgbe_adapter {
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct watchdog_task; struct work_struct watchdog_task;
struct work_struct sfp_task;
struct work_struct multispeed_fiber_task;
struct work_struct sfp_config_module_task;
struct work_struct fdir_reinit_task; struct work_struct fdir_reinit_task;
struct work_struct check_overtemp_task; struct work_struct check_overtemp_task;
struct work_struct service_task;
struct timer_list watchdog_timer; struct timer_list watchdog_timer;
struct timer_list sfp_timer; struct timer_list service_timer;
u32 fdir_pballoc; u32 fdir_pballoc;
u32 atr_sample_rate; u32 atr_sample_rate;
spinlock_t fdir_perfect_lock; spinlock_t fdir_perfect_lock;
...@@ -492,7 +491,8 @@ enum ixbge_state_t { ...@@ -492,7 +491,8 @@ enum ixbge_state_t {
__IXGBE_TESTING, __IXGBE_TESTING,
__IXGBE_RESETTING, __IXGBE_RESETTING,
__IXGBE_DOWN, __IXGBE_DOWN,
__IXGBE_SFP_MODULE_NOT_FOUND __IXGBE_SERVICE_SCHED,
__IXGBE_IN_SFP_INIT,
}; };
struct ixgbe_rsc_cb { struct ixgbe_rsc_cb {
......
...@@ -191,6 +191,22 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) ...@@ -191,6 +191,22 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
} }
static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
{
if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
!test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
schedule_work(&adapter->service_task);
}
static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
{
BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
/* flush memory to make sure state is correct before next watchog */
smp_mb__before_clear_bit();
clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
}
struct ixgbe_reg_info { struct ixgbe_reg_info {
u32 ofs; u32 ofs;
char *name; char *name;
...@@ -1858,15 +1874,19 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr) ...@@ -1858,15 +1874,19 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
if (eicr & IXGBE_EICR_GPI_SDP2) { if (eicr & IXGBE_EICR_GPI_SDP2) {
/* Clear the interrupt */ /* Clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
if (!test_bit(__IXGBE_DOWN, &adapter->state)) if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
schedule_work(&adapter->sfp_config_module_task); adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
ixgbe_service_event_schedule(adapter);
}
} }
if (eicr & IXGBE_EICR_GPI_SDP1) { if (eicr & IXGBE_EICR_GPI_SDP1) {
/* Clear the interrupt */ /* Clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
if (!test_bit(__IXGBE_DOWN, &adapter->state)) if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
schedule_work(&adapter->multispeed_fiber_task); adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
ixgbe_service_event_schedule(adapter);
}
} }
} }
...@@ -1937,8 +1957,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) ...@@ -1937,8 +1957,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
ixgbe_check_fan_failure(adapter, eicr); ixgbe_check_fan_failure(adapter, eicr);
/* re-enable the original interrupt state, no lsc, no queues */
if (!test_bit(__IXGBE_DOWN, &adapter->state)) if (!test_bit(__IXGBE_DOWN, &adapter->state))
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -3772,31 +3794,16 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw) ...@@ -3772,31 +3794,16 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
**/ **/
static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
{ {
struct ixgbe_hw *hw = &adapter->hw; /*
* We are assuming the worst case scenerio here, and that
* is that an SFP was inserted/removed after the reset
* but before SFP detection was enabled. As such the best
* solution is to just start searching as soon as we start
*/
if (adapter->hw.mac.type == ixgbe_mac_82598EB)
adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
if (hw->phy.multispeed_fiber) { adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
/*
* In multispeed fiber setups, the device may not have
* had a physical connection when the driver loaded.
* If that's the case, the initial link configuration
* couldn't get the MAC into 10G or 1G mode, so we'll
* never have a link status change interrupt fire.
* We need to try and force an autonegotiation
* session, then bring up link.
*/
if (hw->mac.ops.setup_sfp)
hw->mac.ops.setup_sfp(hw);
if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
schedule_work(&adapter->multispeed_fiber_task);
} else {
/*
* Direct Attach Cu and non-multispeed fiber modules
* still need to be configured properly prior to
* attempting link.
*/
if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
schedule_work(&adapter->sfp_config_module_task);
}
} }
/** /**
...@@ -3926,17 +3933,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ...@@ -3926,17 +3933,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
e_crit(drv, "Fan has stopped, replace the adapter\n"); e_crit(drv, "Fan has stopped, replace the adapter\n");
} }
/*
* For hot-pluggable SFP+ devices, a new SFP+ module may have
* arrived before interrupts were enabled but after probe. Such
* devices wouldn't have their type identified yet. We need to
* kick off the SFP+ module setup first, then try to bring up link.
* If we're not hot-pluggable SFP+, we just need to configure link
* and bring it up.
*/
if (hw->phy.type == ixgbe_phy_none)
schedule_work(&adapter->sfp_config_module_task);
/* enable transmits */ /* enable transmits */
netif_tx_start_all_queues(adapter->netdev); netif_tx_start_all_queues(adapter->netdev);
...@@ -3945,6 +3941,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ...@@ -3945,6 +3941,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->link_check_timeout = jiffies; adapter->link_check_timeout = jiffies;
mod_timer(&adapter->watchdog_timer, jiffies); mod_timer(&adapter->watchdog_timer, jiffies);
mod_timer(&adapter->service_timer, jiffies);
/* Set PF Reset Done bit so PF/VF Mail Ops can work */ /* Set PF Reset Done bit so PF/VF Mail Ops can work */
ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
...@@ -3957,6 +3954,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) ...@@ -3957,6 +3954,9 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
{ {
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
/* put off any impending NetWatchDogTimeout */
adapter->netdev->trans_start = jiffies;
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000); usleep_range(1000, 2000);
ixgbe_down(adapter); ixgbe_down(adapter);
...@@ -3985,10 +3985,20 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) ...@@ -3985,10 +3985,20 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_hw *hw = &adapter->hw;
int err; int err;
/* lock SFP init bit to prevent race conditions with the watchdog */
while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
usleep_range(1000, 2000);
/* clear all SFP and link config related flags while holding SFP_INIT */
adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP |
IXGBE_FLAG2_SFP_NEEDS_RESET);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
err = hw->mac.ops.init_hw(hw); err = hw->mac.ops.init_hw(hw);
switch (err) { switch (err) {
case 0: case 0:
case IXGBE_ERR_SFP_NOT_PRESENT: case IXGBE_ERR_SFP_NOT_PRESENT:
case IXGBE_ERR_SFP_NOT_SUPPORTED:
break; break;
case IXGBE_ERR_MASTER_REQUESTS_PENDING: case IXGBE_ERR_MASTER_REQUESTS_PENDING:
e_dev_err("master disable timed out\n"); e_dev_err("master disable timed out\n");
...@@ -4006,6 +4016,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) ...@@ -4006,6 +4016,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
e_dev_err("Hardware Error: %d\n", err); e_dev_err("Hardware Error: %d\n", err);
} }
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
/* reprogram the RAR[0] in case user changed it. */ /* reprogram the RAR[0] in case user changed it. */
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
IXGBE_RAH_AV); IXGBE_RAH_AV);
...@@ -4167,11 +4179,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ...@@ -4167,11 +4179,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
del_timer_sync(&adapter->sfp_timer);
del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->watchdog_timer);
cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->watchdog_task);
/* call carrier off first to avoid false dev_watchdog timeouts */
netif_carrier_off(netdev); netif_carrier_off(netdev);
netif_tx_disable(netdev); netif_tx_disable(netdev);
...@@ -4179,6 +4189,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter) ...@@ -4179,6 +4189,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter); ixgbe_napi_disable_all(adapter);
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
del_timer_sync(&adapter->service_timer);
/* Cleanup the affinity_hint CPU mask memory and callback */ /* Cleanup the affinity_hint CPU mask memory and callback */
for (i = 0; i < num_q_vectors; i++) { for (i = 0; i < num_q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
...@@ -5147,57 +5161,6 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) ...@@ -5147,57 +5161,6 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
ixgbe_reset_interrupt_capability(adapter); ixgbe_reset_interrupt_capability(adapter);
} }
/**
* ixgbe_sfp_timer - worker thread to find a missing module
* @data: pointer to our adapter struct
**/
static void ixgbe_sfp_timer(unsigned long data)
{
struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
/*
* Do the sfp_timer outside of interrupt context due to the
* delays that sfp+ detection requires
*/
schedule_work(&adapter->sfp_task);
}
/**
* ixgbe_sfp_task - worker thread to find a missing module
* @work: pointer to work_struct containing our data
**/
static void ixgbe_sfp_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
struct ixgbe_adapter,
sfp_task);
struct ixgbe_hw *hw = &adapter->hw;
if ((hw->phy.type == ixgbe_phy_nl) &&
(hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
s32 ret = hw->phy.ops.identify_sfp(hw);
if (ret == IXGBE_ERR_SFP_NOT_PRESENT)
goto reschedule;
ret = hw->phy.ops.reset(hw);
if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
e_dev_err("failed to initialize because an unsupported "
"SFP+ module type was detected.\n");
e_dev_err("Reload the driver after installing a "
"supported module.\n");
unregister_netdev(adapter->netdev);
} else {
e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
}
/* don't need this routine any more */
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
}
return;
reschedule:
if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
mod_timer(&adapter->sfp_timer,
round_jiffies(jiffies + (2 * HZ)));
}
/** /**
* ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
* @adapter: board private structure to initialize * @adapter: board private structure to initialize
...@@ -6041,65 +6004,6 @@ static void ixgbe_watchdog(unsigned long data) ...@@ -6041,65 +6004,6 @@ static void ixgbe_watchdog(unsigned long data)
schedule_work(&adapter->watchdog_task); schedule_work(&adapter->watchdog_task);
} }
/**
* ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
* @work: pointer to work_struct containing our data
**/
static void ixgbe_multispeed_fiber_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
struct ixgbe_adapter,
multispeed_fiber_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 autoneg;
bool negotiation;
adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
autoneg = hw->phy.autoneg_advertised;
if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
hw->mac.autotry_restart = false;
if (hw->mac.ops.setup_link)
hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
}
/**
* ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
* @work: pointer to work_struct containing our data
**/
static void ixgbe_sfp_config_module_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
struct ixgbe_adapter,
sfp_config_module_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 err;
adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
/* Time for electrical oscillations to settle down */
msleep(100);
err = hw->phy.ops.identify_sfp(hw);
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
e_dev_err("failed to initialize because an unsupported SFP+ "
"module type was detected.\n");
e_dev_err("Reload the driver after installing a supported "
"module.\n");
unregister_netdev(adapter->netdev);
return;
}
if (hw->mac.ops.setup_sfp)
hw->mac.ops.setup_sfp(hw);
if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
/* This will also work for DA Twinax connections */
schedule_work(&adapter->multispeed_fiber_task);
adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
}
/** /**
* ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table
* @work: pointer to work_struct containing our data * @work: pointer to work_struct containing our data
...@@ -6273,6 +6177,141 @@ static void ixgbe_watchdog_task(struct work_struct *work) ...@@ -6273,6 +6177,141 @@ static void ixgbe_watchdog_task(struct work_struct *work)
mutex_unlock(&ixgbe_watchdog_lock); mutex_unlock(&ixgbe_watchdog_lock);
} }
/**
* ixgbe_sfp_detection_subtask - poll for SFP+ cable
* @adapter - the ixgbe adapter structure
**/
static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
s32 err;
/* not searching for SFP so there is nothing to do here */
if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) &&
!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
return;
/* someone else is in init, wait until next service event */
if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
return;
err = hw->phy.ops.identify_sfp(hw);
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
goto sfp_out;
if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
/* If no cable is present, then we need to reset
* the next time we find a good cable. */
adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
}
/* exit on error */
if (err)
goto sfp_out;
/* exit if reset not needed */
if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
goto sfp_out;
adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET;
/*
* A module may be identified correctly, but the EEPROM may not have
* support for that module. setup_sfp() will fail in that case, so
* we should not allow that module to load.
*/
if (hw->mac.type == ixgbe_mac_82598EB)
err = hw->phy.ops.reset(hw);
else
err = hw->mac.ops.setup_sfp(hw);
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
goto sfp_out;
adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
sfp_out:
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
(adapter->netdev->reg_state == NETREG_REGISTERED)) {
e_dev_err("failed to initialize because an unsupported "
"SFP+ module type was detected.\n");
e_dev_err("Reload the driver after installing a "
"supported module.\n");
unregister_netdev(adapter->netdev);
}
}
/**
* ixgbe_sfp_link_config_subtask - set up link SFP after module install
* @adapter - the ixgbe adapter structure
**/
static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 autoneg;
bool negotiation;
if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
return;
/* someone else is in init, wait until next service event */
if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
return;
adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
autoneg = hw->phy.autoneg_advertised;
if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
hw->mac.autotry_restart = false;
if (hw->mac.ops.setup_link)
hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->link_check_timeout = jiffies;
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
}
/**
* ixgbe_service_timer - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
**/
static void ixgbe_service_timer(unsigned long data)
{
struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
unsigned long next_event_offset;
/* poll faster when waiting for link */
if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
next_event_offset = HZ / 10;
else
next_event_offset = HZ * 2;
/* Reset the timer */
mod_timer(&adapter->service_timer, next_event_offset + jiffies);
ixgbe_service_event_schedule(adapter);
}
/**
* ixgbe_service_task - manages and runs subtasks
* @work: pointer to work_struct containing our data
**/
static void ixgbe_service_task(struct work_struct *work)
{
struct ixgbe_adapter *adapter = container_of(work,
struct ixgbe_adapter,
service_task);
ixgbe_sfp_detection_subtask(adapter);
ixgbe_sfp_link_config_subtask(adapter);
ixgbe_service_event_complete(adapter);
}
static int ixgbe_tso(struct ixgbe_adapter *adapter, static int ixgbe_tso(struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring, struct sk_buff *skb, struct ixgbe_ring *tx_ring, struct sk_buff *skb,
u32 tx_flags, u8 *hdr_len, __be16 protocol) u32 tx_flags, u8 *hdr_len, __be16 protocol)
...@@ -7317,22 +7356,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7317,22 +7356,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->phy.mdio.mdio_read = ixgbe_mdio_read; hw->phy.mdio.mdio_read = ixgbe_mdio_read;
hw->phy.mdio.mdio_write = ixgbe_mdio_write; hw->phy.mdio.mdio_write = ixgbe_mdio_write;
/* set up this timer and work struct before calling get_invariants
* which might start the timer
*/
init_timer(&adapter->sfp_timer);
adapter->sfp_timer.function = ixgbe_sfp_timer;
adapter->sfp_timer.data = (unsigned long) adapter;
INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
/* multispeed fiber has its own tasklet, called from GPI SDP1 context */
INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
/* a new SFP+ module arrival, called from GPI SDP2 context */
INIT_WORK(&adapter->sfp_config_module_task,
ixgbe_sfp_config_module_task);
ii->get_invariants(hw); ii->get_invariants(hw);
/* setup the private structure */ /* setup the private structure */
...@@ -7366,17 +7389,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7366,17 +7389,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->phy.reset_if_overtemp = false; hw->phy.reset_if_overtemp = false;
if (err == IXGBE_ERR_SFP_NOT_PRESENT && if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
hw->mac.type == ixgbe_mac_82598EB) { hw->mac.type == ixgbe_mac_82598EB) {
/*
* Start a kernel thread to watch for a module to arrive.
* Only do this for 82598, since 82599 will generate
* interrupts on module arrival.
*/
set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
mod_timer(&adapter->sfp_timer,
round_jiffies(jiffies + (2 * HZ)));
err = 0; err = 0;
} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
e_dev_err("failed to initialize because an unsupported SFP+ " e_dev_err("failed to load because an unsupported SFP+ "
"module type was detected.\n"); "module type was detected.\n");
e_dev_err("Reload the driver after installing a supported " e_dev_err("Reload the driver after installing a supported "
"module.\n"); "module.\n");
...@@ -7468,6 +7483,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7468,6 +7483,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
(hw->mac.type == ixgbe_mac_82599EB)))) (hw->mac.type == ixgbe_mac_82599EB))))
hw->mac.ops.disable_tx_laser(hw); hw->mac.ops.disable_tx_laser(hw);
setup_timer(&adapter->service_timer, &ixgbe_service_timer,
(unsigned long) adapter);
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;
...@@ -7475,6 +7492,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7475,6 +7492,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->reset_task, ixgbe_reset_task); INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task);
INIT_WORK(&adapter->service_task, ixgbe_service_task);
clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
err = ixgbe_init_interrupt_scheme(adapter); err = ixgbe_init_interrupt_scheme(adapter);
if (err) if (err)
goto err_sw_init; goto err_sw_init;
...@@ -7593,11 +7613,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, ...@@ -7593,11 +7613,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err_eeprom: err_eeprom:
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
ixgbe_disable_sriov(adapter); ixgbe_disable_sriov(adapter);
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
del_timer_sync(&adapter->sfp_timer);
cancel_work_sync(&adapter->sfp_task);
cancel_work_sync(&adapter->multispeed_fiber_task);
cancel_work_sync(&adapter->sfp_config_module_task);
iounmap(hw->hw_addr); iounmap(hw->hw_addr);
err_ioremap: err_ioremap:
free_netdev(netdev); free_netdev(netdev);
...@@ -7625,19 +7641,15 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) ...@@ -7625,19 +7641,15 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
set_bit(__IXGBE_DOWN, &adapter->state); set_bit(__IXGBE_DOWN, &adapter->state);
cancel_work_sync(&adapter->service_task);
/* /*
* The timers may be rescheduled, so explicitly disable them * The timers may be rescheduled, so explicitly disable them
* from being rescheduled. * from being rescheduled.
*/ */
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->watchdog_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->multispeed_fiber_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 ||
adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
cancel_work_sync(&adapter->fdir_reinit_task); cancel_work_sync(&adapter->fdir_reinit_task);
......
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