TAILQ_HEAD_INITIALIZER(priv_list);
static pthread_mutex_t priv_list_lock = PTHREAD_MUTEX_INITIALIZER;
+struct mlx5_vdpa_conf_thread_mng conf_thread_mng;
+
static void mlx5_vdpa_dev_release(struct mlx5_vdpa_priv *priv);
static struct mlx5_vdpa_priv *
DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
return -1;
}
- *queue_num = priv->caps.max_num_virtio_queues;
+ *queue_num = priv->caps.max_num_virtio_queues / 2;
return 0;
}
struct rte_vdpa_device *vdev = rte_vhost_get_vdpa_device(vid);
struct mlx5_vdpa_priv *priv =
mlx5_vdpa_find_priv_resource_by_vdev(vdev);
+ struct mlx5_vdpa_virtq *virtq;
int ret;
if (priv == NULL) {
DRV_LOG(ERR, "Invalid vDPA device: %s.", vdev->device->name);
return -EINVAL;
}
- if (vring >= (int)priv->caps.max_num_virtio_queues * 2) {
+ if (vring >= (int)priv->caps.max_num_virtio_queues) {
DRV_LOG(ERR, "Too big vring id: %d.", vring);
return -E2BIG;
}
- pthread_mutex_lock(&priv->vq_config_lock);
+ virtq = &priv->virtqs[vring];
+ pthread_mutex_lock(&virtq->virtq_lock);
ret = mlx5_vdpa_virtq_enable(priv, vring, state);
- pthread_mutex_unlock(&priv->vq_config_lock);
+ pthread_mutex_unlock(&virtq->virtq_lock);
return ret;
}
static void
mlx5_vdpa_dev_cache_clean(struct mlx5_vdpa_priv *priv)
{
- mlx5_vdpa_virtqs_cleanup(priv);
+ /* Clean pre-created resource in dev removal only. */
+ if (!priv->queues)
+ mlx5_vdpa_virtqs_cleanup(priv);
mlx5_vdpa_mem_dereg(priv);
}
ret |= mlx5_vdpa_lm_log(priv);
priv->state = MLX5_VDPA_STATE_IN_PROGRESS;
}
+ pthread_mutex_lock(&priv->steer_update_lock);
mlx5_vdpa_steer_unset(priv);
+ pthread_mutex_unlock(&priv->steer_update_lock);
mlx5_vdpa_virtqs_release(priv);
+ mlx5_vdpa_drain_cq(priv);
if (priv->lm_mr.addr)
mlx5_os_wrapped_mkey_destroy(&priv->lm_mr);
priv->state = MLX5_VDPA_STATE_PROBED;
if (!priv->connected)
mlx5_vdpa_dev_cache_clean(priv);
priv->vid = 0;
- /* The mutex may stay locked after event thread cancel - initiate it. */
- pthread_mutex_init(&priv->vq_config_lock, NULL);
DRV_LOG(INFO, "vDPA device %d was closed.", vid);
return ret;
}
DRV_LOG(ERR, "Invalid device: %s.", vdev->device->name);
return -ENODEV;
}
- if (qid >= (int)priv->caps.max_num_virtio_queues * 2) {
+ if (qid >= (int)priv->caps.max_num_virtio_queues) {
DRV_LOG(ERR, "Too big vring id: %d for device %s.", qid,
vdev->device->name);
return -E2BIG;
DRV_LOG(ERR, "Invalid device: %s.", vdev->device->name);
return -ENODEV;
}
- if (qid >= (int)priv->caps.max_num_virtio_queues * 2) {
+ if (qid >= (int)priv->caps.max_num_virtio_queues) {
DRV_LOG(ERR, "Too big vring id: %d for device %s.", qid,
vdev->device->name);
return -E2BIG;
DRV_LOG(WARNING, "Invalid event_core %s.", val);
else
priv->event_core = tmp;
+ } else if (strcmp(key, "max_conf_threads") == 0) {
+ if (tmp) {
+ priv->use_c_thread = true;
+ if (!conf_thread_mng.initializer_priv) {
+ conf_thread_mng.initializer_priv = priv;
+ if (tmp > MLX5_VDPA_MAX_C_THRD) {
+ DRV_LOG(WARNING,
+ "Invalid max_conf_threads %s "
+ "and set max_conf_threads to %d",
+ val, MLX5_VDPA_MAX_C_THRD);
+ tmp = MLX5_VDPA_MAX_C_THRD;
+ }
+ conf_thread_mng.max_thrds = tmp;
+ } else if (tmp != conf_thread_mng.max_thrds) {
+ DRV_LOG(WARNING,
+ "max_conf_threads is PMD argument and not per device, "
+ "only the first device configuration set it, current value is %d "
+ "and will not be changed to %d.",
+ conf_thread_mng.max_thrds, (int)tmp);
+ }
+ } else {
+ priv->use_c_thread = false;
+ }
} else if (strcmp(key, "hw_latency_mode") == 0) {
priv->hw_latency_mode = (uint32_t)tmp;
} else if (strcmp(key, "hw_max_latency_us") == 0) {
priv->hw_max_latency_us = (uint32_t)tmp;
} else if (strcmp(key, "hw_max_pending_comp") == 0) {
priv->hw_max_pending_comp = (uint32_t)tmp;
+ } else if (strcmp(key, "queue_size") == 0) {
+ priv->queue_size = (uint16_t)tmp;
+ } else if (strcmp(key, "queues") == 0) {
+ priv->queues = (uint16_t)tmp;
+ } else {
+ DRV_LOG(WARNING, "Invalid key %s.", key);
}
return 0;
}
"hw_max_latency_us",
"hw_max_pending_comp",
"no_traffic_time",
+ "queue_size",
+ "queues",
+ "max_conf_threads",
NULL,
};
if (!priv->event_us &&
priv->event_mode == MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER)
priv->event_us = MLX5_VDPA_DEFAULT_TIMER_STEP_US;
+ if ((priv->queue_size && !priv->queues) ||
+ (!priv->queue_size && priv->queues)) {
+ priv->queue_size = 0;
+ priv->queues = 0;
+ DRV_LOG(WARNING, "Please provide both queue_size and queues.");
+ }
DRV_LOG(DEBUG, "event mode is %d.", priv->event_mode);
DRV_LOG(DEBUG, "event_us is %u us.", priv->event_us);
DRV_LOG(DEBUG, "no traffic max is %u.", priv->no_traffic_max);
+ DRV_LOG(DEBUG, "queues is %u, queue_size is %u.", priv->queues,
+ priv->queue_size);
+}
+
+static int
+mlx5_vdpa_virtq_resource_prepare(struct mlx5_vdpa_priv *priv)
+{
+ struct mlx5_vdpa_virtq *virtq;
+ uint32_t index;
+ uint32_t i;
+
+ for (index = 0; index < priv->caps.max_num_virtio_queues * 2;
+ index++) {
+ virtq = &priv->virtqs[index];
+ pthread_mutex_init(&virtq->virtq_lock, NULL);
+ }
+ if (!priv->queues)
+ return 0;
+ for (index = 0; index < (priv->queues * 2); ++index) {
+ virtq = &priv->virtqs[index];
+ int ret = mlx5_vdpa_event_qp_prepare(priv, priv->queue_size,
+ -1, virtq);
+
+ if (ret) {
+ DRV_LOG(ERR, "Failed to create event QPs for virtq %d.",
+ index);
+ return -1;
+ }
+ if (priv->caps.queue_counters_valid) {
+ if (!virtq->counters)
+ virtq->counters =
+ mlx5_devx_cmd_create_virtio_q_counters
+ (priv->cdev->ctx);
+ if (!virtq->counters) {
+ DRV_LOG(ERR, "Failed to create virtq couners for virtq"
+ " %d.", index);
+ return -1;
+ }
+ }
+ for (i = 0; i < RTE_DIM(virtq->umems); ++i) {
+ uint32_t size;
+ void *buf;
+ struct mlx5dv_devx_umem *obj;
+
+ size = priv->caps.umems[i].a * priv->queue_size +
+ priv->caps.umems[i].b;
+ buf = rte_zmalloc(__func__, size, 4096);
+ if (buf == NULL) {
+ DRV_LOG(ERR, "Cannot allocate umem %d memory for virtq"
+ " %u.", i, index);
+ return -1;
+ }
+ obj = mlx5_glue->devx_umem_reg(priv->cdev->ctx, buf,
+ size, IBV_ACCESS_LOCAL_WRITE);
+ if (obj == NULL) {
+ rte_free(buf);
+ DRV_LOG(ERR, "Failed to register umem %d for virtq %u.",
+ i, index);
+ return -1;
+ }
+ virtq->umems[i].size = size;
+ virtq->umems[i].buf = buf;
+ virtq->umems[i].obj = obj;
+ }
+ }
+ return 0;
}
static int
return -rte_errno;
if (mlx5_vdpa_event_qp_global_prepare(priv))
return -rte_errno;
+ if (mlx5_vdpa_virtq_resource_prepare(priv))
+ return -rte_errno;
return 0;
}
DRV_LOG(DEBUG, "No capability to support virtq statistics.");
priv = rte_zmalloc("mlx5 vDPA device private", sizeof(*priv) +
sizeof(struct mlx5_vdpa_virtq) *
- attr->vdpa.max_num_virtio_queues * 2,
+ attr->vdpa.max_num_virtio_queues,
RTE_CACHE_LINE_SIZE);
if (!priv) {
DRV_LOG(ERR, "Failed to allocate private memory.");
priv->num_lag_ports = attr->num_lag_ports;
if (attr->num_lag_ports == 0)
priv->num_lag_ports = 1;
- pthread_mutex_init(&priv->vq_config_lock, NULL);
+ rte_spinlock_init(&priv->db_lock);
+ pthread_mutex_init(&priv->steer_update_lock, NULL);
priv->cdev = cdev;
+ mlx5_vdpa_config_get(mkvlist, priv);
+ if (priv->use_c_thread) {
+ if (conf_thread_mng.initializer_priv == priv)
+ if (mlx5_vdpa_mult_threads_create(priv->event_core))
+ goto error;
+ __atomic_fetch_add(&conf_thread_mng.refcnt, 1,
+ __ATOMIC_RELAXED);
+ }
if (mlx5_vdpa_create_dev_resources(priv))
goto error;
priv->vdev = rte_vdpa_register_device(cdev->dev, &mlx5_vdpa_ops);
rte_errno = rte_errno ? rte_errno : EINVAL;
goto error;
}
- mlx5_vdpa_config_get(mkvlist, priv);
SLIST_INIT(&priv->mr_list);
pthread_mutex_lock(&priv_list_lock);
TAILQ_INSERT_TAIL(&priv_list, priv, next);
pthread_mutex_unlock(&priv_list_lock);
return 0;
error:
+ if (conf_thread_mng.initializer_priv == priv)
+ mlx5_vdpa_mult_threads_destroy(false);
if (priv)
mlx5_vdpa_dev_release(priv);
return -rte_errno;
{
uint32_t i;
+ if (priv->queues)
+ mlx5_vdpa_virtqs_cleanup(priv);
mlx5_vdpa_dev_cache_clean(priv);
- for (i = 0; i < priv->caps.max_num_virtio_queues * 2; i++) {
+ for (i = 0; i < priv->caps.max_num_virtio_queues; i++) {
if (!priv->virtqs[i].counters)
continue;
claim_zero(mlx5_devx_cmd_destroy(priv->virtqs[i].counters));
mlx5_vdpa_release_dev_resources(priv);
if (priv->vdev)
rte_vdpa_unregister_device(priv->vdev);
- pthread_mutex_destroy(&priv->vq_config_lock);
+ if (priv->use_c_thread)
+ if (__atomic_fetch_sub(&conf_thread_mng.refcnt,
+ 1, __ATOMIC_RELAXED) == 1)
+ mlx5_vdpa_mult_threads_destroy(true);
rte_free(priv);
}