diff options
Diffstat (limited to 'arch/um/drivers/virtio_uml.c')
-rw-r--r-- | arch/um/drivers/virtio_uml.c | 92 |
1 files changed, 48 insertions, 44 deletions
diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 9db9d00b2dc2..bda3ab468938 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -55,16 +55,14 @@ struct virtio_uml_device { u64 protocol_features; u8 status; u8 registered:1; + + u8 config_changed_irq:1; + uint64_t vq_irq_vq_map; }; struct virtio_uml_vq_info { int kick_fd, call_fd; char name[32]; -#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT - struct virtqueue *vq; - vq_callback_t *callback; - struct time_travel_event defer; -#endif bool suspended; }; @@ -351,9 +349,9 @@ static void vhost_user_reply(struct virtio_uml_device *vu_dev, rc, size); } -static irqreturn_t vu_req_interrupt(int irq, void *data) +static irqreturn_t vu_req_read_message(struct virtio_uml_device *vu_dev, + struct time_travel_event *ev) { - struct virtio_uml_device *vu_dev = data; struct virtqueue *vq; int response = 1; struct { @@ -371,14 +369,14 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) switch (msg.msg.header.request) { case VHOST_USER_SLAVE_CONFIG_CHANGE_MSG: - virtio_config_changed(&vu_dev->vdev); + vu_dev->config_changed_irq = true; response = 0; break; case VHOST_USER_SLAVE_VRING_CALL: virtio_device_for_each_vq((&vu_dev->vdev), vq) { if (vq->index == msg.msg.payload.vring_state.index) { response = 0; - vring_interrupt(0 /* ignored */, vq); + vu_dev->vq_irq_vq_map |= BIT_ULL(vq->index); break; } } @@ -392,12 +390,45 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) msg.msg.header.request); } + if (ev) + time_travel_add_irq_event(ev); + if (msg.msg.header.flags & VHOST_USER_FLAG_NEED_REPLY) vhost_user_reply(vu_dev, &msg.msg, response); return IRQ_HANDLED; } +static irqreturn_t vu_req_interrupt(int irq, void *data) +{ + struct virtio_uml_device *vu_dev = data; + irqreturn_t ret = IRQ_HANDLED; + + if (!um_irq_timetravel_handler_used()) + ret = vu_req_read_message(vu_dev, NULL); + + if (vu_dev->vq_irq_vq_map) { + struct virtqueue *vq; + + virtio_device_for_each_vq((&vu_dev->vdev), vq) { + if (vu_dev->vq_irq_vq_map & BIT_ULL(vq->index)) + vring_interrupt(0 /* ignored */, vq); + } + vu_dev->vq_irq_vq_map = 0; + } else if (vu_dev->config_changed_irq) { + virtio_config_changed(&vu_dev->vdev); + vu_dev->config_changed_irq = false; + } + + return ret; +} + +static void vu_req_interrupt_comm_handler(int irq, int fd, void *data, + struct time_travel_event *ev) +{ + vu_req_read_message(data, ev); +} + static int vhost_user_init_slave_req(struct virtio_uml_device *vu_dev) { int rc, req_fds[2]; @@ -408,9 +439,10 @@ static int vhost_user_init_slave_req(struct virtio_uml_device *vu_dev) return rc; vu_dev->req_fd = req_fds[0]; - rc = um_request_irq(UM_IRQ_ALLOC, vu_dev->req_fd, IRQ_READ, - vu_req_interrupt, IRQF_SHARED, - vu_dev->pdev->name, vu_dev); + rc = um_request_irq_tt(UM_IRQ_ALLOC, vu_dev->req_fd, IRQ_READ, + vu_req_interrupt, IRQF_SHARED, + vu_dev->pdev->name, vu_dev, + vu_req_interrupt_comm_handler); if (rc < 0) goto err_close; @@ -882,23 +914,6 @@ out: return rc; } -#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT -static void vu_defer_irq_handle(struct time_travel_event *d) -{ - struct virtio_uml_vq_info *info; - - info = container_of(d, struct virtio_uml_vq_info, defer); - info->callback(info->vq); -} - -static void vu_defer_irq_callback(struct virtqueue *vq) -{ - struct virtio_uml_vq_info *info = vq->priv; - - time_travel_add_irq_event(&info->defer); -} -#endif - static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, unsigned index, vq_callback_t *callback, const char *name, bool ctx) @@ -918,18 +933,6 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name, pdev->id, name); -#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT - /* - * When we get an interrupt, we must bounce it through the simulation - * calendar (the time-travel=ext:... socket). - */ - if (time_travel_mode == TT_MODE_EXTERNAL && callback) { - info->callback = callback; - callback = vu_defer_irq_callback; - time_travel_set_event_fn(&info->defer, vu_defer_irq_handle); - } -#endif - vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true, ctx, vu_notify, callback, info->name); if (!vq) { @@ -938,9 +941,6 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, } vq->priv = info; num = virtqueue_get_vring_size(vq); -#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT - info->vq = vq; -#endif if (vu_dev->protocol_features & BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)) { @@ -999,6 +999,10 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs, int i, queue_idx = 0, rc; struct virtqueue *vq; + /* not supported for now */ + if (WARN_ON(nvqs > 64)) + return -EINVAL; + rc = vhost_user_set_mem_table(vu_dev); if (rc) return rc; |