Skip to contentSkip to conversation

net/mlx5: introduce limit watermark and host shaper

RFC In review Spike Du 11 participants 131 messages Apr 1, 2022 – Jun 23, 2022 Page 2 of 2

Subsystems (4)
lore
Share & tools
lore
author
#97 lore raw

PATCH v10 2/6 common/mlx5: share interrupt management

In reply to Spike Du

There are many duplicate code of creating and initializing rte_intr_handle. Add a new mlx5_os API to do this, replace all PMD related code with this API.

---
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +++
 drivers/common/mlx5/version.map              |   2 +
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 --------------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 ++++++---------------------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 ++---------
 drivers/net/mlx5/mlx5.h                      |   2 -
 drivers/net/mlx5/mlx5_txpp.c                 |  28 ++----
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 -----
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  48 ++--------
 11 files changed, 217 insertions(+), 307 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +131 -0
index d40cfd5..f10a981 100644
@@ -11,6 +11,7 @@
 #endif
 #include <dirent.h>
 #include <net/if.h>
+#include <fcntl.h>
 
 #include <rte_errno.h>
 #include <rte_string_fns.h>
@@ -964,3 +965,133 @@
 		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
 	memset(pmd_mr, 0, sizeof(*pmd_mr));
 }
+
+/**
+ * Rte_intr_handle create and init helper.
+ *
+ * @param[in] mode
+ *   interrupt instance can be shared between primary and secondary
+ *   processes or not.
+ * @param[in] set_fd_nonblock
+ *   Whether to set fd to O_NONBLOCK.
+ * @param[in] fd
+ *   Fd to set in created intr_handle.
+ * @param[in] cb
+ *   Callback to register for intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ * @return
+ *  - Interrupt handle on success.
+ *  - NULL on failure, with rte_errno set.
+ */
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle;
+	int ret, flags;
+
+	tmp_intr_handle = rte_intr_instance_alloc(mode);
+	if (!tmp_intr_handle) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	if (set_fd_nonblock) {
+		flags = fcntl(fd, F_GETFL);
+		ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+		if (ret) {
+			rte_errno = errno;
+			goto err;
+		}
+	}
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret)
+		goto err;
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret)
+		goto err;
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		rte_errno = -ret;
+		goto err;
+	}
+	return tmp_intr_handle;
+err:
+	if (tmp_intr_handle)
+		rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+/* Safe unregistration for interrupt callback. */
+static void
+mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
+			      rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+	uint64_t twait = 0;
+	uint64_t start = 0;
+
+	do {
+		int ret;
+
+		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
+		if (ret >= 0)
+			return;
+		if (ret != -EAGAIN) {
+			DRV_LOG(INFO, "failed to unregister interrupt"
+				      " handler (error: %d)", ret);
+			MLX5_ASSERT(false);
+			return;
+		}
+		if (twait) {
+			struct timespec onems;
+
+			/* Wait one millisecond and try again. */
+			onems.tv_sec = 0;
+			onems.tv_nsec = NS_PER_S / MS_PER_S;
+			nanosleep(&onems, 0);
+			/* Check whether one second elapsed. */
+			if ((rte_get_timer_cycles() - start) <= twait)
+				continue;
+		} else {
+			/*
+			 * We get the amount of timer ticks for one second.
+			 * If this amount elapsed it means we spent one
+			 * second in waiting. This branch is executed once
+			 * on first iteration.
+			 */
+			twait = rte_get_timer_hz();
+			MLX5_ASSERT(twait);
+		}
+		/*
+		 * Timeout elapsed, show message (once a second) and retry.
+		 * We have no other acceptable option here, if we ignore
+		 * the unregistering return code the handler will not
+		 * be unregistered, fd will be closed and we may get the
+		 * crush. Hanging and messaging in the loop seems not to be
+		 * the worst choice.
+		 */
+		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
+		start = rte_get_timer_cycles();
+	} while (true);
+}
+
+/**
+ * Rte_intr_handle destroy helper.
+ *
+ * @param[in] intr_handle
+ *   Rte_intr_handle to destroy.
+ * @param[in] cb
+ *   Callback which is registered to intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ */
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
drivers/common/mlx5/linux/mlx5_common_os.h +11 -0
index 27f1192..479bb3c 100644
@@ -15,6 +15,7 @@
 #include <rte_log.h>
 #include <rte_kvargs.h>
 #include <rte_devargs.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -299,4 +300,14 @@
 int
 mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len);
 
+__rte_internal
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg);
+
+__rte_internal
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg);
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/common/mlx5/version.map +2 -0
index a23a30a..413dec1 100644
@@ -153,5 +153,7 @@ INTERNAL {
 	mlx5_mr_mempool2mr_bh;
 	mlx5_mr_mempool_populate_cache;
 
+	mlx5_os_interrupt_handler_create; # WINDOWS_NO_EXPORT
+	mlx5_os_interrupt_handler_destroy; # WINDOWS_NO_EXPORT
 	local: *;
 };
drivers/common/mlx5/windows/mlx5_common_os.h +24 -0
index ee7973f..e9e9108 100644
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <rte_errno.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -253,4 +254,27 @@
 __rte_internal
 int mlx5_os_umem_dereg(void *pumem);
 
+static inline struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)mode;
+	(void)set_fd_nonblock;
+	(void)fd;
+	(void)cb;
+	(void)cb_arg;
+	rte_errno = ENOTSUP;
+	return NULL;
+}
+
+static inline void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)intr_handle;
+	(void)cb;
+	(void)cb_arg;
+}
+
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/net/mlx5/linux/mlx5_ethdev_os.c +0 -71

77 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_os.c +29 -103

169 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_socket.c +6 -47

71 lines not on this page · raw message

drivers/net/mlx5/mlx5.h +0 -2
index 305edff..7ebb2cc 100644
@@ -1682,8 +1682,6 @@ int mlx5_sysfs_switch_info(unsigned int ifindex,
 			   struct mlx5_switch_info *info);
 void mlx5_translate_port_name(const char *port_name_in,
 			      struct mlx5_switch_info *port_info_out);
-void mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-				   rte_intr_callback_fn cb_fn, void *cb_arg);
 int mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
 			 char *ifname);
 int mlx5_get_module_info(struct rte_eth_dev *dev,
drivers/net/mlx5/mlx5_txpp.c +7 -21
index fe74317..f853a67 100644
@@ -741,11 +741,8 @@
 static void
 mlx5_txpp_stop_service(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!rte_intr_fd_get(sh->txpp.intr_handle))
-		return;
-	mlx5_intr_callback_unregister(sh->txpp.intr_handle,
-				      mlx5_txpp_interrupt_handler, sh);
-	rte_intr_instance_free(sh->txpp.intr_handle);
+	mlx5_os_interrupt_handler_destroy(sh->txpp.intr_handle,
+					  mlx5_txpp_interrupt_handler, sh);
 }
 
 /* Attach interrupt handler and fires first request to Rearm Queue. */
@@ -769,23 +766,12 @@
 		rte_errno = errno;
 		return -rte_errno;
 	}
-	sh->txpp.intr_handle =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->txpp.intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
 	fd = mlx5_os_get_devx_channel_fd(sh->txpp.echan);
-	if (rte_intr_fd_set(sh->txpp.intr_handle, fd))
-		return -rte_errno;
-
-	if (rte_intr_type_set(sh->txpp.intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	if (rte_intr_callback_register(sh->txpp.intr_handle,
-				       mlx5_txpp_interrupt_handler, sh)) {
-		rte_intr_fd_set(sh->txpp.intr_handle, 0);
-		DRV_LOG(ERR, "Failed to register CQE interrupt %d.", rte_errno);
+	sh->txpp.intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, false,
+		 fd, mlx5_txpp_interrupt_handler, sh);
+	if (!sh->txpp.intr_handle) {
+		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		return -rte_errno;
 	}
 	/* Subscribe CQ event to the event channel controlled by the driver. */
drivers/net/mlx5/windows/mlx5_ethdev_os.c +0 -22
index f975265..88d8213 100644
@@ -140,28 +140,6 @@
 	return 0;
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	RTE_SET_USED(handle);
-	RTE_SET_USED(cb_fn);
-	RTE_SET_USED(cb_arg);
-}
-
 /**
  * DPDK callback to get flow control status.
  *
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +7 -41

64 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#98 lore raw

Re: [PATCH v10 2/6] common/mlx5: share interrupt management

Quoted 218 lines · Spike Du

There are many duplicate code of creating and initializing rte_intr_handle. Add a new mlx5_os API to do this, replace all PMD related code with this API.

---
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +++
 drivers/common/mlx5/version.map              |   2 +
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 --------------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 ++++++---------------------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 ++---------
 drivers/net/mlx5/mlx5.h                      |   2 -
 drivers/net/mlx5/mlx5_txpp.c                 |  28 ++----
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 -----
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  48 ++--------
 11 files changed, 217 insertions(+), 307 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +131 -0
index d40cfd5..f10a981 100644
@@ -11,6 +11,7 @@
 #endif
 #include <dirent.h>
 #include <net/if.h>
+#include <fcntl.h>
 
 #include <rte_errno.h>
 #include <rte_string_fns.h>
@@ -964,3 +965,133 @@
 		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
 	memset(pmd_mr, 0, sizeof(*pmd_mr));
 }
+
+/**
+ * Rte_intr_handle create and init helper.
+ *
+ * @param[in] mode
+ *   interrupt instance can be shared between primary and secondary
+ *   processes or not.
+ * @param[in] set_fd_nonblock
+ *   Whether to set fd to O_NONBLOCK.
+ * @param[in] fd
+ *   Fd to set in created intr_handle.
+ * @param[in] cb
+ *   Callback to register for intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ * @return
+ *  - Interrupt handle on success.
+ *  - NULL on failure, with rte_errno set.
+ */
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle;
+	int ret, flags;
+
+	tmp_intr_handle = rte_intr_instance_alloc(mode);
+	if (!tmp_intr_handle) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	if (set_fd_nonblock) {
+		flags = fcntl(fd, F_GETFL);
+		ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+		if (ret) {
+			rte_errno = errno;
+			goto err;
+		}
+	}
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret)
+		goto err;
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret)
+		goto err;
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		rte_errno = -ret;
+		goto err;
+	}
+	return tmp_intr_handle;
+err:
+	if (tmp_intr_handle)
+		rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+/* Safe unregistration for interrupt callback. */
+static void
+mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
+			      rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+	uint64_t twait = 0;
+	uint64_t start = 0;
+
+	do {
+		int ret;
+
+		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
+		if (ret >= 0)
+			return;
+		if (ret != -EAGAIN) {
+			DRV_LOG(INFO, "failed to unregister interrupt"
+				      " handler (error: %d)", ret);
+			MLX5_ASSERT(false);
+			return;
+		}
+		if (twait) {
+			struct timespec onems;
+
+			/* Wait one millisecond and try again. */
+			onems.tv_sec = 0;
+			onems.tv_nsec = NS_PER_S / MS_PER_S;
+			nanosleep(&onems, 0);
+			/* Check whether one second elapsed. */
+			if ((rte_get_timer_cycles() - start) <= twait)
+				continue;
+		} else {
+			/*
+			 * We get the amount of timer ticks for one second.
+			 * If this amount elapsed it means we spent one
+			 * second in waiting. This branch is executed once
+			 * on first iteration.
+			 */
+			twait = rte_get_timer_hz();
+			MLX5_ASSERT(twait);
+		}
+		/*
+		 * Timeout elapsed, show message (once a second) and retry.
+		 * We have no other acceptable option here, if we ignore
+		 * the unregistering return code the handler will not
+		 * be unregistered, fd will be closed and we may get the
+		 * crush. Hanging and messaging in the loop seems not to be
+		 * the worst choice.
+		 */
+		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
+		start = rte_get_timer_cycles();
+	} while (true);
+}
+
+/**
+ * Rte_intr_handle destroy helper.
+ *
+ * @param[in] intr_handle
+ *   Rte_intr_handle to destroy.
+ * @param[in] cb
+ *   Callback which is registered to intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ */
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
drivers/common/mlx5/linux/mlx5_common_os.h +11 -0
index 27f1192..479bb3c 100644
@@ -15,6 +15,7 @@
 #include <rte_log.h>
 #include <rte_kvargs.h>
 #include <rte_devargs.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -299,4 +300,14 @@
 int
 mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len);
 
+__rte_internal
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg);
+
+__rte_internal
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg);
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/common/mlx5/version.map +2 -0
index a23a30a..413dec1 100644
@@ -153,5 +153,7 @@ INTERNAL {
 	mlx5_mr_mempool2mr_bh;
 	mlx5_mr_mempool_populate_cache;
 
+	mlx5_os_interrupt_handler_create; # WINDOWS_NO_EXPORT
+	mlx5_os_interrupt_handler_destroy; # WINDOWS_NO_EXPORT
 	local: *;
 };
drivers/common/mlx5/windows/mlx5_common_os.h +1 -0
index ee7973f..e9e9108 100644
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <rte_errno.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"

drivers/common/mlx5/windows/mlx5_common_os.h line 257

Quoted 4 lines
drivers/common/mlx5/windows/mlx5_common_os.h +1 -0
@@ -253,4 +254,27 @@
 __rte_internal
 int mlx5_os_umem_dereg(void *pumem);
 
+static inline struct rte_intr_handle *

Are you sure the static inline is required here, anywhere I see this called is from a function pointer?

Quoted 522 lines
drivers/common/mlx5/windows/mlx5_common_os.h +22 -0
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)mode;
+	(void)set_fd_nonblock;
+	(void)fd;
+	(void)cb;
+	(void)cb_arg;
+	rte_errno = ENOTSUP;
+	return NULL;
+}
+
+static inline void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)intr_handle;
+	(void)cb;
+	(void)cb_arg;
+}
+
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/net/mlx5/linux/mlx5_ethdev_os.c +0 -71
index 8d30ad0..760eaed 100644
@@ -881,77 +881,6 @@ struct ethtool_link_settings {
 	}
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	/*
-	 * Try to reduce timeout management overhead by not calling
-	 * the timer related routines on the first iteration. If the
-	 * unregistering succeeds on first call there will be no
-	 * timer calls at all.
-	 */
-	uint64_t twait = 0;
-	uint64_t start = 0;
-
-	do {
-		int ret;
-
-		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
-		if (ret >= 0)
-			return;
-		if (ret != -EAGAIN) {
-			DRV_LOG(INFO, "failed to unregister interrupt"
-				      " handler (error: %d)", ret);
-			MLX5_ASSERT(false);
-			return;
-		}
-		if (twait) {
-			struct timespec onems;
-
-			/* Wait one millisecond and try again. */
-			onems.tv_sec = 0;
-			onems.tv_nsec = NS_PER_S / MS_PER_S;
-			nanosleep(&onems, 0);
-			/* Check whether one second elapsed. */
-			if ((rte_get_timer_cycles() - start) <= twait)
-				continue;
-		} else {
-			/*
-			 * We get the amount of timer ticks for one second.
-			 * If this amount elapsed it means we spent one
-			 * second in waiting. This branch is executed once
-			 * on first iteration.
-			 */
-			twait = rte_get_timer_hz();
-			MLX5_ASSERT(twait);
-		}
-		/*
-		 * Timeout elapsed, show message (once a second) and retry.
-		 * We have no other acceptable option here, if we ignore
-		 * the unregistering return code the handler will not
-		 * be unregistered, fd will be closed and we may get the
-		 * crush. Hanging and messaging in the loop seems not to be
-		 * the worst choice.
-		 */
-		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
-		start = rte_get_timer_cycles();
-	} while (true);
-}
-
 /**
  * Handle DEVX interrupts from the NIC.
  * This function is probably called from the DPDK host thread.
drivers/net/mlx5/linux/mlx5_os.c +29 -103
index a821153..0741028 100644
@@ -2494,40 +2494,6 @@
 	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;
-	}
-	rte_intr_type_set(sh->intr_handle_nl, RTE_INTR_HANDLE_EXT);
-	rte_intr_fd_set(sh->intr_handle_nl, 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");
-		rte_intr_fd_set(sh->intr_handle_nl, -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
@@ -2539,76 +2505,47 @@
 void
 mlx5_os_dev_shared_handler_install(struct mlx5_dev_ctx_shared *sh)
 {
-	int ret;
-	int flags;
 	struct ibv_context *ctx = sh->cdev->ctx;
+	int nlsk_fd;
 
-	sh->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		rte_errno = ENOMEM;
+	sh->intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 ctx->async_fd, mlx5_dev_interrupt_handler, sh);
+	if (!sh->intr_handle) {
+		DRV_LOG(ERR, "Failed to allocate intr_handle.");
 		return;
 	}
-	rte_intr_fd_set(sh->intr_handle, -1);
-
-	flags = fcntl(ctx->async_fd, F_GETFL);
-	ret = fcntl(ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
-	if (ret) {
-		DRV_LOG(INFO, "failed to change file descriptor async event"
-			" queue");
-	} else {
-		rte_intr_fd_set(sh->intr_handle, ctx->async_fd);
-		rte_intr_type_set(sh->intr_handle, RTE_INTR_HANDLE_EXT);
-		if (rte_intr_callback_register(sh->intr_handle,
-					mlx5_dev_interrupt_handler, sh)) {
-			DRV_LOG(INFO, "Fail to install the shared interrupt.");
-			rte_intr_fd_set(sh->intr_handle, -1);
-		}
+	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;
 	}
-	sh->intr_handle_nl = rte_intr_instance_alloc
-						(RTE_INTR_INSTANCE_F_SHARED);
+	sh->intr_handle_nl = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 nlsk_fd, mlx5_dev_interrupt_handler_nl, sh);
 	if (sh->intr_handle_nl == NULL) {
 		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		rte_errno = ENOMEM;
 		return;
 	}
-	rte_intr_fd_set(sh->intr_handle_nl, -1);
-	if (mlx5_os_dev_shared_handler_install_lsc(sh) < 0) {
-		DRV_LOG(INFO, "Fail to install the shared Netlink event handler.");
-		rte_intr_fd_set(sh->intr_handle_nl, -1);
-	}
 	if (sh->cdev->config.devx) {
 #ifdef HAVE_IBV_DEVX_ASYNC
-		sh->intr_handle_devx =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-		if (!sh->intr_handle_devx) {
-			DRV_LOG(ERR, "Fail to allocate intr_handle");
-			rte_errno = ENOMEM;
-			return;
-		}
-		rte_intr_fd_set(sh->intr_handle_devx, -1);
+		struct mlx5dv_devx_cmd_comp *devx_comp;
+
 		sh->devx_comp = (void *)mlx5_glue->devx_create_cmd_comp(ctx);
-		struct mlx5dv_devx_cmd_comp *devx_comp = sh->devx_comp;
+		devx_comp = sh->devx_comp;
 		if (!devx_comp) {
 			DRV_LOG(INFO, "failed to allocate devx_comp.");
 			return;
 		}
-		flags = fcntl(devx_comp->fd, F_GETFL);
-		ret = fcntl(devx_comp->fd, F_SETFL, flags | O_NONBLOCK);
-		if (ret) {
-			DRV_LOG(INFO, "failed to change file descriptor"
-				" devx comp");
+		sh->intr_handle_devx = mlx5_os_interrupt_handler_create
+			(RTE_INTR_INSTANCE_F_SHARED, true,
+			 devx_comp->fd,
+			 mlx5_dev_interrupt_handler_devx, sh);
+		if (!sh->intr_handle_devx) {
+			DRV_LOG(ERR, "Failed to allocate intr_handle.");
 			return;
 		}
-		rte_intr_fd_set(sh->intr_handle_devx, devx_comp->fd);
-		rte_intr_type_set(sh->intr_handle_devx,
-					 RTE_INTR_HANDLE_EXT);
-		if (rte_intr_callback_register(sh->intr_handle_devx,
-					mlx5_dev_interrupt_handler_devx, sh)) {
-			DRV_LOG(INFO, "Fail to install the devx shared"
-				" interrupt.");
-			rte_intr_fd_set(sh->intr_handle_devx, -1);
-		}
 #endif /* HAVE_IBV_DEVX_ASYNC */
 	}
 }
@@ -2624,24 +2561,13 @@
 void
 mlx5_os_dev_shared_handler_uninstall(struct mlx5_dev_ctx_shared *sh)
 {
-	int nlsk_fd;
-
-	if (rte_intr_fd_get(sh->intr_handle) >= 0)
-		mlx5_intr_callback_unregister(sh->intr_handle,
-					      mlx5_dev_interrupt_handler, sh);
-	rte_intr_instance_free(sh->intr_handle);
-	nlsk_fd = rte_intr_fd_get(sh->intr_handle_nl);
-	if (nlsk_fd >= 0) {
-		mlx5_intr_callback_unregister
-			(sh->intr_handle_nl, mlx5_dev_interrupt_handler_nl, sh);
-		close(nlsk_fd);
-	}
-	rte_intr_instance_free(sh->intr_handle_nl);
+	mlx5_os_interrupt_handler_destroy(sh->intr_handle,
+					  mlx5_dev_interrupt_handler, sh);
+	mlx5_os_interrupt_handler_destroy(sh->intr_handle_nl,
+					  mlx5_dev_interrupt_handler_nl, sh);
 #ifdef HAVE_IBV_DEVX_ASYNC
-	if (rte_intr_fd_get(sh->intr_handle_devx) >= 0)
-		rte_intr_callback_unregister(sh->intr_handle_devx,
-				  mlx5_dev_interrupt_handler_devx, sh);
-	rte_intr_instance_free(sh->intr_handle_devx);
+	mlx5_os_interrupt_handler_destroy(sh->intr_handle_devx,
+					  mlx5_dev_interrupt_handler_devx, sh);
 	if (sh->devx_comp)
 		mlx5_glue->devx_destroy_cmd_comp(sh->devx_comp);
 #endif
drivers/net/mlx5/linux/mlx5_socket.c +6 -47
index 4882e5f..0e01aff 100644
@@ -134,51 +134,6 @@
 }
 
 /**
- * Install interrupt handler.
- *
- * @param dev
- *   Pointer to Ethernet device.
- * @return
- *   0 on success, a negative errno value otherwise.
- */
-static int
-mlx5_pmd_interrupt_handler_install(void)
-{
-	MLX5_ASSERT(server_socket != -1);
-
-	server_intr_handle =
-		rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
-	if (server_intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
-	if (rte_intr_fd_set(server_intr_handle, server_socket))
-		return -rte_errno;
-
-	if (rte_intr_type_set(server_intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	return rte_intr_callback_register(server_intr_handle,
-					  mlx5_pmd_socket_handle, NULL);
-}
-
-/**
- * Uninstall interrupt handler.
- */
-static void
-mlx5_pmd_interrupt_handler_uninstall(void)
-{
-	if (server_socket != -1) {
-		mlx5_intr_callback_unregister(server_intr_handle,
-					      mlx5_pmd_socket_handle,
-					      NULL);
-	}
-	rte_intr_fd_set(server_intr_handle, 0);
-	rte_intr_type_set(server_intr_handle, RTE_INTR_HANDLE_UNKNOWN);
-	rte_intr_instance_free(server_intr_handle);
-}
-
-/**
  * Initialise the socket to communicate with external tools.
  *
  * @return
@@ -224,7 +179,10 @@
 			strerror(errno));
 		goto remove;
 	}
-	if (mlx5_pmd_interrupt_handler_install()) {
+	server_intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_PRIVATE, false,
+		 server_socket, mlx5_pmd_socket_handle, NULL);
+	if (server_intr_handle == NULL) {
 		DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s",
 			strerror(errno));
 		goto remove;
@@ -248,7 +206,8 @@
 {
 	if (server_socket == -1)
 		return;
-	mlx5_pmd_interrupt_handler_uninstall();
+	mlx5_os_interrupt_handler_destroy(server_intr_handle,
+					  mlx5_pmd_socket_handle, NULL);
 	claim_zero(close(server_socket));
 	server_socket = -1;
 	MKSTR(path, MLX5_SOCKET_PATH, getpid());
drivers/net/mlx5/mlx5.h +0 -2
index 305edff..7ebb2cc 100644
@@ -1682,8 +1682,6 @@ int mlx5_sysfs_switch_info(unsigned int ifindex,
 			   struct mlx5_switch_info *info);
 void mlx5_translate_port_name(const char *port_name_in,
 			      struct mlx5_switch_info *port_info_out);
-void mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-				   rte_intr_callback_fn cb_fn, void *cb_arg);
 int mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
 			 char *ifname);
 int mlx5_get_module_info(struct rte_eth_dev *dev,
drivers/net/mlx5/mlx5_txpp.c +7 -21
index fe74317..f853a67 100644
@@ -741,11 +741,8 @@
 static void
 mlx5_txpp_stop_service(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!rte_intr_fd_get(sh->txpp.intr_handle))
-		return;
-	mlx5_intr_callback_unregister(sh->txpp.intr_handle,
-				      mlx5_txpp_interrupt_handler, sh);
-	rte_intr_instance_free(sh->txpp.intr_handle);
+	mlx5_os_interrupt_handler_destroy(sh->txpp.intr_handle,
+					  mlx5_txpp_interrupt_handler, sh);
 }
 
 /* Attach interrupt handler and fires first request to Rearm Queue. */
@@ -769,23 +766,12 @@
 		rte_errno = errno;
 		return -rte_errno;
 	}
-	sh->txpp.intr_handle =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->txpp.intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
 	fd = mlx5_os_get_devx_channel_fd(sh->txpp.echan);
-	if (rte_intr_fd_set(sh->txpp.intr_handle, fd))
-		return -rte_errno;
-
-	if (rte_intr_type_set(sh->txpp.intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	if (rte_intr_callback_register(sh->txpp.intr_handle,
-				       mlx5_txpp_interrupt_handler, sh)) {
-		rte_intr_fd_set(sh->txpp.intr_handle, 0);
-		DRV_LOG(ERR, "Failed to register CQE interrupt %d.", rte_errno);
+	sh->txpp.intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, false,
+		 fd, mlx5_txpp_interrupt_handler, sh);
+	if (!sh->txpp.intr_handle) {
+		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		return -rte_errno;
 	}
 	/* Subscribe CQ event to the event channel controlled by the driver. */
drivers/net/mlx5/windows/mlx5_ethdev_os.c +0 -22
index f975265..88d8213 100644
@@ -140,28 +140,6 @@
 	return 0;
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	RTE_SET_USED(handle);
-	RTE_SET_USED(cb_fn);
-	RTE_SET_USED(cb_arg);
-}
-
 /**
  * DPDK callback to get flow control status.
  *
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +7 -41
index e025be4..fd447cc 100644
@@ -93,22 +93,10 @@
 static int
 mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq)
 {
-	int ret = -EAGAIN;
-
-	if (rte_intr_fd_get(virtq->intr_handle) >= 0) {
-		while (ret == -EAGAIN) {
-			ret = rte_intr_callback_unregister(virtq->intr_handle,
-					mlx5_vdpa_virtq_kick_handler, virtq);
-			if (ret == -EAGAIN) {
-				DRV_LOG(DEBUG, "Try again to unregister fd %d of virtq %hu interrupt",
-					rte_intr_fd_get(virtq->intr_handle),
-					virtq->index);
-				usleep(MLX5_VDPA_INTR_RETRIES_USEC);
-			}
-		}
-		rte_intr_fd_set(virtq->intr_handle, -1);
-	}
-	rte_intr_instance_free(virtq->intr_handle);
+	int ret;
+
+	mlx5_os_interrupt_handler_destroy(virtq->intr_handle,
+					  mlx5_vdpa_virtq_kick_handler, virtq);
 	if (virtq->virtq) {
 		ret = mlx5_vdpa_virtq_stop(virtq->priv, virtq->index);
 		if (ret)
@@ -365,35 +353,13 @@
 	virtq->priv = priv;
 	rte_write32(virtq->index, priv->virtq_db_addr);
 	/* Setup doorbell mapping. */
-	virtq->intr_handle =
-		rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
+	virtq->intr_handle = mlx5_os_interrupt_handler_create(
+				  RTE_INTR_INSTANCE_F_SHARED, false,
+				  vq.kickfd, mlx5_vdpa_virtq_kick_handler, virtq);
 	if (virtq->intr_handle == NULL) {
 		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		goto error;
 	}
-
-	if (rte_intr_fd_set(virtq->intr_handle, vq.kickfd))
-		goto error;
-
-	if (rte_intr_fd_get(virtq->intr_handle) == -1) {
-		DRV_LOG(WARNING, "Virtq %d kickfd is invalid.", index);
-	} else {
-		if (rte_intr_type_set(virtq->intr_handle, RTE_INTR_HANDLE_EXT))
-			goto error;
-
-		if (rte_intr_callback_register(virtq->intr_handle,
-					       mlx5_vdpa_virtq_kick_handler,
-					       virtq)) {
-			rte_intr_fd_set(virtq->intr_handle, -1);
-			DRV_LOG(ERR, "Failed to register virtq %d interrupt.",
-				index);
-			goto error;
-		} else {
-			DRV_LOG(DEBUG, "Register fd %d interrupt for virtq %d.",
-				rte_intr_fd_get(virtq->intr_handle),
-				index);
-		}
-	}
 	/* Subscribe virtq error event. */
 	virtq->version++;
 	cookie = ((uint64_t)virtq->version << 32) + index;
Signature · 1 line
Regards, Ray K
author
#99 lore raw

PATCH v10 3/6 net/mlx5: add LWM event handling support

In reply to Spike Du

When LWM meets RQ WQE, the kernel driver raises an event to SW. Use devx event_channel to catch this and to notify the user. Allocate this channel per shared device.
The channel has a cookie that informs the specific event port and queue.

---
 drivers/net/mlx5/mlx5.c      | 66 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5.h      |  7 +++++
 drivers/net/mlx5/mlx5_devx.c | 47 +++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.c   | 33 ++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h   |  7 +++++
 5 files changed, 160 insertions(+)
drivers/net/mlx5/mlx5.c +66 -0
index f098871..e04a666 100644
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <rte_malloc.h>
 #include <ethdev_driver.h>
@@ -22,6 +23,7 @@
 #include <rte_eal_paging.h>
 #include <rte_alarm.h>
 #include <rte_cycles.h>
+#include <rte_interrupts.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -1525,6 +1527,69 @@ struct mlx5_dev_ctx_shared *
 }
 
 /**
+ * Create LWM event_channel and interrupt handle for shared device
+ * context. All rxqs sharing the device context share the event_channel.
+ * A callback is registered in interrupt thread to receive the LWM event.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5_priv instance.
+ *
+ * @return
+ *   0 on success, negative with rte_errno set.
+ */
+int
+mlx5_lwm_setup(struct mlx5_priv *priv)
+{
+	int fd_lwm;
+
+	pthread_mutex_init(&priv->sh->lwm_config_lock, NULL);
+	priv->sh->devx_channel_lwm = mlx5_os_devx_create_event_channel
+			(priv->sh->cdev->ctx,
+			 MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
+	if (!priv->sh->devx_channel_lwm)
+		goto err;
+	fd_lwm = mlx5_os_get_devx_channel_fd(priv->sh->devx_channel_lwm);
+	priv->sh->intr_handle_lwm = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 fd_lwm, mlx5_dev_interrupt_handler_lwm, priv);
+	if (!priv->sh->intr_handle_lwm)
+		goto err;
+	return 0;
+err:
+	if (priv->sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(priv->sh->devx_channel_lwm);
+		priv->sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&priv->sh->lwm_config_lock);
+	return -rte_errno;
+}
+
+/**
+ * Destroy LWM event_channel and interrupt handle for shared device
+ * context before free this context. The interrupt handler is also
+ * unregistered.
+ *
+ * @param[in] sh
+ *   Pointer to shared device context.
+ */
+void
+mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh)
+{
+	if (sh->intr_handle_lwm) {
+		mlx5_os_interrupt_handler_destroy(sh->intr_handle_lwm,
+			mlx5_dev_interrupt_handler_lwm, (void *)-1);
+		sh->intr_handle_lwm = NULL;
+	}
+	if (sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(sh->devx_channel_lwm);
+		sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&sh->lwm_config_lock);
+}
+
+/**
  * Free shared IB device context. Decrement counter and if zero free
  * all allocated resources and close handles.
  *
@@ -1601,6 +1666,7 @@ struct mlx5_dev_ctx_shared *
 		claim_zero(mlx5_devx_cmd_destroy(sh->td));
 	MLX5_ASSERT(sh->geneve_tlv_option_resource == NULL);
 	pthread_mutex_destroy(&sh->txpp.mutex);
+	mlx5_lwm_unset(sh);
 	mlx5_free(sh);
 	return;
 exit:
drivers/net/mlx5/mlx5.h +7 -0
index 7ebb2cc..a76f2fe 100644
@@ -1268,6 +1268,9 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */
 	unsigned int flow_max_priority;
 	enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM];
+	void *devx_channel_lwm;
+	struct rte_intr_handle *intr_handle_lwm;
+	pthread_mutex_t lwm_config_lock;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
@@ -1405,6 +1408,7 @@ enum mlx5_txq_modify_type {
 };
 
 struct mlx5_rxq_priv;
+struct mlx5_priv;
 
 /* HW objects operations structure. */
 struct mlx5_obj_ops {
@@ -1413,6 +1417,7 @@ struct mlx5_obj_ops {
 	int (*rxq_event_get)(struct mlx5_rxq_obj *rxq_obj);
 	int (*rxq_obj_modify)(struct mlx5_rxq_priv *rxq, uint8_t type);
 	void (*rxq_obj_release)(struct mlx5_rxq_priv *rxq);
+	int (*rxq_event_get_lwm)(struct mlx5_priv *priv, int *rxq_idx, int *port_id);
 	int (*ind_table_new)(struct rte_eth_dev *dev, const unsigned int log_n,
 			     struct mlx5_ind_table_obj *ind_tbl);
 	int (*ind_table_modify)(struct rte_eth_dev *dev,
@@ -1603,6 +1608,8 @@ int mlx5_udp_tunnel_port_add(struct rte_eth_dev *dev,
 bool mlx5_is_hpf(struct rte_eth_dev *dev);
 bool mlx5_is_sf_repr(struct rte_eth_dev *dev);
 void mlx5_age_event_prepare(struct mlx5_dev_ctx_shared *sh);
+int mlx5_lwm_setup(struct mlx5_priv *priv);
+void mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh);
 
 /* Macro to iterate over all valid ports for mlx5 driver. */
 #define MLX5_ETH_FOREACH_DEV(port_id, dev) \
drivers/net/mlx5/mlx5_devx.c +47 -0

59 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.c +33 -0
index e5eea0a..197d708 100644
@@ -1187,3 +1187,36 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 {
 	return -ENOTSUP;
 }
+
+/**
+ * Rte interrupt handler for LWM event.
+ * It first checks if the event arrives, if so process the callback for
+ * RTE_ETH_EVENT_RX_LWM.
+ *
+ * @param args
+ *   Generic pointer to mlx5_priv.
+ */
+void
+mlx5_dev_interrupt_handler_lwm(void *args)
+{
+	struct mlx5_priv *priv = args;
+	struct mlx5_rxq_priv *rxq;
+	struct rte_eth_dev *dev;
+	int ret, rxq_idx = 0, port_id = 0;
+
+	ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
+	if (unlikely(ret < 0)) {
+		DRV_LOG(WARNING, "Cannot get LWM event context.");
+		return;
+	}
+	DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
+		port_id, rxq_idx);
+	dev = &rte_eth_devices[port_id];
+	rxq = mlx5_rxq_get(dev, rxq_idx);
+	if (rxq) {
+		pthread_mutex_lock(&priv->sh->lwm_config_lock);
+		rxq->lwm_event_pending = 1;
+		pthread_mutex_unlock(&priv->sh->lwm_config_lock);
+	}
+	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
+}
drivers/net/mlx5/mlx5_rx.h +7 -0
index 25a5f2c..068dff5 100644
@@ -176,6 +176,7 @@ struct mlx5_rxq_priv {
 	struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
+	uint32_t lwm_event_pending:1;
 };
 
 /* External RX queue descriptor. */
@@ -295,6 +296,7 @@ void mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+void mlx5_dev_interrupt_handler_lwm(void *args);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
@@ -675,4 +677,9 @@ uint16_t mlx5_rx_burst_mprq_vec(void *dpdk_rxq, struct rte_mbuf **pkts,
 	return !!__atomic_load_n(&rxq->refcnt, __ATOMIC_RELAXED);
 }
 
+#define LWM_COOKIE_RXQID_OFFSET 0
+#define LWM_COOKIE_RXQID_MASK 0xffff
+#define LWM_COOKIE_PORTID_OFFSET 16
+#define LWM_COOKIE_PORTID_MASK 0xffff
+
 #endif /* RTE_PMD_MLX5_RX_H_ */
Signature · 1 line
1.8.3.1
author
#100 lore raw

PATCH v10 4/6 net/mlx5: support Rx queue based available descriptor threshold

In reply to Spike Du

Add mlx5 specific available descriptor threshold configuration and query handler.
In mlx5 PMD, available descriptor threshold is also called LWM(limit watermark).
While the Rx queue fullness reaches the LWM limit, the driver catches an HW event and invokes the user callback.
The query handler finds the next RX queue with pending LWM event if any, starting from the given RX queue index.

---
 doc/guides/nics/mlx5.rst               |  12 +++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/mlx5_prm.h         |   1 +
 drivers/net/mlx5/mlx5.c                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 151 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h             |   5 ++
 6 files changed, 172 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
index d83c56d..cceaddf 100644
@@ -93,6 +93,7 @@ Features
 - Connection tracking.
 - Sub-Function representors.
 - Sub-Function.
+- Rx queue available descriptor threshold configuration.
 
 
 Limitations
@@ -520,6 +521,9 @@ Limitations
 
 - The NIC egress flow rules on representor port are not supported.
 
+- Available descriptor threshold:
+
+  - Doesn't support shared Rx queue and Hairpin Rx queue.
 
 Statistics
 ----------
@@ -1680,3 +1684,11 @@ The procedure below is an example of using a ConnectX-5 adapter card (pf0) with
 #. For each VF PCIe, using the following command to bind the driver::
 
    $ echo "0000:82:00.2" >> /sys/bus/pci/drivers/mlx5_core/bind
+
+Available descriptor threshold introduction
+-------------------------------------------
+
+Available descriptor threshold is a per Rx queue attribute, it should be configured as
+a percentage of the Rx queue size.
+When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
+
doc/guides/rel_notes/release_22_07.rst +1 -0
index 6fc044e..7fb98cd 100644
@@ -151,6 +151,7 @@ New Features
   * Added support for promiscuous mode on Windows.
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
+  * Added Rx queue available descriptor threshold support.
 
 * **Updated VMware vmxnet3 networking driver.**
 
drivers/common/mlx5/mlx5_prm.h +1 -0
index 654e5f4..7c4030a 100644
@@ -3294,6 +3294,7 @@ struct mlx5_aso_wqe {
 
 enum {
 	MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+	MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED = 0x14,
 };
 
 enum {
drivers/net/mlx5/mlx5.c +2 -0
index e04a666..998846a 100644
@@ -2071,6 +2071,8 @@ struct mlx5_dev_ctx_shared *
 	.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
 	.vlan_filter_set = mlx5_vlan_filter_set,
 	.rx_queue_setup = mlx5_rx_queue_setup,
+	.rx_queue_avail_thresh_set = mlx5_rx_queue_lwm_set,
+	.rx_queue_avail_thresh_query = mlx5_rx_queue_lwm_query,
 	.rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,
 	.tx_queue_setup = mlx5_tx_queue_setup,
 	.tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
drivers/net/mlx5/mlx5_rx.c +151 -0

184 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.h +5 -0
index 068dff5..e078aaf 100644
@@ -177,6 +177,7 @@ struct mlx5_rxq_priv {
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
 	uint32_t lwm_event_pending:1;
+	uint32_t lwm_devx_subscribed:1;
 };
 
 /* External RX queue descriptor. */
@@ -297,6 +298,10 @@ int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 void mlx5_dev_interrupt_handler_lwm(void *args);
+int mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			  uint8_t lwm);
+int mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev, uint16_t *rx_queue_id,
+			    uint8_t *lwm);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
Signature · 1 line
1.8.3.1
author
#101 lore raw

PATCH v10 5/6 net/mlx5: add private API to config host port shaper

In reply to Spike Du

Host port shaper can be configured with QSHR(QoS Shaper Host Register). Add check in build files to enable this function or not.

The host shaper configuration affects all the ethdev ports belonging to the same host port.

Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives available descriptor threshold event.

---
 doc/guides/nics/mlx5.rst               |  35 +++++++++++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/linux/meson.build  |  13 +++++
 drivers/common/mlx5/mlx5_prm.h         |  25 ++++++++
 drivers/net/mlx5/mlx5.h                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 104 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/rte_pmd_mlx5.h        |  30 ++++++++++
 drivers/net/mlx5/version.map           |   2 +
 8 files changed, 212 insertions(+)
doc/guides/nics/mlx5.rst +35 -0
index cceaddf..5f7b060 100644
@@ -94,6 +94,7 @@ Features
 - Sub-Function representors.
 - Sub-Function.
 - Rx queue available descriptor threshold configuration.
+- Host shaper support.
 
 
 Limitations
@@ -525,6 +526,12 @@ Limitations
 
   - Doesn't support shared Rx queue and Hairpin Rx queue.
 
+- Host shaper:
+
+  - Support BlueField series NIC from BlueField 2.
+  - When configure host shaper with MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED flag set,
+    only rate 0 and 100Mbps are supported.
+
 Statistics
 ----------
 
@@ -1692,3 +1699,31 @@ Available descriptor threshold is a per Rx queue attribute, it should be configu
 a percentage of the Rx queue size.
 When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
 
+Host shaper introduction
+------------------------
+
+Host shaper register is per host port register which sets a shaper
+on the host port.
+All VF/hostPF representors belonging to one host port share one host shaper.
+For example, if representor 0 and representor 1 belong to same host port,
+and a host shaper rate of 1Gbps is configured, the shaper throttles both
+representors' traffic from host.
+Host shaper has two modes for setting the shaper, immediate and deferred to
+available descriptor threshold event trigger. In immediate mode, the rate limit is configured
+immediately to host shaper. When deferring to available descriptor threshold trigger, the shaper
+is not set until an available descriptor threshold event is received by any Rx queue in a VF
+representor belonging to the host port. The only rate supported for deferred
+mode is 100Mbps (there is no limit on the supported rates for immediate mode).
+In deferred mode, the shaper is set on the host port by the firmware upon
+receiving the available descriptor threshold event, which allows throttling host traffic on
+available descriptor threshold events at minimum latency, preventing excess drops in the
+Rx queue.
+
+Host shaper dependency for mstflint package
+-------------------------------------------
+
+In order to configure host shaper register, ``librte_net_mlx5`` depends on ``libmtcr_ul``
+which can be installed from OFED mstflint package.
+Meson detects ``libmtcr_ul`` existence at configure stage.
+If the library is detected, the application must link with ``-lmtcr_ul``,
+as done by the pkg-config file libdpdk.pc.
doc/guides/rel_notes/release_22_07.rst +1 -0
index 7fb98cd..199a775 100644
@@ -152,6 +152,7 @@ New Features
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
   * Added Rx queue available descriptor threshold support.
+  * Added host shaper support.
 
 * **Updated VMware vmxnet3 networking driver.**
 
drivers/common/mlx5/linux/meson.build +13 -0
index 5335f5b..51c6e5d 100644
@@ -45,6 +45,13 @@ if static_ibverbs
     ext_deps += declare_dependency(link_args:ibv_ldflags.split())
 endif
 
+libmtcr_ul_found = false
+lib = cc.find_library('mtcr_ul', required:false)
+if lib.found() and run_command('meson', '--version').stdout().version_compare('>= 0.49.2')
+    libmtcr_ul_found = true
+    ext_deps += lib
+endif
+
 sources += files('mlx5_nl.c')
 sources += files('mlx5_common_auxiliary.c')
 sources += files('mlx5_common_os.c')
@@ -207,6 +214,12 @@ has_sym_args = [
         [ 'HAVE_MLX5_IBV_IMPORT_CTX_PD_AND_MR', 'infiniband/verbs.h',
             'ibv_import_device' ],
 ]
+if  libmtcr_ul_found
+    has_sym_args += [
+        [  'HAVE_MLX5_MSTFLINT', 'mstflint/mtcr.h',
+            'mopen'],
+    ]
+endif
 config = configuration_data()
 foreach arg:has_sym_args
     config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
drivers/common/mlx5/mlx5_prm.h +25 -0
index 7c4030a..137a7c5 100644
@@ -3772,6 +3772,7 @@ enum {
 	MLX5_CRYPTO_COMMISSIONING_REGISTER_ID = 0xC003,
 	MLX5_IMPORT_KEK_HANDLE_REGISTER_ID = 0xC004,
 	MLX5_CREDENTIAL_HANDLE_REGISTER_ID = 0xC005,
+	MLX5_QSHR_REGISTER_ID = 0x4030,
 };
 
 struct mlx5_ifc_register_mtutc_bits {
@@ -3786,6 +3787,30 @@ struct mlx5_ifc_register_mtutc_bits {
 	u8 time_adjustment[0x20];
 };
 
+struct mlx5_ifc_ets_global_config_register_bits {
+	u8 reserved_at_0[0x2];
+	u8 rate_limit_update[0x1];
+	u8 reserved_at_3[0x29];
+	u8 max_bw_units[0x4];
+	u8 reserved_at_48[0x8];
+	u8 max_bw_value[0x8];
+};
+
+#define ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED      0x0
+#define ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS 0x3
+#define ETS_GLOBAL_CONFIG_BW_UNIT_GBPS          0x4
+
+struct mlx5_ifc_register_qshr_bits {
+	u8 reserved_at_0[0x4];
+	u8 connected_host[0x1];
+	u8 vqos[0x1];
+	u8 fast_response[0x1];
+	u8 reserved_at_7[0x1];
+	u8 local_port[0x8];
+	u8 reserved_at_16[0x230];
+	struct mlx5_ifc_ets_global_config_register_bits global_config;
+};
+
 #define MLX5_MTUTC_TIMESTAMP_MODE_INTERNAL_TIMER 0
 #define MLX5_MTUTC_TIMESTAMP_MODE_REAL_TIME 1
 
drivers/net/mlx5/mlx5.h +2 -0
index a76f2fe..8af84ae 100644
@@ -1271,6 +1271,8 @@ struct mlx5_dev_ctx_shared {
 	void *devx_channel_lwm;
 	struct rte_intr_handle *intr_handle_lwm;
 	pthread_mutex_t lwm_config_lock;
+	uint32_t host_shaper_rate:8;
+	uint32_t lwm_triggered:1;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
drivers/net/mlx5/mlx5_rx.c +104 -0

119 lines not on this page · raw message

drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
index 6e7907e..fbfdd97 100644
@@ -109,6 +109,36 @@ int rte_pmd_mlx5_external_rx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
 int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id,
 					    uint16_t dpdk_idx);
 
+/**
+ * The rate of the host port shaper will be updated directly at the next
+ * available descriptor threshold event to the rate that comes with this flag set;
+ * set rate 0 to disable this rate update.
+ * Unset this flag to update the rate of the host port shaper directly in
+ * the API call; use rate 0 to disable the current shaper.
+ */
+#define MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED 0
+
+/**
+ * Configure a HW shaper to limit Tx rate for a host port.
+ * The configuration will affect all the ethdev ports belonging to
+ * the same rte_device.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] rate
+ *   Unit is 100Mbps, setting the rate to 0 disables the shaper.
+ * @param[in] flags
+ *   Host shaper flags.
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOENT - no ibdev interface.
+ *   - EBUSY  - the register access unit is busy.
+ *   - EIO    - the register access command meets IO error.
+ */
+__rte_experimental
+int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, uint32_t flags);
+
 #ifdef __cplusplus
 }
 #endif
drivers/net/mlx5/version.map +2 -0
index 79cb79a..c97dfe4 100644
@@ -12,4 +12,6 @@ EXPERIMENTAL {
 	# added in 22.03
 	rte_pmd_mlx5_external_rx_queue_id_map;
 	rte_pmd_mlx5_external_rx_queue_id_unmap;
+	# added in 22.07
+	rte_pmd_mlx5_host_shaper_config;
 };
Signature · 1 line
1.8.3.1
author
#102 lore raw

PATCH v10 6/6 app/testpmd: add Host Shaper command

In reply to Spike Du

Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> rate
<rate_num>

- Example commands:
To enable avail_thresh_triggered on port 1 and disable current host shaper:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 1 rate 0

To disable avail_thresh_triggered and current host shaper on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 0

The rate unit is 100Mbps.
To disable avail_thresh_triggered and configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50

Add sample code to handle rxq available descriptor threshold event, it delays a while so that rxq empties, then disables host shaper and rearms available descriptor threshold event.

---
 app/test-pmd/testpmd.c          |   7 ++
 doc/guides/nics/mlx5.rst        |  46 +++++++++
 drivers/net/mlx5/meson.build    |   3 +
 drivers/net/mlx5/mlx5_testpmd.c | 205 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_testpmd.h |  26 +++++
 5 files changed, 287 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.c
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +7 -0
index 205d98e..e6321bd 100644
@@ -69,6 +69,9 @@
 #ifdef RTE_NET_BOND
 #include <rte_eth_bond.h>
 #endif
+#ifdef RTE_NET_MLX5
+#include "mlx5_testpmd.h"
+#endif
 
 #include "testpmd.h"
 
@@ -3726,6 +3729,10 @@ struct pmd_test_command {
 				break;
 			printf("Received avail_thresh event, port: %u, rxq_id: %u\n",
 			       port_id, rxq_id);
+
+#ifdef RTE_NET_MLX5
+			mlx5_test_avail_thresh_event_handler(port_id, rxq_id);
+#endif
 		}
 		break;
 	}
doc/guides/nics/mlx5.rst +46 -0

49 lines not on this page · raw message

drivers/net/mlx5/meson.build +3 -0
index 99210fd..6a84d96 100644
@@ -68,4 +68,7 @@ if get_option('buildtype').contains('debug')
 else
     cflags += [ '-UPEDANTIC' ]
 endif
+
+testpmd_sources += files('mlx5_testpmd.c')
+
 subdir(exec_env)
drivers/net/mlx5/mlx5_testpmd.c new file +205 -0

205 lines not on this page · raw message

drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
new file mode 100644
index 0000000..7a54658
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 6WIND S.A.
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#ifndef RTE_PMD_MLX5_TEST_H_
+#define RTE_PMD_MLX5_TEST_H_
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+/**
+ * RTE_ETH_EVENT_RX_AVAIL_THRESH handler sample code.
+ * It's called in testpmd, the work flow here is delay a while until
+ * RX queueu is empty, then disable host shaper.
+ *
+ * @param[in] port_id
+ *   Port identifier.
+ * @param[in] rxq_id
+ *   Rx queue identifier.
+ */
+void
+mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id);
+
+#endif
Signature · 1 line
1.8.3.1
#103 lore raw

RE: [PATCH v10 0/6] introduce per-queue available descriptor threshold and host shaper

In reply to Spike Du

Hi,

Quoted 78 lines

-----Original Message-----
From: Spike Du <[email protected]>
Sent: Thursday, June 16, 2022 11:42 AM
To: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: [PATCH v10 0/6] introduce per-queue available descriptor threshold and host shaper

available descriptor threshold(ADT for short) is per RX queue attribute, when RX queue available descriptors for HW is below ADT, HW sends an event to application.
Host shaper can configure shaper rate and avail_thresh-triggered for a host port.
The shaper limits the rate of traffic from host port to embedded ARM rx port on Nvidia BlueField 2 NIC.
If avail_thresh-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives available descriptor threshold event.

These two features can combine to control traffic from host port to wire port for BlueField 2 NIC.
The traffic flows from host to embedded ARM, then to the physical port. The work flow is on the ARM system, configure available descriptor threshold to RX queue and enable avail_thresh-triggered flag in host shaper, after receiving available descriptor threshold event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to reduce RX queue drops on ARM system.

Add new libethdev API to set available descriptor threshold, add rte event RTE_ETH_EVENT_RX_AVAIL_THRESH to handle available descriptor threshold event. For host shaper, because it doesn't align to existing DPDK framework and is specific to Nvidia NIC, use PMD private API.

For integration with testpmd, put the private cmdline function and available descriptor threshold event handler in mlx5 PMD directory by adding a new file mlx5_testpmd.c. Follow David Marchand's driver specific commands framework to add mlx5 specific commands.

Spike Du (6):
net/mlx5: add LWM support for Rxq
common/mlx5: share interrupt management
net/mlx5: add LWM event handling support
net/mlx5: support Rx queue based available descriptor threshold net/mlx5: add private API to config host port shaper app/testpmd: add Host Shaper command

 app/test-pmd/testpmd.c                       |   7 +
 doc/guides/nics/mlx5.rst                     |  93 +++++++++
 doc/guides/rel_notes/release_22_07.rst       |   2 +
 drivers/common/mlx5/linux/meson.build        |  13 ++
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +
 drivers/common/mlx5/mlx5_prm.h               |  26 +++
 drivers/common/mlx5/version.map              |   2 +
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 -------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 +++---------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 +----
 drivers/net/mlx5/meson.build                 |   3 +
 drivers/net/mlx5/mlx5.c                      |  68 +++++++
 drivers/net/mlx5/mlx5.h                      |  12 +-
 drivers/net/mlx5/mlx5_devx.c                 |  60 +++++-
 drivers/net/mlx5/mlx5_devx.h                 |   1 +
 drivers/net/mlx5/mlx5_rx.c                   | 288
+++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h                   |  13 ++
 drivers/net/mlx5/mlx5_testpmd.c              | 205 +++++++++++++++++++
 drivers/net/mlx5/mlx5_testpmd.h              |  26 +++
 drivers/net/mlx5/mlx5_txpp.c                 |  28 +--
 drivers/net/mlx5/rte_pmd_mlx5.h              |  30 +++
 drivers/net/mlx5/version.map                 |   2 +
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 --
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  48 +----
 26 files changed, 1063 insertions(+), 308 deletions(-)  create mode 100644
Quoted 5 lines

drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h

--
1.8.3.1

Series applied to next-net-mlx,

Kindest regards,
Raslan Darawsheh

author
#104 lore raw

PATCH v9 2/6 common/mlx5: share interrupt management

In reply to Spike Du

There are many duplicate code of creating and initializing rte_intr_handle. Add a new mlx5_os API to do this, replace all PMD related code with this API.

---
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +++
 drivers/common/mlx5/version.map              |   2 +
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 --------------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 ++++++---------------------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 ++---------
 drivers/net/mlx5/mlx5.h                      |   2 -
 drivers/net/mlx5/mlx5_txpp.c                 |  28 ++----
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 -----
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  48 ++--------
 11 files changed, 217 insertions(+), 307 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +131 -0
index d40cfd5..f10a981 100644
@@ -11,6 +11,7 @@
 #endif
 #include <dirent.h>
 #include <net/if.h>
+#include <fcntl.h>
 
 #include <rte_errno.h>
 #include <rte_string_fns.h>
@@ -964,3 +965,133 @@
 		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
 	memset(pmd_mr, 0, sizeof(*pmd_mr));
 }
+
+/**
+ * Rte_intr_handle create and init helper.
+ *
+ * @param[in] mode
+ *   interrupt instance can be shared between primary and secondary
+ *   processes or not.
+ * @param[in] set_fd_nonblock
+ *   Whether to set fd to O_NONBLOCK.
+ * @param[in] fd
+ *   Fd to set in created intr_handle.
+ * @param[in] cb
+ *   Callback to register for intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ * @return
+ *  - Interrupt handle on success.
+ *  - NULL on failure, with rte_errno set.
+ */
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle;
+	int ret, flags;
+
+	tmp_intr_handle = rte_intr_instance_alloc(mode);
+	if (!tmp_intr_handle) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	if (set_fd_nonblock) {
+		flags = fcntl(fd, F_GETFL);
+		ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+		if (ret) {
+			rte_errno = errno;
+			goto err;
+		}
+	}
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret)
+		goto err;
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret)
+		goto err;
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		rte_errno = -ret;
+		goto err;
+	}
+	return tmp_intr_handle;
+err:
+	if (tmp_intr_handle)
+		rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+/* Safe unregistration for interrupt callback. */
+static void
+mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
+			      rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+	uint64_t twait = 0;
+	uint64_t start = 0;
+
+	do {
+		int ret;
+
+		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
+		if (ret >= 0)
+			return;
+		if (ret != -EAGAIN) {
+			DRV_LOG(INFO, "failed to unregister interrupt"
+				      " handler (error: %d)", ret);
+			MLX5_ASSERT(false);
+			return;
+		}
+		if (twait) {
+			struct timespec onems;
+
+			/* Wait one millisecond and try again. */
+			onems.tv_sec = 0;
+			onems.tv_nsec = NS_PER_S / MS_PER_S;
+			nanosleep(&onems, 0);
+			/* Check whether one second elapsed. */
+			if ((rte_get_timer_cycles() - start) <= twait)
+				continue;
+		} else {
+			/*
+			 * We get the amount of timer ticks for one second.
+			 * If this amount elapsed it means we spent one
+			 * second in waiting. This branch is executed once
+			 * on first iteration.
+			 */
+			twait = rte_get_timer_hz();
+			MLX5_ASSERT(twait);
+		}
+		/*
+		 * Timeout elapsed, show message (once a second) and retry.
+		 * We have no other acceptable option here, if we ignore
+		 * the unregistering return code the handler will not
+		 * be unregistered, fd will be closed and we may get the
+		 * crush. Hanging and messaging in the loop seems not to be
+		 * the worst choice.
+		 */
+		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
+		start = rte_get_timer_cycles();
+	} while (true);
+}
+
+/**
+ * Rte_intr_handle destroy helper.
+ *
+ * @param[in] intr_handle
+ *   Rte_intr_handle to destroy.
+ * @param[in] cb
+ *   Callback which is registered to intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ */
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
drivers/common/mlx5/linux/mlx5_common_os.h +11 -0
index 27f1192..479bb3c 100644
@@ -15,6 +15,7 @@
 #include <rte_log.h>
 #include <rte_kvargs.h>
 #include <rte_devargs.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -299,4 +300,14 @@
 int
 mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len);
 
+__rte_internal
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg);
+
+__rte_internal
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg);
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/common/mlx5/version.map +2 -0
index a23a30a..413dec1 100644
@@ -153,5 +153,7 @@ INTERNAL {
 	mlx5_mr_mempool2mr_bh;
 	mlx5_mr_mempool_populate_cache;
 
+	mlx5_os_interrupt_handler_create; # WINDOWS_NO_EXPORT
+	mlx5_os_interrupt_handler_destroy; # WINDOWS_NO_EXPORT
 	local: *;
 };
drivers/common/mlx5/windows/mlx5_common_os.h +24 -0
index ee7973f..e9e9108 100644
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <rte_errno.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -253,4 +254,27 @@
 __rte_internal
 int mlx5_os_umem_dereg(void *pumem);
 
+static inline struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)mode;
+	(void)set_fd_nonblock;
+	(void)fd;
+	(void)cb;
+	(void)cb_arg;
+	rte_errno = ENOTSUP;
+	return NULL;
+}
+
+static inline void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)intr_handle;
+	(void)cb;
+	(void)cb_arg;
+}
+
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/net/mlx5/linux/mlx5_ethdev_os.c +0 -71

77 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_os.c +29 -103

169 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_socket.c +6 -47

71 lines not on this page · raw message

drivers/net/mlx5/mlx5.h +0 -2
index 305edff..7ebb2cc 100644
@@ -1682,8 +1682,6 @@ int mlx5_sysfs_switch_info(unsigned int ifindex,
 			   struct mlx5_switch_info *info);
 void mlx5_translate_port_name(const char *port_name_in,
 			      struct mlx5_switch_info *port_info_out);
-void mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-				   rte_intr_callback_fn cb_fn, void *cb_arg);
 int mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
 			 char *ifname);
 int mlx5_get_module_info(struct rte_eth_dev *dev,
drivers/net/mlx5/mlx5_txpp.c +7 -21
index fe74317..f853a67 100644
@@ -741,11 +741,8 @@
 static void
 mlx5_txpp_stop_service(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!rte_intr_fd_get(sh->txpp.intr_handle))
-		return;
-	mlx5_intr_callback_unregister(sh->txpp.intr_handle,
-				      mlx5_txpp_interrupt_handler, sh);
-	rte_intr_instance_free(sh->txpp.intr_handle);
+	mlx5_os_interrupt_handler_destroy(sh->txpp.intr_handle,
+					  mlx5_txpp_interrupt_handler, sh);
 }
 
 /* Attach interrupt handler and fires first request to Rearm Queue. */
@@ -769,23 +766,12 @@
 		rte_errno = errno;
 		return -rte_errno;
 	}
-	sh->txpp.intr_handle =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->txpp.intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
 	fd = mlx5_os_get_devx_channel_fd(sh->txpp.echan);
-	if (rte_intr_fd_set(sh->txpp.intr_handle, fd))
-		return -rte_errno;
-
-	if (rte_intr_type_set(sh->txpp.intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	if (rte_intr_callback_register(sh->txpp.intr_handle,
-				       mlx5_txpp_interrupt_handler, sh)) {
-		rte_intr_fd_set(sh->txpp.intr_handle, 0);
-		DRV_LOG(ERR, "Failed to register CQE interrupt %d.", rte_errno);
+	sh->txpp.intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, false,
+		 fd, mlx5_txpp_interrupt_handler, sh);
+	if (!sh->txpp.intr_handle) {
+		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		return -rte_errno;
 	}
 	/* Subscribe CQ event to the event channel controlled by the driver. */
drivers/net/mlx5/windows/mlx5_ethdev_os.c +0 -22
index f975265..88d8213 100644
@@ -140,28 +140,6 @@
 	return 0;
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	RTE_SET_USED(handle);
-	RTE_SET_USED(cb_fn);
-	RTE_SET_USED(cb_arg);
-}
-
 /**
  * DPDK callback to get flow control status.
  *
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +7 -41

64 lines not on this page · raw message

Signature · 1 line
1.8.3.1
author
#105 lore raw

PATCH v9 3/6 net/mlx5: add LWM event handling support

In reply to Spike Du

When LWM meets RQ WQE, the kernel driver raises an event to SW. Use devx event_channel to catch this and to notify the user. Allocate this channel per shared device.
The channel has a cookie that informs the specific event port and queue.

---
 drivers/net/mlx5/mlx5.c      | 66 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5.h      |  7 +++++
 drivers/net/mlx5/mlx5_devx.c | 47 +++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.c   | 33 ++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h   |  7 +++++
 5 files changed, 160 insertions(+)
drivers/net/mlx5/mlx5.c +66 -0
index f098871..e04a666 100644
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <rte_malloc.h>
 #include <ethdev_driver.h>
@@ -22,6 +23,7 @@
 #include <rte_eal_paging.h>
 #include <rte_alarm.h>
 #include <rte_cycles.h>
+#include <rte_interrupts.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -1525,6 +1527,69 @@ struct mlx5_dev_ctx_shared *
 }
 
 /**
+ * Create LWM event_channel and interrupt handle for shared device
+ * context. All rxqs sharing the device context share the event_channel.
+ * A callback is registered in interrupt thread to receive the LWM event.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5_priv instance.
+ *
+ * @return
+ *   0 on success, negative with rte_errno set.
+ */
+int
+mlx5_lwm_setup(struct mlx5_priv *priv)
+{
+	int fd_lwm;
+
+	pthread_mutex_init(&priv->sh->lwm_config_lock, NULL);
+	priv->sh->devx_channel_lwm = mlx5_os_devx_create_event_channel
+			(priv->sh->cdev->ctx,
+			 MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
+	if (!priv->sh->devx_channel_lwm)
+		goto err;
+	fd_lwm = mlx5_os_get_devx_channel_fd(priv->sh->devx_channel_lwm);
+	priv->sh->intr_handle_lwm = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 fd_lwm, mlx5_dev_interrupt_handler_lwm, priv);
+	if (!priv->sh->intr_handle_lwm)
+		goto err;
+	return 0;
+err:
+	if (priv->sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(priv->sh->devx_channel_lwm);
+		priv->sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&priv->sh->lwm_config_lock);
+	return -rte_errno;
+}
+
+/**
+ * Destroy LWM event_channel and interrupt handle for shared device
+ * context before free this context. The interrupt handler is also
+ * unregistered.
+ *
+ * @param[in] sh
+ *   Pointer to shared device context.
+ */
+void
+mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh)
+{
+	if (sh->intr_handle_lwm) {
+		mlx5_os_interrupt_handler_destroy(sh->intr_handle_lwm,
+			mlx5_dev_interrupt_handler_lwm, (void *)-1);
+		sh->intr_handle_lwm = NULL;
+	}
+	if (sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(sh->devx_channel_lwm);
+		sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&sh->lwm_config_lock);
+}
+
+/**
  * Free shared IB device context. Decrement counter and if zero free
  * all allocated resources and close handles.
  *
@@ -1601,6 +1666,7 @@ struct mlx5_dev_ctx_shared *
 		claim_zero(mlx5_devx_cmd_destroy(sh->td));
 	MLX5_ASSERT(sh->geneve_tlv_option_resource == NULL);
 	pthread_mutex_destroy(&sh->txpp.mutex);
+	mlx5_lwm_unset(sh);
 	mlx5_free(sh);
 	return;
 exit:
drivers/net/mlx5/mlx5.h +7 -0
index 7ebb2cc..a76f2fe 100644
@@ -1268,6 +1268,9 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */
 	unsigned int flow_max_priority;
 	enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM];
+	void *devx_channel_lwm;
+	struct rte_intr_handle *intr_handle_lwm;
+	pthread_mutex_t lwm_config_lock;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
@@ -1405,6 +1408,7 @@ enum mlx5_txq_modify_type {
 };
 
 struct mlx5_rxq_priv;
+struct mlx5_priv;
 
 /* HW objects operations structure. */
 struct mlx5_obj_ops {
@@ -1413,6 +1417,7 @@ struct mlx5_obj_ops {
 	int (*rxq_event_get)(struct mlx5_rxq_obj *rxq_obj);
 	int (*rxq_obj_modify)(struct mlx5_rxq_priv *rxq, uint8_t type);
 	void (*rxq_obj_release)(struct mlx5_rxq_priv *rxq);
+	int (*rxq_event_get_lwm)(struct mlx5_priv *priv, int *rxq_idx, int *port_id);
 	int (*ind_table_new)(struct rte_eth_dev *dev, const unsigned int log_n,
 			     struct mlx5_ind_table_obj *ind_tbl);
 	int (*ind_table_modify)(struct rte_eth_dev *dev,
@@ -1603,6 +1608,8 @@ int mlx5_udp_tunnel_port_add(struct rte_eth_dev *dev,
 bool mlx5_is_hpf(struct rte_eth_dev *dev);
 bool mlx5_is_sf_repr(struct rte_eth_dev *dev);
 void mlx5_age_event_prepare(struct mlx5_dev_ctx_shared *sh);
+int mlx5_lwm_setup(struct mlx5_priv *priv);
+void mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh);
 
 /* Macro to iterate over all valid ports for mlx5 driver. */
 #define MLX5_ETH_FOREACH_DEV(port_id, dev) \
drivers/net/mlx5/mlx5_devx.c +47 -0

59 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.c +33 -0
index e5eea0a..197d708 100644
@@ -1187,3 +1187,36 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 {
 	return -ENOTSUP;
 }
+
+/**
+ * Rte interrupt handler for LWM event.
+ * It first checks if the event arrives, if so process the callback for
+ * RTE_ETH_EVENT_RX_LWM.
+ *
+ * @param args
+ *   Generic pointer to mlx5_priv.
+ */
+void
+mlx5_dev_interrupt_handler_lwm(void *args)
+{
+	struct mlx5_priv *priv = args;
+	struct mlx5_rxq_priv *rxq;
+	struct rte_eth_dev *dev;
+	int ret, rxq_idx = 0, port_id = 0;
+
+	ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
+	if (unlikely(ret < 0)) {
+		DRV_LOG(WARNING, "Cannot get LWM event context.");
+		return;
+	}
+	DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
+		port_id, rxq_idx);
+	dev = &rte_eth_devices[port_id];
+	rxq = mlx5_rxq_get(dev, rxq_idx);
+	if (rxq) {
+		pthread_mutex_lock(&priv->sh->lwm_config_lock);
+		rxq->lwm_event_pending = 1;
+		pthread_mutex_unlock(&priv->sh->lwm_config_lock);
+	}
+	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
+}
drivers/net/mlx5/mlx5_rx.h +7 -0
index 25a5f2c..068dff5 100644
@@ -176,6 +176,7 @@ struct mlx5_rxq_priv {
 	struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
+	uint32_t lwm_event_pending:1;
 };
 
 /* External RX queue descriptor. */
@@ -295,6 +296,7 @@ void mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+void mlx5_dev_interrupt_handler_lwm(void *args);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
@@ -675,4 +677,9 @@ uint16_t mlx5_rx_burst_mprq_vec(void *dpdk_rxq, struct rte_mbuf **pkts,
 	return !!__atomic_load_n(&rxq->refcnt, __ATOMIC_RELAXED);
 }
 
+#define LWM_COOKIE_RXQID_OFFSET 0
+#define LWM_COOKIE_RXQID_MASK 0xffff
+#define LWM_COOKIE_PORTID_OFFSET 16
+#define LWM_COOKIE_PORTID_MASK 0xffff
+
 #endif /* RTE_PMD_MLX5_RX_H_ */
Signature · 1 line
1.8.3.1
author
#106 lore raw

PATCH v9 4/6 net/mlx5: support Rx queue based available descriptor threshold

In reply to Spike Du

Add mlx5 specific available descriptor threshold configuration and query handler.
In mlx5 PMD, available descriptor threshold is also called LWM(limit watermark).
While the Rx queue fullness reaches the LWM limit, the driver catches an HW event and invokes the user callback.
The query handler finds the next RX queue with pending LWM event if any, starting from the given RX queue index.

---
 doc/guides/nics/mlx5.rst               |  12 +++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/mlx5_prm.h         |   1 +
 drivers/net/mlx5/mlx5.c                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 151 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h             |   5 ++
 6 files changed, 172 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
index d83c56d..cceaddf 100644
@@ -93,6 +93,7 @@ Features
 - Connection tracking.
 - Sub-Function representors.
 - Sub-Function.
+- Rx queue available descriptor threshold configuration.
 
 
 Limitations
@@ -520,6 +521,9 @@ Limitations
 
 - The NIC egress flow rules on representor port are not supported.
 
+- Available descriptor threshold:
+
+  - Doesn't support shared Rx queue and Hairpin Rx queue.
 
 Statistics
 ----------
@@ -1680,3 +1684,11 @@ The procedure below is an example of using a ConnectX-5 adapter card (pf0) with
 #. For each VF PCIe, using the following command to bind the driver::
 
    $ echo "0000:82:00.2" >> /sys/bus/pci/drivers/mlx5_core/bind
+
+Available descriptor threshold introduction
+-------------------------------------------
+
+Available descriptor threshold is a per Rx queue attribute, it should be configured as
+a percentage of the Rx queue size.
+When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
+
doc/guides/rel_notes/release_22_07.rst +1 -0
index 6fc044e..7fb98cd 100644
@@ -151,6 +151,7 @@ New Features
   * Added support for promiscuous mode on Windows.
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
+  * Added Rx queue available descriptor threshold support.
 
 * **Updated VMware vmxnet3 networking driver.**
 
drivers/common/mlx5/mlx5_prm.h +1 -0
index 654e5f4..7c4030a 100644
@@ -3294,6 +3294,7 @@ struct mlx5_aso_wqe {
 
 enum {
 	MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+	MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED = 0x14,
 };
 
 enum {
drivers/net/mlx5/mlx5.c +2 -0
index e04a666..998846a 100644
@@ -2071,6 +2071,8 @@ struct mlx5_dev_ctx_shared *
 	.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
 	.vlan_filter_set = mlx5_vlan_filter_set,
 	.rx_queue_setup = mlx5_rx_queue_setup,
+	.rx_queue_avail_thresh_set = mlx5_rx_queue_lwm_set,
+	.rx_queue_avail_thresh_query = mlx5_rx_queue_lwm_query,
 	.rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,
 	.tx_queue_setup = mlx5_tx_queue_setup,
 	.tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
drivers/net/mlx5/mlx5_rx.c +151 -0

184 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.h +5 -0
index 068dff5..e078aaf 100644
@@ -177,6 +177,7 @@ struct mlx5_rxq_priv {
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
 	uint32_t lwm_event_pending:1;
+	uint32_t lwm_devx_subscribed:1;
 };
 
 /* External RX queue descriptor. */
@@ -297,6 +298,10 @@ int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 void mlx5_dev_interrupt_handler_lwm(void *args);
+int mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			  uint8_t lwm);
+int mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev, uint16_t *rx_queue_id,
+			    uint8_t *lwm);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
Signature · 1 line
1.8.3.1
author
#107 lore raw

PATCH v9 5/6 net/mlx5: add private API to config host port shaper

In reply to Spike Du

Host port shaper can be configured with QSHR(QoS Shaper Host Register). Add check in build files to enable this function or not.

The host shaper configuration affects all the ethdev ports belonging to the same host port.

Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives available descriptor threshold event.

---
 doc/guides/nics/mlx5.rst               |  35 +++++++++++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/linux/meson.build  |  13 +++++
 drivers/common/mlx5/mlx5_prm.h         |  25 ++++++++
 drivers/net/mlx5/mlx5.h                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 104 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/rte_pmd_mlx5.h        |  30 ++++++++++
 drivers/net/mlx5/version.map           |   2 +
 8 files changed, 212 insertions(+)
doc/guides/nics/mlx5.rst +35 -0
index cceaddf..5f7b060 100644
@@ -94,6 +94,7 @@ Features
 - Sub-Function representors.
 - Sub-Function.
 - Rx queue available descriptor threshold configuration.
+- Host shaper support.
 
 
 Limitations
@@ -525,6 +526,12 @@ Limitations
 
   - Doesn't support shared Rx queue and Hairpin Rx queue.
 
+- Host shaper:
+
+  - Support BlueField series NIC from BlueField 2.
+  - When configure host shaper with MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED flag set,
+    only rate 0 and 100Mbps are supported.
+
 Statistics
 ----------
 
@@ -1692,3 +1699,31 @@ Available descriptor threshold is a per Rx queue attribute, it should be configu
 a percentage of the Rx queue size.
 When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
 
+Host shaper introduction
+------------------------
+
+Host shaper register is per host port register which sets a shaper
+on the host port.
+All VF/hostPF representors belonging to one host port share one host shaper.
+For example, if representor 0 and representor 1 belong to same host port,
+and a host shaper rate of 1Gbps is configured, the shaper throttles both
+representors' traffic from host.
+Host shaper has two modes for setting the shaper, immediate and deferred to
+available descriptor threshold event trigger. In immediate mode, the rate limit is configured
+immediately to host shaper. When deferring to available descriptor threshold trigger, the shaper
+is not set until an available descriptor threshold event is received by any Rx queue in a VF
+representor belonging to the host port. The only rate supported for deferred
+mode is 100Mbps (there is no limit on the supported rates for immediate mode).
+In deferred mode, the shaper is set on the host port by the firmware upon
+receiving the available descriptor threshold event, which allows throttling host traffic on
+available descriptor threshold events at minimum latency, preventing excess drops in the
+Rx queue.
+
+Host shaper dependency for mstflint package
+-------------------------------------------
+
+In order to configure host shaper register, ``librte_net_mlx5`` depends on ``libmtcr_ul``
+which can be installed from OFED mstflint package.
+Meson detects ``libmtcr_ul`` existence at configure stage.
+If the library is detected, the application must link with ``-lmtcr_ul``,
+as done by the pkg-config file libdpdk.pc.
doc/guides/rel_notes/release_22_07.rst +1 -0
index 7fb98cd..199a775 100644
@@ -152,6 +152,7 @@ New Features
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
   * Added Rx queue available descriptor threshold support.
+  * Added host shaper support.
 
 * **Updated VMware vmxnet3 networking driver.**
 
drivers/common/mlx5/linux/meson.build +13 -0
index 5335f5b..51c6e5d 100644
@@ -45,6 +45,13 @@ if static_ibverbs
     ext_deps += declare_dependency(link_args:ibv_ldflags.split())
 endif
 
+libmtcr_ul_found = false
+lib = cc.find_library('mtcr_ul', required:false)
+if lib.found() and run_command('meson', '--version').stdout().version_compare('>= 0.49.2')
+    libmtcr_ul_found = true
+    ext_deps += lib
+endif
+
 sources += files('mlx5_nl.c')
 sources += files('mlx5_common_auxiliary.c')
 sources += files('mlx5_common_os.c')
@@ -207,6 +214,12 @@ has_sym_args = [
         [ 'HAVE_MLX5_IBV_IMPORT_CTX_PD_AND_MR', 'infiniband/verbs.h',
             'ibv_import_device' ],
 ]
+if  libmtcr_ul_found
+    has_sym_args += [
+        [  'HAVE_MLX5_MSTFLINT', 'mstflint/mtcr.h',
+            'mopen'],
+    ]
+endif
 config = configuration_data()
 foreach arg:has_sym_args
     config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
drivers/common/mlx5/mlx5_prm.h +25 -0
index 7c4030a..137a7c5 100644
@@ -3772,6 +3772,7 @@ enum {
 	MLX5_CRYPTO_COMMISSIONING_REGISTER_ID = 0xC003,
 	MLX5_IMPORT_KEK_HANDLE_REGISTER_ID = 0xC004,
 	MLX5_CREDENTIAL_HANDLE_REGISTER_ID = 0xC005,
+	MLX5_QSHR_REGISTER_ID = 0x4030,
 };
 
 struct mlx5_ifc_register_mtutc_bits {
@@ -3786,6 +3787,30 @@ struct mlx5_ifc_register_mtutc_bits {
 	u8 time_adjustment[0x20];
 };
 
+struct mlx5_ifc_ets_global_config_register_bits {
+	u8 reserved_at_0[0x2];
+	u8 rate_limit_update[0x1];
+	u8 reserved_at_3[0x29];
+	u8 max_bw_units[0x4];
+	u8 reserved_at_48[0x8];
+	u8 max_bw_value[0x8];
+};
+
+#define ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED      0x0
+#define ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS 0x3
+#define ETS_GLOBAL_CONFIG_BW_UNIT_GBPS          0x4
+
+struct mlx5_ifc_register_qshr_bits {
+	u8 reserved_at_0[0x4];
+	u8 connected_host[0x1];
+	u8 vqos[0x1];
+	u8 fast_response[0x1];
+	u8 reserved_at_7[0x1];
+	u8 local_port[0x8];
+	u8 reserved_at_16[0x230];
+	struct mlx5_ifc_ets_global_config_register_bits global_config;
+};
+
 #define MLX5_MTUTC_TIMESTAMP_MODE_INTERNAL_TIMER 0
 #define MLX5_MTUTC_TIMESTAMP_MODE_REAL_TIME 1
 
drivers/net/mlx5/mlx5.h +2 -0
index a76f2fe..8af84ae 100644
@@ -1271,6 +1271,8 @@ struct mlx5_dev_ctx_shared {
 	void *devx_channel_lwm;
 	struct rte_intr_handle *intr_handle_lwm;
 	pthread_mutex_t lwm_config_lock;
+	uint32_t host_shaper_rate:8;
+	uint32_t lwm_triggered:1;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
drivers/net/mlx5/mlx5_rx.c +104 -0

119 lines not on this page · raw message

drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
index 6e7907e..fbfdd97 100644
@@ -109,6 +109,36 @@ int rte_pmd_mlx5_external_rx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
 int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id,
 					    uint16_t dpdk_idx);
 
+/**
+ * The rate of the host port shaper will be updated directly at the next
+ * available descriptor threshold event to the rate that comes with this flag set;
+ * set rate 0 to disable this rate update.
+ * Unset this flag to update the rate of the host port shaper directly in
+ * the API call; use rate 0 to disable the current shaper.
+ */
+#define MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED 0
+
+/**
+ * Configure a HW shaper to limit Tx rate for a host port.
+ * The configuration will affect all the ethdev ports belonging to
+ * the same rte_device.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] rate
+ *   Unit is 100Mbps, setting the rate to 0 disables the shaper.
+ * @param[in] flags
+ *   Host shaper flags.
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOENT - no ibdev interface.
+ *   - EBUSY  - the register access unit is busy.
+ *   - EIO    - the register access command meets IO error.
+ */
+__rte_experimental
+int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, uint32_t flags);
+
 #ifdef __cplusplus
 }
 #endif
drivers/net/mlx5/version.map +2 -0
index 79cb79a..c97dfe4 100644
@@ -12,4 +12,6 @@ EXPERIMENTAL {
 	# added in 22.03
 	rte_pmd_mlx5_external_rx_queue_id_map;
 	rte_pmd_mlx5_external_rx_queue_id_unmap;
+	# added in 22.07
+	rte_pmd_mlx5_host_shaper_config;
 };
Signature · 1 line
1.8.3.1
author
#108 lore raw

PATCH v9 6/6 app/testpmd: add Host Shaper command

In reply to Spike Du

Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> rate
<rate_num>

- Example commands:
To enable avail_thresh_triggered on port 1 and disable current host shaper:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 1 rate 0

To disable avail_thresh_triggered and current host shaper on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 0

The rate unit is 100Mbps.
To disable avail_thresh_triggered and configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50

Add sample code to handle rxq available descriptor threshold event, it delays a while so that rxq empties, then disables host shaper and rearms available descriptor threshold event.

---
 app/test-pmd/testpmd.c          |   7 ++
 doc/guides/nics/mlx5.rst        |  46 +++++++++
 drivers/net/mlx5/meson.build    |   4 +
 drivers/net/mlx5/mlx5_testpmd.c | 205 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_testpmd.h |  26 +++++
 5 files changed, 288 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.c
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +7 -0
index 205d98e..e6321bd 100644
@@ -69,6 +69,9 @@
 #ifdef RTE_NET_BOND
 #include <rte_eth_bond.h>
 #endif
+#ifdef RTE_NET_MLX5
+#include "mlx5_testpmd.h"
+#endif
 
 #include "testpmd.h"
 
@@ -3726,6 +3729,10 @@ struct pmd_test_command {
 				break;
 			printf("Received avail_thresh event, port: %u, rxq_id: %u\n",
 			       port_id, rxq_id);
+
+#ifdef RTE_NET_MLX5
+			mlx5_test_avail_thresh_event_handler(port_id, rxq_id);
+#endif
 		}
 		break;
 	}
doc/guides/nics/mlx5.rst +46 -0

49 lines not on this page · raw message

drivers/net/mlx5/meson.build +4 -0
index 99210fd..941642b 100644
@@ -68,4 +68,8 @@ if get_option('buildtype').contains('debug')
 else
     cflags += [ '-UPEDANTIC' ]
 endif
+
+testpmd_sources += files('mlx5_testpmd.c')
+testpmd_drivers_deps += 'net_mlx5'
+
 subdir(exec_env)
drivers/net/mlx5/mlx5_testpmd.c new file +205 -0

205 lines not on this page · raw message

drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
new file mode 100644
index 0000000..7a54658
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 6WIND S.A.
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#ifndef RTE_PMD_MLX5_TEST_H_
+#define RTE_PMD_MLX5_TEST_H_
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+/**
+ * RTE_ETH_EVENT_RX_AVAIL_THRESH handler sample code.
+ * It's called in testpmd, the work flow here is delay a while until
+ * RX queueu is empty, then disable host shaper.
+ *
+ * @param[in] port_id
+ *   Port identifier.
+ * @param[in] rxq_id
+ *   Rx queue identifier.
+ */
+void
+mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id);
+
+#endif
Signature · 1 line
1.8.3.1
author
#109 lore raw

PATCH v8 2/6 common/mlx5: share interrupt management

In reply to Spike Du

There are many duplicate code of creating and initializing rte_intr_handle. Add a new mlx5_os API to do this, replace all PMD related code with this API.

---
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +++
 drivers/common/mlx5/version.map              |   2 +
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 --------------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 ++++++---------------------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 ++---------
 drivers/net/mlx5/mlx5.h                      |   2 -
 drivers/net/mlx5/mlx5_txpp.c                 |  28 ++----
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 -----
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  48 ++--------
 11 files changed, 217 insertions(+), 307 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +131 -0
index d40cfd5..f10a981 100644
@@ -11,6 +11,7 @@
 #endif
 #include <dirent.h>
 #include <net/if.h>
+#include <fcntl.h>
 
 #include <rte_errno.h>
 #include <rte_string_fns.h>
@@ -964,3 +965,133 @@
 		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
 	memset(pmd_mr, 0, sizeof(*pmd_mr));
 }
+
+/**
+ * Rte_intr_handle create and init helper.
+ *
+ * @param[in] mode
+ *   interrupt instance can be shared between primary and secondary
+ *   processes or not.
+ * @param[in] set_fd_nonblock
+ *   Whether to set fd to O_NONBLOCK.
+ * @param[in] fd
+ *   Fd to set in created intr_handle.
+ * @param[in] cb
+ *   Callback to register for intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ * @return
+ *  - Interrupt handle on success.
+ *  - NULL on failure, with rte_errno set.
+ */
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle;
+	int ret, flags;
+
+	tmp_intr_handle = rte_intr_instance_alloc(mode);
+	if (!tmp_intr_handle) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	if (set_fd_nonblock) {
+		flags = fcntl(fd, F_GETFL);
+		ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+		if (ret) {
+			rte_errno = errno;
+			goto err;
+		}
+	}
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret)
+		goto err;
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret)
+		goto err;
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		rte_errno = -ret;
+		goto err;
+	}
+	return tmp_intr_handle;
+err:
+	if (tmp_intr_handle)
+		rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+/* Safe unregistration for interrupt callback. */
+static void
+mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
+			      rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+	uint64_t twait = 0;
+	uint64_t start = 0;
+
+	do {
+		int ret;
+
+		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
+		if (ret >= 0)
+			return;
+		if (ret != -EAGAIN) {
+			DRV_LOG(INFO, "failed to unregister interrupt"
+				      " handler (error: %d)", ret);
+			MLX5_ASSERT(false);
+			return;
+		}
+		if (twait) {
+			struct timespec onems;
+
+			/* Wait one millisecond and try again. */
+			onems.tv_sec = 0;
+			onems.tv_nsec = NS_PER_S / MS_PER_S;
+			nanosleep(&onems, 0);
+			/* Check whether one second elapsed. */
+			if ((rte_get_timer_cycles() - start) <= twait)
+				continue;
+		} else {
+			/*
+			 * We get the amount of timer ticks for one second.
+			 * If this amount elapsed it means we spent one
+			 * second in waiting. This branch is executed once
+			 * on first iteration.
+			 */
+			twait = rte_get_timer_hz();
+			MLX5_ASSERT(twait);
+		}
+		/*
+		 * Timeout elapsed, show message (once a second) and retry.
+		 * We have no other acceptable option here, if we ignore
+		 * the unregistering return code the handler will not
+		 * be unregistered, fd will be closed and we may get the
+		 * crush. Hanging and messaging in the loop seems not to be
+		 * the worst choice.
+		 */
+		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
+		start = rte_get_timer_cycles();
+	} while (true);
+}
+
+/**
+ * Rte_intr_handle destroy helper.
+ *
+ * @param[in] intr_handle
+ *   Rte_intr_handle to destroy.
+ * @param[in] cb
+ *   Callback which is registered to intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ */
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
drivers/common/mlx5/linux/mlx5_common_os.h +11 -0
index 27f1192..479bb3c 100644
@@ -15,6 +15,7 @@
 #include <rte_log.h>
 #include <rte_kvargs.h>
 #include <rte_devargs.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -299,4 +300,14 @@
 int
 mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len);
 
+__rte_internal
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg);
+
+__rte_internal
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg);
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/common/mlx5/version.map +2 -0
index a23a30a..413dec1 100644
@@ -153,5 +153,7 @@ INTERNAL {
 	mlx5_mr_mempool2mr_bh;
 	mlx5_mr_mempool_populate_cache;
 
+	mlx5_os_interrupt_handler_create; # WINDOWS_NO_EXPORT
+	mlx5_os_interrupt_handler_destroy; # WINDOWS_NO_EXPORT
 	local: *;
 };
drivers/common/mlx5/windows/mlx5_common_os.h +24 -0
index ee7973f..e9e9108 100644
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <rte_errno.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -253,4 +254,27 @@
 __rte_internal
 int mlx5_os_umem_dereg(void *pumem);
 
+static inline struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)mode;
+	(void)set_fd_nonblock;
+	(void)fd;
+	(void)cb;
+	(void)cb_arg;
+	rte_errno = ENOTSUP;
+	return NULL;
+}
+
+static inline void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)intr_handle;
+	(void)cb;
+	(void)cb_arg;
+}
+
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/net/mlx5/linux/mlx5_ethdev_os.c +0 -71

77 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_os.c +29 -103

169 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_socket.c +6 -47

71 lines not on this page · raw message

drivers/net/mlx5/mlx5.h +0 -2
index 305edff..7ebb2cc 100644
@@ -1682,8 +1682,6 @@ int mlx5_sysfs_switch_info(unsigned int ifindex,
 			   struct mlx5_switch_info *info);
 void mlx5_translate_port_name(const char *port_name_in,
 			      struct mlx5_switch_info *port_info_out);
-void mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-				   rte_intr_callback_fn cb_fn, void *cb_arg);
 int mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
 			 char *ifname);
 int mlx5_get_module_info(struct rte_eth_dev *dev,
drivers/net/mlx5/mlx5_txpp.c +7 -21
index fe74317..f853a67 100644
@@ -741,11 +741,8 @@
 static void
 mlx5_txpp_stop_service(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!rte_intr_fd_get(sh->txpp.intr_handle))
-		return;
-	mlx5_intr_callback_unregister(sh->txpp.intr_handle,
-				      mlx5_txpp_interrupt_handler, sh);
-	rte_intr_instance_free(sh->txpp.intr_handle);
+	mlx5_os_interrupt_handler_destroy(sh->txpp.intr_handle,
+					  mlx5_txpp_interrupt_handler, sh);
 }
 
 /* Attach interrupt handler and fires first request to Rearm Queue. */
@@ -769,23 +766,12 @@
 		rte_errno = errno;
 		return -rte_errno;
 	}
-	sh->txpp.intr_handle =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->txpp.intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
 	fd = mlx5_os_get_devx_channel_fd(sh->txpp.echan);
-	if (rte_intr_fd_set(sh->txpp.intr_handle, fd))
-		return -rte_errno;
-
-	if (rte_intr_type_set(sh->txpp.intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	if (rte_intr_callback_register(sh->txpp.intr_handle,
-				       mlx5_txpp_interrupt_handler, sh)) {
-		rte_intr_fd_set(sh->txpp.intr_handle, 0);
-		DRV_LOG(ERR, "Failed to register CQE interrupt %d.", rte_errno);
+	sh->txpp.intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, false,
+		 fd, mlx5_txpp_interrupt_handler, sh);
+	if (!sh->txpp.intr_handle) {
+		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		return -rte_errno;
 	}
 	/* Subscribe CQ event to the event channel controlled by the driver. */
drivers/net/mlx5/windows/mlx5_ethdev_os.c +0 -22
index f975265..88d8213 100644
@@ -140,28 +140,6 @@
 	return 0;
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	RTE_SET_USED(handle);
-	RTE_SET_USED(cb_fn);
-	RTE_SET_USED(cb_arg);
-}
-
 /**
  * DPDK callback to get flow control status.
  *
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +7 -41

64 lines not on this page · raw message

Signature · 1 line
1.8.3.1
author
#110 lore raw

PATCH v8 3/6 net/mlx5: add LWM event handling support

In reply to Spike Du

When LWM meets RQ WQE, the kernel driver raises an event to SW. Use devx event_channel to catch this and to notify the user. Allocate this channel per shared device.
The channel has a cookie that informs the specific event port and queue.

---
 drivers/net/mlx5/mlx5.c      | 66 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5.h      |  7 +++++
 drivers/net/mlx5/mlx5_devx.c | 47 +++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.c   | 33 ++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h   |  7 +++++
 5 files changed, 160 insertions(+)
drivers/net/mlx5/mlx5.c +66 -0
index f098871..e04a666 100644
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <rte_malloc.h>
 #include <ethdev_driver.h>
@@ -22,6 +23,7 @@
 #include <rte_eal_paging.h>
 #include <rte_alarm.h>
 #include <rte_cycles.h>
+#include <rte_interrupts.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -1525,6 +1527,69 @@ struct mlx5_dev_ctx_shared *
 }
 
 /**
+ * Create LWM event_channel and interrupt handle for shared device
+ * context. All rxqs sharing the device context share the event_channel.
+ * A callback is registered in interrupt thread to receive the LWM event.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5_priv instance.
+ *
+ * @return
+ *   0 on success, negative with rte_errno set.
+ */
+int
+mlx5_lwm_setup(struct mlx5_priv *priv)
+{
+	int fd_lwm;
+
+	pthread_mutex_init(&priv->sh->lwm_config_lock, NULL);
+	priv->sh->devx_channel_lwm = mlx5_os_devx_create_event_channel
+			(priv->sh->cdev->ctx,
+			 MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
+	if (!priv->sh->devx_channel_lwm)
+		goto err;
+	fd_lwm = mlx5_os_get_devx_channel_fd(priv->sh->devx_channel_lwm);
+	priv->sh->intr_handle_lwm = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 fd_lwm, mlx5_dev_interrupt_handler_lwm, priv);
+	if (!priv->sh->intr_handle_lwm)
+		goto err;
+	return 0;
+err:
+	if (priv->sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(priv->sh->devx_channel_lwm);
+		priv->sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&priv->sh->lwm_config_lock);
+	return -rte_errno;
+}
+
+/**
+ * Destroy LWM event_channel and interrupt handle for shared device
+ * context before free this context. The interrupt handler is also
+ * unregistered.
+ *
+ * @param[in] sh
+ *   Pointer to shared device context.
+ */
+void
+mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh)
+{
+	if (sh->intr_handle_lwm) {
+		mlx5_os_interrupt_handler_destroy(sh->intr_handle_lwm,
+			mlx5_dev_interrupt_handler_lwm, (void *)-1);
+		sh->intr_handle_lwm = NULL;
+	}
+	if (sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(sh->devx_channel_lwm);
+		sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&sh->lwm_config_lock);
+}
+
+/**
  * Free shared IB device context. Decrement counter and if zero free
  * all allocated resources and close handles.
  *
@@ -1601,6 +1666,7 @@ struct mlx5_dev_ctx_shared *
 		claim_zero(mlx5_devx_cmd_destroy(sh->td));
 	MLX5_ASSERT(sh->geneve_tlv_option_resource == NULL);
 	pthread_mutex_destroy(&sh->txpp.mutex);
+	mlx5_lwm_unset(sh);
 	mlx5_free(sh);
 	return;
 exit:
drivers/net/mlx5/mlx5.h +7 -0
index 7ebb2cc..a76f2fe 100644
@@ -1268,6 +1268,9 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */
 	unsigned int flow_max_priority;
 	enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM];
+	void *devx_channel_lwm;
+	struct rte_intr_handle *intr_handle_lwm;
+	pthread_mutex_t lwm_config_lock;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
@@ -1405,6 +1408,7 @@ enum mlx5_txq_modify_type {
 };
 
 struct mlx5_rxq_priv;
+struct mlx5_priv;
 
 /* HW objects operations structure. */
 struct mlx5_obj_ops {
@@ -1413,6 +1417,7 @@ struct mlx5_obj_ops {
 	int (*rxq_event_get)(struct mlx5_rxq_obj *rxq_obj);
 	int (*rxq_obj_modify)(struct mlx5_rxq_priv *rxq, uint8_t type);
 	void (*rxq_obj_release)(struct mlx5_rxq_priv *rxq);
+	int (*rxq_event_get_lwm)(struct mlx5_priv *priv, int *rxq_idx, int *port_id);
 	int (*ind_table_new)(struct rte_eth_dev *dev, const unsigned int log_n,
 			     struct mlx5_ind_table_obj *ind_tbl);
 	int (*ind_table_modify)(struct rte_eth_dev *dev,
@@ -1603,6 +1608,8 @@ int mlx5_udp_tunnel_port_add(struct rte_eth_dev *dev,
 bool mlx5_is_hpf(struct rte_eth_dev *dev);
 bool mlx5_is_sf_repr(struct rte_eth_dev *dev);
 void mlx5_age_event_prepare(struct mlx5_dev_ctx_shared *sh);
+int mlx5_lwm_setup(struct mlx5_priv *priv);
+void mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh);
 
 /* Macro to iterate over all valid ports for mlx5 driver. */
 #define MLX5_ETH_FOREACH_DEV(port_id, dev) \
drivers/net/mlx5/mlx5_devx.c +47 -0

59 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.c +33 -0
index e5eea0a..197d708 100644
@@ -1187,3 +1187,36 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 {
 	return -ENOTSUP;
 }
+
+/**
+ * Rte interrupt handler for LWM event.
+ * It first checks if the event arrives, if so process the callback for
+ * RTE_ETH_EVENT_RX_LWM.
+ *
+ * @param args
+ *   Generic pointer to mlx5_priv.
+ */
+void
+mlx5_dev_interrupt_handler_lwm(void *args)
+{
+	struct mlx5_priv *priv = args;
+	struct mlx5_rxq_priv *rxq;
+	struct rte_eth_dev *dev;
+	int ret, rxq_idx = 0, port_id = 0;
+
+	ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
+	if (unlikely(ret < 0)) {
+		DRV_LOG(WARNING, "Cannot get LWM event context.");
+		return;
+	}
+	DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
+		port_id, rxq_idx);
+	dev = &rte_eth_devices[port_id];
+	rxq = mlx5_rxq_get(dev, rxq_idx);
+	if (rxq) {
+		pthread_mutex_lock(&priv->sh->lwm_config_lock);
+		rxq->lwm_event_pending = 1;
+		pthread_mutex_unlock(&priv->sh->lwm_config_lock);
+	}
+	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
+}
drivers/net/mlx5/mlx5_rx.h +7 -0
index 25a5f2c..068dff5 100644
@@ -176,6 +176,7 @@ struct mlx5_rxq_priv {
 	struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
+	uint32_t lwm_event_pending:1;
 };
 
 /* External RX queue descriptor. */
@@ -295,6 +296,7 @@ void mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+void mlx5_dev_interrupt_handler_lwm(void *args);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
@@ -675,4 +677,9 @@ uint16_t mlx5_rx_burst_mprq_vec(void *dpdk_rxq, struct rte_mbuf **pkts,
 	return !!__atomic_load_n(&rxq->refcnt, __ATOMIC_RELAXED);
 }
 
+#define LWM_COOKIE_RXQID_OFFSET 0
+#define LWM_COOKIE_RXQID_MASK 0xffff
+#define LWM_COOKIE_PORTID_OFFSET 16
+#define LWM_COOKIE_PORTID_MASK 0xffff
+
 #endif /* RTE_PMD_MLX5_RX_H_ */
Signature · 1 line
1.8.3.1
author
#111 lore raw

PATCH v8 4/6 net/mlx5: support Rx queue based available descriptor threshold

In reply to Spike Du

Add mlx5 specific available descriptor threshold configuration and query handler.
In mlx5 PMD, available descriptor threshold is also called LWM(limit watermark).
While the Rx queue fullness reaches the LWM limit, the driver catches an HW event and invokes the user callback.
The query handler finds the next RX queue with pending LWM event if any, starting from the given RX queue index.

---
 doc/guides/nics/mlx5.rst               |  12 +++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/mlx5_prm.h         |   1 +
 drivers/net/mlx5/mlx5.c                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 151 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h             |   5 ++
 6 files changed, 172 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
index d83c56d..cceaddf 100644
@@ -93,6 +93,7 @@ Features
 - Connection tracking.
 - Sub-Function representors.
 - Sub-Function.
+- Rx queue available descriptor threshold configuration.
 
 
 Limitations
@@ -520,6 +521,9 @@ Limitations
 
 - The NIC egress flow rules on representor port are not supported.
 
+- Available descriptor threshold:
+
+  - Doesn't support shared Rx queue and Hairpin Rx queue.
 
 Statistics
 ----------
@@ -1680,3 +1684,11 @@ The procedure below is an example of using a ConnectX-5 adapter card (pf0) with
 #. For each VF PCIe, using the following command to bind the driver::
 
    $ echo "0000:82:00.2" >> /sys/bus/pci/drivers/mlx5_core/bind
+
+Available descriptor threshold introduction
+-------------------------------------------
+
+Available descriptor threshold is a per Rx queue attribute, it should be configured as
+a percentage of the Rx queue size.
+When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
+
doc/guides/rel_notes/release_22_07.rst +1 -0
index 0ed4f92..46fd73a 100644
@@ -89,6 +89,7 @@ New Features
   * Added support for promiscuous mode on Windows.
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
+  * Added Rx queue available descriptor threshold support.
 
 * **Updated Marvell cnxk crypto driver.**
 
drivers/common/mlx5/mlx5_prm.h +1 -0
index 630b2c5..3b5e605 100644
@@ -3293,6 +3293,7 @@ struct mlx5_aso_wqe {
 
 enum {
 	MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+	MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED = 0x14,
 };
 
 enum {
drivers/net/mlx5/mlx5.c +2 -0
index e04a666..998846a 100644
@@ -2071,6 +2071,8 @@ struct mlx5_dev_ctx_shared *
 	.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
 	.vlan_filter_set = mlx5_vlan_filter_set,
 	.rx_queue_setup = mlx5_rx_queue_setup,
+	.rx_queue_avail_thresh_set = mlx5_rx_queue_lwm_set,
+	.rx_queue_avail_thresh_query = mlx5_rx_queue_lwm_query,
 	.rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,
 	.tx_queue_setup = mlx5_tx_queue_setup,
 	.tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
drivers/net/mlx5/mlx5_rx.c +151 -0

184 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.h +5 -0
index 068dff5..e078aaf 100644
@@ -177,6 +177,7 @@ struct mlx5_rxq_priv {
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
 	uint32_t lwm_event_pending:1;
+	uint32_t lwm_devx_subscribed:1;
 };
 
 /* External RX queue descriptor. */
@@ -297,6 +298,10 @@ int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 void mlx5_dev_interrupt_handler_lwm(void *args);
+int mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+			  uint8_t lwm);
+int mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev, uint16_t *rx_queue_id,
+			    uint8_t *lwm);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
Signature · 1 line
1.8.3.1
author
#112 lore raw

PATCH v8 5/6 net/mlx5: add private API to config host port shaper

In reply to Spike Du

Host port shaper can be configured with QSHR(QoS Shaper Host Register). Add check in build files to enable this function or not.

The host shaper configuration affects all the ethdev ports belonging to the same host port.

Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives available descriptor threshold event.

---
 doc/guides/nics/mlx5.rst               |  35 +++++++++++
 doc/guides/rel_notes/release_22_07.rst |   1 +
 drivers/common/mlx5/linux/meson.build  |  13 +++++
 drivers/common/mlx5/mlx5_prm.h         |  25 ++++++++
 drivers/net/mlx5/mlx5.h                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 104 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/rte_pmd_mlx5.h        |  30 ++++++++++
 drivers/net/mlx5/version.map           |   2 +
 8 files changed, 212 insertions(+)
doc/guides/nics/mlx5.rst +35 -0
index cceaddf..5f7b060 100644
@@ -94,6 +94,7 @@ Features
 - Sub-Function representors.
 - Sub-Function.
 - Rx queue available descriptor threshold configuration.
+- Host shaper support.
 
 
 Limitations
@@ -525,6 +526,12 @@ Limitations
 
   - Doesn't support shared Rx queue and Hairpin Rx queue.
 
+- Host shaper:
+
+  - Support BlueField series NIC from BlueField 2.
+  - When configure host shaper with MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED flag set,
+    only rate 0 and 100Mbps are supported.
+
 Statistics
 ----------
 
@@ -1692,3 +1699,31 @@ Available descriptor threshold is a per Rx queue attribute, it should be configu
 a percentage of the Rx queue size.
 When Rx queue available descriptors for hardware are below the threshold, an event is sent to PMD.
 
+Host shaper introduction
+------------------------
+
+Host shaper register is per host port register which sets a shaper
+on the host port.
+All VF/hostPF representors belonging to one host port share one host shaper.
+For example, if representor 0 and representor 1 belong to same host port,
+and a host shaper rate of 1Gbps is configured, the shaper throttles both
+representors' traffic from host.
+Host shaper has two modes for setting the shaper, immediate and deferred to
+available descriptor threshold event trigger. In immediate mode, the rate limit is configured
+immediately to host shaper. When deferring to available descriptor threshold trigger, the shaper
+is not set until an available descriptor threshold event is received by any Rx queue in a VF
+representor belonging to the host port. The only rate supported for deferred
+mode is 100Mbps (there is no limit on the supported rates for immediate mode).
+In deferred mode, the shaper is set on the host port by the firmware upon
+receiving the available descriptor threshold event, which allows throttling host traffic on
+available descriptor threshold events at minimum latency, preventing excess drops in the
+Rx queue.
+
+Host shaper dependency for mstflint package
+-------------------------------------------
+
+In order to configure host shaper register, ``librte_net_mlx5`` depends on ``libmtcr_ul``
+which can be installed from OFED mstflint package.
+Meson detects ``libmtcr_ul`` existence at configure stage.
+If the library is detected, the application must link with ``-lmtcr_ul``,
+as done by the pkg-config file libdpdk.pc.
doc/guides/rel_notes/release_22_07.rst +1 -0
index 46fd73a..3349cda 100644
@@ -90,6 +90,7 @@ New Features
   * Added support for MTU on Windows.
   * Added matching and RSS on IPsec ESP.
   * Added Rx queue available descriptor threshold support.
+  * Added host shaper support.
 
 * **Updated Marvell cnxk crypto driver.**
 
drivers/common/mlx5/linux/meson.build +13 -0
index 5335f5b..51c6e5d 100644
@@ -45,6 +45,13 @@ if static_ibverbs
     ext_deps += declare_dependency(link_args:ibv_ldflags.split())
 endif
 
+libmtcr_ul_found = false
+lib = cc.find_library('mtcr_ul', required:false)
+if lib.found() and run_command('meson', '--version').stdout().version_compare('>= 0.49.2')
+    libmtcr_ul_found = true
+    ext_deps += lib
+endif
+
 sources += files('mlx5_nl.c')
 sources += files('mlx5_common_auxiliary.c')
 sources += files('mlx5_common_os.c')
@@ -207,6 +214,12 @@ has_sym_args = [
         [ 'HAVE_MLX5_IBV_IMPORT_CTX_PD_AND_MR', 'infiniband/verbs.h',
             'ibv_import_device' ],
 ]
+if  libmtcr_ul_found
+    has_sym_args += [
+        [  'HAVE_MLX5_MSTFLINT', 'mstflint/mtcr.h',
+            'mopen'],
+    ]
+endif
 config = configuration_data()
 foreach arg:has_sym_args
     config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
drivers/common/mlx5/mlx5_prm.h +25 -0
index 3b5e605..92d05a7 100644
@@ -3771,6 +3771,7 @@ enum {
 	MLX5_CRYPTO_COMMISSIONING_REGISTER_ID = 0xC003,
 	MLX5_IMPORT_KEK_HANDLE_REGISTER_ID = 0xC004,
 	MLX5_CREDENTIAL_HANDLE_REGISTER_ID = 0xC005,
+	MLX5_QSHR_REGISTER_ID = 0x4030,
 };
 
 struct mlx5_ifc_register_mtutc_bits {
@@ -3785,6 +3786,30 @@ struct mlx5_ifc_register_mtutc_bits {
 	u8 time_adjustment[0x20];
 };
 
+struct mlx5_ifc_ets_global_config_register_bits {
+	u8 reserved_at_0[0x2];
+	u8 rate_limit_update[0x1];
+	u8 reserved_at_3[0x29];
+	u8 max_bw_units[0x4];
+	u8 reserved_at_48[0x8];
+	u8 max_bw_value[0x8];
+};
+
+#define ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED      0x0
+#define ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS 0x3
+#define ETS_GLOBAL_CONFIG_BW_UNIT_GBPS          0x4
+
+struct mlx5_ifc_register_qshr_bits {
+	u8 reserved_at_0[0x4];
+	u8 connected_host[0x1];
+	u8 vqos[0x1];
+	u8 fast_response[0x1];
+	u8 reserved_at_7[0x1];
+	u8 local_port[0x8];
+	u8 reserved_at_16[0x230];
+	struct mlx5_ifc_ets_global_config_register_bits global_config;
+};
+
 #define MLX5_MTUTC_TIMESTAMP_MODE_INTERNAL_TIMER 0
 #define MLX5_MTUTC_TIMESTAMP_MODE_REAL_TIME 1
 
drivers/net/mlx5/mlx5.h +2 -0
index a76f2fe..8af84ae 100644
@@ -1271,6 +1271,8 @@ struct mlx5_dev_ctx_shared {
 	void *devx_channel_lwm;
 	struct rte_intr_handle *intr_handle_lwm;
 	pthread_mutex_t lwm_config_lock;
+	uint32_t host_shaper_rate:8;
+	uint32_t lwm_triggered:1;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
drivers/net/mlx5/mlx5_rx.c +104 -0

119 lines not on this page · raw message

drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
index 6e7907e..fbfdd97 100644
@@ -109,6 +109,36 @@ int rte_pmd_mlx5_external_rx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
 int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id,
 					    uint16_t dpdk_idx);
 
+/**
+ * The rate of the host port shaper will be updated directly at the next
+ * available descriptor threshold event to the rate that comes with this flag set;
+ * set rate 0 to disable this rate update.
+ * Unset this flag to update the rate of the host port shaper directly in
+ * the API call; use rate 0 to disable the current shaper.
+ */
+#define MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED 0
+
+/**
+ * Configure a HW shaper to limit Tx rate for a host port.
+ * The configuration will affect all the ethdev ports belonging to
+ * the same rte_device.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] rate
+ *   Unit is 100Mbps, setting the rate to 0 disables the shaper.
+ * @param[in] flags
+ *   Host shaper flags.
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOENT - no ibdev interface.
+ *   - EBUSY  - the register access unit is busy.
+ *   - EIO    - the register access command meets IO error.
+ */
+__rte_experimental
+int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, uint32_t flags);
+
 #ifdef __cplusplus
 }
 #endif
drivers/net/mlx5/version.map +2 -0
index 79cb79a..c97dfe4 100644
@@ -12,4 +12,6 @@ EXPERIMENTAL {
 	# added in 22.03
 	rte_pmd_mlx5_external_rx_queue_id_map;
 	rte_pmd_mlx5_external_rx_queue_id_unmap;
+	# added in 22.07
+	rte_pmd_mlx5_host_shaper_config;
 };
Signature · 1 line
1.8.3.1
author
#113 lore raw

PATCH v8 6/6 app/testpmd: add Host Shaper command

In reply to Spike Du

Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id> host_shaper avail_thresh_triggered <0|1> rate
<rate_num>

- Example commands:
To enable avail_thresh_triggered on port 1 and disable current host shaper:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 1 rate 0

To disable avail_thresh_triggered and current host shaper on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 0

The rate unit is 100Mbps.
To disable avail_thresh_triggered and configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50

Add sample code to handle rxq available descriptor threshold event, it delays a while so that rxq empties, then disables host shaper and rearms available descriptor threshold event.

---
 app/test-pmd/testpmd.c          |   7 ++
 doc/guides/nics/mlx5.rst        |  46 +++++++++
 drivers/net/mlx5/meson.build    |   4 +
 drivers/net/mlx5/mlx5_testpmd.c | 205 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_testpmd.h |  26 +++++
 5 files changed, 288 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.c
 create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +7 -0
index 33d9b85..b491719 100644
@@ -69,6 +69,9 @@
 #ifdef RTE_NET_BOND
 #include <rte_eth_bond.h>
 #endif
+#ifdef RTE_NET_MLX5
+#include "mlx5_testpmd.h"
+#endif
 
 #include "testpmd.h"
 
@@ -3659,6 +3662,10 @@ struct pmd_test_command {
 				break;
 			printf("Received avail_thresh event, port:%d rxq_id:%d\n",
 			       port_id, rxq_id);
+
+#ifdef RTE_NET_MLX5
+			mlx5_test_avail_thresh_event_handler(port_id, rxq_id);
+#endif
 		}
 		break;
 	default:
doc/guides/nics/mlx5.rst +46 -0

49 lines not on this page · raw message

drivers/net/mlx5/meson.build +4 -0
index 99210fd..941642b 100644
@@ -68,4 +68,8 @@ if get_option('buildtype').contains('debug')
 else
     cflags += [ '-UPEDANTIC' ]
 endif
+
+testpmd_sources += files('mlx5_testpmd.c')
+testpmd_drivers_deps += 'net_mlx5'
+
 subdir(exec_env)
drivers/net/mlx5/mlx5_testpmd.c new file +205 -0

205 lines not on this page · raw message

drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
new file mode 100644
index 0000000..7a54658
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2021 6WIND S.A.
+ * Copyright 2021 Mellanox Technologies, Ltd
+ */
+
+#ifndef RTE_PMD_MLX5_TEST_H_
+#define RTE_PMD_MLX5_TEST_H_
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+/**
+ * RTE_ETH_EVENT_RX_AVAIL_THRESH handler sample code.
+ * It's called in testpmd, the work flow here is delay a while until
+ * RX queueu is empty, then disable host shaper.
+ *
+ * @param[in] port_id
+ *   Port identifier.
+ * @param[in] rxq_id
+ *   Rx queue identifier.
+ */
+void
+mlx5_test_avail_thresh_event_handler(uint16_t port_id, uint16_t rxq_id);
+
+#endif
Signature · 1 line
1.8.3.1
#114 lore raw

Re: [PATCH v5 0/7] introduce per-queue available descriptor threshold and host shaper

In reply to Spike Du

@Matan, @Viacheslav, could you review mlx5 patches of the series, please.

Quoted 22 lines · Spike Du

available descriptor threshold(ADT for short) is per RX queue attribute, when RX queue available descriptors for HW is below ADT, HW sends an event to application. Host shaper can configure shaper rate and avail_thresh-triggered for a host port.
The shaper limits the rate of traffic from host port to embedded ARM rx port on Nvidia BlueField 2 NIC.
If avail_thresh-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives available descriptor threshold event.

These two features can combine to control traffic from host port to wire port for BlueField 2 NIC.
The traffic flows from host to embedded ARM, then to the physical port.
The work flow is on the ARM system, configure available descriptor threshold to RX queue and enable avail_thresh-triggered flag in host shaper, after receiving available descriptor threshold event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to reduce RX queue drops on ARM system.

Add new libethdev API to set available descriptor threshold, add rte event RTE_ETH_EVENT_RX_AVAIL_THRESH to handle available descriptor threshold event. For host shaper, because it doesn't align to existing DPDK framework and is specific to Nvidia NIC, use PMD private API.

For integration with testpmd, put the private cmdline function and available descriptor threshold event handler in mlx5 PMD directory by adding a new file mlx5_testpmd.c. Follow David Marchand's driver specific commands framework to add mlx5 specific commands.

Spike Du (7):
net/mlx5: add LWM support for Rxq
common/mlx5: share interrupt management
ethdev: introduce Rx queue based available descriptor threshold net/mlx5: add LWM event handling support
net/mlx5: support Rx queue based available descriptor threshold net/mlx5: add private API to config host port shaper app/testpmd: add Host Shaper command

#115 lore raw

PATCH v6 1/1 ethdev: introduce available Rx descriptors threshold

In reply to Spike Du

From: Spike Du <[email protected]>

A new event RTE_ETH_EVENT_RX_AVAIL_THRESH should be generated by HW when number of available descriptors in Rx queue goes below the threshold.

The threshold is defined as a percentage of an Rx queue size with valid values from 0 to 99 (inclusive). Zero (default) value disables it.

There is no capability reporting for the feature. Application should simply try to set required threshold value and handle result.

Add testpmd commands to control the threshold:
set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>

---
v6:
- try to make descriptor shorter and more useful
- refine terminology to use "available descriptors threshold" everywhere (plural "descriptors")
- fix ethdev API documenation
- define negative return values
- define rules to convert percentage to descriptors number in drivers
- avoid extra checks in testpmd helper to allow ethdev API to do its job
- minor fixes in testpmd variables naming
- fix testpmd help to be human oriented
- update testpmd users guide
- add release notes

 app/test-pmd/cmdline.c                      | 72 +++++++++++++++++++++
 app/test-pmd/config.c                       |  9 +++
 app/test-pmd/testpmd.c                      | 16 +++++
 app/test-pmd/testpmd.h                      |  2 +
 doc/guides/rel_notes/release_22_07.rst      |  6 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  9 +++
 lib/ethdev/ethdev_driver.h                  | 25 +++++++
 lib/ethdev/rte_ethdev.c                     | 44 +++++++++++++
 lib/ethdev/rte_ethdev.h                     | 71 ++++++++++++++++++++
 lib/ethdev/version.map                      |  2 +
 10 files changed, 256 insertions(+)
app/test-pmd/cmdline.c +72 -0
index fdd0cada3b..3acdd33cd9 100644
@@ -750,6 +750,9 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"set port (port_id) fec_mode auto|off|rs|baser\n"
 			"    set fec mode for a specific port\n\n"
 
+			"set port (port_id) rxq (queue_id) avail_thresh (0..99)>\n "
+			"    set available descriptors threshold for Rx queue\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -17331,6 +17334,74 @@ static cmdline_parse_inst_t cmd_set_fec_mode = {
 	},
 };
 
+/* *** set available descriptors threshold for an RxQ of a port *** */
+struct cmd_set_rxq_avail_thresh_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	uint16_t port_num;
+	cmdline_fixed_string_t rxq;
+	uint16_t rxq_num;
+	cmdline_fixed_string_t avail_thresh;
+	uint8_t avail_thresh_num;
+};
+
+static void cmd_set_rxq_avail_thresh_parsed(void *parsed_result,
+		__rte_unused struct cmdline *cl,
+		__rte_unused void *data)
+{
+	struct cmd_set_rxq_avail_thresh_result *res = parsed_result;
+	int ret = 0;
+
+	if ((strcmp(res->set, "set") == 0) && (strcmp(res->port, "port") == 0)
+	    && (strcmp(res->rxq, "rxq") == 0)
+	    && (strcmp(res->avail_thresh, "avail_thresh") == 0))
+		ret = set_rxq_avail_thresh(res->port_num, res->rxq_num,
+				  res->avail_thresh_num);
+	if (ret < 0)
+		printf("rxq_avail_thresh_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+static cmdline_parse_token_string_t cmd_set_rxq_avail_thresh_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				set, "set");
+static cmdline_parse_token_string_t cmd_set_rxq_avail_thresh_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				port, "port");
+static cmdline_parse_token_num_t cmd_set_rxq_avail_thresh_portnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				port_num, RTE_UINT16);
+static cmdline_parse_token_string_t cmd_set_rxq_avail_thresh_rxq =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				rxq, "rxq");
+static cmdline_parse_token_num_t cmd_set_rxq_avail_thresh_rxqnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				rxq_num, RTE_UINT16);
+static cmdline_parse_token_string_t cmd_set_rxq_avail_thresh_avail_thresh =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				avail_thresh, "avail_thresh");
+static cmdline_parse_token_num_t cmd_set_rxq_avail_thresh_avail_threshnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_rxq_avail_thresh_result,
+				avail_thresh_num, RTE_UINT8);
+
+static cmdline_parse_inst_t cmd_set_rxq_avail_thresh = {
+	.f = cmd_set_rxq_avail_thresh_parsed,
+	.data = (void *)0,
+	.help_str =
+		"set port <port_id> rxq <queue_id> avail_thresh <0..99>: "
+		"Set available descriptors threshold for Rx queue",
+	.tokens = {
+		(void *)&cmd_set_rxq_avail_thresh_set,
+		(void *)&cmd_set_rxq_avail_thresh_port,
+		(void *)&cmd_set_rxq_avail_thresh_portnum,
+		(void *)&cmd_set_rxq_avail_thresh_rxq,
+		(void *)&cmd_set_rxq_avail_thresh_rxqnum,
+		(void *)&cmd_set_rxq_avail_thresh_avail_thresh,
+		(void *)&cmd_set_rxq_avail_thresh_avail_threshnum,
+		NULL,
+	},
+};
+
 /* show port supported ptypes */
 
 /* Common result structure for show port ptypes */
@@ -18110,6 +18181,7 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_config_tx_dynf_specific,
 	(cmdline_parse_inst_t *)&cmd_show_fec_mode,
 	(cmdline_parse_inst_t *)&cmd_set_fec_mode,
+	(cmdline_parse_inst_t *)&cmd_set_rxq_avail_thresh,
 	(cmdline_parse_inst_t *)&cmd_show_capability,
 	(cmdline_parse_inst_t *)&cmd_set_flex_is_pattern,
 	(cmdline_parse_inst_t *)&cmd_set_flex_spec_pattern,
app/test-pmd/config.c +9 -0
index d6caa1f0b2..e490d7f921 100644
@@ -6392,3 +6392,12 @@ show_mcast_macs(portid_t port_id)
 		printf("  %s\n", buf);
 	}
 }
+
+int
+set_rxq_avail_thresh(portid_t port_id, uint16_t queue_id, uint8_t avail_thresh)
+{
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return -EINVAL;
+
+	return rte_eth_rx_avail_thresh_set(port_id, queue_id, avail_thresh);
+}
app/test-pmd/testpmd.c +16 -0
index 9d6175e9a7..3e39584549 100644
@@ -420,6 +420,7 @@ static const char * const eth_event_desc[] = {
 	[RTE_ETH_EVENT_NEW] = "device probed",
 	[RTE_ETH_EVENT_DESTROY] = "device released",
 	[RTE_ETH_EVENT_FLOW_AGED] = "flow aged",
+	[RTE_ETH_EVENT_RX_AVAIL_THRESH] = "RxQ available descriptors threshold reached",
 	[RTE_ETH_EVENT_MAX] = NULL,
 };
 
@@ -3672,6 +3673,21 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
 		ports[port_id].port_status = RTE_PORT_CLOSED;
 		printf("Port %u is closed\n", port_id);
 		break;
+	case RTE_ETH_EVENT_RX_AVAIL_THRESH: {
+		uint16_t rxq_id;
+		int ret;
+
+		/* avail_thresh query API rewinds rxq_id, no need to check max RxQ num */
+		for (rxq_id = 0; ; rxq_id++) {
+			ret = rte_eth_rx_avail_thresh_query(port_id, &rxq_id,
+							    NULL);
+			if (ret <= 0)
+				break;
+			printf("Received avail_thresh event, port:%u rxq_id:%u\n",
+			       port_id, rxq_id);
+		}
+		break;
+	}
 	default:
 		break;
 	}
app/test-pmd/testpmd.h +2 -0
index dd34b025e6..212d836a19 100644
@@ -1190,6 +1190,8 @@ int update_jumbo_frame_offload(portid_t portid);
 void flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename);
 void flex_item_destroy(portid_t port_id, uint16_t flex_id);
 void port_flex_item_flush(portid_t port_id);
+int set_rxq_avail_thresh(portid_t port_id, uint16_t queue_id,
+			 uint8_t avail_thresh);
 
 extern int flow_parse(const char *src, void *result, unsigned int size,
 		      struct rte_flow_attr **attr,
doc/guides/rel_notes/release_22_07.rst +6 -0
index 5551332bcb..913add127c 100644
@@ -73,6 +73,12 @@ New Features
     * SFF-8472 revision 12.0
     * SFF-8636 revision 2.7
 
+* **Added Rx queue available descriptors threshold and event.**
+
+  Added ethdev API and corresponding driver operations to set Rx queue
+  available descriptors threshold and query for queues with reached
+  threshold when a new event RTE_ETH_EVENT_RX_AVAIL_THRESH is received.
+
 * **Added vhost API to get the number of in-flight packets.**
 
   Added an API which can get the number of in-flight packets in
doc/guides/testpmd_app_ug/testpmd_funcs.rst +9 -0
index bbeba554eb..fb7d2839fe 100644
@@ -2021,6 +2021,15 @@ Set fec mode for a specific port::
 
   testpmd> set port (port_id) fec_mode auto|off|rs|baser
 
+Set Rx queue available descriptors threshold
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Set available descriptors threshold for a specific Rx queue of port::
+
+  testpmd> set port (port_id) rxq (queue_id) avail_thresh (0..99)
+
+Use 0 value to disable the threshold and corresponding event.
+
 Config Sample actions list
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
lib/ethdev/ethdev_driver.h +25 -0
index 69d9dc21d8..5101868ea7 100644
@@ -1073,6 +1073,26 @@ typedef int (*eth_ip_reassembly_conf_set_t)(struct rte_eth_dev *dev,
  */
 typedef int (*eth_dev_priv_dump_t)(struct rte_eth_dev *dev, FILE *file);
 
+/**
+ * @internal Set Rx queue available descriptors threshold.
+ * @see rte_eth_rx_avail_thresh_set()
+ *
+ * Driver should round down number of descriptors on conversion from
+ * percentage.
+ */
+typedef int (*eth_rx_queue_avail_thresh_set_t)(struct rte_eth_dev *dev,
+				      uint16_t rx_queue_id,
+				      uint8_t avail_thresh);
+
+/**
+ * @internal Query Rx queue available descriptors threshold event.
+ * @see rte_eth_rx_avail_thresh_query()
+ */
+
+typedef int (*eth_rx_queue_avail_thresh_query_t)(struct rte_eth_dev *dev,
+					uint16_t *rx_queue_id,
+					uint8_t *avail_thresh);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -1283,6 +1303,11 @@ struct eth_dev_ops {
 
 	/** Dump private info from device */
 	eth_dev_priv_dump_t eth_dev_priv_dump;
+
+	/** Set Rx queue available descriptors threshold */
+	eth_rx_queue_avail_thresh_set_t rx_queue_avail_thresh_set;
+	/** Query Rx queue available descriptors threshold event */
+	eth_rx_queue_avail_thresh_query_t rx_queue_avail_thresh_query;
 };
 
 /**
lib/ethdev/rte_ethdev.c +44 -0

50 lines not on this page · raw message

lib/ethdev/rte_ethdev.h +71 -0

89 lines not on this page · raw message

lib/ethdev/version.map +2 -0
index 8a7ef35233..adfc9fe624 100644
@@ -279,6 +279,8 @@ EXPERIMENTAL {
 	rte_flow_async_action_handle_update;
 
 	# added in 22.07
+	rte_eth_rx_avail_thresh_set;
+	rte_eth_rx_avail_thresh_query;
 	rte_mtr_color_in_protocol_get;
 	rte_mtr_color_in_protocol_priority_get;
 	rte_mtr_color_in_protocol_set;
Signature · 1 line
2.30.2
Acked-by on v6 1/1
#116 lore raw

Re: [PATCH v6] ethdev: introduce available Rx descriptors threshold

08/06/2022 18:35, Andrew Rybchenko:

Quoted 17 lines

From: Spike Du <[email protected]>

A new event RTE_ETH_EVENT_RX_AVAIL_THRESH should be generated by HW when number of available descriptors in Rx queue goes below the threshold.

The threshold is defined as a percentage of an Rx queue size with valid values from 0 to 99 (inclusive). Zero (default) value disables it.

There is no capability reporting for the feature. Application should simply try to set required threshold value and handle result.

Add testpmd commands to control the threshold:
set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>

Quoted 15 lines

---
v6:
- try to make descriptor shorter and more useful
- refine terminology to use "available descriptors threshold" everywhere (plural "descriptors")
- fix ethdev API documenation
- define negative return values
- define rules to convert percentage to descriptors number in drivers
- avoid extra checks in testpmd helper to allow ethdev API to do its job
- minor fixes in testpmd variables naming
- fix testpmd help to be human oriented
- update testpmd users guide
- add release notes

What a (more than) review work, thanks a lot for this v6!

With a few minor arrangements,
applied, thanks.

#117 lore raw

Re: [PATCH v6] ethdev: introduce available Rx descriptors threshold

08/06/2022 19:22, Thomas Monjalon:

Quoted 34 lines

08/06/2022 18:35, Andrew Rybchenko:

Quoted 17 lines

From: Spike Du <[email protected]>

A new event RTE_ETH_EVENT_RX_AVAIL_THRESH should be generated by HW when number of available descriptors in Rx queue goes below the threshold.

The threshold is defined as a percentage of an Rx queue size with valid values from 0 to 99 (inclusive). Zero (default) value disables it.

There is no capability reporting for the feature. Application should simply try to set required threshold value and handle result.

Add testpmd commands to control the threshold:
set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>

Quoted 15 lines

---
v6:
- try to make descriptor shorter and more useful
- refine terminology to use "available descriptors threshold" everywhere (plural "descriptors")
- fix ethdev API documenation
- define negative return values
- define rules to convert percentage to descriptors number in drivers
- avoid extra checks in testpmd helper to allow ethdev API to do its job
- minor fixes in testpmd variables naming
- fix testpmd help to be human oriented
- update testpmd users guide
- add release notes

Quoted 6 lines

What a (more than) review work, thanks a lot for this v6!

With a few minor arrangements,
applied, thanks.

PS: some ABI exceptions have to be added as discussed in the thread:

+; Ignore ethdev event enum update
+; because new event cannot be received if not registered +[suppress_type]
+ type_kind = enum
+ changed_enumerators = RTE_ETH_EVENT_MAX
+
+; Ignore fields inserted in cacheline boundary of rte_eth_rxq_info +; because the struct size is unchanged
+[suppress_type]
+ name = rte_eth_rxq_info
+ has_data_member_inserted_between = {offset_of(rx_buf_size), end}

#118 lore raw

Re: [PATCH v6] ethdev: introduce available Rx descriptors threshold

Hi Thomas,

Could it possible accept the patch ' [dpdk-dev] [PATCH v7 1/4] ethdev: support device reset and recovery events'
which was delayed by ABI exceptions like this patch ?

PS: I noticed RC-1 was released just now and there may be no window left, but I think since this patch can be an
exception, why not that patch ?

Thanks.

Quoted 62 lines · Thomas Monjalon

08/06/2022 19:22, Thomas Monjalon:

Quoted 34 lines

08/06/2022 18:35, Andrew Rybchenko:

Quoted 17 lines

From: Spike Du <[email protected]>

A new event RTE_ETH_EVENT_RX_AVAIL_THRESH should be generated by HW when number of available descriptors in Rx queue goes below the threshold.

The threshold is defined as a percentage of an Rx queue size with valid values from 0 to 99 (inclusive). Zero (default) value disables it.

There is no capability reporting for the feature. Application should simply try to set required threshold value and handle result.

Add testpmd commands to control the threshold:
set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>

Quoted 15 lines

---
v6:
- try to make descriptor shorter and more useful
- refine terminology to use "available descriptors threshold" everywhere (plural "descriptors")
- fix ethdev API documenation
- define negative return values
- define rules to convert percentage to descriptors number in drivers
- avoid extra checks in testpmd helper to allow ethdev API to do its job
- minor fixes in testpmd variables naming
- fix testpmd help to be human oriented
- update testpmd users guide
- add release notes

Quoted 6 lines

What a (more than) review work, thanks a lot for this v6!

With a few minor arrangements,
applied, thanks.

PS: some ABI exceptions have to be added as discussed in the thread:

(quoted diff) +11 -0
+; Ignore ethdev event enum update
+; because new event cannot be received if not registered
+[suppress_type]
+        type_kind = enum
+        changed_enumerators = RTE_ETH_EVENT_MAX
+
+; Ignore fields inserted in cacheline boundary of rte_eth_rxq_info
+; because the struct size is unchanged
+[suppress_type]
+        name = rte_eth_rxq_info
+        has_data_member_inserted_between = {offset_of(rx_buf_size), end}

.

#119 lore raw

Re: [PATCH v6] ethdev: introduce available Rx descriptors threshold

09/06/2022 02:17, fengchengwen:

Quoted 4 lines

Hi Thomas,

Could it possible accept the patch ' [dpdk-dev] [PATCH v7 1/4] ethdev: support device reset and recovery events'
which was delayed by ABI exceptions like this patch ?

I suppose you refer to this explanation:

+; Ignore ethdev event enum update
+; because new event cannot be received if not registered

That's true we discussed in the past that it should have no effect on applications compiled with an old version of DPDK.

Quoted 2 lines

PS: I noticed RC-1 was released just now and there may be no window left, but I think since this patch can be an
exception, why not that patch ?

As far as I remember, the reset and recovery events patch have other comments to address before it can be accepted.

#120 lore raw

Re: [PATCH v6] ethdev: introduce available Rx descriptors threshold

Hi Thomas,

Quoted 7 lines · Thomas Monjalon

09/06/2022 02:17, fengchengwen:

Quoted 4 lines

Hi Thomas,

Could it possible accept the patch ' [dpdk-dev] [PATCH v7 1/4] ethdev: support device reset and recovery events'
which was delayed by ABI exceptions like this patch ?

I suppose you refer to this explanation:

Yes

Quoted 4 lines
(quoted diff) +2 -0
+; Ignore ethdev event enum update
+; because new event cannot be received if not registered
Quoted 8 lines

That's true we discussed in the past that it should have no effect on applications compiled with an old version of DPDK.

Quoted 2 lines

PS: I noticed RC-1 was released just now and there may be no window left, but I think since this patch can be an
exception, why not that patch ?

As far as I remember, the reset and recovery events patch have other comments to address before it can be accepted.

Yes, but the ABI exceptions is the primary cause of blockage.

There's two weeks left to fully discuss I think.

We have product requirements for this feature ("device reset and recovery events"), So:

Hi kalesh-anakkur,

Could you please send a new version about it ? If not, do you mind if I re-develop over it ?

Quoted 5 lines

.

author
#121 lore raw

RFC 2/6 common/mlx5: share interrupt management

In reply to Spike Du

There are many duplicate code of creating and initializing rte_intr_handle. Add a new mlx5_os API to do this, replace all PMD related code with this API.

---
 drivers/common/mlx5/linux/mlx5_common_os.c   | 131 ++++++++++++++++++++++++++
 drivers/common/mlx5/linux/mlx5_common_os.h   |  11 +++
 drivers/common/mlx5/version.map              |   3 +-
 drivers/common/mlx5/windows/mlx5_common_os.h |  24 +++++
 drivers/net/mlx5/linux/mlx5_ethdev_os.c      |  71 --------------
 drivers/net/mlx5/linux/mlx5_os.c             | 132 ++++++---------------------
 drivers/net/mlx5/linux/mlx5_socket.c         |  53 ++---------
 drivers/net/mlx5/mlx5.h                      |   2 -
 drivers/net/mlx5/mlx5_txpp.c                 |  28 ++----
 drivers/net/mlx5/windows/mlx5_ethdev_os.c    |  22 -----
 drivers/vdpa/mlx5/mlx5_vdpa_virtq.c          |  52 ++---------
 11 files changed, 217 insertions(+), 312 deletions(-)
drivers/common/mlx5/linux/mlx5_common_os.c +131 -0
index 030ceb5..6e7c59b 100644
@@ -11,6 +11,7 @@
 #endif
 #include <dirent.h>
 #include <net/if.h>
+#include <fcntl.h>
 
 #include <rte_errno.h>
 #include <rte_string_fns.h>
@@ -952,3 +953,133 @@
 		claim_zero(mlx5_glue->dereg_mr(pmd_mr->obj));
 	memset(pmd_mr, 0, sizeof(*pmd_mr));
 }
+
+/**
+ * Rte_intr_handle create and init helper.
+ *
+ * @param[in] mode
+ *   interrupt instance can be shared between primary and secondary
+ *   processes or not.
+ * @param[in] set_fd_nonblock
+ *   Whether to set fd to O_NONBLOCK.
+ * @param[in] fd
+ *   Fd to set in created intr_handle.
+ * @param[in] cb
+ *   Callback to register for intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ * @return
+ *  - Interrupt handle on success.
+ *  - NULL on failure, with rte_errno set.
+ */
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	struct rte_intr_handle *tmp_intr_handle;
+	int ret, flags;
+
+	tmp_intr_handle = rte_intr_instance_alloc(mode);
+	if (!tmp_intr_handle) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	if (set_fd_nonblock) {
+		flags = fcntl(fd, F_GETFL);
+		ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+		if (ret) {
+			rte_errno = errno;
+			goto err;
+		}
+	}
+	ret = rte_intr_fd_set(tmp_intr_handle, fd);
+	if (ret)
+		goto err;
+	ret = rte_intr_type_set(tmp_intr_handle, RTE_INTR_HANDLE_EXT);
+	if (ret)
+		goto err;
+	ret = rte_intr_callback_register(tmp_intr_handle, cb, cb_arg);
+	if (ret) {
+		rte_errno = -ret;
+		goto err;
+	}
+	return tmp_intr_handle;
+err:
+	if (tmp_intr_handle)
+		rte_intr_instance_free(tmp_intr_handle);
+	return NULL;
+}
+
+/* Safe unregistration for interrupt callback. */
+static void
+mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
+			      rte_intr_callback_fn cb_fn, void *cb_arg)
+{
+	uint64_t twait = 0;
+	uint64_t start = 0;
+
+	do {
+		int ret;
+
+		ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
+		if (ret >= 0)
+			return;
+		if (ret != -EAGAIN) {
+			DRV_LOG(INFO, "failed to unregister interrupt"
+				      " handler (error: %d)", ret);
+			MLX5_ASSERT(false);
+			return;
+		}
+		if (twait) {
+			struct timespec onems;
+
+			/* Wait one millisecond and try again. */
+			onems.tv_sec = 0;
+			onems.tv_nsec = NS_PER_S / MS_PER_S;
+			nanosleep(&onems, 0);
+			/* Check whether one second elapsed. */
+			if ((rte_get_timer_cycles() - start) <= twait)
+				continue;
+		} else {
+			/*
+			 * We get the amount of timer ticks for one second.
+			 * If this amount elapsed it means we spent one
+			 * second in waiting. This branch is executed once
+			 * on first iteration.
+			 */
+			twait = rte_get_timer_hz();
+			MLX5_ASSERT(twait);
+		}
+		/*
+		 * Timeout elapsed, show message (once a second) and retry.
+		 * We have no other acceptable option here, if we ignore
+		 * the unregistering return code the handler will not
+		 * be unregistered, fd will be closed and we may get the
+		 * crush. Hanging and messaging in the loop seems not to be
+		 * the worst choice.
+		 */
+		DRV_LOG(INFO, "Retrying to unregister interrupt handler");
+		start = rte_get_timer_cycles();
+	} while (true);
+}
+
+/**
+ * Rte_intr_handle destroy helper.
+ *
+ * @param[in] intr_handle
+ *   Rte_intr_handle to destroy.
+ * @param[in] cb
+ *   Callback which is registered to intr_handle.
+ * @param[in] cb_arg
+ *   Callback argument for cb.
+ *
+ */
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	if (rte_intr_fd_get(intr_handle) >= 0)
+		mlx5_intr_callback_unregister(intr_handle, cb, cb_arg);
+	rte_intr_instance_free(intr_handle);
+}
drivers/common/mlx5/linux/mlx5_common_os.h +11 -0
index 27f1192..479bb3c 100644
@@ -15,6 +15,7 @@
 #include <rte_log.h>
 #include <rte_kvargs.h>
 #include <rte_devargs.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -299,4 +300,14 @@
 int
 mlx5_get_device_guid(const struct rte_pci_addr *dev, uint8_t *guid, size_t len);
 
+__rte_internal
+struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg);
+
+__rte_internal
+void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg);
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/common/mlx5/version.map +2 -1
index a23a30a..2900544 100644
@@ -152,6 +152,7 @@ INTERNAL {
 	mlx5_mp_req_mempool_reg;
 	mlx5_mr_mempool2mr_bh;
 	mlx5_mr_mempool_populate_cache;
-
+	mlx5_os_interrupt_handler_create; # WINDOWS_NO_EXPORT
+	mlx5_os_interrupt_handler_destroy; # WINDOWS_NO_EXPORT
 	local: *;
 };
drivers/common/mlx5/windows/mlx5_common_os.h +24 -0
index ee7973f..e9e9108 100644
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <rte_errno.h>
+#include <rte_interrupts.h>
 
 #include "mlx5_autoconf.h"
 #include "mlx5_glue.h"
@@ -253,4 +254,27 @@
 __rte_internal
 int mlx5_os_umem_dereg(void *pumem);
 
+static inline struct rte_intr_handle *
+mlx5_os_interrupt_handler_create(int mode, bool set_fd_nonblock, int fd,
+				 rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)mode;
+	(void)set_fd_nonblock;
+	(void)fd;
+	(void)cb;
+	(void)cb_arg;
+	rte_errno = ENOTSUP;
+	return NULL;
+}
+
+static inline void
+mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
+				  rte_intr_callback_fn cb, void *cb_arg)
+{
+	(void)intr_handle;
+	(void)cb;
+	(void)cb_arg;
+}
+
+
 #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
drivers/net/mlx5/linux/mlx5_ethdev_os.c +0 -71

77 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_os.c +29 -103

169 lines not on this page · raw message

drivers/net/mlx5/linux/mlx5_socket.c +6 -47

71 lines not on this page · raw message

drivers/net/mlx5/mlx5.h +0 -2
index f3e6682..4821ff0 100644
@@ -1678,8 +1678,6 @@ int mlx5_sysfs_switch_info(unsigned int ifindex,
 			   struct mlx5_switch_info *info);
 void mlx5_translate_port_name(const char *port_name_in,
 			      struct mlx5_switch_info *port_info_out);
-void mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-				   rte_intr_callback_fn cb_fn, void *cb_arg);
 int mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
 			 char *ifname);
 int mlx5_get_module_info(struct rte_eth_dev *dev,
drivers/net/mlx5/mlx5_txpp.c +7 -21
index fe74317..f853a67 100644
@@ -741,11 +741,8 @@
 static void
 mlx5_txpp_stop_service(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!rte_intr_fd_get(sh->txpp.intr_handle))
-		return;
-	mlx5_intr_callback_unregister(sh->txpp.intr_handle,
-				      mlx5_txpp_interrupt_handler, sh);
-	rte_intr_instance_free(sh->txpp.intr_handle);
+	mlx5_os_interrupt_handler_destroy(sh->txpp.intr_handle,
+					  mlx5_txpp_interrupt_handler, sh);
 }
 
 /* Attach interrupt handler and fires first request to Rearm Queue. */
@@ -769,23 +766,12 @@
 		rte_errno = errno;
 		return -rte_errno;
 	}
-	sh->txpp.intr_handle =
-			rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
-	if (sh->txpp.intr_handle == NULL) {
-		DRV_LOG(ERR, "Fail to allocate intr_handle");
-		return -ENOMEM;
-	}
 	fd = mlx5_os_get_devx_channel_fd(sh->txpp.echan);
-	if (rte_intr_fd_set(sh->txpp.intr_handle, fd))
-		return -rte_errno;
-
-	if (rte_intr_type_set(sh->txpp.intr_handle, RTE_INTR_HANDLE_EXT))
-		return -rte_errno;
-
-	if (rte_intr_callback_register(sh->txpp.intr_handle,
-				       mlx5_txpp_interrupt_handler, sh)) {
-		rte_intr_fd_set(sh->txpp.intr_handle, 0);
-		DRV_LOG(ERR, "Failed to register CQE interrupt %d.", rte_errno);
+	sh->txpp.intr_handle = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, false,
+		 fd, mlx5_txpp_interrupt_handler, sh);
+	if (!sh->txpp.intr_handle) {
+		DRV_LOG(ERR, "Fail to allocate intr_handle");
 		return -rte_errno;
 	}
 	/* Subscribe CQ event to the event channel controlled by the driver. */
drivers/net/mlx5/windows/mlx5_ethdev_os.c +0 -22
index c6315ce..b52faea 100644
@@ -117,28 +117,6 @@
 	return -ENOTSUP;
 }
 
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- *   interrupt handle
- * @param cb_fn
- *   pointer to callback routine
- * @cb_arg
- *   opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
-			      rte_intr_callback_fn cb_fn, void *cb_arg)
-{
-	RTE_SET_USED(handle);
-	RTE_SET_USED(cb_fn);
-	RTE_SET_USED(cb_arg);
-}
-
 /**
  * DPDK callback to get flow control status.
  *
drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +7 -45

68 lines not on this page · raw message

Signature · 1 line
1.8.3.1
author
#122 lore raw

RFC 3/6 net/mlx5: add LWM event handling support

In reply to Spike Du

When LWM meets RQ WQE, the kernel driver raises an event to SW. Use devx event_channel to catch this and to notify the user. Allocate this channel per shared device.
The channel has a cookie that informs the specific event port and queue.

---
 drivers/net/mlx5/mlx5.c      | 61 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5.h      |  7 +++++
 drivers/net/mlx5/mlx5_devx.c | 47 ++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.c   | 29 +++++++++++++++++++++
 drivers/net/mlx5/mlx5_rx.h   |  7 +++++
 5 files changed, 151 insertions(+)
drivers/net/mlx5/mlx5.c +61 -0
index 72b1e35..334223e 100644
@@ -9,6 +9,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include <rte_malloc.h>
 #include <ethdev_driver.h>
@@ -22,6 +23,7 @@
 #include <rte_eal_paging.h>
 #include <rte_alarm.h>
 #include <rte_cycles.h>
+#include <rte_interrupts.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -1521,6 +1523,64 @@ struct mlx5_dev_ctx_shared *
 }
 
 /**
+ * Create LWM event_channel and interrupt handle for shared device
+ * context. All rxqs sharing the device context share the event_channel.
+ * A callback is registered in interrupt thread to receive the LWM event.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5_priv instance.
+ *
+ * @return
+ *   0 on success, negative with rte_errno set.
+ */
+int
+mlx5_lwm_setup(struct mlx5_priv *priv)
+{
+	int fd_lwm;
+
+	pthread_mutex_init(&priv->sh->lwm_config_lock, NULL);
+	priv->sh->devx_channel_lwm = mlx5_os_devx_create_event_channel
+			(priv->sh->cdev->ctx,
+			 MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
+	if (!priv->sh->devx_channel_lwm)
+		goto err;
+	fd_lwm = mlx5_os_get_devx_channel_fd(priv->sh->devx_channel_lwm);
+	priv->sh->intr_handle_lwm = mlx5_os_interrupt_handler_create
+		(RTE_INTR_INSTANCE_F_SHARED, true,
+		 fd_lwm, mlx5_dev_interrupt_handler_lwm, priv);
+	if (!priv->sh->intr_handle_lwm)
+		goto err;
+	return 0;
+err:
+	mlx5_lwm_unset(priv->sh);
+	return -rte_errno;
+}
+
+/**
+ * Destroy LWM event_channel and interrupt handle for shared device
+ * context before free this context. The interrupt handler is also
+ * unregistered.
+ *
+ * @param[in] sh
+ *   Pointer to shared device context.
+ */
+void
+mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh)
+{
+	if (sh->intr_handle_lwm) {
+		mlx5_os_interrupt_handler_destroy(sh->intr_handle_lwm,
+			mlx5_dev_interrupt_handler_lwm, (void *)-1);
+		sh->intr_handle_lwm = NULL;
+	}
+	if (sh->devx_channel_lwm) {
+		mlx5_os_devx_destroy_event_channel
+			(sh->devx_channel_lwm);
+		sh->devx_channel_lwm = NULL;
+	}
+	pthread_mutex_destroy(&sh->lwm_config_lock);
+}
+
+/**
  * Free shared IB device context. Decrement counter and if zero free
  * all allocated resources and close handles.
  *
@@ -1597,6 +1657,7 @@ struct mlx5_dev_ctx_shared *
 		claim_zero(mlx5_devx_cmd_destroy(sh->td));
 	MLX5_ASSERT(sh->geneve_tlv_option_resource == NULL);
 	pthread_mutex_destroy(&sh->txpp.mutex);
+	mlx5_lwm_unset(sh);
 	mlx5_free(sh);
 	return;
 exit:
drivers/net/mlx5/mlx5.h +7 -0
index 4821ff0..515ff33 100644
@@ -1264,6 +1264,9 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */
 	unsigned int flow_max_priority;
 	enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM];
+	void *devx_channel_lwm;
+	struct rte_intr_handle *intr_handle_lwm;
+	pthread_mutex_t lwm_config_lock;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
@@ -1401,6 +1404,7 @@ enum mlx5_txq_modify_type {
 };
 
 struct mlx5_rxq_priv;
+struct mlx5_priv;
 
 /* HW objects operations structure. */
 struct mlx5_obj_ops {
@@ -1409,6 +1413,7 @@ struct mlx5_obj_ops {
 	int (*rxq_event_get)(struct mlx5_rxq_obj *rxq_obj);
 	int (*rxq_obj_modify)(struct mlx5_rxq_priv *rxq, uint8_t type);
 	void (*rxq_obj_release)(struct mlx5_rxq_priv *rxq);
+	int (*rxq_event_get_lwm)(struct mlx5_priv *priv, int *rxq_idx, int *port_id);
 	int (*ind_table_new)(struct rte_eth_dev *dev, const unsigned int log_n,
 			     struct mlx5_ind_table_obj *ind_tbl);
 	int (*ind_table_modify)(struct rte_eth_dev *dev,
@@ -1599,6 +1604,8 @@ int mlx5_udp_tunnel_port_add(struct rte_eth_dev *dev,
 bool mlx5_is_hpf(struct rte_eth_dev *dev);
 bool mlx5_is_sf_repr(struct rte_eth_dev *dev);
 void mlx5_age_event_prepare(struct mlx5_dev_ctx_shared *sh);
+int mlx5_lwm_setup(struct mlx5_priv *priv);
+void mlx5_lwm_unset(struct mlx5_dev_ctx_shared *sh);
 
 /* Macro to iterate over all valid ports for mlx5 driver. */
 #define MLX5_ETH_FOREACH_DEV(port_id, dev) \
drivers/net/mlx5/mlx5_devx.c +47 -0

59 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.c +29 -0
index e5eea0a..f72364e 100644
@@ -1187,3 +1187,32 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 {
 	return -ENOTSUP;
 }
+
+/**
+ * Rte interrupt handler for LWM event.
+ * It first checks if the event arrives, if so invokes the callback registered
+ * for LWM event in the rxq.
+ *
+ * @param args
+ *   Generic pointer to mlx5_priv.
+ */
+void
+mlx5_dev_interrupt_handler_lwm(void *args)
+{
+	struct mlx5_priv *priv = args;
+	struct mlx5_rxq_priv *rxq;
+	struct rte_eth_dev *dev;
+	int ret, rxq_idx = 0, port_id = 0;
+
+	ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
+	if (unlikely(ret < 0)) {
+		DRV_LOG(WARNING, "Cannot get LWM event context.");
+		return;
+	}
+	DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
+		port_id, rxq_idx);
+	dev = &rte_eth_devices[port_id];
+	rxq = mlx5_rxq_get(dev, rxq_idx);
+	if (rxq && rxq->lwm_event_rxq_limit_reached)
+		rxq->lwm_event_rxq_limit_reached(port_id, rxq_idx);
+}
drivers/net/mlx5/mlx5_rx.h +7 -0
index 98d7cae..bf3c5e1 100644
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {
 	struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
+	void (*lwm_event_rxq_limit_reached)(uint16_t port_id, uint16_t rxq_id);
 };
 
 /* External RX queue descriptor. */
@@ -294,6 +295,7 @@ void mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 int mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 			   struct rte_eth_burst_mode *mode);
 int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
+void mlx5_dev_interrupt_handler_lwm(void *args);
 
 /* Vectorized version of mlx5_rx.c */
 int mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq_data);
@@ -674,4 +676,9 @@ uint16_t mlx5_rx_burst_mprq_vec(void *dpdk_rxq, struct rte_mbuf **pkts,
 	return !!__atomic_load_n(&rxq->refcnt, __ATOMIC_RELAXED);
 }
 
+#define LWM_COOKIE_RXQID_OFFSET 0
+#define LWM_COOKIE_RXQID_MASK 0xffff
+#define LWM_COOKIE_PORTID_OFFSET 16
+#define LWM_COOKIE_PORTID_MASK 0xffff
+
 #endif /* RTE_PMD_MLX5_RX_H_ */
Signature · 1 line
1.8.3.1
author
#123 lore raw

RFC 4/6 net/mlx5: add private API to configure Rxq LWM

In reply to Spike Du

The new API allows setting/unsetting/modifying an LWM(limit watermark) event per Rxq.
While the Rx queue fullness reaches the LWM limit, the driver catches an HW event and invokes the user callback.

---
 doc/guides/nics/mlx5.rst               |  4 ++
 doc/guides/rel_notes/release_22_03.rst |  6 +++
 drivers/common/mlx5/mlx5_prm.h         |  1 +
 drivers/net/mlx5/mlx5_rx.c             | 88 +++++++++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_rx.h             |  1 +
 drivers/net/mlx5/rte_pmd_mlx5.h        | 32 +++++++++++++
 drivers/net/mlx5/version.map           |  1 +
 7 files changed, 132 insertions(+), 1 deletion(-)
doc/guides/nics/mlx5.rst +4 -0
index a734d10..0e983a6 100644
@@ -92,6 +92,7 @@ Features
 - Connection tracking.
 - Sub-Function representors.
 - Sub-Function.
+- Rx queue LWM (Limit WaterMark) configuration.
 
 
 Limitations
@@ -507,6 +508,9 @@ Limitations
 - The NIC egress flow rules on representor port are not supported.
 
 
+- LWM:
+  - Doesn't support shared Rx queue and Hairpin Rx queue.
+
 Statistics
 ----------
 
doc/guides/rel_notes/release_22_03.rst +6 -0
index 60e5b4f..0c9d3b6 100644
@@ -187,6 +187,12 @@ New Features
 
   An API was added to get/set an asymmetric crypto session's user data.
 
+* **Updated Mellanox mlx5 driver.**
+
+  Updated the Mellanox mlx5 driver with new features and improvements, including:
+
+  * Added Rx queue LWM(Limit WaterMark) support.
+
 * **Updated Marvell cnxk crypto PMD.**
 
   * Added SHA256-HMAC support in lookaside protocol (IPsec) for CN10K.
drivers/common/mlx5/mlx5_prm.h +1 -0
index 44b1822..23b13e3 100644
@@ -3290,6 +3290,7 @@ struct mlx5_aso_wqe {
 
 enum {
 	MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+	MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED = 0x14,
 };
 
 enum {
drivers/net/mlx5/mlx5_rx.c +87 -1

105 lines not on this page · raw message

drivers/net/mlx5/mlx5_rx.h +1 -0
index bf3c5e1..5e56258 100644
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {
 	struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */
 	uint32_t hairpin_status; /* Hairpin binding status. */
 	uint32_t lwm:16;
+	uint32_t lwm_devx_subscribed:1;
 	void (*lwm_event_rxq_limit_reached)(uint16_t port_id, uint16_t rxq_id);
 };
 
drivers/net/mlx5/rte_pmd_mlx5.h +32 -0
index 6e7907e..4d2fb42 100644
@@ -109,6 +109,38 @@ int rte_pmd_mlx5_external_rx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
 int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id,
 					    uint16_t dpdk_idx);
 
+typedef void (*lwm_event_rxq_limit_reached_t)(uint16_t port_id,
+					      uint16_t rxq_id);
+/**
+ * Arm an Rx queue LWM(limit watermark) event.
+ * While the Rx queue fullness reaches the LWM limit, the driver catches
+ * an HW event and invokes the user event callback.
+ * After the last event handling, the user needs to call this API again
+ * to arm an additional event.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] rxq_id
+ *   The rxq id.
+ * @param[in] lwm
+ *   The LWM value, is defined by a percentage of the Rx queue size.
+ *   [1-99] to set a new LWM (update the old value).
+ *   0 to unarm the event.
+ * @param[in] cb
+ *   The LWM event callback.
+ *
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOMEM - not enough memory to create LWM event channel.
+ *   - EINVAL - the input Rxq is not created by devx.
+ *   - E2BIG  - lwm is bigger than 99.
+ */
+__rte_experimental
+int rte_pmd_mlx5_config_rxq_lwm(uint16_t port_id, uint16_t rxq_id,
+				uint8_t lwm,
+				lwm_event_rxq_limit_reached_t cb);
+
 #ifdef __cplusplus
 }
 #endif
drivers/net/mlx5/version.map +1 -0
index 79cb79a..8c965dd 100644
@@ -12,4 +12,5 @@ EXPERIMENTAL {
 	# added in 22.03
 	rte_pmd_mlx5_external_rx_queue_id_map;
 	rte_pmd_mlx5_external_rx_queue_id_unmap;
+	rte_pmd_mlx5_config_rxq_lwm;
 };
Signature · 1 line
1.8.3.1
author
#124 lore raw

RFC 5/6 net/mlx5: add private API to config host port shaper

In reply to Spike Du

Host port shaper can be configured with QSHR(QoS Shaper Host Register). Add check in build files to enable this function or not.

The host shaper configuration affects all the ethdev ports belonging to the same host port.

Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM(Limit Watermark) event.

---
 doc/guides/nics/mlx5.rst               |   7 +++
 doc/guides/rel_notes/release_22_03.rst |   1 +
 drivers/common/mlx5/linux/meson.build  |  21 +++++--
 drivers/common/mlx5/mlx5_prm.h         |  25 ++++++++
 drivers/net/mlx5/mlx5.h                |   2 +
 drivers/net/mlx5/mlx5_rx.c             | 104 +++++++++++++++++++++++++++++++++
 drivers/net/mlx5/rte_pmd_mlx5.h        |  30 ++++++++++
 drivers/net/mlx5/version.map           |   1 +
 8 files changed, 187 insertions(+), 4 deletions(-)
doc/guides/nics/mlx5.rst +7 -0
index 0e983a6..35210c1 100644
@@ -93,6 +93,7 @@ Features
 - Sub-Function representors.
 - Sub-Function.
 - Rx queue LWM (Limit WaterMark) configuration.
+- Host shaper support.
 
 
 Limitations
@@ -511,6 +512,12 @@ Limitations
 - LWM:
   - Doesn't support shared Rx queue and Hairpin Rx queue.
 
+- Host shaper:
+
+  - Support BlueField series NIC from BlueField 2.
+  - When configure host shaper with MLX5_HOST_SHAPER_FLAG_LWM_TRIGGERED flag set,
+    only rate 0 and 100Mbps are supported.
+
 Statistics
 ----------
 
doc/guides/rel_notes/release_22_03.rst +1 -0
index 0c9d3b6..3ab4388 100644
@@ -192,6 +192,7 @@ New Features
   Updated the Mellanox mlx5 driver with new features and improvements, including:
 
   * Added Rx queue LWM(Limit WaterMark) support.
+  * Added host shaper support.
 
 * **Updated Marvell cnxk crypto PMD.**
 
drivers/common/mlx5/linux/meson.build +17 -4
index ed48245..c88c184 100644
@@ -16,8 +16,9 @@ if dlopen_ibverbs
     ]
 endif
 
-libnames = [ 'mlx5', 'ibverbs' ]
+libnames = [ 'mlx5', 'ibverbs', 'mtcr_ul' ]
 libs = []
+libmtcr_ul_found = false
 foreach libname:libnames
     lib = dependency('lib' + libname, static:static_ibverbs, required:false, method: 'pkg-config')
     if not lib.found() and not static_ibverbs
@@ -28,10 +29,16 @@ foreach libname:libnames
         if not static_ibverbs and not dlopen_ibverbs
             ext_deps += lib
         endif
+        if libname == 'mtcr_ul'
+            libmtcr_ul_found = true
+            ext_deps += lib
+        endif
     else
-        build = false
-        reason = 'missing dependency, "' + libname + '"'
-        subdir_done()
+        if libname != 'mtcr_ul'
+            build = false
+            reason = 'missing dependency, "' + libname + '"'
+            subdir_done()
+        endif
     endif
 endforeach
 if static_ibverbs or dlopen_ibverbs
@@ -205,6 +212,12 @@ has_sym_args = [
         [ 'HAVE_MLX5_IBV_IMPORT_CTX_PD_AND_MR', 'infiniband/verbs.h',
             'ibv_import_device' ],
 ]
+if  libmtcr_ul_found
+    has_sym_args += [
+        [  'HAVE_MLX5_MSTFLINT', 'mstflint/mtcr.h',
+            'mopen'],
+    ]
+endif
 config = configuration_data()
 foreach arg:has_sym_args
     config.set(arg[0], cc.has_header_symbol(arg[1], arg[2], dependencies: libs))
drivers/common/mlx5/mlx5_prm.h +25 -0
index 23b13e3..3559927 100644
@@ -3768,6 +3768,7 @@ enum {
 	MLX5_CRYPTO_COMMISSIONING_REGISTER_ID = 0xC003,
 	MLX5_IMPORT_KEK_HANDLE_REGISTER_ID = 0xC004,
 	MLX5_CREDENTIAL_HANDLE_REGISTER_ID = 0xC005,
+	MLX5_QSHR_REGISTER_ID = 0x4030,
 };
 
 struct mlx5_ifc_register_mtutc_bits {
@@ -3782,6 +3783,30 @@ struct mlx5_ifc_register_mtutc_bits {
 	u8 time_adjustment[0x20];
 };
 
+struct mlx5_ifc_ets_global_config_register_bits {
+	u8 reserved_at_0[0x2];
+	u8 rate_limit_update[0x1];
+	u8 reserved_at_3[0x29];
+	u8 max_bw_units[0x4];
+	u8 reserved_at_48[0x8];
+	u8 max_bw_value[0x8];
+};
+
+#define ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED      0x0
+#define ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS 0x3
+#define ETS_GLOBAL_CONFIG_BW_UNIT_GBPS          0x4
+
+struct mlx5_ifc_register_qshr_bits {
+	u8 reserved_at_0[0x4];
+	u8 connected_host[0x1];
+	u8 vqos[0x1];
+	u8 fast_response[0x1];
+	u8 reserved_at_7[0x1];
+	u8 local_port[0x8];
+	u8 reserved_at_16[0x230];
+	struct mlx5_ifc_ets_global_config_register_bits global_config;
+};
+
 #define MLX5_MTUTC_TIMESTAMP_MODE_INTERNAL_TIMER 0
 #define MLX5_MTUTC_TIMESTAMP_MODE_REAL_TIME 1
 
drivers/net/mlx5/mlx5.h +2 -0
index 515ff33..5dfd375 100644
@@ -1267,6 +1267,8 @@ struct mlx5_dev_ctx_shared {
 	void *devx_channel_lwm;
 	struct rte_intr_handle *intr_handle_lwm;
 	pthread_mutex_t lwm_config_lock;
+	uint32_t host_shaper_rate:8;
+	uint32_t lwm_triggered:1;
 	/* Availability of mreg_c's. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
drivers/net/mlx5/mlx5_rx.c +104 -0

113 lines not on this page · raw message

drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
index 4d2fb42..3a32463 100644
@@ -141,6 +141,36 @@ int rte_pmd_mlx5_config_rxq_lwm(uint16_t port_id, uint16_t rxq_id,
 				uint8_t lwm,
 				lwm_event_rxq_limit_reached_t cb);
 
+/**
+ * The rate of the host port shaper will be updated directly at the next
+ * LWM event to the rate that comes with this flag set; set rate 0
+ * to disable this rate update.
+ * Unset this flag to update the rate of the host port shaper directly in
+ * the API call; use rate 0 to disable the current shaper.
+ */
+#define MLX5_HOST_SHAPER_FLAG_LWM_TRIGGERED 0
+
+/**
+ * Configure an HW shaper to limit Rx rate for a host port.
+ * The configuration will affect all the ethdev ports belonging to
+ * the same rte_device.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] rate
+ *   Unit is 100Mbps, setting the rate to 0 disables the shaper.
+ * @param[in] flags
+ *   Host shaper flags.
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOENT - no ibdev interface.
+ *   - EBUSY  - the register access unit is busy.
+ *   - EIO    - the register access command meets IO error.
+ */
+__rte_experimental
+int rte_pmd_mlx5_config_host_shaper(int port_id, uint8_t rate, uint32_t flags);
+
 #ifdef __cplusplus
 }
 #endif
drivers/net/mlx5/version.map +1 -0
index 8c965dd..5029e19 100644
@@ -13,4 +13,5 @@ EXPERIMENTAL {
 	rte_pmd_mlx5_external_rx_queue_id_map;
 	rte_pmd_mlx5_external_rx_queue_id_unmap;
 	rte_pmd_mlx5_config_rxq_lwm;
+	rte_pmd_mlx5_config_host_shaper;
 };
Signature · 1 line
1.8.3.1
author
#125 lore raw

RFC 6/6 app/testpmd: add LWM and Host Shaper command

In reply to Spike Du

Add command line options to support LWM per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> lwm <lwm_num>
set port <port_id> host_shaper lwm_triggered <0|1> rate <rate_num>

- Example commands:
To configure LWM as 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0 lwm 30

To disable LWM on port 1 rxq 0:
testpmd> set port 1 rxq 0 lwm 0

To enable lwm_triggered on port 1 and disable current host shaper:
testpmd> set port 1 host_shaper lwm_triggered 1 rate 0

To disable lwm_triggered and current host shaper on port 1:
testpmd> set port 1 host_shaper lwm_triggered 0 rate 0

The rate unit is 100Mbps.
To disable lwm_triggered and configure a shaper of 5Gbps on port 1:
testpmd> set port 1 host_shaper lwm_triggered 0 rate 50

Add sample code to handle rxq LWM event, it delays a while so that rxq empties, then disables host shaper and rearms LWM event.

---
 app/test-pmd/cmdline.c   | 149 +++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/config.c    | 122 ++++++++++++++++++++++++++++++++++++++
 app/test-pmd/meson.build |   3 +
 app/test-pmd/testpmd.c   |   3 +
 app/test-pmd/testpmd.h   |   5 ++
 doc/guides/nics/mlx5.rst |  76 ++++++++++++++++++++++++
 6 files changed, 358 insertions(+)
app/test-pmd/cmdline.c +149 -0
index 7ab0575..8a5fe26 100644
@@ -17807,6 +17807,151 @@ struct cmd_show_port_flow_transfer_proxy_result {
 	}
 };
 
+#ifdef RTE_NET_MLX5
+
+/* *** SET LIMIT WARTER MARK FOR A RXQ OF A PORT *** */
+struct cmd_rxq_lwm_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	uint16_t port_num;
+	cmdline_fixed_string_t rxq;
+	uint16_t rxq_num;
+	cmdline_fixed_string_t lwm;
+	uint16_t lwm_num;
+};
+
+static void cmd_rxq_lwm_parsed(void *parsed_result,
+		__rte_unused struct cmdline *cl,
+		__rte_unused void *data)
+{
+	struct cmd_rxq_lwm_result *res = parsed_result;
+	int ret = 0;
+
+	if ((strcmp(res->set, "set") == 0) && (strcmp(res->port, "port") == 0)
+	    && (strcmp(res->rxq, "rxq") == 0)
+	    && (strcmp(res->lwm, "lwm") == 0))
+		ret = set_rxq_lwm(res->port_num, res->rxq_num,
+				  res->lwm_num);
+	if (ret < 0)
+		printf("rxq_lwm_cmd error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_rxq_lwm_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_rxq_lwm_result,
+				set, "set");
+cmdline_parse_token_string_t cmd_rxq_lwm_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_rxq_lwm_result,
+				port, "port");
+cmdline_parse_token_num_t cmd_rxq_lwm_portnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_rxq_lwm_result,
+				port_num, RTE_UINT16);
+cmdline_parse_token_string_t cmd_rxq_lwm_rxq =
+	TOKEN_STRING_INITIALIZER(struct cmd_rxq_lwm_result,
+				rxq, "rxq");
+cmdline_parse_token_num_t cmd_rxq_lwm_rxqnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_rxq_lwm_result,
+				rxq_num, RTE_UINT8);
+cmdline_parse_token_string_t cmd_rxq_lwm_lwm =
+	TOKEN_STRING_INITIALIZER(struct cmd_rxq_lwm_result,
+				lwm, "lwm");
+cmdline_parse_token_num_t cmd_rxq_lwm_lwmnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_rxq_lwm_result,
+				lwm_num, RTE_UINT16);
+
+cmdline_parse_inst_t cmd_rxq_lwm = {
+	.f = cmd_rxq_lwm_parsed,
+	.data = (void *)0,
+	.help_str = "set port <port_id> rxq <rxq_id> lwm <lwm_num>"
+		"Set lwm for rxq on port_id",
+	.tokens = {
+		(void *)&cmd_rxq_lwm_set,
+		(void *)&cmd_rxq_lwm_port,
+		(void *)&cmd_rxq_lwm_portnum,
+		(void *)&cmd_rxq_lwm_rxq,
+		(void *)&cmd_rxq_lwm_rxqnum,
+		(void *)&cmd_rxq_lwm_lwm,
+		(void *)&cmd_rxq_lwm_lwmnum,
+		NULL,
+	},
+};
+
+/* *** SET HOST_SHAPER LWM TRIGGERED FOR A PORT *** */
+struct cmd_port_host_shaper_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	uint16_t port_num;
+	cmdline_fixed_string_t host_shaper;
+	cmdline_fixed_string_t lwm_triggered;
+	uint16_t fr;
+	cmdline_fixed_string_t rate;
+	uint8_t rate_num;
+};
+
+static void cmd_port_host_shaper_parsed(void *parsed_result,
+		__rte_unused struct cmdline *cl,
+		__rte_unused void *data)
+{
+	struct cmd_port_host_shaper_result *res = parsed_result;
+	int ret = 0;
+
+	if ((strcmp(res->set, "set") == 0) && (strcmp(res->port, "port") == 0)
+	    && (strcmp(res->host_shaper, "host_shaper") == 0)
+	    && (strcmp(res->lwm_triggered, "lwm_triggered") == 0)
+	    && (strcmp(res->rate, "rate") == 0))
+		ret = set_port_host_shaper(res->port_num, res->fr,
+					   res->rate_num);
+	if (ret < 0)
+		printf("cmd_port_host_shaper error: (%s)\n", strerror(-ret));
+
+}
+
+cmdline_parse_token_string_t cmd_port_host_shaper_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
+				set, "set");
+cmdline_parse_token_string_t cmd_port_host_shaper_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
+				port, "port");
+cmdline_parse_token_num_t cmd_port_host_shaper_portnum =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
+				port_num, RTE_UINT16);
+cmdline_parse_token_string_t cmd_port_host_shaper_host_shaper =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
+				 host_shaper, "host_shaper");
+cmdline_parse_token_string_t cmd_port_host_shaper_lwm_triggered =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
+				 lwm_triggered, "lwm_triggered");
+cmdline_parse_token_num_t cmd_port_host_shaper_fr =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
+			      fr, RTE_UINT16);
+cmdline_parse_token_string_t cmd_port_host_shaper_rate =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result,
+				 rate, "rate");
+cmdline_parse_token_num_t cmd_port_host_shaper_rate_num =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_host_shaper_result,
+			      rate_num, RTE_UINT8);
+
+
+cmdline_parse_inst_t cmd_port_host_shaper = {
+	.f = cmd_port_host_shaper_parsed,
+	.data = (void *)0,
+	.help_str = "set port <port_id> host_shaper lwm_triggered <0|1> "
+	"rate <rate_num>: Set HOST_SHAPER lwm_triggered and rate with port_id",
+	.tokens = {
+		(void *)&cmd_port_host_shaper_set,
+		(void *)&cmd_port_host_shaper_port,
+		(void *)&cmd_port_host_shaper_portnum,
+		(void *)&cmd_port_host_shaper_host_shaper,
+		(void *)&cmd_port_host_shaper_lwm_triggered,
+		(void *)&cmd_port_host_shaper_fr,
+		(void *)&cmd_port_host_shaper_rate,
+		(void *)&cmd_port_host_shaper_rate_num,
+		NULL,
+	},
+};
+
+#endif
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -18093,6 +18238,10 @@ struct cmd_show_port_flow_transfer_proxy_result {
 	(cmdline_parse_inst_t *)&cmd_show_capability,
 	(cmdline_parse_inst_t *)&cmd_set_flex_is_pattern,
 	(cmdline_parse_inst_t *)&cmd_set_flex_spec_pattern,
+#ifdef RTE_NET_MLX5
+	(cmdline_parse_inst_t *)&cmd_rxq_lwm,
+	(cmdline_parse_inst_t *)&cmd_port_host_shaper,
+#endif
 	NULL,
 };
 
app/test-pmd/config.c +122 -0

137 lines not on this page · raw message

app/test-pmd/meson.build +3 -0
index 43130c8..c4fd379 100644
@@ -73,3 +73,6 @@ endif
 if dpdk_conf.has('RTE_NET_DPAA')
     deps += ['bus_dpaa', 'mempool_dpaa', 'net_dpaa']
 endif
+if dpdk_conf.has('RTE_NET_MLX5')
+    deps += 'net_mlx5'
+endif
app/test-pmd/testpmd.c +3 -0
index fe2ce19..3b53cd8 100644
@@ -66,6 +66,9 @@
 #ifdef RTE_EXEC_ENV_WINDOWS
 #include <process.h>
 #endif
+#ifdef RTE_NET_MLX5
+#include <rte_pmd_mlx5.h>
+#endif
 
 #include "testpmd.h"
 
app/test-pmd/testpmd.h +5 -0
index 31f766c..aed2057 100644
@@ -1163,6 +1163,11 @@ uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue,
 void flex_item_create(portid_t port_id, uint16_t flex_id, const char *filename);
 void flex_item_destroy(portid_t port_id, uint16_t flex_id);
 void port_flex_item_flush(portid_t port_id);
+#ifdef RTE_NET_MLX5
+int set_rxq_lwm(portid_t port_id, uint16_t queue_idx, uint16_t lwm);
+int set_port_host_shaper(portid_t port_id, uint16_t lwm_triggered,
+			 uint8_t rate);
+#endif
 
 extern int flow_parse(const char *src, void *result, unsigned int size,
 		      struct rte_flow_attr **attr,
doc/guides/nics/mlx5.rst +76 -0

79 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#126 lore raw
In reply to Spike Du
Quoted 13 lines · Spike Du

LWM(limit watermark) is per RX queue attribute, when RX queue fullness reach the LWM limit, HW sends an event to dpdk application.
Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM event.

These two features can combine to control traffic from host port to wire port. The work flow is configure LWM to RX queue and enable lwm-triggered flag in host shaper, after receiving LWM event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to reduce RX queue drops.

Quoted 7 lines

Spike Du (6):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management net/mlx5: add LWM event handling support net/mlx5: add private API to configure Rxq LWM net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command

+ @Andrew Rybchenko @Ferruh Yigit [email protected]

I think, case one, can be easily abstracted via adding new rte_eth_event_type event and
case two can be abstracted via the existing Rx meter framework in ethdev.

Also, Updating generic testpmd to support PMD specific API should be avoided, I know there
is existing stuff in testpmd, I think, we should have the policy to add PMD specific commands to testpmd.

There are around 56PMDs in ethdev now, If PMDs try to add PMD specific API in testpmd it will be bloated or
at minimum, it should a separate file in testpmd if we choose to take that path.

+ @[email protected]

author
#127 lore raw

Hi Jerin,
Thanks for your comments and sorry for the late response.

For case one, I think I can refine the design and add LWM(limit watermark) in rte_eth_rxconf, and add a new rte_eth_event_type event.

For case two(host shaper), I think we can't use RX meter, because it's actually TX shaper on a remote system. It's quite specific to Mellanox/Nvidia BlueField 2(BF2 for short) NIC. The NIC contains an ARM system. We have two terms here: Host-system stands for the system the BF2 NIC is inserted; ARM-system stands for the embedded ARM in BF2. ARM-system is doing the forwarding. This is the way host shaper works: we configure the register on ARM-system, but it affects Host-system's TX shaper, which means the shaper is working on the remote port, it's not a RX meter concept, hence we can't use DPDK RX meter framework. I'd suggest to still use private API.

For testpmd part, I understand your concern. Because we need one private API for host shaper, and we need testpmd's forwarding code to show how it works to user, we need to call the private API in testpmd. If current patch is not acceptable, what's the correct way to do it? Any framework to isolate the PMD private logic from testpmd common code, but still give a chance to call private APIs in testpmd?

Regards,
Spike.

Quoted 55 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, April 5, 2022 4:59 PM
To: Spike Du <[email protected]>; Andrew Rybchenko <[email protected]>; Cristian Dumitrescu <[email protected]>; Ferruh Yigit <[email protected]>; [email protected]
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; dpdk-dev <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC 0/6] net/mlx5: introduce limit watermark and host shaper

External email: Use caution opening links or attachments

Quoted 9 lines · Spike Du

LWM(limit watermark) is per RX queue attribute, when RX queue fullness reach the LWM limit, HW sends an event to dpdk application. Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM event.

These two features can combine to control traffic from host port to wire

port.

Quoted 3 lines

The work flow is configure LWM to RX queue and enable lwm-triggered flag in host shaper, after receiving LWM event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to

reduce RX queue drops.

Quoted 8 lines

Spike Du (6):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management net/mlx5: add LWM event handling support net/mlx5: add private API to configure Rxq LWM net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command

+ @Andrew Rybchenko @Ferruh Yigit [email protected]

I think, case one, can be easily abstracted via adding new rte_eth_event_type event and case two can be abstracted via the existing Rx meter framework in ethdev.

Also, Updating generic testpmd to support PMD specific API should be avoided, I know there is existing stuff in testpmd, I think, we should have the policy to add PMD specific commands to testpmd.

There are around 56PMDs in ethdev now, If PMDs try to add PMD specific API in testpmd it will be bloated or at minimum, it should a separate file in testpmd if we choose to take that path.

+ @[email protected]

#128 lore raw
Quoted 2 lines · Spike Du

Hi Jerin,

Hi Spike,

Quoted 3 lines

Thanks for your comments and sorry for the late response.

For case one, I think I can refine the design and add LWM(limit watermark) in rte_eth_rxconf, and add a new rte_eth_event_type event.

OK.

Quoted 2 lines

For case two(host shaper), I think we can't use RX meter, because it's actually TX shaper on a remote system. It's quite specific to Mellanox/Nvidia BlueField 2(BF2 for short) NIC. The NIC contains an ARM system. We have two terms here: Host-system stands for the system the BF2 NIC is inserted; ARM-system stands for the embedded ARM in BF2. ARM-system is doing the forwarding. This is the way host shaper works: we configure the register on ARM-system, but it affects Host-system's TX shaper, which means the shaper is working on the remote port, it's not a RX meter concept, hence we can't use DPDK RX meter framework. I'd suggest to still use private API.

OK. If the host is using the DPDK application then rte_tm can be used on the egress side to enable the same. If it is not DPDK, then yes, we need private APIs.

Quoted 2 lines

For testpmd part, I understand your concern. Because we need one private API for host shaper, and we need testpmd's forwarding code to show how it works to user, we need to call the private API in testpmd. If current patch is not acceptable, what's the correct way to do it? Any framework to isolate the PMD private logic from testpmd common code, but still give a chance to call private APIs in testpmd?

Please check "PMD API" item in
http://mails.dpdk.org/archives/dev/2022-April/239191.html

Quoted 62 lines

Regards,
Spike.

Quoted 55 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, April 5, 2022 4:59 PM
To: Spike Du <[email protected]>; Andrew Rybchenko <[email protected]>; Cristian Dumitrescu <[email protected]>; Ferruh Yigit <[email protected]>; [email protected]
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; dpdk-dev <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC 0/6] net/mlx5: introduce limit watermark and host shaper

External email: Use caution opening links or attachments

Quoted 9 lines · Spike Du

LWM(limit watermark) is per RX queue attribute, when RX queue fullness reach the LWM limit, HW sends an event to dpdk application. Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM event.

These two features can combine to control traffic from host port to wire

port.

Quoted 3 lines

The work flow is configure LWM to RX queue and enable lwm-triggered flag in host shaper, after receiving LWM event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to

reduce RX queue drops.

Quoted 8 lines

Spike Du (6):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management net/mlx5: add LWM event handling support net/mlx5: add private API to configure Rxq LWM net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command

+ @Andrew Rybchenko @Ferruh Yigit [email protected]

I think, case one, can be easily abstracted via adding new rte_eth_event_type event and case two can be abstracted via the existing Rx meter framework in ethdev.

Also, Updating generic testpmd to support PMD specific API should be avoided, I know there is existing stuff in testpmd, I think, we should have the policy to add PMD specific commands to testpmd.

There are around 56PMDs in ethdev now, If PMDs try to add PMD specific API in testpmd it will be bloated or at minimum, it should a separate file in testpmd if we choose to take that path.

+ @[email protected]

author
#129 lore raw

Hi Jerin,

Quoted 10 lines
Quoted 1 line

For case two(host shaper), I think we can't use RX meter, because it's

actually TX shaper on a remote system. It's quite specific to Mellanox/Nvidia BlueField 2(BF2 for short) NIC. The NIC contains an ARM system. We have two terms here: Host-system stands for the system the BF2 NIC is inserted; ARM-system stands for the embedded ARM in BF2. ARM-system is doing the forwarding. This is the way host shaper works: we configure the register on ARM-system, but it affects Host-system's TX shaper, which means the shaper is working on the remote port, it's not a RX meter concept, hence we can't use DPDK RX meter framework. I'd suggest to still use private API.

Quoted 3 lines

OK. If the host is using the DPDK application then rte_tm can be used on the egress side to enable the same. If it is not DPDK, then yes, we need private APIs.

I see your point. The RX drop happens on ARM-system, it'll be too late to notify Host-system to reduce traffic rate. To achieve dropless, MLX developed this feature to configure host shaper on remote port. The Host-system is flexible, it may use DPDK or not.

Regards,
Spike.

Quoted 121 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Sunday, May 1, 2022 8:51 PM
To: Spike Du <[email protected]>
Cc: Andrew Rybchenko <[email protected]>; Cristian Dumitrescu <[email protected]>; Ferruh Yigit <[email protected]>; [email protected]; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; dpdk-dev <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC 0/6] net/mlx5: introduce limit watermark and host shaper

External email: Use caution opening links or attachments

Quoted 2 lines · Spike Du

Hi Jerin,

Hi Spike,

Quoted 3 lines

Thanks for your comments and sorry for the late response.

For case one, I think I can refine the design and add LWM(limit

watermark) in rte_eth_rxconf, and add a new rte_eth_event_type event.

OK.

Quoted 2 lines

For case two(host shaper), I think we can't use RX meter, because it's

actually TX shaper on a remote system. It's quite specific to Mellanox/Nvidia BlueField 2(BF2 for short) NIC. The NIC contains an ARM system. We have two terms here: Host-system stands for the system the BF2 NIC is inserted; ARM-system stands for the embedded ARM in BF2. ARM-system is doing the forwarding. This is the way host shaper works: we configure the register on ARM-system, but it affects Host-system's TX shaper, which means the shaper is working on the remote port, it's not a RX meter concept, hence we can't use DPDK RX meter framework. I'd suggest to still use private API.

OK. If the host is using the DPDK application then rte_tm can be used on the egress side to enable the same. If it is not DPDK, then yes, we need private APIs.

Quoted 2 lines

For testpmd part, I understand your concern. Because we need one

private API for host shaper, and we need testpmd's forwarding code to show how it works to user, we need to call the private API in testpmd. If current patch is not acceptable, what's the correct way to do it? Any framework to isolate the PMD private logic from testpmd common code, but still give a chance to call private APIs in testpmd?

Please check "PMD API" item in
http://mails.dpdk.org/archives/dev/2022-April/239191.html

Quoted 32 lines

Regards,
Spike.

Quoted 25 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, April 5, 2022 4:59 PM
To: Spike Du <[email protected]>; Andrew Rybchenko <[email protected]>; Cristian Dumitrescu <[email protected]>; Ferruh Yigit <[email protected]>; [email protected]
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; dpdk-dev <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC 0/6] net/mlx5: introduce limit watermark and host shaper

External email: Use caution opening links or attachments

Quoted 7 lines · Spike Du

LWM(limit watermark) is per RX queue attribute, when RX queue fullness reach the LWM limit, HW sends an event to dpdk application. Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM

event.

Quoted 33 lines
Quoted 33 lines
Quoted 3 lines

These two features can combine to control traffic from host port to wire

port.

Quoted 4 lines

The work flow is configure LWM to RX queue and enable lwm-triggered flag in host shaper, after receiving LWM event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to

reduce RX queue drops.

Quoted 8 lines

Spike Du (6):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management net/mlx5: add LWM event handling support net/mlx5: add private API to configure Rxq LWM net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command

+ @Andrew Rybchenko @Ferruh Yigit [email protected]

I think, case one, can be easily abstracted via adding new rte_eth_event_type event and case two can be abstracted via the existing Rx meter framework in ethdev.

Also, Updating generic testpmd to support PMD specific API should be avoided, I know there is existing stuff in testpmd, I think, we should have the policy to add PMD specific commands to testpmd.

There are around 56PMDs in ethdev now, If PMDs try to add PMD specific API in testpmd it will be bloated or at minimum, it should a separate file in testpmd if we choose to take that path.

+ @[email protected]

author
#130 lore raw
In reply to Jerin Jacob

Hi Jerin,
Thanks for your comments and sorry for the late response.

For case one, I think I can refine the design and add LWM(limit watermark) in rte_eth_rxconf, and add a new rte_eth_event_type event.

For case two(host shaper), I think we can't use RX meter, because it's actually TX shaper on a remote system. It's quite specific to Mellanox/Nvidia BlueField 2(BF2 for short) NIC. The NIC contains an ARM system. We have two terms here: Host-system stands for the system the BF2 NIC is inserted; ARM-system stands for the embedded ARM in BF2. ARM-system is doing the forwarding. This is the way host shaper works: we configure the register on ARM-system, but it affects Host-system's TX shaper, which means the shaper is working on the remote port, it's not a RX meter concept, hence we can't use DPDK RX meter framework. I'd suggest to still use private API.

For testpmd part, I understand your concern. Because we need one private API for host shaper, and we need testpmd's forwarding code to show how it works to user, we need to call the private API in testpmd. If current patch is not acceptable, what's the correct way to do it? Any framework to isolate the PMD private logic from testpmd common code, but still give a chance to call private APIs in testpmd?

Regards,
Spike.

Quoted 55 lines

-----Original Message-----
From: Jerin Jacob <[email protected]>
Sent: Tuesday, April 5, 2022 4:59 PM
To: Spike Du <[email protected]>; Andrew Rybchenko <[email protected]>; Cristian Dumitrescu <[email protected]>; Ferruh Yigit <[email protected]>; [email protected]
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; dpdk-dev <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC 0/6] net/mlx5: introduce limit watermark and host shaper

External email: Use caution opening links or attachments

Quoted 9 lines · Spike Du

LWM(limit watermark) is per RX queue attribute, when RX queue fullness reach the LWM limit, HW sends an event to dpdk application. Host shaper can configure shaper rate and lwm-triggered for a host port. The shaper limits the rate of traffic from host port to wire port. If lwm-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives LWM event.

These two features can combine to control traffic from host port to wire

port.

Quoted 3 lines

The work flow is configure LWM to RX queue and enable lwm-triggered flag in host shaper, after receiving LWM event, delay a while until RX queue is empty , then disable the shaper. We recycle this work flow to

reduce RX queue drops.

Quoted 8 lines

Spike Du (6):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management net/mlx5: add LWM event handling support net/mlx5: add private API to configure Rxq LWM net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command

+ @Andrew Rybchenko @Ferruh Yigit [email protected]

I think, case one, can be easily abstracted via adding new rte_eth_event_type event and case two can be abstracted via the existing Rx meter framework in ethdev.

Also, Updating generic testpmd to support PMD specific API should be avoided, I know there is existing stuff in testpmd, I think, we should have the policy to add PMD specific commands to testpmd.

There are around 56PMDs in ethdev now, If PMDs try to add PMD specific API in testpmd it will be bloated or at minimum, it should a separate file in testpmd if we choose to take that path.

+ @[email protected]