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