net/mlx5: introduce limit watermark and host shaper
cover net/mlx5: introduce limit watermark and host shaper
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.
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
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 | 87 +++++++++++ doc/guides/rel_notes/release_22_03.rst | 7 + drivers/common/mlx5/linux/meson.build | 21 ++- 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 | 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.c | 61 ++++++++ drivers/net/mlx5/mlx5.h | 12 +- drivers/net/mlx5/mlx5_devx.c | 57 ++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.c | 221 ++++++++++++++++++++++++++- drivers/net/mlx5/mlx5_rx.h | 9 ++ drivers/net/mlx5/mlx5_txpp.c | 28 +--- drivers/net/mlx5/rte_pmd_mlx5.h | 62 ++++++++ drivers/net/mlx5/version.map | 2 + drivers/net/mlx5/windows/mlx5_ethdev_os.c | 22 --- drivers/vdpa/mlx5/mlx5_vdpa_virtq.c | 52 +------ 27 files changed, 1057 insertions(+), 318 deletions(-)
Signature · 1 line
1.8.3.1
RFC 1/6 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 10 +++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 12 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1391,6 +1391,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +9 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,8 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm;break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +87,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -174,6 +174,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
cover net/mlx5: introduce limit watermark and host shaper
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.
Add new libethdev API to set LWM, add rte event RTE_ETH_EVENT_RXQ_LIMIT_REACHED to handle LWM 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 LWM event handler in mlx5 PMD directory by adding a new file mlx5_test.c. Only add minimal code in testpmd to invoke interfaces from mlx5_test.c.
Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command
app/test-pmd/cmdline.c | 74 ++++++++ app/test-pmd/config.c | 23 +++ app/test-pmd/meson.build | 3 + app/test-pmd/testpmd.c | 13 ++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 87 +++++++++ doc/guides/rel_notes/release_22_07.rst | 2 + drivers/common/mlx5/linux/meson.build | 44 +++-- 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 | 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/meson.build | 7 +- drivers/net/mlx5/mlx5.c | 62 +++++++ 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 | 253 +++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 11 ++ drivers/net/mlx5/mlx5_test.c | 191 ++++++++++++++++++++ drivers/net/mlx5/mlx5_test.h | 27 +++ 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 | 52 +----- lib/ethdev/ethdev_driver.h | 7 + lib/ethdev/rte_ethdev.c | 28 +++ lib/ethdev/rte_ethdev.h | 30 +++- lib/ethdev/version.map | 3 + 34 files changed, 1193 insertions(+), 331 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_test.c create mode 100644 drivers/net/mlx5/mlx5_test.h
Signature · 1 line
1.8.3.1
RFC 1/7 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1391,6 +1391,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
RFC 2/7 common/mlx5: share interrupt management
In reply to Spike DuThere 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 -45
68 lines not on this page · raw message
Signature · 1 line
1.8.3.1
RFC 3/7 ethdev: introduce Rx queue based limit watermark
In reply to Spike DuLWM(limit watermark) is a per Rx queue attribute that notifies dpdk application event of RTE_ETH_EVENT_RXQ_LIMIT_REACHED when the Rx queue's usable descriptor is under the watermark.
To simplify its configuration, LWM is a percentage of Rx queue descriptor size with valid value of [0,99].
Setting LWM to 0 means disable it.
Add LWM's configuration handle in eth_dev_ops.
--- lib/ethdev/ethdev_driver.h | 7 +++++++ lib/ethdev/rte_ethdev.c | 28 ++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 30 +++++++++++++++++++++++++++++- lib/ethdev/version.map | 3 +++ 4 files changed, 67 insertions(+), 1 deletion(-)
lib/ethdev/ethdev_driver.h +7 -0
@@ -470,6 +470,10 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +typedef int (*eth_rx_queue_set_lwm_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t lwm); +/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,
@@ -1283,6 +1287,9 @@ struct eth_dev_ops {/** Dump private info from device */ eth_dev_priv_dump_t eth_dev_priv_dump; + +/** Set Rx queue limit watermark */ +eth_rx_queue_set_lwm_t rx_queue_set_lwm; };/**
lib/ethdev/rte_ethdev.c +28 -0
@@ -4414,6 +4414,34 @@ int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, queue_idx, tx_rate)); } +int rte_eth_rx_queue_set_lwm (uint16_t port_id,uint16_t queue_idx, +uint8_t lwm) +{ +struct rte_eth_dev *dev; +struct rte_eth_dev_info dev_info; +int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_idx > dev_info.max_rx_queues) { +RTE_ETHDEV_LOG (ERR , +"Set queue rate limit:port %u: invalid queue ID=%u\n" , + port_id, queue_idx); +return -EINVAL ; + } + +if (lwm >99 ) +return -EINVAL ; +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_set_lwm, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_set_lwm)(dev, + queue_idx, lwm)); +} +RTE_INIT (eth_dev_init_fp_ops) {uint32_t i;
lib/ethdev/rte_ethdev.h +29 -1
@@ -1249,8 +1249,12 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +uint64_t reserved_64s; +uint32_t reserved_32s; + uint32_t lwm:8; + uint32_t reserved_bits:24;void *reserved_ptrs[2 ];/**< Reserved for future fields */ + };/**
@@ -3668,6 +3672,29 @@ int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,*/ int rte_eth_dev_set_vlan_pvid (uint16_t port_id,uint16_t pvid,int on); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Set Rx queue based limit watermark. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_idx +* The index of the receive queue +* @param lwm +* The limit watermark percentage of Rx queue descriptor size. +* The valid range is [0,99]. +* Setting 0 means disable limit watermark. +* +* @return +* - (0) if successful. +* - negative if failed. +*/ +__rte_experimental +int rte_eth_rx_queue_set_lwm(uint16_t port_id, uint16_t queue_idx, +uint8_t lwm); +typedef void (*buffer_tx_error_fn )(struct rte_mbuf **unsent,uint16_t count,void *userdata);
@@ -3873,6 +3900,7 @@ enum rte_eth_event_type {RTE_ETH_EVENT_DESTROY ,/**< port is released */ RTE_ETH_EVENT_IPSEC ,/**< IPsec offload related event */ RTE_ETH_EVENT_FLOW_AGED ,/**< New aged-out flows is detected */ +RTE_ETH_EVENT_RXQ_LIMIT_REACHED ,/**< RX queue limit reached */ RTE_ETH_EVENT_MAX /**< max value of this enum */ };
lib/ethdev/version.map +3 -0
@@ -279,6 +279,9 @@ EXPERIMENTAL { rte_flow_async_action_handle_create; rte_flow_async_action_handle_destroy; rte_flow_async_action_handle_update; + + # added in 22.07 + rte_eth_rx_queue_set_lwm; }; INTERNAL {
Signature · 1 line
1.8.3.1
Re: [RFC v1 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 1 line · Spike Du
LWM(limit watermark) is a per Rx queue attribute that notifies dpdk
dpdk is not necessary about.
I'm not sure that "attribute" can notify application. Please, reword the description.
Quoted 5 lines
application event of
RTE_ETH_EVENT_RXQ_LIMIT_REACHEDwhen the Rx queue's usable descriptor is under the watermark.
To simplify its configuration, LWM is a percentage of Rx queue descriptor size with valid value of [0,99].
Setting LWM to 0 means disable it.
... which is the default.
Can I request notification when no descriptors left? 1 seems to be close to the answer, but not in the case of big Rx rings.
Quoted 1 line
Add LWM's configuration handle in
eth_dev_ops.
handle sounds bad here. May be "driver callback" or "driver method".
Quoted 14 lines
Signed-off-by Spike Du <[email protected]>--- lib/ethdev/ethdev_driver.h | 7 +++++++ lib/ethdev/rte_ethdev.c | 28 ++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 30 +++++++++++++++++++++++++++++- lib/ethdev/version.map | 3 +++ 4 files changed, 67 insertions(+), 1 deletion(-)lib/ethdev/ethdev_driver.h +0
-0
lib/ethdev/ethdev_driver.h typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev, · line 476
Quoted 7 lines
lib/ethdev/ethdev_driver.h +4
-0@@ -470,6 +470,10 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +typedef int (*eth_rx_queue_set_lwm_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t lwm); +
Please, add full description including parameters and return values.
Quoted 26 lines
lib/ethdev/ethdev_driver.h +3
-0/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,@@ -1283,6 +1287,9 @@ struct eth_dev_ops {/** Dump private info from device */ eth_dev_priv_dump_t eth_dev_priv_dump; + +/** Set Rx queue limit watermark */ +eth_rx_queue_set_lwm_t rx_queue_set_lwm; };/** lib/ethdev/rte_ethdev.c +5
-0@@ -4414,6 +4414,34 @@ int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, queue_idx, tx_rate)); } +int rte_eth_rx_queue_set_lwm (uint16_t port_id,uint16_t queue_idx, +uint8_t lwm) +{ +struct rte_eth_dev *dev; +struct rte_eth_dev_info dev_info;
lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4431
Quoted 10 lines
lib/ethdev/rte_ethdev.c +10
-0+int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_idx > dev_info.max_rx_queues) {
It should be >=
Quoted 21 lines
lib/ethdev/rte_ethdev.c +13
-0+RTE_ETHDEV_LOG (ERR , +"Set queue rate limit:port %u: invalid queue ID=%u\n" , + port_id, queue_idx); +return -EINVAL ; + } + +if (lwm >99 ) +return -EINVAL ; +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_set_lwm, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_set_lwm)(dev, + queue_idx, lwm)); +} +RTE_INIT (eth_dev_init_fp_ops) {uint32_t i;lib/ethdev/rte_ethdev.h +0
-0
lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1255
Quoted 8 lines
lib/ethdev/rte_ethdev.h +4
-1@@ -1249,8 +1249,12 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +uint64_t reserved_64s; +uint32_t reserved_32s; + uint32_t lwm:8; + uint32_t reserved_bits:24;
I strong dislike bit fields for such purpose. It should be uint8_t field.
Since we break ABI below anyway, we can break it here as well.
lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1257
Quoted 2 lines
lib/ethdev/rte_ethdev.h +1
-0void *reserved_ptrs[2 ];/**< Reserved for future fields */ +
No unrelated changes, please.
Quoted 15 lines
lib/ethdev/rte_ethdev.h +8
-0};/** @@ -3668,6 +3672,29 @@ int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,*/ int rte_eth_dev_set_vlan_pvid (uint16_t port_id,uint16_t pvid,int on); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Set Rx queue based limit watermark. +* +* @param port_id +* The port identifier of the Ethernet device.
lib/ethdev/rte_ethdev.h int rte_eth_dev_set_vlan_ether_type(uint16_t port_id, · line 3692
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+* @param queue_idx +* The index of the receive queue +* @param lwm +* The limit watermark percentage of Rx queue descriptor size. +* The valid range is [0,99]. +* Setting 0 means disable limit watermark. +* +* @return +* - (0) if successful. +* - negative if failed.
Please, be precise with negative return values specification and its meaning.
lib/ethdev/rte_ethdev.h enum rte_eth_event_type { · line 3903
Quoted 13 lines
lib/ethdev/rte_ethdev.h +6
-0+*/ +__rte_experimental +int rte_eth_rx_queue_set_lwm(uint16_t port_id, uint16_t queue_idx, +uint8_t lwm); +typedef void (*buffer_tx_error_fn )(struct rte_mbuf **unsent,uint16_t count,void *userdata);@@ -3873,6 +3900,7 @@ enum rte_eth_event_type {RTE_ETH_EVENT_DESTROY ,/**< port is released */ RTE_ETH_EVENT_IPSEC ,/**< IPsec offload related event */ RTE_ETH_EVENT_FLOW_AGED ,/**< New aged-out flows is detected */ + RTE_ETH_EVENT_RXQ_LIMIT_REACHED,/**< RX queue limit reached */
RX -> Rx
as I understand it is an ABI breakage.
Quoted 17 lines
lib/ethdev/rte_ethdev.h +0
-0RTE_ETH_EVENT_MAX /**< max value of this enum */ };lib/ethdev/version.map +3
-0@@ -279,6 +279,9 @@ EXPERIMENTAL { rte_flow_async_action_handle_create; rte_flow_async_action_handle_destroy; rte_flow_async_action_handle_update; + + # added in 22.07 + rte_eth_rx_queue_set_lwm; }; INTERNAL {
RFC 4/7 net/mlx5: add LWM event handling support
In reply to Spike DuWhen 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 | 27 ++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 7 +++++ 5 files changed, 149 insertions(+)
drivers/net/mlx5/mlx5.c +61 -0
@@ -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
@@ -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 +27 -0
@@ -1187,3 +1187,30 @@ 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_RXQ_LIMIT_REACHED. +* +* @param args +* Generic pointer to mlx5_priv. +*/ +void +mlx5_dev_interrupt_handler_lwm (void *args) +{ +struct mlx5_priv *priv = args; +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]; +rte_eth_dev_callback_process (dev,RTE_ETH_EVENT_RXQ_LIMIT_REACHED , + (void *)(uintptr_t )rxq_idx); +}
drivers/net/mlx5/mlx5_rx.h +7 -0
@@ -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; +void (*lwm_event_rxq_limit_reached)(uint16_t port_id,uint16_t rxq_id); };/* 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
RFC 5/7 net/mlx5: support Rx queue based limit watermark
In reply to Spike DuAdd mlx5 specific LWM(limit watermark) configuration handler. 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_07.rst | 1 + drivers/common/mlx5/mlx5_prm.h | 1 + drivers/net/mlx5/mlx5.c | 1 + drivers/net/mlx5/mlx5_rx.c | 123 +++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 3 + 6 files changed, 133 insertions(+)
doc/guides/nics/mlx5.rst +4 -0
@@ -92,6 +92,7 @@ Features - Connection tracking. - Sub-Function representors. - Sub-Function. +- Rx queue LWM (Limit WaterMark) configuration. Limitations
@@ -518,6 +519,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_07.rst +1 -0
@@ -64,6 +64,7 @@ New Features * Added support for promiscuous mode on Windows. * Added support for MTU on Windows. + * Added Rx queue LWM(Limit WaterMark) support. Removed Items
drivers/common/mlx5/mlx5_prm.h +1 -0
@@ -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.c +1 -0
@@ -2062,6 +2062,7 @@ 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_set_lwm = mlx5_rx_queue_set_lwm, .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 +123 -0
156 lines not on this page · raw message
drivers/net/mlx5/mlx5_rx.h +3 -0
@@ -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_devx_subscribed:1;void (*lwm_event_rxq_limit_reached)(uint16_t port_id,uint16_t rxq_id); };
@@ -297,6 +298,8 @@ 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_set_lwm (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
RFC 6/7 net/mlx5: add private API to config host port shaper
In reply to Spike DuHost 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_07.rst | 1 + drivers/common/mlx5/linux/meson.build | 44 +++++++++----- drivers/common/mlx5/mlx5_prm.h | 25 ++++++++ drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_rx.c | 103 +++++++++++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 30 ++++++++++ drivers/net/mlx5/version.map | 2 + 8 files changed, 199 insertions(+), 15 deletions(-)
doc/guides/nics/mlx5.rst +7 -0
@@ -93,6 +93,7 @@ Features - Sub-Function representors. - Sub-Function. - Rx queue LWM (Limit WaterMark) configuration. +- Host shaper support. Limitations
@@ -522,6 +523,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_07.rst +1 -0
@@ -65,6 +65,7 @@ New Features * Added support for promiscuous mode on Windows. * Added support for MTU on Windows. * Added Rx queue LWM(Limit WaterMark) support. + * Added host shaper support. Removed Items
drivers/common/mlx5/linux/meson.build +29 -15
64 lines not on this page · raw message
drivers/common/mlx5/mlx5_prm.h +25 -0
@@ -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
@@ -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 +103 -0
112 lines not on this page · raw message
drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
@@ -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 +* 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 +2 -0
@@ -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_config_host_shaper; };
Signature · 1 line
1.8.3.1
RFC 7/7 app/testpmd: add LWM and Host Shaper command
In reply to Spike DuAdd command line options to support LWM per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> lwm <lwm_num>
mlx5 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> mlx5 set port 1 host_shaper lwm_triggered 1 rate 0
To disable lwm_triggered and current host shaper on port 1:
testpmd> mlx5 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> mlx5 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 | 74 +++++++++++++++++ app/test-pmd/config.c | 23 ++++++ app/test-pmd/meson.build | 3 + app/test-pmd/testpmd.c | 13 +++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 76 +++++++++++++++++ drivers/net/mlx5/meson.build | 7 +- drivers/net/mlx5/mlx5_test.c | 191 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_test.h | 27 ++++++ 9 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_test.c create mode 100644 drivers/net/mlx5/mlx5_test.h
app/test-pmd/cmdline.c +74 -0
@@ -67,6 +67,9 @@#include "cmdline_mtr.h" #include "cmdline_tm.h" #include "bpf_cmd.h" +#ifdef RTE_NET_MLX5 +#include "mlx5_test.h" +#endif static struct cmdline *testpmd_cl;
@@ -17807,6 +17810,73 @@ struct cmd_show_port_flow_transfer_proxy_result { } }; +/* *** 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 , + }, +}; +/* ******************************************************************************** */ /* list of instructions */
@@ -18093,6 +18163,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, + (cmdline_parse_inst_t *)&cmd_rxq_lwm, +#ifdef RTE_NET_MLX5 + (cmdline_parse_inst_t *)&_rte_pmd_mlx5_cmd_port_host_shaper, +#endif NULL, };
app/test-pmd/config.c +23 -0
@@ -6281,3 +6281,26 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (lwm >99 ) +return -EINVAL ; + ret =rte_eth_rx_queue_set_lwm (port_id, queue_idx, lwm); + +if (ret) +return ret; +/* Save the input lwm. */ + ports[port_id].rx_conf[queue_idx].lwm = lwm; +return 0 ; +} +
app/test-pmd/meson.build +3 -0
@@ -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 +13 -0
@@ -66,6 +66,9 @@#ifdef RTE_EXEC_ENV_WINDOWS #include <process.h> #endif +#ifdef RTE_NET_MLX5 +#include "mlx5_test.h" +#endif #include "testpmd.h"
@@ -417,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [RTE_ETH_EVENT_NEW] = "device probed", [RTE_ETH_EVENT_DESTROY] = "device released", [RTE_ETH_EVENT_FLOW_AGED] = "flow aged", + [RTE_ETH_EVENT_RXQ_LIMIT_REACHED] = "rxq limit reached", [RTE_ETH_EVENT_MAX] = NULL, };
@@ -3539,6 +3543,7 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + uint16_t rxq_idx;RTE_SET_USED (param);RTE_SET_USED (ret_param);
@@ -3570,6 +3575,14 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RXQ_LIMIT_REACHED : + rxq_idx = (uint16_t )(uintptr_t )ret_param; +printf ("recv rxq_limit_reached event, port:%d rxq_id:%d\n" , port_id, + rxq_idx); +#ifdef RTE_NET_MLX5 +mlx5_test_lwm_event_rxq_limit_reached (port_id, rxq_idx); +#endif +break ;default :break ; }
app/test-pmd/testpmd.h +1 -0
@@ -1163,6 +1163,7 @@ 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); +int set_rxq_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm); 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
drivers/net/mlx5/meson.build +5 -2
@@ -8,8 +8,10 @@ if not (is_linux or is_windows) subdir_done() endif -deps += ['hash', 'common_mlx5'] -headers = files('rte_pmd_mlx5.h') +deps += ['hash', 'common_mlx5', 'cmdline'] +headers = files('rte_pmd_mlx5.h', + 'mlx5_test.h', + ) sources = files( 'mlx5.c', 'mlx5_ethdev.c',
@@ -38,6 +40,7 @@ sources = files( 'mlx5_vlan.c', 'mlx5_utils.c', 'mlx5_devx.c', + 'mlx5_test.c', ) if is_linux
drivers/net/mlx5/mlx5_test.c new file +191 -0
191 lines not on this page · raw message
drivers/net/mlx5/mlx5_test.h new file +27 -0
@@ -0,0 +1,27 @@ +/* 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_RXQ_LIMIT_REACHED 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_lwm_event_rxq_limit_reached (uint16_t port_id,uint16_t rxq_id); + +extern cmdline_parse_inst_t _rte_pmd_mlx5_cmd_port_host_shaper; +#endif
Signature · 1 line
1.8.3.1
v2 cover introduce per-queue limit watermark and host shaper
In reply to Spike DuLWM(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.
Add new libethdev API to set LWM, add rte event RTE_ETH_EVENT_RXQ_LIMIT_REACHED to handle LWM 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 LWM event handler in mlx5 PMD directory by adding a new file mlx5_test.c. Only add minimal code in testpmd to invoke interfaces from mlx5_test.c.
Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command
app/test-pmd/cmdline.c | 74 +++++ app/test-pmd/config.c | 23 ++ app/test-pmd/meson.build | 4 + app/test-pmd/testpmd.c | 24 ++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 84 ++++++ 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/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 | 292 +++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 13 + drivers/net/mlx5/mlx5_testpmd.c | 184 ++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 27 ++ 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 +-- lib/ethdev/ethdev_driver.h | 22 ++ lib/ethdev/rte_ethdev.c | 52 ++++ lib/ethdev/rte_ethdev.h | 74 ++++- lib/ethdev/version.map | 4 + 33 files changed, 1305 insertions(+), 309 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
2.27.0
RFC v2 1/7 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@ mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_priv *rxq, int on)* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@ mlx5_devx_modify_rq(struct mlx5_rxq_priv *rxq, uint8_t type)case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ mlx5_devx_modify_rq(struct mlx5_rxq_priv *rxq, uint8_t type) rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@ int mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx);int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
2.27.0
RFC v2 2/7 common/mlx5: share interrupt management
In reply to Spike DuThere 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
@@ -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 @@ mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *pmd_mr)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
@@ -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 @@ __rte_internalint 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
@@ -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
@@ -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 @@ void *mlx5_os_umem_reg(void *ctx, void *addr, size_t size, uint32_t access);__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
@@ -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
@@ -741,11 +741,8 @@ mlx5_txpp_interrupt_handler(void *cb_arg)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 @@ mlx5_txpp_start_service(struct mlx5_dev_ctx_shared *sh) 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
@@ -140,28 +140,6 @@ mlx5_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)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
2.27.0
RFC v2 3/7 ethdev: introduce Rx queue based limit watermark
In reply to Spike DuLWM(limit watermark) describes the fullness of a Rx queue. If the Rx queue fullness is above LWM, the device will trigger the event RTE_ETH_EVENT_RX_LWM.
LWM is defined as a percentage of Rx queue size with valid value of [0,99].
Setting LWM to 0 means disable it, which is the default. When translate the percentage to queue descriptor number, the numbe should be bigger than 0 and less than queue size.
Add LWM's configuration and query driver callbacks in eth_dev_ops.
--- lib/ethdev/ethdev_driver.h | 22 ++++++++++++ lib/ethdev/rte_ethdev.c | 52 +++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 74 +++++++++++++++++++++++++++++++++++++- lib/ethdev/version.map | 4 +++ 4 files changed, 151 insertions(+), 1 deletion(-)
lib/ethdev/ethdev_driver.h +22 -0
@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue limit watermark. +* see @rte_eth_rx_lwm_set() +*/ +typedef int (*eth_rx_queue_lwm_set_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t lwm); + +/** +* @internal Query queue limit watermark. +* see @rte_eth_rx_lwm_query() +*/ + +typedef int (*eth_rx_queue_lwm_query_t )(struct rte_eth_dev *dev, +uint16_t *rx_queue_id, +uint8_t *lwm); +/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,
@@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t priority_flow_ctrl_queue_config; +/** Set Rx queue limit watermark */ +eth_rx_queue_lwm_set_t rx_queue_lwm_set; +/** Query Rx queue limit watermark */ +eth_rx_queue_lwm_query_t rx_queue_lwm_query; +/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set;/** Set Unicast hash bitmap */
lib/ethdev/rte_ethdev.c +52 -0
58 lines not on this page · raw message
lib/ethdev/rte_ethdev.h +73 -1
92 lines not on this page · raw message
lib/ethdev/version.map +4 -0
@@ -279,6 +279,10 @@ EXPERIMENTAL { rte_flow_async_action_handle_create; rte_flow_async_action_handle_destroy; rte_flow_async_action_handle_update; + + # added in 22.07 + rte_eth_rx_lwm_set; + rte_eth_rx_lwm_query; }; INTERNAL {
Signature · 1 line
2.27.0
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 12 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
lib/ethdev/rte_ethdev.h +3
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage,
lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1264
Quoted 10 lines
lib/ethdev/rte_ethdev.h +7
-0+* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;void *reserved_ptrs[2 ];/**< Reserved for future fields */ };
Ok but, this is an ABI risk about this because reserved stuff was never required before. Whenever is a reserved field is introduced the code (in this case rte_ethdev_configure).
Best practice would have been to have the code require all reserved fields be 0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.
Also, using 8 bits as percentage is different than how other API's handle this. Since Rx queue size is in packets, why is this not in packets? Also document what behavior of 0 is.
Why introduce new query/set operations? This should just be part of the overall device configuration.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Hi, pls see below.
Quoted 44 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Sunday, May 22, 2022 11:23 PM
To: Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
Quoted 12 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
lib/ethdev/rte_ethdev.h index renamed from lib/ethdev/rte_ethdev.h +0
-0
04cff8ee10..687ae5ff29100644lib/ethdev/rte_ethdev.h +3
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1264
Quoted 10 lines
lib/ethdev/rte_ethdev.h +7
-0+* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;void *reserved_ptrs[2 ];/**< Reserved for future fields */ };Ok but, this is an ABI risk about this because reserved stuff was never required before.
Whenever is a reserved field is introduced the code (in this caserte_ethdev_configure).
Quoted 3 lines
Best practice would have been to have the code require all reserved fields be 0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.
Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is generated.
Quoted 3 lines
Also, using 8 bits as percentage is different than how other API's handle this. Since Rx queue size is in packets, why is this not in packets?
The short answer is to simply the LWM configuration.
Rx queue descriptor is complex nowadays.
For normal queue, user may configure LWM according to queue descriptor number easily.
But for below queues, it's not easy:
Take mprq as example, the testpmd cmd options can be " -a 0000:03:00.0,rxqs_min_mprq=1,mprq_en=1,mprq_max_memcpy_len=465,mprq_log_stride_size=8,mprq_log_stride_num=3 -- --mbcache=512 -i --nb-cores=7 --txd=1024 --rxd=1024 ",
For MLX5 implementation, the minimum "unit" in queue has 64 descriptors, the "unit" number is 16, if you configure according to descriptor number(1024) Here, you may easily set LWM as something like 512, but HW doesn't allow it, because 512 > 16. If you want the watermark to be half, the correct value is 8. The same issue happens to feature like "Rx queue buffer split" where a packet can be split to multiple descriptors.
Using percentage doesn't have such issues, PMD will cover all the details.
Quoted 1 line
Also document what behavior of 0 is.
Sure. The behavior is like the old days without this feature, pls see above.
Quoted 2 lines
Why introduce new query/set operations? This should just be part of the overall device configuration.
Due to different implementation. LWM can be a dynamic configuration which can help user design a flexible flow control.
User may feel ok with LWM of 80% to get high throughput, or later on with 50% to throttle the traffic responsively by handling LWM event in order to reduce drop. Some driver like mlx5 may implement LWM event as one-time shot. When you receive LWM event, you need to reconfigure LWM in order to receive the event again, thus you will not likely to be overwhelmed by the events.
These all require set operation.
For the query operation. The rte_event API rte_eth_dev_callback_process() is per-port API, it doesn't carry much information when an event happens. When a LWM event happens, we need to know in which Rx queue it happens or optionally what's the current LWM percentage of this queue. The query operation serves this purpose.
Regards,
Spike.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime. Let's think what would happen in such a case.
Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup() is called with rx_conf->lwm not initialized. Then the library and drivers may interpret a wrong value.
Quoted 6 lines
Quoted 3 lines
Best practice would have been to have the code require all reserved fields be 0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.
Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value,
we should better add a field in the struct rte_eth_rxq_info.
[...]
Quoted 3 lines
Quoted 3 lines
Why introduce new query/set operations? This should just be part of the overall device configuration.
Thanks to the "set" function, we can avoid the ABI compat issue.
Quoted 5 lines
Due to different implementation. LWM can be a dynamic configuration which can help user design a flexible flow control.
User may feel ok with LWM of 80% to get high throughput, or later on with 50% to throttle the traffic responsively by handling LWM event in order to reduce drop. Some driver like mlx5 may implement LWM event as one-time shot. When you receive LWM event, you need to reconfigure LWM in order to receive the event again, thus you will not likely to be overwhelmed by the events.
These all require set operation.
Yes it is better to allow dynamic watermark configuration, not using the function rte_eth_rx_queue_setup().
Quoted 3 lines
For the query operation. The
rte_eventAPIrte_eth_dev_callback_process()is per-port API, it doesn't carry much information when an event happens. When a LWM event happens, we need to know in which Rx queue it happens or optionally what's the current LWM percentage of this queue. The query operation serves this purpose.
Yes "query" has to be called in the event handler because event structure is not specific to any event type.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 57 lines
-----Original Message-----
From: Thomas Monjalon <[email protected]>
Sent: Tuesday, May 24, 2022 5:46 AM
To: Stephen Hemminger <[email protected]>; Spike Du <[email protected]>
Cc: [email protected]; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; Raslan Darawsheh <[email protected]>; [email protected]; [email protected]
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime.
Let's think what would happen in such a case.Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup()is called withrx_conf->lwmnot initialized. Then the library and drivers may interpret a wrong value.Quoted 7 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
Quoted 7 lines
generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value, we should better add a field in the structrte_eth_rxq_info.
At least from all the dpdk app/example code, rxconf is initialized to 0 then setup The Rx queue, if user follows these examples we should not have ABI issue. Since many people are concerned about rxconf change, it's ok to remove the LWM Field there.
Yes, I think we can add lwm into rte_eth_rxq_info. If we can set Rx queue's attribute, We should have a way to get it.
Quoted 32 lines
[...]
Quoted 3 lines
Quoted 3 lines
Why introduce new query/set operations? This should just be part of the overall device configuration.
Thanks to the "set" function, we can avoid the ABI compat issue.
Quoted 1 line
Due to different implementation. LWM can be a dynamic configuration
which can help user design a flexible flow control.
Quoted 1 line
User may feel ok with LWM of 80% to get high throughput, or later on with
50% to throttle the traffic responsively by handling LWM event in order to reduce drop.
Quoted 2 lines
Some driver like mlx5 may implement LWM event as one-time shot. When you receive LWM event, you need to reconfigure LWM in order to receive
the event again, thus you will not likely to be overwhelmed by the events.
Quoted 1 line
These all require set operation.
Yes it is better to allow dynamic watermark configuration, not using the function
rte_eth_rx_queue_setup().Quoted 1 line
For the query operation. The
rte_eventAPI
rte_eth_dev_callback_process()is per-port API, it doesn't carry much information when an event happens.Quoted 1 line
When a LWM event happens, we need to know in which Rx queue it
happens or optionally what's the current LWM percentage of this queue.
Quoted 1 line
The query operation serves this purpose.
Yes "query" has to be called in the event handler because event structure is not specific to any event type.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
24/05/2022 04:50, Spike Du:
Quoted 50 lines
From: Thomas Monjalon <[email protected]>
Quoted 41 lines
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime.
Let's think what would happen in such a case.Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup()is called withrx_conf->lwmnot initialized. Then the library and drivers may interpret a wrong value.Quoted 7 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
Quoted 7 lines
generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value, we should better add a field in the structrte_eth_rxq_info.
Quoted 6 lines
At least from all the dpdk app/example code, rxconf is initialized to 0 then setup The Rx queue, if user follows these examples we should not have ABI issue. Since many people are concerned about rxconf change, it's ok to remove the LWM Field there.
Yes, I think we can add lwm intorte_eth_rxq_info. If we can set Rx queue's attribute, We should have a way to get it.
Unfortunately we cannot rely on examples for ABI compatibility. My suggestion of moving the field in rte_eth_rxq_info is not obvious because it could change the size of the struct. But thanks to __rte_cache_min_aligned, it is OK. Running pahole on this struct shows we have 50 bytes free:
/* size: 128, cachelines: 2, members: 6 */
/* padding: 50 */The other option would be to get the LWM value with a "get" function.
What others prefer?
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 63 lines · Thomas Monjalon
24/05/2022 04:50, Spike Du:
Quoted 50 lines
From: Thomas Monjalon <[email protected]>
Quoted 41 lines
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime.
Let's think what would happen in such a case.Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup()is called withrx_conf->lwmnot initialized. Then the library and drivers may interpret a wrong value.Quoted 7 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
Quoted 7 lines
generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value, we should better add a field in the structrte_eth_rxq_info.Quoted 6 lines
At least from all the dpdk app/example code, rxconf is initialized to 0 then setup The Rx queue, if user follows these examples we should not have ABI issue. Since many people are concerned about rxconf change, it's ok to remove the LWM Field there.
Yes, I think we can add lwm intorte_eth_rxq_info. If we can set Rx queue's attribute, We should have a way to get it.Unfortunately we cannot rely on examples for ABI compatibility. My suggestion of moving the field in
rte_eth_rxq_infois not obvious because it could change the size of the struct. But thanks to__rte_cache_min_aligned, it is OK. Running pahole on this struct shows we have 50 bytes free:
Quoted 6 lines
/* size: 128, cachelines: 2, members: 6 */ /* padding: 50 */The other option would be to get the LWM value with a "get" function.
What others prefer?
If I'm not mistaken the changeset breaks ABI in any case since it adds a new event and changes MAX. If so, I'd wait for the next ABI breaking release and do not touch reserved fields.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
25/05/2022 14:59, Andrew Rybchenko:
Quoted 67 lines · Thomas Monjalon
Quoted 66 lines
24/05/2022 04:50, Spike Du:
Quoted 50 lines
From: Thomas Monjalon <[email protected]>
Quoted 41 lines
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime.
Let's think what would happen in such a case.Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup()is called withrx_conf->lwmnot initialized. Then the library and drivers may interpret a wrong value.Quoted 7 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
Quoted 7 lines
generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value, we should better add a field in the structrte_eth_rxq_info.Quoted 6 lines
At least from all the dpdk app/example code, rxconf is initialized to 0 then setup The Rx queue, if user follows these examples we should not have ABI issue. Since many people are concerned about rxconf change, it's ok to remove the LWM Field there.
Yes, I think we can add lwm intorte_eth_rxq_info. If we can set Rx queue's attribute, We should have a way to get it.Unfortunately we cannot rely on examples for ABI compatibility. My suggestion of moving the field in
rte_eth_rxq_infois not obvious because it could change the size of the struct. But thanks to__rte_cache_min_aligned, it is OK. Running pahole on this struct shows we have 50 bytes free:/* size: 128, cachelines: 2, members: 6 */ /* padding: 50 */
Quoted 6 lines
Quoted 3 lines
The other option would be to get the LWM value with a "get" function.
What others prefer?
If I'm not mistaken the changeset breaks ABI in any case since it adds a new event and changes MAX.
I think we can consider it as not a breakage (a rule should be added). Last time we had to update this enum, this was the conclusion:
from https://git.dpdk.org/dpdk/commit/?id=44bf3c796be3f
"
The new event type addition in the enum is flagged as an ABI breakage, so an ignore rule is added for these reasons:
- It is not changing value of existing types (except MAX)
- The new value is not used by existing API if the event is not registered
In general, it is safe adding new ethdev event types at the end of the enum, because of event callback registration mechanism.
"
Quoted 2 lines
If so, I'd wait for the
next ABI breaking release and do not touch reserved fields.
In any case, rte_eth_rxconf is not a good fit
because we have a separate function for configuration.
It should be either in rte_eth_rxq_info or a specific "get" function.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 75 lines · Thomas Monjalon
25/05/2022 14:59, Andrew Rybchenko:
Quoted 67 lines · Thomas Monjalon
Quoted 66 lines
24/05/2022 04:50, Spike Du:
Quoted 50 lines
From: Thomas Monjalon <[email protected]>
Quoted 41 lines
23/05/2022 05:01, Spike Du:
Quoted 22 lines
From: Stephen Hemminger <[email protected]>
Quoted 21 lines
Quoted 7 lines · Spike Du
lib/ethdev/rte_ethdev.h +0
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1261
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;Ok but, this is an ABI risk about this because reserved stuff was never required before.
An ABI compatibility issue would be for an application compiled with an old DPDK, and loading a new DPDK at runtime.
Let's think what would happen in such a case.Quoted 2 lines
Quoted 2 lines
Whenever is a reserved field is introduced the code (in this case
rte_ethdev_configure).
rte_eth_rx_queue_setup()is called withrx_conf->lwmnot initialized. Then the library and drivers may interpret a wrong value.Quoted 7 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
Quoted 7 lines
generated.
The problem is to have a value not initialized.
I think the best approach is to not expose the LWM value through this configuration structure.
If the need is to get the current value, we should better add a field in the structrte_eth_rxq_info.Quoted 6 lines
At least from all the dpdk app/example code, rxconf is initialized to 0 then setup The Rx queue, if user follows these examples we should not have ABI issue. Since many people are concerned about rxconf change, it's ok to remove the LWM Field there.
Yes, I think we can add lwm intorte_eth_rxq_info. If we can set Rx queue's attribute, We should have a way to get it.Unfortunately we cannot rely on examples for ABI compatibility. My suggestion of moving the field in
rte_eth_rxq_infois not obvious because it could change the size of the struct. But thanks to__rte_cache_min_aligned, it is OK. Running pahole on this struct shows we have 50 bytes free:/* size: 128, cachelines: 2, members: 6 */ /* padding: 50 */Quoted 6 lines
Quoted 3 lines
The other option would be to get the LWM value with a "get" function.
What others prefer?
If I'm not mistaken the changeset breaks ABI in any case since it adds a new event and changes MAX.
Quoted 12 lines
I think we can consider it as not a breakage (a rule should be added). Last time we had to update this enum, this was the conclusion:
from https://git.dpdk.org/dpdk/commit/?id=44bf3c796be3f
"
The new event type addition in the enum is flagged as an ABI breakage, so an ignore rule is added for these reasons:
- It is not changing value of existing types (except MAX)
- The new value is not used by existing API if the event is not registered
In general, it is safe adding new ethdev event types at the end of the enum, because of event callback registration mechanism.
"
I see. Makes sense. Thanks for the information.
Quoted 5 lines
Quoted 2 lines
If so, I'd wait for the
next ABI breaking release and do not touch reserved fields.In any case,
rte_eth_rxconfis not a good fit because we have a separate function for configuration.
Yes, it is better to avoid two ways to configure the same thing.
Quoted 1 line
It should be either in
rte_eth_rxq_infoor a specific "get" function.
I see no point to introduce specific get function for a single value. I think that rte_eth_rxq_info is the right way to get current value.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
In reply to Spike DuQuoted 76 lines · On Mon, 23 May 2022 03:01:20 +0000 Spike Du <[email protected]> wrote:
Hi, pls see below.
Quoted 44 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Sunday, May 22, 2022 11:23 PM
To: Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
Quoted 12 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
lib/ethdev/rte_ethdev.h index renamed from lib/ethdev/rte_ethdev.h +0
-0
04cff8ee10..687ae5ff29100644lib/ethdev/rte_ethdev.h +3
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1264
Quoted 10 lines
lib/ethdev/rte_ethdev.h +7
-0+* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;void *reserved_ptrs[2 ];/**< Reserved for future fields */ };Ok but, this is an ABI risk about this because reserved stuff was never required before.
Whenever is a reserved field is introduced the code (in this caserte_ethdev_configure).Quoted 3 lines
Best practice would have been to have the code require all reserved fields be 0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.
Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is generated.
Quoted 3 lines
Also, using 8 bits as percentage is different than how other API's handle this. Since Rx queue size is in packets, why is this not in packets?
The short answer is to simply the LWM configuration.
Rx queue descriptor is complex nowadays.
For normal queue, user may configure LWM according to queue descriptor number easily.
But for below queues, it's not easy:
Take mprq as example, the testpmd cmd options can be " -a 0000:03:00.0,rxqs_min_mprq=1,mprq_en=1,mprq_max_memcpy_len=465,mprq_log_stride_size=8,mprq_log_stride_num=3 -- --mbcache=512 -i --nb-cores=7 --txd=1024 --rxd=1024 ",
For MLX5 implementation, the minimum "unit" in queue has 64 descriptors, the "unit" number is 16, if you configure according to descriptor number(1024) Here, you may easily set LWM as something like 512, but HW doesn't allow it, because 512 > 16. If you want the watermark to be half, the correct value is 8. The same issue happens to feature like "Rx queue buffer split" where a packet can be split to multiple descriptors.
Using percentage doesn't have such issues, PMD will cover all the details.Quoted 1 line
Also document what behavior of 0 is.
Sure. The behavior is like the old days without this feature, pls see above.
Quoted 2 lines
Why introduce new query/set operations? This should just be part of the overall device configuration.
Due to different implementation. LWM can be a dynamic configuration which can help user design a flexible flow control.
User may feel ok with LWM of 80% to get high throughput, or later on with 50% to throttle the traffic responsively by handling LWM event in order to reduce drop. Some driver like mlx5 may implement LWM event as one-time shot. When you receive LWM event, you need to reconfigure LWM in order to receive the event again, thus you will not likely to be overwhelmed by the events.
These all require set operation.
Quoted 9 lines
For the query operation. The
rte_eventAPIrte_eth_dev_callback_process()is per-port API, it doesn't carry much information when an event happens. When a LWM event happens, we need to know in which Rx queue it happens or optionally what's the current LWM percentage of this queue. The query operation serves this purpose.Regards,
Spike.
The bigger question is why does this have to be just MLX5 and why can't it fit into the existing DPDK RX interrupt framework?
Linux and BSD have had this for years in their packet coalescing logic. Ethtool provides ability to set lot of irq coalescing parameters like:
ethtool -C|--coalesce devname [adaptive-rx on|off] [adaptive-tx on|off]
[rx-usecs N] [rx-frames N] [rx-usecs-irq N] [rx-frames-irq N] [tx-usecs N] [tx-frames N] [tx-usecs-irq N] [tx-frames-irq N] [stats-block-usecs N] [pkt-rate-low N] [rx-usecs-low N] [rx-frames-low N] [tx-usecs-low N] [tx-frames-low N] [pkt-rate-high N] [rx-usecs-high N] [rx-frames-high N] [tx-usecs-high N] [tx-frames-high N] [sample-interval N] [cqe-mode-rx on|off] [cqe-mode-tx on|off]
It feels like this is just the DPDK version of a small subset of that. Since many device already support IRQ coalescing, it would be best to build one new API that has most of these. Rather than a MLX/Nvidia only API for a single parameter.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 139 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Tuesday, May 24, 2022 6:55 AM
To: Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
Quoted 48 lines · On Mon, 23 May 2022 03:01:20 +0000 Spike Du <[email protected]> wrote:
Hi, pls see below.
Quoted 46 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Sunday, May 22, 2022 11:23 PM
To: Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
Quoted 13 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
lib/ethdev/rte_ethdev.h +0
-0index
04cff8ee10..687ae5ff29100644lib/ethdev/rte_ethdev.h +3
-1@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/ union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1264
Quoted 10 lines
lib/ethdev/rte_ethdev.h +7
-0+* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm; + +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;void *reserved_ptrs[2 ];/**< Reserved for future fields */ };Ok but, this is an ABI risk about this because reserved stuff was never required before.
Whenever is a reserved field is introduced the code (in this caserte_ethdev_configure).Quoted 6 lines
Quoted 4 lines
Best practice would have been to have the code require all reserved fields be
0 in earlier releases. In this case an application is like to define a watermark of zero; how will your code handle it.Having watermark of 0 is desired, which is the default. LWM of 0 means the Rx Queue's watermark is not monitored, hence no LWM event is
generated.
Quoted 2 lines
Quoted 2 lines
Also, using 8 bits as percentage is different than how other API's handle
this.
Quoted 4 lines
Quoted 1 line
Since Rx queue size is in packets, why is this not in packets?
The short answer is to simply the LWM configuration.
Rx queue descriptor is complex nowadays.
For normal queue, user may configure LWM according to queue descriptornumber easily.
Quoted 3 lines
But for below queues, it's not easy:
Take mprq as example, the testpmd cmd options can be " -a0000:03:00.0,rxqs_min_mprq=1,mprq_en=1,mprq_max_memcpy_len=465,
mprq_loQuoted 4 lines
g_stride_size=8,mprq_log_stride_num=3
-- --mbcache=512 -i --nb-cores=7 --txd=1024 --rxd=1024 ", For MLX5 implementation, the minimum "unit" in queue has 64 descriptors, the "unit" number is 16, if you configure according to descriptor number(1024)Here, you may easily set LWM as something like 512, but HW doesn't allow it, because 512 > 16. If you want the watermark to be half, the correct value is 8.
Quoted 1 line
The same issue happens to feature like "Rx queue buffer split" where a
packet can be split to multiple descriptors.
Quoted 8 lines
Using percentage doesn't have such issues, PMD will cover all the details.
Quoted 1 line
Also document what behavior of 0 is.
Sure. The behavior is like the old days without this feature, pls see above.
Quoted 2 lines
Why introduce new query/set operations? This should just be part of the overall device configuration.
Due to different implementation. LWM can be a dynamic configuration
which can help user design a flexible flow control.
Quoted 1 line
User may feel ok with LWM of 80% to get high throughput, or later on with
50% to throttle the traffic responsively by handling LWM event in order to reduce drop.
Quoted 2 lines
Some driver like mlx5 may implement LWM event as one-time shot. When you receive LWM event, you need to reconfigure LWM in order to receive
the event again, thus you will not likely to be overwhelmed by the events.
Quoted 3 lines
These all require set operation.
For the query operation. The
rte_eventAPI
rte_eth_dev_callback_process()is per-port API, it doesn't carry much information when an event happens.Quoted 1 line
When a LWM event happens, we need to know in which Rx queue it
happens or optionally what's the current LWM percentage of this queue.
Quoted 7 lines
The query operation serves this purpose.
Regards,
Spike.The bigger question is why does this have to be just MLX5 and why can't it fit into the existing DPDK RX interrupt framework?
Linux and BSD have had this for years in their packet coalescing logic. Ethtool provides ability to set lot of irq coalescing parameters like:
ethtool -C|--coalesce devname [adaptive-rx on|off] [adaptive-tx on|off]
[rx-usecs N] [rx-frames N] [rx-usecs-irq N] [rx-frames-irq N] [tx-usecs N] [tx-frames N] [tx-usecs-irq N] [tx-frames-irq N] [stats-block-usecs N] [pkt-rate-low N] [rx-usecs-low N] [rx-frames-low N] [tx-usecs-low N] [tx-frames-low N] [pkt-rate-high N] [rx-usecs-high N] [rx-frames-high N] [tx-usecs-high N] [tx-frames-high N] [sample-interval N] [cqe-mode-rx on|off] [cqe-mode-tx on|off]
Quoted 4 lines
It feels like this is just the DPDK version of a small subset of that. Since many device already support IRQ coalescing, it would be best to build one new API that has most of these. Rather than a MLX/Nvidia only API for a single parameter.
I take MLX5 as example here because I only know how mlx5 works, I don't understand How other NICs work. It doesn't mean I try to change common code only to satisfy Mlx5 needs.
I think interrupt coalesce is different from LWM:
Interrupt coalesce is delay interrupt until a batch of packets(or an interval) is received. LWM intends to notify when a Rx queue is out of buffer. Delaying interrupt can't detect A specific fullness value of the Rx queue, but LWM can if driver supports it.
Regards,
Spike.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
In reply to Spike DuQuoted 11 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
LWM(limit watermark) describes the fullness of a Rx queue. If the Rx queue fullness is above LWM, the device will trigger the event
RTE_ETH_EVENT_RX_LWM.
LWM is defined as a percentage of Rx queue size with valid value of [0,99].
Setting LWM to 0 means disable it, which is the default. When translate the percentage to queue descriptor number, the numbe should be bigger than 0 and less than queue size.
Add LWM's configuration and query driver callbacks ineth_dev_ops.Signed-off-by Spike Du <[email protected]>
One other objection, please don't invent yet another event channel for this. It should be part of existing Rx interrupt logic.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Hi,
Quoted 26 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: Sunday, May 22, 2022 11:25 PM
To: Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact- Thomas Monjalon (EXTERNAL) <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
Quoted 10 lines · On Sun, 22 May 2022 08:58:56 +0300 Spike Du <[email protected]> wrote:
LWM(limit watermark) describes the fullness of a Rx queue. If the Rx queue fullness is above LWM, the device will trigger the event
RTE_ETH_EVENT_RX_LWM.
LWM is defined as a percentage of Rx queue size with valid value of [0,99].
Setting LWM to 0 means disable it, which is the default. When translate the percentage to queue descriptor number, the numbe should be bigger than 0 and less than queue size.
Add LWM's configuration and query driver callbacks ineth_dev_ops.
Quoted 4 lines
Quoted 1 line
Signed-off-by Spike Du <[email protected]>One other objection, please don't invent yet another event channel for this. It should be part of existing Rx interrupt logic.
I think this is misunderstanding, the "event channel" is a specific concept in MLX5 PMD. For the DPDK common code like testpmd and event register/callback, I'm using standard dpdk interfaces.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
In reply to Spike DuQuoted 19 lines
From: Spike Du [mailto:[email protected]]
Sent: Sunday, 22 May 2022 07.59LWM(limit watermark) describes the fullness of a Rx queue. If the Rx queue fullness is above LWM, the device will trigger the event
RTE_ETH_EVENT_RX_LWM.
LWM is defined as a percentage of Rx queue size with valid value of [0,99].
Setting LWM to 0 means disable it, which is the default. When translate the percentage to queue descriptor number, the numbe should be bigger than 0 and less than queue size.
Add LWM's configuration and query driver callbacks ineth_dev_ops.Signed-off-by Spike Du <[email protected]>---
lib/ethdev/rte_ethdev.h +0
-0@@ -1249,7 +1249,16 @@ struct rte_eth_rxconf {*/
lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1258
Quoted 10 lines
lib/ethdev/rte_ethdev.h +6
-1union rte_eth_rxseg *rx_seg; -uint64_t reserved_64s[2 ];/**< Reserved for future fields */ +/** +* Per-queue Rx limit watermark defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_LWM is triggered. +*/ +uint8_t lwm;
Why percentage, why not 1/128th, or 1/16th? 2^N seems more logical, and I wonder if such high granularity is really necessary. Just a thought, it's not important.
If you stick with percentage, it only needs 7 bits, and you can make the remaining one bit reserved.
Also, please add here that 0 means disable.
Quoted 7 lines
lib/ethdev/rte_ethdev.h +4
-0+ +uint8_t reserved_bits[3 ]; +uint32_t reserved_32s; +uint64_t reserved_64s;void *reserved_ptrs[2 ];/**< Reserved for future fields */ };
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
23/05/2022 08:07, Morten Brørup:
Quoted 3 lines
lib/ethdev/rte_ethdev.h struct rte_eth_rxconf { · line 1257
Quoted 1 line
lib/ethdev/rte_ethdev.h +1
-0+uint8_t lwm;Why percentage, why not 1/128th, or 1/16th? 2^N seems more logical, and I wonder if such high granularity is really necessary. Just a thought, it's not important.
I think percentage is the easiest to understand and to share with other teams in design documents.
Quoted 3 lines
If you stick with percentage, it only needs 7 bits, and you can make the remaining one bit reserved.
Also, please add here that 0 means disable.
Good idea.
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 19 lines
-----Original Message-----
From: Thomas Monjalon <[email protected]>
Sent: Monday, May 23, 2022 6:59 PM
To: Spike Du <[email protected]>; Morten Brørup <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermarkExternal email: Use caution opening links or attachments
23/05/2022 08:07, Morten Brørup:
Quoted 3 lines
Quoted 1 line
+
uint8_tlwm;Why percentage, why not 1/128th, or 1/16th? 2^N seems more logical, and
Quoted 8 lines
I wonder if such high granularity is really necessary. Just a thought, it's not important.
I think percentage is the easiest to understand and to share with other teams in design documents.
Quoted 1 line
If you stick with percentage, it only needs 7 bits, and you can make the
remaining one bit reserved.
Agree, will change to use 7 bits.
Quoted 2 lines
Quoted 2 lines
Also, please add here that 0 means disable.
Sure.
Quoted 3 lines
Good idea.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
23/05/2022 16:10, Spike Du:
Quoted 5 lines
Quoted 3 lines
From: Thomas Monjalon <[email protected]>
Quoted 1 line
If you stick with percentage, it only needs 7 bits, and you can make the
remaining one bit reserved.
Agree, will change to use 7 bits.
I'm not sure it's worth introducing a bit field here.
Re: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 8 lines · Thomas Monjalon
23/05/2022 16:10, Spike Du:
Quoted 5 lines
Quoted 3 lines
From: Thomas Monjalon <[email protected]>
Quoted 1 line
If you stick with percentage, it only needs 7 bits, and you can make the
remaining one bit reserved.
Agree, will change to use 7 bits.
I'm not sure it's worth introducing a bit field here.
+1
RE: [RFC v2 3/7] ethdev: introduce Rx queue based limit watermark
Quoted 7 lines
From: Andrew Rybchenko [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 08.35Quoted 3 lines · Thomas Monjalon
23/05/2022 16:10, Spike Du:
Quoted 2 lines
Quoted 2 lines
From: Thomas Monjalon <[email protected]>
Quoted 1 line
If you stick with percentage, it only needs 7 bits, and you can
Quoted 8 lines
make the
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
remaining one bit reserved.
Agree, will change to use 7 bits.
I'm not sure it's worth introducing a bit field here.
+1
It's not important for me either. Just stick with the full byte. I mainly mentioned it in case you considered reducing the parameter granularity to 1/16th instead of percent, so you would only need 4 bits.
RFC v2 4/7 net/mlx5: add LWM event handling support
In reply to Spike DuWhen 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
@@ -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>
@@ -1524,6 +1526,69 @@ mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn,return NULL ; } +/** +* 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 @@ mlx5_free_shared_dev_ctx(struct mlx5_dev_ctx_shared *sh)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
@@ -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_net_remove(struct mlx5_common_device *cdev);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
@@ -1187,3 +1187,36 @@ mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused) {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_LWM ,NULL ); +}
drivers/net/mlx5/mlx5_rx.h +7 -0
@@ -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 @@ mlx5_is_external_rxq(struct rte_eth_dev *dev, uint16_t queue_idx) 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
2.27.0
RFC v2 5/7 net/mlx5: support Rx queue based limit watermark
In reply to Spike DuAdd mlx5 specific LWM(limit watermark) configuration and query handler. 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 | 156 +++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 5 + 6 files changed, 177 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
@@ -93,6 +93,7 @@ Features - Connection tracking. - Sub-Function representors. - Sub-Function. +- Rx queue LWM (Limit WaterMark) configuration. Limitations
@@ -520,6 +521,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 ----------
@@ -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 + +LWM introduction +---------------- + +LWM (Limit WaterMark) is a per Rx queue attribute, it should be configured as +a percentage of the Rx queue size. +When Rx queue fullness is above LWM, an event is sent to PMD. +
doc/guides/rel_notes/release_22_07.rst +1 -0
@@ -80,6 +80,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 LWM(Limit WaterMark) support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/mlx5_prm.h +1 -0
@@ -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
@@ -2071,6 +2071,8 @@ const struct eth_dev_ops mlx5_dev_ops = { .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_lwm_set = mlx5_rx_queue_lwm_set, + .rx_queue_lwm_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 +156 -0
195 lines not on this page · raw message
drivers/net/mlx5/mlx5_rx.h +5 -0
@@ -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
2.27.0
RFC v2 6/7 net/mlx5: add private API to config host port shaper
In reply to Spike DuHost 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 | 26 +++++++ 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 | 103 +++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 30 +++++++ drivers/net/mlx5/version.map | 2 + 8 files changed, 202 insertions(+)
doc/guides/nics/mlx5.rst +26 -0
@@ -94,6 +94,7 @@ Features - Sub-Function representors. - Sub-Function. - Rx queue LWM (Limit WaterMark) 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_LWM_TRIGGERED flag set, + only rate 0 and 100Mbps are supported. + Statistics ----------
@@ -1692,3 +1699,22 @@ LWM (Limit WaterMark) is a per Rx queue attribute, it should be configured as a percentage of the Rx queue size. When Rx queue fullness is above LWM, 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 +LWM event trigger. In immediate mode, the rate limit is configured immediately +to host shaper. When deferring to LWM trigger, the shaper is not set until an +LWM 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 LMW event, which allows +throttling host traffic on LWM events at minimum latency, preventing excess +drops in the Rx queue. +
doc/guides/rel_notes/release_22_07.rst +1 -0
@@ -81,6 +81,7 @@ New Features * Added support for MTU on Windows. * Added matching and RSS on IPsec ESP. * Added Rx queue LWM(Limit WaterMark) support. + * Added host shaper support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/linux/meson.build +13 -0
@@ -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
@@ -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
@@ -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 +103 -0
112 lines not on this page · raw message
drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
@@ -109,6 +109,36 @@ __rte_experimentalint 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 +* 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 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
@@ -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
2.27.0
RFC v2 7/7 app/testpmd: add LWM and Host Shaper command
In reply to Spike DuAdd command line options to support LWM per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> lwm <lwm_num>
mlx5 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> mlx5 set port 1 host_shaper lwm_triggered 1 rate 0
To disable lwm_triggered and current host shaper on port 1:
testpmd> mlx5 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> mlx5 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 | 74 +++++++++++++ app/test-pmd/config.c | 23 ++++ app/test-pmd/meson.build | 4 + app/test-pmd/testpmd.c | 24 +++++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 46 ++++++++ drivers/net/mlx5/mlx5_testpmd.c | 184 ++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 27 +++++ 8 files changed, 383 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/cmdline.c +74 -0
@@ -67,6 +67,9 @@#include "cmdline_mtr.h" #include "cmdline_tm.h" #include "bpf_cmd.h" +#ifdef RTE_NET_MLX5 +#include "mlx5_testpmd.h" +#endif static struct cmdline *testpmd_cl;
@@ -17803,6 +17806,73 @@ cmdline_parse_inst_t cmd_show_port_flow_transfer_proxy = { } }; +/* *** 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 , + }, +}; +/* ******************************************************************************** */ /* list of instructions */
@@ -18089,6 +18159,10 @@ cmdline_parse_ctx_t main_ctx[] = { (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, + (cmdline_parse_inst_t *)&cmd_rxq_lwm, +#ifdef RTE_NET_MLX5 + (cmdline_parse_inst_t *)&mlx5_test_cmd_port_host_shaper, +#endif NULL, };
app/test-pmd/config.c +23 -0
@@ -6342,3 +6342,26 @@ show_mcast_macs(portid_t port_id)printf (" %s\n" , buf); } } + +int +set_rxq_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (lwm >99 ) +return -EINVAL ; + ret =rte_eth_rx_lwm_set (port_id, queue_idx, lwm); + +if (ret) +return ret; +/* Save the input lwm. */ + ports[port_id].rx_conf[queue_idx].lwm = lwm; +return 0 ; +} +
app/test-pmd/meson.build +4 -0
@@ -73,3 +73,7 @@ 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' + sources += files('../../drivers/net/mlx5/mlx5_testpmd.c') +endif
app/test-pmd/testpmd.c +24 -0
@@ -66,6 +66,9 @@#ifdef RTE_EXEC_ENV_WINDOWS #include <process.h> #endif +#ifdef RTE_NET_MLX5 +#include "mlx5_testpmd.h" +#endif #include "testpmd.h"
@@ -417,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_LWM] = "rxq limit reached", [RTE_ETH_EVENT_MAX] = NULL, };
@@ -3551,6 +3555,10 @@ static int eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t lwm; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);
@@ -3582,6 +3590,22 @@ 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_LWM : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ; +/* LWM query API rewinds rxq_id, no need to check max rxq num. */ +for (rxq_id =0 ; ; rxq_id++) { + ret =rte_eth_rx_lwm_query (port_id, &rxq_id, &lwm); +if (ret <=0 ) +break ; +printf ("Received LWM event, port:%d rxq_id:%d\n" , + port_id, rxq_id); +#ifdef RTE_NET_MLX5 +mlx5_test_lwm_event_handler (port_id, rxq_id); +#endif + } +break ;default :break ; }
app/test-pmd/testpmd.h +1 -0
@@ -1163,6 +1163,7 @@ 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_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm); extern int flow_parse(const char *src, void *result, unsigned int size, struct rte_flow_attr **attr,
doc/guides/nics/mlx5.rst +46 -0
49 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.c new file +184 -0
184 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +27 -0
@@ -0,0 +1,27 @@ +/* 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_LWM 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_lwm_event_handler (uint16_t port_id,uint16_t rxq_id); + +extern cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper; +#endif
Signature · 1 line
2.27.0
v3 cover introduce per-queue limit watermark and host shaper
In reply to Spike DuLWM(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.
Add new libethdev API to set LWM, add rte event RTE_ETH_EVENT_RXQ_LIMIT_REACHED to handle LWM 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 LWM event handler in mlx5 PMD directory by adding a new file mlx5_test.c. Only add minimal code in testpmd to invoke interfaces from mlx5_test.c.
Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command
app/test-pmd/cmdline.c | 74 +++++ app/test-pmd/config.c | 21 ++ app/test-pmd/meson.build | 4 + app/test-pmd/testpmd.c | 24 ++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 84 ++++++ 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/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 | 292 +++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 13 + drivers/net/mlx5/mlx5_testpmd.c | 184 ++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 27 ++ 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 +-- lib/ethdev/ethdev_driver.h | 22 ++ lib/ethdev/rte_ethdev.c | 52 ++++ lib/ethdev/rte_ethdev.h | 71 +++++ lib/ethdev/version.map | 2 + 33 files changed, 1299 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
2.27.0
PATCH v3 1/7 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@ mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_priv *rxq, int on)* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@ mlx5_devx_modify_rq(struct mlx5_rxq_priv *rxq, uint8_t type)case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ mlx5_devx_modify_rq(struct mlx5_rxq_priv *rxq, uint8_t type) rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@ int mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx);int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
2.27.0
PATCH v3 2/7 common/mlx5: share interrupt management
In reply to Spike DuThere 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
@@ -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 @@ mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *pmd_mr)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
@@ -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 @@ __rte_internalint 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
@@ -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
@@ -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 @@ void *mlx5_os_umem_reg(void *ctx, void *addr, size_t size, uint32_t access);__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
@@ -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
@@ -741,11 +741,8 @@ mlx5_txpp_interrupt_handler(void *cb_arg)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 @@ mlx5_txpp_start_service(struct mlx5_dev_ctx_shared *sh) 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
@@ -140,28 +140,6 @@ mlx5_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)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
2.27.0
PATCH v3 3/7 ethdev: introduce Rx queue based limit watermark
In reply to Spike DuLWM (limit watermark) describes the fullness of a Rx queue. If the Rx queue fullness is above LWM, the device will trigger the event RTE_ETH_EVENT_RX_LWM.
LWM is defined as a percentage of Rx queue size with valid value of [0,99].
Setting LWM to 0 means disable it, which is the default. Add LWM's configuration and query driver callbacks in eth_dev_ops.
--- lib/ethdev/ethdev_driver.h | 22 ++++++++++++ lib/ethdev/rte_ethdev.c | 52 ++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 71 ++++++++++++++++++++++++++++++++++++++ lib/ethdev/version.map | 2 ++ 4 files changed, 147 insertions(+)
lib/ethdev/ethdev_driver.h +22 -0
@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue limit watermark. +* @see rte_eth_rx_lwm_set() +*/ +typedef int (*eth_rx_queue_lwm_set_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t lwm); + +/** +* @internal Query queue limit watermark event. +* @see rte_eth_rx_lwm_query() +*/ + +typedef int (*eth_rx_queue_lwm_query_t )(struct rte_eth_dev *dev, +uint16_t *rx_queue_id, +uint8_t *lwm); +/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,
@@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t priority_flow_ctrl_queue_config; +/** Set Rx queue limit watermark. */ +eth_rx_queue_lwm_set_t rx_queue_lwm_set; +/** Query Rx queue limit watermark event. */ +eth_rx_queue_lwm_query_t rx_queue_lwm_query; +/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set;/** Set Unicast hash bitmap */
lib/ethdev/rte_ethdev.c +52 -0
58 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
@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update; + rte_eth_rx_lwm_set; + rte_eth_rx_lwm_query; }; INTERNAL {
Signature · 1 line
2.27.0
PATCH v3 4/7 net/mlx5: add LWM event handling support
In reply to Spike DuWhen 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
@@ -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>
@@ -1524,6 +1526,69 @@ mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn,return NULL ; } +/** +* 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 @@ mlx5_free_shared_dev_ctx(struct mlx5_dev_ctx_shared *sh)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
@@ -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_net_remove(struct mlx5_common_device *cdev);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
@@ -1187,3 +1187,36 @@ mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused) {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_LWM ,NULL ); +}
drivers/net/mlx5/mlx5_rx.h +7 -0
@@ -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 @@ mlx5_is_external_rxq(struct rte_eth_dev *dev, uint16_t queue_idx) 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
2.27.0
PATCH v3 5/7 net/mlx5: support Rx queue based limit watermark
In reply to Spike DuAdd mlx5 specific LWM(limit watermark) configuration and query handler. 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 | 156 +++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 5 + 6 files changed, 177 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
@@ -93,6 +93,7 @@ Features - Connection tracking. - Sub-Function representors. - Sub-Function. +- Rx queue LWM (Limit WaterMark) configuration. Limitations
@@ -520,6 +521,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 ----------
@@ -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 + +LWM introduction +---------------- + +LWM (Limit WaterMark) is a per Rx queue attribute, it should be configured as +a percentage of the Rx queue size. +When Rx queue fullness is above LWM, an event is sent to PMD. +
doc/guides/rel_notes/release_22_07.rst +1 -0
@@ -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 LWM(Limit WaterMark) support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/mlx5_prm.h +1 -0
@@ -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
@@ -2071,6 +2071,8 @@ const struct eth_dev_ops mlx5_dev_ops = { .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_lwm_set = mlx5_rx_queue_lwm_set, + .rx_queue_lwm_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 +156 -0
195 lines not on this page · raw message
drivers/net/mlx5/mlx5_rx.h +5 -0
@@ -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
2.27.0
PATCH v3 6/7 net/mlx5: add private API to config host port shaper
In reply to Spike DuHost 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 | 26 +++++++ 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 | 103 +++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 30 +++++++ drivers/net/mlx5/version.map | 2 + 8 files changed, 202 insertions(+)
doc/guides/nics/mlx5.rst +26 -0
@@ -94,6 +94,7 @@ Features - Sub-Function representors. - Sub-Function. - Rx queue LWM (Limit WaterMark) 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_LWM_TRIGGERED flag set, + only rate 0 and 100Mbps are supported. + Statistics ----------
@@ -1692,3 +1699,22 @@ LWM (Limit WaterMark) is a per Rx queue attribute, it should be configured as a percentage of the Rx queue size. When Rx queue fullness is above LWM, 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 +LWM event trigger. In immediate mode, the rate limit is configured immediately +to host shaper. When deferring to LWM trigger, the shaper is not set until an +LWM 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 LMW event, which allows +throttling host traffic on LWM events at minimum latency, preventing excess +drops in the Rx queue. +
doc/guides/rel_notes/release_22_07.rst +1 -0
@@ -90,6 +90,7 @@ New Features * Added support for MTU on Windows. * Added matching and RSS on IPsec ESP. * Added Rx queue LWM(Limit WaterMark) support. + * Added host shaper support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/linux/meson.build +13 -0
@@ -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
@@ -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
@@ -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 +103 -0
112 lines not on this page · raw message
drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
@@ -109,6 +109,36 @@ __rte_experimentalint 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 +* 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 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
@@ -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
2.27.0
PATCH v3 7/7 app/testpmd: add LWM and Host Shaper command
In reply to Spike DuAdd command line options to support LWM per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> lwm <lwm_num>
mlx5 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> mlx5 set port 1 host_shaper lwm_triggered 1 rate 0
To disable lwm_triggered and current host shaper on port 1:
testpmd> mlx5 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> mlx5 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 | 74 +++++++++++++ app/test-pmd/config.c | 21 ++++ app/test-pmd/meson.build | 4 + app/test-pmd/testpmd.c | 24 +++++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 46 ++++++++ drivers/net/mlx5/mlx5_testpmd.c | 184 ++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 27 +++++ 8 files changed, 381 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/cmdline.c +74 -0
@@ -67,6 +67,9 @@#include "cmdline_mtr.h" #include "cmdline_tm.h" #include "bpf_cmd.h" +#ifdef RTE_NET_MLX5 +#include "mlx5_testpmd.h" +#endif static struct cmdline *testpmd_cl;
@@ -17804,6 +17807,73 @@ cmdline_parse_inst_t cmd_show_port_flow_transfer_proxy = { } }; +/* *** 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 , + }, +}; +/* ******************************************************************************** */ /* list of instructions */
@@ -18091,6 +18161,10 @@ cmdline_parse_ctx_t main_ctx[] = { (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, + (cmdline_parse_inst_t *)&cmd_rxq_lwm, +#ifdef RTE_NET_MLX5 + (cmdline_parse_inst_t *)&mlx5_test_cmd_port_host_shaper, +#endif NULL, };
app/test-pmd/config.c +21 -0
@@ -6342,3 +6342,24 @@ show_mcast_macs(portid_t port_id)printf (" %s\n" , buf); } } + +int +set_rxq_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (lwm >99 ) +return -EINVAL ; + ret =rte_eth_rx_lwm_set (port_id, queue_idx, lwm); + +if (ret) +return ret; +return 0 ; +} +
app/test-pmd/meson.build +4 -0
@@ -73,3 +73,7 @@ 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' + sources += files('../../drivers/net/mlx5/mlx5_testpmd.c') +endif
app/test-pmd/testpmd.c +24 -0
@@ -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"
@@ -420,6 +423,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_LWM] = "rxq limit reached", [RTE_ETH_EVENT_MAX] = NULL, };
@@ -3616,6 +3620,10 @@ static int eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t lwm; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);
@@ -3647,6 +3655,22 @@ 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_LWM : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ; +/* LWM query API rewinds rxq_id, no need to check max rxq num. */ +for (rxq_id =0 ; ; rxq_id++) { + ret =rte_eth_rx_lwm_query (port_id, &rxq_id, &lwm); +if (ret <=0 ) +break ; +printf ("Received LWM event, port:%d rxq_id:%d\n" , + port_id, rxq_id); +#ifdef RTE_NET_MLX5 +mlx5_test_lwm_event_handler (port_id, rxq_id); +#endif + } +break ;default :break ; }
app/test-pmd/testpmd.h +1 -0
@@ -1166,6 +1166,7 @@ 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_lwm (portid_t port_id,uint16_t queue_idx,uint16_t lwm); extern int flow_parse(const char *src, void *result, unsigned int size, struct rte_flow_attr **attr,
doc/guides/nics/mlx5.rst +46 -0
49 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.c new file +184 -0
184 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +27 -0
@@ -0,0 +1,27 @@ +/* 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_LWM 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_lwm_event_handler (uint16_t port_id,uint16_t rxq_id); + +extern cmdline_parse_inst_t mlx5_test_cmd_port_host_shaper; +#endif
Signature · 1 line
2.27.0
Re: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
In reply to Spike Du+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 57 lines
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.Add new libethdev API to set LWM, add rte event
RTE_ETH_EVENT_RXQ_LIMIT_REACHEDto handle LWM 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 LWM event handler in mlx5 PMD directory by adding a new file
mlx5_test.c. Only add minimal code in testpmd to invoke interfaces frommlx5_test.c.Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper commandapp/test-pmd/cmdline.c | 74 +++++ app/test-pmd/config.c | 21 ++ app/test-pmd/meson.build | 4 + app/test-pmd/testpmd.c | 24 ++ app/test-pmd/testpmd.h | 1 + doc/guides/nics/mlx5.rst | 84 ++++++ 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/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 | 292 +++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 13 + drivers/net/mlx5/mlx5_testpmd.c | 184 ++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 27 ++ 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 +-- lib/ethdev/ethdev_driver.h | 22 ++ lib/ethdev/rte_ethdev.c | 52 ++++ lib/ethdev/rte_ethdev.h | 71 +++++ lib/ethdev/version.map | 2 + 33 files changed, 1299 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 10 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk application.
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a host
port.
Please ignore this comment, it is not important, but I had to get it out of my system: I assume that the "LWM" name is from the NIC datasheet; otherwise I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Quoted 1 line
Quoted 1 line
The shaper limits the rate of traffic from host port to wire port.
From host to wire? It is RX, so you must mean from wire to host.
Quoted 5 lines
Quoted 1 line
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives LWM event.
Quoted 2 lines
These two features can combine to control traffic from host port to
wire port.
Again, you mean from wire to host?
Quoted 4 lines
Quoted 1 line
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.
You delay while RX queue gets drained by some other threads, I assume.
Surely, the excess packets must be dropped somewhere, e.g. by the shaper?
Quoted 3 lines
Quoted 2 lines
Add new libethdev API to set LWM, add rte event
RTE_ETH_EVENT_RXQ_LIMIT_REACHEDto handle LWM event.
Makes sense to make it public; could be usable for other purposes, similar to interrupt coalescing, as mentioned by Stephen.
Quoted 3 lines
Quoted 1 line
For host shaper,
because it doesn't align to existing DPDK framework and is specific to Nvidia NIC, use PMD private API.
Makes sense to keep it private.
Quoted 15 lines
Quoted 2 lines
For integration with testpmd, put the private cmdline function and
LWM event handler in mlx5 PMD directory by adding a new file
mlx5_test.c. Only add minimal code in testpmd to invoke interfaces frommlx5_test.c.Quoted 10 lines
Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command
Re: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
24/05/2022 21:00, Morten Brørup:
Quoted 6 lines
From: Thomas Monjalon [mailto:[email protected]]
Quoted 3 lines
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk application.
Please ignore this comment, it is not important, but I had to get it out of my system: I assume that the "LWM" name is from the NIC datasheet; otherwise I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Yes it is a threshold, and yes it is often called a watermark. I think we can get more ideas and votes about the naming. Please let's conclude on a short name which can be inserted easily in function names.
Re: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 4 lines · Thomas Monjalon
24/05/2022 21:00, Morten Brørup:
Quoted 3 lines
From: Thomas Monjalon [mailto:[email protected]]
Quoted 2 lines
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
fullness reach the LWM limit, HW sends an event to dpdk application.
Please ignore this comment, it is not important, but I had to get it out of my system: I assume that the "LWM" name is from the NIC datasheet; otherwise I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Yes it is a threshold, and yes it is often called a watermark. I think we can get more ideas and votes about the naming. Please let's conclude on a short name which can be inserted easily in function names.
As I understand it is an Rx queue fill (level) threshold. "fill_thresh" or "flt" if the first one is too long.
RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
In reply to Morten BrørupQuoted 35 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 3:00 AM
To: NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Spike Du <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaperExternal email: Use caution opening links or attachments
Quoted 10 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk application.
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a host
port.
Please ignore this comment, it is not important, but I had to get it out of my
system: I assume that the "LWM" name is from the NIC datasheet; otherwise I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Quoted 3 lines
Quoted 1 line
Quoted 1 line
The shaper limits the rate of traffic from host port to wire port.
From host to wire? It is RX, so you must mean from wire to host.
The host shaper is quite private to Nvidia's BlueField 2 NIC. The NIC is inserted In a server which we call it host-system, and the NIC has an embedded Arm-system Which does the forwarding.
The traffic flows from host-system to wire like this:
Host-system generates traffic, send it to Arm-system, Arm sends it to physical/wire port. So the RX happens between host-system and Arm-system, and the traffic is host to wire. The shaper also works in a special way: you configure it on Arm-system, but it takes effect On host-sysmem's TX side.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives LWM event.
Quoted 2 lines
These two features can combine to control traffic from host port to
wire port.
Again, you mean from wire to host?
Pls see above.
Quoted 7 lines
Quoted 5 lines
Quoted 2 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.
You delay while RX queue gets drained by some other threads, I assume.
The PMD thread drains the Rx queue, the PMD receiving as normal, as the PMD Implementation uses rte interrupt thread to handle LWM event.
Quoted 31 lines
Surely, the excess packets must be dropped somewhere, e.g. by the shaper?
Quoted 3 lines
Quoted 2 lines
Add new libethdev API to set LWM, add rte event
RTE_ETH_EVENT_RXQ_LIMIT_REACHEDto handle LWM event.Makes sense to make it public; could be usable for other purposes, similar to interrupt coalescing, as mentioned by Stephen.
Quoted 3 lines
Quoted 1 line
For host shaper,
because it doesn't align to existing DPDK framework and is specific to Nvidia NIC, use PMD private API.
Makes sense to keep it private.
Quoted 15 lines
Quoted 2 lines
For integration with testpmd, put the private cmdline function and
LWM event handler in mlx5 PMD directory by adding a new file
mlx5_test.c. Only add minimal code in testpmd to invoke interfaces frommlx5_test.c.Quoted 10 lines
Spike Du (7):
net/mlx5: add LWM support for Rxq common/mlx5: share interrupt management
ethdev: introduce Rx queue based limit watermark net/mlx5: add LWM event handling support net/mlx5: support Rx queue based limit watermark net/mlx5: add private API to config host port shaper app/testpmd: add LWM and Host Shaper command
RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 66 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.15Quoted 11 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 3:00 AMQuoted 8 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk
application.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a
host
Quoted 3 lines
Quoted 1 line
port.
Please ignore this comment, it is not important, but I had to get it
out of my
Quoted 1 line
system: I assume that the "LWM" name is from the NIC datasheet;
otherwise
Quoted 5 lines
I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Quoted 1 line
Quoted 1 line
The shaper limits the rate of traffic from host port to wire
port.
Quoted 2 lines
From host to wire? It is RX, so you must mean from wire to host.
The host shaper is quite private to Nvidia's BlueField 2 NIC. The NIC is inserted
In a server which we call it host-system, and the NIC has an embedded Arm-system
Which does the forwarding.
The traffic flows from host-system to wire like this:
Host-system generates traffic, send it to Arm-system, Arm sends it to physical/wire port.
So the RX happens between host-system and Arm-system, and the traffic is host to wire.
The shaper also works in a special way: you configure it on Arm-system, but it takes effect
On host-sysmem's TX side.Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives LWM
event.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
These two features can combine to control traffic from host port
to
Quoted 3 lines
Quoted 1 line
wire port.
Again, you mean from wire to host?
Pls see above.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The work flow is configure LWM to RX queue and enable lwm-
triggered
Quoted 1 line
Quoted 1 line
flag in host shaper, after receiving LWM event, delay a while until
RX
Quoted 1 line
Quoted 1 line
queue is empty , then disable the shaper. We recycle this work flow
to
Quoted 9 lines
Quoted 3 lines
Quoted 1 line
reduce RX queue drops.
You delay while RX queue gets drained by some other threads, I
assume.
The PMD thread drains the Rx queue, the PMD receiving as normal, as the PMD
Implementation uses rte interrupt thread to handle LWM event.
Thank you for the explanation, Spike. It really clarifies a lot!
If this patch is intended for DPDK running on the host-system, then the LWM attribute is associated with a TX queue, not an RX queue. The packets are egressing from the host-system, so TX from the host-system's perspective.
Otherwise, if this patch is for DPDK running on the embedded ARM-system, it should be highlighted somewhere.
Quoted 3 lines
Quoted 2 lines
Surely, the excess packets must be dropped somewhere, e.g. by the
shaper?
I guess the shaper doesn't have to drop any packets, but the host-system will simply be unable to put more packets into the queue if it runs full.
RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 92 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 9:40 PM
To: Spike Du <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>
Cc: Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; [email protected]; Raslan Darawsheh <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaperExternal email: Use caution opening links or attachments
Quoted 64 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.15Quoted 11 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 3:00 AMQuoted 8 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk
application.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a
host
Quoted 3 lines
Quoted 1 line
port.
Please ignore this comment, it is not important, but I had to get it
out of my
Quoted 1 line
system: I assume that the "LWM" name is from the NIC datasheet;
otherwise
Quoted 5 lines
I would probably prefer something with "threshold"... LWM is easily confused with "low water mark", which is the opposite of what the LWM does. Names are always open for discussion, so I won't object to it.
Quoted 1 line
Quoted 1 line
The shaper limits the rate of traffic from host port to wire
port.
Quoted 2 lines
From host to wire? It is RX, so you must mean from wire to host.
The host shaper is quite private to Nvidia's BlueField 2 NIC. The NIC is inserted In a server which we call it host-system, and the NIC has an embedded Arm-system Which does the forwarding.
The traffic flows from host-system to wire like this:
Host-system generates traffic, send it to Arm-system, Arm sends it to physical/wire port.
So the RX happens between host-system and Arm-system, and the traffic is host to wire.
The shaper also works in a special way: you configure it on Arm-system, but it takes effect On host-sysmem's TX side.Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives LWM
event.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
These two features can combine to control traffic from host port
to
Quoted 3 lines
Quoted 1 line
wire port.
Again, you mean from wire to host?
Pls see above.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The work flow is configure LWM to RX queue and enable lwm-
triggered
Quoted 2 lines
Quoted 2 lines
flag in host shaper, after receiving LWM event, delay a while until
RX
Quoted 2 lines
Quoted 2 lines
queue is empty , then disable the shaper. We recycle this work flow
Quoted 9 lines
to
Quoted 3 lines
Quoted 1 line
reduce RX queue drops.
You delay while RX queue gets drained by some other threads, I
assume.
The PMD thread drains the Rx queue, the PMD receiving as normal, as the PMD Implementation uses rte interrupt thread to handle LWM event.
Quoted 8 lines
Thank you for the explanation, Spike. It really clarifies a lot!
If this patch is intended for DPDK running on the host-system, then the LWM attribute is associated with a TX queue, not an RX queue. The packets are egressing from the host-system, so TX from the host-system's perspective.
Otherwise, if this patch is for DPDK running on the embedded ARM-system, it should be highlighted somewhere.
The host-shaper patch is running on ARM-system, I think in that patch I have some explanation in mlx5.rst. The LWM patch is common and should work on any Rx queue(right now mlx5 doesn't support Hairpin Rx queue and shared Rx queue). On ARM-system, we can use it to monitor traffic from host(representor port) or from wire(physical port). LWM can also work on host-system if there is DPDK running, for example it can monitor traffic from Arm-system to host-system.
Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
Surely, the excess packets must be dropped somewhere, e.g. by the
shaper?
I guess the shaper doesn't have to drop any packets, but the host-system will simply be unable to put more packets into the queue if it runs full.
When LWM event happens, the host-shaper throttles traffic from host-system to Arm-system. Yes, the shaper doesn't drop pkts. Normally the shaper is small and if PMD thread on Arm keeps working, Rx queue is dropless.
But if PMD thread doesn't receive fast enough, or even with a small shaper but host-system is sending some burst, Rx queue may still drop on Arm. Anyway even sometimes drop still happens, the cooperation of host-shaper and LWM greatly reduce the Rx drop on Arm.
RE: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 94 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.59Quoted 29 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 9:40 PMQuoted 26 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.15Quoted 11 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 3:00 AMQuoted 8 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk
application.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a
host
Quoted 4 lines
Quoted 4 lines
port.
Quoted 1 line
The shaper limits the rate of traffic from host port to wire
port.
Quoted 2 lines
From host to wire? It is RX, so you must mean from wire to host.
The host shaper is quite private to Nvidia's BlueField 2 NIC. The
NIC
Quoted 1 line
Quoted 1 line
is inserted In a server which we call it host-system, and the NIC
has
Quoted 3 lines
Quoted 3 lines
an embedded Arm-system Which does the forwarding.
The traffic flows from host-system to wire like this:
Host-system generates traffic, send it to Arm-system, Arm sends itto
Quoted 2 lines
Quoted 2 lines
physical/wire port.
So the RX happens between host-system and Arm-system, and thetraffic
Quoted 7 lines
Quoted 7 lines
is host to wire.
The shaper also works in a special way: you configure it on Arm-system, but it takes effect On host-sysmem's TX side.Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives
LWM
Quoted 3 lines
Quoted 3 lines
event.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
These two features can combine to control traffic from host
port
Quoted 15 lines
Quoted 15 lines
to
Quoted 3 lines
Quoted 1 line
wire port.
Again, you mean from wire to host?
Pls see above.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The work flow is configure LWM to RX queue and enable lwm-
triggered
Quoted 2 lines
Quoted 2 lines
flag in host shaper, after receiving LWM event, delay a while until
RX
Quoted 2 lines
Quoted 2 lines
queue is empty , then disable the shaper. We recycle this work flow
Quoted 7 lines
Quoted 7 lines
to
Quoted 3 lines
Quoted 1 line
reduce RX queue drops.
You delay while RX queue gets drained by some other threads, I
assume.
The PMD thread drains the Rx queue, the PMD receiving as normal,
as
Quoted 1 line
Quoted 1 line
the PMD Implementation uses rte interrupt thread to handle LWM
event.
Quoted 5 lines
Quoted 1 line
Thank you for the explanation, Spike. It really clarifies a lot!
If this patch is intended for DPDK running on the host-system, then
the LWM
Quoted 1 line
attribute is associated with a TX queue, not an RX queue. The packets
are
Quoted 1 line
egressing from the host-system, so TX from the host-system's
perspective.
Quoted 2 lines
Otherwise, if this patch is for DPDK running on the embedded ARM-
system,
Quoted 1 line
it should be highlighted somewhere.
Quoted 8 lines
The host-shaper patch is running on ARM-system, I think in that patch I have some explanation in
mlx5.rst.
The LWM patch is common and should work on any Rx queue(right now mlx5 doesn't support Hairpin Rx queue and shared Rx queue).
On ARM-system, we can use it to monitor traffic from host(representor port) or from wire(physical port).
LWM can also work on host-system if there is DPDK running, for example it can monitor traffic from Arm-system to host-system.
OK. Then I get it! I was reading the patch description wearing my host-system glasses, and thus got very confused. :-)
Quoted 11 lines
Quoted 7 lines
Quoted 5 lines
Quoted 4 lines
Surely, the excess packets must be dropped somewhere, e.g. by the
shaper?
I guess the shaper doesn't have to drop any packets, but the host-
system will
Quoted 2 lines
simply be unable to put more packets into the queue if it runs full.
Quoted 9 lines
When LWM event happens, the host-shaper throttles traffic from host- system to Arm-system. Yes, the shaper doesn't drop pkts. Normally the shaper is small and if PMD thread on Arm keeps working, Rx queue is dropless.
But if PMD thread doesn't receive fast enough, or even with a small shaper but host-system is sending some burst, Rx queue may still drop on Arm.
Anyway even sometimes drop still happens, the cooperation of host- shaper and LWM greatly reduce the Rx drop on Arm.
Thanks for elaborating. And yes, shapers are excellent for many scenarios.
Re: [PATCH v3 0/7] introduce per-queue limit watermark and host shaper
Quoted 103 lines · Morten Brørup
Quoted 94 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.59Quoted 29 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 9:40 PMQuoted 26 lines
From: Spike Du [mailto:[email protected]]
Sent: Wednesday, 25 May 2022 15.15Quoted 11 lines
From: Morten Brørup <[email protected]>
Sent: Wednesday, May 25, 2022 3:00 AMQuoted 8 lines
From: Thomas Monjalon [mailto:[email protected]]
Sent: Tuesday, 24 May 2022 17.59+Cc people involved in previous versions
24/05/2022 17:20, Spike Du:
Quoted 1 line
LWM(limit watermark) is per RX queue attribute, when RX queue
fullness reach the LWM limit, HW sends an event to dpdk
application.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Host shaper can configure shaper rate and lwm-triggered for a
host
Quoted 4 lines
Quoted 4 lines
port.
Quoted 1 line
The shaper limits the rate of traffic from host port to wire
port.
Quoted 2 lines
From host to wire? It is RX, so you must mean from wire to host.
The host shaper is quite private to Nvidia's BlueField 2 NIC. The
NIC
Quoted 1 line
Quoted 1 line
is inserted In a server which we call it host-system, and the NIC
has
Quoted 3 lines
Quoted 3 lines
an embedded Arm-system Which does the forwarding.
The traffic flows from host-system to wire like this:
Host-system generates traffic, send it to Arm-system, Arm sends itto
Quoted 2 lines
Quoted 2 lines
physical/wire port.
So the RX happens between host-system and Arm-system, and thetraffic
Quoted 7 lines
Quoted 7 lines
is host to wire.
The shaper also works in a special way: you configure it on Arm-system, but it takes effect On host-sysmem's TX side.Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
If lwm-triggered is enabled, a 100Mbps shaper is enabled
automatically when one of the host port's Rx queues receives
LWM
Quoted 3 lines
Quoted 3 lines
event.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
These two features can combine to control traffic from host
port
Quoted 15 lines
Quoted 15 lines
to
Quoted 3 lines
Quoted 1 line
wire port.
Again, you mean from wire to host?
Pls see above.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The work flow is configure LWM to RX queue and enable lwm-
triggered
Quoted 2 lines
Quoted 2 lines
flag in host shaper, after receiving LWM event, delay a while until
RX
Quoted 2 lines
Quoted 2 lines
queue is empty , then disable the shaper. We recycle this work flow
Quoted 7 lines
Quoted 7 lines
to
Quoted 3 lines
Quoted 1 line
reduce RX queue drops.
You delay while RX queue gets drained by some other threads, I
assume.
The PMD thread drains the Rx queue, the PMD receiving as normal,
as
Quoted 1 line
Quoted 1 line
the PMD Implementation uses rte interrupt thread to handle LWM
event.
Quoted 5 lines
Quoted 1 line
Thank you for the explanation, Spike. It really clarifies a lot!
If this patch is intended for DPDK running on the host-system, then
the LWM
Quoted 1 line
attribute is associated with a TX queue, not an RX queue. The packets
are
Quoted 1 line
egressing from the host-system, so TX from the host-system's
perspective.
Quoted 2 lines
Otherwise, if this patch is for DPDK running on the embedded ARM-
system,
Quoted 1 line
it should be highlighted somewhere.
Quoted 8 lines
The host-shaper patch is running on ARM-system, I think in that patch I have some explanation in
mlx5.rst.
The LWM patch is common and should work on any Rx queue(right now mlx5 doesn't support Hairpin Rx queue and shared Rx queue).
On ARM-system, we can use it to monitor traffic from host(representor port) or from wire(physical port).
LWM can also work on host-system if there is DPDK running, for example it can monitor traffic from Arm-system to host-system.
Quoted 1 line
OK. Then I get it! I was reading the patch description wearing my host-system glasses, and thus got very confused. :-)
The description in cover letter is very misleading for me as well. It is not a problem right now after long detailed explanations. Hopefully there is no such problem in suggested ethdev documentation. I'll reread it carefully before applying when time comes.
Quoted 24 lines
Quoted 12 lines
Quoted 8 lines
Quoted 6 lines
Quoted 5 lines
Surely, the excess packets must be dropped somewhere, e.g. by the
shaper?
I guess the shaper doesn't have to drop any packets, but the host-
system will
Quoted 2 lines
simply be unable to put more packets into the queue if it runs full.
Quoted 9 lines
When LWM event happens, the host-shaper throttles traffic from host- system to Arm-system. Yes, the shaper doesn't drop pkts. Normally the shaper is small and if PMD thread on Arm keeps working, Rx queue is dropless.
But if PMD thread doesn't receive fast enough, or even with a small shaper but host-system is sending some burst, Rx queue may still drop on Arm.
Anyway even sometimes drop still happens, the cooperation of host- shaper and LWM greatly reduce the Rx drop on Arm.Thanks for elaborating. And yes, shapers are excellent for many scenarios.
v4 cover introduce per-queue fill threshold and host shaper
In reply to Spike DuFill threshold is per RX queue attribute, when RX queue fullness reach the fill threshold limit, HW sends an event to application. Host shaper can configure shaper rate and fill_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 fill_thresh-triggered is enabled, a 100Mbps shaper is enabled automatically when one of the host port's Rx queues receives fill 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 fill threshold to RX queue and enable fill_thresh-triggered flag in host shaper, after receiving fill 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 fill threshold, add rte event RTE_ETH_EVENT_RX_FILL_THRESH to handle fill 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 fill 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 fill threshold net/mlx5: add LWM event handling support net/mlx5: support Rx queue based fill threshold net/mlx5: add private API to config host port shaper app/testpmd: add Host Shaper command
app/test-pmd/cmdline.c | 68 +++++++ app/test-pmd/config.c | 21 ++ app/test-pmd/testpmd.c | 24 +++ app/test-pmd/testpmd.h | 2 + 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 | 4 + 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 | 292 +++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 13 ++ drivers/net/mlx5/mlx5_testpmd.c | 201 ++++++++++++++++++ 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 +---- lib/ethdev/ethdev_driver.h | 22 ++ lib/ethdev/rte_ethdev.c | 52 +++++ lib/ethdev/rte_ethdev.h | 72 +++++++ lib/ethdev/version.map | 2 + 33 files changed, 1320 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v4 1/7 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
PATCH v4 2/7 common/mlx5: share interrupt management
In reply to Spike DuThere 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Re: [PATCH v4 2/7] common/mlx5: share interrupt management
Quoted 5 lines · Spike Du
There are many duplicate code of creating and initializing
rte_intr_handle. Add a newmlx5_osAPI to do this, replace all PMD related code with this API.Signed-off-by Spike Du <[email protected]>
Quoted 14 lines
--- 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(-)
PATCH v4 3/7 ethdev: introduce Rx queue based fill threshold
In reply to Spike DuFill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event RTE_ETH_EVENT_RX_FILL_THRESH.
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks in eth_dev_ops. Add command line options to support fill_thresh per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> fill_thresh <fill_thresh_num>
- Example commands:
To configure fill_thresh as 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0 fill_thresh 30
To disable fill_thresh on port 1 rxq 0:
testpmd> set port 1 rxq 0 fill_thresh 0
--- app/test-pmd/cmdline.c | 68 +++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 21 ++++++++++++++ app/test-pmd/testpmd.c | 18 ++++++++++++ app/test-pmd/testpmd.h | 2 ++ lib/ethdev/ethdev_driver.h | 22 ++++++++++++++ lib/ethdev/rte_ethdev.c | 52 +++++++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++ lib/ethdev/version.map | 2 ++ 8 files changed, 257 insertions(+)
app/test-pmd/cmdline.c +68 -0
@@ -17823,6 +17823,73 @@ struct cmd_show_port_flow_transfer_proxy_result { } }; +/* *** SET FILL THRESHOLD FOR A RXQ OF A PORT *** */ +struct cmd_rxq_fill_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 fill_thresh; +uint16_t fill_thresh_num; +}; + +static void cmd_rxq_fill_thresh_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_rxq_fill_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->fill_thresh,"fill_thresh" ) ==0 )) + ret =set_rxq_fill_thresh (res->port_num, res->rxq_num, + res->fill_thresh_num); +if (ret <0 ) +printf ("rxq_fill_thresh_cmd error: (%s)\n" ,strerror (-ret)); + +} + +cmdline_parse_token_string_t cmd_rxq_fill_thresh_set = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + set,"set" ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_port = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port,"port" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_portnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port_num,RTE_UINT16 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_rxq = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq,"rxq" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_rxqnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq_num,RTE_UINT8 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_fill_thresh = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh,"fill_thresh" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_fill_threshnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh_num,RTE_UINT16 ); + +cmdline_parse_inst_t cmd_rxq_fill_thresh = { + .f = cmd_rxq_fill_thresh_parsed, + .data = (void *)0 , + .help_str ="set port <port_id> rxq <rxq_id> fill_thresh <fill_thresh_num>" +"Set fill_thresh for rxq on port_id" , + .tokens = { + (void *)&cmd_rxq_fill_thresh_set, + (void *)&cmd_rxq_fill_thresh_port, + (void *)&cmd_rxq_fill_thresh_portnum, + (void *)&cmd_rxq_fill_thresh_rxq, + (void *)&cmd_rxq_fill_thresh_rxqnum, + (void *)&cmd_rxq_fill_thresh_fill_thresh, + (void *)&cmd_rxq_fill_thresh_fill_threshnum, +NULL , + }, +}; +/* ******************************************************************************** */ /* list of instructions */
@@ -18110,6 +18177,7 @@ 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, + (cmdline_parse_inst_t *)&cmd_rxq_fill_thresh, NULL, };
app/test-pmd/config.c +21 -0
@@ -6342,3 +6342,24 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx,uint16_t fill_thresh) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (fill_thresh >99 ) +return -EINVAL ; + ret =rte_eth_rx_fill_thresh_set (port_id, queue_idx, fill_thresh); + +if (ret) +return ret; +return 0 ; +} +
app/test-pmd/testpmd.c +18 -0
@@ -420,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [RTE_ETH_EVENT_NEW] = "device probed", [RTE_ETH_EVENT_DESTROY] = "device released", [RTE_ETH_EVENT_FLOW_AGED] = "flow aged", + [RTE_ETH_EVENT_RX_FILL_THRESH] = "rxq fill threshold reached", [RTE_ETH_EVENT_MAX] = NULL, };
@@ -3616,6 +3617,10 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t fill_thresh; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);
@@ -3647,6 +3652,19 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RX_FILL_THRESH : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ; +/* fill_thresh query API rewinds rxq_id, no need to check max rxq num. */ +for (rxq_id =0 ; ; rxq_id++) { + ret =rte_eth_rx_fill_thresh_query (port_id, &rxq_id, &fill_thresh); +if (ret <=0 ) +break ; +printf ("Received fill_thresh event, port:%d rxq_id:%d\n" , + port_id, rxq_id); + } +break ;default :break ; }
app/test-pmd/testpmd.h +2 -0
@@ -1173,6 +1173,8 @@ 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); +int set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx, +uint16_t fill_thresh); extern int flow_parse(const char *src, void *result, unsigned int size, struct rte_flow_attr **attr,
lib/ethdev/ethdev_driver.h +22 -0
@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue fill threshold. +* @see rte_eth_rx_fill_thresh_set() +*/ +typedef int (*eth_rx_queue_fill_thresh_set_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t fill_thresh); + +/** +* @internal Query queue fill threshold event. +* @see rte_eth_rx_fill_thresh_query() +*/ + +typedef int (*eth_rx_queue_fill_thresh_query_t )(struct rte_eth_dev *dev, +uint16_t *rx_queue_id, +uint8_t *fill_thresh); +/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,
@@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t priority_flow_ctrl_queue_config; +/** Set Rx queue fill threshold. */ +eth_rx_queue_fill_thresh_set_t rx_queue_fill_thresh_set; +/** Query Rx queue fill threshold event. */ +eth_rx_queue_fill_thresh_query_t rx_queue_fill_thresh_query; +/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set;/** Set Unicast hash bitmap */
lib/ethdev/rte_ethdev.c +52 -0
58 lines not on this page · raw message
lib/ethdev/rte_ethdev.h +72 -0
90 lines not on this page · raw message
lib/ethdev/version.map +2 -0
@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update; + rte_eth_rx_fill_thresh_set; + rte_eth_rx_fill_thresh_query; }; INTERNAL {
Signature · 1 line
1.8.3.1
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
Quoted 406 lines · Spike Du
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>--- app/test-pmd/cmdline.c | 68 +++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 21 ++++++++++++++ app/test-pmd/testpmd.c | 18 ++++++++++++ app/test-pmd/testpmd.h | 2 ++ lib/ethdev/ethdev_driver.h | 22 ++++++++++++++ lib/ethdev/rte_ethdev.c | 52 +++++++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++ lib/ethdev/version.map | 2 ++ 8 files changed, 257 insertions(+)app/test-pmd/cmdline.c +68
-0@@ -17823,6 +17823,73 @@ struct cmd_show_port_flow_transfer_proxy_result { } }; +/* *** SET FILL THRESHOLD FOR A RXQ OF A PORT *** */ +struct cmd_rxq_fill_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 fill_thresh; +uint16_t fill_thresh_num; +}; + +static void cmd_rxq_fill_thresh_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_rxq_fill_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->fill_thresh,"fill_thresh" ) ==0 )) + ret =set_rxq_fill_thresh (res->port_num, res->rxq_num, + res->fill_thresh_num); +if (ret <0 ) +printf ("rxq_fill_thresh_cmd error: (%s)\n" ,strerror (-ret)); + +} + +cmdline_parse_token_string_t cmd_rxq_fill_thresh_set = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + set,"set" ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_port = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port,"port" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_portnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port_num,RTE_UINT16 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_rxq = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq,"rxq" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_rxqnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq_num,RTE_UINT8 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_fill_thresh = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh,"fill_thresh" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_fill_threshnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh_num,RTE_UINT16 ); + +cmdline_parse_inst_t cmd_rxq_fill_thresh = { + .f = cmd_rxq_fill_thresh_parsed, + .data = (void *)0 , + .help_str ="set port <port_id> rxq <rxq_id> fill_thresh <fill_thresh_num>" +"Set fill_thresh for rxq on port_id" , + .tokens = { + (void *)&cmd_rxq_fill_thresh_set, + (void *)&cmd_rxq_fill_thresh_port, + (void *)&cmd_rxq_fill_thresh_portnum, + (void *)&cmd_rxq_fill_thresh_rxq, + (void *)&cmd_rxq_fill_thresh_rxqnum, + (void *)&cmd_rxq_fill_thresh_fill_thresh, + (void *)&cmd_rxq_fill_thresh_fill_threshnum, +NULL , + }, +}; +/* ******************************************************************************** */ /* list of instructions */ @@ -18110,6 +18177,7 @@ 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, + (cmdline_parse_inst_t *)&cmd_rxq_fill_thresh, NULL, };app/test-pmd/config.c +21
-0@@ -6342,3 +6342,24 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx,uint16_t fill_thresh) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (fill_thresh >99 ) +return -EINVAL ; + ret =rte_eth_rx_fill_thresh_set (port_id, queue_idx, fill_thresh); + +if (ret) +return ret; +return 0 ; +} +app/test-pmd/testpmd.c +18
-0@@ -420,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [RTE_ETH_EVENT_NEW] = "device probed", [RTE_ETH_EVENT_DESTROY] = "device released", [RTE_ETH_EVENT_FLOW_AGED] = "flow aged", + [RTE_ETH_EVENT_RX_FILL_THRESH] = "rxq fill threshold reached", [RTE_ETH_EVENT_MAX] = NULL, };@@ -3616,6 +3617,10 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t fill_thresh; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);@@ -3647,6 +3652,19 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RX_FILL_THRESH : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ; +/* fill_thresh query API rewinds rxq_id, no need to check max rxq num. */ +for (rxq_id =0 ; ; rxq_id++) { + ret =rte_eth_rx_fill_thresh_query (port_id, &rxq_id, &fill_thresh); +if (ret <=0 ) +break ; +printf ("Received fill_thresh event, port:%d rxq_id:%d\n" , + port_id, rxq_id); + } +break ;default :break ; }app/test-pmd/testpmd.h +2
-0@@ -1173,6 +1173,8 @@ 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); +int set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx, +uint16_t fill_thresh); extern int flow_parse(const char *src, void *result, unsigned int size, struct rte_flow_attr **attr,lib/ethdev/ethdev_driver.h +22
-0@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue fill threshold. +* @see rte_eth_rx_fill_thresh_set() +*/ +typedef int (*eth_rx_queue_fill_thresh_set_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t fill_thresh); + +/** +* @internal Query queue fill threshold event. +* @see rte_eth_rx_fill_thresh_query() +*/ + +typedef int (*eth_rx_queue_fill_thresh_query_t )(struct rte_eth_dev *dev, +uint16_t *rx_queue_id, +uint8_t *fill_thresh); +/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,@@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t priority_flow_ctrl_queue_config; +/** Set Rx queue fill threshold. */ +eth_rx_queue_fill_thresh_set_t rx_queue_fill_thresh_set; +/** Query Rx queue fill threshold event. */ +eth_rx_queue_fill_thresh_query_t rx_queue_fill_thresh_query; +/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set;/** Set Unicast hash bitmap */ lib/ethdev/rte_ethdev.c +52
-0@@ -4424,6 +4424,58 @@ int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, queue_idx, tx_rate)); } +int rte_eth_rx_fill_thresh_set (uint16_t port_id,uint16_t queue_id, +uint8_t fill_thresh) +{ +struct rte_eth_dev *dev; +struct rte_eth_dev_info dev_info; +int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id > dev_info.max_rx_queues) { +RTE_ETHDEV_LOG (ERR , +"Set queue fill thresh: port %u: invalid queue ID=%u.\n" , + port_id, queue_id); +return -EINVAL ; + } + +if (fill_thresh >99 ) +return -EINVAL ; +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_fill_thresh_set, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_fill_thresh_set)(dev, + queue_id, fill_thresh)); +} + +int rte_eth_rx_fill_thresh_query (uint16_t port_id,uint16_t *queue_id, +uint8_t *fill_thresh) +{ +struct rte_eth_dev_info dev_info; +struct rte_eth_dev *dev; +int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id ==NULL ) +return -EINVAL ; +if (*queue_id >= dev_info.max_rx_queues) + *queue_id =0 ; + +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_fill_thresh_query, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_fill_thresh_query)(dev, + queue_id, fill_thresh)); +} +RTE_INIT (eth_dev_init_fp_ops) {uint32_t i;lib/ethdev/rte_ethdev.h +72
-0@@ -1931,6 +1931,14 @@ struct rte_eth_rxq_info {uint8_t queue_state;/**< one of RTE_ETH_QUEUE_STATE_*. */ uint16_t nb_desc;/**< configured number of RXDs. */ uint16_t rx_buf_size;/**< hardware receive buffer size. */ +/** +* Per-queue Rx fill threshold defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_FILL_THESH is triggered. +* Value 0 means threshold monitoring is disabled, no event is +* triggered. +*/ +uint8_t fill_thresh; } __rte_cache_min_aligned;/** @@ -3672,6 +3680,65 @@ int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,*/ int rte_eth_dev_set_vlan_pvid (uint16_t port_id,uint16_t pvid,int on); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Set Rx queue based fill threshold. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The index of the receive queue. +* @param fill_thresh +* The fill threshold percentage of Rx queue size which describes +* the fullness of Rx queue. If the Rx queue fullness is above it, +* the device will trigger the event RTE_ETH_EVENT_RX_FILL_THRESH. +* [1-99] to set a new fill thresold. +* 0 to disable thresold monitoring. +* +* @return +* - 0 if successful. +* - negative if failed. +*/ +__rte_experimental +int rte_eth_rx_fill_thresh_set(uint16_t port_id, uint16_t queue_id, +uint8_t fill_thresh); + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Query Rx queue based fill threshold event. +* The function queries all queues in the port circularly until one +* pending fill_thresh event is found or no pending fill_thresh event is found. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The API caller sets the starting Rx queue id in the pointer. +* If the queue_id is bigger than maximum queue id of the port, +* it's rewinded to 0 so that application can keep calling +* this function to handle all pending fill_thresh events in the queues +* with a simple increment between calls. +* If a Rx queue has pending fill_thresh event, the pointer is updated +* with this Rx queue id; otherwise this pointer's content is +* unchanged. +* @param fill_thresh +* The pointer to the fill threshold percentage of Rx queue. +* If Rx queue with pending fill_thresh event is found, the queue's fill_thresh +* percentage is stored in this pointer, otherwise the pointer's +* content is unchanged. +* +* @return +* - 1 if a Rx queue with pending fill_thresh event is found. +* - 0 if no Rx queue with pending fill_thresh event is found. +* - -EINVAL if queue_id is NULL. +*/ +__rte_experimental +int rte_eth_rx_fill_thresh_query(uint16_t port_id, uint16_t *queue_id, +uint8_t *fill_thresh); +typedef void (*buffer_tx_error_fn )(struct rte_mbuf **unsent,uint16_t count,void *userdata);@@ -3877,6 +3944,11 @@ enum rte_eth_event_type {RTE_ETH_EVENT_DESTROY ,/**< port is released */ RTE_ETH_EVENT_IPSEC ,/**< IPsec offload related event */ RTE_ETH_EVENT_FLOW_AGED ,/**< New aged-out flows is detected */ +/** +* Fill threshold value is exceeded in a queue. +* @see rte_eth_rx_fill_thresh_set() +*/ +RTE_ETH_EVENT_RX_FILL_THRESH , RTE_ETH_EVENT_MAX /**< max value of this enum */ };lib/ethdev/version.map +0
-0
lib/ethdev/version.map EXPERIMENTAL { · line 287
Quoted 3 lines
lib/ethdev/version.map +0
-0@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update;
Comment with # added in 22.XX
Quoted 5 lines
lib/ethdev/version.map +2
-0+ rte_eth_rx_fill_thresh_set; + rte_eth_rx_fill_thresh_query; }; INTERNAL {
Signature · 1 line
Regards, Ray K
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
In reply to Spike DuQuoted 3 lines · Spike Du
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.
Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx queue. If so, fill threashold should be a minimum fill level and below the level we should generate an event.
However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx descriptors could be used. Second, HW ring size could differ queue size specified in SW. Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.
Quoted 34 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>--- app/test-pmd/cmdline.c | 68 +++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 21 ++++++++++++++ app/test-pmd/testpmd.c | 18 ++++++++++++ app/test-pmd/testpmd.h | 2 ++ lib/ethdev/ethdev_driver.h | 22 ++++++++++++++ lib/ethdev/rte_ethdev.c | 52 +++++++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++ lib/ethdev/version.map | 2 ++ 8 files changed, 257 insertions(+)app/test-pmd/cmdline.c +0
-0@@ -17823,6 +17823,73 @@ struct cmd_show_port_flow_transfer_proxy_result { } };
app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17834
Quoted 10 lines
app/test-pmd/cmdline.c +9
-0+/* *** SET FILL THRESHOLD FOR A RXQ OF A PORT *** */ +struct cmd_rxq_fill_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 fill_thresh; +uint16_t fill_thresh_num;
uint8_t to be consistent with ethdev
Quoted 24 lines
app/test-pmd/cmdline.c +24
-0+}; + +static void cmd_rxq_fill_thresh_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_rxq_fill_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->fill_thresh,"fill_thresh" ) ==0 )) + ret =set_rxq_fill_thresh (res->port_num, res->rxq_num, + res->fill_thresh_num); +if (ret <0 ) +printf ("rxq_fill_thresh_cmd error: (%s)\n" ,strerror (-ret)); + +} + +cmdline_parse_token_string_t cmd_rxq_fill_thresh_set = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + set,"set" ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_port = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result,
app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17868
Quoted 10 lines
app/test-pmd/cmdline.c +10
-0+ port, "port"); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_portnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port_num,RTE_UINT16 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_rxq = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq,"rxq" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_rxqnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq_num,RTE_UINT8 );
RTE_UINT16 since it is an Rx queue ID
app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17874
Quoted 6 lines
app/test-pmd/cmdline.c +6
-0+cmdline_parse_token_string_t cmd_rxq_fill_thresh_fill_thresh = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh,"fill_thresh" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_fill_threshnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh_num,RTE_UINT16 );
RTE_UINT16 -> RTE_UINT8
Quoted 7 lines
app/test-pmd/cmdline.c +7
-0+ +cmdline_parse_inst_t cmd_rxq_fill_thresh = { + .f = cmd_rxq_fill_thresh_parsed, + .data = (void *)0 , + .help_str ="set port <port_id> rxq <rxq_id> fill_thresh <fill_thresh_num>" +"Set fill_thresh for rxq on port_id" , + .tokens = {
app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17891
Quoted 10 lines
app/test-pmd/cmdline.c +10
-0+ (void *)&cmd_rxq_fill_thresh_set, + (void *)&cmd_rxq_fill_thresh_port, + (void *)&cmd_rxq_fill_thresh_portnum, + (void *)&cmd_rxq_fill_thresh_rxq, + (void *)&cmd_rxq_fill_thresh_rxqnum, + (void *)&cmd_rxq_fill_thresh_fill_thresh, + (void *)&cmd_rxq_fill_thresh_fill_threshnum, + NULL, + }, +};
Please, add 'static' keyword to all above cmdline_parse_* variable.
Quoted 17 lines
app/test-pmd/cmdline.c +2
-0+/* ******************************************************************************** */ /* list of instructions */ @@ -18110,6 +18177,7 @@ 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, + (cmdline_parse_inst_t *)&cmd_rxq_fill_thresh, NULL, };app/test-pmd/config.c +0
-0
app/test-pmd/config.c struct igb_ring_desc_16_bytes { · line 6347
Quoted 6 lines
app/test-pmd/config.c +3
-0@@ -6342,3 +6342,24 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx,uint16_t fill_thresh)
uint8_t for fill_threash since the type is used in ethdev API
Quoted 4 lines
app/test-pmd/config.c +4
-0+{ +struct rte_eth_link link; +int ret; +
app/test-pmd/config.c struct igb_ring_desc_16_bytes { · line 6361
Quoted 10 lines
app/test-pmd/config.c +10
-0+if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (fill_thresh >99 ) +return -EINVAL ; + ret =rte_eth_rx_fill_thresh_set (port_id, queue_idx, fill_thresh); + +if (ret)
Please remove extra empty line above and compare with 0 explicitly.
Quoted 28 lines
app/test-pmd/config.c +4
-0+return ret; +return 0 ; +} +app/test-pmd/testpmd.c +5
-0@@ -420,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [RTE_ETH_EVENT_NEW] = "device probed", [RTE_ETH_EVENT_DESTROY] = "device released", [RTE_ETH_EVENT_FLOW_AGED] = "flow aged", + [RTE_ETH_EVENT_RX_FILL_THRESH] = "rxq fill threshold reached", [RTE_ETH_EVENT_MAX] = NULL, };@@ -3616,6 +3617,10 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t fill_thresh; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);
app/test-pmd/testpmd.c struct pmd_test_command { · line 3658
Quoted 7 lines
app/test-pmd/testpmd.c +4
-0@@ -3647,6 +3652,19 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RX_FILL_THRESH : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ;
What's the point to get device info above? It is unused as far as I can see.
Quoted 16 lines
app/test-pmd/testpmd.c +8
-0+/* fill_thresh query API rewinds rxq_id, no need to check max rxq num. */ +for (rxq_id =0 ; ; rxq_id++) { + ret =rte_eth_rx_fill_thresh_query (port_id, &rxq_id, &fill_thresh); +if (ret <=0 ) + break; > + printf("Received fill_thresh event, port:%d rxq_id:%d\n", + port_id, rxq_id); + } +break ;default :break ; }app/test-pmd/testpmd.h +0
-0
app/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue, · line 1176
Quoted 4 lines
app/test-pmd/testpmd.h +1
-0@@ -1173,6 +1173,8 @@ 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); +int set_rxq_fill_thresh(portid_t port_id, uint16_t queue_idx,
it is better to be consistent with variable nameing queue_idx -> queue_id
app/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue, · line 1177
Quoted 1 line
app/test-pmd/testpmd.h +1
-0+ uint16_t fill_thresh);
uint16_t -> uint8_t since ethdev API uses uint8_t. It must be consistent with ethdev.
Quoted 17 lines
app/test-pmd/testpmd.h +0
-0extern int flow_parse(const char *src, void *result, unsigned int size, struct rte_flow_attr **attr,lib/ethdev/ethdev_driver.h +6
-0@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue fill threshold. +* @see rte_eth_rx_fill_thresh_set() +*/ +typedef int (*eth_rx_queue_fill_thresh_set_t)(struct rte_eth_dev *dev, + uint16_t rx_queue_id,
lib/ethdev/ethdev_driver.h typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev, · line 488
Quoted 10 lines
lib/ethdev/ethdev_driver.h +10
-0+ uint8_t fill_thresh); + +/** +* @internal Query queue fill threshold event. +* @see rte_eth_rx_fill_thresh_query() +*/ + +typedef int (*eth_rx_queue_fill_thresh_query_t )(struct rte_eth_dev *dev, +uint16_t *rx_queue_id, +uint8_t *fill_thresh);
Should fill_thresh be round UP or DOWN by the driver? Order of prototypes definition must follow order of ops in the structure.
lib/ethdev/ethdev_driver.h struct eth_dev_ops { · line 1192
Quoted 13 lines
lib/ethdev/ethdev_driver.h +6
-0+/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id,@@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t priority_flow_ctrl_queue_config; +/** Set Rx queue fill threshold. */ +eth_rx_queue_fill_thresh_set_t rx_queue_fill_thresh_set; +/** Query Rx queue fill threshold event. */ +eth_rx_queue_fill_thresh_query_t rx_queue_fill_thresh_query; +
Why is it added in the middle fo the structure?
Isn't it better to add at the end?
Quoted 16 lines
lib/ethdev/ethdev_driver.h +0
-0/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set;/** Set Unicast hash bitmap */ lib/ethdev/rte_ethdev.c +5
-0@@ -4424,6 +4424,58 @@ int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, queue_idx, tx_rate)); } +int rte_eth_rx_fill_thresh_set (uint16_t port_id,uint16_t queue_id, +uint8_t fill_thresh) +{ +struct rte_eth_dev *dev; +struct rte_eth_dev_info dev_info;
lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4441
Quoted 10 lines
lib/ethdev/rte_ethdev.c +10
-0+int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id > dev_info.max_rx_queues) {
We don't need dev_info to get number of Rx queues. dev->data->nb_rx_queues does the job.
lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4449
Quoted 8 lines
lib/ethdev/rte_ethdev.c +8
-0+RTE_ETHDEV_LOG (ERR , +"Set queue fill thresh: port %u: invalid queue ID=%u.\n" , + port_id, queue_id); +return -EINVAL ; + } + +if (fill_thresh >99 ) +return -EINVAL ;
Why do you have error log above, but don't have it here?
Quoted 12 lines
lib/ethdev/rte_ethdev.c +12
-0+RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_fill_thresh_set, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_fill_thresh_set)(dev, + queue_id, fill_thresh)); +} + +int rte_eth_rx_fill_thresh_query (uint16_t port_id,uint16_t *queue_id, +uint8_t *fill_thresh) +{ +struct rte_eth_dev_info dev_info; +struct rte_eth_dev *dev; +int ret; +
lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4471
Quoted 10 lines
lib/ethdev/rte_ethdev.c +10
-0+RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id ==NULL ) +return -EINVAL ; +if (*queue_id >= dev_info.max_rx_queues)
Same here. you don't need dev_info
Quoted 120 lines
lib/ethdev/rte_ethdev.c +7
-0+ *queue_id =0 ; + +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->rx_queue_fill_thresh_query, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops->rx_queue_fill_thresh_query)(dev, + queue_id, fill_thresh)); +} +RTE_INIT (eth_dev_init_fp_ops) {uint32_t i;lib/ethdev/rte_ethdev.h +72
-0@@ -1931,6 +1931,14 @@ struct rte_eth_rxq_info {uint8_t queue_state;/**< one of RTE_ETH_QUEUE_STATE_*. */ uint16_t nb_desc;/**< configured number of RXDs. */ uint16_t rx_buf_size;/**< hardware receive buffer size. */ +/** +* Per-queue Rx fill threshold defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_FILL_THESH is triggered. +* Value 0 means threshold monitoring is disabled, no event is +* triggered. +*/ +uint8_t fill_thresh; } __rte_cache_min_aligned;/** @@ -3672,6 +3680,65 @@ int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,*/ int rte_eth_dev_set_vlan_pvid (uint16_t port_id,uint16_t pvid,int on); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Set Rx queue based fill threshold. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The index of the receive queue. +* @param fill_thresh +* The fill threshold percentage of Rx queue size which describes +* the fullness of Rx queue. If the Rx queue fullness is above it, +* the device will trigger the event RTE_ETH_EVENT_RX_FILL_THRESH. +* [1-99] to set a new fill thresold. +* 0 to disable thresold monitoring. +* +* @return +* - 0 if successful. +* - negative if failed. +*/ +__rte_experimental +int rte_eth_rx_fill_thresh_set(uint16_t port_id, uint16_t queue_id, +uint8_t fill_thresh); + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Query Rx queue based fill threshold event. +* The function queries all queues in the port circularly until one +* pending fill_thresh event is found or no pending fill_thresh event is found. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The API caller sets the starting Rx queue id in the pointer. +* If the queue_id is bigger than maximum queue id of the port, +* it's rewinded to 0 so that application can keep calling +* this function to handle all pending fill_thresh events in the queues +* with a simple increment between calls. +* If a Rx queue has pending fill_thresh event, the pointer is updated +* with this Rx queue id; otherwise this pointer's content is +* unchanged. +* @param fill_thresh +* The pointer to the fill threshold percentage of Rx queue. +* If Rx queue with pending fill_thresh event is found, the queue's fill_thresh +* percentage is stored in this pointer, otherwise the pointer's +* content is unchanged. +* +* @return +* - 1 if a Rx queue with pending fill_thresh event is found. +* - 0 if no Rx queue with pending fill_thresh event is found. +* - -EINVAL if queue_id is NULL. +*/ +__rte_experimental +int rte_eth_rx_fill_thresh_query(uint16_t port_id, uint16_t *queue_id, +uint8_t *fill_thresh); +typedef void (*buffer_tx_error_fn )(struct rte_mbuf **unsent,uint16_t count,void *userdata);@@ -3877,6 +3944,11 @@ enum rte_eth_event_type {RTE_ETH_EVENT_DESTROY ,/**< port is released */ RTE_ETH_EVENT_IPSEC ,/**< IPsec offload related event */ RTE_ETH_EVENT_FLOW_AGED ,/**< New aged-out flows is detected */ +/** +* Fill threshold value is exceeded in a queue. +* @see rte_eth_rx_fill_thresh_set() +*/ +RTE_ETH_EVENT_RX_FILL_THRESH , RTE_ETH_EVENT_MAX /**< max value of this enum */ };lib/ethdev/version.map +2
-0@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update; + rte_eth_rx_fill_thresh_set; + rte_eth_rx_fill_thresh_query; }; INTERNAL {
RE: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
Hi Andrew,
Please see below for "fill threshold" concept, I'm ok with other comments about code.
Regards,
Spike.
Quoted 34 lines
-----Original Message-----
From: Andrew Rybchenko <[email protected]>
Sent: Saturday, June 4, 2022 8:46 PM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Wenzhuo Lu <[email protected]>; Beilei Xing <[email protected]>; Bernard Iremonger <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill thresholdExternal email: Use caution opening links or attachments
Quoted 3 lines · Spike Du
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx queue.
If so, fill threashold should be a minimum fill level and below the level we should generate an event.However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Quoted 9 lines
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx descriptors could be used. Second, HW ring size could differ queue size specified in SW.
Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.
Let me use other terms because "fill"/"refill" is also ambiguous to me.
In a RX ring, there are Rx buffers with received packets, you call it "ready Rx buffers", there is a RTE api rte_eth_rx_queue_count() to get the number,
It's also called "used descriptors" in the code.
Also there are Rx buffers provided by SW to allow HW "fill in" received packets, we can call it "usable Rx buffers" (here "usable" means usable for HW).
Let's define Rx queue "fullness":
Fullness = ready-Rx-buffers/Rxq-size
On the opposite, we have "emptiness"
Emptiness = usable-Rx-buffers/Rxq-size
Here "fill threshold" describes "fullness", it's not "refill" described in you above words. Because in your words, "refill" is the opposite, it's filling "usable/free Rx buffers", or "emptiness".
I can only briefly explain how mlx5 works to get LWM, because I'm not a Firmware guy.
Mlx5 Rx queue is basically RDMA queue. It has two indexes: producer index which increases when HW fills in packet, consumer index which increases when SW consumes the packet. The queue size is known when it's created. The fullness is something like (producer_index - consumer_index) (I don't consider in wrap-around here). So mlx5 has the way to get the fullness or emptiness in HW or FW.
Another detail is mlx5 uses the term "LWM"(limit watermark), which describes "emptiness". When usable-Rx-buffers is below LWM, we trigger an event. But Thomas think "fullness" is easier to understand, so we use "fullness" in rte APIs and we'll translate it to LWM in mlx5 PMD.
Quoted 485 lines
Quoted 12 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30Quoted 6 lines
To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>--- app/test-pmd/cmdline.c | 68+++++++++++++++++++++++++++++++++++++++++++
Quoted 6 lines
app/test-pmd/config.c | 21 ++++++++++++++ app/test-pmd/testpmd.c | 18 ++++++++++++ app/test-pmd/testpmd.h | 2 ++ lib/ethdev/ethdev_driver.h | 22 ++++++++++++++ lib/ethdev/rte_ethdev.c | 52 +++++++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 72++++++++++++++++++++++++++++++++++++++++++++++
app/test-pmd/cmdline.c struct
Quoted 8 lines
lib/ethdev/version.map | 2 ++ 8 files changed, 257 insertions(+)app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0
-00410bad..918581e 100644
app/test-pmd/cmdline.c +0
-0@@ -17823,6 +17823,73 @@ struct
cmd_show_port_flow_transfer_proxy_result{app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17834
Quoted 12 lines
app/test-pmd/cmdline.c +9
-0} }; +/* *** SET FILL THRESHOLD FOR A RXQ OF A PORT *** */ struct +cmd_rxq_fill_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 fill_thresh; +uint16_t fill_thresh_num;
uint8_tto be consistent with ethdevQuoted 24 lines
app/test-pmd/cmdline.c +24
-0+}; + +static void cmd_rxq_fill_thresh_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) { +struct cmd_rxq_fill_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->fill_thresh,"fill_thresh" ) ==0 )) + ret =set_rxq_fill_thresh (res->port_num, res->rxq_num, + res->fill_thresh_num); +if (ret <0 ) +printf ("rxq_fill_thresh_cmd error: (%s)\n" , +strerror (-ret)); + +} + +cmdline_parse_token_string_t cmd_rxq_fill_thresh_set = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + set,"set" ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_port = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result,app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17868
Quoted 10 lines
app/test-pmd/cmdline.c +10
-0+ port, "port"); cmdline_parse_token_num_t +cmd_rxq_fill_thresh_portnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + port_num,RTE_UINT16 ); +cmdline_parse_token_string_t cmd_rxq_fill_thresh_rxq = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq,"rxq" );cmdline_parse_token_num_t +cmd_rxq_fill_thresh_rxqnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + rxq_num,RTE_UINT8 );
RTE_UINT16since it is an Rx queue IDapp/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17874
Quoted 6 lines
app/test-pmd/cmdline.c +6
-0+cmdline_parse_token_string_t cmd_rxq_fill_thresh_fill_thresh = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh,"fill_thresh" ); +cmdline_parse_token_num_t cmd_rxq_fill_thresh_fill_threshnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_fill_thresh_result, + fill_thresh_num,RTE_UINT16 );
RTE_UINT16->RTE_UINT8app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result {
Quoted 5 lines
app/test-pmd/cmdline.c +5
-0+ +cmdline_parse_inst_t cmd_rxq_fill_thresh = { + .f = cmd_rxq_fill_thresh_parsed, + .data = (void *)0 , + .help_str = "set port <port_id> rxq <rxq_id> fill_thresh<
fill_thresh_num>"app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17891
Quoted 12 lines
app/test-pmd/cmdline.c +12
-0+ "Set fill_thresh for rxq on port_id", + .tokens = { + (void *)&cmd_rxq_fill_thresh_set, + (void *)&cmd_rxq_fill_thresh_port, + (void *)&cmd_rxq_fill_thresh_portnum, + (void *)&cmd_rxq_fill_thresh_rxq, + (void *)&cmd_rxq_fill_thresh_rxqnum, + (void *)&cmd_rxq_fill_thresh_fill_thresh, + (void *)&cmd_rxq_fill_thresh_fill_threshnum, + NULL, + }, +};Please, add 'static' keyword to all above cmdline_parse_* variable.
app/test-pmd/cmdline.c struct cmd_show_port_flow_transfer_proxy_result { · line 17894
Quoted 3 lines
app/test-pmd/cmdline.c +1
-0+/* **********************************************************
************app/test-pmd/cmdline.c struct
Quoted 4 lines
app/test-pmd/cmdline.c +0
-0********** */ /* list of instructions */
app/test-pmd/cmdline.c +0
-0@@ -18110,6 +18177,7 @@ struct
cmd_show_port_flow_transfer_proxy_result{Quoted 12 lines
app/test-pmd/cmdline.c +1
-0(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, + (cmdline_parse_inst_t *)&cmd_rxq_fill_thresh, NULL, };app/test-pmd/config.c index renamed from app/test-pmd/config.c +0
-01b1e738..d0c519b 100644
app/test-pmd/config.c struct igb_ring_desc_16_bytes { · line 6348
Quoted 7 lines
app/test-pmd/config.c +4
-0@@ -6342,3 +6342,24 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_fill_thresh (portid_t port_id,uint16_t queue_idx,uint16_t +fill_thresh)
uint8_tforfill_threashsince the type is used in ethdev APIQuoted 5 lines
app/test-pmd/config.c +5
-0+{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN ))app/test-pmd/config.c struct igb_ring_desc_16_bytes { · line 6361
Quoted 10 lines
app/test-pmd/config.c +10
-0+return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (fill_thresh >99 ) +return -EINVAL ; + ret =rte_eth_rx_fill_thresh_set (port_id, queue_idx, + fill_thresh); + +if (ret)Please remove extra empty line above and compare with 0 explicitly.
Quoted 17 lines
app/test-pmd/config.c +4
-0+return ret; +return 0 ; +} +app/test-pmd/testpmd.c index renamed from app/test-pmd/testpmd.c +0
-0767765d..1209230 100644
app/test-pmd/testpmd.c +1
-0@@ -420,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [RTE_ETH_EVENT_NEW] = "device probed", [RTE_ETH_EVENT_DESTROY] = "device released", [RTE_ETH_EVENT_FLOW_AGED] = "flow aged", + [RTE_ETH_EVENT_RX_FILL_THRESH] = "rxq fill threshold reached", [RTE_ETH_EVENT_MAX] = NULL, };app/test-pmd/testpmd.c struct pmd_test_command { · line 3617
Quoted 1 line
app/test-pmd/testpmd.c +0
-0@@ -3616,6 +3617,10 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type,void *param,
Quoted 10 lines
app/test-pmd/testpmd.c +4
-0void *ret_param) { +struct rte_eth_dev_info dev_info; +uint16_t rxq_id; +uint8_t fill_thresh; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);app/test-pmd/testpmd.c struct pmd_test_command { · line 3658
Quoted 7 lines
app/test-pmd/testpmd.c +4
-0@@ -3647,6 +3652,19 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RX_FILL_THRESH : + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +break ;What's the point to get device info above? It is unused as far as I can see.
app/test-pmd/testpmd.c struct pmd_test_command { · line 3659
Quoted 1 line
app/test-pmd/testpmd.c +1
-0+/* fill_thresh query API rewinds rxq_id, no need to check max rxq num. */
app/test-pmd/testpmd.c struct pmd_test_command { · line 3661
Quoted 2 lines
app/test-pmd/testpmd.c +2
-0+for (rxq_id =0 ; ; rxq_id++) { + ret = rte_eth_rx_fill_thresh_query(port_id, &rxq_id,
&fill_thresh);app/test-pmd/testpmd.c struct pmd_test_command { · line 3663
Quoted 2 lines
app/test-pmd/testpmd.c +2
-0+if (ret <=0 ) + break; > + printf("Received fill_thresh event,port:%d rxq_id:%d\n",
app/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id,
Quoted 11 lines
app/test-pmd/testpmd.c +3
-0+ port_id, rxq_id); + } +break ;default :break ; }app/test-pmd/testpmd.h index renamed from app/test-pmd/testpmd.h +0
-078a5f4e..c7a144e 100644
app/test-pmd/testpmd.h +0
-0@@ -1173,6 +1173,8 @@ uint16_t tx_pkt_set_dynf(uint16_t port_id,
__rte_unuseduint16_tqueue,app/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id, · line 1173
Quoted 1 line
app/test-pmd/testpmd.h +0
-0void flex_item_create(portid_t port_id, uint16_t flex_id, const char*filename);
app/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue, · line 1176
Quoted 3 lines
app/test-pmd/testpmd.h +1
-0void flex_item_destroy (portid_t port_id,uint16_t flex_id);void port_flex_item_flush (portid_t port_id); +int set_rxq_fill_thresh(portid_t port_id, uint16_t queue_idx,it is better to be consistent with variable nameing
queue_idx->queue_idapp/test-pmd/testpmd.h uint16_t tx_pkt_set_dynf(uint16_t port_id, __rte_unused uint16_t queue, · line 1177
Quoted 1 line
app/test-pmd/testpmd.h +1
-0+ uint16_t fill_thresh);
uint16_t->uint8_tsince ethdev API usesuint8_t. It must be consistent with ethdev.lib/ethdev/ethdev_driver.h typedef int (*eth_rx_queue_setup_t)(struct
Quoted 8 lines
app/test-pmd/testpmd.h +0
-0extern int flow_parse (const char *src,void *result,unsigned int size, struct rte_flow_attr **attr, diff --git
a/lib/ethdev/ethdev_driver.hb/lib/ethdev/ethdev_driver.hindex 69d9dc2..7ef7dba 100644lib/ethdev/ethdev_driver.h +0
-0@@ -470,6 +470,23 @@ typedef int (*eth_rx_queue_setup_t)(struct
rte_eth_dev*dev,Quoted 6 lines
lib/ethdev/ethdev_driver.h +3
-0const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mb_pool); +/** +* @internal Set Rx queue fill threshold. +* @see rte_eth_rx_fill_thresh_set() lib/ethdev/ethdev_driver.h typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev,
Quoted 10 lines
lib/ethdev/ethdev_driver.h +10
-0+*/ +typedef int (*eth_rx_queue_fill_thresh_set_t )(struct rte_eth_dev *dev, +uint16_t rx_queue_id, +uint8_t fill_thresh); + +/** +* @internal Query queue fill threshold event. +* @see rte_eth_rx_fill_thresh_query() */ + +typedef int (*eth_rx_queue_fill_thresh_query_t)(struct rte_eth_dev*dev,
lib/ethdev/ethdev_driver.h typedef int (*eth_rx_queue_setup_t)(struct rte_eth_dev *dev, · line 488
Quoted 2 lines
lib/ethdev/ethdev_driver.h +2
-0+uint16_t *rx_queue_id, + uint8_t *fill_thresh);Should
fill_threshbe round UP or DOWN by the driver?
Order of prototypes definition must follow order of ops in the structure.Quoted 9 lines
lib/ethdev/ethdev_driver.h +2
-0+/** @internal Setup a transmit queue of an Ethernet device. */ typedef int (*eth_tx_queue_setup_t)(struct rte_eth_dev *dev, uint16_t tx_queue_id, @@ -1168,6 +1185,11 @@ struct eth_dev_ops {/** Priority flow control queue configure */ priority_flow_ctrl_queue_config_t
priority_flow_ctrl_queue_config;lib/ethdev/ethdev_driver.h struct eth_dev_ops { · line 1192
Quoted 5 lines
lib/ethdev/ethdev_driver.h +5
-0+/** Set Rx queue fill threshold. */ +eth_rx_queue_fill_thresh_set_t rx_queue_fill_thresh_set; +/** Query Rx queue fill threshold event. */ +eth_rx_queue_fill_thresh_query_t rx_queue_fill_thresh_query; +Why is it added in the middle fo the structure?
Isn't it better to add at the end?lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t
Quoted 8 lines
/** Set Unicast Table Array */ eth_uc_hash_table_set_t uc_hash_table_set; /** Set Unicast hash bitmap */lib/ethdev/rte_ethdev.c index renamed from lib/ethdev/rte_ethdev.c +0
-0a175867..69a1f75 100644
lib/ethdev/rte_ethdev.c +0
-0@@ -4424,6 +4424,58 @@ int rte_eth_set_queue_rate_limit(uint16_t
port_id,uint16_tqueue_idx,Quoted 7 lines
lib/ethdev/rte_ethdev.c +4
-0queue_idx, tx_rate)); } +int rte_eth_rx_fill_thresh_set (uint16_t port_id,uint16_t queue_id, +uint8_t fill_thresh) { +struct rte_eth_dev *dev; +struct rte_eth_dev_info dev_info;lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4441
Quoted 10 lines
lib/ethdev/rte_ethdev.c +10
-0+int ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id > dev_info.max_rx_queues) {We don't need
dev_infoto get number of Rx queues.dev->data->nb_rx_queuesdoes the job.lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4449
Quoted 8 lines
lib/ethdev/rte_ethdev.c +8
-0+RTE_ETHDEV_LOG (ERR , +"Set queue fill thresh: port %u: invalid queue ID=%u.\n" , + port_id, queue_id); +return -EINVAL ; + } + +if (fill_thresh >99 ) +return -EINVAL ;Why do you have error log above, but don't have it here?
Quoted 13 lines
lib/ethdev/rte_ethdev.c +11
-0+RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops- rx_queue_fill_thresh_set, -ENOTSUP ); +return eth_err (port_id, (*dev->dev_ops- rx_queue_fill_thresh_set)(dev, + queue_id, +fill_thresh)); } + +int rte_eth_rx_fill_thresh_query (uint16_t port_id,uint16_t *queue_id, +uint8_t *fill_thresh) { +struct rte_eth_dev_info dev_info; +struct rte_eth_dev *dev; +int ret; +lib/ethdev/rte_ethdev.c int rte_eth_set_queue_rate_limit(uint16_t port_id, uint16_t queue_idx, · line 4471
Quoted 10 lines
lib/ethdev/rte_ethdev.c +10
-0+RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + dev = &rte_eth_devices[port_id]; + + ret =rte_eth_dev_info_get (port_id, &dev_info); +if (ret !=0 ) +return ret; + +if (queue_id ==NULL ) +return -EINVAL ; +if (*queue_id >= dev_info.max_rx_queues)Same here. you don't need
dev_infolib/ethdev/rte_ethdev.h int rte_eth_dev_set_vlan_ether_type(uint16_t
Quoted 32 lines
lib/ethdev/rte_ethdev.c +4
-0+ *queue_id =0 ; + +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops- rx_queue_fill_thresh_query, -ENOTSUP ); + return eth_err(port_id, (*dev->dev_ops-rx_queue_fill_thresh_query)(dev,
lib/ethdev/rte_ethdev.c +3
-0+ queue_id, +fill_thresh)); } +RTE_INIT (eth_dev_init_fp_ops) {uint32_t i;lib/ethdev/rte_ethdev.h index renamed from lib/ethdev/rte_ethdev.h +0
-004225bb..d44e5da 100644
lib/ethdev/rte_ethdev.h +8
-0@@ -1931,6 +1931,14 @@ struct rte_eth_rxq_info {uint8_t queue_state;/**< one of RTE_ETH_QUEUE_STATE_*. */ uint16_t nb_desc;/**< configured number of RXDs. */ uint16_t rx_buf_size;/**< hardware receive buffer size. */ +/** +* Per-queue Rx fill threshold defined as percentage of Rx queue +* size. If Rx queue receives traffic higher than this percentage, +* the event RTE_ETH_EVENT_RX_FILL_THESH is triggered. +* Value 0 means threshold monitoring is disabled, no event is +* triggered. +*/ +uint8_t fill_thresh; } __rte_cache_min_aligned;/** @@ -3672,6 +3680,65 @@ int rte_eth_dev_set_vlan_ether_type(uint16_t
port_id,Quoted 26 lines
lib/ethdev/rte_ethdev.h +22
-0*/ int rte_eth_dev_set_vlan_pvid (uint16_t port_id,uint16_t pvid,int on); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Set Rx queue based fill threshold. +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The index of the receive queue. +* @param fill_thresh +* The fill threshold percentage of Rx queue size which describes +* the fullness of Rx queue. If the Rx queue fullness is above it, +* the device will trigger the event RTE_ETH_EVENT_RX_FILL_THRESH. +* [1-99] to set a new fill thresold. +* 0 to disable thresold monitoring. +* +* @return +* - 0 if successful. +* - negative if failed. +*/ +__rte_experimentallib/ethdev/rte_ethdev.h int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,
Quoted 10 lines
lib/ethdev/rte_ethdev.h +10
-0+int rte_eth_rx_fill_thresh_set (uint16_t port_id,uint16_t queue_id, +uint8_t fill_thresh); + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice. +* +* Query Rx queue based fill threshold event. +* The function queries all queues in the port circularly until one +* pending fill_thresh event is found or no pending fill_thresh event is found.
Quoted 21 lines
lib/ethdev/rte_ethdev.h +21
-0+* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The API caller sets the starting Rx queue id in the pointer. +* If the queue_id is bigger than maximum queue id of the port, +* it's rewinded to 0 so that application can keep calling +* this function to handle all pending fill_thresh events in the +queues +* with a simple increment between calls. +* If a Rx queue has pending fill_thresh event, the pointer is +updated +* with this Rx queue id; otherwise this pointer's content is +* unchanged. +* @param fill_thresh +* The pointer to the fill threshold percentage of Rx queue. +* If Rx queue with pending fill_thresh event is found, the queue's +fill_thresh +* percentage is stored in this pointer, otherwise the pointer's +* content is unchanged. +* lib/ethdev/rte_ethdev.h int rte_eth_dev_set_vlan_ether_type(uint16_t port_id,
Quoted 10 lines
lib/ethdev/rte_ethdev.h +9
-0+* @return +* - 1 if a Rx queue with pending fill_thresh event is found. +* - 0 if no Rx queue with pending fill_thresh event is found. +* - -EINVAL if queue_id is NULL. +*/ +__rte_experimental +int rte_eth_rx_fill_thresh_query(uint16_t port_id, uint16_t *queue_id, +uint8_t *fill_thresh); + typedef void (*buffer_tx_error_fn)(struct rte_mbuf **unsent, uint16_tcount,
Quoted 27 lines
void *userdata);lib/ethdev/rte_ethdev.h +5
-0@@ -3877,6 +3944,11 @@ enum rte_eth_event_type {RTE_ETH_EVENT_DESTROY ,/**< port is released */ RTE_ETH_EVENT_IPSEC ,/**< IPsec offload related event */ RTE_ETH_EVENT_FLOW_AGED ,/**< New aged-out flows is detected */ +/** +* Fill threshold value is exceeded in a queue. +* @see rte_eth_rx_fill_thresh_set() +*/ +RTE_ETH_EVENT_RX_FILL_THRESH , RTE_ETH_EVENT_MAX /**< max value of this enum */ };lib/ethdev/version.map index renamed from lib/ethdev/version.map +0
-0daca785..29b1fe8 100644
lib/ethdev/version.map +2
-0@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update; + rte_eth_rx_fill_thresh_set; + rte_eth_rx_fill_thresh_query; }; INTERNAL {
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
Quoted 51 lines · Spike Du
Hi Andrew,
Please see below for "fill threshold" concept, I'm ok with other comments about code.Regards,
Spike.Quoted 34 lines
-----Original Message-----
From: Andrew Rybchenko <[email protected]>
Sent: Saturday, June 4, 2022 8:46 PM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Wenzhuo Lu <[email protected]>; Beilei Xing <[email protected]>; Bernard Iremonger <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill thresholdExternal email: Use caution opening links or attachments
Quoted 3 lines · Spike Du
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx queue.
If so, fill threashold should be a minimum fill level and below the level we should generate an event.However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Quoted 9 lines
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx descriptors could be used. Second, HW ring size could differ queue size specified in SW.
Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.
Quoted 4 lines
Let me use other terms because "fill"/"refill" is also ambiguous to me.
In a RX ring, there are Rx buffers with received packets, you call it "ready Rx buffers", there is a RTE apirte_eth_rx_queue_count()to get the number, It's also called "used descriptors" in the code.
Also there are Rx buffers provided by SW to allow HW "fill in" received packets, we can call it "usable Rx buffers" (here "usable" means usable for HW).
May be it is better to stick to Rx descriptor status terminology? Available - Rx descriptor available to HW to put received packet to Done - Rx descriptor with received packet reported to Sw Unavailable - other (e.g. gap which cannot be used or just processed Done, but not refilled (made available to HW).
Quoted 2 lines
Let's define Rx queue "fullness":
Fullness = ready-Rx-buffers/Rxq-size
i.e. number of DONE descriptors divided by RxQ size
Quoted 2 lines
On the opposite, we have "emptiness"
Emptiness = usable-Rx-buffers/Rxq-size
i.e. number of AVAIL descriptors divided by RxQ size Note, that AVAIL != RxQ-size - DONE
HW really knows number of available descriptors by its nature. It is a space between latest done and latest received on refill.
HW does not know which descriptors are DONE, since some which are DONE before could be already processed by SW, but not yet made available again.
Quoted 8 lines
Here "fill threshold" describes "fullness", it's not "refill" described in you above words. Because in your words, "refill" is the opposite, it's filling "usable/free Rx buffers", or "emptiness".
I can only briefly explain how mlx5 works to get LWM, because I'm not a Firmware guy.
Mlx5 Rx queue is basically RDMA queue. It has two indexes: producer index which increases when HW fills in packet, consumer index which increases when SW consumes the packet. The queue size is known when it's created. The fullness is something like (producer_index-consumer_index) (I don't consider in wrap-around here). So mlx5 has the way to get the fullness or emptiness in HW or FW.
Another detail is mlx5 uses the term "LWM"(limit watermark), which describes "emptiness". When usable-Rx-buffers is below LWM, we trigger an event. But Thomas think "fullness" is easier to understand, so we use "fullness" in rte APIs and we'll translate it to LWM in mlx5 PMD.
HW simply does now know fullness and there can't generate any events based on it. It is a problem on Rx when there is now available descriptors. I.e. emptiness.
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>
[snip]
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
It seems we share a common understanding
and we need to agree on a good wording
for the most meaningful API.
Questions inline below:
06/06/2022 19:15, Andrew Rybchenko:
Quoted 59 lines · Spike Du
Quoted 36 lines
Hi Andrew,
Please see below for "fill threshold" concept, I'm ok with other comments about code.Regards,
Spike.From: Andrew Rybchenko <[email protected]>
Quoted 18 lines · Spike Du
Quoted 3 lines
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx queue.
If so, fill threashold should be a minimum fill level and below the level we should generate an event.However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Quoted 9 lines
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx descriptors could be used. Second, HW ring size could differ queue size specified in SW.
Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.Quoted 4 lines
Let me use other terms because "fill"/"refill" is also ambiguous to me.
In a RX ring, there are Rx buffers with received packets, you call it "ready Rx buffers", there is a RTE apirte_eth_rx_queue_count()to get the number, It's also called "used descriptors" in the code.
Also there are Rx buffers provided by SW to allow HW "fill in" received packets, we can call it "usable Rx buffers" (here "usable" means usable for HW).May be it is better to stick to Rx descriptor status terminology? Available - Rx descriptor available to HW to put received packet to Done - Rx descriptor with received packet reported to Sw Unavailable - other (e.g. gap which cannot be used or just processed Done, but not refilled (made available to HW).
Quoted 2 lines
Let's define Rx queue "fullness":
Fullness = ready-Rx-buffers/Rxq-sizei.e. number of DONE descriptors divided by RxQ size
Quoted 2 lines
On the opposite, we have "emptiness"
Emptiness = usable-Rx-buffers/Rxq-sizei.e. number of AVAIL descriptors divided by RxQ size Note, that AVAIL != RxQ-size - DONE
Quoted 16 lines
HW really knows number of available descriptors by its nature. It is a space between latest done and latest received on refill.
HW does not know which descriptors are DONE, since some which are DONE before could be already processed by SW, but not yet made available again.
Quoted 8 lines
Here "fill threshold" describes "fullness", it's not "refill" described in you above words. Because in your words, "refill" is the opposite, it's filling "usable/free Rx buffers", or "emptiness".
I can only briefly explain how mlx5 works to get LWM, because I'm not a Firmware guy.
Mlx5 Rx queue is basically RDMA queue. It has two indexes: producer index which increases when HW fills in packet, consumer index which increases when SW consumes the packet. The queue size is known when it's created. The fullness is something like (producer_index-consumer_index) (I don't consider in wrap-around here). So mlx5 has the way to get the fullness or emptiness in HW or FW.
Another detail is mlx5 uses the term "LWM"(limit watermark), which describes "emptiness". When usable-Rx-buffers is below LWM, we trigger an event. But Thomas think "fullness" is easier to understand, so we use "fullness" in rte APIs and we'll translate it to LWM in mlx5 PMD.
I may be wrong :)
Quoted 3 lines
HW simply does now know fullness and there can't generate any events based on it. It is a problem on Rx when there is now available descriptors. I.e. emptiness.
So you think "empty_thresh" would be better?
Or "avail_thresh"?
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
Quoted 82 lines · Thomas Monjalon
It seems we share a common understanding
and we need to agree on a good wording
for the most meaningful API.
Questions inline below:06/06/2022 19:15, Andrew Rybchenko:
Quoted 59 lines · Spike Du
Quoted 36 lines
Hi Andrew,
Please see below for "fill threshold" concept, I'm ok with other comments about code.Regards,
Spike.From: Andrew Rybchenko <[email protected]>
Quoted 18 lines · Spike Du
Quoted 3 lines
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx queue.
If so, fill threashold should be a minimum fill level and below the level we should generate an event.However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Quoted 9 lines
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx descriptors could be used. Second, HW ring size could differ queue size specified in SW.
Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.Quoted 4 lines
Let me use other terms because "fill"/"refill" is also ambiguous to me.
In a RX ring, there are Rx buffers with received packets, you call it "ready Rx buffers", there is a RTE apirte_eth_rx_queue_count()to get the number, It's also called "used descriptors" in the code.
Also there are Rx buffers provided by SW to allow HW "fill in" received packets, we can call it "usable Rx buffers" (here "usable" means usable for HW).May be it is better to stick to Rx descriptor status terminology? Available - Rx descriptor available to HW to put received packet to Done - Rx descriptor with received packet reported to Sw Unavailable - other (e.g. gap which cannot be used or just processed Done, but not refilled (made available to HW).
Quoted 2 lines
Let's define Rx queue "fullness":
Fullness = ready-Rx-buffers/Rxq-sizei.e. number of DONE descriptors divided by RxQ size
Quoted 2 lines
On the opposite, we have "emptiness"
Emptiness = usable-Rx-buffers/Rxq-sizei.e. number of AVAIL descriptors divided by RxQ size Note, that AVAIL != RxQ-size - DONE
Quoted 16 lines
HW really knows number of available descriptors by its nature. It is a space between latest done and latest received on refill.
HW does not know which descriptors are DONE, since some which are DONE before could be already processed by SW, but not yet made available again.
Quoted 8 lines
Here "fill threshold" describes "fullness", it's not "refill" described in you above words. Because in your words, "refill" is the opposite, it's filling "usable/free Rx buffers", or "emptiness".
I can only briefly explain how mlx5 works to get LWM, because I'm not a Firmware guy.
Mlx5 Rx queue is basically RDMA queue. It has two indexes: producer index which increases when HW fills in packet, consumer index which increases when SW consumes the packet. The queue size is known when it's created. The fullness is something like (producer_index-consumer_index) (I don't consider in wrap-around here). So mlx5 has the way to get the fullness or emptiness in HW or FW.
Another detail is mlx5 uses the term "LWM"(limit watermark), which describes "emptiness". When usable-Rx-buffers is below LWM, we trigger an event. But Thomas think "fullness" is easier to understand, so we use "fullness" in rte APIs and we'll translate it to LWM in mlx5 PMD.
Quoted 8 lines
I may be wrong :)
Quoted 3 lines
HW simply does now know fullness and there can't generate any events based on it. It is a problem on Rx when there is now available descriptors. I.e. emptiness.
So you think "
empty_thresh" would be better?
Or "avail_thresh"?
I'd go for "avail_thresh" since it is consistent with descriptor status API terminology.
One moment I thought that there is a problem with rx_free_threshold, but finally realize that there is no problem, since it is in terms of free descriptors which could be made available (refilled).
Quoted 19 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>
RE: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
In reply to Andrew RybchenkoIf you think HW knows "emptiness", and we want to stick to DPDK descriptor terms. Can we use the name "avail_thresh?"
When HW sees available descriptors is under this threshold, an event is triggered.
Quoted 146 lines
-----Original Message-----
From: Andrew Rybchenko <[email protected]>
Sent: Tuesday, June 7, 2022 1:16 AM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Wenzhuo Lu <[email protected]>; Beilei Xing <[email protected]>; Bernard Iremonger <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill thresholdExternal email: Use caution opening links or attachments
Quoted 2 lines · Spike Du
Hi Andrew,
Please see below for "fill threshold" concept, I'm ok with othercomments about code.
Quoted 11 lines
Regards,
Spike.Quoted 6 lines
-----Original Message-----
From: Andrew Rybchenko <[email protected]>
Sent: Saturday, June 4, 2022 8:46 PM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>;Wenzhuo
Quoted 11 lines
Quoted 11 lines
Lu <[email protected]>; Beilei Xing <[email protected]>; Bernard Iremonger <[email protected]>; Ray Kinsella <[email protected]>; Neil Horman <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill thresholdExternal email: Use caution opening links or attachments
Quoted 8 lines
Quoted 8 lines · Spike Du
Quoted 3 lines
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.Sorry, I'm not sure that I understand. As far as I know the process to add more Rx buffers to Rx queue is called 'refill' in many drivers. So fill level is a number (or percentage) of free buffers in an Rx
queue.
Quoted 7 lines
Quoted 7 lines
If so, fill threashold should be a minimum fill level and below the level we should generate an event.
However reading the first paragraph of the descrition it looks like you mean oposite thing - a number (or percentage) of ready Rx buffers with received packets.
Quoted 8 lines
Quoted 8 lines
I think that the term "fill threshold" is suggested by me, but I did it with mine understanding of the added feature. Now I'm confused.
Moreover, I don't understand how "fill threshold" could be in terms of ready Rx buffers. HW simply don't really know when ready Rx buffers are processed by SW. So, HW can't say for sure how many ready Rx buffers are pending. It could be calculated as Rx queue size minus number of free Rx buffers, but it is imprecise. First of all not all Rx
descriptors could be used.
Quoted 8 lines
Quoted 4 lines
Second, HW ring size could differ queue size specified in SW. Queue size specified in SW could just limit maximum nubmer of free Rx buffers provided by the driver.
Let me use other terms because "fill"/"refill" is also ambiguous to me. In a RX ring, there are Rx buffers with received packets, you call it "ready Rx buffers", there is a RTE api
rte_eth_rx_queue_count()to get thenumber, It's also called "used descriptors" in the code.
Quoted 1 line
Also there are Rx buffers provided by SW to allow HW "fill in" received
packets, we can call it "usable Rx buffers" (here "usable" means usable for HW).
May be it is better to stick to Rx descriptor status terminology? Available - Rx descriptor available to HW to put received packet to Done - Rx descriptor with received packet reported to Sw Unavailable - other (e.g. gap which cannot be used or just processed Done, but not refilled (made available to HW).
Quoted 2 lines
Let's define Rx queue "fullness":
Fullness = ready-Rx-buffers/Rxq-sizei.e. number of DONE descriptors divided by RxQ size
Quoted 2 lines
On the opposite, we have "emptiness"
Emptiness = usable-Rx-buffers/Rxq-sizei.e. number of AVAIL descriptors divided by RxQ size Note, that AVAIL != RxQ-size - DONE
HW really knows number of available descriptors by its nature. It is a space between latest done and latest received on refill.
HW does not know which descriptors are DONE, since some which are DONE before could be already processed by SW, but not yet made available again.
Quoted 1 line
Here "fill threshold" describes "fullness", it's not "refill" described in you
above words. Because in your words, "refill" is the opposite, it's filling "usable/free Rx buffers", or "emptiness".
Quoted 2 lines
I can only briefly explain how mlx5 works to get LWM, because I'm not a
Firmware guy.
Quoted 1 line
Mlx5 Rx queue is basically RDMA queue. It has two indexes: producer index
which increases when HW fills in packet, consumer index which increases when SW consumes the packet.
Quoted 1 line
The queue size is known when it's created. The fullness is something like
(
producer_index-consumer_index) (I don't consider in wrap-around here).Quoted 2 lines
So mlx5 has the way to get the fullness or emptiness in HW or FW. Another detail is mlx5 uses the term "LWM"(limit watermark), which
describes "emptiness". When usable-Rx-buffers is below LWM, we trigger an event.
Quoted 1 line
But Thomas think "fullness" is easier to understand, so we use "fullness" in
rte APIs and we'll translate it to LWM in mlx5 PMD.
HW simply does now know fullness and there can't generate any events based on it. It is a problem on Rx when there is now available descriptors. I.e. emptiness.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks in
eth_dev_ops.Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Add command line options to support
fill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>[snip]
Re: [PATCH v4 3/7] ethdev: introduce Rx queue based fill threshold
In reply to Spike DuQuoted 11 lines · On Fri, 3 Jun 2022 15:48:17 +0300 Spike Du <[email protected]> wrote:
Fill threshold describes the fullness of a Rx queue. If the Rx queue fullness is above the threshold, the device will trigger the event
RTE_ETH_EVENT_RX_FILL_THRESH.
Fill threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting fill threshold to 0 means disable it, which is the default. Add fill threshold configuration and query driver callbacks ineth_dev_ops. Add command line options to supportfill_threshper-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id>fill_thresh<fill_thresh_num>
Quoted 8 lines
- Example commands:
To configurefill_threshas 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh30To disable
fill_threshon port 1 rxq 0:
testpmd> set port 1 rxq 0fill_thresh0Signed-off-by Spike Du <[email protected]>
Could the name be shortened to just rte_event_rx_thresh?
The eth_ and _fill_ part are redundant.
PATCH v4 4/7 net/mlx5: add LWM event handling support
In reply to Spike DuWhen 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
@@ -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
@@ -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
@@ -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_FILL_THRESH ,NULL ); +}
drivers/net/mlx5/mlx5_rx.h +7 -0
@@ -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
PATCH v4 5/7 net/mlx5: support Rx queue based fill threshold
In reply to Spike DuAdd mlx5 specific fill threshold configuration and query handler. In mlx5 PMD, fill 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 | 156 +++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 5 ++ 6 files changed, 177 insertions(+)
doc/guides/nics/mlx5.rst +12 -0
@@ -93,6 +93,7 @@ Features - Connection tracking. - Sub-Function representors. - Sub-Function. +- Rx queue fill threshold configuration. Limitations
@@ -520,6 +521,9 @@ Limitations - The NIC egress flow rules on representor port are not supported. +- Fill 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 + +Fill threshold introduction +---------------- + +Fill threshold is a per Rx queue attribute, it should be configured as +a percentage of the Rx queue size. +When Rx queue fullness is above the threshold, an event is sent to PMD. +
doc/guides/rel_notes/release_22_07.rst +1 -0
@@ -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 fill threshold support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/mlx5_prm.h +1 -0
@@ -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
@@ -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_fill_thresh_set = mlx5_rx_queue_lwm_set, + .rx_queue_fill_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 +156 -0
195 lines not on this page · raw message
drivers/net/mlx5/mlx5_rx.h +5 -0
@@ -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
PATCH v4 6/7 net/mlx5: add private API to config host port shaper
In reply to Spike DuHost 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 fill 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 | 103 +++++++++++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 30 ++++++++++ drivers/net/mlx5/version.map | 2 + 8 files changed, 211 insertions(+)
doc/guides/nics/mlx5.rst +35 -0
@@ -94,6 +94,7 @@ Features - Sub-Function representors. - Sub-Function. - Rx queue fill 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_FILL_THRESH_TRIGGERED flag set, + only rate 0 and 100Mbps are supported. + Statistics ----------
@@ -1692,3 +1699,31 @@ Fill threshold is a per Rx queue attribute, it should be configured as a percentage of the Rx queue size. When Rx queue fullness is above 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 +fill threshold event trigger. In immediate mode, the rate limit is configured +immediately to host shaper. When deferring to fill threshold trigger, the shaper +is not set until an fill 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 fill threshold event, which allows throttling host traffic on +fill 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
@@ -90,6 +90,7 @@ New Features * Added support for MTU on Windows. * Added matching and RSS on IPsec ESP. * Added Rx queue fill threshold support. + * Added host shaper support. * **Updated Marvell cnxk crypto driver.**
drivers/common/mlx5/linux/meson.build +13 -0
@@ -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
@@ -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
@@ -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 +103 -0
112 lines not on this page · raw message
drivers/net/mlx5/rte_pmd_mlx5.h +30 -0
@@ -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 +* fill 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_FILL_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
@@ -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
Re: [PATCH v4 6/7] net/mlx5: add private API to config host port shaper
Quoted 12 lines · 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 fill threshold event.
Signed-off-by Spike Du <[email protected]>
Quoted 11 lines
--- 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 | 103 +++++++++++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 30 ++++++++++ drivers/net/mlx5/version.map | 2 + 8 files changed, 211 insertions(+)
PATCH v4 7/7 app/testpmd: add Host Shaper command
In reply to Spike DuAdd command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id> host_shaper fill_thresh_triggered <0|1> rate
<rate_num>
- Example commands:
To enable fill_thresh_triggered on port 1 and disable current host shaper:
testpmd> mlx5 set port 1 host_shaper fill_thresh_triggered 1 rate 0
To disable fill_thresh_triggered and current host shaper on port 1:
testpmd> mlx5 set port 1 host_shaper fill_thresh_triggered 0 rate 0
The rate unit is 100Mbps.
To disable fill_thresh_triggered and configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1 host_shaper fill_thresh_triggered 0 rate 50
Add sample code to handle rxq fill_thresh event, it delays a while so that rxq empties, then disables host shaper and rearms fill_thresh event.
--- app/test-pmd/testpmd.c | 6 ++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 201 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 ++++++ 5 files changed, 283 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +6 -0
@@ -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"
@@ -3663,6 +3666,9 @@ struct pmd_test_command {break ;printf ("Received fill_thresh event, port:%d rxq_id:%d\n" , port_id, rxq_id); +#ifdef RTE_NET_MLX5 +mlx5_test_fill_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
@@ -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 +201 -0
201 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
@@ -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_FILL_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_fill_thresh_event_handler (uint16_t port_id,uint16_t rxq_id); + +#endif
Signature · 1 line
1.8.3.1
v5 cover introduce per-queue available descriptor threshold and host shaper
In reply to Spike Duavailable 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
app/test-pmd/cmdline.c | 68 +++++++ app/test-pmd/config.c | 21 ++ app/test-pmd/testpmd.c | 24 +++ app/test-pmd/testpmd.h | 2 + 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 | 4 + 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 | 289 +++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_rx.h | 13 ++ drivers/net/mlx5/mlx5_testpmd.c | 201 +++++++++++++++++++ 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 +---- lib/ethdev/ethdev_driver.h | 22 ++ lib/ethdev/rte_ethdev.c | 52 +++++ lib/ethdev/rte_ethdev.h | 73 +++++++ lib/ethdev/version.map | 2 + 33 files changed, 1318 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v5 1/7 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
Re: [PATCH v5 1/7] net/mlx5: add LWM support for Rxq
קבל Outlook עבור Android<https://aka.ms/AAb9ysg>
________________________________
From: Spike Du <[email protected]>
Sent: Tuesday, June 7, 2022 3:59:36 PM
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]>; [email protected] <[email protected]>; [email protected] <[email protected]>; Raslan Darawsheh <[email protected]>
Subject: [PATCH v5 1/7] net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
--
1.8.3.1
PATCH v5 2/7 common/mlx5: share interrupt management
In reply to Spike DuThere 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 3/7 ethdev: introduce Rx queue based available descriptor threshold
In reply to Spike Duavailable descriptor threshold describes the availability of a Rx queue for hardware.
If the availability is below the threshold, the device will trigger the event RTE_ETH_EVENT_RX_AVAIL_THRESH.
available descriptor threshold is defined as a percentage of Rx queue size with valid value of [0,99].
Setting available descriptor threshold to 0 means disable it, which is the default.
Add available descriptor threshold configuration and query driver callbacks in eth_dev_ops.
Add command line options to support avail_thresh per-rxq configure.
- Command syntax:
set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>
- Example commands:
To configure avail_thresh as 30% of rxq size on port 1 rxq 0:
testpmd> set port 1 rxq 0 avail_thresh 30
To disable avail_thresh on port 1 rxq 0:
testpmd> set port 1 rxq 0 avail_thresh 0
--- app/test-pmd/cmdline.c | 68 ++++++++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 20 +++++++++++++ app/test-pmd/testpmd.c | 14 +++++++++ app/test-pmd/testpmd.h | 2 ++ lib/ethdev/ethdev_driver.h | 22 ++++++++++++++ lib/ethdev/rte_ethdev.c | 44 ++++++++++++++++++++++++++++ lib/ethdev/rte_ethdev.h | 73 ++++++++++++++++++++++++++++++++++++++++++++++ lib/ethdev/version.map | 2 ++ 8 files changed, 245 insertions(+)
app/test-pmd/cmdline.c +68 -0
@@ -17823,6 +17823,73 @@ struct cmd_show_port_flow_transfer_proxy_result { } }; +/* *** SET AVAIL THRESHOLD FOR A RXQ OF A PORT *** */ +struct cmd_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_rxq_avail_thresh_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_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_rxq_avail_thresh_set = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_avail_thresh_result, + set,"set" ); +static cmdline_parse_token_string_t cmd_rxq_avail_thresh_port = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_avail_thresh_result, + port,"port" ); +static cmdline_parse_token_num_t cmd_rxq_avail_thresh_portnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_avail_thresh_result, + port_num,RTE_UINT16 ); +static cmdline_parse_token_string_t cmd_rxq_avail_thresh_rxq = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_avail_thresh_result, + rxq,"rxq" ); +static cmdline_parse_token_num_t cmd_rxq_avail_thresh_rxqnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_avail_thresh_result, + rxq_num,RTE_UINT16 ); +static cmdline_parse_token_string_t cmd_rxq_avail_thresh_avail_thresh = + TOKEN_STRING_INITIALIZER(struct cmd_rxq_avail_thresh_result, + avail_thresh,"avail_thresh" ); +static cmdline_parse_token_num_t cmd_rxq_avail_thresh_avail_threshnum = + TOKEN_NUM_INITIALIZER(struct cmd_rxq_avail_thresh_result, + avail_thresh_num,RTE_UINT8 ); + +static cmdline_parse_inst_t cmd_rxq_avail_thresh = { + .f = cmd_rxq_avail_thresh_parsed, + .data = (void *)0 , + .help_str ="set port <port_id> rxq <rxq_id> avail_thresh <avail_thresh_num>" +"Set avail_thresh for rxq on port_id" , + .tokens = { + (void *)&cmd_rxq_avail_thresh_set, + (void *)&cmd_rxq_avail_thresh_port, + (void *)&cmd_rxq_avail_thresh_portnum, + (void *)&cmd_rxq_avail_thresh_rxq, + (void *)&cmd_rxq_avail_thresh_rxqnum, + (void *)&cmd_rxq_avail_thresh_avail_thresh, + (void *)&cmd_rxq_avail_thresh_avail_threshnum, +NULL , + }, +}; +/* ******************************************************************************** */ /* list of instructions */
@@ -18110,6 +18177,7 @@ 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, + (cmdline_parse_inst_t *)&cmd_rxq_avail_thresh, NULL, };
app/test-pmd/config.c +20 -0
@@ -6342,3 +6342,23 @@ struct igb_ring_desc_16_bytes {printf (" %s\n" , buf); } } + +int +set_rxq_avail_thresh (portid_t port_id,uint16_t queue_id,uint8_t avail_thresh) +{ +struct rte_eth_link link; +int ret; + +if (port_id_is_invalid (port_id,ENABLED_WARN )) +return -EINVAL ; + ret =eth_link_get_nowait_print_err (port_id, &link); +if (ret <0 ) +return -EINVAL ; +if (avail_thresh >99 ) +return -EINVAL ; + ret =rte_eth_rx_avail_thresh_set (port_id, queue_id, avail_thresh); +if (ret !=0 ) +return ret; +return 0 ; +} +
app/test-pmd/testpmd.c +14 -0
@@ -420,6 +420,7 @@ struct fwd_engine * fwd_engines[] = { [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 threshold reached", [RTE_ETH_EVENT_MAX] = NULL, };
@@ -3616,6 +3617,9 @@ struct pmd_test_command { eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param, void *ret_param) { + uint16_t rxq_id; +uint8_t avail_thresh; +int ret;RTE_SET_USED (param);RTE_SET_USED (ret_param);
@@ -3647,6 +3651,16 @@ struct pmd_test_command { ports[port_id].port_status =RTE_PORT_CLOSED ;printf ("Port %u is closed\n" , port_id);break ; +case RTE_ETH_EVENT_RX_AVAIL_THRESH : +/* 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, &avail_thresh); +if (ret <=0 ) +break ; +printf ("Received avail_thresh event, port:%d rxq_id:%d\n" , + port_id, rxq_id); + } +break ;default :break ; }
app/test-pmd/testpmd.h +2 -0
@@ -1173,6 +1173,8 @@ 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); +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,
lib/ethdev/ethdev_driver.h +22 -0
@@ -1074,6 +1074,23 @@ 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 descriptor threshold. +* @see rte_eth_rx_avail_thresh_set() +*/ +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 queue available descriptor 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. */ struct eth_dev_ops {
@@ -1283,6 +1300,11 @@ struct eth_dev_ops {/** Dump private info from device */ eth_dev_priv_dump_t eth_dev_priv_dump; + +/** Set Rx queue available descriptor threshold. */ +eth_rx_queue_avail_thresh_set_t rx_queue_avail_thresh_set; +/** Query Rx queue available descriptor 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 +73 -0
91 lines not on this page · raw message
lib/ethdev/version.map +2 -0
@@ -285,6 +285,8 @@ EXPERIMENTAL { rte_mtr_color_in_protocol_priority_get; rte_mtr_color_in_protocol_set; rte_mtr_meter_vlan_table_update; + rte_eth_rx_avail_thresh_set; + rte_eth_rx_avail_thresh_query; }; INTERNAL {
Signature · 1 line
1.8.3.1
PATCH v5 4/7 net/mlx5: add LWM event handling support
In reply to Spike DuWhen 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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 5/7 net/mlx5: support Rx queue based available descriptor threshold
In reply to Spike DuAdd 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 6/7 net/mlx5: add private API to config host port shaper
In reply to Spike DuHost 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH v5 7/7 app/testpmd: add Host Shaper command
In reply to Spike DuAdd 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 | 6 ++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 201 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 ++++++ 5 files changed, 283 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +6 -0
@@ -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,9 @@ 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
@@ -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 +201 -0
201 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
@@ -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
Re: [PATCH v5 7/7] app/testpmd: add Host Shaper command
Since ethdev patch is factored out from the patch series the rest could go to mlx5 maintainers.
Quoted 23 lines · Spike Du
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1> rate
<rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50Add 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.
Signed-off-by Spike Du <[email protected]>
[snip]
Quoted 28 lines
drivers/net/mlx5/mlx5_testpmd.c new file +28
-0+ +static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS ]; +#define SHAPER_DISABLE_DELAY_US 100000/* 100ms */ + +/** +* Disable the host shaper and re-arm available descriptor threshold event. +* +* @param[in] args +* uint32_t integer combining port_id and rxq_id. +*/ +static void +mlx5_test_host_shaper_disable (void *args) +{ +uint32_t port_rxq_id = (uint32_t )(uintptr_t )args; +uint16_t port_id = port_rxq_id &0xffff ; +uint16_t qid = (port_rxq_id >>16 ) &0xffff ; +struct rte_eth_rxq_info qinfo; + +printf ("%s disable shaper\n" , __func__); +if (rte_eth_rx_queue_info_get (port_id, qid, &qinfo)) { +printf ("rx_queue_info_get returns error\n" ); +return ; + } +/* Rearm the available descriptor threshold event. */ +if (rte_eth_rx_avail_thresh_set (port_id, qid, qinfo.avail_thresh)) { +printf ("config avail_thresh returns error\n" ); +return ; + }
drivers/net/mlx5/mlx5_testpmd.c line 56
Quoted 10 lines
drivers/net/mlx5/mlx5_testpmd.c new file +10
-0+/* Only disable the shaper when avail_thresh_triggered is set. */ +if (host_shaper_avail_thresh_triggered[port_id] && +rte_pmd_mlx5_host_shaper_config (port_id,0 ,0 )) +printf ("%s disable shaper returns error\n" , __func__); +} + +void +mlx5_test_avail_thresh_event_handler (uint16_t port_id,uint16_t rxq_id) +{ +uint32_t port_rxq_id = port_id | (rxq_id <<16 );
Nobody guarantees here that port_id refers to an mlx5 port. It could be any port with avail_thres support.
Quoted 6 lines
drivers/net/mlx5/mlx5_testpmd.c new file +6
-0+ +rte_eal_alarm_set (SHAPER_DISABLE_DELAY_US , + mlx5_test_host_shaper_disable, + (void *)(uintptr_t )port_rxq_id); +printf ("%s port_id:%u rxq_id:%u\n" , __func__, port_id, rxq_id); +}
[snip]
drivers/net/mlx5/mlx5_testpmd.c line 143
Quoted 3 lines
drivers/net/mlx5/mlx5_testpmd.c new file +3
-0+cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 = + TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, + mlx5,"mlx5" );
I think it lucks 'static' keyword (many cases below).
[snip]
RE: [PATCH v5 7/7] app/testpmd: add Host Shaper command
Quoted 78 lines
-----Original Message-----
From: Andrew Rybchenko <[email protected]>
Sent: Thursday, June 9, 2022 3:55 PM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Xiaoyun Li <[email protected]>; Aman Singh <[email protected]>; Yuying Zhang <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v5 7/7] app/testpmd: add Host Shaper commandExternal email: Use caution opening links or attachments
Since ethdev patch is factored out from the patch series the rest could go to mlx5 maintainers.
Quoted 23 lines · Spike Du
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1>
rate <rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50Add 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.
Signed-off-by Spike Du <[email protected]>[snip]
Quoted 31 lines
drivers/net/mlx5/mlx5_testpmd.c new file +31
-0+ +static uint8_t host_shaper_avail_thresh_triggered[RTE_MAX_ETHPORTS ]; +#define SHAPER_DISABLE_DELAY_US 100000/* 100ms */ + +/** +* Disable the host shaper and re-arm available descriptor threshold event. +* +* @param[in] args +* uint32_t integer combining port_id and rxq_id. +*/ +static void +mlx5_test_host_shaper_disable (void *args) { +uint32_t port_rxq_id = (uint32_t )(uintptr_t )args; +uint16_t port_id = port_rxq_id &0xffff ; +uint16_t qid = (port_rxq_id >>16 ) &0xffff ; +struct rte_eth_rxq_info qinfo; + +printf ("%s disable shaper\n" , __func__); +if (rte_eth_rx_queue_info_get (port_id, qid, &qinfo)) { +printf ("rx_queue_info_get returns error\n" ); +return ; + } +/* Rearm the available descriptor threshold event. */ +if (rte_eth_rx_avail_thresh_set (port_id, qid, qinfo.avail_thresh)) { +printf ("config avail_thresh returns error\n" ); +return ; + } +/* Only disable the shaper when avail_thresh_triggered is set. */ +if (host_shaper_avail_thresh_triggered[port_id] && +rte_pmd_mlx5_host_shaper_config (port_id,0 ,0 )) +printf ("%s disable shaper returns error\n" , __func__); }
Quoted 8 lines
drivers/net/mlx5/mlx5_testpmd.c line 56
Quoted 5 lines
drivers/net/mlx5/mlx5_testpmd.c new file +5
-0+ +void +mlx5_test_avail_thresh_event_handler (uint16_t port_id,uint16_t +rxq_id) { +uint32_t port_rxq_id = port_id | (rxq_id <<16 );Nobody guarantees here that
port_idrefers to an mlx5 port. It could be any port withavail_thressupport.
I think at the beginning of this function, we can add below check:
if (rte_eth_dev_info_get(port_id, &dev_info) != 0 ||
(strncmp(dev_info.driver_name, "mlx5", 4) != 0)) return;
is it ok?
Quoted 10 lines
Quoted 7 lines
drivers/net/mlx5/mlx5_testpmd.c new file +6
-0+ +rte_eal_alarm_set (SHAPER_DISABLE_DELAY_US , + mlx5_test_host_shaper_disable, + (void *)(uintptr_t )port_rxq_id); +printf ("%s port_id:%u rxq_id:%u\n" , __func__, port_id, rxq_id); +}[snip]
Quoted 5 lines
drivers/net/mlx5/mlx5_testpmd.c line 143
Quoted 3 lines
drivers/net/mlx5/mlx5_testpmd.c new file +3
-0+cmdline_parse_token_string_t cmd_port_host_shaper_mlx5 = + TOKEN_STRING_INITIALIZER(struct cmd_port_host_shaper_result, + mlx5,"mlx5" );I think it lucks 'static' keyword (many cases below).
Sure, will add 'static'.
Quoted 2 lines
[snip]
PATCH v6 1/1 app/testpmd: add Host Shaper command
In reply to Spike Duthis patch is taken out from series of "introduce per-queue available descriptor threshold and host shaper" to simplify the review, and it's the last one for non-PMD change.
However it depends on a PMD commit for host shaper config API, should be merged after PMD patches.
--
v6:
- add 'static' keyword for cmdline structs
- in AVAIL_THRESH event callback, add check to ensure it's mlx5 port
Spike Du (1):
app/testpmd: add Host Shaper command
app/test-pmd/testpmd.c | 11 +++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 206 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 293 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v6 1/1 app/testpmd: add Host Shaper command
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 | 11 +++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 206 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 293 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
app/test-pmd/testpmd.c +11 -0
@@ -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,14 @@ struct pmd_test_command {break ;printf ("Received avail_thresh event, port:%d rxq_id:%d\n" , port_id, rxq_id); + +struct rte_eth_dev_info dev_info; +if (rte_eth_dev_info_get (port_id, &dev_info) !=0 || + (strncmp (dev_info.driver_name,"mlx5" ,4 ) !=0 )) +printf ("%s\n" , dev_info.driver_name); +#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
@@ -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 +206 -0
206 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
@@ -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
Re: [PATCH v6] app/testpmd: add Host Shaper command
Hi Spike,
Quoted 50 lines · Spike Du
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1> rate
<rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50Add 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.
Signed-off-by Spike Du <[email protected]>--- app/test-pmd/testpmd.c | 11 +++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 206 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 293 insertions(+)create mode 100644
drivers/net/mlx5/mlx5_testpmd.ccreate mode 100644drivers/net/mlx5/mlx5_testpmd.happ/test-pmd/testpmd.c +3
-0@@ -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,14 @@ struct pmd_test_command {break ; printf("Received avail_thresh event, port:%d rxq_id:%d\n",
app/test-pmd/testpmd.c struct pmd_test_command { · line 3673
Quoted 10 lines
app/test-pmd/testpmd.c +8
-0port_id, rxq_id); + +struct rte_eth_dev_info dev_info; +if (rte_eth_dev_info_get (port_id, &dev_info) !=0 || + (strncmp (dev_info.driver_name,"mlx5" ,4 ) !=0 )) +printf ("%s\n" , dev_info.driver_name); +#ifdef RTE_NET_MLX5 +mlx5_test_avail_thresh_event_handler (port_id, rxq_id); +#endif }
Wanted to check the intend of above "if-statement". Currently i think only print() is dependent on it. Do we want to call mlx5 event_handler, only if driver_name is mlx5 ?
Quoted 3 lines
app/test-pmd/testpmd.c +0
-0break ;default :
<snip>
RE: [PATCH v6] app/testpmd: add Host Shaper command
Quoted 89 lines
-----Original Message-----
From: Singh, Aman Deep <[email protected]>
Sent: Tuesday, June 14, 2022 5:44 PM
To: Spike Du <[email protected]>; Matan Azrad <[email protected]>; Slava Ovsiienko <[email protected]>; Ori Kam <[email protected]>; NBU-Contact-Thomas Monjalon (EXTERNAL) <[email protected]>; Wenzhuo Lu <[email protected]>; Beilei Xing <[email protected]>; Bernard Iremonger <[email protected]>; Shahaf Shuler <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; Raslan Darawsheh <[email protected]>
Subject: Re: [PATCH v6] app/testpmd: add Host Shaper commandExternal email: Use caution opening links or attachments
Hi Spike,
Quoted 22 lines · Spike Du
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1>
rate <rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50Add 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.
Quoted 6 lines
Signed-off-by Spike Du <[email protected]>--- app/test-pmd/testpmd.c | 11 +++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 206++++++++++++++++++++++++++++++++++++++++
Quoted 22 lines
drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 293 insertions(+)create mode 100644
drivers/net/mlx5/mlx5_testpmd.ccreate mode 100644drivers/net/mlx5/mlx5_testpmd.happ/test-pmd/testpmd.c index renamed from app/test-pmd/testpmd.c +0
-033d9b85..e1ac75a 100644
app/test-pmd/testpmd.c +3
-0@@ -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,14 @@ struct pmd_test_command {break ; printf("Received avail_thresh event, port:%d rxq_id:%d\n",app/test-pmd/testpmd.c struct pmd_test_command { · line 3673
Quoted 10 lines
app/test-pmd/testpmd.c +8
-0port_id, rxq_id); + +struct rte_eth_dev_info dev_info; +if (rte_eth_dev_info_get (port_id, &dev_info) !=0 || + (strncmp (dev_info.driver_name,"mlx5" ,4 ) !=0 )) +printf ("%s\n" , dev_info.driver_name); +#ifdef RTE_NET_MLX5 +mlx5_test_avail_thresh_event_handler (port_id, +rxq_id);#endif }Wanted to check the intend of above "if-statement". Currently i think only
print()is dependent on it.
Do we want to call mlx5event_handler, only ifdriver_nameis mlx5 ?
Quoted 4 lines
Quoted 3 lines
app/test-pmd/testpmd.c +0
-0break ;default :<snip>
Sorry, it is test code that I should remove. The check of mlx5 driver_name Is done in mlx5_test_avail_thresh_event_handler(), if the port is not mlx5 port, We simply return there.
Will update the patch soon, thanks for the catch!
PATCH v7 1/1 app/testpmd: add Host Shaper command
In reply to Spike Duthis patch is taken out from series of "introduce per-queue available descriptor threshold and host shaper" to simplify the review, and it's the last one for non-PMD change.
However it depends on a PMD commit for host shaper config API, should be merged after PMD patches.
--
v7:
- remove some test code.
Spike Du (1):
app/testpmd: add Host Shaper command
app/test-pmd/testpmd.c | 7 ++ doc/guides/nics/mlx5.rst | 46 +++++++++ drivers/net/mlx5/meson.build | 4 + drivers/net/mlx5/mlx5_testpmd.c | 206 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 289 insertions(+) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v7 1/1 app/testpmd: add Host Shaper command
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 | 206 ++++++++++++++++++++++++++++++++++++++++ drivers/net/mlx5/mlx5_testpmd.h | 26 +++++ 5 files changed, 289 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
@@ -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
@@ -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 +206 -0
206 lines not on this page · raw message
drivers/net/mlx5/mlx5_testpmd.h new file +26 -0
@@ -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
RE: [PATCH v7] app/testpmd: add Host Shaper command
From: Spike Du
Quoted 17 lines
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1> rate
<rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50
Quoted 5 lines
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.
Signed-off-by Spike Du <[email protected]>
Re: [PATCH v7] app/testpmd: add Host Shaper command
In reply to Spike DuFew comments below,
14/06/2022 14:01, Spike Du:
Quoted 23 lines
Add command line options to support host shaper configure.
- Command syntax:
mlx5 set port <port_id>host_shaperavail_thresh_triggered<0|1> rate
<rate_num>- Example commands:
To enableavail_thresh_triggeredon port 1 and disable current host shaper:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered1 rate 0To disable
avail_thresh_triggeredand current host shaper on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 0The rate unit is 100Mbps.
To disableavail_thresh_triggeredand configure a shaper of 5Gbps on port 1:
testpmd> mlx5 set port 1host_shaperavail_thresh_triggered0 rate 50Add 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.
Signed-off-by Spike Du <[email protected]>
[...]
app/test-pmd/testpmd.c struct pmd_test_command { · line 3668
Quoted 8 lines
app/test-pmd/testpmd.c +4
-0@@ -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
This function includes a check of the driver in use for the port, so I assume it is OK to call it unconditionally here.
[...]
doc/guides/nics/mlx5.rst which can be installed from OFED mstflint package. · line 1732
Quoted 2 lines
doc/guides/nics/mlx5.rst +2
-0+How to use available descriptor threshold and Host Shaper +------------------------------
Underlining should be of same size as the title.
Review struct pmd_test_command {
Quoted 2 lines
(quoted diff) +2
-0+ +There are sample command lines to configure available descriptor threshold in testpmd.
Simpler:
There is a command to configure available descriptor threshold in testpmd.
You could add a link here to the doc of the command.
doc/guides/nics/mlx5.rst which can be installed from OFED mstflint package. · line 1743
Quoted 9 lines
doc/guides/nics/mlx5.rst +9
-0+Testpmd also contains sample logic to handle available descriptor threshold event. +The typical workflow is: testpmd configure available descriptor threshold for Rx queues, enable +avail_thresh_triggered in host shaper and register a callback, when traffic from host is +too high and Rx queue emptiness is below available descriptor threshold, PMD receives an event and +firmware configures a 100Mbps shaper on host port automatically, then PMD call +the callback registered previously, which will delay a while to let Rx queue +empty, then disable host shaper. + +Let's assume we have a simple Blue Field 2 setup: port 0 is uplink, port 1
There's no space in BlueField.
doc/guides/nics/mlx5.rst which can be installed from OFED mstflint package. · line 1754
Quoted 11 lines
doc/guides/nics/mlx5.rst +11
-0+is VF representor. Each port has 2 Rx queues. +In order to control traffic from host to ARM, we can enable available descriptor threshold in testpmd by: + +.. code-block:: console + + testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 1 rate 0 + testpmd> set port 1 rxq 0 avail_thresh 70 + testpmd> set port 1 rxq 1 avail_thresh 70 + +The first command disables current host shaper, and enables available descriptor threshold triggered mode. +The left commands configure available descriptor threshold to 70% of Rx queue size for both Rx queues,
left -> other
doc/guides/nics/mlx5.rst which can be installed from OFED mstflint package. · line 1759
Quoted 5 lines
doc/guides/nics/mlx5.rst +5
-0+When traffic from host is too high, you can see testpmd console prints log +about available descriptor threshold event receiving, then host shaper is disabled. +The traffic rate from host is controlled and less drop happens in Rx queues. + +When disable available descriptor threshold and avail_thresh_triggered, we can invoke below commands in testpmd:
Reword:
The threshold event and shaper can be disabled like this:
Quoted 16 lines
doc/guides/nics/mlx5.rst +16
-0+ +.. code-block:: console + + testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 0 + testpmd> set port 1 rxq 0 avail_thresh 0 + testpmd> set port 1 rxq 1 avail_thresh 0 + +It's recommended an application disables available descriptor threshold and avail_thresh_triggered before exit, +if it enables them before. + +We can also configure the shaper with a value, the rate unit is 100Mbps, below +command sets current shaper to 5Gbps and disables avail_thresh_triggered. + +.. code-block:: console + + testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50
v8 cover introduce per-queue available descriptor threshold and host shaper
In reply to Spike Duavailable 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 | 4 + 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, 1064 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v8 1/6 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
v9 cover 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 | 4 + 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, 1064 insertions(+), 308 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v9 1/6 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1
v10 cover 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 drivers/net/mlx5/mlx5_testpmd.c create mode 100644 drivers/net/mlx5/mlx5_testpmd.h
Signature · 1 line
1.8.3.1
PATCH v10 1/6 net/mlx5: add LWM support for Rxq
Add lwm(Limit WaterMark) field to Rxq object which indicates the percentage of RX queue size used by HW to raise LWM event to the user. Allow LWM setting in modify_rq command.
Allow the LWM configuration dynamically by adding RDY2RDY state change.
--- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_devx.c | 13 ++++++++++++- drivers/net/mlx5/mlx5_devx.h | 1 + drivers/net/mlx5/mlx5_rx.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-)
drivers/net/mlx5/mlx5.h +1 -0
@@ -1395,6 +1395,7 @@ enum mlx5_rxq_modify_type {MLX5_RXQ_MOD_RST2RDY ,/* modify state from reset to ready. */ MLX5_RXQ_MOD_RDY2ERR ,/* modify state from ready to error. */ MLX5_RXQ_MOD_RDY2RST ,/* modify state from ready to reset. */ + MLX5_RXQ_MOD_RDY2RDY, /* modify state from ready to ready. */ }; enum mlx5_txq_modify_type {
drivers/net/mlx5/mlx5_devx.c +12 -1
@@ -62,7 +62,7 @@* @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type) {struct mlx5_devx_modify_rq_attr rq_attr;
@@ -76,6 +76,11 @@case MLX5_RXQ_MOD_RST2RDY : rq_attr.rq_state =MLX5_RQC_STATE_RST ; rq_attr.state =MLX5_RQC_STATE_RDY ; +if (rxq->lwm) { + rq_attr.modify_bitmask |= +MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; + }break ;case MLX5_RXQ_MOD_RDY2ERR : rq_attr.rq_state =MLX5_RQC_STATE_RDY ;
@@ -85,6 +90,12 @@ rq_attr.rq_state =MLX5_RQC_STATE_RDY ; rq_attr.state =MLX5_RQC_STATE_RST ;break ; +case MLX5_RXQ_MOD_RDY2RDY : + rq_attr.rq_state =MLX5_RQC_STATE_RDY ; + rq_attr.state =MLX5_RQC_STATE_RDY ; + rq_attr.modify_bitmask |=MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM ; + rq_attr.lwm = rxq->lwm; +break ;default :break ; }
drivers/net/mlx5/mlx5_devx.h +1 -0
@@ -11,6 +11,7 @@int mlx5_txq_devx_modify (struct mlx5_txq_obj *obj,enum mlx5_txq_modify_type type,uint8_t dev_port);void mlx5_txq_devx_obj_release (struct mlx5_txq_obj *txq_obj); +int mlx5_devx_modify_rq (struct mlx5_rxq_priv *rxq,uint8_t type);extern struct mlx5_obj_ops devx_obj_ops;
drivers/net/mlx5/mlx5_rx.h +1 -0
@@ -175,6 +175,7 @@ struct mlx5_rxq_priv {struct mlx5_devx_rq devx_rq;struct rte_eth_hairpin_conf hairpin_conf;/* Hairpin configuration. */ uint32_t hairpin_status;/* Hairpin binding status. */ + uint32_t lwm:16; };/* External RX queue descriptor. */
Signature · 1 line
1.8.3.1