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" 12c6ac52a4SJohn Levon #include "qemu/error-report.h" 139fca2b7dSJohn Levon 149fca2b7dSJohn Levon #include "hw/qdev-properties.h" 159fca2b7dSJohn Levon #include "hw/vfio/pci.h" 16667866d6SJohn Levon #include "hw/vfio-user/device.h" 17438d863fSJohn Levon #include "hw/vfio-user/proxy.h" 189fca2b7dSJohn Levon 199fca2b7dSJohn Levon #define TYPE_VFIO_USER_PCI "vfio-user-pci" 209fca2b7dSJohn Levon OBJECT_DECLARE_SIMPLE_TYPE(VFIOUserPCIDevice, VFIO_USER_PCI) 219fca2b7dSJohn Levon 229fca2b7dSJohn Levon struct VFIOUserPCIDevice { 239fca2b7dSJohn Levon VFIOPCIDevice device; 249fca2b7dSJohn Levon SocketAddress *socket; 2536227628SJohn Levon bool send_queued; /* all sends are queued */ 26*3358d926SJohn Levon uint32_t wait_time; /* timeout for message replies */ 279fca2b7dSJohn Levon }; 289fca2b7dSJohn Levon 299fca2b7dSJohn Levon /* 30777e45c7SJohn Levon * The server maintains the device's pending interrupts, 31777e45c7SJohn Levon * via its MSIX table and PBA, so we treat these accesses 32777e45c7SJohn Levon * like PCI config space and forward them. 33777e45c7SJohn Levon */ 34777e45c7SJohn Levon static uint64_t vfio_user_pba_read(void *opaque, hwaddr addr, 35777e45c7SJohn Levon unsigned size) 36777e45c7SJohn Levon { 37777e45c7SJohn Levon VFIOPCIDevice *vdev = opaque; 38777e45c7SJohn Levon VFIORegion *region = &vdev->bars[vdev->msix->pba_bar].region; 39777e45c7SJohn Levon uint64_t data; 40777e45c7SJohn Levon 41777e45c7SJohn Levon /* server copy is what matters */ 42777e45c7SJohn Levon data = vfio_region_read(region, addr + vdev->msix->pba_offset, size); 43777e45c7SJohn Levon return data; 44777e45c7SJohn Levon } 45777e45c7SJohn Levon 46777e45c7SJohn Levon static void vfio_user_pba_write(void *opaque, hwaddr addr, 47777e45c7SJohn Levon uint64_t data, unsigned size) 48777e45c7SJohn Levon { 49777e45c7SJohn Levon /* dropped */ 50777e45c7SJohn Levon } 51777e45c7SJohn Levon 52777e45c7SJohn Levon static const MemoryRegionOps vfio_user_pba_ops = { 53777e45c7SJohn Levon .read = vfio_user_pba_read, 54777e45c7SJohn Levon .write = vfio_user_pba_write, 55777e45c7SJohn Levon .endianness = DEVICE_LITTLE_ENDIAN, 56777e45c7SJohn Levon }; 57777e45c7SJohn Levon 58777e45c7SJohn Levon static void vfio_user_msix_setup(VFIOPCIDevice *vdev) 59777e45c7SJohn Levon { 60777e45c7SJohn Levon MemoryRegion *vfio_reg, *msix_reg, *pba_reg; 61777e45c7SJohn Levon 62777e45c7SJohn Levon pba_reg = g_new0(MemoryRegion, 1); 63777e45c7SJohn Levon vdev->msix->pba_region = pba_reg; 64777e45c7SJohn Levon 65777e45c7SJohn Levon vfio_reg = vdev->bars[vdev->msix->pba_bar].mr; 66777e45c7SJohn Levon msix_reg = &vdev->pdev.msix_pba_mmio; 67777e45c7SJohn Levon memory_region_init_io(pba_reg, OBJECT(vdev), &vfio_user_pba_ops, vdev, 68777e45c7SJohn Levon "VFIO MSIX PBA", int128_get64(msix_reg->size)); 69777e45c7SJohn Levon memory_region_add_subregion_overlap(vfio_reg, vdev->msix->pba_offset, 70777e45c7SJohn Levon pba_reg, 1); 71777e45c7SJohn Levon } 72777e45c7SJohn Levon 73777e45c7SJohn Levon static void vfio_user_msix_teardown(VFIOPCIDevice *vdev) 74777e45c7SJohn Levon { 75777e45c7SJohn Levon MemoryRegion *mr, *sub; 76777e45c7SJohn Levon 77777e45c7SJohn Levon mr = vdev->bars[vdev->msix->pba_bar].mr; 78777e45c7SJohn Levon sub = vdev->msix->pba_region; 79777e45c7SJohn Levon memory_region_del_subregion(mr, sub); 80777e45c7SJohn Levon 81777e45c7SJohn Levon g_free(vdev->msix->pba_region); 82777e45c7SJohn Levon vdev->msix->pba_region = NULL; 83777e45c7SJohn Levon } 84777e45c7SJohn Levon 85c6ac52a4SJohn Levon static void vfio_user_dma_read(VFIOPCIDevice *vdev, VFIOUserDMARW *msg) 86c6ac52a4SJohn Levon { 87c6ac52a4SJohn Levon PCIDevice *pdev = &vdev->pdev; 88c6ac52a4SJohn Levon VFIOUserProxy *proxy = vdev->vbasedev.proxy; 89c6ac52a4SJohn Levon VFIOUserDMARW *res; 90c6ac52a4SJohn Levon MemTxResult r; 91c6ac52a4SJohn Levon size_t size; 92c6ac52a4SJohn Levon 93c6ac52a4SJohn Levon if (msg->hdr.size < sizeof(*msg)) { 94c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EINVAL); 95c6ac52a4SJohn Levon return; 96c6ac52a4SJohn Levon } 97c6ac52a4SJohn Levon if (msg->count > proxy->max_xfer_size) { 98c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, E2BIG); 99c6ac52a4SJohn Levon return; 100c6ac52a4SJohn Levon } 101c6ac52a4SJohn Levon 102c6ac52a4SJohn Levon /* switch to our own message buffer */ 103c6ac52a4SJohn Levon size = msg->count + sizeof(VFIOUserDMARW); 104c6ac52a4SJohn Levon res = g_malloc0(size); 105c6ac52a4SJohn Levon memcpy(res, msg, sizeof(*res)); 106c6ac52a4SJohn Levon g_free(msg); 107c6ac52a4SJohn Levon 108c6ac52a4SJohn Levon r = pci_dma_read(pdev, res->offset, &res->data, res->count); 109c6ac52a4SJohn Levon 110c6ac52a4SJohn Levon switch (r) { 111c6ac52a4SJohn Levon case MEMTX_OK: 112c6ac52a4SJohn Levon if (res->hdr.flags & VFIO_USER_NO_REPLY) { 113c6ac52a4SJohn Levon g_free(res); 114c6ac52a4SJohn Levon return; 115c6ac52a4SJohn Levon } 116c6ac52a4SJohn Levon vfio_user_send_reply(proxy, &res->hdr, size); 117c6ac52a4SJohn Levon break; 118c6ac52a4SJohn Levon case MEMTX_ERROR: 119c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, EFAULT); 120c6ac52a4SJohn Levon break; 121c6ac52a4SJohn Levon case MEMTX_DECODE_ERROR: 122c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, ENODEV); 123c6ac52a4SJohn Levon break; 124c6ac52a4SJohn Levon case MEMTX_ACCESS_ERROR: 125c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, EPERM); 126c6ac52a4SJohn Levon break; 127c6ac52a4SJohn Levon default: 128c6ac52a4SJohn Levon error_printf("vfio_user_dma_read unknown error %d\n", r); 129c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, &res->hdr, EINVAL); 130c6ac52a4SJohn Levon } 131c6ac52a4SJohn Levon } 132c6ac52a4SJohn Levon 133c6ac52a4SJohn Levon static void vfio_user_dma_write(VFIOPCIDevice *vdev, VFIOUserDMARW *msg) 134c6ac52a4SJohn Levon { 135c6ac52a4SJohn Levon PCIDevice *pdev = &vdev->pdev; 136c6ac52a4SJohn Levon VFIOUserProxy *proxy = vdev->vbasedev.proxy; 137c6ac52a4SJohn Levon MemTxResult r; 138c6ac52a4SJohn Levon 139c6ac52a4SJohn Levon if (msg->hdr.size < sizeof(*msg)) { 140c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EINVAL); 141c6ac52a4SJohn Levon return; 142c6ac52a4SJohn Levon } 143c6ac52a4SJohn Levon /* make sure transfer count isn't larger than the message data */ 144c6ac52a4SJohn Levon if (msg->count > msg->hdr.size - sizeof(*msg)) { 145c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, E2BIG); 146c6ac52a4SJohn Levon return; 147c6ac52a4SJohn Levon } 148c6ac52a4SJohn Levon 149c6ac52a4SJohn Levon r = pci_dma_write(pdev, msg->offset, &msg->data, msg->count); 150c6ac52a4SJohn Levon 151c6ac52a4SJohn Levon switch (r) { 152c6ac52a4SJohn Levon case MEMTX_OK: 153c6ac52a4SJohn Levon if ((msg->hdr.flags & VFIO_USER_NO_REPLY) == 0) { 154c6ac52a4SJohn Levon vfio_user_send_reply(proxy, &msg->hdr, sizeof(msg->hdr)); 155c6ac52a4SJohn Levon } else { 156c6ac52a4SJohn Levon g_free(msg); 157c6ac52a4SJohn Levon } 158c6ac52a4SJohn Levon break; 159c6ac52a4SJohn Levon case MEMTX_ERROR: 160c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EFAULT); 161c6ac52a4SJohn Levon break; 162c6ac52a4SJohn Levon case MEMTX_DECODE_ERROR: 163c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, ENODEV); 164c6ac52a4SJohn Levon break; 165c6ac52a4SJohn Levon case MEMTX_ACCESS_ERROR: 166c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EPERM); 167c6ac52a4SJohn Levon break; 168c6ac52a4SJohn Levon default: 169c6ac52a4SJohn Levon error_printf("vfio_user_dma_write unknown error %d\n", r); 170c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, &msg->hdr, EINVAL); 171c6ac52a4SJohn Levon } 172c6ac52a4SJohn Levon } 173c6ac52a4SJohn Levon 174777e45c7SJohn Levon /* 1750b3d881aSJohn Levon * Incoming request message callback. 1760b3d881aSJohn Levon * 1770b3d881aSJohn Levon * Runs off main loop, so BQL held. 1780b3d881aSJohn Levon */ 1790b3d881aSJohn Levon static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg) 1800b3d881aSJohn Levon { 181c6ac52a4SJohn Levon VFIOPCIDevice *vdev = opaque; 182c6ac52a4SJohn Levon VFIOUserHdr *hdr = msg->hdr; 1830b3d881aSJohn Levon 184c6ac52a4SJohn Levon /* no incoming PCI requests pass FDs */ 185c6ac52a4SJohn Levon if (msg->fds != NULL) { 186c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, hdr, EINVAL); 187c6ac52a4SJohn Levon vfio_user_putfds(msg); 188c6ac52a4SJohn Levon return; 189c6ac52a4SJohn Levon } 190c6ac52a4SJohn Levon 191c6ac52a4SJohn Levon switch (hdr->command) { 192c6ac52a4SJohn Levon case VFIO_USER_DMA_READ: 193c6ac52a4SJohn Levon vfio_user_dma_read(vdev, (VFIOUserDMARW *)hdr); 194c6ac52a4SJohn Levon break; 195c6ac52a4SJohn Levon case VFIO_USER_DMA_WRITE: 196c6ac52a4SJohn Levon vfio_user_dma_write(vdev, (VFIOUserDMARW *)hdr); 197c6ac52a4SJohn Levon break; 198c6ac52a4SJohn Levon default: 199c6ac52a4SJohn Levon error_printf("vfio_user_pci_process_req unknown cmd %d\n", 200c6ac52a4SJohn Levon hdr->command); 201c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, hdr, ENOSYS); 202c6ac52a4SJohn Levon } 2030b3d881aSJohn Levon } 2040b3d881aSJohn Levon 2050b3d881aSJohn Levon /* 2069fca2b7dSJohn Levon * Emulated devices don't use host hot reset 2079fca2b7dSJohn Levon */ 2089fca2b7dSJohn Levon static void vfio_user_compute_needs_reset(VFIODevice *vbasedev) 2099fca2b7dSJohn Levon { 2109fca2b7dSJohn Levon vbasedev->needs_reset = false; 2119fca2b7dSJohn Levon } 2129fca2b7dSJohn Levon 2139fca2b7dSJohn Levon static Object *vfio_user_pci_get_object(VFIODevice *vbasedev) 2149fca2b7dSJohn Levon { 2159fca2b7dSJohn Levon VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice, 2169fca2b7dSJohn Levon device.vbasedev); 2179fca2b7dSJohn Levon 2189fca2b7dSJohn Levon return OBJECT(vdev); 2199fca2b7dSJohn Levon } 2209fca2b7dSJohn Levon 2219fca2b7dSJohn Levon static VFIODeviceOps vfio_user_pci_ops = { 2229fca2b7dSJohn Levon .vfio_compute_needs_reset = vfio_user_compute_needs_reset, 2239fca2b7dSJohn Levon .vfio_eoi = vfio_pci_intx_eoi, 2249fca2b7dSJohn Levon .vfio_get_object = vfio_user_pci_get_object, 2259fca2b7dSJohn Levon /* No live migration support yet. */ 2269fca2b7dSJohn Levon .vfio_save_config = NULL, 2279fca2b7dSJohn Levon .vfio_load_config = NULL, 2289fca2b7dSJohn Levon }; 2299fca2b7dSJohn Levon 2309fca2b7dSJohn Levon static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) 2319fca2b7dSJohn Levon { 2329fca2b7dSJohn Levon ERRP_GUARD(); 2339fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev); 2349fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev); 2359fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 2369fca2b7dSJohn Levon const char *sock_name; 2379fca2b7dSJohn Levon AddressSpace *as; 238438d863fSJohn Levon SocketAddress addr; 239438d863fSJohn Levon VFIOUserProxy *proxy; 2409fca2b7dSJohn Levon 2419fca2b7dSJohn Levon if (!udev->socket) { 2429fca2b7dSJohn Levon error_setg(errp, "No socket specified"); 2439fca2b7dSJohn Levon error_append_hint(errp, "e.g. -device '{" 2449fca2b7dSJohn Levon "\"driver\":\"vfio-user-pci\", " 2459fca2b7dSJohn Levon "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", " 2469fca2b7dSJohn Levon "\"type\": \"unix\"}'" 2479fca2b7dSJohn Levon "}'\n"); 2489fca2b7dSJohn Levon return; 2499fca2b7dSJohn Levon } 2509fca2b7dSJohn Levon 2519fca2b7dSJohn Levon sock_name = udev->socket->u.q_unix.path; 2529fca2b7dSJohn Levon 2539fca2b7dSJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name); 2549fca2b7dSJohn Levon 255438d863fSJohn Levon memset(&addr, 0, sizeof(addr)); 256438d863fSJohn Levon addr.type = SOCKET_ADDRESS_TYPE_UNIX; 257438d863fSJohn Levon addr.u.q_unix.path = (char *)sock_name; 258438d863fSJohn Levon proxy = vfio_user_connect_dev(&addr, errp); 259438d863fSJohn Levon if (!proxy) { 260438d863fSJohn Levon return; 261438d863fSJohn Levon } 262438d863fSJohn Levon vbasedev->proxy = proxy; 2630b3d881aSJohn Levon vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev); 264438d863fSJohn Levon 26536227628SJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name); 26636227628SJohn Levon 26736227628SJohn Levon if (udev->send_queued) { 26836227628SJohn Levon proxy->flags |= VFIO_PROXY_FORCE_QUEUED; 26936227628SJohn Levon } 27036227628SJohn Levon 271*3358d926SJohn Levon /* user specified or 5 sec default */ 272*3358d926SJohn Levon proxy->wait_time = udev->wait_time; 273*3358d926SJohn Levon 27436227628SJohn Levon if (!vfio_user_validate_version(proxy, errp)) { 27536227628SJohn Levon goto error; 27636227628SJohn Levon } 27736227628SJohn Levon 2789fca2b7dSJohn Levon /* 279667866d6SJohn Levon * Use socket-based device I/O instead of vfio kernel driver. 280667866d6SJohn Levon */ 281667866d6SJohn Levon vbasedev->io_ops = &vfio_user_device_io_ops_sock; 282667866d6SJohn Levon 283667866d6SJohn Levon /* 2849fca2b7dSJohn Levon * vfio-user devices are effectively mdevs (don't use a host iommu). 2859fca2b7dSJohn Levon */ 2869fca2b7dSJohn Levon vbasedev->mdev = true; 2879fca2b7dSJohn Levon 288667866d6SJohn Levon /* 289667866d6SJohn Levon * Enable per-region fds. 290667866d6SJohn Levon */ 291667866d6SJohn Levon vbasedev->use_region_fds = true; 292667866d6SJohn Levon 2939fca2b7dSJohn Levon as = pci_device_iommu_address_space(pdev); 2949fca2b7dSJohn Levon if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER, 2959fca2b7dSJohn Levon vbasedev->name, vbasedev, 2969fca2b7dSJohn Levon as, errp)) { 29736227628SJohn Levon goto error; 2989fca2b7dSJohn Levon } 29936227628SJohn Levon 300692e0ec5SJohn Levon if (!vfio_pci_populate_device(vdev, errp)) { 301692e0ec5SJohn Levon goto error; 302692e0ec5SJohn Levon } 303692e0ec5SJohn Levon 304692e0ec5SJohn Levon if (!vfio_pci_config_setup(vdev, errp)) { 305692e0ec5SJohn Levon goto error; 306692e0ec5SJohn Levon } 307692e0ec5SJohn Levon 308692e0ec5SJohn Levon /* 309692e0ec5SJohn Levon * vfio_pci_config_setup will have registered the device's BARs 310692e0ec5SJohn Levon * and setup any MSIX BARs, so errors after it succeeds must 311692e0ec5SJohn Levon * use out_teardown 312692e0ec5SJohn Levon */ 313692e0ec5SJohn Levon 314692e0ec5SJohn Levon if (!vfio_pci_add_capabilities(vdev, errp)) { 315692e0ec5SJohn Levon goto out_teardown; 316692e0ec5SJohn Levon } 317692e0ec5SJohn Levon 318777e45c7SJohn Levon if (vdev->msix != NULL) { 319777e45c7SJohn Levon vfio_user_msix_setup(vdev); 320777e45c7SJohn Levon } 321777e45c7SJohn Levon 322692e0ec5SJohn Levon if (!vfio_pci_interrupt_setup(vdev, errp)) { 323692e0ec5SJohn Levon goto out_teardown; 324692e0ec5SJohn Levon } 325692e0ec5SJohn Levon 326692e0ec5SJohn Levon vfio_pci_register_err_notifier(vdev); 327692e0ec5SJohn Levon vfio_pci_register_req_notifier(vdev); 328692e0ec5SJohn Levon 32936227628SJohn Levon return; 33036227628SJohn Levon 331692e0ec5SJohn Levon out_teardown: 332692e0ec5SJohn Levon vfio_pci_teardown_msi(vdev); 333692e0ec5SJohn Levon vfio_pci_bars_exit(vdev); 33436227628SJohn Levon error: 33536227628SJohn Levon error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); 336692e0ec5SJohn Levon vfio_pci_put_device(vdev); 3379fca2b7dSJohn Levon } 3389fca2b7dSJohn Levon 3399fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj) 3409fca2b7dSJohn Levon { 3419fca2b7dSJohn Levon PCIDevice *pci_dev = PCI_DEVICE(obj); 3429fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 3439fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 3449fca2b7dSJohn Levon 3459fca2b7dSJohn Levon device_add_bootindex_property(obj, &vdev->bootindex, 3469fca2b7dSJohn Levon "bootindex", NULL, 3479fca2b7dSJohn Levon &pci_dev->qdev); 3489fca2b7dSJohn Levon vdev->host.domain = ~0U; 3499fca2b7dSJohn Levon vdev->host.bus = ~0U; 3509fca2b7dSJohn Levon vdev->host.slot = ~0U; 3519fca2b7dSJohn Levon vdev->host.function = ~0U; 3529fca2b7dSJohn Levon 3539fca2b7dSJohn Levon vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops, 3549fca2b7dSJohn Levon DEVICE(vdev), false); 3559fca2b7dSJohn Levon 3569fca2b7dSJohn Levon vdev->nv_gpudirect_clique = 0xFF; 3579fca2b7dSJohn Levon 3589fca2b7dSJohn Levon /* 3599fca2b7dSJohn Levon * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command 3609fca2b7dSJohn Levon * line, therefore, no need to wait to realize like other devices. 3619fca2b7dSJohn Levon */ 3629fca2b7dSJohn Levon pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; 3639fca2b7dSJohn Levon } 3649fca2b7dSJohn Levon 3659fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj) 3669fca2b7dSJohn Levon { 3679fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj); 368438d863fSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 3699fca2b7dSJohn Levon 370777e45c7SJohn Levon if (vdev->msix != NULL) { 371777e45c7SJohn Levon vfio_user_msix_teardown(vdev); 372777e45c7SJohn Levon } 373777e45c7SJohn Levon 3749fca2b7dSJohn Levon vfio_pci_put_device(vdev); 375438d863fSJohn Levon 376438d863fSJohn Levon if (vbasedev->proxy != NULL) { 377438d863fSJohn Levon vfio_user_disconnect(vbasedev->proxy); 378438d863fSJohn Levon } 3799fca2b7dSJohn Levon } 3809fca2b7dSJohn Levon 38101923235SJohn Levon static void vfio_user_pci_reset(DeviceState *dev) 38201923235SJohn Levon { 38301923235SJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(dev); 38401923235SJohn Levon VFIODevice *vbasedev = &vdev->vbasedev; 38501923235SJohn Levon 38601923235SJohn Levon vfio_pci_pre_reset(vdev); 38701923235SJohn Levon 38801923235SJohn Levon if (vbasedev->reset_works) { 38901923235SJohn Levon vfio_user_device_reset(vbasedev->proxy); 39001923235SJohn Levon } 39101923235SJohn Levon 39201923235SJohn Levon vfio_pci_post_reset(vdev); 39301923235SJohn Levon } 39401923235SJohn Levon 3959fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = { 3969fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, 3979fca2b7dSJohn Levon vendor_id, PCI_ANY_ID), 3989fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, 3999fca2b7dSJohn Levon device_id, PCI_ANY_ID), 4009fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice, 4019fca2b7dSJohn Levon sub_vendor_id, PCI_ANY_ID), 4029fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice, 4039fca2b7dSJohn Levon sub_device_id, PCI_ANY_ID), 40436227628SJohn Levon DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false), 405*3358d926SJohn Levon DEFINE_PROP_UINT32("x-msg-timeout", VFIOUserPCIDevice, wait_time, 5000), 4069fca2b7dSJohn Levon }; 4079fca2b7dSJohn Levon 4089fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name, 4099fca2b7dSJohn Levon void *opaque, Error **errp) 4109fca2b7dSJohn Levon { 4119fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj); 4129fca2b7dSJohn Levon bool success; 4139fca2b7dSJohn Levon 414438d863fSJohn Levon if (udev->device.vbasedev.proxy) { 415438d863fSJohn Levon error_setg(errp, "Proxy is connected"); 416438d863fSJohn Levon return; 417438d863fSJohn Levon } 418438d863fSJohn Levon 4199fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 4209fca2b7dSJohn Levon 4219fca2b7dSJohn Levon udev->socket = NULL; 4229fca2b7dSJohn Levon 4239fca2b7dSJohn Levon success = visit_type_SocketAddress(v, name, &udev->socket, errp); 4249fca2b7dSJohn Levon 4259fca2b7dSJohn Levon if (!success) { 4269fca2b7dSJohn Levon return; 4279fca2b7dSJohn Levon } 4289fca2b7dSJohn Levon 4299fca2b7dSJohn Levon if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 4309fca2b7dSJohn Levon error_setg(errp, "Unsupported socket type %s", 4319fca2b7dSJohn Levon SocketAddressType_str(udev->socket->type)); 4329fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket); 4339fca2b7dSJohn Levon udev->socket = NULL; 4349fca2b7dSJohn Levon return; 4359fca2b7dSJohn Levon } 4369fca2b7dSJohn Levon } 4379fca2b7dSJohn Levon 4389fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data) 4399fca2b7dSJohn Levon { 4409fca2b7dSJohn Levon DeviceClass *dc = DEVICE_CLASS(klass); 4419fca2b7dSJohn Levon PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); 4429fca2b7dSJohn Levon 44301923235SJohn Levon device_class_set_legacy_reset(dc, vfio_user_pci_reset); 4449fca2b7dSJohn Levon device_class_set_props(dc, vfio_user_pci_dev_properties); 4459fca2b7dSJohn Levon 4469fca2b7dSJohn Levon object_class_property_add(klass, "socket", "SocketAddress", NULL, 4479fca2b7dSJohn Levon vfio_user_pci_set_socket, NULL, NULL); 4489fca2b7dSJohn Levon object_class_property_set_description(klass, "socket", 4499fca2b7dSJohn Levon "SocketAddress (UNIX sockets only)"); 4509fca2b7dSJohn Levon 4519fca2b7dSJohn Levon dc->desc = "VFIO over socket PCI device assignment"; 4529fca2b7dSJohn Levon pdc->realize = vfio_user_pci_realize; 4539fca2b7dSJohn Levon } 4549fca2b7dSJohn Levon 4559fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = { 4569fca2b7dSJohn Levon .name = TYPE_VFIO_USER_PCI, 4579fca2b7dSJohn Levon .parent = TYPE_VFIO_PCI_BASE, 4589fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserPCIDevice), 4599fca2b7dSJohn Levon .class_init = vfio_user_pci_dev_class_init, 4609fca2b7dSJohn Levon .instance_init = vfio_user_instance_init, 4619fca2b7dSJohn Levon .instance_finalize = vfio_user_instance_finalize, 4629fca2b7dSJohn Levon }; 4639fca2b7dSJohn Levon 4649fca2b7dSJohn Levon static void register_vfio_user_dev_type(void) 4659fca2b7dSJohn Levon { 4669fca2b7dSJohn Levon type_register_static(&vfio_user_pci_dev_info); 4679fca2b7dSJohn Levon } 4689fca2b7dSJohn Levon 4699fca2b7dSJohn Levon type_init(register_vfio_user_dev_type) 470