@@ -229,9 +229,6 @@ static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev);
static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev);
static void ixgbe_dev_interrupt_handler(void *param);
static void ixgbe_dev_interrupt_delayed_handler(void *param);
-static void *ixgbe_dev_setup_link_thread_handler(void *param);
-static int ixgbe_dev_wait_setup_link_complete(struct rte_eth_dev *dev,
- uint32_t timeout_ms);
static int ixgbe_add_rar(struct rte_eth_dev *dev,
struct rte_ether_addr *mac_addr,
@@ -766,6 +763,33 @@ static const struct rte_ixgbe_xstats_name_off rte_ixgbevf_stats_strings[] = {
#define IXGBEVF_NB_XSTATS (sizeof(rte_ixgbevf_stats_strings) / \
sizeof(rte_ixgbevf_stats_strings[0]))
+/**
+ * This function is the same as ixgbe_need_crosstalk_fix() in base/ixgbe_common.c
+ *
+ * ixgbe_need_crosstalk_fix - Determine if we need to do cross talk fix
+ * @hw: pointer to hardware structure
+ *
+ * Contains the logic to identify if we need to verify link for the
+ * crosstalk fix
+ **/
+static bool ixgbe_need_crosstalk_fix(struct ixgbe_hw *hw)
+{
+ /* Does FW say we need the fix */
+ if (!hw->need_crosstalk_fix)
+ return false;
+
+ /* Only consider SFP+ PHYs i.e. media type fiber */
+ switch (ixgbe_get_media_type(hw)) {
+ case ixgbe_media_type_fiber:
+ case ixgbe_media_type_fiber_qsfp:
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
/*
* This function is the same as ixgbe_is_sfp() in base/ixgbe.h.
*/
@@ -1032,6 +1056,306 @@ ixgbe_swfw_lock_reset(struct ixgbe_hw *hw)
ixgbe_release_swfw_semaphore(hw, mask);
}
+/**
+ * ixgbe_check_sfp_cage - Find present status of SFP module
+ * @hw: pointer to hardware structure
+ *
+ * Find if a SFP module is present and if this device supports SFPs
+ **/
+enum ixgbe_sfp_cage_status ixgbe_check_sfp_cage(struct ixgbe_hw *hw)
+{
+ enum ixgbe_sfp_cage_status sfp_cage_status;
+
+ /* If we're not a fiber/fiber_qsfp, no cage to check */
+ switch (hw->mac.ops.get_media_type(hw)) {
+ case ixgbe_media_type_fiber:
+ case ixgbe_media_type_fiber_qsfp:
+ break;
+ default:
+ return IXGBE_SFP_CAGE_NOCAGE;
+ }
+
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ sfp_cage_status = !!(IXGBE_READ_REG(hw, IXGBE_ESDP) &
+ IXGBE_ESDP_SDP2);
+ break;
+ case ixgbe_mac_X550EM_x:
+ case ixgbe_mac_X550EM_a:
+ /* SDP0 is the active low signal PRSNT#, so invert this */
+ sfp_cage_status = !(IXGBE_READ_REG(hw, IXGBE_ESDP) &
+ IXGBE_ESDP_SDP0);
+ break;
+ default:
+ /* Don't know how to check this device type yet */
+ sfp_cage_status = IXGBE_SFP_CAGE_UNKNOWN;
+ DEBUGOUT("IXGBE_SFP_CAGE_UNKNOWN, unknown mac type %d\n",
+ hw->mac.type);
+ break;
+ }
+
+ DEBUGOUT("sfp status %d for mac type %d\n", sfp_cage_status, hw->mac.type);
+ return sfp_cage_status;
+}
+
+static s32
+ixgbe_sfp_id_and_setup(struct rte_eth_dev *dev)
+{
+ struct ixgbe_hw *hw =
+ IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ enum ixgbe_sfp_cage_status sfp_cage_status;
+ s32 err;
+
+ /* Can't ID or setup SFP if it's not plugged in */
+ sfp_cage_status = ixgbe_check_sfp_cage(hw);
+ if (sfp_cage_status == IXGBE_SFP_CAGE_EMPTY ||
+ sfp_cage_status == IXGBE_SFP_CAGE_NOCAGE)
+ return IXGBE_ERR_SFP_NOT_PRESENT;
+
+ /* Something's in the cage, ID it */
+ hw->phy.ops.identify_sfp(hw);
+
+ /* Unknown module type, give up */
+ if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) {
+ PMD_DRV_LOG(ERR, "unknown SFP type, giving up");
+ return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ }
+
+ /* This should be a redundant check, since we looked at the
+ * PRSNT# signal from the cage above, but just in case this is
+ * an SFP that's slow to respond to I2C pokes correctly, try it
+ * again later
+ */
+ if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) {
+ PMD_DRV_LOG(ERR, "IDed SFP as absent but cage PRSNT# active!?");
+ return IXGBE_ERR_SFP_NOT_PRESENT;
+ }
+
+ /* SFP is present and identified, try to set it up */
+ err = hw->mac.ops.setup_sfp(hw);
+ if (err)
+ PMD_DRV_LOG(ERR, "setup_sfp() failed %d", err);
+
+ return err;
+}
+
+static void
+ixgbe_sfp_service(struct rte_eth_dev *dev)
+{
+ struct ixgbe_hw *hw =
+ IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ixgbe_interrupt *intr =
+ IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+ enum ixgbe_sfp_cage_status sfp_cage_status;
+ s32 err;
+ u8 sff_id;
+ bool have_int = false;
+
+ /* If there's no module cage, then there's nothing to service */
+ sfp_cage_status = ixgbe_check_sfp_cage(hw);
+ if (sfp_cage_status == IXGBE_SFP_CAGE_NOCAGE) {
+ PMD_DRV_LOG(DEBUG, "No SFP to service\n");
+ return;
+ }
+
+ /* TODO - Even for platforms where ixgbe_check_sfp_cage() gives a clear
+ * status result, if there's no interrupts, or no interrupt for the SFP
+ * cage present pin, even if other interrupts exist, then we still need
+ * to poll here to set the flag.
+ */
+#ifndef RTE_EXEC_ENV_FREEBSD
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc)
+ have_int = true;
+ }
+#endif /* #ifdef RTE_EXEC_ENV_FREEBSD */
+
+ if (!have_int && sfp_cage_status == IXGBE_SFP_CAGE_EMPTY) {
+ intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP;
+ PMD_DRV_LOG(DEBUG, "No SFP, no LSC, set NEED_SFP_SETUP\n");
+ }
+
+ /* For platforms that don't have a way to read the PRESENT# signal from
+ * the SFP cage, fallback to doing an I2C read and seeing if it's ACKed
+ * to determine if a module is present
+ */
+ if (sfp_cage_status == IXGBE_SFP_CAGE_UNKNOWN) {
+ PMD_DRV_LOG(DEBUG,
+ "SFP present unknown (int? %d), try I2C read\n",
+ have_int);
+
+ /* Rather than calling identify_sfp, which will read a lot of I2C
+ * registers (and in a slow processor intensive fashion due to
+ * bit-banging, just read the SFF ID register, which is at a
+ * common address across SFP/SFP+/QSFP modules and see if
+ * there's a NACK. This works since we only expect a NACK if no
+ * module is present
+ */
+ err = ixgbe_read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &sff_id);
+ if (err != IXGBE_SUCCESS) {
+ PMD_DRV_LOG(DEBUG, "Received I2C NAK from SFP, set NEED_SFP_SETUP flag\n");
+ intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP;
+ sfp_cage_status = IXGBE_SFP_CAGE_EMPTY;
+ } else {
+ PMD_DRV_LOG(DEBUG, "SFP ID read ACKed");
+ sfp_cage_status = IXGBE_SFP_CAGE_FULL;
+ }
+ }
+
+ if (sfp_cage_status == IXGBE_SFP_CAGE_EMPTY) {
+ PMD_DRV_LOG(DEBUG, "SFP absent, cage_status %d\n", sfp_cage_status);
+ return;
+ }
+
+ /* No setup requested? Nothing to do */
+ if (!(intr->flags & IXGBE_FLAG_NEED_SFP_SETUP))
+ return;
+
+ err = ixgbe_sfp_id_and_setup(dev);
+ if (err) {
+ PMD_DRV_LOG(DEBUG, "failed to ID & setup SFP %d", err);
+ return;
+ }
+
+ /* Setup is done, clear the flag, but make sure link config runs for new SFP */
+ intr->flags &= ~IXGBE_FLAG_NEED_SFP_SETUP;
+ intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+
+ /*
+ * Since this is a new SFP, clear the old advertised speed mask so we don't
+ * end up using an old slower rate
+ */
+ hw->phy.autoneg_advertised = 0;
+}
+
+static void
+ixgbe_link_service(struct rte_eth_dev *dev)
+{
+ struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ixgbe_interrupt *intr =
+ IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+ bool link_up, autoneg = false, have_int = false;
+ u32 speed;
+ s32 err;
+
+ /* Test if we have a LSC interrupt for this platform, if not we need to
+ * manually check the link register since IXGBE_FLAG_NEED_LINK_CONFIG
+ * will never be set in the interrupt handler
+ */
+#ifndef RTE_EXEC_ENV_FREEBSD
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
+ if (rte_intr_allow_others(intr_handle)) {
+ /* check if lsc interrupt is enabled */
+ if (dev->data->dev_conf.intr_conf.lsc)
+ have_int = true;
+ }
+#endif /* #ifdef RTE_EXEC_ENV_FREEBSD */
+
+ /* Skip if we still need to setup an SFP, or if no link config requested
+ */
+ if ((intr->flags & IXGBE_FLAG_NEED_SFP_SETUP) ||
+ (!(intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG) && have_int))
+ return;
+
+ if (!have_int && !(intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG)) {
+ err = ixgbe_check_link(hw, &speed, &link_up, 0);
+ if (!err && !link_up) {
+ intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+ PMD_DRV_LOG(DEBUG, "Link down, no LSC, set NEED_LINK_CONFIG\n");
+ } else {
+ return;
+ }
+ }
+
+ speed = hw->phy.autoneg_advertised;
+ if (!speed)
+ ixgbe_get_link_capabilities(hw, &speed, &autoneg);
+
+ err = ixgbe_setup_link(hw, speed, true);
+ if (err) {
+ PMD_DRV_LOG(ERR, "ixgbe_setup_link failed %d", err);
+ return;
+ }
+
+ intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+}
+
+static void
+ixgbe_link_update_service(struct rte_eth_dev *dev)
+{
+ /* Update internal link status, waiting for link */
+ if (!ixgbe_dev_link_update(dev, 0)) {
+ ixgbe_dev_link_status_print(dev);
+ rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+ }
+}
+
+/*
+ * Service task thread to handle periodic tasks
+ */
+static void *
+ixgbe_dev_service_thread_handler(void *param)
+{
+ struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+ struct ixgbe_hw *hw =
+ IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ uint64_t start, ticks, service_ms;
+ uint32_t speed;
+ s32 err;
+ bool link_up;
+
+ while (1) {
+ ixgbe_sfp_service(dev);
+ ixgbe_link_service(dev);
+ ixgbe_link_update_service(dev);
+
+ /* Run the service thread handler more frequently when link is
+ * down to reduce link up latency (every 200ms vs 1s)
+ *
+ * Use a number of smaller sleeps to decrease exit latency when
+ * ixgbe_dev_stop() wants this thread to join
+ */
+ err = ixgbe_check_link(hw, &speed, &link_up, 0);
+ if (err == IXGBE_SUCCESS && link_up)
+ service_ms = 2000;
+ else
+ service_ms = 100;
+
+ /* Call msec_delay in a loop with several smaller sleeps to
+ * provide periodic thread cancellation points
+ */
+ start = rte_get_timer_cycles();
+ ticks = (uint64_t)service_ms * rte_get_timer_hz() / 1E3;
+ while ((rte_get_timer_cycles() - start) < ticks)
+ msec_delay(100);
+ }
+
+ /* Never return */
+ return NULL;
+}
+
+static s32
+eth_ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+ bool *link_up, bool link_up_wait_to_complete)
+{
+ if (ixgbe_need_crosstalk_fix(hw)) {
+ enum ixgbe_sfp_cage_status sfp_cage_status;
+
+ sfp_cage_status = ixgbe_check_sfp_cage(hw);
+ if (sfp_cage_status != IXGBE_SFP_CAGE_FULL) {
+ *link_up = false;
+ *speed = IXGBE_LINK_SPEED_UNKNOWN;
+ return IXGBE_SUCCESS;
+ }
+ }
+
+ return ixgbe_check_mac_link_generic(hw, speed, link_up, link_up_wait_to_complete);
+}
+
/*
* This function is based on code in ixgbe_attach() in base/ixgbe.c.
* It returns 0 on success.
@@ -1054,6 +1378,7 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
IXGBE_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private);
struct ixgbe_bw_conf *bw_conf =
IXGBE_DEV_PRIVATE_TO_BW_CONF(eth_dev->data->dev_private);
+ struct ixgbe_mac_info *mac = &hw->mac;
uint32_t ctrl_ext;
uint16_t csum;
int diag, i, ret;
@@ -1124,6 +1449,17 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused)
return -EIO;
}
+ /* override mac_link_check to check for sfp cage full/empty */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X550EM_x:
+ case ixgbe_mac_X550EM_a:
+ case ixgbe_mac_82599EB:
+ mac->ops.check_link = eth_ixgbe_check_mac_link_generic;
+ break;
+ default:
+ break;
+ }
+
/* pick up the PCI bus settings for reporting later */
ixgbe_get_bus_info(hw);
@@ -2558,8 +2894,11 @@ ixgbe_flow_ctrl_enable(struct rte_eth_dev *dev, struct ixgbe_hw *hw)
static int
ixgbe_dev_start(struct rte_eth_dev *dev)
{
+ struct ixgbe_adapter *ad = dev->data->dev_private;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ixgbe_interrupt *intr =
+ IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
struct ixgbe_vf_info *vfinfo =
*IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private);
struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
@@ -2580,9 +2919,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
- /* Stop the link setup handler before resetting the HW. */
- ixgbe_dev_wait_setup_link_complete(dev, 0);
-
/* disable uio/vfio intr/eventfd mapping */
rte_intr_disable(intr_handle);
@@ -2815,6 +3151,20 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
ixgbe_l2_tunnel_conf(dev);
ixgbe_filter_restore(dev);
+ /* Spawn service thread */
+ if (ixgbe_is_sfp(hw)) {
+ intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP;
+ err = rte_ctrl_thread_create(&ad->service_thread_tid,
+ "ixgbe-service-thread",
+ NULL,
+ ixgbe_dev_service_thread_handler,
+ dev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "service_thread err");
+ goto error;
+ }
+ }
+
if (tm_conf->root && !tm_conf->committed)
PMD_DRV_LOG(WARNING,
"please call hierarchy_commit() "
@@ -2860,13 +3210,21 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
int vf;
struct ixgbe_tm_conf *tm_conf =
IXGBE_DEV_PRIVATE_TO_TM_CONF(dev->data->dev_private);
+ void *res;
+ s32 err;
if (hw->adapter_stopped)
return 0;
PMD_INIT_FUNC_TRACE();
- ixgbe_dev_wait_setup_link_complete(dev, 0);
+ /* Cancel the service thread, and wait for it to join */
+ err = pthread_cancel(adapter->service_thread_tid);
+ if (err)
+ PMD_DRV_LOG(ERR, "failed to cancel service thread %d", err);
+ err = pthread_join(adapter->service_thread_tid, &res);
+ if (err)
+ PMD_DRV_LOG(ERR, "failed to join service thread %d", err);
/* disable interrupts */
ixgbe_disable_intr(hw);
@@ -2945,7 +3303,6 @@ ixgbe_dev_set_link_up(struct rte_eth_dev *dev)
} else {
/* Turn on the laser */
ixgbe_enable_tx_laser(hw);
- ixgbe_dev_link_update(dev, 0);
}
return 0;
@@ -2976,7 +3333,6 @@ ixgbe_dev_set_link_down(struct rte_eth_dev *dev)
} else {
/* Turn off the laser */
ixgbe_disable_tx_laser(hw);
- ixgbe_dev_link_update(dev, 0);
}
return 0;
@@ -4128,57 +4484,6 @@ ixgbevf_check_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
return ret_val;
}
-/*
- * If @timeout_ms was 0, it means that it will not return until link complete.
- * It returns 1 on complete, return 0 on timeout.
- */
-static int
-ixgbe_dev_wait_setup_link_complete(struct rte_eth_dev *dev, uint32_t timeout_ms)
-{
-#define WARNING_TIMEOUT 9000 /* 9s in total */
- struct ixgbe_adapter *ad = dev->data->dev_private;
- uint32_t timeout = timeout_ms ? timeout_ms : WARNING_TIMEOUT;
-
- while (rte_atomic32_read(&ad->link_thread_running)) {
- msec_delay(1);
- timeout--;
-
- if (timeout_ms) {
- if (!timeout)
- return 0;
- } else if (!timeout) {
- /* It will not return until link complete */
- timeout = WARNING_TIMEOUT;
- PMD_DRV_LOG(ERR, "IXGBE link thread not complete too long time!");
- }
- }
-
- return 1;
-}
-
-static void *
-ixgbe_dev_setup_link_thread_handler(void *param)
-{
- struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
- struct ixgbe_adapter *ad = dev->data->dev_private;
- struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
- u32 speed;
- bool autoneg = false;
-
- pthread_detach(pthread_self());
- speed = hw->phy.autoneg_advertised;
- if (!speed)
- ixgbe_get_link_capabilities(hw, &speed, &autoneg);
-
- ixgbe_setup_link(hw, speed, true);
-
- intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
- rte_atomic32_clear(&ad->link_thread_running);
- return NULL;
-}
-
/*
* In freebsd environment, nic_uio drivers do not support interrupts,
* rte_intr_callback_register() will fail to register interrupts.
@@ -4218,11 +4523,8 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
int wait_to_complete, int vf)
{
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
- struct ixgbe_adapter *ad = dev->data->dev_private;
struct rte_eth_link link;
ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
- struct ixgbe_interrupt *intr =
- IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
bool link_up;
int diag;
int wait = 1;
@@ -4237,9 +4539,6 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
hw->mac.get_link_status = true;
- if (intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG)
- return rte_eth_linkstatus_set(dev, &link);
-
/* check if it needs to wait to complete, if lsc interrupt is enabled */
if (wait_to_complete == 0 || dev->data->dev_conf.intr_conf.lsc != 0)
wait = 0;
@@ -4254,7 +4553,7 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
else
diag = ixgbe_check_link(hw, &link_speed, &link_up, wait);
- if (diag != 0) {
+ if (diag != 0 || !link_up) {
link.link_speed = RTE_ETH_SPEED_NUM_100M;
link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
return rte_eth_linkstatus_set(dev, &link);
@@ -4267,32 +4566,6 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
link_up = 0;
}
- if (link_up == 0) {
- if (ixgbe_get_media_type(hw) == ixgbe_media_type_fiber) {
- ixgbe_dev_wait_setup_link_complete(dev, 0);
- if (rte_atomic32_test_and_set(&ad->link_thread_running)) {
- /* To avoid race condition between threads, set
- * the IXGBE_FLAG_NEED_LINK_CONFIG flag only
- * when there is no link thread running.
- */
- intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
- if (rte_ctrl_thread_create(&ad->link_thread_tid,
- "ixgbe-link-handler",
- NULL,
- ixgbe_dev_setup_link_thread_handler,
- dev) < 0) {
- PMD_DRV_LOG(ERR,
- "Create link thread failed!");
- rte_atomic32_clear(&ad->link_thread_running);
- }
- } else {
- PMD_DRV_LOG(ERR,
- "Other link thread is running now!");
- }
- }
- return rte_eth_linkstatus_set(dev, &link);
- }
-
link.link_status = RTE_ETH_LINK_UP;
link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
@@ -4498,8 +4771,6 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
PMD_DRV_LOG(DEBUG, "eicr %x", eicr);
- intr->flags = 0;
-
/* set flag for async link update */
if (eicr & IXGBE_EICR_LSC)
intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4515,6 +4786,14 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
(eicr & IXGBE_EICR_GPI_SDP0_X550EM_x))
intr->flags |= IXGBE_FLAG_PHY_INTERRUPT;
+ /* Check for loss of SFP */
+ /* TODO - For platforms that don't have this flag, do we need to set
+ * NEED_SFP_SETUP on LSC if we're a SFP platform?
+ */
+ if (hw->mac.type == ixgbe_mac_X550EM_a &&
+ (eicr & IXGBE_EICR_GPI_SDP0_X550EM_a))
+ intr->flags |= IXGBE_FLAG_NEED_SFP_SETUP;
+
return 0;
}
@@ -4566,11 +4845,13 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev)
static int
ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+ struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
struct ixgbe_interrupt *intr =
IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
- int64_t timeout;
struct ixgbe_hw *hw =
IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ int64_t timeout;
PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags);
@@ -4605,16 +4886,14 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
if (rte_eal_alarm_set(timeout * 1000,
ixgbe_dev_interrupt_delayed_handler, (void *)dev) < 0)
PMD_DRV_LOG(ERR, "Error setting alarm");
- else {
- /* remember original mask */
- intr->mask_original = intr->mask;
+ else
/* only disable lsc interrupt */
intr->mask &= ~IXGBE_EIMS_LSC;
- }
}
PMD_DRV_LOG(DEBUG, "enable intr immediately");
ixgbe_enable_intr(dev);
+ rte_intr_ack(intr_handle);
return 0;
}
@@ -4637,8 +4916,6 @@ static void
ixgbe_dev_interrupt_delayed_handler(void *param)
{
struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
- struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
- struct rte_intr_handle *intr_handle = pci_dev->intr_handle;
struct ixgbe_interrupt *intr =
IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
struct ixgbe_hw *hw =
@@ -4668,13 +4945,10 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
intr->flags &= ~IXGBE_FLAG_MACSEC;
}
- /* restore original mask */
- intr->mask = intr->mask_original;
- intr->mask_original = 0;
+ if (dev->data->dev_conf.intr_conf.lsc != 0)
+ intr->mask |= IXGBE_EICR_LSC;
- PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]", eicr);
ixgbe_enable_intr(dev);
- rte_intr_ack(intr_handle);
}
/**
@@ -5316,9 +5590,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
- /* Stop the link setup handler before resetting the HW. */
- ixgbe_dev_wait_setup_link_complete(dev, 0);
-
err = hw->mac.ops.reset_hw(hw);
/**
@@ -5398,12 +5669,6 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
/* Re-enable interrupt for VF */
ixgbevf_intr_enable(dev);
- /*
- * Update link status right before return, because it may
- * start link configuration process in a separate thread.
- */
- ixgbevf_dev_link_update(dev, 0);
-
hw->adapter_stopped = false;
return 0;
@@ -5422,8 +5687,6 @@ ixgbevf_dev_stop(struct rte_eth_dev *dev)
PMD_INIT_FUNC_TRACE();
- ixgbe_dev_wait_setup_link_complete(dev, 0);
-
ixgbevf_intr_disable(dev);
dev->data->dev_started = 0;
@@ -29,6 +29,7 @@
#define IXGBE_FLAG_PHY_INTERRUPT (uint32_t)(1 << 2)
#define IXGBE_FLAG_MACSEC (uint32_t)(1 << 3)
#define IXGBE_FLAG_NEED_LINK_CONFIG (uint32_t)(1 << 4)
+#define IXGBE_FLAG_NEED_SFP_SETUP ((uint32_t)(1 << 5))
/*
* Defines that were not part of ixgbe_type.h as they are not used by the
@@ -223,8 +224,6 @@ struct ixgbe_rte_flow_rss_conf {
struct ixgbe_interrupt {
uint32_t flags;
uint32_t mask;
- /*to save original mask during delayed handler */
- uint32_t mask_original;
};
struct ixgbe_stat_mapping_registers {
@@ -507,7 +506,7 @@ struct ixgbe_adapter {
uint8_t pflink_fullchk;
uint8_t mac_ctrl_frame_fwd;
rte_atomic32_t link_thread_running;
- pthread_t link_thread_tid;
+ pthread_t service_thread_tid;
};
struct ixgbe_vf_representor {
@@ -670,6 +669,15 @@ int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
struct rte_eth_syn_filter *filter,
bool add);
+enum ixgbe_sfp_cage_status {
+ IXGBE_SFP_CAGE_EMPTY = 0,
+ IXGBE_SFP_CAGE_FULL,
+ IXGBE_SFP_CAGE_UNKNOWN = -1,
+ IXGBE_SFP_CAGE_NOCAGE = -2,
+};
+enum ixgbe_sfp_cage_status ixgbe_check_sfp_cage(struct ixgbe_hw *hw);
+
+
/**
* l2 tunnel configuration.
*/