1*9fca2b7dSJohn Levon /* 2*9fca2b7dSJohn Levon * vfio PCI device over a UNIX socket. 3*9fca2b7dSJohn Levon * 4*9fca2b7dSJohn Levon * Copyright © 2018, 2021 Oracle and/or its affiliates. 5*9fca2b7dSJohn Levon * 6*9fca2b7dSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 7*9fca2b7dSJohn Levon */ 8*9fca2b7dSJohn Levon 9*9fca2b7dSJohn Levon #include <sys/ioctl.h> 10*9fca2b7dSJohn Levon #include "qemu/osdep.h" 11*9fca2b7dSJohn Levon #include "qapi-visit-sockets.h" 12*9fca2b7dSJohn Levon 13*9fca2b7dSJohn Levon #include "hw/qdev-properties.h" 14*9fca2b7dSJohn Levon #include "hw/vfio/pci.h" 15*9fca2b7dSJohn Levon 16*9fca2b7dSJohn Levon #define TYPE_VFIO_USER_PCI "vfio-user-pci" 17*9fca2b7dSJohn Levon OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI) 18*9fca2b7dSJohn Levon 19*9fca2b7dSJohn Levon struct VFIOUserPCIDevice { 20*9fca2b7dSJohn Levon VFIOPCIDevice device; 21*9fca2b7dSJohn Levon SocketAddress *socket; 22*9fca2b7dSJohn Levon }; 23*9fca2b7dSJohn Levon 24*9fca2b7dSJohn Levon /* 25*9fca2b7dSJohn Levon * Emulated devices don't use host hot reset 26*9fca2b7dSJohn Levon */ 27*9fca2b7dSJohn Levon static void vfio_user_compute_needs_reset(VFIODevice *vbasedev) 28*9fca2b7dSJohn Levon { 29*9fca2b7dSJohn Levon vbasedev->needs_reset = false; 30*9fca2b7dSJohn Levon } 31*9fca2b7dSJohn Levon 32*9fca2b7dSJohn Levon static Object *vfio_user_pci_get_object(VFIODevice *vbasedev) 33*9fca2b7dSJohn Levon { 34*9fca2b7dSJohn Levon VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice, 35*9fca2b7dSJohn Levon device.vbasedev); 36*9fca2b7dSJohn Levon 37*9fca2b7dSJohn Levon return OBJECT(vdev); 38*9fca2b7dSJohn Levon } 39*9fca2b7dSJohn Levon 40*9fca2b7dSJohn Levon static VFIODeviceOps vfio_user_pci_ops = { 41*9fca2b7dSJohn Levon .vfio_compute_needs_reset = vfio_user_compute_needs_reset, 42*9fca2b7dSJohn Levon .vfio_eoi = vfio_pci_intx_eoi, 43*9fca2b7dSJohn Levon .vfio_get_object = vfio_user_pci_get_object, 44*9fca2b7dSJohn Levon /* No live migration support yet. */ 45*9fca2b7dSJohn Levon .vfio_save_config = NULL, 46*9fca2b7dSJohn Levon .vfio_load_config = NULL, 47*9fca2b7dSJohn Levon }; 48*9fca2b7dSJohn Levon 49*9fca2b7dSJohn Levon static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) 50*9fca2b7dSJohn Levon { 51*9fca2b7dSJohn Levon ERRP_GUARD(); 52*9fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev); 53*9fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev); 54*9fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 55*9fca2b7dSJohn Levon const char *sock_name; 56*9fca2b7dSJohn Levon AddressSpace *as; 57*9fca2b7dSJohn Levon 58*9fca2b7dSJohn Levon if (!udev->socket) { 59*9fca2b7dSJohn Levon error_setg(errp, "No socket specified"); 60*9fca2b7dSJohn Levon error_append_hint(errp, "e.g. -device '{" 61*9fca2b7dSJohn Levon "\"driver\":\"vfio-user-pci\", " 62*9fca2b7dSJohn Levon "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", " 63*9fca2b7dSJohn Levon "\"type\": \"unix\"}'" 64*9fca2b7dSJohn Levon "}'\n"); 65*9fca2b7dSJohn Levon return; 66*9fca2b7dSJohn Levon } 67*9fca2b7dSJohn Levon 68*9fca2b7dSJohn Levon sock_name = udev->socket->u.q_unix.path; 69*9fca2b7dSJohn Levon 70*9fca2b7dSJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name); 71*9fca2b7dSJohn Levon 72*9fca2b7dSJohn Levon /* 73*9fca2b7dSJohn Levon * vfio-user devices are effectively mdevs (don't use a host iommu). 74*9fca2b7dSJohn Levon */ 75*9fca2b7dSJohn Levon vbasedev->mdev = true; 76*9fca2b7dSJohn Levon 77*9fca2b7dSJohn Levon as = pci_device_iommu_address_space(pdev); 78*9fca2b7dSJohn Levon if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER, 79*9fca2b7dSJohn Levon vbasedev->name, vbasedev, 80*9fca2b7dSJohn Levon as, errp)) { 81*9fca2b7dSJohn Levon error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name); 82*9fca2b7dSJohn Levon return; 83*9fca2b7dSJohn Levon } 84*9fca2b7dSJohn Levon } 85*9fca2b7dSJohn Levon 86*9fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj) 87*9fca2b7dSJohn Levon { 88*9fca2b7dSJohn Levon PCIDevice *pci_dev = PCI_DEVICE(obj); 89*9fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 90*9fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 91*9fca2b7dSJohn Levon 92*9fca2b7dSJohn Levon device_add_bootindex_property(obj, &vdev->bootindex, 93*9fca2b7dSJohn Levon "bootindex", NULL, 94*9fca2b7dSJohn Levon &pci_dev->qdev); 95*9fca2b7dSJohn Levon vdev->host.domain = ~0U; 96*9fca2b7dSJohn Levon vdev->host.bus = ~0U; 97*9fca2b7dSJohn Levon vdev->host.slot = ~0U; 98*9fca2b7dSJohn Levon vdev->host.function = ~0U; 99*9fca2b7dSJohn Levon 100*9fca2b7dSJohn Levon vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops, 101*9fca2b7dSJohn Levon DEVICE(vdev), false); 102*9fca2b7dSJohn Levon 103*9fca2b7dSJohn Levon vdev->nv_gpudirect_clique = 0xFF; 104*9fca2b7dSJohn Levon 105*9fca2b7dSJohn Levon /* 106*9fca2b7dSJohn Levon * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command 107*9fca2b7dSJohn Levon * line, therefore, no need to wait to realize like other devices. 108*9fca2b7dSJohn Levon */ 109*9fca2b7dSJohn Levon pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; 110*9fca2b7dSJohn Levon } 111*9fca2b7dSJohn Levon 112*9fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj) 113*9fca2b7dSJohn Levon { 114*9fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 115*9fca2b7dSJohn Levon 116*9fca2b7dSJohn Levon vfio_pci_put_device(vdev); 117*9fca2b7dSJohn Levon } 118*9fca2b7dSJohn Levon 119*9fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = { 120*9fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, 121*9fca2b7dSJohn Levon vendor_id, PCI_ANY_ID), 122*9fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, 123*9fca2b7dSJohn Levon device_id, PCI_ANY_ID), 124*9fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice, 125*9fca2b7dSJohn Levon sub_vendor_id, PCI_ANY_ID), 126*9fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice, 127*9fca2b7dSJohn Levon sub_device_id, PCI_ANY_ID), 128*9fca2b7dSJohn Levon }; 129*9fca2b7dSJohn Levon 130*9fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name, 131*9fca2b7dSJohn Levon void *opaque, Error **errp) 132*9fca2b7dSJohn Levon { 133*9fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj); 134*9fca2b7dSJohn Levon bool success; 135*9fca2b7dSJohn Levon 136*9fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 137*9fca2b7dSJohn Levon 138*9fca2b7dSJohn Levon udev->socket = NULL; 139*9fca2b7dSJohn Levon 140*9fca2b7dSJohn Levon success = visit_type_SocketAddress(v, name, &udev->socket, errp); 141*9fca2b7dSJohn Levon 142*9fca2b7dSJohn Levon if (!success) { 143*9fca2b7dSJohn Levon return; 144*9fca2b7dSJohn Levon } 145*9fca2b7dSJohn Levon 146*9fca2b7dSJohn Levon if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 147*9fca2b7dSJohn Levon error_setg(errp, "Unsupported socket type %s", 148*9fca2b7dSJohn Levon SocketAddressType_str(udev->socket->type)); 149*9fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 150*9fca2b7dSJohn Levon udev->socket = NULL; 151*9fca2b7dSJohn Levon return; 152*9fca2b7dSJohn Levon } 153*9fca2b7dSJohn Levon } 154*9fca2b7dSJohn Levon 155*9fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data) 156*9fca2b7dSJohn Levon { 157*9fca2b7dSJohn Levon DeviceClass *dc = DEVICE_CLASS(klass); 158*9fca2b7dSJohn Levon PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); 159*9fca2b7dSJohn Levon 160*9fca2b7dSJohn Levon device_class_set_props(dc, vfio_user_pci_dev_properties); 161*9fca2b7dSJohn Levon 162*9fca2b7dSJohn Levon object_class_property_add(klass, "socket", "SocketAddress", NULL, 163*9fca2b7dSJohn Levon vfio_user_pci_set_socket, NULL, NULL); 164*9fca2b7dSJohn Levon object_class_property_set_description(klass, "socket", 165*9fca2b7dSJohn Levon "SocketAddress (UNIX sockets only)"); 166*9fca2b7dSJohn Levon 167*9fca2b7dSJohn Levon dc->desc = "VFIO over socket PCI device assignment"; 168*9fca2b7dSJohn Levon pdc->realize = vfio_user_pci_realize; 169*9fca2b7dSJohn Levon } 170*9fca2b7dSJohn Levon 171*9fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = { 172*9fca2b7dSJohn Levon .name = TYPE_VFIO_USER_PCI, 173*9fca2b7dSJohn Levon .parent = TYPE_VFIO_PCI_BASE, 174*9fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserPCIDevice), 175*9fca2b7dSJohn Levon .class_init = vfio_user_pci_dev_class_init, 176*9fca2b7dSJohn Levon .instance_init = vfio_user_instance_init, 177*9fca2b7dSJohn Levon .instance_finalize = vfio_user_instance_finalize, 178*9fca2b7dSJohn Levon }; 179*9fca2b7dSJohn Levon 180*9fca2b7dSJohn Levon static void register_vfio_user_dev_type(void) 181*9fca2b7dSJohn Levon { 182*9fca2b7dSJohn Levon type_register_static(&vfio_user_pci_dev_info); 183*9fca2b7dSJohn Levon } 184*9fca2b7dSJohn Levon 185*9fca2b7dSJohn Levon type_init(register_vfio_user_dev_type) 186