+static struct mlx5_vdpa_priv *
+mlx5_vdpa_find_priv_resource_by_did(int did)
+{
+ struct mlx5_vdpa_priv *priv;
+ int found = 0;
+
+ pthread_mutex_lock(&priv_list_lock);
+ TAILQ_FOREACH(priv, &priv_list, next) {
+ if (did == priv->id) {
+ found = 1;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&priv_list_lock);
+ if (!found) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ rte_errno = EINVAL;
+ return NULL;
+ }
+ return priv;
+}
+
+static int
+mlx5_vdpa_get_queue_num(int did, uint32_t *queue_num)
+{
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -1;
+ }
+ *queue_num = priv->caps.max_num_virtio_queues;
+ return 0;
+}
+
+static int
+mlx5_vdpa_get_vdpa_features(int did, uint64_t *features)
+{
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -1;
+ }
+ *features = MLX5_VDPA_DEFAULT_FEATURES;
+ if (priv->caps.virtio_queue_type & (1 << MLX5_VIRTQ_TYPE_PACKED))
+ *features |= (1ULL << VIRTIO_F_RING_PACKED);
+ if (priv->caps.tso_ipv4)
+ *features |= (1ULL << VIRTIO_NET_F_HOST_TSO4);
+ if (priv->caps.tso_ipv6)
+ *features |= (1ULL << VIRTIO_NET_F_HOST_TSO6);
+ if (priv->caps.tx_csum)
+ *features |= (1ULL << VIRTIO_NET_F_CSUM);
+ if (priv->caps.rx_csum)
+ *features |= (1ULL << VIRTIO_NET_F_GUEST_CSUM);
+ if (priv->caps.virtio_version_1_0)
+ *features |= (1ULL << VIRTIO_F_VERSION_1);
+ return 0;
+}
+
+static int
+mlx5_vdpa_get_protocol_features(int did, uint64_t *features)
+{
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -1;
+ }
+ *features = MLX5_VDPA_PROTOCOL_FEATURES;
+ return 0;
+}
+
+static int
+mlx5_vdpa_set_vring_state(int vid, int vring, int state)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -EINVAL;
+ }
+ if (vring >= (int)priv->caps.max_num_virtio_queues * 2) {
+ DRV_LOG(ERR, "Too big vring id: %d.", vring);
+ return -E2BIG;
+ }
+ return mlx5_vdpa_virtq_enable(priv, vring, state);
+}
+
+static int
+mlx5_vdpa_direct_db_prepare(struct mlx5_vdpa_priv *priv)
+{
+ int ret;
+
+ if (priv->direct_notifier) {
+ ret = rte_vhost_host_notifier_ctrl(priv->vid, false);
+ if (ret != 0) {
+ DRV_LOG(INFO, "Direct HW notifier FD cannot be "
+ "destroyed for device %d: %d.", priv->vid, ret);
+ return -1;
+ }
+ priv->direct_notifier = 0;
+ }
+ ret = rte_vhost_host_notifier_ctrl(priv->vid, true);
+ if (ret != 0)
+ DRV_LOG(INFO, "Direct HW notifier FD cannot be configured for"
+ " device %d: %d.", priv->vid, ret);
+ else
+ priv->direct_notifier = 1;
+ return 0;
+}
+
+static int
+mlx5_vdpa_features_set(int vid)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+ uint64_t log_base, log_size;
+ uint64_t features;
+ int ret;
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -EINVAL;
+ }
+ ret = rte_vhost_get_negotiated_features(vid, &features);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to get negotiated features.");
+ return ret;
+ }
+ if (RTE_VHOST_NEED_LOG(features)) {
+ ret = rte_vhost_get_log_base(vid, &log_base, &log_size);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to get log base.");
+ return ret;
+ }
+ ret = mlx5_vdpa_dirty_bitmap_set(priv, log_base, log_size);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to set dirty bitmap.");
+ return ret;
+ }
+ DRV_LOG(INFO, "mlx5 vdpa: enabling dirty logging...");
+ ret = mlx5_vdpa_logging_enable(priv, 1);
+ if (ret) {
+ DRV_LOG(ERR, "Failed t enable dirty logging.");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int
+mlx5_vdpa_dev_close(int vid)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+ int ret = 0;
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -1;
+ }
+ if (priv->configured)
+ ret |= mlx5_vdpa_lm_log(priv);
+ mlx5_vdpa_cqe_event_unset(priv);
+ mlx5_vdpa_steer_unset(priv);
+ mlx5_vdpa_virtqs_release(priv);
+ mlx5_vdpa_event_qp_global_release(priv);
+ mlx5_vdpa_mem_dereg(priv);
+ priv->configured = 0;
+ priv->vid = 0;
+ DRV_LOG(INFO, "vDPA device %d was closed.", vid);
+ return ret;
+}
+
+static int
+mlx5_vdpa_dev_config(int vid)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -EINVAL;
+ }
+ if (priv->configured && mlx5_vdpa_dev_close(vid)) {
+ DRV_LOG(ERR, "Failed to reconfigure vid %d.", vid);
+ return -1;
+ }
+ priv->vid = vid;
+ if (mlx5_vdpa_mem_register(priv) || mlx5_vdpa_direct_db_prepare(priv) ||
+ mlx5_vdpa_virtqs_prepare(priv) || mlx5_vdpa_steer_setup(priv) ||
+ mlx5_vdpa_cqe_event_setup(priv)) {
+ mlx5_vdpa_dev_close(vid);
+ return -1;
+ }
+ priv->configured = 1;
+ DRV_LOG(INFO, "vDPA device %d was configured.", vid);
+ return 0;
+}
+
+static int
+mlx5_vdpa_get_device_fd(int vid)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -EINVAL;
+ }
+ return priv->ctx->cmd_fd;
+}
+
+static int
+mlx5_vdpa_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
+{
+ int did = rte_vhost_get_vdpa_device_id(vid);
+ struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
+
+ RTE_SET_USED(qid);
+ if (priv == NULL) {
+ DRV_LOG(ERR, "Invalid device id: %d.", did);
+ return -EINVAL;
+ }
+ if (!priv->var) {
+ DRV_LOG(ERR, "VAR was not created for device %d, is the device"
+ " configured?.", did);
+ return -EINVAL;
+ }
+ *offset = priv->var->mmap_off;
+ *size = priv->var->length;
+ return 0;
+}
+