Rather than run-to-completion, allow the link update thread to be periodic. This will set the stage for properly handling hot-plugging.
Signed-off-by: Jeff Daly <je...@silicom-usa.com> Inspired-by: Stephen Douthit <steph...@silicom-usa.com> --- drivers/net/ixgbe/base/ixgbe_common.c | 4 +- drivers/net/ixgbe/ixgbe_ethdev.c | 180 ++++++++++---------------- 2 files changed, 71 insertions(+), 113 deletions(-) diff --git a/drivers/net/ixgbe/base/ixgbe_common.c b/drivers/net/ixgbe/base/ixgbe_common.c index aa843bd5c4a5..712062306491 100644 --- a/drivers/net/ixgbe/base/ixgbe_common.c +++ b/drivers/net/ixgbe/base/ixgbe_common.c @@ -4154,8 +4154,8 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, break; case ixgbe_mac_X550EM_x: case ixgbe_mac_X550EM_a: - sfp_cage_full = IXGBE_READ_REG(hw, IXGBE_ESDP) & - IXGBE_ESDP_SDP0; + sfp_cage_full = !(IXGBE_READ_REG(hw, IXGBE_ESDP) & + IXGBE_ESDP_SDP0); break; default: /* sanity check - No SFP+ devices here */ diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c index 2da3f67bbc78..81b15ad28212 100644 --- a/drivers/net/ixgbe/ixgbe_ethdev.c +++ b/drivers/net/ixgbe/ixgbe_ethdev.c @@ -230,8 +230,6 @@ 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, @@ -1039,7 +1037,6 @@ ixgbe_swfw_lock_reset(struct ixgbe_hw *hw) static int eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) { - struct ixgbe_adapter *ad = eth_dev->data->dev_private; struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); struct rte_intr_handle *intr_handle = pci_dev->intr_handle; struct ixgbe_hw *hw = @@ -1094,7 +1091,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) return 0; } - rte_atomic32_clear(&ad->link_thread_running); rte_eth_copy_pci_info(eth_dev, pci_dev); eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; @@ -1547,7 +1543,6 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev) { int diag; uint32_t tc, tcs; - struct ixgbe_adapter *ad = eth_dev->data->dev_private; struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); struct rte_intr_handle *intr_handle = pci_dev->intr_handle; struct ixgbe_hw *hw = @@ -1590,7 +1585,6 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev) return 0; } - rte_atomic32_clear(&ad->link_thread_running); ixgbevf_parse_devargs(eth_dev->data->dev_private, pci_dev->device.devargs); @@ -2558,8 +2552,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 +2577,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); @@ -2700,8 +2694,16 @@ ixgbe_dev_start(struct rte_eth_dev *dev) if (ixgbe_is_sfp(hw) && hw->phy.multispeed_fiber) { err = hw->mac.ops.setup_sfp(hw); - if (err) + intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + err = rte_ctrl_thread_create(&ad->link_thread_tid, + "ixgbe-service-tid", + NULL, + ixgbe_dev_setup_link_thread_handler, + dev); + if (err) { + PMD_DRV_LOG(ERR, "service_thread err"); goto error; + } } if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) { @@ -2825,12 +2827,6 @@ ixgbe_dev_start(struct rte_eth_dev *dev) if (err) goto error; - /* - * Update link status right before return, because it may - * start link configuration process in a separate thread. - */ - ixgbe_dev_link_update(dev, 0); - /* setup the macsec setting register */ if (macsec_setting->offload_en) ixgbe_dev_macsec_register_enable(dev, macsec_setting); @@ -2860,13 +2856,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 */ + err = pthread_cancel(adapter->link_thread_tid); + if (err) + PMD_DRV_LOG(ERR, "failed to cancel service thread %d", err); + err = pthread_join(adapter->link_thread_tid, &res); + if (err) + PMD_DRV_LOG(ERR, "failed to join service thread %d", err); /* disable interrupts */ ixgbe_disable_intr(hw); @@ -2945,7 +2949,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 +2979,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; @@ -4129,54 +4131,58 @@ 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; + u32 speed, start, ticks, service_ms; + s32 err; + bool link_up, 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); + while (1) { + service_ms = 100; + if (intr->flags & IXGBE_FLAG_NEED_LINK_CONFIG) { + speed = hw->phy.autoneg_advertised; + + if (!speed) + ixgbe_get_link_capabilities(hw, &speed, &autoneg); + + err = ixgbe_setup_link(hw, speed, true); + + if (err == IXGBE_SUCCESS) + err = ixgbe_check_link(hw, &speed, &link_up, 0); + + /* 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 + */ + if (err == IXGBE_SUCCESS && link_up) { + service_ms = 2000; + intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + } + + 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); + } + } + + /* 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); + } - intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; - rte_atomic32_clear(&ad->link_thread_running); return NULL; } @@ -4219,11 +4225,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; @@ -4238,9 +4241,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; @@ -4255,7 +4255,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 +4267,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; @@ -4566,6 +4540,8 @@ 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; @@ -4605,16 +4581,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 +4611,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 +4640,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 +5285,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 +5364,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 +5382,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; -- 2.25.1