1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
6 #include <linux/device.h>
7 #include <linux/module.h>
8 #include <linux/mutex.h>
10 #include <linux/pm_runtime.h>
11 #include <linux/types.h>
12 #include <linux/uaccess.h>
13 #include <linux/vfio.h>
14 #include <linux/vfio_pci_core.h>
15 #include <linux/virtio_pci.h>
16 #include <linux/virtio_net.h>
17 #include <linux/virtio_pci_admin.h>
21 static int virtiovf_pci_open_device(struct vfio_device
*core_vdev
)
23 struct virtiovf_pci_core_device
*virtvdev
= container_of(core_vdev
,
24 struct virtiovf_pci_core_device
, core_device
.vdev
);
25 struct vfio_pci_core_device
*vdev
= &virtvdev
->core_device
;
28 ret
= vfio_pci_core_enable(vdev
);
32 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
33 ret
= virtiovf_open_legacy_io(virtvdev
);
35 vfio_pci_core_disable(vdev
);
40 virtiovf_open_migration(virtvdev
);
41 vfio_pci_core_finish_enable(vdev
);
45 static void virtiovf_pci_close_device(struct vfio_device
*core_vdev
)
47 struct virtiovf_pci_core_device
*virtvdev
= container_of(core_vdev
,
48 struct virtiovf_pci_core_device
, core_device
.vdev
);
50 virtiovf_close_migration(virtvdev
);
51 vfio_pci_core_close_device(core_vdev
);
54 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
55 static int virtiovf_pci_init_device(struct vfio_device
*core_vdev
)
57 struct virtiovf_pci_core_device
*virtvdev
= container_of(core_vdev
,
58 struct virtiovf_pci_core_device
, core_device
.vdev
);
61 ret
= vfio_pci_core_init_dev(core_vdev
);
66 * The vfio_device_ops.init() callback is set to virtiovf_pci_init_device()
67 * only when legacy I/O is supported. Now, let's initialize it.
69 return virtiovf_init_legacy_io(virtvdev
);
73 static void virtiovf_pci_core_release_dev(struct vfio_device
*core_vdev
)
75 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
76 struct virtiovf_pci_core_device
*virtvdev
= container_of(core_vdev
,
77 struct virtiovf_pci_core_device
, core_device
.vdev
);
79 virtiovf_release_legacy_io(virtvdev
);
81 vfio_pci_core_release_dev(core_vdev
);
84 static const struct vfio_device_ops virtiovf_vfio_pci_lm_ops
= {
85 .name
= "virtio-vfio-pci-lm",
86 .init
= vfio_pci_core_init_dev
,
87 .release
= virtiovf_pci_core_release_dev
,
88 .open_device
= virtiovf_pci_open_device
,
89 .close_device
= virtiovf_pci_close_device
,
90 .ioctl
= vfio_pci_core_ioctl
,
91 .device_feature
= vfio_pci_core_ioctl_feature
,
92 .read
= vfio_pci_core_read
,
93 .write
= vfio_pci_core_write
,
94 .mmap
= vfio_pci_core_mmap
,
95 .request
= vfio_pci_core_request
,
96 .match
= vfio_pci_core_match
,
97 .bind_iommufd
= vfio_iommufd_physical_bind
,
98 .unbind_iommufd
= vfio_iommufd_physical_unbind
,
99 .attach_ioas
= vfio_iommufd_physical_attach_ioas
,
100 .detach_ioas
= vfio_iommufd_physical_detach_ioas
,
103 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
104 static const struct vfio_device_ops virtiovf_vfio_pci_tran_lm_ops
= {
105 .name
= "virtio-vfio-pci-trans-lm",
106 .init
= virtiovf_pci_init_device
,
107 .release
= virtiovf_pci_core_release_dev
,
108 .open_device
= virtiovf_pci_open_device
,
109 .close_device
= virtiovf_pci_close_device
,
110 .ioctl
= virtiovf_vfio_pci_core_ioctl
,
111 .device_feature
= vfio_pci_core_ioctl_feature
,
112 .read
= virtiovf_pci_core_read
,
113 .write
= virtiovf_pci_core_write
,
114 .mmap
= vfio_pci_core_mmap
,
115 .request
= vfio_pci_core_request
,
116 .match
= vfio_pci_core_match
,
117 .bind_iommufd
= vfio_iommufd_physical_bind
,
118 .unbind_iommufd
= vfio_iommufd_physical_unbind
,
119 .attach_ioas
= vfio_iommufd_physical_attach_ioas
,
120 .detach_ioas
= vfio_iommufd_physical_detach_ioas
,
124 static const struct vfio_device_ops virtiovf_vfio_pci_ops
= {
125 .name
= "virtio-vfio-pci",
126 .init
= vfio_pci_core_init_dev
,
127 .release
= vfio_pci_core_release_dev
,
128 .open_device
= virtiovf_pci_open_device
,
129 .close_device
= vfio_pci_core_close_device
,
130 .ioctl
= vfio_pci_core_ioctl
,
131 .device_feature
= vfio_pci_core_ioctl_feature
,
132 .read
= vfio_pci_core_read
,
133 .write
= vfio_pci_core_write
,
134 .mmap
= vfio_pci_core_mmap
,
135 .request
= vfio_pci_core_request
,
136 .match
= vfio_pci_core_match
,
137 .bind_iommufd
= vfio_iommufd_physical_bind
,
138 .unbind_iommufd
= vfio_iommufd_physical_unbind
,
139 .attach_ioas
= vfio_iommufd_physical_attach_ioas
,
140 .detach_ioas
= vfio_iommufd_physical_detach_ioas
,
143 static int virtiovf_pci_probe(struct pci_dev
*pdev
,
144 const struct pci_device_id
*id
)
146 const struct vfio_device_ops
*ops
= &virtiovf_vfio_pci_ops
;
147 struct virtiovf_pci_core_device
*virtvdev
;
148 bool sup_legacy_io
= false;
152 if (pdev
->is_virtfn
) {
153 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
154 sup_legacy_io
= virtiovf_support_legacy_io(pdev
);
156 ops
= &virtiovf_vfio_pci_tran_lm_ops
;
158 sup_lm
= virtio_pci_admin_has_dev_parts(pdev
);
159 if (sup_lm
&& !sup_legacy_io
)
160 ops
= &virtiovf_vfio_pci_lm_ops
;
163 virtvdev
= vfio_alloc_device(virtiovf_pci_core_device
, core_device
.vdev
,
165 if (IS_ERR(virtvdev
))
166 return PTR_ERR(virtvdev
);
169 virtiovf_set_migratable(virtvdev
);
171 dev_set_drvdata(&pdev
->dev
, &virtvdev
->core_device
);
172 ret
= vfio_pci_core_register_device(&virtvdev
->core_device
);
177 vfio_put_device(&virtvdev
->core_device
.vdev
);
181 static void virtiovf_pci_remove(struct pci_dev
*pdev
)
183 struct virtiovf_pci_core_device
*virtvdev
= dev_get_drvdata(&pdev
->dev
);
185 vfio_pci_core_unregister_device(&virtvdev
->core_device
);
186 vfio_put_device(&virtvdev
->core_device
.vdev
);
189 static const struct pci_device_id virtiovf_pci_table
[] = {
190 /* Only virtio-net is supported/tested so far */
191 { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_REDHAT_QUMRANET
, 0x1041) },
195 MODULE_DEVICE_TABLE(pci
, virtiovf_pci_table
);
197 static void virtiovf_pci_aer_reset_done(struct pci_dev
*pdev
)
199 #ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY
200 virtiovf_legacy_io_reset_done(pdev
);
202 virtiovf_migration_reset_done(pdev
);
205 static const struct pci_error_handlers virtiovf_err_handlers
= {
206 .reset_done
= virtiovf_pci_aer_reset_done
,
207 .error_detected
= vfio_pci_core_aer_err_detected
,
210 static struct pci_driver virtiovf_pci_driver
= {
211 .name
= KBUILD_MODNAME
,
212 .id_table
= virtiovf_pci_table
,
213 .probe
= virtiovf_pci_probe
,
214 .remove
= virtiovf_pci_remove
,
215 .err_handler
= &virtiovf_err_handlers
,
216 .driver_managed_dma
= true,
219 module_pci_driver(virtiovf_pci_driver
);
221 MODULE_LICENSE("GPL");
222 MODULE_AUTHOR("Yishai Hadas <yishaih@nvidia.com>");
224 "VIRTIO VFIO PCI - User Level meta-driver for VIRTIO NET devices");