X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fvdpa%2Fmlx5%2Fmlx5_vdpa_virtq.c;h=3e6126492b38eb109a7135fef3417c94b8811e22;hb=9c99878aa1b16de26fcce82c112b401766dd910e;hp=32a13ceba76e0608cde7cf1dd751090138b517f9;hpb=62c813706e41f8f6ca5672fcea0f6f0be6d905a4;p=dpdk.git diff --git a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c index 32a13ceba7..3e6126492b 100644 --- a/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c +++ b/drivers/vdpa/mlx5/mlx5_vdpa_virtq.c @@ -36,6 +36,17 @@ mlx5_vdpa_virtq_handler(void *cb_arg) break; } while (1); rte_write32(virtq->index, priv->virtq_db_addr); + if (virtq->notifier_state == MLX5_VDPA_NOTIFIER_STATE_DISABLED) { + if (rte_vhost_host_notifier_ctrl(priv->vid, virtq->index, true)) + virtq->notifier_state = MLX5_VDPA_NOTIFIER_STATE_ERR; + else + virtq->notifier_state = + MLX5_VDPA_NOTIFIER_STATE_ENABLED; + DRV_LOG(INFO, "Virtq %u notifier state is %s.", virtq->index, + virtq->notifier_state == + MLX5_VDPA_NOTIFIER_STATE_ENABLED ? "enabled" : + "disabled"); + } DRV_LOG(DEBUG, "Ring virtq %u doorbell.", virtq->index); } @@ -46,7 +57,7 @@ mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq) int retries = MLX5_VDPA_INTR_RETRIES; int ret = -EAGAIN; - if (virtq->intr_handle.fd) { + if (virtq->intr_handle.fd != -1) { while (retries-- && ret == -EAGAIN) { ret = rte_intr_callback_unregister(&virtq->intr_handle, mlx5_vdpa_virtq_handler, @@ -59,12 +70,11 @@ mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq) usleep(MLX5_VDPA_INTR_RETRIES_USEC); } } - memset(&virtq->intr_handle, 0, sizeof(virtq->intr_handle)); + virtq->intr_handle.fd = -1; } - if (virtq->virtq) { + if (virtq->virtq) claim_zero(mlx5_devx_cmd_destroy(virtq->virtq)); - virtq->virtq = NULL; - } + virtq->virtq = NULL; for (i = 0; i < RTE_DIM(virtq->umems); ++i) { if (virtq->umems[i].obj) claim_zero(mlx5_glue->devx_umem_dereg @@ -73,26 +83,24 @@ mlx5_vdpa_virtq_unset(struct mlx5_vdpa_virtq *virtq) rte_free(virtq->umems[i].buf); } memset(&virtq->umems, 0, sizeof(virtq->umems)); + if (virtq->counters) { + claim_zero(mlx5_devx_cmd_destroy(virtq->counters)); + virtq->counters = NULL; + } + memset(&virtq->reset, 0, sizeof(virtq->reset)); if (virtq->eqp.fw_qp) mlx5_vdpa_event_qp_destroy(&virtq->eqp); + virtq->notifier_state = MLX5_VDPA_NOTIFIER_STATE_DISABLED; return 0; } void mlx5_vdpa_virtqs_release(struct mlx5_vdpa_priv *priv) { - struct mlx5_vdpa_virtq *entry; - struct mlx5_vdpa_virtq *next; + int i; - entry = SLIST_FIRST(&priv->virtq_list); - while (entry) { - next = SLIST_NEXT(entry, next); - mlx5_vdpa_virtq_unset(entry); - SLIST_REMOVE(&priv->virtq_list, entry, mlx5_vdpa_virtq, next); - rte_free(entry); - entry = next; - } - SLIST_INIT(&priv->virtq_list); + for (i = 0; i < priv->nr_virtqs; i++) + mlx5_vdpa_virtq_unset(&priv->virtqs[i]); if (priv->tis) { claim_zero(mlx5_devx_cmd_destroy(priv->tis)); priv->tis = NULL; @@ -105,14 +113,11 @@ mlx5_vdpa_virtqs_release(struct mlx5_vdpa_priv *priv) claim_zero(munmap(priv->virtq_db_addr, priv->var->length)); priv->virtq_db_addr = NULL; } - if (priv->var) { - mlx5_glue->dv_free_var(priv->var); - priv->var = NULL; - } priv->features = 0; + priv->nr_virtqs = 0; } -static int +int mlx5_vdpa_virtq_modify(struct mlx5_vdpa_virtq *virtq, int state) { struct mlx5_devx_virtq_attr attr = { @@ -125,6 +130,33 @@ mlx5_vdpa_virtq_modify(struct mlx5_vdpa_virtq *virtq, int state) return mlx5_devx_cmd_modify_virtq(virtq->virtq, &attr); } +int +mlx5_vdpa_virtq_stop(struct mlx5_vdpa_priv *priv, int index) +{ + struct mlx5_devx_virtq_attr attr = {0}; + struct mlx5_vdpa_virtq *virtq = &priv->virtqs[index]; + int ret = mlx5_vdpa_virtq_modify(virtq, 0); + + if (ret) + return -1; + if (mlx5_devx_cmd_query_virtq(virtq->virtq, &attr)) { + DRV_LOG(ERR, "Failed to query virtq %d.", index); + return -1; + } + DRV_LOG(INFO, "Query vid %d vring %d: hw_available_idx=%d, " + "hw_used_index=%d", priv->vid, index, + attr.hw_available_index, attr.hw_used_index); + ret = rte_vhost_set_vring_base(priv->vid, index, + attr.hw_available_index, + attr.hw_used_index); + if (ret) { + DRV_LOG(ERR, "Failed to set virtq %d base.", index); + return -1; + } + DRV_LOG(DEBUG, "vid %u virtq %u was stopped.", priv->vid, index); + return 0; +} + static uint64_t mlx5_vdpa_hva_to_gpa(struct rte_vhost_memory *mem, uint64_t hva) { @@ -144,9 +176,9 @@ mlx5_vdpa_hva_to_gpa(struct rte_vhost_memory *mem, uint64_t hva) } static int -mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, - struct mlx5_vdpa_virtq *virtq, int index) +mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, int index) { + struct mlx5_vdpa_virtq *virtq = &priv->virtqs[index]; struct rte_vhost_vring vq; struct mlx5_devx_virtq_attr attr = {0}; uint64_t gpa; @@ -189,6 +221,16 @@ mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, DRV_LOG(INFO, "Virtq %d is, for sure, working by poll mode, no" " need event QPs and event mechanism.", index); } + if (priv->caps.queue_counters_valid) { + virtq->counters = mlx5_devx_cmd_create_virtio_q_counters + (priv->ctx); + if (!virtq->counters) { + DRV_LOG(ERR, "Failed to create virtq couners for virtq" + " %d.", index); + goto error; + } + attr.counters_obj_id = virtq->counters->id; + } /* Setup 3 UMEMs for each virtq. */ for (i = 0; i < RTE_DIM(virtq->umems); ++i) { virtq->umems[i].size = priv->caps.umems[i].a * vq.size + @@ -236,34 +278,53 @@ mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv, } attr.available_addr = gpa; } - rte_vhost_get_vring_base(priv->vid, index, &last_avail_idx, + ret = rte_vhost_get_vring_base(priv->vid, index, &last_avail_idx, &last_used_idx); - DRV_LOG(INFO, "vid %d: Init last_avail_idx=%d, last_used_idx=%d for " - "virtq %d.", priv->vid, last_avail_idx, last_used_idx, index); + if (ret) { + last_avail_idx = 0; + last_used_idx = 0; + DRV_LOG(WARNING, "Couldn't get vring base, idx are set to 0"); + } else { + DRV_LOG(INFO, "vid %d: Init last_avail_idx=%d, last_used_idx=%d for " + "virtq %d.", priv->vid, last_avail_idx, + last_used_idx, index); + } attr.hw_available_index = last_avail_idx; attr.hw_used_index = last_used_idx; attr.q_size = vq.size; attr.mkey = priv->gpa_mkey_index; attr.tis_id = priv->tis->id; attr.queue_index = index; + attr.pd = priv->pdn; virtq->virtq = mlx5_devx_cmd_create_virtq(priv->ctx, &attr); virtq->priv = priv; if (!virtq->virtq) goto error; + claim_zero(rte_vhost_enable_guest_notification(priv->vid, index, 1)); if (mlx5_vdpa_virtq_modify(virtq, 1)) goto error; - virtq->enable = 1; + virtq->priv = priv; + rte_write32(virtq->index, priv->virtq_db_addr); + /* Setup doorbell mapping. */ virtq->intr_handle.fd = vq.kickfd; - virtq->intr_handle.type = RTE_INTR_HANDLE_EXT; - if (rte_intr_callback_register(&virtq->intr_handle, - mlx5_vdpa_virtq_handler, virtq)) { - virtq->intr_handle.fd = 0; - DRV_LOG(ERR, "Failed to register virtq %d interrupt.", index); - goto error; + if (virtq->intr_handle.fd == -1) { + DRV_LOG(WARNING, "Virtq %d kickfd is invalid.", index); } else { - DRV_LOG(DEBUG, "Register fd %d interrupt for virtq %d.", - virtq->intr_handle.fd, index); + virtq->intr_handle.type = RTE_INTR_HANDLE_EXT; + if (rte_intr_callback_register(&virtq->intr_handle, + mlx5_vdpa_virtq_handler, + virtq)) { + virtq->intr_handle.fd = -1; + DRV_LOG(ERR, "Failed to register virtq %d interrupt.", + index); + goto error; + } else { + DRV_LOG(DEBUG, "Register fd %d interrupt for virtq %d.", + virtq->intr_handle.fd, index); + } } + DRV_LOG(DEBUG, "vid %u virtq %u was created successfully.", priv->vid, + index); return 0; error: mlx5_vdpa_virtq_unset(virtq); @@ -329,7 +390,6 @@ int mlx5_vdpa_virtqs_prepare(struct mlx5_vdpa_priv *priv) { struct mlx5_devx_tis_attr tis_attr = {0}; - struct mlx5_vdpa_virtq *virtq; uint32_t i; uint16_t nr_vring = rte_vhost_get_vring_num(priv->vid); int ret = rte_vhost_get_negotiated_features(priv->vid, &priv->features); @@ -338,9 +398,10 @@ mlx5_vdpa_virtqs_prepare(struct mlx5_vdpa_priv *priv) DRV_LOG(ERR, "Failed to configure negotiated features."); return -1; } - priv->var = mlx5_glue->dv_alloc_var(priv->ctx, 0); - if (!priv->var) { - DRV_LOG(ERR, "Failed to allocate VAR %u.\n", errno); + if (nr_vring > priv->caps.max_num_virtio_queues * 2) { + DRV_LOG(ERR, "Do not support more than %d virtqs(%d).", + (int)priv->caps.max_num_virtio_queues * 2, + (int)nr_vring); return -1; } /* Always map the entire page. */ @@ -366,18 +427,160 @@ mlx5_vdpa_virtqs_prepare(struct mlx5_vdpa_priv *priv) DRV_LOG(ERR, "Failed to create TIS."); goto error; } - for (i = 0; i < nr_vring; i++) { - virtq = rte_zmalloc(__func__, sizeof(*virtq), 0); - if (!virtq || mlx5_vdpa_virtq_setup(priv, virtq, i)) { - if (virtq) - rte_free(virtq); - goto error; - } - SLIST_INSERT_HEAD(&priv->virtq_list, virtq, next); - } priv->nr_virtqs = nr_vring; + for (i = 0; i < nr_vring; i++) + if (priv->virtqs[i].enable && mlx5_vdpa_virtq_setup(priv, i)) + goto error; return 0; error: mlx5_vdpa_virtqs_release(priv); return -1; } + +static int +mlx5_vdpa_virtq_is_modified(struct mlx5_vdpa_priv *priv, + struct mlx5_vdpa_virtq *virtq) +{ + struct rte_vhost_vring vq; + int ret = rte_vhost_get_vhost_vring(priv->vid, virtq->index, &vq); + + if (ret) + return -1; + if (vq.size != virtq->vq_size || vq.kickfd != virtq->intr_handle.fd) + return 1; + if (virtq->eqp.cq.cq) { + if (vq.callfd != virtq->eqp.cq.callfd) + return 1; + } else if (vq.callfd != -1) { + return 1; + } + return 0; +} + +int +mlx5_vdpa_virtq_enable(struct mlx5_vdpa_priv *priv, int index, int enable) +{ + struct mlx5_vdpa_virtq *virtq = &priv->virtqs[index]; + int ret; + + DRV_LOG(INFO, "Update virtq %d status %sable -> %sable.", index, + virtq->enable ? "en" : "dis", enable ? "en" : "dis"); + if (!priv->configured) { + virtq->enable = !!enable; + return 0; + } + if (virtq->enable == !!enable) { + if (!enable) + return 0; + ret = mlx5_vdpa_virtq_is_modified(priv, virtq); + if (ret < 0) { + DRV_LOG(ERR, "Virtq %d modify check failed.", index); + return -1; + } + if (ret == 0) + return 0; + DRV_LOG(INFO, "Virtq %d was modified, recreate it.", index); + } + if (virtq->virtq) { + ret = mlx5_vdpa_virtq_stop(priv, index); + if (ret) + DRV_LOG(WARNING, "Failed to stop virtq %d.", index); + mlx5_vdpa_virtq_unset(virtq); + } + if (enable) { + ret = mlx5_vdpa_virtq_setup(priv, index); + if (ret) { + DRV_LOG(ERR, "Failed to setup virtq %d.", index); + return ret; + } + } + virtq->enable = !!enable; + if (is_virtq_recvq(virtq->index, priv->nr_virtqs)) { + /* Need to add received virtq to the RQT table of the TIRs. */ + ret = mlx5_vdpa_steer_update(priv); + if (ret) { + virtq->enable = !enable; + return ret; + } + } + return 0; +} + +int +mlx5_vdpa_virtq_stats_get(struct mlx5_vdpa_priv *priv, int qid, + struct rte_vdpa_stat *stats, unsigned int n) +{ + struct mlx5_vdpa_virtq *virtq = &priv->virtqs[qid]; + struct mlx5_devx_virtio_q_couners_attr attr = {0}; + int ret; + + if (!virtq->virtq || !virtq->enable) { + DRV_LOG(ERR, "Failed to read virtq %d statistics - virtq " + "is invalid.", qid); + return -EINVAL; + } + MLX5_ASSERT(virtq->counters); + ret = mlx5_devx_cmd_query_virtio_q_counters(virtq->counters, &attr); + if (ret) { + DRV_LOG(ERR, "Failed to read virtq %d stats from HW.", qid); + return ret; + } + ret = (int)RTE_MIN(n, (unsigned int)MLX5_VDPA_STATS_MAX); + if (ret == MLX5_VDPA_STATS_RECEIVED_DESCRIPTORS) + return ret; + stats[MLX5_VDPA_STATS_RECEIVED_DESCRIPTORS] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_RECEIVED_DESCRIPTORS, + .value = attr.received_desc - virtq->reset.received_desc, + }; + if (ret == MLX5_VDPA_STATS_COMPLETED_DESCRIPTORS) + return ret; + stats[MLX5_VDPA_STATS_COMPLETED_DESCRIPTORS] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_COMPLETED_DESCRIPTORS, + .value = attr.completed_desc - virtq->reset.completed_desc, + }; + if (ret == MLX5_VDPA_STATS_BAD_DESCRIPTOR_ERRORS) + return ret; + stats[MLX5_VDPA_STATS_BAD_DESCRIPTOR_ERRORS] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_BAD_DESCRIPTOR_ERRORS, + .value = attr.bad_desc_errors - virtq->reset.bad_desc_errors, + }; + if (ret == MLX5_VDPA_STATS_EXCEED_MAX_CHAIN) + return ret; + stats[MLX5_VDPA_STATS_EXCEED_MAX_CHAIN] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_EXCEED_MAX_CHAIN, + .value = attr.exceed_max_chain - virtq->reset.exceed_max_chain, + }; + if (ret == MLX5_VDPA_STATS_INVALID_BUFFER) + return ret; + stats[MLX5_VDPA_STATS_INVALID_BUFFER] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_INVALID_BUFFER, + .value = attr.invalid_buffer - virtq->reset.invalid_buffer, + }; + if (ret == MLX5_VDPA_STATS_COMPLETION_ERRORS) + return ret; + stats[MLX5_VDPA_STATS_COMPLETION_ERRORS] = (struct rte_vdpa_stat) { + .id = MLX5_VDPA_STATS_COMPLETION_ERRORS, + .value = attr.error_cqes - virtq->reset.error_cqes, + }; + return ret; +} + +int +mlx5_vdpa_virtq_stats_reset(struct mlx5_vdpa_priv *priv, int qid) +{ + struct mlx5_vdpa_virtq *virtq = &priv->virtqs[qid]; + int ret; + + if (!virtq->virtq || !virtq->enable) { + DRV_LOG(ERR, "Failed to read virtq %d statistics - virtq " + "is invalid.", qid); + return -EINVAL; + } + MLX5_ASSERT(virtq->counters); + ret = mlx5_devx_cmd_query_virtio_q_counters(virtq->counters, + &virtq->reset); + if (ret) + DRV_LOG(ERR, "Failed to read virtq %d reset stats from HW.", + qid); + return ret; +}