Commit 34b1cf60 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 27529c89 46ed90f1
...@@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, ...@@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (!sparse) if (!sparse)
return -ENOMEM; return -ENOMEM;
sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
sparse->header.version = 1;
sparse->nr_areas = nr_areas; sparse->nr_areas = nr_areas;
cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
sparse->areas[0].offset = sparse->areas[0].offset =
...@@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, ...@@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
break; break;
default: 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 + if (info.index >= VFIO_PCI_NUM_REGIONS +
vgpu->vdev.num_regions) vgpu->vdev.num_regions)
...@@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, ...@@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
cap_type.subtype = vgpu->vdev.region[i].subtype; cap_type.subtype = vgpu->vdev.region[i].subtype;
ret = vfio_info_add_capability(&caps, ret = vfio_info_add_capability(&caps,
VFIO_REGION_INFO_CAP_TYPE, &cap_type.header,
&cap_type); sizeof(cap_type));
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, ...@@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
switch (cap_type_id) { switch (cap_type_id) {
case VFIO_REGION_INFO_CAP_SPARSE_MMAP: case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
ret = vfio_info_add_capability(&caps, ret = vfio_info_add_capability(&caps,
VFIO_REGION_INFO_CAP_SPARSE_MMAP, &sparse->header, sizeof(*sparse) +
sparse); (sparse->nr_areas *
sizeof(*sparse->areas)));
kfree(sparse); kfree(sparse);
if (ret) if (ret)
return ret; return ret;
......
...@@ -111,19 +111,19 @@ static const struct vfio_device_ops vfio_mdev_dev_ops = { ...@@ -111,19 +111,19 @@ static const struct vfio_device_ops vfio_mdev_dev_ops = {
.mmap = vfio_mdev_mmap, .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); struct mdev_device *mdev = to_mdev_device(dev);
return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); 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); vfio_del_group_dev(dev);
} }
struct mdev_driver vfio_mdev_driver = { static struct mdev_driver vfio_mdev_driver = {
.name = "vfio_mdev", .name = "vfio_mdev",
.probe = vfio_mdev_probe, .probe = vfio_mdev_probe,
.remove = vfio_mdev_remove, .remove = vfio_mdev_remove,
......
...@@ -207,6 +207,9 @@ static bool vfio_pci_nointx(struct pci_dev *pdev) ...@@ -207,6 +207,9 @@ static bool vfio_pci_nointx(struct pci_dev *pdev)
} }
} }
if (!pdev->irq)
return true;
return false; return false;
} }
...@@ -562,46 +565,15 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev, ...@@ -562,46 +565,15 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
return walk.ret; return walk.ret;
} }
static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev, static int msix_mmappable_cap(struct vfio_pci_device *vdev,
struct vfio_info_cap *caps) struct vfio_info_cap *caps)
{ {
struct vfio_region_info_cap_sparse_mmap *sparse; struct vfio_info_cap_header header = {
size_t end, size; .id = VFIO_REGION_INFO_CAP_MSIX_MAPPABLE,
int nr_areas = 2, i = 0, ret; .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, int vfio_pci_register_dev_region(struct vfio_pci_device *vdev,
...@@ -692,7 +664,7 @@ static long vfio_pci_ioctl(void *device_data, ...@@ -692,7 +664,7 @@ static long vfio_pci_ioctl(void *device_data,
if (vdev->bar_mmap_supported[info.index]) { if (vdev->bar_mmap_supported[info.index]) {
info.flags |= VFIO_REGION_INFO_FLAG_MMAP; info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
if (info.index == vdev->msix_bar) { if (info.index == vdev->msix_bar) {
ret = msix_sparse_mmap_cap(vdev, &caps); ret = msix_mmappable_cap(vdev, &caps);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -741,7 +713,9 @@ static long vfio_pci_ioctl(void *device_data, ...@@ -741,7 +713,9 @@ static long vfio_pci_ioctl(void *device_data,
break; break;
default: 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 >= if (info.index >=
VFIO_PCI_NUM_REGIONS + vdev->num_regions) VFIO_PCI_NUM_REGIONS + vdev->num_regions)
...@@ -756,9 +730,8 @@ static long vfio_pci_ioctl(void *device_data, ...@@ -756,9 +730,8 @@ static long vfio_pci_ioctl(void *device_data,
cap_type.type = vdev->region[i].type; cap_type.type = vdev->region[i].type;
cap_type.subtype = vdev->region[i].subtype; cap_type.subtype = vdev->region[i].subtype;
ret = vfio_info_add_capability(&caps, ret = vfio_info_add_capability(&caps, &cap_type.header,
VFIO_REGION_INFO_CAP_TYPE, sizeof(cap_type));
&cap_type);
if (ret) if (ret)
return ret; return ret;
...@@ -1122,22 +1095,6 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) ...@@ -1122,22 +1095,6 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
if (req_start + req_len > phys_len) if (req_start + req_len > phys_len)
return -EINVAL; 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, * Even though we don't make use of the barmap for the mmap,
* we need to request the region and the barmap tracks that. * 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) ...@@ -1857,63 +1857,19 @@ void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
} }
EXPORT_SYMBOL(vfio_info_cap_shift); 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_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, cap->id, cap->version);
header = vfio_info_cap_add(caps, size,
VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
if (IS_ERR(header)) if (IS_ERR(header))
return PTR_ERR(header); return PTR_ERR(header);
sparse_cap = container_of(header, memcpy(header + 1, cap + 1, size - sizeof(*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));
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; 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); EXPORT_SYMBOL(vfio_info_add_capability);
int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs, 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( ...@@ -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 void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
extern int vfio_info_add_capability(struct vfio_info_cap *caps, 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, extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr,
int num_irqs, int max_irq_type, int num_irqs, int max_irq_type,
......
...@@ -301,6 +301,16 @@ struct vfio_region_info_cap_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_HOST_CFG (2)
#define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) #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, * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9,
* struct vfio_irq_info) * struct vfio_irq_info)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment