X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_vhost%2Fvhost_user.c;h=c3c924faecf49c4cee294694b6e32c695096ef39;hb=b53a4972946d4fb82ae323ca036e8d6e61db44d6;hp=3405cd8c0b4fe4797e1dbf4340fc184e66ba7267;hpb=2263f13941a10989d141e73529fa1b0fe356608b;p=dpdk.git diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c index 3405cd8c0b..c3c924faec 100644 --- a/lib/librte_vhost/vhost_user.c +++ b/lib/librte_vhost/vhost_user.c @@ -87,6 +87,8 @@ static const char *vhost_message_str[VHOST_USER_MAX] = { [VHOST_USER_POSTCOPY_END] = "VHOST_USER_POSTCOPY_END", [VHOST_USER_GET_INFLIGHT_FD] = "VHOST_USER_GET_INFLIGHT_FD", [VHOST_USER_SET_INFLIGHT_FD] = "VHOST_USER_SET_INFLIGHT_FD", + [VHOST_USER_SET_STATUS] = "VHOST_USER_SET_STATUS", + [VHOST_USER_GET_STATUS] = "VHOST_USER_GET_STATUS", }; static int send_vhost_reply(int sockfd, struct VhostUserMsg *msg); @@ -228,6 +230,25 @@ vhost_backend_cleanup(struct virtio_net *dev) dev->postcopy_listening = 0; } +static void +vhost_user_notify_queue_state(struct virtio_net *dev, uint16_t index, + int enable) +{ + struct rte_vdpa_device *vdpa_dev = dev->vdpa_dev; + struct vhost_virtqueue *vq = dev->virtqueue[index]; + + /* Configure guest notifications on enable */ + if (enable && vq->notif_enable != VIRTIO_UNINITIALIZED_NOTIF) + vhost_enable_guest_notification(dev, vq, vq->notif_enable); + + if (vdpa_dev && vdpa_dev->ops->set_vring_state) + vdpa_dev->ops->set_vring_state(dev->vid, index, enable); + + if (dev->notify_ops->vring_state_changed) + dev->notify_ops->vring_state_changed(dev->vid, + index, enable); +} + /* * This function just returns success at the moment unless * the device hasn't been initialised. @@ -324,6 +345,9 @@ vhost_user_set_features(struct virtio_net **pdev, struct VhostUserMsg *msg, VHOST_LOG_CONFIG(ERR, "(%d) received invalid negotiated features.\n", dev->vid); + dev->flags |= VIRTIO_DEV_FEATURES_FAILED; + dev->status &= ~VIRTIO_DEVICE_STATUS_FEATURES_OK; + return RTE_VHOST_MSG_RESULT_ERR; } @@ -384,9 +408,10 @@ vhost_user_set_features(struct virtio_net **pdev, struct VhostUserMsg *msg, } vdpa_dev = dev->vdpa_dev; - if (vdpa_dev && vdpa_dev->ops->set_features) + if (vdpa_dev) vdpa_dev->ops->set_features(dev->vid); + dev->flags &= ~VIRTIO_DEV_FEATURES_FAILED; return RTE_VHOST_MSG_RESULT_OK; } @@ -462,12 +487,14 @@ vhost_user_set_vring_num(struct virtio_net **pdev, } else { if (vq->shadow_used_split) rte_free(vq->shadow_used_split); + vq->shadow_used_split = rte_malloc(NULL, vq->size * sizeof(struct vring_used_elem), RTE_CACHE_LINE_SIZE); + if (!vq->shadow_used_split) { VHOST_LOG_CONFIG(ERR, - "failed to allocate memory for shadow used ring.\n"); + "failed to allocate memory for vq internal data.\n"); return RTE_VHOST_MSG_RESULT_ERR; } } @@ -1056,6 +1083,13 @@ vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *msg, } if (dev->mem) { + if (dev->flags & VIRTIO_DEV_VDPA_CONFIGURED) { + struct rte_vdpa_device *vdpa_dev = dev->vdpa_dev; + + if (vdpa_dev && vdpa_dev->ops->dev_close) + vdpa_dev->ops->dev_close(dev->vid); + dev->flags &= ~VIRTIO_DEV_VDPA_CONFIGURED; + } free_mem_region(dev); rte_free(dev->mem); dev->mem = NULL; @@ -1145,7 +1179,8 @@ vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *msg, goto err_mmap; } - populate = (dev->dequeue_zero_copy) ? MAP_POPULATE : 0; + populate = (dev->dequeue_zero_copy || dev->async_copy) ? + MAP_POPULATE : 0; mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED | populate, fd, 0); @@ -1160,7 +1195,7 @@ vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *msg, reg->host_user_addr = (uint64_t)(uintptr_t)mmap_addr + mmap_offset; - if (dev->dequeue_zero_copy) + if (dev->dequeue_zero_copy || dev->async_copy) if (add_guest_pages(dev, reg, alignment) < 0) { VHOST_LOG_CONFIG(ERR, "adding guest pages to region %u failed.\n", @@ -1304,27 +1339,41 @@ vq_is_ready(struct virtio_net *dev, struct vhost_virtqueue *vq) return rings_ok && vq->kickfd != VIRTIO_UNINITIALIZED_EVENTFD && - vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD; + vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD && + vq->enabled; } +#define VIRTIO_DEV_NUM_VQS_TO_BE_READY 2u + static int virtio_is_ready(struct virtio_net *dev) { struct vhost_virtqueue *vq; uint32_t i; - if (dev->nr_vring == 0) + if (dev->flags & VIRTIO_DEV_READY) + return 1; + + if (dev->nr_vring < VIRTIO_DEV_NUM_VQS_TO_BE_READY) return 0; - for (i = 0; i < dev->nr_vring; i++) { + for (i = 0; i < VIRTIO_DEV_NUM_VQS_TO_BE_READY; i++) { vq = dev->virtqueue[i]; if (!vq_is_ready(dev, vq)) return 0; } - VHOST_LOG_CONFIG(INFO, - "virtio is now ready for processing.\n"); + /* If supported, ensure the frontend is really done with config */ + if (dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_STATUS)) + if (!(dev->status & VIRTIO_DEVICE_STATUS_DRIVER_OK)) + return 0; + + dev->flags |= VIRTIO_DEV_READY; + + if (!(dev->flags & VIRTIO_DEV_RUNNING)) + VHOST_LOG_CONFIG(INFO, + "virtio is now ready for processing.\n"); return 1; } @@ -1594,6 +1643,12 @@ vhost_user_set_vring_call(struct virtio_net **pdev, struct VhostUserMsg *msg, "vring call idx:%d file:%d\n", file.index, file.fd); vq = dev->virtqueue[file.index]; + + if (vq->ready) { + vq->ready = 0; + vhost_user_notify_queue_state(dev, file.index, 0); + } + if (vq->callfd >= 0) close(vq->callfd); @@ -1852,6 +1907,11 @@ vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *msg, dev->vid, file.index, 1); } + if (vq->ready) { + vq->ready = 0; + vhost_user_notify_queue_state(dev, file.index, 0); + } + if (vq->kickfd >= 0) close(vq->kickfd); vq->kickfd = file.fd; @@ -1879,6 +1939,7 @@ free_zmbufs(struct vhost_virtqueue *vq) drain_zmbuf_list(vq); rte_free(vq->zmbufs); + vq->zmbufs = NULL; } /* @@ -1943,6 +2004,12 @@ vhost_user_get_vring_base(struct virtio_net **pdev, } else { rte_free(vq->shadow_used_split); vq->shadow_used_split = NULL; + if (vq->async_pkts_pending) + rte_free(vq->async_pkts_pending); + if (vq->async_pending_info) + rte_free(vq->async_pending_info); + vq->async_pkts_pending = NULL; + vq->async_pending_info = NULL; } rte_free(vq->batch_copy_elems); @@ -1968,7 +2035,6 @@ vhost_user_set_vring_enable(struct virtio_net **pdev, struct virtio_net *dev = *pdev; int enable = (int)msg->payload.state.num; int index = (int)msg->payload.state.index; - struct rte_vdpa_device *vdpa_dev; if (validate_msg_fds(msg, 0) != 0) return RTE_VHOST_MSG_RESULT_ERR; @@ -1977,13 +2043,13 @@ vhost_user_set_vring_enable(struct virtio_net **pdev, "set queue enable: %d to qp idx: %d\n", enable, index); - vdpa_dev = dev->vdpa_dev; - if (vdpa_dev && vdpa_dev->ops->set_vring_state) - vdpa_dev->ops->set_vring_state(dev->vid, index, enable); - - if (dev->notify_ops->vring_state_changed) - dev->notify_ops->vring_state_changed(dev->vid, - index, enable); + if (!enable && dev->virtqueue[index]->async_registered) { + if (dev->virtqueue[index]->async_pkts_inflight_n) { + VHOST_LOG_CONFIG(ERR, "failed to disable vring. " + "async inflight packets must be completed first\n"); + return RTE_VHOST_MSG_RESULT_ERR; + } + } /* On disable, rings have to be stopped being processed. */ if (!enable && dev->dequeue_zero_copy) @@ -2420,6 +2486,68 @@ vhost_user_postcopy_end(struct virtio_net **pdev, struct VhostUserMsg *msg, return RTE_VHOST_MSG_RESULT_REPLY; } +static int +vhost_user_get_status(struct virtio_net **pdev, struct VhostUserMsg *msg, + int main_fd __rte_unused) +{ + struct virtio_net *dev = *pdev; + + if (validate_msg_fds(msg, 0) != 0) + return RTE_VHOST_MSG_RESULT_ERR; + + msg->payload.u64 = dev->status; + msg->size = sizeof(msg->payload.u64); + msg->fd_num = 0; + + return RTE_VHOST_MSG_RESULT_REPLY; +} + +static int +vhost_user_set_status(struct virtio_net **pdev, struct VhostUserMsg *msg, + int main_fd __rte_unused) +{ + struct virtio_net *dev = *pdev; + + if (validate_msg_fds(msg, 0) != 0) + return RTE_VHOST_MSG_RESULT_ERR; + + /* As per Virtio specification, the device status is 8bits long */ + if (msg->payload.u64 > UINT8_MAX) { + VHOST_LOG_CONFIG(ERR, "Invalid VHOST_USER_SET_STATUS payload 0x%" PRIx64 "\n", + msg->payload.u64); + return RTE_VHOST_MSG_RESULT_ERR; + } + + dev->status = msg->payload.u64; + + if ((dev->status & VIRTIO_DEVICE_STATUS_FEATURES_OK) && + (dev->flags & VIRTIO_DEV_FEATURES_FAILED)) { + VHOST_LOG_CONFIG(ERR, "FEATURES_OK bit is set but feature negotiation failed\n"); + /* + * Clear the bit to let the driver know about the feature + * negotiation failure + */ + dev->status &= ~VIRTIO_DEVICE_STATUS_FEATURES_OK; + } + + VHOST_LOG_CONFIG(INFO, "New device status(0x%08x):\n" + "\t-ACKNOWLEDGE: %u\n" + "\t-DRIVER: %u\n" + "\t-FEATURES_OK: %u\n" + "\t-DRIVER_OK: %u\n" + "\t-DEVICE_NEED_RESET: %u\n" + "\t-FAILED: %u\n", + dev->status, + !!(dev->status & VIRTIO_DEVICE_STATUS_ACK), + !!(dev->status & VIRTIO_DEVICE_STATUS_DRIVER), + !!(dev->status & VIRTIO_DEVICE_STATUS_FEATURES_OK), + !!(dev->status & VIRTIO_DEVICE_STATUS_DRIVER_OK), + !!(dev->status & VIRTIO_DEVICE_STATUS_DEV_NEED_RESET), + !!(dev->status & VIRTIO_DEVICE_STATUS_FAILED)); + + return RTE_VHOST_MSG_RESULT_OK; +} + typedef int (*vhost_message_handler_t)(struct virtio_net **pdev, struct VhostUserMsg *msg, int main_fd); @@ -2452,6 +2580,8 @@ static vhost_message_handler_t vhost_message_handlers[VHOST_USER_MAX] = { [VHOST_USER_POSTCOPY_END] = vhost_user_postcopy_end, [VHOST_USER_GET_INFLIGHT_FD] = vhost_user_get_inflight_fd, [VHOST_USER_SET_INFLIGHT_FD] = vhost_user_set_inflight_fd, + [VHOST_USER_SET_STATUS] = vhost_user_set_status, + [VHOST_USER_GET_STATUS] = vhost_user_get_status, }; /* return bytes# of read on success or negative val on failure. */ @@ -2611,6 +2741,7 @@ vhost_user_msg_handler(int vid, int fd) int unlock_required = 0; bool handled; int request; + uint32_t i; dev = get_device(vid); if (dev == NULL) @@ -2683,8 +2814,10 @@ vhost_user_msg_handler(int vid, int fd) case VHOST_USER_SEND_RARP: case VHOST_USER_NET_SET_MTU: case VHOST_USER_SET_SLAVE_REQ_FD: - vhost_user_lock_all_queue_pairs(dev); - unlock_required = 1; + if (!(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED)) { + vhost_user_lock_all_queue_pairs(dev); + unlock_required = 1; + } break; default: break; @@ -2784,29 +2917,44 @@ skip_to_post_handle: return -1; } - if (!(dev->flags & VIRTIO_DEV_RUNNING) && virtio_is_ready(dev)) { - dev->flags |= VIRTIO_DEV_READY; - - if (!(dev->flags & VIRTIO_DEV_RUNNING)) { - if (dev->dequeue_zero_copy) { - VHOST_LOG_CONFIG(INFO, - "dequeue zero copy is enabled\n"); - } + for (i = 0; i < dev->nr_vring; i++) { + struct vhost_virtqueue *vq = dev->virtqueue[i]; + bool cur_ready = vq_is_ready(dev, vq); - if (dev->notify_ops->new_device(dev->vid) == 0) - dev->flags |= VIRTIO_DEV_RUNNING; + if (cur_ready != (vq && vq->ready)) { + vq->ready = cur_ready; + vhost_user_notify_queue_state(dev, i, cur_ready); } } + + if (!virtio_is_ready(dev)) + goto out; + + /* + * Virtio is now ready. If not done already, it is time + * to notify the application it can process the rings and + * configure the vDPA device if present. + */ + + if (!(dev->flags & VIRTIO_DEV_RUNNING)) { + if (dev->notify_ops->new_device(dev->vid) == 0) + dev->flags |= VIRTIO_DEV_RUNNING; + } + vdpa_dev = dev->vdpa_dev; - if (vdpa_dev && virtio_is_ready(dev) && - !(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED) && - msg.request.master == VHOST_USER_SET_VRING_CALL) { - if (vdpa_dev->ops->dev_conf) - vdpa_dev->ops->dev_conf(dev->vid); - dev->flags |= VIRTIO_DEV_VDPA_CONFIGURED; + if (!vdpa_dev) + goto out; + + if (!(dev->flags & VIRTIO_DEV_VDPA_CONFIGURED)) { + if (vdpa_dev->ops->dev_conf(dev->vid)) + VHOST_LOG_CONFIG(ERR, + "Failed to configure vDPA device\n"); + else + dev->flags |= VIRTIO_DEV_VDPA_CONFIGURED; } +out: return 0; } @@ -2943,13 +3091,13 @@ static int vhost_user_slave_set_vring_host_notifier(struct virtio_net *dev, return process_slave_message_reply(dev, &msg); } -int rte_vhost_host_notifier_ctrl(int vid, bool enable) +int rte_vhost_host_notifier_ctrl(int vid, uint16_t qid, bool enable) { struct virtio_net *dev; struct rte_vdpa_device *vdpa_dev; int vfio_device_fd, ret = 0; uint64_t offset, size; - unsigned int i; + unsigned int i, q_start, q_last; dev = get_device(vid); if (!dev) @@ -2969,6 +3117,16 @@ int rte_vhost_host_notifier_ctrl(int vid, bool enable) (1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER))) return -ENOTSUP; + if (qid == RTE_VHOST_QUEUE_ALL) { + q_start = 0; + q_last = dev->nr_vring - 1; + } else { + if (qid >= dev->nr_vring) + return -EINVAL; + q_start = qid; + q_last = qid; + } + RTE_FUNC_PTR_OR_ERR_RET(vdpa_dev->ops->get_vfio_device_fd, -ENOTSUP); RTE_FUNC_PTR_OR_ERR_RET(vdpa_dev->ops->get_notify_area, -ENOTSUP); @@ -2977,7 +3135,7 @@ int rte_vhost_host_notifier_ctrl(int vid, bool enable) return -ENOTSUP; if (enable) { - for (i = 0; i < dev->nr_vring; i++) { + for (i = q_start; i <= q_last; i++) { if (vdpa_dev->ops->get_notify_area(vid, i, &offset, &size) < 0) { ret = -ENOTSUP; @@ -2992,7 +3150,7 @@ int rte_vhost_host_notifier_ctrl(int vid, bool enable) } } else { disable: - for (i = 0; i < dev->nr_vring; i++) { + for (i = q_start; i <= q_last; i++) { vhost_user_slave_set_vring_host_notifier(dev, i, -1, 0, 0); }