diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 16:18:25 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-01 16:18:25 -0500 |
| commit | 34b1cf60abb06fa79d5f8e56f1def843dbf91888 (patch) | |
| tree | 2b6145709fa3c5900957cc0f625fad85f9378c7b | |
| parent | 27529c891b132f4fc65711334e885f466138ea2a (diff) | |
| parent | 46ed90f157f42d956ffed17c003f089a59b76e3e (diff) | |
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
| -rw-r--r-- | drivers/gpu/drm/i915/gvt/kvmgt.c | 15 | ||||
| -rw-r--r-- | drivers/vfio/mdev/vfio_mdev.c | 6 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 75 | ||||
| -rw-r--r-- | drivers/vfio/vfio.c | 52 | ||||
| -rw-r--r-- | include/linux/vfio.h | 3 | ||||
| -rw-r--r-- | include/uapi/linux/vfio.h | 10 |
6 files changed, 45 insertions, 116 deletions
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 96060920a6fe..0a7d084da1a2 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c | |||
| @@ -1012,6 +1012,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1012 | if (!sparse) | 1012 | if (!sparse) |
| 1013 | return -ENOMEM; | 1013 | return -ENOMEM; |
| 1014 | 1014 | ||
| 1015 | sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; | ||
| 1016 | sparse->header.version = 1; | ||
| 1015 | sparse->nr_areas = nr_areas; | 1017 | sparse->nr_areas = nr_areas; |
| 1016 | cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; | 1018 | cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; |
| 1017 | sparse->areas[0].offset = | 1019 | sparse->areas[0].offset = |
| @@ -1033,7 +1035,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1033 | break; | 1035 | break; |
| 1034 | default: | 1036 | default: |
| 1035 | { | 1037 | { |
| 1036 | struct vfio_region_info_cap_type cap_type; | 1038 | struct vfio_region_info_cap_type cap_type = { |
| 1039 | .header.id = VFIO_REGION_INFO_CAP_TYPE, | ||
| 1040 | .header.version = 1 }; | ||
| 1037 | 1041 | ||
| 1038 | if (info.index >= VFIO_PCI_NUM_REGIONS + | 1042 | if (info.index >= VFIO_PCI_NUM_REGIONS + |
| 1039 | vgpu->vdev.num_regions) | 1043 | vgpu->vdev.num_regions) |
| @@ -1050,8 +1054,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1050 | cap_type.subtype = vgpu->vdev.region[i].subtype; | 1054 | cap_type.subtype = vgpu->vdev.region[i].subtype; |
| 1051 | 1055 | ||
| 1052 | ret = vfio_info_add_capability(&caps, | 1056 | ret = vfio_info_add_capability(&caps, |
| 1053 | VFIO_REGION_INFO_CAP_TYPE, | 1057 | &cap_type.header, |
| 1054 | &cap_type); | 1058 | sizeof(cap_type)); |
| 1055 | if (ret) | 1059 | if (ret) |
| 1056 | return ret; | 1060 | return ret; |
| 1057 | } | 1061 | } |
| @@ -1061,8 +1065,9 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
| 1061 | switch (cap_type_id) { | 1065 | switch (cap_type_id) { |
| 1062 | case VFIO_REGION_INFO_CAP_SPARSE_MMAP: | 1066 | case VFIO_REGION_INFO_CAP_SPARSE_MMAP: |
| 1063 | ret = vfio_info_add_capability(&caps, | 1067 | ret = vfio_info_add_capability(&caps, |
| 1064 | VFIO_REGION_INFO_CAP_SPARSE_MMAP, | 1068 | &sparse->header, sizeof(*sparse) + |
| 1065 | sparse); | 1069 | (sparse->nr_areas * |
| 1070 | sizeof(*sparse->areas))); | ||
| 1066 | kfree(sparse); | 1071 | kfree(sparse); |
| 1067 | if (ret) | 1072 | if (ret) |
| 1068 | return ret; | 1073 | return ret; |
diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index fa848a701b8b..d230620fe02d 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c | |||
| @@ -111,19 +111,19 @@ static const struct vfio_device_ops vfio_mdev_dev_ops = { | |||
| 111 | .mmap = vfio_mdev_mmap, | 111 | .mmap = vfio_mdev_mmap, |
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | int vfio_mdev_probe(struct device *dev) | 114 | static int vfio_mdev_probe(struct device *dev) |
| 115 | { | 115 | { |
| 116 | struct mdev_device *mdev = to_mdev_device(dev); | 116 | struct mdev_device *mdev = to_mdev_device(dev); |
| 117 | 117 | ||
| 118 | return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); | 118 | return vfio_add_group_dev(dev, &vfio_mdev_dev_ops, mdev); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | void vfio_mdev_remove(struct device *dev) | 121 | static void vfio_mdev_remove(struct device *dev) |
| 122 | { | 122 | { |
| 123 | vfio_del_group_dev(dev); | 123 | vfio_del_group_dev(dev); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | struct mdev_driver vfio_mdev_driver = { | 126 | static struct mdev_driver vfio_mdev_driver = { |
| 127 | .name = "vfio_mdev", | 127 | .name = "vfio_mdev", |
| 128 | .probe = vfio_mdev_probe, | 128 | .probe = vfio_mdev_probe, |
| 129 | .remove = vfio_mdev_remove, | 129 | .remove = vfio_mdev_remove, |
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index f041b1a6cf66..b0f759476900 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
| @@ -207,6 +207,9 @@ static bool vfio_pci_nointx(struct pci_dev *pdev) | |||
| 207 | } | 207 | } |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | if (!pdev->irq) | ||
| 211 | return true; | ||
| 212 | |||
| 210 | return false; | 213 | return false; |
| 211 | } | 214 | } |
| 212 | 215 | ||
| @@ -562,46 +565,15 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev, | |||
| 562 | return walk.ret; | 565 | return walk.ret; |
| 563 | } | 566 | } |
| 564 | 567 | ||
| 565 | static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev, | 568 | static int msix_mmappable_cap(struct vfio_pci_device *vdev, |
| 566 | struct vfio_info_cap *caps) | 569 | struct vfio_info_cap *caps) |
| 567 | { | 570 | { |
| 568 | struct vfio_region_info_cap_sparse_mmap *sparse; | 571 | struct vfio_info_cap_header header = { |
| 569 | size_t end, size; | 572 | .id = VFIO_REGION_INFO_CAP_MSIX_MAPPABLE, |
| 570 | int nr_areas = 2, i = 0, ret; | 573 | .version = 1 |
| 571 | 574 | }; | |
| 572 | end = pci_resource_len(vdev->pdev, vdev->msix_bar); | ||
| 573 | |||
| 574 | /* If MSI-X table is aligned to the start or end, only one area */ | ||
| 575 | if (((vdev->msix_offset & PAGE_MASK) == 0) || | ||
| 576 | (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) >= end)) | ||
| 577 | nr_areas = 1; | ||
| 578 | |||
| 579 | size = sizeof(*sparse) + (nr_areas * sizeof(*sparse->areas)); | ||
| 580 | |||
| 581 | sparse = kzalloc(size, GFP_KERNEL); | ||
| 582 | if (!sparse) | ||
| 583 | return -ENOMEM; | ||
| 584 | |||
| 585 | sparse->nr_areas = nr_areas; | ||
| 586 | |||
| 587 | if (vdev->msix_offset & PAGE_MASK) { | ||
| 588 | sparse->areas[i].offset = 0; | ||
| 589 | sparse->areas[i].size = vdev->msix_offset & PAGE_MASK; | ||
| 590 | i++; | ||
| 591 | } | ||
| 592 | |||
| 593 | if (PAGE_ALIGN(vdev->msix_offset + vdev->msix_size) < end) { | ||
| 594 | sparse->areas[i].offset = PAGE_ALIGN(vdev->msix_offset + | ||
| 595 | vdev->msix_size); | ||
| 596 | sparse->areas[i].size = end - sparse->areas[i].offset; | ||
| 597 | i++; | ||
| 598 | } | ||
| 599 | |||
| 600 | ret = vfio_info_add_capability(caps, VFIO_REGION_INFO_CAP_SPARSE_MMAP, | ||
| 601 | sparse); | ||
| 602 | kfree(sparse); | ||
| 603 | 575 | ||
| 604 | return ret; | 576 | return vfio_info_add_capability(caps, &header, sizeof(header)); |
| 605 | } | 577 | } |
| 606 | 578 | ||
| 607 | int vfio_pci_register_dev_region(struct vfio_pci_device *vdev, | 579 | int vfio_pci_register_dev_region(struct vfio_pci_device *vdev, |
| @@ -692,7 +664,7 @@ static long vfio_pci_ioctl(void *device_data, | |||
| 692 | if (vdev->bar_mmap_supported[info.index]) { | 664 | if (vdev->bar_mmap_supported[info.index]) { |
| 693 | info.flags |= VFIO_REGION_INFO_FLAG_MMAP; | 665 | info.flags |= VFIO_REGION_INFO_FLAG_MMAP; |
| 694 | if (info.index == vdev->msix_bar) { | 666 | if (info.index == vdev->msix_bar) { |
| 695 | ret = msix_sparse_mmap_cap(vdev, &caps); | 667 | ret = msix_mmappable_cap(vdev, &caps); |
| 696 | if (ret) | 668 | if (ret) |
| 697 | return ret; | 669 | return ret; |
| 698 | } | 670 | } |
| @@ -741,7 +713,9 @@ static long vfio_pci_ioctl(void *device_data, | |||
| 741 | break; | 713 | break; |
| 742 | default: | 714 | default: |
| 743 | { | 715 | { |
| 744 | struct vfio_region_info_cap_type cap_type; | 716 | struct vfio_region_info_cap_type cap_type = { |
| 717 | .header.id = VFIO_REGION_INFO_CAP_TYPE, | ||
| 718 | .header.version = 1 }; | ||
| 745 | 719 | ||
| 746 | if (info.index >= | 720 | if (info.index >= |
| 747 | VFIO_PCI_NUM_REGIONS + vdev->num_regions) | 721 | VFIO_PCI_NUM_REGIONS + vdev->num_regions) |
| @@ -756,9 +730,8 @@ static long vfio_pci_ioctl(void *device_data, | |||
| 756 | cap_type.type = vdev->region[i].type; | 730 | cap_type.type = vdev->region[i].type; |
| 757 | cap_type.subtype = vdev->region[i].subtype; | 731 | cap_type.subtype = vdev->region[i].subtype; |
| 758 | 732 | ||
| 759 | ret = vfio_info_add_capability(&caps, | 733 | ret = vfio_info_add_capability(&caps, &cap_type.header, |
| 760 | VFIO_REGION_INFO_CAP_TYPE, | 734 | sizeof(cap_type)); |
| 761 | &cap_type); | ||
| 762 | if (ret) | 735 | if (ret) |
| 763 | return ret; | 736 | return ret; |
| 764 | 737 | ||
| @@ -1122,22 +1095,6 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) | |||
| 1122 | if (req_start + req_len > phys_len) | 1095 | if (req_start + req_len > phys_len) |
| 1123 | return -EINVAL; | 1096 | return -EINVAL; |
| 1124 | 1097 | ||
| 1125 | if (index == vdev->msix_bar) { | ||
| 1126 | /* | ||
| 1127 | * Disallow mmaps overlapping the MSI-X table; users don't | ||
| 1128 | * get to touch this directly. We could find somewhere | ||
| 1129 | * else to map the overlap, but page granularity is only | ||
| 1130 | * a recommendation, not a requirement, so the user needs | ||
| 1131 | * to know which bits are real. Requiring them to mmap | ||
| 1132 | * around the table makes that clear. | ||
| 1133 | */ | ||
| 1134 | |||
| 1135 | /* If neither entirely above nor below, then it overlaps */ | ||
| 1136 | if (!(req_start >= vdev->msix_offset + vdev->msix_size || | ||
| 1137 | req_start + req_len <= vdev->msix_offset)) | ||
| 1138 | return -EINVAL; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | /* | 1098 | /* |
| 1142 | * Even though we don't make use of the barmap for the mmap, | 1099 | * Even though we don't make use of the barmap for the mmap, |
| 1143 | * we need to request the region and the barmap tracks that. | 1100 | * we need to request the region and the barmap tracks that. |
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 2bc3705a99bd..721f97f8dac1 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
| @@ -1857,63 +1857,19 @@ void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset) | |||
| 1857 | } | 1857 | } |
| 1858 | EXPORT_SYMBOL(vfio_info_cap_shift); | 1858 | EXPORT_SYMBOL(vfio_info_cap_shift); |
| 1859 | 1859 | ||
| 1860 | static int sparse_mmap_cap(struct vfio_info_cap *caps, void *cap_type) | 1860 | int vfio_info_add_capability(struct vfio_info_cap *caps, |
| 1861 | struct vfio_info_cap_header *cap, size_t size) | ||
| 1861 | { | 1862 | { |
| 1862 | struct vfio_info_cap_header *header; | 1863 | struct vfio_info_cap_header *header; |
| 1863 | struct vfio_region_info_cap_sparse_mmap *sparse_cap, *sparse = cap_type; | ||
| 1864 | size_t size; | ||
| 1865 | 1864 | ||
| 1866 | size = sizeof(*sparse) + sparse->nr_areas * sizeof(*sparse->areas); | 1865 | header = vfio_info_cap_add(caps, size, cap->id, cap->version); |
| 1867 | header = vfio_info_cap_add(caps, size, | ||
| 1868 | VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1); | ||
| 1869 | if (IS_ERR(header)) | 1866 | if (IS_ERR(header)) |
| 1870 | return PTR_ERR(header); | 1867 | return PTR_ERR(header); |
| 1871 | 1868 | ||
| 1872 | sparse_cap = container_of(header, | 1869 | memcpy(header + 1, cap + 1, size - sizeof(*header)); |
| 1873 | struct vfio_region_info_cap_sparse_mmap, header); | ||
| 1874 | sparse_cap->nr_areas = sparse->nr_areas; | ||
| 1875 | memcpy(sparse_cap->areas, sparse->areas, | ||
| 1876 | sparse->nr_areas * sizeof(*sparse->areas)); | ||
| 1877 | return 0; | ||
| 1878 | } | ||
| 1879 | |||
| 1880 | static int region_type_cap(struct vfio_info_cap *caps, void *cap_type) | ||
| 1881 | { | ||
| 1882 | struct vfio_info_cap_header *header; | ||
| 1883 | struct vfio_region_info_cap_type *type_cap, *cap = cap_type; | ||
| 1884 | 1870 | ||
| 1885 | header = vfio_info_cap_add(caps, sizeof(*cap), | ||
| 1886 | VFIO_REGION_INFO_CAP_TYPE, 1); | ||
| 1887 | if (IS_ERR(header)) | ||
| 1888 | return PTR_ERR(header); | ||
| 1889 | |||
| 1890 | type_cap = container_of(header, struct vfio_region_info_cap_type, | ||
| 1891 | header); | ||
| 1892 | type_cap->type = cap->type; | ||
| 1893 | type_cap->subtype = cap->subtype; | ||
| 1894 | return 0; | 1871 | return 0; |
| 1895 | } | 1872 | } |
| 1896 | |||
| 1897 | int vfio_info_add_capability(struct vfio_info_cap *caps, int cap_type_id, | ||
| 1898 | void *cap_type) | ||
| 1899 | { | ||
| 1900 | int ret = -EINVAL; | ||
| 1901 | |||
| 1902 | if (!cap_type) | ||
| 1903 | return 0; | ||
| 1904 | |||
| 1905 | switch (cap_type_id) { | ||
| 1906 | case VFIO_REGION_INFO_CAP_SPARSE_MMAP: | ||
| 1907 | ret = sparse_mmap_cap(caps, cap_type); | ||
| 1908 | break; | ||
| 1909 | |||
| 1910 | case VFIO_REGION_INFO_CAP_TYPE: | ||
| 1911 | ret = region_type_cap(caps, cap_type); | ||
| 1912 | break; | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | return ret; | ||
| 1916 | } | ||
| 1917 | EXPORT_SYMBOL(vfio_info_add_capability); | 1873 | EXPORT_SYMBOL(vfio_info_add_capability); |
| 1918 | 1874 | ||
| 1919 | int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs, | 1875 | int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs, |
diff --git a/include/linux/vfio.h b/include/linux/vfio.h index a47b985341d1..66741ab087c1 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h | |||
| @@ -145,7 +145,8 @@ extern struct vfio_info_cap_header *vfio_info_cap_add( | |||
| 145 | extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset); | 145 | extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset); |
| 146 | 146 | ||
| 147 | extern int vfio_info_add_capability(struct vfio_info_cap *caps, | 147 | extern int vfio_info_add_capability(struct vfio_info_cap *caps, |
| 148 | int cap_type_id, void *cap_type); | 148 | struct vfio_info_cap_header *cap, |
| 149 | size_t size); | ||
| 149 | 150 | ||
| 150 | extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, | 151 | extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, |
| 151 | int num_irqs, int max_irq_type, | 152 | int num_irqs, int max_irq_type, |
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h index e3301dbd27d4..0d914350f7bf 100644 --- a/include/uapi/linux/vfio.h +++ b/include/uapi/linux/vfio.h | |||
| @@ -301,6 +301,16 @@ struct vfio_region_info_cap_type { | |||
| 301 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) | 301 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) |
| 302 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) | 302 | #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) |
| 303 | 303 | ||
| 304 | /* | ||
| 305 | * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped | ||
| 306 | * which allows direct access to non-MSIX registers which happened to be within | ||
| 307 | * the same system page. | ||
| 308 | * | ||
| 309 | * Even though the userspace gets direct access to the MSIX data, the existing | ||
| 310 | * VFIO_DEVICE_SET_IRQS interface must still be used for MSIX configuration. | ||
| 311 | */ | ||
| 312 | #define VFIO_REGION_INFO_CAP_MSIX_MAPPABLE 3 | ||
| 313 | |||
| 304 | /** | 314 | /** |
| 305 | * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9, | 315 | * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9, |
| 306 | * struct vfio_irq_info) | 316 | * struct vfio_irq_info) |
