]> git.droids-corp.org - dpdk.git/commitdiff
net/mlx5: support Rx descriptor threshold event
authorSpike Du <spiked@nvidia.com>
Thu, 16 Jun 2022 08:41:52 +0000 (11:41 +0300)
committerRaslan Darawsheh <rasland@nvidia.com>
Thu, 23 Jun 2022 15:25:02 +0000 (17:25 +0200)
Add mlx5 specific available descriptor threshold configuration
and query handler.
In mlx5 PMD, available descriptor threshold is also called
LWM (limit watermark).
While the Rx queue fullness reaches the LWM limit, the driver catches
an HW event and invokes the user callback.
The query handler finds the next Rx queue with pending LWM event
if any, starting from the given Rx queue index.

Signed-off-by: Spike Du <spiked@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
doc/guides/nics/mlx5.rst
doc/guides/rel_notes/release_22_07.rst
drivers/common/mlx5/mlx5_prm.h
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5_rx.c
drivers/net/mlx5/mlx5_rx.h

index 73ed28ffaf68d1c46817ea5c797f02d2abfc76eb..f15c04f1e551d4b53a53049a8274e1555b719efa 100644 (file)
@@ -38,6 +38,7 @@ Features
 - Multiple TX and RX queues.
 - Shared Rx queue.
 - Rx queue delay drop.
+- Rx queue available descriptor threshold event.
 - Support steering for external Rx queue created outside the PMD.
 - Support for scattered TX frames.
 - Advanced support for scattered Rx frames with tunable buffer attributes.
@@ -132,6 +133,10 @@ Limitations
   - Counters of received packets and bytes number of devices in same share group are same.
   - Counters of received packets and bytes number of queues in same group and queue ID are same.
 
+- Available descriptor threshold event:
+
+  - Does not support shared Rx queue and hairpin Rx queue.
+
 - When using Verbs flow engine (``dv_flow_en`` = 0), flow pattern without any
   specific VLAN will match for VLAN packets as well:
 
index a94cd3a298098b0cb7c1bf246ed9031be70d00c1..24036c7b190096ef1342fe457af8b3899eb534fb 100644 (file)
@@ -170,6 +170,7 @@ New Features
   * Added matching and RSS on IPsec ESP.
   * Added matching on represented port.
   * Added support for modifying ECN field of IPv4/IPv6.
+  * Added Rx queue available descriptor threshold support.
 
 * **Updated Netronome nfp driver.**
 
index d5d1bb2f4202b8670581a341649c8209e452aac8..a1ef83333bbf525bc15155fded7eac3ca3fe7cb0 100644 (file)
@@ -3365,6 +3365,7 @@ struct mlx5_aso_wqe {
 
 enum {
        MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+       MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED = 0x14,
 };
 
 enum {
index e04a66625e0ceab39777afeb13659ddd17e1262b..998846adbed910908533d4fdfd91ade56b86c8be 100644 (file)
@@ -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_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,
index 197d708bd93a8c4c469b42e447a117d155c7cfc4..2cb70063c59406a3b15f292cb4954c4a7447b04c 100644 (file)
@@ -25,6 +25,7 @@
 #include "mlx5.h"
 #include "mlx5_utils.h"
 #include "mlx5_rxtx.h"
+#include "mlx5_devx.h"
 #include "mlx5_rx.h"
 
 
@@ -128,6 +129,16 @@ mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
        return RTE_ETH_RX_DESC_AVAIL;
 }
 
+/* Get rxq lwm percentage according to lwm number. */
+static uint8_t
+mlx5_rxq_lwm_to_percentage(struct mlx5_rxq_priv *rxq)
+{
+       struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq;
+       uint32_t wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
+
+       return rxq->lwm * 100 / wqe_cnt;
+}
+
 /**
  * DPDK callback to get the RX queue information.
  *
@@ -150,6 +161,7 @@ mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
 {
        struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, rx_queue_id);
        struct mlx5_rxq_data *rxq = mlx5_rxq_data_get(dev, rx_queue_id);
+       struct mlx5_rxq_priv *rxq_priv = mlx5_rxq_get(dev, rx_queue_id);
 
        if (!rxq)
                return;
@@ -169,6 +181,8 @@ mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
        qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ?
                RTE_BIT32(rxq->elts_n) * RTE_BIT32(rxq->log_strd_num) :
                RTE_BIT32(rxq->elts_n);
+       qinfo->avail_thresh = rxq_priv ?
+               mlx5_rxq_lwm_to_percentage(rxq_priv) : 0;
 }
 
 /**
@@ -1188,6 +1202,34 @@ mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused)
        return -ENOTSUP;
 }
 
+int
+mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev,
+                       uint16_t *queue_id, uint8_t *lwm)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       unsigned int rxq_id, found = 0, n;
+       struct mlx5_rxq_priv *rxq;
+
+       if (!queue_id)
+               return -EINVAL;
+       /* Query all the Rx queues of the port in a circular way. */
+       for (rxq_id = *queue_id, n = 0; n < priv->rxqs_n; n++) {
+               rxq = mlx5_rxq_get(dev, rxq_id);
+               if (rxq && rxq->lwm_event_pending) {
+                       pthread_mutex_lock(&priv->sh->lwm_config_lock);
+                       rxq->lwm_event_pending = 0;
+                       pthread_mutex_unlock(&priv->sh->lwm_config_lock);
+                       *queue_id = rxq_id;
+                       found = 1;
+                       if (lwm)
+                               *lwm =  mlx5_rxq_lwm_to_percentage(rxq);
+                       break;
+               }
+               rxq_id = (rxq_id + 1) % priv->rxqs_n;
+       }
+       return found;
+}
+
 /**
  * Rte interrupt handler for LWM event.
  * It first checks if the event arrives, if so process the callback for
@@ -1220,3 +1262,112 @@ mlx5_dev_interrupt_handler_lwm(void *args)
        }
        rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
 }
+
+/**
+ * DPDK callback to arm an Rx queue LWM(limit watermark) event.
+ * While the Rx queue fullness reaches the LWM limit, the driver catches
+ * an HW event and invokes the user event callback.
+ * After the last event handling, the user needs to call this API again
+ * to arm an additional event.
+ *
+ * @param dev
+ *   Pointer to the device structure.
+ * @param[in] rx_queue_id
+ *   Rx queue identificator.
+ * @param[in] lwm
+ *   The LWM value, is defined by a percentage of the Rx queue size.
+ *   [1-99] to set a new LWM (update the old value).
+ *   0 to unarm the event.
+ *
+ * @return
+ *   0 : operation success.
+ *   Otherwise:
+ *   - ENOMEM - not enough memory to create LWM event channel.
+ *   - EINVAL - the input Rxq is not created by devx.
+ *   - E2BIG  - lwm is bigger than 99.
+ */
+int
+mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+                     uint8_t lwm)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       uint16_t port_id = PORT_ID(priv);
+       struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id);
+       uint16_t event_nums[1] = {MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED};
+       struct mlx5_rxq_data *rxq_data;
+       uint32_t wqe_cnt;
+       uint64_t cookie;
+       int ret = 0;
+
+       if (!rxq) {
+               rte_errno = EINVAL;
+               return -rte_errno;
+       }
+       rxq_data = &rxq->ctrl->rxq;
+       /* Ensure the Rq is created by devx. */
+       if (priv->obj_ops.rxq_obj_new != devx_obj_ops.rxq_obj_new) {
+               rte_errno = EINVAL;
+               return -rte_errno;
+       }
+       if (lwm > 99) {
+               DRV_LOG(WARNING, "Too big LWM configuration.");
+               rte_errno = E2BIG;
+               return -rte_errno;
+       }
+       /* Start config LWM. */
+       pthread_mutex_lock(&priv->sh->lwm_config_lock);
+       if (rxq->lwm == 0 && lwm == 0) {
+               /* Both old/new values are 0, do nothing. */
+               ret = 0;
+               goto end;
+       }
+       wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
+       if (lwm) {
+               if (!priv->sh->devx_channel_lwm) {
+                       ret = mlx5_lwm_setup(priv);
+                       if (ret) {
+                               DRV_LOG(WARNING,
+                                       "Failed to create shared_lwm.");
+                               rte_errno = ENOMEM;
+                               ret = -rte_errno;
+                               goto end;
+                       }
+               }
+               if (!rxq->lwm_devx_subscribed) {
+                       cookie = ((uint32_t)
+                                 (port_id << LWM_COOKIE_PORTID_OFFSET)) |
+                               (rx_queue_id << LWM_COOKIE_RXQID_OFFSET);
+                       ret = mlx5_os_devx_subscribe_devx_event
+                               (priv->sh->devx_channel_lwm,
+                                rxq->devx_rq.rq->obj,
+                                sizeof(event_nums),
+                                event_nums,
+                                cookie);
+                       if (ret) {
+                               rte_errno = rte_errno ? rte_errno : EINVAL;
+                               ret = -rte_errno;
+                               goto end;
+                       }
+                       rxq->lwm_devx_subscribed = 1;
+               }
+       }
+       /* Save LWM to rxq and send modify_rq devx command. */
+       rxq->lwm = lwm * wqe_cnt / 100;
+       /* Prevent integer division loss when switch lwm number to percentage. */
+       if (lwm && (lwm * wqe_cnt % 100)) {
+               rxq->lwm = ((uint32_t)(rxq->lwm + 1) >= wqe_cnt) ?
+                       rxq->lwm : (rxq->lwm + 1);
+       }
+       if (lwm && !rxq->lwm) {
+               /* With mprq, wqe_cnt may be < 100. */
+               DRV_LOG(WARNING, "Too small LWM configuration.");
+               rte_errno = EINVAL;
+               ret = -rte_errno;
+               goto end;
+       }
+       ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RDY2RDY);
+end:
+       pthread_mutex_unlock(&priv->sh->lwm_config_lock);
+       return ret;
+}
+
index 068dff586322cd62d653b90277ba8030a8012c90..e078aaf3dc3e2273e3f3bc421763619da6bb5380 100644 (file)
@@ -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);