diff --git a/drivers/common/mlx5/mlx5_devx_cmds.c b/drivers/common/mlx5/mlx5_devx_cmds.c
index 4d94f92..3a10ff0 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.c
+++ b/drivers/common/mlx5/mlx5_devx_cmds.c
@@ -285,6 +285,91 @@ struct mlx5_devx_obj *
 }
 
 /**
+ * Query NIC vDPA attributes.
+ *
+ * @param[in] ctx
+ *   ibv contexts returned from mlx5dv_open_device.
+ * @param[out] vdpa_attr
+ *   vDPA Attributes structure to fill.
+ */
+static void
+mlx5_devx_cmd_query_hca_vdpa_attr(struct ibv_context *ctx,
+				  struct mlx5_hca_vdpa_attr *vdpa_attr)
+{
+	uint32_t in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {0};
+	uint32_t out[MLX5_ST_SZ_DW(query_hca_cap_out)] = {0};
+	void *hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+	int status, syndrome, rc;
+
+	MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
+	MLX5_SET(query_hca_cap_in, in, op_mod,
+		 MLX5_GET_HCA_CAP_OP_MOD_VDPA_EMULATION |
+		 MLX5_HCA_CAP_OPMOD_GET_CUR);
+	rc = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+	status = MLX5_GET(query_hca_cap_out, out, status);
+	syndrome = MLX5_GET(query_hca_cap_out, out, syndrome);
+	if (rc || status) {
+		RTE_LOG(DEBUG, PMD, "Failed to query devx VDPA capabilities,"
+			" status %x, syndrome = %x", status, syndrome);
+		vdpa_attr->valid = 0;
+	} else {
+		vdpa_attr->valid = 1;
+		vdpa_attr->desc_tunnel_offload_type =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 desc_tunnel_offload_type);
+		vdpa_attr->eth_frame_offload_type =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 eth_frame_offload_type);
+		vdpa_attr->virtio_version_1_0 =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 virtio_version_1_0);
+		vdpa_attr->tso_ipv4 = MLX5_GET(virtio_emulation_cap, hcattr,
+					       tso_ipv4);
+		vdpa_attr->tso_ipv6 = MLX5_GET(virtio_emulation_cap, hcattr,
+					       tso_ipv6);
+		vdpa_attr->tx_csum = MLX5_GET(virtio_emulation_cap, hcattr,
+					      tx_csum);
+		vdpa_attr->rx_csum = MLX5_GET(virtio_emulation_cap, hcattr,
+					      rx_csum);
+		vdpa_attr->event_mode = MLX5_GET(virtio_emulation_cap, hcattr,
+						 event_mode);
+		vdpa_attr->virtio_queue_type =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 virtio_queue_type);
+		vdpa_attr->log_doorbell_stride =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 log_doorbell_stride);
+		vdpa_attr->log_doorbell_bar_size =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 log_doorbell_bar_size);
+		vdpa_attr->doorbell_bar_offset =
+			MLX5_GET64(virtio_emulation_cap, hcattr,
+				   doorbell_bar_offset);
+		vdpa_attr->max_num_virtio_queues =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 max_num_virtio_queues);
+		vdpa_attr->umem_1_buffer_param_a =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_1_buffer_param_a);
+		vdpa_attr->umem_1_buffer_param_b =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_1_buffer_param_b);
+		vdpa_attr->umem_2_buffer_param_a =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_2_buffer_param_a);
+		vdpa_attr->umem_2_buffer_param_b =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_2_buffer_param_a);
+		vdpa_attr->umem_3_buffer_param_a =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_3_buffer_param_a);
+		vdpa_attr->umem_3_buffer_param_b =
+			MLX5_GET(virtio_emulation_cap, hcattr,
+				 umem_3_buffer_param_b);
+	}
+}
+
+/**
  * Query HCA attributes.
  * Using those attributes we can check on run time if the device
  * is having the required capabilities.
@@ -343,6 +428,9 @@ struct mlx5_devx_obj *
 	attr->flex_parser_protocols = MLX5_GET(cmd_hca_cap, hcattr,
 					       flex_parser_protocols);
 	attr->qos.sup = MLX5_GET(cmd_hca_cap, hcattr, qos);
+	attr->vdpa.valid = !!(MLX5_GET64(cmd_hca_cap, hcattr,
+					 general_obj_types) &
+			      MLX5_GENERAL_OBJ_TYPES_CAP_VIRTQ_NET_Q);
 	if (attr->qos.sup) {
 		MLX5_SET(query_hca_cap_in, in, op_mod,
 			 MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP |
@@ -367,6 +455,8 @@ struct mlx5_devx_obj *
 		attr->qos.flow_meter_reg_share =
 			MLX5_GET(qos_cap, hcattr, flow_meter_reg_share);
 	}
+	if (attr->vdpa.valid)
+		mlx5_devx_cmd_query_hca_vdpa_attr(ctx, &attr->vdpa);
 	if (!attr->eth_net_offloads)
 		return 0;
 
diff --git a/drivers/common/mlx5/mlx5_devx_cmds.h b/drivers/common/mlx5/mlx5_devx_cmds.h
index 2d58d96..c1c9e99 100644
--- a/drivers/common/mlx5/mlx5_devx_cmds.h
+++ b/drivers/common/mlx5/mlx5_devx_cmds.h
@@ -34,6 +34,29 @@ struct mlx5_hca_qos_attr {
 
 };
 
+struct mlx5_hca_vdpa_attr {
+	uint8_t virtio_queue_type;
+	uint32_t valid:1;
+	uint32_t desc_tunnel_offload_type:1;
+	uint32_t eth_frame_offload_type:1;
+	uint32_t virtio_version_1_0:1;
+	uint32_t tso_ipv4:1;
+	uint32_t tso_ipv6:1;
+	uint32_t tx_csum:1;
+	uint32_t rx_csum:1;
+	uint32_t event_mode:3;
+	uint32_t log_doorbell_stride:5;
+	uint32_t log_doorbell_bar_size:5;
+	uint32_t max_num_virtio_queues;
+	uint32_t umem_1_buffer_param_a;
+	uint32_t umem_1_buffer_param_b;
+	uint32_t umem_2_buffer_param_a;
+	uint32_t umem_2_buffer_param_b;
+	uint32_t umem_3_buffer_param_a;
+	uint32_t umem_3_buffer_param_b;
+	uint64_t doorbell_bar_offset;
+};
+
 /* HCA supports this number of time periods for LRO. */
 #define MLX5_LRO_NUM_SUPP_PERIODS 4
 
@@ -62,6 +85,7 @@ struct mlx5_hca_attr {
 	uint32_t log_max_hairpin_num_packets:5;
 	uint32_t vhca_id:16;
 	struct mlx5_hca_qos_attr qos;
+	struct mlx5_hca_vdpa_attr vdpa;
 };
 
 struct mlx5_devx_wq_attr {
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index 5730ad1..efd6ad4 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -881,6 +881,11 @@ enum {
 	MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE = 0x0 << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_ETHERNET_OFFLOAD_CAPS = 0x1 << 1,
 	MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP = 0xc << 1,
+	MLX5_GET_HCA_CAP_OP_MOD_VDPA_EMULATION = 0x13 << 1,
+};
+
+enum {
+	MLX5_GENERAL_OBJ_TYPES_CAP_VIRTQ_NET_Q = (1ULL << 0xd),
 };
 
 enum {
@@ -1256,11 +1261,51 @@ struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
 	u8 reserved_at_200[0x600];
 };
 
+enum {
+	MLX5_VIRTQ_TYPE_SPLIT = 0,
+	MLX5_VIRTQ_TYPE_PACKED = 1,
+};
+
+enum {
+	MLX5_VIRTQ_EVENT_MODE_NO_MSIX = 0,
+	MLX5_VIRTQ_EVENT_MODE_QP = 1,
+	MLX5_VIRTQ_EVENT_MODE_MSIX = 2,
+};
+
+struct mlx5_ifc_virtio_emulation_cap_bits {
+	u8 desc_tunnel_offload_type[0x1];
+	u8 eth_frame_offload_type[0x1];
+	u8 virtio_version_1_0[0x1];
+	u8 tso_ipv4[0x1];
+	u8 tso_ipv6[0x1];
+	u8 tx_csum[0x1];
+	u8 rx_csum[0x1];
+	u8 reserved_at_7[0x1][0x9];
+	u8 event_mode[0x8];
+	u8 virtio_queue_type[0x8];
+	u8 reserved_at_20[0x13];
+	u8 log_doorbell_stride[0x5];
+	u8 reserved_at_3b[0x3];
+	u8 log_doorbell_bar_size[0x5];
+	u8 doorbell_bar_offset[0x40];
+	u8 reserved_at_80[0x8];
+	u8 max_num_virtio_queues[0x18];
+	u8 reserved_at_a0[0x60];
+	u8 umem_1_buffer_param_a[0x20];
+	u8 umem_1_buffer_param_b[0x20];
+	u8 umem_2_buffer_param_a[0x20];
+	u8 umem_2_buffer_param_b[0x20];
+	u8 umem_3_buffer_param_a[0x20];
+	u8 umem_3_buffer_param_b[0x20];
+	u8 reserved_at_1c0[0x620];
+};
+
 union mlx5_ifc_hca_cap_union_bits {
 	struct mlx5_ifc_cmd_hca_cap_bits cmd_hca_cap;
 	struct mlx5_ifc_per_protocol_networking_offload_caps_bits
 	       per_protocol_networking_offload_caps;
 	struct mlx5_ifc_qos_cap_bits qos_cap;
+	struct mlx5_ifc_virtio_emulation_cap_bits vdpa_caps;
 	u8 reserved_at_0[0x8000];
 };
 
