mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
VFIO updates for v4.16-rc1
- Mask INTx from user if pdev->irq is zero (Alexey Kardashevskiy) - Capability helper cleanup (Alex Williamson) - Allow mmaps overlapping MSI-X vector table with region capability exposing this feature (Alexey Kardashevskiy) - mdev static cleanups (Xiongwei Song) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJac2tQAAoJECObm247sIsiUr8P/2zrK0G/mVrHWGEjlnlvgYjg FSozgN0fmc9mJ+Hg8ntfXn4GXuTaCq0uz96eMl9Wy1tMpLs4hoQf20IRojIpqgpb aVUHKg+7sJUWNsd+u1jSBb64SvQLdTbesfGgL8WLcJB90jWxzaZjEZ3mgKO4Lb88 rNEpiTVoOURDgJo+bOMEnJJ6okmpRLBgw5pqrdLT2BButZg3QfLtcuoY18pFYxc7 INy4YPWPe93aiDGloUrjj6xKRKfTaL7L8KGZBlk4FR5JENDRoOtGEguGcQRl0u8w IYLIkIE9p172S5bkeCYqawyxAPgQQIk5Wd4buFArg9w7tdWJOkEiCMwSu/LCocR8 CiwZHKOWp7mJWv3XxJGY+rU3nHIuB+IaeKknE6rLXgkLVXED5Ta4pPzrpoUZezsT yyI5U2BnWNL5ISaWY3i+YQKvFUgPe8Az9Zw4p3zGUJ+zu2QheN7x+BVXT0xENMfk 2sdNFeZwkxmB18pdsJdb+/DpL9yCrS7VxP3IDnAdfR8VIyLE3QFRTnsfNX7F1Uvr zKBZChuah2osiiM3k3ncwkovsM6iN1ZLVnHUg7xRBmp6WQnBYN02wrTXM/e1UqsS nKIBYA9fIcpLZ4hXMuiMmk7LFlScl/HngW+h+jWAyoP/j3X0gw/YM5hrPEJEV3fN WuIPpBYN36+0V9cUDMnN =Ww3n -----END PGP SIGNATURE----- Merge tag 'vfio-v4.16-rc1' of git://github.com/awilliam/linux-vfio Pull VFIO updates from Alex Williamson: - Mask INTx from user if pdev->irq is zero (Alexey Kardashevskiy) - Capability helper cleanup (Alex Williamson) - Allow mmaps overlapping MSI-X vector table with region capability exposing this feature (Alexey Kardashevskiy) - mdev static cleanups (Xiongwei Song) * tag 'vfio-v4.16-rc1' of git://github.com/awilliam/linux-vfio: vfio: mdev: make a couple of functions and structure vfio_mdev_driver static vfio-pci: Allow mapping MSIX BAR vfio: Simplify capability helper vfio-pci: Mask INTx if a device is not capabable of enabling it
This commit is contained in:
commit
34b1cf60ab
6 changed files with 46 additions and 117 deletions
|
@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
|
|||
if (!sparse)
|
||||
return -ENOMEM;
|
||||
|
||||
sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
|
||||
sparse->header.version = 1;
|
||||
sparse->nr_areas = nr_areas;
|
||||
cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
|
||||
sparse->areas[0].offset =
|
||||
|
@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
|
|||
break;
|
||||
default:
|
||||
{
|
||||
struct vfio_region_info_cap_type cap_type;
|
||||
struct vfio_region_info_cap_type cap_type = {
|
||||
.header.id = VFIO_REGION_INFO_CAP_TYPE,
|
||||
.header.version = 1 };
|
||||
|
||||
if (info.index >= VFIO_PCI_NUM_REGIONS +
|
||||
vgpu->vdev.num_regions)
|
||||
|
@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
|
|||
cap_type.subtype = vgpu->vdev.region[i].subtype;
|
||||
|
||||
ret = vfio_info_add_capability(&caps,
|
||||
VFIO_REGION_INFO_CAP_TYPE,
|
||||
&cap_type);
|
||||
&cap_type.header,
|
||||
sizeof(cap_type));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
|
|||
switch (cap_type_id) {
|
||||
case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
|
||||
ret = vfio_info_add_capability(&caps,
|
||||
VFIO_REGION_INFO_CAP_SPARSE_MMAP,
|
||||
sparse);
|
||||
&sparse->header, sizeof(*sparse) +
|
||||
(sparse->nr_areas *
|
||||
sizeof(*sparse->areas)));
|
||||
kfree(sparse);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -111,19 +111,19 @@ static const struct vfio_device_ops vfio_mdev_dev_ops = {
|
|||
.mmap = vfio_mdev_mmap,
|
||||
};
|
||||
|
||||
int vfio_mdev_probe(struct device *dev)
|
||||
static int vfio_mdev_probe(struct device *dev)
|
||||
{
|
||||
struct mdev_device *mdev = to_mdev_device(dev);
|
||||
|
||||
return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev);
|
||||
}
|
||||
|
||||
void vfio_mdev_remove(struct device *dev)
|
||||
static void vfio_mdev_remove(struct device *dev)
|
||||
{
|
||||
vfio_del_group_dev(dev);
|
||||
}
|
||||
|
||||
struct mdev_driver vfio_mdev_driver = {
|
||||
static struct mdev_driver vfio_mdev_driver = {
|
||||
.name = "vfio_mdev",
|
||||
.probe = vfio_mdev_probe,
|
||||
.remove = vfio_mdev_remove,
|
||||
|
|
|
@ -207,6 +207,9 @@ static bool vfio_pci_nointx(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (!pdev->irq)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -562,46 +565,15 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
|
|||
return walk.ret;
|
||||
}
|
||||
|
||||
static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
|
||||
struct vfio_info_cap *caps)
|
||||
static int msix_mmappable_cap(struct vfio_pci_device *vdev,
|
||||
struct vfio_info_cap *caps)
|
||||
{
|
||||
struct vfio_region_info_cap_sparse_mmap *sparse;
|
||||
size_t end, size;
|
||||
int nr_areas = 2, i = 0, ret;
|
||||
struct vfio_info_cap_header header = {
|
||||
.id = VFIO_REGION_INFO_CAP_MSIX_MAPPABLE,
|
||||
.version = 1
|
||||
};
|
||||
|
||||
end = pci_resource_len(vdev->pdev, vdev->msix_bar);
|
||||
|
||||
/* If MSI-X table is aligned to the start or end, only one area */
|
||||
if (((vdev->msix_offset & PAGE_MASK) == 0) ||
|
||||
(PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) >= end))
|
||||
nr_areas = 1;
|
||||
|
||||
size = sizeof(*sparse) + (nr_areas * sizeof(*sparse->areas));
|
||||
|
||||
sparse = kzalloc(size, GFP_KERNEL);
|
||||
if (!sparse)
|
||||
return -ENOMEM;
|
||||
|
||||
sparse->nr_areas = nr_areas;
|
||||
|
||||
if (vdev->msix_offset & PAGE_MASK) {
|
||||
sparse->areas[i].offset = 0;
|
||||
sparse->areas[i].size = vdev->msix_offset & PAGE_MASK;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) < end) {
|
||||
sparse->areas[i].offset = PAGE_ALIGN(vdev->msix_offset +
|
||||
vdev->msix_size);
|
||||
sparse->areas[i].size = end - sparse->areas[i].offset;
|
||||
i++;
|
||||
}
|
||||
|
||||
ret = vfio_info_add_capability(caps, VFIO_REGION_INFO_CAP_SPARSE_MMAP,
|
||||
sparse);
|
||||
kfree(sparse);
|
||||
|
||||
return ret;
|
||||
return vfio_info_add_capability(caps, &header, sizeof(header));
|
||||
}
|
||||
|
||||
int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
|
||||
|
@ -692,7 +664,7 @@ static long vfio_pci_ioctl(void *device_data,
|
|||
if (vdev->bar_mmap_supported[info.index]) {
|
||||
info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
|
||||
if (info.index == vdev->msix_bar) {
|
||||
ret = msix_sparse_mmap_cap(vdev, &caps);
|
||||
ret = msix_mmappable_cap(vdev, &caps);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -741,7 +713,9 @@ static long vfio_pci_ioctl(void *device_data,
|
|||
break;
|
||||
default:
|
||||
{
|
||||
struct vfio_region_info_cap_type cap_type;
|
||||
struct vfio_region_info_cap_type cap_type = {
|
||||
.header.id = VFIO_REGION_INFO_CAP_TYPE,
|
||||
.header.version = 1 };
|
||||
|
||||
if (info.index >=
|
||||
VFIO_PCI_NUM_REGIONS + vdev->num_regions)
|
||||
|
@ -756,9 +730,8 @@ static long vfio_pci_ioctl(void *device_data,
|
|||
cap_type.type = vdev->region[i].type;
|
||||
cap_type.subtype = vdev->region[i].subtype;
|
||||
|
||||
ret = vfio_info_add_capability(&caps,
|
||||
VFIO_REGION_INFO_CAP_TYPE,
|
||||
&cap_type);
|
||||
ret = vfio_info_add_capability(&caps, &cap_type.header,
|
||||
sizeof(cap_type));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1122,22 +1095,6 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
|
|||
if (req_start + req_len > phys_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (index == vdev->msix_bar) {
|
||||
/*
|
||||
* Disallow mmaps overlapping the MSI-X table; users don't
|
||||
* get to touch this directly. We could find somewhere
|
||||
* else to map the overlap, but page granularity is only
|
||||
* a recommendation, not a requirement, so the user needs
|
||||
* to know which bits are real. Requiring them to mmap
|
||||
* around the table makes that clear.
|
||||
*/
|
||||
|
||||
/* If neither entirely above nor below, then it overlaps */
|
||||
if (!(req_start >= vdev->msix_offset + vdev->msix_size ||
|
||||
req_start + req_len <= vdev->msix_offset))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Even though we don't make use of the barmap for the mmap,
|
||||
* we need to request the region and the barmap tracks that.
|
||||
|
|
|
@ -1857,63 +1857,19 @@ void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
|
|||
}
|
||||
EXPORT_SYMBOL(vfio_info_cap_shift);
|
||||
|
||||
static int sparse_mmap_cap(struct vfio_info_cap *caps, void *cap_type)
|
||||
int vfio_info_add_capability(struct vfio_info_cap *caps,
|
||||
struct vfio_info_cap_header *cap, size_t size)
|
||||
{
|
||||
struct vfio_info_cap_header *header;
|
||||
struct vfio_region_info_cap_sparse_mmap *sparse_cap, *sparse = cap_type;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*sparse) + sparse->nr_areas * sizeof(*sparse->areas);
|
||||
header = vfio_info_cap_add(caps, size,
|
||||
VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
|
||||
header = vfio_info_cap_add(caps, size, cap->id, cap->version);
|
||||
if (IS_ERR(header))
|
||||
return PTR_ERR(header);
|
||||
|
||||
sparse_cap = container_of(header,
|
||||
struct vfio_region_info_cap_sparse_mmap, header);
|
||||
sparse_cap->nr_areas = sparse->nr_areas;
|
||||
memcpy(sparse_cap->areas, sparse->areas,
|
||||
sparse->nr_areas * sizeof(*sparse->areas));
|
||||
memcpy(header + 1, cap + 1, size - sizeof(*header));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int region_type_cap(struct vfio_info_cap *caps, void *cap_type)
|
||||
{
|
||||
struct vfio_info_cap_header *header;
|
||||
struct vfio_region_info_cap_type *type_cap, *cap = cap_type;
|
||||
|
||||
header = vfio_info_cap_add(caps, sizeof(*cap),
|
||||
VFIO_REGION_INFO_CAP_TYPE, 1);
|
||||
if (IS_ERR(header))
|
||||
return PTR_ERR(header);
|
||||
|
||||
type_cap = container_of(header, struct vfio_region_info_cap_type,
|
||||
header);
|
||||
type_cap->type = cap->type;
|
||||
type_cap->subtype = cap->subtype;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfio_info_add_capability(struct vfio_info_cap *caps, int cap_type_id,
|
||||
void *cap_type)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!cap_type)
|
||||
return 0;
|
||||
|
||||
switch (cap_type_id) {
|
||||
case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
|
||||
ret = sparse_mmap_cap(caps, cap_type);
|
||||
break;
|
||||
|
||||
case VFIO_REGION_INFO_CAP_TYPE:
|
||||
ret = region_type_cap(caps, cap_type);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(vfio_info_add_capability);
|
||||
|
||||
int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
|
||||
|
|
|
@ -145,7 +145,8 @@ extern struct vfio_info_cap_header *vfio_info_cap_add(
|
|||
extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
|
||||
|
||||
extern int vfio_info_add_capability(struct vfio_info_cap *caps,
|
||||
int cap_type_id, void *cap_type);
|
||||
struct vfio_info_cap_header *cap,
|
||||
size_t size);
|
||||
|
||||
extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr,
|
||||
int num_irqs, int max_irq_type,
|
||||
|
|
|
@ -301,6 +301,16 @@ struct vfio_region_info_cap_type {
|
|||
#define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2)
|
||||
#define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3)
|
||||
|
||||
/*
|
||||
* The MSIX mappable capability informs that MSIX data of a BAR can be mmapped
|
||||
* which allows direct access to non-MSIX registers which happened to be within
|
||||
* the same system page.
|
||||
*
|
||||
* Even though the userspace gets direct access to the MSIX data, the existing
|
||||
* VFIO_DEVICE_SET_IRQS interface must still be used for MSIX configuration.
|
||||
*/
|
||||
#define VFIO_REGION_INFO_CAP_MSIX_MAPPABLE 3
|
||||
|
||||
/**
|
||||
* VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
|
||||
* struct vfio_irq_info)
|
||||
|
|
Loading…
Reference in a new issue