xref: /qemu/hw/vfio-user/pci.c (revision 667866d66620e9f545eb3bd4f065d9ab81bda727)
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