From: Jeff Daly <jeffd@silicom-usa.com>
To: dev@dpdk.org
Cc: Stephen Douthit <stephend@silicom-usa.com>,
Qiming Yang <qiming.yang@intel.com>,
Wenjun Wu <wenjun1.wu@intel.com>
Subject: [PATCH v2 1/3] ixgbe: make link update thread periodic
Date: Thu, 19 May 2022 15:37:36 -0400 [thread overview]
Message-ID: <ffbdaf3aa487241a51bb6512bbb4701da17e69fe.1652988826.git.jeffd@silicom-usa.com> (raw)
In-Reply-To: <cover.1652988826.git.jeffd@silicom-usa.com>
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 <jeffd@silicom-usa.com>
Suggested-by: Stephen Douthit <stephend@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
next parent reply other threads:[~2022-05-19 19:38 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1652988826.git.jeffd@silicom-usa.com>
2022-05-19 19:37 ` Jeff Daly [this message]
2022-05-19 19:37 ` [PATCH v2 2/3] ixgbe: move periodic link service work into separate function Jeff Daly
2022-05-19 19:37 ` [PATCH v2 3/3] ixgbe: make hotplug detection aware of changed SFPs Jeff Daly
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ffbdaf3aa487241a51bb6512bbb4701da17e69fe.1652988826.git.jeffd@silicom-usa.com \
--to=jeffd@silicom-usa.com \
--cc=dev@dpdk.org \
--cc=qiming.yang@intel.com \
--cc=stephend@silicom-usa.com \
--cc=wenjun1.wu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).