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