xref: /qemu/hw/vfio-user/pci.c (revision 438d863f1f40fbc2b57bf94cc6c998a6445c0932)
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*438d863fSJohn Levon #include "hw/vfio-user/proxy.h"
169fca2b7dSJohn Levon 
179fca2b7dSJohn Levon #define TYPE_VFIO_USER_PCI "vfio-user-pci"
189fca2b7dSJohn Levon OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI)
199fca2b7dSJohn Levon 
209fca2b7dSJohn Levon struct VFIOUserPCIDevice {
219fca2b7dSJohn Levon     VFIOPCIDevice device;
229fca2b7dSJohn Levon     SocketAddress *socket;
239fca2b7dSJohn Levon };
249fca2b7dSJohn Levon 
259fca2b7dSJohn Levon /*
269fca2b7dSJohn Levon  * Emulated devices don't use host hot reset
279fca2b7dSJohn Levon  */
289fca2b7dSJohn Levon static void vfio_user_compute_needs_reset(VFIODevice *vbasedev)
299fca2b7dSJohn Levon {
309fca2b7dSJohn Levon     vbasedev->needs_reset = false;
319fca2b7dSJohn Levon }
329fca2b7dSJohn Levon 
339fca2b7dSJohn Levon static Object *vfio_user_pci_get_object(VFIODevice *vbasedev)
349fca2b7dSJohn Levon {
359fca2b7dSJohn Levon     VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice,
369fca2b7dSJohn Levon                                            device.vbasedev);
379fca2b7dSJohn Levon 
389fca2b7dSJohn Levon     return OBJECT(vdev);
399fca2b7dSJohn Levon }
409fca2b7dSJohn Levon 
419fca2b7dSJohn Levon static VFIODeviceOps vfio_user_pci_ops = {
429fca2b7dSJohn Levon     .vfio_compute_needs_reset = vfio_user_compute_needs_reset,
439fca2b7dSJohn Levon     .vfio_eoi = vfio_pci_intx_eoi,
449fca2b7dSJohn Levon     .vfio_get_object = vfio_user_pci_get_object,
459fca2b7dSJohn Levon     /* No live migration support yet. */
469fca2b7dSJohn Levon     .vfio_save_config = NULL,
479fca2b7dSJohn Levon     .vfio_load_config = NULL,
489fca2b7dSJohn Levon };
499fca2b7dSJohn Levon 
509fca2b7dSJohn Levon static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
519fca2b7dSJohn Levon {
529fca2b7dSJohn Levon     ERRP_GUARD();
539fca2b7dSJohn Levon     VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev);
549fca2b7dSJohn Levon     VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
559fca2b7dSJohn Levon     VFIODevice *vbasedev = &vdev->vbasedev;
569fca2b7dSJohn Levon     const char *sock_name;
579fca2b7dSJohn Levon     AddressSpace *as;
58*438d863fSJohn Levon     SocketAddress addr;
59*438d863fSJohn Levon     VFIOUserProxy *proxy;
609fca2b7dSJohn Levon 
619fca2b7dSJohn Levon     if (!udev->socket) {
629fca2b7dSJohn Levon         error_setg(errp, "No socket specified");
639fca2b7dSJohn Levon         error_append_hint(errp, "e.g. -device '{"
649fca2b7dSJohn Levon             "\"driver\":\"vfio-user-pci\", "
659fca2b7dSJohn Levon             "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", "
669fca2b7dSJohn Levon             "\"type\": \"unix\"}'"
679fca2b7dSJohn Levon             "}'\n");
689fca2b7dSJohn Levon         return;
699fca2b7dSJohn Levon     }
709fca2b7dSJohn Levon 
719fca2b7dSJohn Levon     sock_name = udev->socket->u.q_unix.path;
729fca2b7dSJohn Levon 
739fca2b7dSJohn Levon     vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
749fca2b7dSJohn Levon 
75*438d863fSJohn Levon     memset(&addr, 0, sizeof(addr));
76*438d863fSJohn Levon     addr.type = SOCKET_ADDRESS_TYPE_UNIX;
77*438d863fSJohn Levon     addr.u.q_unix.path = (char *)sock_name;
78*438d863fSJohn Levon     proxy = vfio_user_connect_dev(&addr, errp);
79*438d863fSJohn Levon     if (!proxy) {
80*438d863fSJohn Levon         return;
81*438d863fSJohn Levon     }
82*438d863fSJohn Levon     vbasedev->proxy = proxy;
83*438d863fSJohn Levon 
849fca2b7dSJohn Levon     /*
859fca2b7dSJohn Levon      * vfio-user devices are effectively mdevs (don't use a host iommu).
869fca2b7dSJohn Levon      */
879fca2b7dSJohn Levon     vbasedev->mdev = true;
889fca2b7dSJohn Levon 
899fca2b7dSJohn Levon     as = pci_device_iommu_address_space(pdev);
909fca2b7dSJohn Levon     if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER,
919fca2b7dSJohn Levon                                           vbasedev->name, vbasedev,
929fca2b7dSJohn Levon                                           as, errp)) {
939fca2b7dSJohn Levon         error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
949fca2b7dSJohn Levon         return;
959fca2b7dSJohn Levon     }
969fca2b7dSJohn Levon }
979fca2b7dSJohn Levon 
989fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj)
999fca2b7dSJohn Levon {
1009fca2b7dSJohn Levon     PCIDevice *pci_dev = PCI_DEVICE(obj);
1019fca2b7dSJohn Levon     VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
1029fca2b7dSJohn Levon     VFIODevice *vbasedev = &vdev->vbasedev;
1039fca2b7dSJohn Levon 
1049fca2b7dSJohn Levon     device_add_bootindex_property(obj, &vdev->bootindex,
1059fca2b7dSJohn Levon                                   "bootindex", NULL,
1069fca2b7dSJohn Levon                                   &pci_dev->qdev);
1079fca2b7dSJohn Levon     vdev->host.domain = ~0U;
1089fca2b7dSJohn Levon     vdev->host.bus = ~0U;
1099fca2b7dSJohn Levon     vdev->host.slot = ~0U;
1109fca2b7dSJohn Levon     vdev->host.function = ~0U;
1119fca2b7dSJohn Levon 
1129fca2b7dSJohn Levon     vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops,
1139fca2b7dSJohn Levon                      DEVICE(vdev), false);
1149fca2b7dSJohn Levon 
1159fca2b7dSJohn Levon     vdev->nv_gpudirect_clique = 0xFF;
1169fca2b7dSJohn Levon 
1179fca2b7dSJohn Levon     /*
1189fca2b7dSJohn Levon      * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
1199fca2b7dSJohn Levon      * line, therefore, no need to wait to realize like other devices.
1209fca2b7dSJohn Levon      */
1219fca2b7dSJohn Levon     pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
1229fca2b7dSJohn Levon }
1239fca2b7dSJohn Levon 
1249fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj)
1259fca2b7dSJohn Levon {
1269fca2b7dSJohn Levon     VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
127*438d863fSJohn Levon     VFIODevice *vbasedev = &vdev->vbasedev;
1289fca2b7dSJohn Levon 
1299fca2b7dSJohn Levon     vfio_pci_put_device(vdev);
130*438d863fSJohn Levon 
131*438d863fSJohn Levon     if (vbasedev->proxy != NULL) {
132*438d863fSJohn Levon         vfio_user_disconnect(vbasedev->proxy);
133*438d863fSJohn Levon     }
1349fca2b7dSJohn Levon }
1359fca2b7dSJohn Levon 
1369fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = {
1379fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice,
1389fca2b7dSJohn Levon                        vendor_id, PCI_ANY_ID),
1399fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice,
1409fca2b7dSJohn Levon                        device_id, PCI_ANY_ID),
1419fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
1429fca2b7dSJohn Levon                        sub_vendor_id, PCI_ANY_ID),
1439fca2b7dSJohn Levon     DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
1449fca2b7dSJohn Levon                        sub_device_id, PCI_ANY_ID),
1459fca2b7dSJohn Levon };
1469fca2b7dSJohn Levon 
1479fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name,
1489fca2b7dSJohn Levon                                      void *opaque, Error **errp)
1499fca2b7dSJohn Levon {
1509fca2b7dSJohn Levon     VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj);
1519fca2b7dSJohn Levon     bool success;
1529fca2b7dSJohn Levon 
153*438d863fSJohn Levon     if (udev->device.vbasedev.proxy) {
154*438d863fSJohn Levon         error_setg(errp, "Proxy is connected");
155*438d863fSJohn Levon         return;
156*438d863fSJohn Levon     }
157*438d863fSJohn Levon 
1589fca2b7dSJohn Levon     qapi_free_SocketAddress(udev->socket);
1599fca2b7dSJohn Levon 
1609fca2b7dSJohn Levon     udev->socket = NULL;
1619fca2b7dSJohn Levon 
1629fca2b7dSJohn Levon     success = visit_type_SocketAddress(v, name, &udev->socket, errp);
1639fca2b7dSJohn Levon 
1649fca2b7dSJohn Levon     if (!success) {
1659fca2b7dSJohn Levon         return;
1669fca2b7dSJohn Levon     }
1679fca2b7dSJohn Levon 
1689fca2b7dSJohn Levon     if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
1699fca2b7dSJohn Levon         error_setg(errp, "Unsupported socket type %s",
1709fca2b7dSJohn Levon                    SocketAddressType_str(udev->socket->type));
1719fca2b7dSJohn Levon         qapi_free_SocketAddress(udev->socket);
1729fca2b7dSJohn Levon         udev->socket = NULL;
1739fca2b7dSJohn Levon         return;
1749fca2b7dSJohn Levon     }
1759fca2b7dSJohn Levon }
1769fca2b7dSJohn Levon 
1779fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data)
1789fca2b7dSJohn Levon {
1799fca2b7dSJohn Levon     DeviceClass *dc = DEVICE_CLASS(klass);
1809fca2b7dSJohn Levon     PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
1819fca2b7dSJohn Levon 
1829fca2b7dSJohn Levon     device_class_set_props(dc, vfio_user_pci_dev_properties);
1839fca2b7dSJohn Levon 
1849fca2b7dSJohn Levon     object_class_property_add(klass, "socket", "SocketAddress", NULL,
1859fca2b7dSJohn Levon                               vfio_user_pci_set_socket, NULL, NULL);
1869fca2b7dSJohn Levon     object_class_property_set_description(klass, "socket",
1879fca2b7dSJohn Levon                                           "SocketAddress (UNIX sockets only)");
1889fca2b7dSJohn Levon 
1899fca2b7dSJohn Levon     dc->desc = "VFIO over socket PCI device assignment";
1909fca2b7dSJohn Levon     pdc->realize = vfio_user_pci_realize;
1919fca2b7dSJohn Levon }
1929fca2b7dSJohn Levon 
1939fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = {
1949fca2b7dSJohn Levon     .name = TYPE_VFIO_USER_PCI,
1959fca2b7dSJohn Levon     .parent = TYPE_VFIO_PCI_BASE,
1969fca2b7dSJohn Levon     .instance_size = sizeof(VFIOUserPCIDevice),
1979fca2b7dSJohn Levon     .class_init = vfio_user_pci_dev_class_init,
1989fca2b7dSJohn Levon     .instance_init = vfio_user_instance_init,
1999fca2b7dSJohn Levon     .instance_finalize = vfio_user_instance_finalize,
2009fca2b7dSJohn Levon };
2019fca2b7dSJohn Levon 
2029fca2b7dSJohn Levon static void register_vfio_user_dev_type(void)
2039fca2b7dSJohn Levon {
2049fca2b7dSJohn Levon     type_register_static(&vfio_user_pci_dev_info);
2059fca2b7dSJohn Levon }
2069fca2b7dSJohn Levon 
2079fca2b7dSJohn Levon  type_init(register_vfio_user_dev_type)
208