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 */
263358d926SJohn Levon uint32_t wait_time; /* timeout for message replies */
27*98a906d9SJohn Levon bool no_post; /* all region writes are sync */
289fca2b7dSJohn Levon };
299fca2b7dSJohn Levon
309fca2b7dSJohn Levon /*
31777e45c7SJohn Levon * The server maintains the device's pending interrupts,
32777e45c7SJohn Levon * via its MSIX table and PBA, so we treat these accesses
33777e45c7SJohn Levon * like PCI config space and forward them.
34777e45c7SJohn Levon */
vfio_user_pba_read(void * opaque,hwaddr addr,unsigned size)35777e45c7SJohn Levon static uint64_t vfio_user_pba_read(void *opaque, hwaddr addr,
36777e45c7SJohn Levon unsigned size)
37777e45c7SJohn Levon {
38777e45c7SJohn Levon VFIOPCIDevice *vdev = opaque;
39777e45c7SJohn Levon VFIORegion *region = &vdev->bars[vdev->msix->pba_bar].region;
40777e45c7SJohn Levon uint64_t data;
41777e45c7SJohn Levon
42777e45c7SJohn Levon /* server copy is what matters */
43777e45c7SJohn Levon data = vfio_region_read(region, addr + vdev->msix->pba_offset, size);
44777e45c7SJohn Levon return data;
45777e45c7SJohn Levon }
46777e45c7SJohn Levon
vfio_user_pba_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)47777e45c7SJohn Levon static void vfio_user_pba_write(void *opaque, hwaddr addr,
48777e45c7SJohn Levon uint64_t data, unsigned size)
49777e45c7SJohn Levon {
50777e45c7SJohn Levon /* dropped */
51777e45c7SJohn Levon }
52777e45c7SJohn Levon
53777e45c7SJohn Levon static const MemoryRegionOps vfio_user_pba_ops = {
54777e45c7SJohn Levon .read = vfio_user_pba_read,
55777e45c7SJohn Levon .write = vfio_user_pba_write,
56777e45c7SJohn Levon .endianness = DEVICE_LITTLE_ENDIAN,
57777e45c7SJohn Levon };
58777e45c7SJohn Levon
vfio_user_msix_setup(VFIOPCIDevice * vdev)59777e45c7SJohn Levon static void vfio_user_msix_setup(VFIOPCIDevice *vdev)
60777e45c7SJohn Levon {
61777e45c7SJohn Levon MemoryRegion *vfio_reg, *msix_reg, *pba_reg;
62777e45c7SJohn Levon
63777e45c7SJohn Levon pba_reg = g_new0(MemoryRegion, 1);
64777e45c7SJohn Levon vdev->msix->pba_region = pba_reg;
65777e45c7SJohn Levon
66777e45c7SJohn Levon vfio_reg = vdev->bars[vdev->msix->pba_bar].mr;
67777e45c7SJohn Levon msix_reg = &vdev->pdev.msix_pba_mmio;
68777e45c7SJohn Levon memory_region_init_io(pba_reg, OBJECT(vdev), &vfio_user_pba_ops, vdev,
69777e45c7SJohn Levon "VFIO MSIX PBA", int128_get64(msix_reg->size));
70777e45c7SJohn Levon memory_region_add_subregion_overlap(vfio_reg, vdev->msix->pba_offset,
71777e45c7SJohn Levon pba_reg, 1);
72777e45c7SJohn Levon }
73777e45c7SJohn Levon
vfio_user_msix_teardown(VFIOPCIDevice * vdev)74777e45c7SJohn Levon static void vfio_user_msix_teardown(VFIOPCIDevice *vdev)
75777e45c7SJohn Levon {
76777e45c7SJohn Levon MemoryRegion *mr, *sub;
77777e45c7SJohn Levon
78777e45c7SJohn Levon mr = vdev->bars[vdev->msix->pba_bar].mr;
79777e45c7SJohn Levon sub = vdev->msix->pba_region;
80777e45c7SJohn Levon memory_region_del_subregion(mr, sub);
81777e45c7SJohn Levon
82777e45c7SJohn Levon g_free(vdev->msix->pba_region);
83777e45c7SJohn Levon vdev->msix->pba_region = NULL;
84777e45c7SJohn Levon }
85777e45c7SJohn Levon
vfio_user_dma_read(VFIOPCIDevice * vdev,VFIOUserDMARW * msg)86c6ac52a4SJohn Levon static void vfio_user_dma_read(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
87c6ac52a4SJohn Levon {
88c6ac52a4SJohn Levon PCIDevice *pdev = &vdev->pdev;
89c6ac52a4SJohn Levon VFIOUserProxy *proxy = vdev->vbasedev.proxy;
90c6ac52a4SJohn Levon VFIOUserDMARW *res;
91c6ac52a4SJohn Levon MemTxResult r;
92c6ac52a4SJohn Levon size_t size;
93c6ac52a4SJohn Levon
94c6ac52a4SJohn Levon if (msg->hdr.size < sizeof(*msg)) {
95c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EINVAL);
96c6ac52a4SJohn Levon return;
97c6ac52a4SJohn Levon }
98c6ac52a4SJohn Levon if (msg->count > proxy->max_xfer_size) {
99c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, E2BIG);
100c6ac52a4SJohn Levon return;
101c6ac52a4SJohn Levon }
102c6ac52a4SJohn Levon
103c6ac52a4SJohn Levon /* switch to our own message buffer */
104c6ac52a4SJohn Levon size = msg->count + sizeof(VFIOUserDMARW);
105c6ac52a4SJohn Levon res = g_malloc0(size);
106c6ac52a4SJohn Levon memcpy(res, msg, sizeof(*res));
107c6ac52a4SJohn Levon g_free(msg);
108c6ac52a4SJohn Levon
109c6ac52a4SJohn Levon r = pci_dma_read(pdev, res->offset, &res->data, res->count);
110c6ac52a4SJohn Levon
111c6ac52a4SJohn Levon switch (r) {
112c6ac52a4SJohn Levon case MEMTX_OK:
113c6ac52a4SJohn Levon if (res->hdr.flags & VFIO_USER_NO_REPLY) {
114c6ac52a4SJohn Levon g_free(res);
115c6ac52a4SJohn Levon return;
116c6ac52a4SJohn Levon }
117c6ac52a4SJohn Levon vfio_user_send_reply(proxy, &res->hdr, size);
118c6ac52a4SJohn Levon break;
119c6ac52a4SJohn Levon case MEMTX_ERROR:
120c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, EFAULT);
121c6ac52a4SJohn Levon break;
122c6ac52a4SJohn Levon case MEMTX_DECODE_ERROR:
123c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, ENODEV);
124c6ac52a4SJohn Levon break;
125c6ac52a4SJohn Levon case MEMTX_ACCESS_ERROR:
126c6ac52a4SJohn Levon vfio_user_send_error(proxy, &res->hdr, EPERM);
127c6ac52a4SJohn Levon break;
128c6ac52a4SJohn Levon default:
129c6ac52a4SJohn Levon error_printf("vfio_user_dma_read unknown error %d\n", r);
130c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, &res->hdr, EINVAL);
131c6ac52a4SJohn Levon }
132c6ac52a4SJohn Levon }
133c6ac52a4SJohn Levon
vfio_user_dma_write(VFIOPCIDevice * vdev,VFIOUserDMARW * msg)134c6ac52a4SJohn Levon static void vfio_user_dma_write(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
135c6ac52a4SJohn Levon {
136c6ac52a4SJohn Levon PCIDevice *pdev = &vdev->pdev;
137c6ac52a4SJohn Levon VFIOUserProxy *proxy = vdev->vbasedev.proxy;
138c6ac52a4SJohn Levon MemTxResult r;
139c6ac52a4SJohn Levon
140c6ac52a4SJohn Levon if (msg->hdr.size < sizeof(*msg)) {
141c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EINVAL);
142c6ac52a4SJohn Levon return;
143c6ac52a4SJohn Levon }
144c6ac52a4SJohn Levon /* make sure transfer count isn't larger than the message data */
145c6ac52a4SJohn Levon if (msg->count > msg->hdr.size - sizeof(*msg)) {
146c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, E2BIG);
147c6ac52a4SJohn Levon return;
148c6ac52a4SJohn Levon }
149c6ac52a4SJohn Levon
150c6ac52a4SJohn Levon r = pci_dma_write(pdev, msg->offset, &msg->data, msg->count);
151c6ac52a4SJohn Levon
152c6ac52a4SJohn Levon switch (r) {
153c6ac52a4SJohn Levon case MEMTX_OK:
154c6ac52a4SJohn Levon if ((msg->hdr.flags & VFIO_USER_NO_REPLY) == 0) {
155c6ac52a4SJohn Levon vfio_user_send_reply(proxy, &msg->hdr, sizeof(msg->hdr));
156c6ac52a4SJohn Levon } else {
157c6ac52a4SJohn Levon g_free(msg);
158c6ac52a4SJohn Levon }
159c6ac52a4SJohn Levon break;
160c6ac52a4SJohn Levon case MEMTX_ERROR:
161c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EFAULT);
162c6ac52a4SJohn Levon break;
163c6ac52a4SJohn Levon case MEMTX_DECODE_ERROR:
164c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, ENODEV);
165c6ac52a4SJohn Levon break;
166c6ac52a4SJohn Levon case MEMTX_ACCESS_ERROR:
167c6ac52a4SJohn Levon vfio_user_send_error(proxy, &msg->hdr, EPERM);
168c6ac52a4SJohn Levon break;
169c6ac52a4SJohn Levon default:
170c6ac52a4SJohn Levon error_printf("vfio_user_dma_write unknown error %d\n", r);
171c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, &msg->hdr, EINVAL);
172c6ac52a4SJohn Levon }
173c6ac52a4SJohn Levon }
174c6ac52a4SJohn Levon
175777e45c7SJohn Levon /*
1760b3d881aSJohn Levon * Incoming request message callback.
1770b3d881aSJohn Levon *
1780b3d881aSJohn Levon * Runs off main loop, so BQL held.
1790b3d881aSJohn Levon */
vfio_user_pci_process_req(void * opaque,VFIOUserMsg * msg)1800b3d881aSJohn Levon static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg)
1810b3d881aSJohn Levon {
182c6ac52a4SJohn Levon VFIOPCIDevice *vdev = opaque;
183c6ac52a4SJohn Levon VFIOUserHdr *hdr = msg->hdr;
1840b3d881aSJohn Levon
185c6ac52a4SJohn Levon /* no incoming PCI requests pass FDs */
186c6ac52a4SJohn Levon if (msg->fds != NULL) {
187c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, hdr, EINVAL);
188c6ac52a4SJohn Levon vfio_user_putfds(msg);
189c6ac52a4SJohn Levon return;
190c6ac52a4SJohn Levon }
191c6ac52a4SJohn Levon
192c6ac52a4SJohn Levon switch (hdr->command) {
193c6ac52a4SJohn Levon case VFIO_USER_DMA_READ:
194c6ac52a4SJohn Levon vfio_user_dma_read(vdev, (VFIOUserDMARW *)hdr);
195c6ac52a4SJohn Levon break;
196c6ac52a4SJohn Levon case VFIO_USER_DMA_WRITE:
197c6ac52a4SJohn Levon vfio_user_dma_write(vdev, (VFIOUserDMARW *)hdr);
198c6ac52a4SJohn Levon break;
199c6ac52a4SJohn Levon default:
200c6ac52a4SJohn Levon error_printf("vfio_user_pci_process_req unknown cmd %d\n",
201c6ac52a4SJohn Levon hdr->command);
202c6ac52a4SJohn Levon vfio_user_send_error(vdev->vbasedev.proxy, hdr, ENOSYS);
203c6ac52a4SJohn Levon }
2040b3d881aSJohn Levon }
2050b3d881aSJohn Levon
2060b3d881aSJohn Levon /*
2079fca2b7dSJohn Levon * Emulated devices don't use host hot reset
2089fca2b7dSJohn Levon */
vfio_user_compute_needs_reset(VFIODevice * vbasedev)2099fca2b7dSJohn Levon static void vfio_user_compute_needs_reset(VFIODevice *vbasedev)
2109fca2b7dSJohn Levon {
2119fca2b7dSJohn Levon vbasedev->needs_reset = false;
2129fca2b7dSJohn Levon }
2139fca2b7dSJohn Levon
vfio_user_pci_get_object(VFIODevice * vbasedev)2149fca2b7dSJohn Levon static Object *vfio_user_pci_get_object(VFIODevice *vbasedev)
2159fca2b7dSJohn Levon {
2169fca2b7dSJohn Levon VFIOUserPCIDevice *vdev = container_of(vbasedev, VFIOUserPCIDevice,
2179fca2b7dSJohn Levon device.vbasedev);
2189fca2b7dSJohn Levon
2199fca2b7dSJohn Levon return OBJECT(vdev);
2209fca2b7dSJohn Levon }
2219fca2b7dSJohn Levon
2229fca2b7dSJohn Levon static VFIODeviceOps vfio_user_pci_ops = {
2239fca2b7dSJohn Levon .vfio_compute_needs_reset = vfio_user_compute_needs_reset,
2249fca2b7dSJohn Levon .vfio_eoi = vfio_pci_intx_eoi,
2259fca2b7dSJohn Levon .vfio_get_object = vfio_user_pci_get_object,
2269fca2b7dSJohn Levon /* No live migration support yet. */
2279fca2b7dSJohn Levon .vfio_save_config = NULL,
2289fca2b7dSJohn Levon .vfio_load_config = NULL,
2299fca2b7dSJohn Levon };
2309fca2b7dSJohn Levon
vfio_user_pci_realize(PCIDevice * pdev,Error ** errp)2319fca2b7dSJohn Levon static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
2329fca2b7dSJohn Levon {
2339fca2b7dSJohn Levon ERRP_GUARD();
2349fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(pdev);
2359fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(pdev);
2369fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev;
2379fca2b7dSJohn Levon const char *sock_name;
2389fca2b7dSJohn Levon AddressSpace *as;
239438d863fSJohn Levon SocketAddress addr;
240438d863fSJohn Levon VFIOUserProxy *proxy;
2419fca2b7dSJohn Levon
2429fca2b7dSJohn Levon if (!udev->socket) {
2439fca2b7dSJohn Levon error_setg(errp, "No socket specified");
2449fca2b7dSJohn Levon error_append_hint(errp, "e.g. -device '{"
2459fca2b7dSJohn Levon "\"driver\":\"vfio-user-pci\", "
2469fca2b7dSJohn Levon "\"socket\": {\"path\": \"/tmp/vfio-user.sock\", "
2479fca2b7dSJohn Levon "\"type\": \"unix\"}'"
2489fca2b7dSJohn Levon "}'\n");
2499fca2b7dSJohn Levon return;
2509fca2b7dSJohn Levon }
2519fca2b7dSJohn Levon
2529fca2b7dSJohn Levon sock_name = udev->socket->u.q_unix.path;
2539fca2b7dSJohn Levon
2549fca2b7dSJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
2559fca2b7dSJohn Levon
256438d863fSJohn Levon memset(&addr, 0, sizeof(addr));
257438d863fSJohn Levon addr.type = SOCKET_ADDRESS_TYPE_UNIX;
258438d863fSJohn Levon addr.u.q_unix.path = (char *)sock_name;
259438d863fSJohn Levon proxy = vfio_user_connect_dev(&addr, errp);
260438d863fSJohn Levon if (!proxy) {
261438d863fSJohn Levon return;
262438d863fSJohn Levon }
263438d863fSJohn Levon vbasedev->proxy = proxy;
2640b3d881aSJohn Levon vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
265438d863fSJohn Levon
26636227628SJohn Levon vbasedev->name = g_strdup_printf("vfio-user:%s", sock_name);
26736227628SJohn Levon
26836227628SJohn Levon if (udev->send_queued) {
26936227628SJohn Levon proxy->flags |= VFIO_PROXY_FORCE_QUEUED;
27036227628SJohn Levon }
27136227628SJohn Levon
272*98a906d9SJohn Levon if (udev->no_post) {
273*98a906d9SJohn Levon proxy->flags |= VFIO_PROXY_NO_POST;
274*98a906d9SJohn Levon }
275*98a906d9SJohn Levon
2763358d926SJohn Levon /* user specified or 5 sec default */
2773358d926SJohn Levon proxy->wait_time = udev->wait_time;
2783358d926SJohn Levon
27936227628SJohn Levon if (!vfio_user_validate_version(proxy, errp)) {
28036227628SJohn Levon goto error;
28136227628SJohn Levon }
28236227628SJohn Levon
2839fca2b7dSJohn Levon /*
284667866d6SJohn Levon * Use socket-based device I/O instead of vfio kernel driver.
285667866d6SJohn Levon */
286667866d6SJohn Levon vbasedev->io_ops = &vfio_user_device_io_ops_sock;
287667866d6SJohn Levon
288667866d6SJohn Levon /*
2899fca2b7dSJohn Levon * vfio-user devices are effectively mdevs (don't use a host iommu).
2909fca2b7dSJohn Levon */
2919fca2b7dSJohn Levon vbasedev->mdev = true;
2929fca2b7dSJohn Levon
293667866d6SJohn Levon /*
294667866d6SJohn Levon * Enable per-region fds.
295667866d6SJohn Levon */
296667866d6SJohn Levon vbasedev->use_region_fds = true;
297667866d6SJohn Levon
2989fca2b7dSJohn Levon as = pci_device_iommu_address_space(pdev);
2999fca2b7dSJohn Levon if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER,
3009fca2b7dSJohn Levon vbasedev->name, vbasedev,
3019fca2b7dSJohn Levon as, errp)) {
30236227628SJohn Levon goto error;
3039fca2b7dSJohn Levon }
30436227628SJohn Levon
305692e0ec5SJohn Levon if (!vfio_pci_populate_device(vdev, errp)) {
306692e0ec5SJohn Levon goto error;
307692e0ec5SJohn Levon }
308692e0ec5SJohn Levon
309692e0ec5SJohn Levon if (!vfio_pci_config_setup(vdev, errp)) {
310692e0ec5SJohn Levon goto error;
311692e0ec5SJohn Levon }
312692e0ec5SJohn Levon
313692e0ec5SJohn Levon /*
314692e0ec5SJohn Levon * vfio_pci_config_setup will have registered the device's BARs
315692e0ec5SJohn Levon * and setup any MSIX BARs, so errors after it succeeds must
316692e0ec5SJohn Levon * use out_teardown
317692e0ec5SJohn Levon */
318692e0ec5SJohn Levon
319692e0ec5SJohn Levon if (!vfio_pci_add_capabilities(vdev, errp)) {
320692e0ec5SJohn Levon goto out_teardown;
321692e0ec5SJohn Levon }
322692e0ec5SJohn Levon
323777e45c7SJohn Levon if (vdev->msix != NULL) {
324777e45c7SJohn Levon vfio_user_msix_setup(vdev);
325777e45c7SJohn Levon }
326777e45c7SJohn Levon
327692e0ec5SJohn Levon if (!vfio_pci_interrupt_setup(vdev, errp)) {
328692e0ec5SJohn Levon goto out_teardown;
329692e0ec5SJohn Levon }
330692e0ec5SJohn Levon
331692e0ec5SJohn Levon vfio_pci_register_err_notifier(vdev);
332692e0ec5SJohn Levon vfio_pci_register_req_notifier(vdev);
333692e0ec5SJohn Levon
33436227628SJohn Levon return;
33536227628SJohn Levon
336692e0ec5SJohn Levon out_teardown:
337692e0ec5SJohn Levon vfio_pci_teardown_msi(vdev);
338692e0ec5SJohn Levon vfio_pci_bars_exit(vdev);
33936227628SJohn Levon error:
34036227628SJohn Levon error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
341692e0ec5SJohn Levon vfio_pci_put_device(vdev);
3429fca2b7dSJohn Levon }
3439fca2b7dSJohn Levon
vfio_user_instance_init(Object * obj)3449fca2b7dSJohn Levon static void vfio_user_instance_init(Object *obj)
3459fca2b7dSJohn Levon {
3469fca2b7dSJohn Levon PCIDevice *pci_dev = PCI_DEVICE(obj);
3479fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
3489fca2b7dSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev;
3499fca2b7dSJohn Levon
3509fca2b7dSJohn Levon device_add_bootindex_property(obj, &vdev->bootindex,
3519fca2b7dSJohn Levon "bootindex", NULL,
3529fca2b7dSJohn Levon &pci_dev->qdev);
3539fca2b7dSJohn Levon vdev->host.domain = ~0U;
3549fca2b7dSJohn Levon vdev->host.bus = ~0U;
3559fca2b7dSJohn Levon vdev->host.slot = ~0U;
3569fca2b7dSJohn Levon vdev->host.function = ~0U;
3579fca2b7dSJohn Levon
3589fca2b7dSJohn Levon vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_PCI, &vfio_user_pci_ops,
3599fca2b7dSJohn Levon DEVICE(vdev), false);
3609fca2b7dSJohn Levon
3619fca2b7dSJohn Levon vdev->nv_gpudirect_clique = 0xFF;
3629fca2b7dSJohn Levon
3639fca2b7dSJohn Levon /*
3649fca2b7dSJohn Levon * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
3659fca2b7dSJohn Levon * line, therefore, no need to wait to realize like other devices.
3669fca2b7dSJohn Levon */
3679fca2b7dSJohn Levon pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
3689fca2b7dSJohn Levon }
3699fca2b7dSJohn Levon
vfio_user_instance_finalize(Object * obj)3709fca2b7dSJohn Levon static void vfio_user_instance_finalize(Object *obj)
3719fca2b7dSJohn Levon {
3729fca2b7dSJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(obj);
373438d863fSJohn Levon VFIODevice *vbasedev = &vdev->vbasedev;
3749fca2b7dSJohn Levon
375777e45c7SJohn Levon if (vdev->msix != NULL) {
376777e45c7SJohn Levon vfio_user_msix_teardown(vdev);
377777e45c7SJohn Levon }
378777e45c7SJohn Levon
3799fca2b7dSJohn Levon vfio_pci_put_device(vdev);
380438d863fSJohn Levon
381438d863fSJohn Levon if (vbasedev->proxy != NULL) {
382438d863fSJohn Levon vfio_user_disconnect(vbasedev->proxy);
383438d863fSJohn Levon }
3849fca2b7dSJohn Levon }
3859fca2b7dSJohn Levon
vfio_user_pci_reset(DeviceState * dev)38601923235SJohn Levon static void vfio_user_pci_reset(DeviceState *dev)
38701923235SJohn Levon {
38801923235SJohn Levon VFIOPCIDevice *vdev = VFIO_PCI_BASE(dev);
38901923235SJohn Levon VFIODevice *vbasedev = &vdev->vbasedev;
39001923235SJohn Levon
39101923235SJohn Levon vfio_pci_pre_reset(vdev);
39201923235SJohn Levon
39301923235SJohn Levon if (vbasedev->reset_works) {
39401923235SJohn Levon vfio_user_device_reset(vbasedev->proxy);
39501923235SJohn Levon }
39601923235SJohn Levon
39701923235SJohn Levon vfio_pci_post_reset(vdev);
39801923235SJohn Levon }
39901923235SJohn Levon
4009fca2b7dSJohn Levon static const Property vfio_user_pci_dev_properties[] = {
4019fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice,
4029fca2b7dSJohn Levon vendor_id, PCI_ANY_ID),
4039fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice,
4049fca2b7dSJohn Levon device_id, PCI_ANY_ID),
4059fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
4069fca2b7dSJohn Levon sub_vendor_id, PCI_ANY_ID),
4079fca2b7dSJohn Levon DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
4089fca2b7dSJohn Levon sub_device_id, PCI_ANY_ID),
40936227628SJohn Levon DEFINE_PROP_BOOL("x-send-queued", VFIOUserPCIDevice, send_queued, false),
4103358d926SJohn Levon DEFINE_PROP_UINT32("x-msg-timeout", VFIOUserPCIDevice, wait_time, 5000),
411*98a906d9SJohn Levon DEFINE_PROP_BOOL("x-no-posted-writes", VFIOUserPCIDevice, no_post, false),
4129fca2b7dSJohn Levon };
4139fca2b7dSJohn Levon
vfio_user_pci_set_socket(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)4149fca2b7dSJohn Levon static void vfio_user_pci_set_socket(Object *obj, Visitor *v, const char *name,
4159fca2b7dSJohn Levon void *opaque, Error **errp)
4169fca2b7dSJohn Levon {
4179fca2b7dSJohn Levon VFIOUserPCIDevice *udev = VFIO_USER_PCI(obj);
4189fca2b7dSJohn Levon bool success;
4199fca2b7dSJohn Levon
420438d863fSJohn Levon if (udev->device.vbasedev.proxy) {
421438d863fSJohn Levon error_setg(errp, "Proxy is connected");
422438d863fSJohn Levon return;
423438d863fSJohn Levon }
424438d863fSJohn Levon
4259fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket);
4269fca2b7dSJohn Levon
4279fca2b7dSJohn Levon udev->socket = NULL;
4289fca2b7dSJohn Levon
4299fca2b7dSJohn Levon success = visit_type_SocketAddress(v, name, &udev->socket, errp);
4309fca2b7dSJohn Levon
4319fca2b7dSJohn Levon if (!success) {
4329fca2b7dSJohn Levon return;
4339fca2b7dSJohn Levon }
4349fca2b7dSJohn Levon
4359fca2b7dSJohn Levon if (udev->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
4369fca2b7dSJohn Levon error_setg(errp, "Unsupported socket type %s",
4379fca2b7dSJohn Levon SocketAddressType_str(udev->socket->type));
4389fca2b7dSJohn Levon qapi_free_SocketAddress(udev->socket);
4399fca2b7dSJohn Levon udev->socket = NULL;
4409fca2b7dSJohn Levon return;
4419fca2b7dSJohn Levon }
4429fca2b7dSJohn Levon }
4439fca2b7dSJohn Levon
vfio_user_pci_dev_class_init(ObjectClass * klass,const void * data)4449fca2b7dSJohn Levon static void vfio_user_pci_dev_class_init(ObjectClass *klass, const void *data)
4459fca2b7dSJohn Levon {
4469fca2b7dSJohn Levon DeviceClass *dc = DEVICE_CLASS(klass);
4479fca2b7dSJohn Levon PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
4489fca2b7dSJohn Levon
44901923235SJohn Levon device_class_set_legacy_reset(dc, vfio_user_pci_reset);
4509fca2b7dSJohn Levon device_class_set_props(dc, vfio_user_pci_dev_properties);
4519fca2b7dSJohn Levon
4529fca2b7dSJohn Levon object_class_property_add(klass, "socket", "SocketAddress", NULL,
4539fca2b7dSJohn Levon vfio_user_pci_set_socket, NULL, NULL);
4549fca2b7dSJohn Levon object_class_property_set_description(klass, "socket",
4559fca2b7dSJohn Levon "SocketAddress (UNIX sockets only)");
4569fca2b7dSJohn Levon
4579fca2b7dSJohn Levon dc->desc = "VFIO over socket PCI device assignment";
4589fca2b7dSJohn Levon pdc->realize = vfio_user_pci_realize;
4599fca2b7dSJohn Levon }
4609fca2b7dSJohn Levon
4619fca2b7dSJohn Levon static const TypeInfo vfio_user_pci_dev_info = {
4629fca2b7dSJohn Levon .name = TYPE_VFIO_USER_PCI,
4639fca2b7dSJohn Levon .parent = TYPE_VFIO_PCI_BASE,
4649fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserPCIDevice),
4659fca2b7dSJohn Levon .class_init = vfio_user_pci_dev_class_init,
4669fca2b7dSJohn Levon .instance_init = vfio_user_instance_init,
4679fca2b7dSJohn Levon .instance_finalize = vfio_user_instance_finalize,
4689fca2b7dSJohn Levon };
4699fca2b7dSJohn Levon
register_vfio_user_dev_type(void)4709fca2b7dSJohn Levon static void register_vfio_user_dev_type(void)
4719fca2b7dSJohn Levon {
4729fca2b7dSJohn Levon type_register_static(&vfio_user_pci_dev_info);
4739fca2b7dSJohn Levon }
4749fca2b7dSJohn Levon
4759fca2b7dSJohn Levon type_init(register_vfio_user_dev_type)
476