+ }
+ if (priv->timer_delay_us)
+ usleep(priv->timer_delay_us);
+ else
+ /* Give-up CPU to improve polling threads scheduling. */
+ sched_yield();
+}
+
+/* Notify virtio device for specific virtq new traffic. */
+static uint32_t
+mlx5_vdpa_queue_complete(struct mlx5_vdpa_cq *cq)
+{
+ uint32_t comp = 0;
+
+ if (cq->cq_obj.cq) {
+ comp = mlx5_vdpa_cq_poll(cq);
+ if (comp) {
+ if (cq->callfd != -1)
+ eventfd_write(cq->callfd, (eventfd_t)1);
+ cq->armed = 0;
+ }
+ }
+ return comp;
+}
+
+/* Notify virtio device for any virtq new traffic. */
+static uint32_t
+mlx5_vdpa_queues_complete(struct mlx5_vdpa_priv *priv)
+{
+ int i;
+ uint32_t max = 0;
+
+ for (i = 0; i < priv->nr_virtqs; i++) {
+ struct mlx5_vdpa_cq *cq = &priv->virtqs[i].eqp.cq;
+ uint32_t comp = mlx5_vdpa_queue_complete(cq);
+
+ if (comp > max)
+ max = comp;
+ }
+ return max;
+}
+
+/* Wait on all CQs channel for completion event. */
+static struct mlx5_vdpa_cq *
+mlx5_vdpa_event_wait(struct mlx5_vdpa_priv *priv __rte_unused)
+{
+#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 = mlx5_glue->devx_get_event(priv->eventc, &out.event_resp,
+ sizeof(out.buf));
+
+ if (ret >= 0)
+ return (struct mlx5_vdpa_cq *)(uintptr_t)out.event_resp.cookie;
+ DRV_LOG(INFO, "Got error in devx_get_event, ret = %d, errno = %d.",
+ ret, errno);
+#endif
+ return NULL;
+}
+
+static void *
+mlx5_vdpa_event_handle(void *arg)
+{
+ struct mlx5_vdpa_priv *priv = arg;
+ struct mlx5_vdpa_cq *cq;
+ uint32_t max;
+
+ switch (priv->event_mode) {
+ case MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER:
+ case MLX5_VDPA_EVENT_MODE_FIXED_TIMER:
+ priv->timer_delay_us = priv->event_us;
+ while (1) {
+ pthread_mutex_lock(&priv->vq_config_lock);
+ max = mlx5_vdpa_queues_complete(priv);
+ if (max == 0 && priv->no_traffic_counter++ >=
+ priv->no_traffic_max) {
+ DRV_LOG(DEBUG, "Device %s traffic was stopped.",
+ priv->vdev->device->name);
+ mlx5_vdpa_arm_all_cqs(priv);
+ do {
+ pthread_mutex_unlock
+ (&priv->vq_config_lock);
+ cq = mlx5_vdpa_event_wait(priv);
+ pthread_mutex_lock
+ (&priv->vq_config_lock);
+ if (cq == NULL ||
+ mlx5_vdpa_queue_complete(cq) > 0)
+ break;
+ } while (1);
+ priv->timer_delay_us = priv->event_us;
+ priv->no_traffic_counter = 0;
+ } else if (max != 0) {
+ priv->no_traffic_counter = 0;
+ }
+ pthread_mutex_unlock(&priv->vq_config_lock);
+ mlx5_vdpa_timer_sleep(priv, max);
+ }
+ return NULL;
+ case MLX5_VDPA_EVENT_MODE_ONLY_INTERRUPT:
+ do {
+ cq = mlx5_vdpa_event_wait(priv);
+ if (cq != NULL) {
+ pthread_mutex_lock(&priv->vq_config_lock);
+ if (mlx5_vdpa_queue_complete(cq) > 0)
+ mlx5_vdpa_cq_arm(priv, cq);
+ pthread_mutex_unlock(&priv->vq_config_lock);
+ }
+ } while (1);
+ return NULL;
+ default:
+ return NULL;
+ }