net/mlx5: handle Rx descriptor LWM event
authorSpike Du <spiked@nvidia.com>
Thu, 16 Jun 2022 08:41:51 +0000 (11:41 +0300)
committerRaslan Darawsheh <rasland@nvidia.com>
Thu, 23 Jun 2022 15:25:00 +0000 (17:25 +0200)
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@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_devx.c
drivers/net/mlx5/mlx5_rx.c
drivers/net/mlx5/mlx5_rx.h

index f098871..e04a666 100644 (file)
@@ -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 @@ error:
        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:
index 7ebb2cc..a76f2fe 100644 (file)
@@ -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) \
index c918a50..6886ae1 100644 (file)
@@ -232,6 +232,52 @@ mlx5_rx_devx_get_event(struct mlx5_rxq_obj *rxq_obj)
 #endif /* HAVE_IBV_DEVX_EVENT */
 }
 
+/**
+ * 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.
  *
@@ -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,
index e5eea0a..197d708 100644 (file)
@@ -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_AVAIL_THRESH, NULL);
+}
index 25a5f2c..068dff5 100644 (file)
@@ -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_ */