xref: /qemu/hw/vfio-user/pci.c (revision 692e0ec50c2f38a7952f7e7c4c375c77b141f6b2)
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"
15667866d6SJohn 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     /*
108667866d6SJohn Levon      * Use socket-based device I/O instead of vfio kernel driver.
109667866d6SJohn Levon      */
110667866d6SJohn Levon     vbasedev->io_ops = &vfio_user_device_io_ops_sock;
111667866d6SJohn Levon 
112667866d6SJohn Levon     /*
1139fca2b7dSJohn Levon      * vfio-user devices are effectively mdevs (don't use a host iommu).
1149fca2b7dSJohn Levon      */
1159fca2b7dSJohn Levon     vbasedev->mdev = true;
1169fca2b7dSJohn Levon 
117667866d6SJohn Levon     /*
118667866d6SJohn Levon      * Enable per-region fds.
119667866d6SJohn Levon      */
120667866d6SJohn Levon     vbasedev->use_region_fds = true;
121667866d6SJohn 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 
129*692e0ec5SJohn Levon     if (!vfio_pci_populate_device(vdev, errp)) {
130*692e0ec5SJohn Levon         goto error;
131*692e0ec5SJohn Levon     }
132*692e0ec5SJohn Levon 
133*692e0ec5SJohn Levon     if (!vfio_pci_config_setup(vdev, errp)) {
134*692e0ec5SJohn Levon         goto error;
135*692e0ec5SJohn Levon     }
136*692e0ec5SJohn Levon 
137*692e0ec5SJohn Levon     /*
138*692e0ec5SJohn Levon      * vfio_pci_config_setup will have registered the device's BARs
139*692e0ec5SJohn Levon      * and setup any MSIX BARs, so errors after it succeeds must
140*692e0ec5SJohn Levon      * use out_teardown
141*692e0ec5SJohn Levon      */
142*692e0ec5SJohn Levon 
143*692e0ec5SJohn Levon     if (!vfio_pci_add_capabilities(vdev, errp)) {
144*692e0ec5SJohn Levon         goto out_teardown;
145*692e0ec5SJohn Levon     }
146*692e0ec5SJohn Levon 
147*692e0ec5SJohn Levon     if (!vfio_pci_interrupt_setup(vdev, errp)) {
148*692e0ec5SJohn Levon         goto out_teardown;
149*692e0ec5SJohn Levon     }
150*692e0ec5SJohn Levon 
151*692e0ec5SJohn Levon     vfio_pci_register_err_notifier(vdev);
152*692e0ec5SJohn Levon     vfio_pci_register_req_notifier(vdev);
153*692e0ec5SJohn Levon 
15436227628SJohn Levon     return;
15536227628SJohn Levon 
156*692e0ec5SJohn Levon out_teardown:
157*692e0ec5SJohn Levon     vfio_pci_teardown_msi(vdev);
158*692e0ec5SJohn Levon     vfio_pci_bars_exit(vdev);
15936227628SJohn Levon error:
16036227628SJohn Levon     error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
161*692e0ec5SJohn Levon     vfio_pci_put_device(vdev);
1629fca2b7dSJohn Levon }
1639fca2b7dSJohn Levon 
1649fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj)
1659fca2b7dSJohn Levon {
1669fca2b7dSJohn Levon     PCIDevice *pci_dev = PCI_DEVICE(obj);
1679fca2b7dSJohn Levon     VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
1689fca2b7dSJohn Levon     VFIODevice *vbasedev = &vdev->vbasedev;
1699fca2b7dSJohn Levon 
1709fca2b7dSJohn Levon     device_add_bootindex_property(obj, &vdev->bootindex,
1719fca2b7dSJohn Levon                                   "bootindex", NULL,
1729fca2b7dSJohn Levon                                   &pci_dev->qdev);
1739fca2b7dSJohn Levon     vdev->host.domain = ~0U;
1749fca2b7dSJohn Levon     vdev->host.bus = ~0U;
1759fca2b7dSJohn Levon     vdev->host.slot = ~0U;
1769fca2b7dSJohn Levon     vdev->host.function = ~0U;
1779fca2b7dSJohn Levon 
1789fca2b7dSJohn Levon     vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops,
1799fca2b7dSJohn Levon                      DEVICE(vdev), false);
1809fca2b7dSJohn Levon 
1819fca2b7dSJohn Levon     vdev->nv_gpudirect_clique = 0xFF;
1829fca2b7dSJohn Levon 
1839fca2b7dSJohn Levon     /*
1849fca2b7dSJohn Levon      * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
1859fca2b7dSJohn Levon      * line, therefore, no need to wait to realize like other devices.
1869fca2b7dSJohn Levon      */
1879fca2b7dSJohn Levon     pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
1889fca2b7dSJohn Levon }
1899fca2b7dSJohn Levon 
1909fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj)
1919fca2b7dSJohn Levon {
1929fca2b7dSJohn Levon     VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
193438d863fSJohn Levon     VFIODevice *vbasedev = &vdev->vbasedev;
1949fca2b7dSJohn Levon 
1959fca2b7dSJohn Levon     vfio_pci_put_device(vdev);
196438d863fSJohn Levon 
197438d863fSJohn Levon     if (vbasedev->proxy != NULL) {
198438d863fSJohn Levon         vfio_user_disconnect(vbasedev->proxy);
199438d863fSJohn Levon     }
2009fca2b7dSJohn Levon }
2019fca2b7dSJohn Levon 
2029fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = {
2039fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice,
2049fca2b7dSJohn Levon                        vendor_id, PCI_ANY_ID),
2059fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice,
2069fca2b7dSJohn Levon                        device_id, PCI_ANY_ID),
2079fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
2089fca2b7dSJohn Levon                        sub_vendor_id, PCI_ANY_ID),
2099fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
2109fca2b7dSJohn Levon                        sub_device_id, PCI_ANY_ID),
21136227628SJohn Levon     DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false),
2129fca2b7dSJohn Levon };
2139fca2b7dSJohn Levon 
2149fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name,
2159fca2b7dSJohn Levon                                      void *opaque, Error **errp)
2169fca2b7dSJohn Levon {
2179fca2b7dSJohn Levon     VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj);
2189fca2b7dSJohn Levon     bool success;
2199fca2b7dSJohn Levon 
220438d863fSJohn Levon     if (udev->device.vbasedev.proxy) {
221438d863fSJohn Levon         error_setg(errp, "Proxy is connected");
222438d863fSJohn Levon         return;
223438d863fSJohn Levon     }
224438d863fSJohn Levon 
2259fca2b7dSJohn Levon     qapi_free_SocketAddress(udev->socket);
2269fca2b7dSJohn Levon 
2279fca2b7dSJohn Levon     udev->socket = NULL;
2289fca2b7dSJohn Levon 
2299fca2b7dSJohn Levon     success = visit_type_SocketAddress(v, name, &udev->socket, errp);
2309fca2b7dSJohn Levon 
2319fca2b7dSJohn Levon     if (!success) {
2329fca2b7dSJohn Levon         return;
2339fca2b7dSJohn Levon     }
2349fca2b7dSJohn Levon 
2359fca2b7dSJohn Levon     if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
2369fca2b7dSJohn Levon         error_setg(errp, "Unsupported socket type %s",
2379fca2b7dSJohn Levon                    SocketAddressType_str(udev->socket->type));
2389fca2b7dSJohn Levon         qapi_free_SocketAddress(udev->socket);
2399fca2b7dSJohn Levon         udev->socket = NULL;
2409fca2b7dSJohn Levon         return;
2419fca2b7dSJohn Levon     }
2429fca2b7dSJohn Levon }
2439fca2b7dSJohn Levon 
2449fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data)
2459fca2b7dSJohn Levon {
2469fca2b7dSJohn Levon     DeviceClass *dc = DEVICE_CLASS(klass);
2479fca2b7dSJohn Levon     PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
2489fca2b7dSJohn Levon 
2499fca2b7dSJohn Levon     device_class_set_props(dc, vfio_user_pci_dev_properties);
2509fca2b7dSJohn Levon 
2519fca2b7dSJohn Levon     object_class_property_add(klass, "socket", "SocketAddress", NULL,
2529fca2b7dSJohn Levon                               vfio_user_pci_set_socket, NULL, NULL);
2539fca2b7dSJohn Levon     object_class_property_set_description(klass, "socket",
2549fca2b7dSJohn Levon                                           "SocketAddress (UNIX sockets only)");
2559fca2b7dSJohn Levon 
2569fca2b7dSJohn Levon     dc->desc = "VFIO over socket PCI device assignment";
2579fca2b7dSJohn Levon     pdc->realize = vfio_user_pci_realize;
2589fca2b7dSJohn Levon }
2599fca2b7dSJohn Levon 
2609fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = {
2619fca2b7dSJohn Levon     .name = TYPE_VFIO_USER_PCI,
2629fca2b7dSJohn Levon     .parent = TYPE_VFIO_PCI_BASE,
2639fca2b7dSJohn Levon     .instance_size = sizeof(VFIOUserPCIDevice),
2649fca2b7dSJohn Levon     .class_init = vfio_user_pci_dev_class_init,
2659fca2b7dSJohn Levon     .instance_init = vfio_user_instance_init,
2669fca2b7dSJohn Levon     .instance_finalize = vfio_user_instance_finalize,
2679fca2b7dSJohn Levon };
2689fca2b7dSJohn Levon 
2699fca2b7dSJohn Levon static void register_vfio_user_dev_type(void)
2709fca2b7dSJohn Levon {
2719fca2b7dSJohn Levon     type_register_static(&vfio_user_pci_dev_info);
2729fca2b7dSJohn Levon }
2739fca2b7dSJohn Levon 
2749fca2b7dSJohn Levon  type_init(register_vfio_user_dev_type)
275