19fca2b7dSJohn Levon /* 29fca2b7dSJohn Levon * vfio PCI device over a UNIX socket. 39fca2b7dSJohn Levon * 49fca2b7dSJohn Levon * Copyright © 2018, 2021 Oracle and/or its affiliates. 59fca2b7dSJohn Levon * 69fca2b7dSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 79fca2b7dSJohn Levon */ 89fca2b7dSJohn Levon 99fca2b7dSJohn Levon #include <sys/ioctl.h> 109fca2b7dSJohn Levon #include "qemu/osdep.h" 119fca2b7dSJohn Levon #include "qapi-visit-sockets.h" 129fca2b7dSJohn Levon 139fca2b7dSJohn Levon #include "hw/qdev-properties.h" 149fca2b7dSJohn Levon #include "hw/vfio/pci.h" 15*667866d6SJohn Levon #include "hw/vfio-user/device.h" 16438d863fSJohn Levon #include "hw/vfio-user/proxy.h" 179fca2b7dSJohn Levon 189fca2b7dSJohn Levon #define TYPE_VFIO_USER_PCI "vfio-user-pci" 199fca2b7dSJohn Levon OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI) 209fca2b7dSJohn Levon 219fca2b7dSJohn Levon struct VFIOUserPCIDevice { 229fca2b7dSJohn Levon VFIOPCIDevice device; 239fca2b7dSJohn Levon SocketAddress *socket; 2436227628SJohn Levon bool send_queued; /* all sends are queued */ 259fca2b7dSJohn Levon }; 269fca2b7dSJohn Levon 279fca2b7dSJohn Levon /* 280b3d881aSJohn Levon * Incoming request message callback. 290b3d881aSJohn Levon * 300b3d881aSJohn Levon * Runs off main loop, so BQL held. 310b3d881aSJohn Levon */ 320b3d881aSJohn Levon static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg) 330b3d881aSJohn Levon { 340b3d881aSJohn Levon 350b3d881aSJohn Levon } 360b3d881aSJohn Levon 370b3d881aSJohn Levon /* 389fca2b7dSJohn Levon * Emulated devices don't use host hot reset 399fca2b7dSJohn Levon */ 409fca2b7dSJohn Levon static void vfio_user_compute_needs_reset(VFIODevice *vbasedev) 419fca2b7dSJohn Levon { 429fca2b7dSJohn Levon vbasedev->needs_reset = false; 439fca2b7dSJohn Levon } 449fca2b7dSJohn Levon 459fca2b7dSJohn Levon static Object *vfio_user_pci_get_object(VFIODevice *vbasedev) 469fca2b7dSJohn Levon { 479fca2b7dSJohn Levon VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice, 489fca2b7dSJohn Levon device.vbasedev); 499fca2b7dSJohn Levon 509fca2b7dSJohn Levon return OBJECT(vdev); 519fca2b7dSJohn Levon } 529fca2b7dSJohn Levon 539fca2b7dSJohn Levon static VFIODeviceOps vfio_user_pci_ops = { 549fca2b7dSJohn Levon .vfio_compute_needs_reset = vfio_user_compute_needs_reset, 559fca2b7dSJohn Levon .vfio_eoi = vfio_pci_intx_eoi, 569fca2b7dSJohn Levon .vfio_get_object = vfio_user_pci_get_object, 579fca2b7dSJohn Levon /* No live migration support yet. */ 589fca2b7dSJohn Levon .vfio_save_config = NULL, 599fca2b7dSJohn Levon .vfio_load_config = NULL, 609fca2b7dSJohn Levon }; 619fca2b7dSJohn Levon 629fca2b7dSJohn Levon static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) 639fca2b7dSJohn Levon { 649fca2b7dSJohn Levon ERRP_GUARD(); 659fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev); 669fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev); 679fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 689fca2b7dSJohn Levon const char *sock_name; 699fca2b7dSJohn Levon AddressSpace *as; 70438d863fSJohn Levon SocketAddress addr; 71438d863fSJohn Levon VFIOUserProxy *proxy; 729fca2b7dSJohn Levon 739fca2b7dSJohn Levon if (!udev->socket) { 749fca2b7dSJohn Levon error_setg(errp, "No socket specified"); 759fca2b7dSJohn Levon error_append_hint(errp, "e.g. -device '{" 769fca2b7dSJohn Levon "\"driver\":\"vfio-user-pci\", " 779fca2b7dSJohn Levon "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", " 789fca2b7dSJohn Levon "\"type\": \"unix\"}'" 799fca2b7dSJohn Levon "}'\n"); 809fca2b7dSJohn Levon return; 819fca2b7dSJohn Levon } 829fca2b7dSJohn Levon 839fca2b7dSJohn Levon sock_name = udev->socket->u.q_unix.path; 849fca2b7dSJohn Levon 859fca2b7dSJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name); 869fca2b7dSJohn Levon 87438d863fSJohn Levon memset(&addr, 0, sizeof(addr)); 88438d863fSJohn Levon addr.type = SOCKET_ADDRESS_TYPE_UNIX; 89438d863fSJohn Levon addr.u.q_unix.path = (char *)sock_name; 90438d863fSJohn Levon proxy = vfio_user_connect_dev(&addr, errp); 91438d863fSJohn Levon if (!proxy) { 92438d863fSJohn Levon return; 93438d863fSJohn Levon } 94438d863fSJohn Levon vbasedev->proxy = proxy; 950b3d881aSJohn Levon vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev); 96438d863fSJohn Levon 9736227628SJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name); 9836227628SJohn Levon 9936227628SJohn Levon if (udev->send_queued) { 10036227628SJohn Levon proxy->flags |= VFIO_PROXY_FORCE_QUEUED; 10136227628SJohn Levon } 10236227628SJohn Levon 10336227628SJohn Levon if (!vfio_user_validate_version(proxy, errp)) { 10436227628SJohn Levon goto error; 10536227628SJohn Levon } 10636227628SJohn Levon 1079fca2b7dSJohn Levon /* 108*667866d6SJohn Levon * Use socket-based device I/O instead of vfio kernel driver. 109*667866d6SJohn Levon */ 110*667866d6SJohn Levon vbasedev->io_ops = &vfio_user_device_io_ops_sock; 111*667866d6SJohn Levon 112*667866d6SJohn Levon /* 1139fca2b7dSJohn Levon * vfio-user devices are effectively mdevs (don't use a host iommu). 1149fca2b7dSJohn Levon */ 1159fca2b7dSJohn Levon vbasedev->mdev = true; 1169fca2b7dSJohn Levon 117*667866d6SJohn Levon /* 118*667866d6SJohn Levon * Enable per-region fds. 119*667866d6SJohn Levon */ 120*667866d6SJohn Levon vbasedev->use_region_fds = true; 121*667866d6SJohn Levon 1229fca2b7dSJohn Levon as = pci_device_iommu_address_space(pdev); 1239fca2b7dSJohn Levon if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER, 1249fca2b7dSJohn Levon vbasedev->name, vbasedev, 1259fca2b7dSJohn Levon as, errp)) { 12636227628SJohn Levon goto error; 1279fca2b7dSJohn Levon } 12836227628SJohn Levon 12936227628SJohn Levon return; 13036227628SJohn Levon 13136227628SJohn Levon error: 13236227628SJohn Levon error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); 1339fca2b7dSJohn Levon } 1349fca2b7dSJohn Levon 1359fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj) 1369fca2b7dSJohn Levon { 1379fca2b7dSJohn Levon PCIDevice *pci_dev = PCI_DEVICE(obj); 1389fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 1399fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 1409fca2b7dSJohn Levon 1419fca2b7dSJohn Levon device_add_bootindex_property(obj, &vdev->bootindex, 1429fca2b7dSJohn Levon "bootindex", NULL, 1439fca2b7dSJohn Levon &pci_dev->qdev); 1449fca2b7dSJohn Levon vdev->host.domain = ~0U; 1459fca2b7dSJohn Levon vdev->host.bus = ~0U; 1469fca2b7dSJohn Levon vdev->host.slot = ~0U; 1479fca2b7dSJohn Levon vdev->host.function = ~0U; 1489fca2b7dSJohn Levon 1499fca2b7dSJohn Levon vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops, 1509fca2b7dSJohn Levon DEVICE(vdev), false); 1519fca2b7dSJohn Levon 1529fca2b7dSJohn Levon vdev->nv_gpudirect_clique = 0xFF; 1539fca2b7dSJohn Levon 1549fca2b7dSJohn Levon /* 1559fca2b7dSJohn Levon * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command 1569fca2b7dSJohn Levon * line, therefore, no need to wait to realize like other devices. 1579fca2b7dSJohn Levon */ 1589fca2b7dSJohn Levon pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; 1599fca2b7dSJohn Levon } 1609fca2b7dSJohn Levon 1619fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj) 1629fca2b7dSJohn Levon { 1639fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 164438d863fSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 1659fca2b7dSJohn Levon 1669fca2b7dSJohn Levon vfio_pci_put_device(vdev); 167438d863fSJohn Levon 168438d863fSJohn Levon if (vbasedev->proxy != NULL) { 169438d863fSJohn Levon vfio_user_disconnect(vbasedev->proxy); 170438d863fSJohn Levon } 1719fca2b7dSJohn Levon } 1729fca2b7dSJohn Levon 1739fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = { 1749fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, 1759fca2b7dSJohn Levon vendor_id, PCI_ANY_ID), 1769fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, 1779fca2b7dSJohn Levon device_id, PCI_ANY_ID), 1789fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice, 1799fca2b7dSJohn Levon sub_vendor_id, PCI_ANY_ID), 1809fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice, 1819fca2b7dSJohn Levon sub_device_id, PCI_ANY_ID), 18236227628SJohn Levon DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false), 1839fca2b7dSJohn Levon }; 1849fca2b7dSJohn Levon 1859fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name, 1869fca2b7dSJohn Levon void *opaque, Error **errp) 1879fca2b7dSJohn Levon { 1889fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj); 1899fca2b7dSJohn Levon bool success; 1909fca2b7dSJohn Levon 191438d863fSJohn Levon if (udev->device.vbasedev.proxy) { 192438d863fSJohn Levon error_setg(errp, "Proxy is connected"); 193438d863fSJohn Levon return; 194438d863fSJohn Levon } 195438d863fSJohn Levon 1969fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 1979fca2b7dSJohn Levon 1989fca2b7dSJohn Levon udev->socket = NULL; 1999fca2b7dSJohn Levon 2009fca2b7dSJohn Levon success = visit_type_SocketAddress(v, name, &udev->socket, errp); 2019fca2b7dSJohn Levon 2029fca2b7dSJohn Levon if (!success) { 2039fca2b7dSJohn Levon return; 2049fca2b7dSJohn Levon } 2059fca2b7dSJohn Levon 2069fca2b7dSJohn Levon if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 2079fca2b7dSJohn Levon error_setg(errp, "Unsupported socket type %s", 2089fca2b7dSJohn Levon SocketAddressType_str(udev->socket->type)); 2099fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 2109fca2b7dSJohn Levon udev->socket = NULL; 2119fca2b7dSJohn Levon return; 2129fca2b7dSJohn Levon } 2139fca2b7dSJohn Levon } 2149fca2b7dSJohn Levon 2159fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data) 2169fca2b7dSJohn Levon { 2179fca2b7dSJohn Levon DeviceClass *dc = DEVICE_CLASS(klass); 2189fca2b7dSJohn Levon PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); 2199fca2b7dSJohn Levon 2209fca2b7dSJohn Levon device_class_set_props(dc, vfio_user_pci_dev_properties); 2219fca2b7dSJohn Levon 2229fca2b7dSJohn Levon object_class_property_add(klass, "socket", "SocketAddress", NULL, 2239fca2b7dSJohn Levon vfio_user_pci_set_socket, NULL, NULL); 2249fca2b7dSJohn Levon object_class_property_set_description(klass, "socket", 2259fca2b7dSJohn Levon "SocketAddress (UNIX sockets only)"); 2269fca2b7dSJohn Levon 2279fca2b7dSJohn Levon dc->desc = "VFIO over socket PCI device assignment"; 2289fca2b7dSJohn Levon pdc->realize = vfio_user_pci_realize; 2299fca2b7dSJohn Levon } 2309fca2b7dSJohn Levon 2319fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = { 2329fca2b7dSJohn Levon .name = TYPE_VFIO_USER_PCI, 2339fca2b7dSJohn Levon .parent = TYPE_VFIO_PCI_BASE, 2349fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserPCIDevice), 2359fca2b7dSJohn Levon .class_init = vfio_user_pci_dev_class_init, 2369fca2b7dSJohn Levon .instance_init = vfio_user_instance_init, 2379fca2b7dSJohn Levon .instance_finalize = vfio_user_instance_finalize, 2389fca2b7dSJohn Levon }; 2399fca2b7dSJohn Levon 2409fca2b7dSJohn Levon static void register_vfio_user_dev_type(void) 2419fca2b7dSJohn Levon { 2429fca2b7dSJohn Levon type_register_static(&vfio_user_pci_dev_info); 2439fca2b7dSJohn Levon } 2449fca2b7dSJohn Levon 2459fca2b7dSJohn Levon type_init(register_vfio_user_dev_type) 246