+static __rte_always_inline int
+async_channel_register(int vid, uint16_t queue_id,
+ struct rte_vhost_async_channel_ops *ops)
+{
+ struct virtio_net *dev = get_device(vid);
+ struct vhost_virtqueue *vq = dev->virtqueue[queue_id];
+ struct vhost_async *async;
+ int node = vq->numa_node;
+
+ if (unlikely(vq->async)) {
+ VHOST_LOG_CONFIG(ERR,
+ "(%s) async register failed: already registered (qid: %d)\n",
+ dev->ifname, queue_id);
+ return -1;
+ }
+
+ async = rte_zmalloc_socket(NULL, sizeof(struct vhost_async), 0, node);
+ if (!async) {
+ VHOST_LOG_CONFIG(ERR, "(%s) failed to allocate async metadata (qid: %d)\n",
+ dev->ifname, queue_id);
+ return -1;
+ }
+
+ async->pkts_info = rte_malloc_socket(NULL, vq->size * sizeof(struct async_inflight_info),
+ RTE_CACHE_LINE_SIZE, node);
+ if (!async->pkts_info) {
+ VHOST_LOG_CONFIG(ERR, "(%s) failed to allocate async_pkts_info (qid: %d)\n",
+ dev->ifname, queue_id);
+ goto out_free_async;
+ }
+
+ if (vq_is_packed(dev)) {
+ async->buffers_packed = rte_malloc_socket(NULL,
+ vq->size * sizeof(struct vring_used_elem_packed),
+ RTE_CACHE_LINE_SIZE, node);
+ if (!async->buffers_packed) {
+ VHOST_LOG_CONFIG(ERR, "(%s) failed to allocate async buffers (qid: %d)\n",
+ dev->ifname, queue_id);
+ goto out_free_inflight;
+ }
+ } else {
+ async->descs_split = rte_malloc_socket(NULL,
+ vq->size * sizeof(struct vring_used_elem),
+ RTE_CACHE_LINE_SIZE, node);
+ if (!async->descs_split) {
+ VHOST_LOG_CONFIG(ERR, "(%s) failed to allocate async descs (qid: %d)\n",
+ dev->ifname, queue_id);
+ goto out_free_inflight;
+ }
+ }
+
+ async->ops.check_completed_copies = ops->check_completed_copies;
+ async->ops.transfer_data = ops->transfer_data;
+
+ vq->async = async;
+
+ return 0;
+out_free_inflight:
+ rte_free(async->pkts_info);
+out_free_async:
+ rte_free(async);
+
+ return -1;
+}
+