Lines Matching +full:num +full:- +full:ids
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Virtio vhost-user driver
7 * This driver allows virtio devices to be used over a vhost-user socket.
14 * <socket> := vhost-user socket path to connect
21 * Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd.
30 #include <linux/time-internal.h>
31 #include <linux/virtio-uml.h>
32 #include <shared/as-layout.h>
76 #define vu_err(vu_dev, ...) dev_err(&(vu_dev)->pdev->dev, ##__VA_ARGS__)
78 /* Vhost-user protocol */
89 len -= rc; in full_sendmsg_fds()
93 } while (len && (rc >= 0 || rc == -EINTR)); in full_sendmsg_fds()
111 len -= rc; in full_read()
113 } while (len && (rc > 0 || rc == -EINTR || (!abortable && rc == -EAGAIN))); in full_read()
118 return -ECONNRESET; in full_read()
124 return full_read(fd, msg, sizeof(msg->header), true); in vhost_user_recv_header()
135 * In virtio time-travel mode, we're handling all the vhost-user in vhost_user_recv()
143 * to also handle messages for the simulation time - this function in vhost_user_recv()
153 size = msg->header.size; in vhost_user_recv()
155 return -EPROTO; in vhost_user_recv()
156 return full_read(fd, &msg->payload, size, false); in vhost_user_recv()
162 struct virtio_uml_platform_data *pdata = vu_dev->pdata; in vhost_user_check_reset()
164 if (rc != -ECONNRESET) in vhost_user_check_reset()
167 if (!vu_dev->registered) in vhost_user_check_reset()
170 vu_dev->registered = 0; in vhost_user_check_reset()
172 schedule_work(&pdata->conn_broken_wk); in vhost_user_check_reset()
179 int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, in vhost_user_recv_resp()
187 if (msg->header.flags != (VHOST_USER_FLAG_REPLY | VHOST_USER_VERSION)) in vhost_user_recv_resp()
188 return -EPROTO; in vhost_user_recv_resp()
203 return -EPROTO; in vhost_user_recv_u64()
212 int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, in vhost_user_recv_req()
218 if ((msg->header.flags & ~VHOST_USER_FLAG_NEED_REPLY) != in vhost_user_recv_req()
220 return -EPROTO; in vhost_user_recv_req()
229 size_t size = sizeof(msg->header) + msg->header.size; in vhost_user_send()
234 msg->header.flags |= VHOST_USER_VERSION; in vhost_user_send()
242 if (!(vu_dev->protocol_features & in vhost_user_send()
247 msg->header.flags |= VHOST_USER_FLAG_NEED_REPLY; in vhost_user_send()
249 raw_spin_lock_irqsave(&vu_dev->sock_lock, flags); in vhost_user_send()
250 rc = full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds); in vhost_user_send()
263 rc = -EIO; in vhost_user_send()
269 raw_spin_unlock_irqrestore(&vu_dev->sock_lock, flags); in vhost_user_send()
365 reply.header = msg->header; in vhost_user_reply()
370 rc = full_sendmsg_fds(vu_dev->req_fd, &reply, size, NULL, 0); in vhost_user_reply()
399 vu_dev->config_changed_irq = true; in vu_req_read_message()
403 virtio_device_for_each_vq((&vu_dev->vdev), vq) { in vu_req_read_message()
404 if (vq->index == msg.msg.payload.vring_state.index) { in vu_req_read_message()
406 vu_dev->vq_irq_vq_map |= BIT_ULL(vq->index); in vu_req_read_message()
412 /* not supported - VIRTIO_F_ACCESS_PLATFORM */ in vu_req_read_message()
414 /* not supported - VHOST_USER_PROTOCOL_F_HOST_NOTIFIER */ in vu_req_read_message()
420 if (ev && !vu_dev->suspended) in vu_req_read_message()
427 /* mask EAGAIN as we try non-blocking read until socket is empty */ in vu_req_read_message()
428 vu_dev->recv_rc = (rc == -EAGAIN) ? 0 : rc; in vu_req_read_message()
440 if (vu_dev->recv_rc) { in vu_req_interrupt()
441 vhost_user_check_reset(vu_dev, vu_dev->recv_rc); in vu_req_interrupt()
442 } else if (vu_dev->vq_irq_vq_map) { in vu_req_interrupt()
445 virtio_device_for_each_vq((&vu_dev->vdev), vq) { in vu_req_interrupt()
446 if (vu_dev->vq_irq_vq_map & BIT_ULL(vq->index)) in vu_req_interrupt()
449 vu_dev->vq_irq_vq_map = 0; in vu_req_interrupt()
450 } else if (vu_dev->config_changed_irq) { in vu_req_interrupt()
451 virtio_config_changed(&vu_dev->vdev); in vu_req_interrupt()
452 vu_dev->config_changed_irq = false; in vu_req_interrupt()
472 vu_dev->req_fd = req_fds[0]; in vhost_user_init_slave_req()
474 rc = um_request_irq_tt(UM_IRQ_ALLOC, vu_dev->req_fd, IRQ_READ, in vhost_user_init_slave_req()
476 vu_dev->pdev->name, vu_dev, in vhost_user_init_slave_req()
481 vu_dev->irq = rc; in vhost_user_init_slave_req()
491 um_free_irq(vu_dev->irq, vu_dev); in vhost_user_init_slave_req()
506 rc = vhost_user_get_features(vu_dev, &vu_dev->features); in vhost_user_init()
510 if (vu_dev->features & BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)) { in vhost_user_init()
512 &vu_dev->protocol_features); in vhost_user_init()
515 vu_dev->protocol_features &= VHOST_USER_SUPPORTED_PROTOCOL_F; in vhost_user_init()
517 vu_dev->protocol_features); in vhost_user_init()
522 if (vu_dev->protocol_features & in vhost_user_init()
529 if (vu_dev->protocol_features & in vhost_user_init()
531 rc = vhost_user_get_queue_num(vu_dev, &vu_dev->max_vqs); in vhost_user_init()
535 vu_dev->max_vqs = U64_MAX; in vhost_user_init()
546 size_t payload_size = sizeof(msg->payload.config) + cfg_size; in vhost_user_get_config()
547 size_t msg_size = sizeof(msg->header) + payload_size; in vhost_user_get_config()
550 if (!(vu_dev->protocol_features & in vhost_user_get_config()
557 msg->header.request = VHOST_USER_GET_CONFIG; in vhost_user_get_config()
558 msg->header.size = payload_size; in vhost_user_get_config()
559 msg->payload.config.offset = 0; in vhost_user_get_config()
560 msg->payload.config.size = cfg_size; in vhost_user_get_config()
577 if (msg->header.size != payload_size || in vhost_user_get_config()
578 msg->payload.config.size != cfg_size) { in vhost_user_get_config()
579 rc = -EPROTO; in vhost_user_get_config()
582 msg->header.size, payload_size, in vhost_user_get_config()
583 msg->payload.config.size, cfg_size); in vhost_user_get_config()
586 memcpy(buf, msg->payload.config.payload + offset, len); in vhost_user_get_config()
596 size_t payload_size = sizeof(msg->payload.config) + len; in vhost_user_set_config()
597 size_t msg_size = sizeof(msg->header) + payload_size; in vhost_user_set_config()
600 if (!(vu_dev->protocol_features & in vhost_user_set_config()
607 msg->header.request = VHOST_USER_SET_CONFIG; in vhost_user_set_config()
608 msg->header.size = payload_size; in vhost_user_set_config()
609 msg->payload.config.offset = offset; in vhost_user_set_config()
610 msg->payload.config.size = len; in vhost_user_set_config()
611 memcpy(msg->payload.config.payload, buf, len); in vhost_user_set_config()
628 return -EFAULT; in vhost_user_init_mem_region()
630 region_out->guest_addr = addr; in vhost_user_init_mem_region()
631 region_out->user_addr = addr; in vhost_user_init_mem_region()
632 region_out->size = size; in vhost_user_init_mem_region()
633 region_out->mmap_offset = mem_offset; in vhost_user_init_mem_region()
636 rc = phys_mapping(addr + size - 1, &mem_offset); in vhost_user_init_mem_region()
638 addr + size - 1, rc, *fd_out)) in vhost_user_init_mem_region()
639 return -EFAULT; in vhost_user_init_mem_region()
648 .payload.mem_regions.num = 1, in vhost_user_set_mem_table()
650 unsigned long reserved = uml_reserved - uml_physmem; in vhost_user_set_mem_table()
666 * Thus, don't advertise this space to the vhost-user slave. This in vhost_user_set_mem_table()
670 * don't just have the slave read an all-zeroes buffer from the in vhost_user_set_mem_table()
677 * file-backed memory in vhost_user_set_mem_table()
689 rc = vhost_user_init_mem_region(reserved, physmem_size - reserved, in vhost_user_set_mem_table()
697 msg.payload.mem_regions.num); in vhost_user_set_mem_table()
701 u32 request, u32 index, u32 num) in vhost_user_set_vring_state() argument
707 .payload.vring_state.num = num, in vhost_user_set_vring_state()
714 u32 index, u32 num) in vhost_user_set_vring_num() argument
717 index, num); in vhost_user_set_vring_num()
754 return -EINVAL; in vhost_user_set_vring_fd()
779 if (!(vu_dev->features & BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES))) in vhost_user_set_vring_enable()
791 struct virtio_uml_vq_info *info = vq->priv; in vu_notify()
795 if (info->suspended) in vu_notify()
800 if (info->kick_fd < 0) { in vu_notify()
803 vu_dev = to_virtio_uml_device(vq->vdev); in vu_notify()
806 vq->index, 0) == 0; in vu_notify()
810 rc = os_write_file(info->kick_fd, &n, sizeof(n)); in vu_notify()
811 } while (rc == -EINTR); in vu_notify()
818 struct virtio_uml_vq_info *info = vq->priv; in vu_interrupt()
824 rc = os_read_file(info->call_fd, &n, sizeof(n)); in vu_interrupt()
827 } while (rc == sizeof(n) || rc == -EINTR); in vu_interrupt()
828 WARN(rc != -EAGAIN, "read returned %d\n", rc); in vu_interrupt()
853 return vu_dev->status; in vu_get_status()
860 vu_dev->status = status; in vu_set_status()
867 vu_dev->status = 0; in vu_reset()
872 struct virtio_uml_vq_info *info = vq->priv; in vu_del_vq()
874 if (info->call_fd >= 0) { in vu_del_vq()
877 vu_dev = to_virtio_uml_device(vq->vdev); in vu_del_vq()
879 um_free_irq(vu_dev->irq, vq); in vu_del_vq()
880 os_close_file(info->call_fd); in vu_del_vq()
883 if (info->kick_fd >= 0) in vu_del_vq()
884 os_close_file(info->kick_fd); in vu_del_vq()
897 list_for_each_entry_reverse(vq, &vdev->vqs, list) in vu_del_vqs()
898 WARN_ON(vhost_user_set_vring_enable(vu_dev, vq->index, false)); in vu_del_vqs()
903 list_for_each_entry_safe(vq, n, &vdev->vqs, list) in vu_del_vqs()
910 struct virtio_uml_vq_info *info = vq->priv; in vu_setup_vq_call_fd()
915 if (vu_dev->protocol_features & in vu_setup_vq_call_fd()
917 vu_dev->protocol_features & in vu_setup_vq_call_fd()
919 info->call_fd = -1; in vu_setup_vq_call_fd()
928 info->call_fd = call_fds[0]; in vu_setup_vq_call_fd()
929 irq = um_request_irq(vu_dev->irq, info->call_fd, IRQ_READ, in vu_setup_vq_call_fd()
930 vu_interrupt, IRQF_SHARED, info->name, vq); in vu_setup_vq_call_fd()
936 rc = vhost_user_set_vring_call(vu_dev, vq->index, call_fds[1]); in vu_setup_vq_call_fd()
940 vu_dev->irq = irq; in vu_setup_vq_call_fd()
960 struct platform_device *pdev = vu_dev->pdev; in vu_setup_vq()
963 int num = MAX_SUPPORTED_QUEUE_SIZE; in vu_setup_vq() local
968 rc = -ENOMEM; in vu_setup_vq()
971 snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name, in vu_setup_vq()
972 pdev->id, name); in vu_setup_vq()
974 vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true, in vu_setup_vq()
975 ctx, vu_notify, callback, info->name); in vu_setup_vq()
977 rc = -ENOMEM; in vu_setup_vq()
980 vq->priv = info; in vu_setup_vq()
981 vq->num_max = num; in vu_setup_vq()
982 num = virtqueue_get_vring_size(vq); in vu_setup_vq()
984 if (vu_dev->protocol_features & in vu_setup_vq()
986 info->kick_fd = -1; in vu_setup_vq()
991 info->kick_fd = rc; in vu_setup_vq()
998 rc = vhost_user_set_vring_num(vu_dev, index, num); in vu_setup_vq()
1010 (u64) -1); in vu_setup_vq()
1017 if (info->call_fd >= 0) { in vu_setup_vq()
1018 um_free_irq(vu_dev->irq, vq); in vu_setup_vq()
1019 os_close_file(info->call_fd); in vu_setup_vq()
1022 if (info->kick_fd >= 0) in vu_setup_vq()
1023 os_close_file(info->kick_fd); in vu_setup_vq()
1042 if (WARN(nvqs > 64 || nvqs > vu_dev->max_vqs, in vu_find_vqs()
1044 nvqs, vu_dev->max_vqs)) in vu_find_vqs()
1045 return -EINVAL; in vu_find_vqs()
1054 if (!vqi->name) { in vu_find_vqs()
1059 vqs[i] = vu_setup_vq(vdev, queue_idx++, vqi->callback, in vu_find_vqs()
1060 vqi->name, vqi->ctx); in vu_find_vqs()
1067 list_for_each_entry(vq, &vdev->vqs, list) { in vu_find_vqs()
1068 struct virtio_uml_vq_info *info = vq->priv; in vu_find_vqs()
1070 if (info->kick_fd >= 0) { in vu_find_vqs()
1071 rc = vhost_user_set_vring_kick(vu_dev, vq->index, in vu_find_vqs()
1072 info->kick_fd); in vu_find_vqs()
1077 rc = vhost_user_set_vring_enable(vu_dev, vq->index, true); in vu_find_vqs()
1093 return vu_dev->features; in vu_get_features()
1099 u64 supported = vdev->features & VHOST_USER_SUPPORTED_F; in vu_finalize_features()
1102 vu_dev->features = vdev->features | supported; in vu_finalize_features()
1104 return vhost_user_set_features(vu_dev, vu_dev->features); in vu_finalize_features()
1111 return vu_dev->pdev->name; in vu_bus_name()
1136 if (vu_dev->req_fd >= 0) { in virtio_uml_release_dev()
1137 um_free_irq(vu_dev->irq, vu_dev); in virtio_uml_release_dev()
1138 os_close_file(vu_dev->req_fd); in virtio_uml_release_dev()
1141 os_close_file(vu_dev->sock); in virtio_uml_release_dev()
1150 if (WARN_ON(vdev->config != &virtio_uml_config_ops)) in virtio_uml_set_no_vq_suspend()
1153 vu_dev->no_vq_suspend = no_vq_suspend; in virtio_uml_set_no_vq_suspend()
1154 dev_info(&vdev->dev, "%sabled VQ suspend\n", in virtio_uml_set_no_vq_suspend()
1165 vu_dev = platform_get_drvdata(pdata->pdev); in vu_of_conn_broken()
1167 virtio_break_device(&vu_dev->vdev); in vu_of_conn_broken()
1181 struct device_node *np = pdev->dev.of_node; in virtio_uml_create_pdata()
1186 return ERR_PTR(-EINVAL); in virtio_uml_create_pdata()
1188 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); in virtio_uml_create_pdata()
1190 return ERR_PTR(-ENOMEM); in virtio_uml_create_pdata()
1192 INIT_WORK(&pdata->conn_broken_wk, vu_of_conn_broken); in virtio_uml_create_pdata()
1193 pdata->pdev = pdev; in virtio_uml_create_pdata()
1195 ret = of_property_read_string(np, "socket-path", &pdata->socket_path); in virtio_uml_create_pdata()
1199 ret = of_property_read_u32(np, "virtio-device-id", in virtio_uml_create_pdata()
1200 &pdata->virtio_device_id); in virtio_uml_create_pdata()
1209 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; in virtio_uml_probe()
1221 return -ENOMEM; in virtio_uml_probe()
1223 vu_dev->pdata = pdata; in virtio_uml_probe()
1224 vu_dev->vdev.dev.parent = &pdev->dev; in virtio_uml_probe()
1225 vu_dev->vdev.dev.release = virtio_uml_release_dev; in virtio_uml_probe()
1226 vu_dev->vdev.config = &virtio_uml_config_ops; in virtio_uml_probe()
1227 vu_dev->vdev.id.device = pdata->virtio_device_id; in virtio_uml_probe()
1228 vu_dev->vdev.id.vendor = VIRTIO_DEV_ANY_ID; in virtio_uml_probe()
1229 vu_dev->pdev = pdev; in virtio_uml_probe()
1230 vu_dev->req_fd = -1; in virtio_uml_probe()
1231 vu_dev->irq = UM_IRQ_ALLOC; in virtio_uml_probe()
1236 rc = os_connect_socket(pdata->socket_path); in virtio_uml_probe()
1237 } while (rc == -EINTR); in virtio_uml_probe()
1240 vu_dev->sock = rc; in virtio_uml_probe()
1242 raw_spin_lock_init(&vu_dev->sock_lock); in virtio_uml_probe()
1250 device_set_wakeup_capable(&vu_dev->vdev.dev, true); in virtio_uml_probe()
1252 rc = register_virtio_device(&vu_dev->vdev); in virtio_uml_probe()
1254 put_device(&vu_dev->vdev.dev); in virtio_uml_probe()
1255 vu_dev->registered = 1; in virtio_uml_probe()
1259 os_close_file(vu_dev->sock); in virtio_uml_probe()
1269 unregister_virtio_device(&vu_dev->vdev); in virtio_uml_remove()
1279 .init_name = "virtio-uml-cmdline",
1289 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; in vu_unregister_cmdline_device()
1291 kfree(pdata->socket_path); in vu_unregister_cmdline_device()
1303 vu_dev = platform_get_drvdata(pdata->pdev); in vu_conn_broken()
1305 virtio_break_device(&vu_dev->vdev); in vu_conn_broken()
1307 vu_unregister_cmdline_device(&pdata->pdev->dev, NULL); in vu_conn_broken()
1312 const char *ids = strchr(device, ':'); in vu_cmdline_set() local
1319 if (!ids || ids == device) in vu_cmdline_set()
1320 return -EINVAL; in vu_cmdline_set()
1322 processed = sscanf(ids, ":%u%n:%d%n", in vu_cmdline_set()
1326 if (processed < 1 || ids[consumed]) in vu_cmdline_set()
1327 return -EINVAL; in vu_cmdline_set()
1339 socket_path = kmemdup_nul(device, ids - device, GFP_KERNEL); in vu_cmdline_set()
1341 return -ENOMEM; in vu_cmdline_set()
1346 pr_info("Registering device virtio-uml.%d id=%d at %s\n", in vu_cmdline_set()
1349 pdev = platform_device_register_data(&vu_cmdline_parent, "virtio-uml", in vu_cmdline_set()
1356 ppdata = pdev->dev.platform_data; in vu_cmdline_set()
1357 ppdata->pdev = pdev; in vu_cmdline_set()
1358 INIT_WORK(&ppdata->conn_broken_wk, vu_conn_broken); in vu_cmdline_set()
1370 struct virtio_uml_platform_data *pdata = pdev->dev.platform_data; in vu_cmdline_get_device()
1374 snprintf(buffer + len, PAGE_SIZE - len, "%s:%d:%d\n", in vu_cmdline_get_device()
1375 pdata->socket_path, pdata->virtio_device_id, pdev->id); in vu_cmdline_get_device()
1396 " Configure a virtio device over a vhost-user socket.\n"
1424 if (!vu_dev->no_vq_suspend) { in virtio_uml_suspend()
1427 virtio_device_for_each_vq((&vu_dev->vdev), vq) { in virtio_uml_suspend()
1428 struct virtio_uml_vq_info *info = vq->priv; in virtio_uml_suspend()
1430 info->suspended = true; in virtio_uml_suspend()
1431 vhost_user_set_vring_enable(vu_dev, vq->index, false); in virtio_uml_suspend()
1435 if (!device_may_wakeup(&vu_dev->vdev.dev)) { in virtio_uml_suspend()
1436 vu_dev->suspended = true; in virtio_uml_suspend()
1440 return irq_set_irq_wake(vu_dev->irq, 1); in virtio_uml_suspend()
1447 if (!vu_dev->no_vq_suspend) { in virtio_uml_resume()
1450 virtio_device_for_each_vq((&vu_dev->vdev), vq) { in virtio_uml_resume()
1451 struct virtio_uml_vq_info *info = vq->priv; in virtio_uml_resume()
1453 info->suspended = false; in virtio_uml_resume()
1454 vhost_user_set_vring_enable(vu_dev, vq->index, true); in virtio_uml_resume()
1458 vu_dev->suspended = false; in virtio_uml_resume()
1460 if (!device_may_wakeup(&vu_dev->vdev.dev)) in virtio_uml_resume()
1463 return irq_set_irq_wake(vu_dev->irq, 0); in virtio_uml_resume()
1470 .name = "virtio-uml",
1492 MODULE_DESCRIPTION("UML driver for vhost-user virtio devices");