Skip to content

Commit 234489a

Browse files
nipung87awilliam
authored andcommitted
vfio/cdx: add support for CDX bus
vfio-cdx driver enables IOCTLs for user space to query MMIO regions for CDX devices and mmap them. This change also adds support for reset of CDX devices. With VFIO enabled on CDX devices, user-space applications can also exercise DMA securely via IOMMU on these devices. This change adds the VFIO CDX driver and enables the following ioctls for CDX devices: - VFIO_DEVICE_GET_INFO: - VFIO_DEVICE_GET_REGION_INFO - VFIO_DEVICE_RESET Signed-off-by: Nipun Gupta <[email protected]> Reviewed-by: Pieter Jansen van Vuuren <[email protected]> Tested-by: Nikhil Agarwal <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 1e44c58 commit 234489a

File tree

12 files changed

+320
-2
lines changed

12 files changed

+320
-2
lines changed

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22085,6 +22085,13 @@ F: Documentation/filesystems/vfat.rst
2208522085
F: fs/fat/
2208622086
F: tools/testing/selftests/filesystems/fat/
2208722087

22088+
VFIO CDX DRIVER
22089+
M: Nipun Gupta <[email protected]>
22090+
M: Nikhil Agarwal <[email protected]>
22091+
22092+
S: Maintained
22093+
F: drivers/vfio/cdx/*
22094+
2208822095
VFIO DRIVER
2208922096
M: Alex Williamson <[email protected]>
2209022097

drivers/vfio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ source "drivers/vfio/pci/Kconfig"
5757
source "drivers/vfio/platform/Kconfig"
5858
source "drivers/vfio/mdev/Kconfig"
5959
source "drivers/vfio/fsl-mc/Kconfig"
60+
source "drivers/vfio/cdx/Kconfig"
6061
endif
6162

6263
source "virt/lib/Kconfig"

drivers/vfio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ obj-$(CONFIG_VFIO_PCI_CORE) += pci/
1414
obj-$(CONFIG_VFIO_PLATFORM_BASE) += platform/
1515
obj-$(CONFIG_VFIO_MDEV) += mdev/
1616
obj-$(CONFIG_VFIO_FSL_MC) += fsl-mc/
17+
obj-$(CONFIG_VFIO_CDX) += cdx/

drivers/vfio/cdx/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# VFIO CDX configuration
4+
#
5+
# Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
6+
#
7+
8+
config VFIO_CDX
9+
tristate "VFIO support for CDX bus devices"
10+
depends on CDX_BUS
11+
select EVENTFD
12+
help
13+
Driver to enable VFIO support for the devices on CDX bus.
14+
This is required to make use of CDX devices present in
15+
the system using the VFIO framework.
16+
17+
If you don't know what to do here, say N.

drivers/vfio/cdx/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
4+
#
5+
6+
obj-$(CONFIG_VFIO_CDX) += vfio-cdx.o
7+
8+
vfio-cdx-objs := main.o

drivers/vfio/cdx/main.c

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
4+
*/
5+
6+
#include <linux/vfio.h>
7+
#include <linux/cdx/cdx_bus.h>
8+
9+
#include "private.h"
10+
11+
static int vfio_cdx_open_device(struct vfio_device *core_vdev)
12+
{
13+
struct vfio_cdx_device *vdev =
14+
container_of(core_vdev, struct vfio_cdx_device, vdev);
15+
struct cdx_device *cdx_dev = to_cdx_device(core_vdev->dev);
16+
int count = cdx_dev->res_count;
17+
int i;
18+
19+
vdev->regions = kcalloc(count, sizeof(struct vfio_cdx_region),
20+
GFP_KERNEL_ACCOUNT);
21+
if (!vdev->regions)
22+
return -ENOMEM;
23+
24+
for (i = 0; i < count; i++) {
25+
struct resource *res = &cdx_dev->res[i];
26+
27+
vdev->regions[i].addr = res->start;
28+
vdev->regions[i].size = resource_size(res);
29+
vdev->regions[i].type = res->flags;
30+
/*
31+
* Only regions addressed with PAGE granularity may be
32+
* MMAP'ed securely.
33+
*/
34+
if (!(vdev->regions[i].addr & ~PAGE_MASK) &&
35+
!(vdev->regions[i].size & ~PAGE_MASK))
36+
vdev->regions[i].flags |=
37+
VFIO_REGION_INFO_FLAG_MMAP;
38+
vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
39+
if (!(cdx_dev->res[i].flags & IORESOURCE_READONLY))
40+
vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE;
41+
}
42+
43+
return 0;
44+
}
45+
46+
static void vfio_cdx_close_device(struct vfio_device *core_vdev)
47+
{
48+
struct vfio_cdx_device *vdev =
49+
container_of(core_vdev, struct vfio_cdx_device, vdev);
50+
51+
kfree(vdev->regions);
52+
cdx_dev_reset(core_vdev->dev);
53+
}
54+
55+
static int vfio_cdx_ioctl_get_info(struct vfio_cdx_device *vdev,
56+
struct vfio_device_info __user *arg)
57+
{
58+
unsigned long minsz = offsetofend(struct vfio_device_info, num_irqs);
59+
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
60+
struct vfio_device_info info;
61+
62+
if (copy_from_user(&info, arg, minsz))
63+
return -EFAULT;
64+
65+
if (info.argsz < minsz)
66+
return -EINVAL;
67+
68+
info.flags = VFIO_DEVICE_FLAGS_CDX;
69+
info.flags |= VFIO_DEVICE_FLAGS_RESET;
70+
71+
info.num_regions = cdx_dev->res_count;
72+
info.num_irqs = 0;
73+
74+
return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
75+
}
76+
77+
static int vfio_cdx_ioctl_get_region_info(struct vfio_cdx_device *vdev,
78+
struct vfio_region_info __user *arg)
79+
{
80+
unsigned long minsz = offsetofend(struct vfio_region_info, offset);
81+
struct cdx_device *cdx_dev = to_cdx_device(vdev->vdev.dev);
82+
struct vfio_region_info info;
83+
84+
if (copy_from_user(&info, arg, minsz))
85+
return -EFAULT;
86+
87+
if (info.argsz < minsz)
88+
return -EINVAL;
89+
90+
if (info.index >= cdx_dev->res_count)
91+
return -EINVAL;
92+
93+
/* map offset to the physical address */
94+
info.offset = vfio_cdx_index_to_offset(info.index);
95+
info.size = vdev->regions[info.index].size;
96+
info.flags = vdev->regions[info.index].flags;
97+
98+
return copy_to_user(arg, &info, minsz) ? -EFAULT : 0;
99+
}
100+
101+
static long vfio_cdx_ioctl(struct vfio_device *core_vdev,
102+
unsigned int cmd, unsigned long arg)
103+
{
104+
struct vfio_cdx_device *vdev =
105+
container_of(core_vdev, struct vfio_cdx_device, vdev);
106+
void __user *uarg = (void __user *)arg;
107+
108+
switch (cmd) {
109+
case VFIO_DEVICE_GET_INFO:
110+
return vfio_cdx_ioctl_get_info(vdev, uarg);
111+
case VFIO_DEVICE_GET_REGION_INFO:
112+
return vfio_cdx_ioctl_get_region_info(vdev, uarg);
113+
case VFIO_DEVICE_RESET:
114+
return cdx_dev_reset(core_vdev->dev);
115+
default:
116+
return -ENOTTY;
117+
}
118+
}
119+
120+
static int vfio_cdx_mmap_mmio(struct vfio_cdx_region region,
121+
struct vm_area_struct *vma)
122+
{
123+
u64 size = vma->vm_end - vma->vm_start;
124+
u64 pgoff, base;
125+
126+
pgoff = vma->vm_pgoff &
127+
((1U << (VFIO_CDX_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
128+
base = pgoff << PAGE_SHIFT;
129+
130+
if (base + size > region.size)
131+
return -EINVAL;
132+
133+
vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
134+
vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
135+
136+
return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
137+
size, vma->vm_page_prot);
138+
}
139+
140+
static int vfio_cdx_mmap(struct vfio_device *core_vdev,
141+
struct vm_area_struct *vma)
142+
{
143+
struct vfio_cdx_device *vdev =
144+
container_of(core_vdev, struct vfio_cdx_device, vdev);
145+
struct cdx_device *cdx_dev = to_cdx_device(core_vdev->dev);
146+
unsigned int index;
147+
148+
index = vma->vm_pgoff >> (VFIO_CDX_OFFSET_SHIFT - PAGE_SHIFT);
149+
150+
if (index >= cdx_dev->res_count)
151+
return -EINVAL;
152+
153+
if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
154+
return -EINVAL;
155+
156+
if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ) &&
157+
(vma->vm_flags & VM_READ))
158+
return -EPERM;
159+
160+
if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE) &&
161+
(vma->vm_flags & VM_WRITE))
162+
return -EPERM;
163+
164+
return vfio_cdx_mmap_mmio(vdev->regions[index], vma);
165+
}
166+
167+
static const struct vfio_device_ops vfio_cdx_ops = {
168+
.name = "vfio-cdx",
169+
.open_device = vfio_cdx_open_device,
170+
.close_device = vfio_cdx_close_device,
171+
.ioctl = vfio_cdx_ioctl,
172+
.mmap = vfio_cdx_mmap,
173+
.bind_iommufd = vfio_iommufd_physical_bind,
174+
.unbind_iommufd = vfio_iommufd_physical_unbind,
175+
.attach_ioas = vfio_iommufd_physical_attach_ioas,
176+
};
177+
178+
static int vfio_cdx_probe(struct cdx_device *cdx_dev)
179+
{
180+
struct vfio_cdx_device *vdev;
181+
struct device *dev = &cdx_dev->dev;
182+
int ret;
183+
184+
vdev = vfio_alloc_device(vfio_cdx_device, vdev, dev,
185+
&vfio_cdx_ops);
186+
if (IS_ERR(vdev))
187+
return PTR_ERR(vdev);
188+
189+
ret = vfio_register_group_dev(&vdev->vdev);
190+
if (ret)
191+
goto out_uninit;
192+
193+
dev_set_drvdata(dev, vdev);
194+
return 0;
195+
196+
out_uninit:
197+
vfio_put_device(&vdev->vdev);
198+
return ret;
199+
}
200+
201+
static int vfio_cdx_remove(struct cdx_device *cdx_dev)
202+
{
203+
struct device *dev = &cdx_dev->dev;
204+
struct vfio_cdx_device *vdev = dev_get_drvdata(dev);
205+
206+
vfio_unregister_group_dev(&vdev->vdev);
207+
vfio_put_device(&vdev->vdev);
208+
209+
return 0;
210+
}
211+
212+
static const struct cdx_device_id vfio_cdx_table[] = {
213+
{ CDX_DEVICE_DRIVER_OVERRIDE(CDX_ANY_ID, CDX_ANY_ID,
214+
CDX_ID_F_VFIO_DRIVER_OVERRIDE) }, /* match all by default */
215+
{}
216+
};
217+
218+
MODULE_DEVICE_TABLE(cdx, vfio_cdx_table);
219+
220+
static struct cdx_driver vfio_cdx_driver = {
221+
.probe = vfio_cdx_probe,
222+
.remove = vfio_cdx_remove,
223+
.match_id_table = vfio_cdx_table,
224+
.driver = {
225+
.name = "vfio-cdx",
226+
.owner = THIS_MODULE,
227+
},
228+
.driver_managed_dma = true,
229+
};
230+
231+
module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister);
232+
233+
MODULE_LICENSE("GPL");
234+
MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver");

drivers/vfio/cdx/private.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
4+
*/
5+
6+
#ifndef VFIO_CDX_PRIVATE_H
7+
#define VFIO_CDX_PRIVATE_H
8+
9+
#define VFIO_CDX_OFFSET_SHIFT 40
10+
11+
static inline u64 vfio_cdx_index_to_offset(u32 index)
12+
{
13+
return ((u64)(index) << VFIO_CDX_OFFSET_SHIFT);
14+
}
15+
16+
struct vfio_cdx_region {
17+
u32 flags;
18+
u32 type;
19+
u64 addr;
20+
resource_size_t size;
21+
};
22+
23+
struct vfio_cdx_device {
24+
struct vfio_device vdev;
25+
struct vfio_cdx_region *regions;
26+
};
27+
28+
#endif /* VFIO_CDX_PRIVATE_H */

include/linux/cdx/cdx_bus.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <linux/mod_devicetable.h>
1515

1616
#define MAX_CDX_DEV_RESOURCES 4
17-
#define CDX_ANY_ID (0xFFFF)
1817
#define CDX_CONTROLLER_ID_SHIFT 4
1918
#define CDX_BUS_NUM_MASK 0xF
2019

include/linux/mod_devicetable.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,12 @@ struct ishtp_device_id {
912912
kernel_ulong_t driver_data;
913913
};
914914

915+
#define CDX_ANY_ID (0xFFFF)
916+
917+
enum {
918+
CDX_ID_F_VFIO_DRIVER_OVERRIDE = 1,
919+
};
920+
915921
/**
916922
* struct cdx_device_id - CDX device identifier
917923
* @vendor: Vendor ID

include/uapi/linux/vfio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ struct vfio_device_info {
213213
#define VFIO_DEVICE_FLAGS_AP (1 << 5) /* vfio-ap device */
214214
#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 6) /* vfio-fsl-mc device */
215215
#define VFIO_DEVICE_FLAGS_CAPS (1 << 7) /* Info supports caps */
216+
#define VFIO_DEVICE_FLAGS_CDX (1 << 8) /* vfio-cdx device */
216217
__u32 num_regions; /* Max region index + 1 */
217218
__u32 num_irqs; /* Max IRQ index + 1 */
218219
__u32 cap_offset; /* Offset within info struct of first cap */

scripts/mod/devicetable-offsets.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ int main(void)
265265
DEVID(cdx_device_id);
266266
DEVID_FIELD(cdx_device_id, vendor);
267267
DEVID_FIELD(cdx_device_id, device);
268+
DEVID_FIELD(cdx_device_id, override_only);
268269

269270
return 0;
270271
}

scripts/mod/file2alias.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,8 +1458,23 @@ static int do_cdx_entry(const char *filename, void *symval,
14581458
{
14591459
DEF_FIELD(symval, cdx_device_id, vendor);
14601460
DEF_FIELD(symval, cdx_device_id, device);
1461+
DEF_FIELD(symval, cdx_device_id, override_only);
14611462

1462-
sprintf(alias, "cdx:v%08Xd%08Xd", vendor, device);
1463+
switch (override_only) {
1464+
case 0:
1465+
strcpy(alias, "cdx:");
1466+
break;
1467+
case CDX_ID_F_VFIO_DRIVER_OVERRIDE:
1468+
strcpy(alias, "vfio_cdx:");
1469+
break;
1470+
default:
1471+
warn("Unknown CDX driver_override alias %08X\n",
1472+
override_only);
1473+
return 0;
1474+
}
1475+
1476+
ADD(alias, "v", vendor != CDX_ANY_ID, vendor);
1477+
ADD(alias, "d", device != CDX_ANY_ID, device);
14631478
return 1;
14641479
}
14651480

0 commit comments

Comments
 (0)