patches for DPDK stable branches
 help / color / mirror / Atom feed
From: Dmitry Kozlyuk <dkozlyuk@nvidia.com>
To: <stable@dpdk.org>
Cc: Luca Boccassi <bluca@debian.org>
Subject: [PATCH 20.11 2/3] net/mlx5: fix link status change detection
Date: Fri, 11 Mar 2022 09:49:32 +0200	[thread overview]
Message-ID: <20220311074933.1194679-3-dkozlyuk@nvidia.com> (raw)
In-Reply-To: <20220311074933.1194679-1-dkozlyuk@nvidia.com>

[ upstream commit 17f95513adca1f4ee5bba305b154ac984ee50cee ]

Sometimes net/mlx5 devices did not detect link status change to "up".

Each shared device was monitoring IBV_EVENT_PORT_{ACTIVE,ERR}
and queried the link status upon receiving the event.
IBV_EVENT_PORT_ACTIVE is delivered when the logical link status
(UP flag) is set, but the physical link status (RUNNING flag)
may be down at that time, in which case the new link status
would be errornously considered down.

IBV interface is insufficient for the task.
Monitor interface events using Netlink.

Fixes: 198a3c339a8f ("mlx5: handle link status interrupts")

Signed-off-by: Dmitry Kozlyuk <dkozlyuk@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_ethdev_os.c | 64 ++++++++++++++++++++-----
 drivers/net/mlx5/linux/mlx5_os.c        | 48 +++++++++++++++++++
 drivers/net/mlx5/mlx5.c                 |  1 +
 drivers/net/mlx5/mlx5.h                 |  3 ++
 drivers/net/mlx5/mlx5_trigger.c         | 12 ++++-
 5 files changed, 114 insertions(+), 14 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
index 08b51b7dc8..e89d16aace 100644
--- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c
+++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
@@ -38,6 +38,7 @@
 #include <mlx5_devx_cmds.h>
 #include <mlx5_common.h>
 #include <mlx5_malloc.h>
+#include <mlx5_nl.h>
 
 #include "mlx5.h"
 #include "mlx5_rxtx.h"
@@ -730,6 +731,57 @@ mlx5_dev_interrupt_device_fatal(struct mlx5_dev_ctx_shared *sh)
 	}
 }
 
+static void
+mlx5_dev_interrupt_nl_cb(struct nlmsghdr *hdr, void *cb_arg)
+{
+	struct mlx5_dev_ctx_shared *sh = cb_arg;
+	uint32_t i;
+	uint32_t if_index;
+
+	if (mlx5_nl_parse_link_status_update(hdr, &if_index) < 0)
+		return;
+	for (i = 0; i < sh->max_port; i++) {
+		struct mlx5_dev_shared_port *port = &sh->port[i];
+		struct rte_eth_dev *dev;
+		struct mlx5_priv *priv;
+		bool configured;
+
+		if (port->nl_ih_port_id >= RTE_MAX_ETHPORTS)
+			continue;
+		dev = &rte_eth_devices[port->nl_ih_port_id];
+		configured = dev->process_private != NULL;
+		/* Probing may initiate an LSC before configuration is done. */
+		if (configured && !dev->data->dev_conf.intr_conf.lsc)
+			break;
+		priv = dev->data->dev_private;
+		if (priv->if_index == if_index) {
+			/* Block logical LSC events. */
+			uint16_t prev_status = dev->data->dev_link.link_status;
+
+			if (mlx5_link_update(dev, 0) < 0)
+				DRV_LOG(ERR, "Failed to update link status: %s",
+					rte_strerror(rte_errno));
+			else if (prev_status != dev->data->dev_link.link_status)
+				rte_eth_dev_callback_process
+					(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+			break;
+		}
+	}
+}
+
+void
+mlx5_dev_interrupt_handler_nl(void *arg)
+{
+	struct mlx5_dev_ctx_shared *sh = arg;
+	int nlsk_fd = sh->intr_handle_nl.fd;
+
+	if (nlsk_fd < 0)
+		return;
+	if (mlx5_nl_read_events(nlsk_fd, mlx5_dev_interrupt_nl_cb, sh) < 0)
+		DRV_LOG(ERR, "Failed to process Netlink events: %s",
+			rte_strerror(rte_errno));
+}
+
 /**
  * Handle shared asynchronous events the NIC (removal event
  * and link status change). Supports multiport IB device.
@@ -793,18 +845,6 @@ mlx5_dev_interrupt_handler(void *cb_arg)
 		tmp = sh->port[tmp - 1].ih_port_id;
 		dev = &rte_eth_devices[tmp];
 		MLX5_ASSERT(dev);
-		if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
-		     event.event_type == IBV_EVENT_PORT_ERR) &&
-			dev->data->dev_conf.intr_conf.lsc) {
-			mlx5_glue->ack_async_event(&event);
-			if (mlx5_link_update(dev, 0) == -EAGAIN) {
-				usleep(0);
-				continue;
-			}
-			rte_eth_dev_callback_process
-				(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
-			continue;
-		}
 		DRV_LOG(DEBUG,
 			"port %u cannot handle an unknown event (type %d)",
 			dev->data->port_id, event.event_type);
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index b3a5a8d3c7..0e738d4a59 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -2438,6 +2438,40 @@ mlx5_os_net_cleanup(void)
 	mlx5_pmd_socket_uninit();
 }
 
+static int
+mlx5_os_dev_shared_handler_install_lsc(struct mlx5_dev_ctx_shared *sh)
+{
+	int nlsk_fd, flags, ret;
+
+	nlsk_fd = mlx5_nl_init(NETLINK_ROUTE, RTMGRP_LINK);
+	if (nlsk_fd < 0) {
+		DRV_LOG(ERR, "Failed to create a socket for Netlink events: %s",
+			rte_strerror(rte_errno));
+		return -1;
+	}
+	flags = fcntl(nlsk_fd, F_GETFL);
+	ret = fcntl(nlsk_fd, F_SETFL, flags | O_NONBLOCK);
+	if (ret != 0) {
+		DRV_LOG(ERR, "Failed to make Netlink event socket non-blocking: %s",
+			strerror(errno));
+		rte_errno = errno;
+		goto error;
+	}
+	sh->intr_handle_nl.type = RTE_INTR_HANDLE_EXT;
+	sh->intr_handle_nl.fd = nlsk_fd;
+	if (rte_intr_callback_register(&sh->intr_handle_nl,
+				       mlx5_dev_interrupt_handler_nl,
+				       sh) != 0) {
+		DRV_LOG(ERR, "Failed to register Netlink events interrupt");
+		sh->intr_handle_nl.fd = -1;
+		goto error;
+	}
+	return 0;
+error:
+	close(nlsk_fd);
+	return -1;
+}
+
 /**
  * Install shared asynchronous device events handler.
  * This function is implemented to support event sharing
@@ -2468,6 +2502,11 @@ mlx5_os_dev_shared_handler_install(struct mlx5_dev_ctx_shared *sh)
 			sh->intr_handle.fd = -1;
 		}
 	}
+	sh->intr_handle_nl.fd = -1;
+	if (mlx5_os_dev_shared_handler_install_lsc(sh) < 0) {
+		DRV_LOG(INFO, "Fail to install the shared Netlink event handler.");
+		sh->intr_handle_nl.fd = -1;
+	}
 	if (sh->devx) {
 #ifdef HAVE_IBV_DEVX_ASYNC
 		sh->intr_handle_devx.fd = -1;
@@ -2508,9 +2547,18 @@ mlx5_os_dev_shared_handler_install(struct mlx5_dev_ctx_shared *sh)
 void
 mlx5_os_dev_shared_handler_uninstall(struct mlx5_dev_ctx_shared *sh)
 {
+	int nlsk_fd;
+
 	if (sh->intr_handle.fd >= 0)
 		mlx5_intr_callback_unregister(&sh->intr_handle,
 					      mlx5_dev_interrupt_handler, sh);
+	nlsk_fd = sh->intr_handle_nl.fd;
+	if (nlsk_fd >= 0) {
+		mlx5_intr_callback_unregister(&sh->intr_handle_nl,
+					      mlx5_dev_interrupt_handler_nl,
+					      sh);
+		close(nlsk_fd);
+	}
 #ifdef HAVE_IBV_DEVX_ASYNC
 	if (sh->intr_handle_devx.fd >= 0)
 		rte_intr_callback_unregister(&sh->intr_handle_devx,
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index cff1188213..0b82969b4d 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -928,6 +928,7 @@ mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn,
 	for (i = 0; i < sh->max_port; i++) {
 		sh->port[i].ih_port_id = RTE_MAX_ETHPORTS;
 		sh->port[i].devx_ih_port_id = RTE_MAX_ETHPORTS;
+		sh->port[i].nl_ih_port_id = RTE_MAX_ETHPORTS;
 	}
 	sh->pd = mlx5_glue->alloc_pd(sh->ctx);
 	if (sh->pd == NULL) {
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index b18fffea52..6c85c4e2db 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -559,6 +559,7 @@ struct mlx5_age_info {
 struct mlx5_dev_shared_port {
 	uint32_t ih_port_id;
 	uint32_t devx_ih_port_id;
+	uint32_t nl_ih_port_id;
 	/*
 	 * Interrupt handler port_id. Used by shared interrupt
 	 * handler to find the corresponding rte_eth device
@@ -741,6 +742,7 @@ struct mlx5_dev_ctx_shared {
 	/* Shared interrupt handler section. */
 	struct rte_intr_handle intr_handle; /* Interrupt handler for device. */
 	struct rte_intr_handle intr_handle_devx; /* DEVX interrupt handler. */
+	struct rte_intr_handle intr_handle_nl; /* Netlink interrupt handler. */
 	void *devx_comp; /* DEVX async comp obj. */
 	struct mlx5_devx_obj *tis; /* TIS object. */
 	struct mlx5_devx_obj *td; /* Transport domain. */
@@ -1085,6 +1087,7 @@ int mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev,
 			   struct rte_eth_fc_conf *fc_conf);
 void mlx5_dev_interrupt_handler(void *arg);
 void mlx5_dev_interrupt_handler_devx(void *arg);
+void mlx5_dev_interrupt_handler_nl(void *arg);
 int mlx5_set_link_down(struct rte_eth_dev *dev);
 int mlx5_set_link_up(struct rte_eth_dev *dev);
 int mlx5_is_removed(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 92eaef87d1..6273122e40 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1134,11 +1134,18 @@ mlx5_dev_start(struct rte_eth_dev *dev)
 		priv->sh->port[priv->dev_port - 1].ih_port_id =
 					(uint32_t)dev->data->port_id;
 	} else {
-		DRV_LOG(INFO, "port %u starts without LSC and RMV interrupts.",
+		DRV_LOG(INFO, "port %u starts without RMV interrupts.",
 			dev->data->port_id);
-		dev->data->dev_conf.intr_conf.lsc = 0;
 		dev->data->dev_conf.intr_conf.rmv = 0;
 	}
+	if (priv->sh->intr_handle_nl.fd >= 0) {
+		priv->sh->port[priv->dev_port - 1].nl_ih_port_id =
+					(uint32_t)dev->data->port_id;
+	} else {
+		DRV_LOG(INFO, "port %u starts without LSC interrupts.",
+			dev->data->port_id);
+		dev->data->dev_conf.intr_conf.lsc = 0;
+	}
 	if (priv->sh->intr_handle_devx.fd >= 0)
 		priv->sh->port[priv->dev_port - 1].devx_ih_port_id =
 					(uint32_t)dev->data->port_id;
@@ -1188,6 +1195,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
 	mlx5_rx_intr_vec_disable(dev);
 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
+	priv->sh->port[priv->dev_port - 1].nl_ih_port_id = RTE_MAX_ETHPORTS;
 	mlx5_txq_stop(dev);
 	mlx5_rxq_stop(dev);
 	if (priv->obj_ops.lb_dummy_queue_release)
-- 
2.25.1


  parent reply	other threads:[~2022-03-11  7:49 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-11  7:49 [PATCH 20.11 0/3] net/mlx5: fix link state detection Dmitry Kozlyuk
2022-03-11  7:49 ` [PATCH 20.11 1/3] common/mlx5: add Netlink event helpers Dmitry Kozlyuk
2022-03-11  7:49 ` Dmitry Kozlyuk [this message]
2022-03-11  7:49 ` [PATCH 20.11 3/3] net/mlx5: fix initial link status detection Dmitry Kozlyuk
2022-03-11 12:19 ` [PATCH 20.11 0/3] net/mlx5: fix link state detection Luca Boccassi

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=20220311074933.1194679-3-dkozlyuk@nvidia.com \
    --to=dkozlyuk@nvidia.com \
    --cc=bluca@debian.org \
    --cc=stable@dpdk.org \
    /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).