Skip to content

Commit ff53edf

Browse files
mgurtovoyAlex Williamson
authored andcommitted
vfio/pci: Split the pci_driver code out of vfio_pci_core.c
Split the vfio_pci driver into two logical parts, the 'struct pci_driver' (vfio_pci.c) which implements "Generic VFIO support for any PCI device" and a library of code (vfio_pci_core.c) that helps implementing a struct vfio_device on top of a PCI device. vfio_pci.ko continues to present the same interface under sysfs and this change should have no functional impact. Following patches will turn vfio_pci and vfio_pci_core into a separate module. This is a preparation for allowing another module to provide the pci_driver and allow that module to customize how VFIO is setup, inject its own operations, and easily extend vendor specific functionality. At this point the vfio_pci_core still contains a lot of vfio_pci functionality mixed into it. Following patches will move more of the large scale items out, but another cleanup series will be needed to get everything. Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Yishai Hadas <yishaih@nvidia.com> Link: https://lore.kernel.org/r/20210826103912.128972-7-yishaih@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent c39f8fa commit ff53edf

4 files changed

Lines changed: 304 additions & 215 deletions

File tree

drivers/vfio/pci/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22

3-
vfio-pci-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
3+
vfio-pci-y := vfio_pci.o vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
44
vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
55
vfio-pci-$(CONFIG_S390) += vfio_pci_zdev.o
66

drivers/vfio/pci/vfio_pci.c

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved
4+
*
5+
* Copyright (C) 2012 Red Hat, Inc. All rights reserved.
6+
* Author: Alex Williamson <alex.williamson@redhat.com>
7+
*
8+
* Derived from original vfio:
9+
* Copyright 2010 Cisco Systems, Inc. All rights reserved.
10+
* Author: Tom Lyon, pugs@cisco.com
11+
*/
12+
13+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14+
15+
#include <linux/device.h>
16+
#include <linux/eventfd.h>
17+
#include <linux/file.h>
18+
#include <linux/interrupt.h>
19+
#include <linux/iommu.h>
20+
#include <linux/module.h>
21+
#include <linux/mutex.h>
22+
#include <linux/notifier.h>
23+
#include <linux/pm_runtime.h>
24+
#include <linux/slab.h>
25+
#include <linux/types.h>
26+
#include <linux/uaccess.h>
27+
28+
#include "vfio_pci_core.h"
29+
30+
#define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
31+
#define DRIVER_DESC "VFIO PCI - User Level meta-driver"
32+
33+
static char ids[1024] __initdata;
34+
module_param_string(ids, ids, sizeof(ids), 0);
35+
MODULE_PARM_DESC(ids, "Initial PCI IDs to add to the vfio driver, format is \"vendor:device[:subvendor[:subdevice[:class[:class_mask]]]]\" and multiple comma separated entries can be specified");
36+
37+
static bool enable_sriov;
38+
#ifdef CONFIG_PCI_IOV
39+
module_param(enable_sriov, bool, 0644);
40+
MODULE_PARM_DESC(enable_sriov, "Enable support for SR-IOV configuration. Enabling SR-IOV on a PF typically requires support of the userspace PF driver, enabling VFs without such support may result in non-functional VFs or PF.");
41+
#endif
42+
43+
static bool disable_denylist;
44+
module_param(disable_denylist, bool, 0444);
45+
MODULE_PARM_DESC(disable_denylist, "Disable use of device denylist. Disabling the denylist allows binding to devices with known errata that may lead to exploitable stability or security issues when accessed by untrusted users.");
46+
47+
static bool vfio_pci_dev_in_denylist(struct pci_dev *pdev)
48+
{
49+
switch (pdev->vendor) {
50+
case PCI_VENDOR_ID_INTEL:
51+
switch (pdev->device) {
52+
case PCI_DEVICE_ID_INTEL_QAT_C3XXX:
53+
case PCI_DEVICE_ID_INTEL_QAT_C3XXX_VF:
54+
case PCI_DEVICE_ID_INTEL_QAT_C62X:
55+
case PCI_DEVICE_ID_INTEL_QAT_C62X_VF:
56+
case PCI_DEVICE_ID_INTEL_QAT_DH895XCC:
57+
case PCI_DEVICE_ID_INTEL_QAT_DH895XCC_VF:
58+
return true;
59+
default:
60+
return false;
61+
}
62+
}
63+
64+
return false;
65+
}
66+
67+
static bool vfio_pci_is_denylisted(struct pci_dev *pdev)
68+
{
69+
if (!vfio_pci_dev_in_denylist(pdev))
70+
return false;
71+
72+
if (disable_denylist) {
73+
pci_warn(pdev,
74+
"device denylist disabled - allowing device %04x:%04x.\n",
75+
pdev->vendor, pdev->device);
76+
return false;
77+
}
78+
79+
pci_warn(pdev, "%04x:%04x exists in vfio-pci device denylist, driver probing disallowed.\n",
80+
pdev->vendor, pdev->device);
81+
82+
return true;
83+
}
84+
85+
static const struct vfio_device_ops vfio_pci_ops = {
86+
.name = "vfio-pci",
87+
.open_device = vfio_pci_core_open_device,
88+
.close_device = vfio_pci_core_close_device,
89+
.ioctl = vfio_pci_core_ioctl,
90+
.read = vfio_pci_core_read,
91+
.write = vfio_pci_core_write,
92+
.mmap = vfio_pci_core_mmap,
93+
.request = vfio_pci_core_request,
94+
.match = vfio_pci_core_match,
95+
};
96+
97+
static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
98+
{
99+
struct vfio_pci_core_device *vdev;
100+
int ret;
101+
102+
if (vfio_pci_is_denylisted(pdev))
103+
return -EINVAL;
104+
105+
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
106+
if (!vdev)
107+
return -ENOMEM;
108+
vfio_pci_core_init_device(vdev, pdev, &vfio_pci_ops);
109+
110+
ret = vfio_pci_core_register_device(vdev);
111+
if (ret)
112+
goto out_free;
113+
return 0;
114+
115+
out_free:
116+
vfio_pci_core_uninit_device(vdev);
117+
kfree(vdev);
118+
return ret;
119+
}
120+
121+
static void vfio_pci_remove(struct pci_dev *pdev)
122+
{
123+
struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev);
124+
125+
vfio_pci_core_unregister_device(vdev);
126+
vfio_pci_core_uninit_device(vdev);
127+
kfree(vdev);
128+
}
129+
130+
static int vfio_pci_sriov_configure(struct pci_dev *pdev, int nr_virtfn)
131+
{
132+
if (!enable_sriov)
133+
return -ENOENT;
134+
135+
return vfio_pci_core_sriov_configure(pdev, nr_virtfn);
136+
}
137+
138+
static struct pci_driver vfio_pci_driver = {
139+
.name = "vfio-pci",
140+
.id_table = NULL, /* only dynamic ids */
141+
.probe = vfio_pci_probe,
142+
.remove = vfio_pci_remove,
143+
.sriov_configure = vfio_pci_sriov_configure,
144+
.err_handler = &vfio_pci_core_err_handlers,
145+
};
146+
147+
static void __init vfio_pci_fill_ids(void)
148+
{
149+
char *p, *id;
150+
int rc;
151+
152+
/* no ids passed actually */
153+
if (ids[0] == '\0')
154+
return;
155+
156+
/* add ids specified in the module parameter */
157+
p = ids;
158+
while ((id = strsep(&p, ","))) {
159+
unsigned int vendor, device, subvendor = PCI_ANY_ID,
160+
subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
161+
int fields;
162+
163+
if (!strlen(id))
164+
continue;
165+
166+
fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
167+
&vendor, &device, &subvendor, &subdevice,
168+
&class, &class_mask);
169+
170+
if (fields < 2) {
171+
pr_warn("invalid id string \"%s\"\n", id);
172+
continue;
173+
}
174+
175+
rc = pci_add_dynid(&vfio_pci_driver, vendor, device,
176+
subvendor, subdevice, class, class_mask, 0);
177+
if (rc)
178+
pr_warn("failed to add dynamic id [%04x:%04x[%04x:%04x]] class %#08x/%08x (%d)\n",
179+
vendor, device, subvendor, subdevice,
180+
class, class_mask, rc);
181+
else
182+
pr_info("add [%04x:%04x[%04x:%04x]] class %#08x/%08x\n",
183+
vendor, device, subvendor, subdevice,
184+
class, class_mask);
185+
}
186+
}
187+
188+
static int __init vfio_pci_init(void)
189+
{
190+
int ret;
191+
192+
ret = vfio_pci_core_init();
193+
if (ret)
194+
return ret;
195+
196+
/* Register and scan for devices */
197+
ret = pci_register_driver(&vfio_pci_driver);
198+
if (ret)
199+
goto out;
200+
201+
vfio_pci_fill_ids();
202+
203+
if (disable_denylist)
204+
pr_warn("device denylist disabled.\n");
205+
206+
return 0;
207+
208+
out:
209+
vfio_pci_core_cleanup();
210+
return ret;
211+
}
212+
module_init(vfio_pci_init);
213+
214+
static void __exit vfio_pci_cleanup(void)
215+
{
216+
pci_unregister_driver(&vfio_pci_driver);
217+
vfio_pci_core_cleanup();
218+
}
219+
module_exit(vfio_pci_cleanup);
220+
221+
MODULE_LICENSE("GPL v2");
222+
MODULE_AUTHOR(DRIVER_AUTHOR);
223+
MODULE_DESCRIPTION(DRIVER_DESC);

0 commit comments

Comments
 (0)