[PATCH v8 3/6] net/mlx5: add LWM event handling support
Spike Du
spiked at nvidia.com
Wed Jun 15 14:58:33 CEST 2022
When LWM meets RQ WQE, the kernel driver raises an event to SW.
Use devx event_channel to catch this and to notify the user.
Allocate this channel per shared device.
The channel has a cookie that informs the specific event port and queue.
Signed-off-by: Spike Du <spiked at nvidia.com>
---
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(+)
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index f098871..e04a666 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -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:
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 7ebb2cc..a76f2fe 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -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) \
diff --git a/drivers/net/mlx5/mlx5_devx.c b/drivers/net/mlx5/mlx5_devx.c
index c918a50..6886ae1 100644
--- a/drivers/net/mlx5/mlx5_devx.c
+++ b/drivers/net/mlx5/mlx5_devx.c
@@ -233,6 +233,52 @@
}
/**
+ * Get LWM event for shared context, return the correct port/rxq for this event.
+ *
+ * @param priv
+ * Mlx5_priv object.
+ * @param rxq_idx [out]
+ * Which rxq gets this event.
+ * @param port_id [out]
+ * Which port gets this event.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_rx_devx_get_event_lwm(struct mlx5_priv *priv, int *rxq_idx, int *port_id)
+{
+#ifdef HAVE_IBV_DEVX_EVENT
+ union {
+ struct mlx5dv_devx_async_event_hdr event_resp;
+ uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
+ } out;
+ int ret;
+
+ memset(&out, 0, sizeof(out));
+ ret = mlx5_glue->devx_get_event(priv->sh->devx_channel_lwm,
+ &out.event_resp,
+ sizeof(out.buf));
+ if (ret < 0) {
+ rte_errno = errno;
+ DRV_LOG(WARNING, "%s err\n", __func__);
+ return -rte_errno;
+ }
+ *port_id = (((uint32_t)out.event_resp.cookie) >>
+ LWM_COOKIE_PORTID_OFFSET) & LWM_COOKIE_PORTID_MASK;
+ *rxq_idx = (((uint32_t)out.event_resp.cookie) >>
+ LWM_COOKIE_RXQID_OFFSET) & LWM_COOKIE_RXQID_MASK;
+ return 0;
+#else
+ (void)priv;
+ (void)rxq_idx;
+ (void)port_id;
+ rte_errno = ENOTSUP;
+ return -rte_errno;
+#endif /* HAVE_IBV_DEVX_EVENT */
+}
+
+/**
* Create a RQ object using DevX.
*
* @param rxq
@@ -1421,6 +1467,7 @@ struct mlx5_obj_ops devx_obj_ops = {
.rxq_event_get = mlx5_rx_devx_get_event,
.rxq_obj_modify = mlx5_devx_modify_rq,
.rxq_obj_release = mlx5_rxq_devx_obj_release,
+ .rxq_event_get_lwm = mlx5_rx_devx_get_event_lwm,
.ind_table_new = mlx5_devx_ind_table_new,
.ind_table_modify = mlx5_devx_ind_table_modify,
.ind_table_destroy = mlx5_devx_ind_table_destroy,
diff --git a/drivers/net/mlx5/mlx5_rx.c b/drivers/net/mlx5/mlx5_rx.c
index e5eea0a..197d708 100644
--- a/drivers/net/mlx5/mlx5_rx.c
+++ b/drivers/net/mlx5/mlx5_rx.c
@@ -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);
+}
diff --git a/drivers/net/mlx5/mlx5_rx.h b/drivers/net/mlx5/mlx5_rx.h
index 25a5f2c..068dff5 100644
--- a/drivers/net/mlx5/mlx5_rx.h
+++ b/drivers/net/mlx5/mlx5_rx.h
@@ -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_ */
--
1.8.3.1
More information about the dev
mailing list