Merge tag 'vfio-v4.6-rc1' of git://github.com/awilliam/linux-vfio
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Mar 2016 20:05:09 +0000 (13:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Mar 2016 20:05:09 +0000 (13:05 -0700)
Pull VFIO updates from Alex Williamson:
 "Various enablers for assignment of Intel graphics devices and future
  support of vGPU devices (Alex Williamson).  This includes

   - Handling the vfio type1 interface as an API rather than a specific
     implementation, allowing multiple type1 providers.

   - Capability chains, similar to PCI device capabilities, that allow
     extending ioctls.  Extensions here include device specific regions
     and sparse mmap descriptions.  The former is used to expose non-PCI
     regions for IGD, including the OpRegion (particularly the Video
     BIOS Table), and read only PCI config access to the host and LPC
     bridge as drivers often depend on identifying those devices.

     Sparse mmaps here are used to describe the MSIx vector table, which
     vfio has always protected from mmap, but never had an API to
     explicitly define that protection.  In future vGPU support this is
     expected to allow the description of PCI BARs that may mix direct
     access and emulated access within a single region.

   - The ability to expose the shadow ROM as an option ROM as IGD use
     cases may rely on the ROM even though the physical device does not
     make use of a PCI option ROM BAR"

* tag 'vfio-v4.6-rc1' of git://github.com/awilliam/linux-vfio:
  vfio/pci: return -EFAULT if copy_to_user fails
  vfio/pci: Expose shadow ROM as PCI option ROM
  vfio/pci: Intel IGD host and LCP bridge config space access
  vfio/pci: Intel IGD OpRegion support
  vfio/pci: Enable virtual register in PCI config space
  vfio/pci: Add infrastructure for additional device specific regions
  vfio: Define device specific region type capability
  vfio/pci: Include sparse mmap capability for MSI-X table regions
  vfio: Define sparse mmap capability for regions
  vfio: Add capability chain helpers
  vfio: Define capability chains
  vfio: If an IOMMU backend fails, keep looking
  vfio/pci: Fix unsigned comparison overflow

1  2 
drivers/vfio/pci/vfio_pci.c

index 8c80a48e32335346e426547fa5007e179ff7cec7,98059df9cff6bd94a015f1f47e3941fbf16775da..712a84978e972bf29082575cdb083ec9450be657
@@@ -443,11 -551,10 +551,11 @@@ static long vfio_pci_ioctl(void *device
                if (vdev->reset_works)
                        info.flags |= VFIO_DEVICE_FLAGS_RESET;
  
-               info.num_regions = VFIO_PCI_NUM_REGIONS;
+               info.num_regions = VFIO_PCI_NUM_REGIONS + vdev->num_regions;
                info.num_irqs = VFIO_PCI_NUM_IRQS;
  
 -              return copy_to_user((void __user *)arg, &info, minsz);
 +              return copy_to_user((void __user *)arg, &info, minsz) ?
 +                      -EFAULT : 0;
  
        } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
                struct pci_dev *pdev = vdev->pdev;
  
                        break;
                default:
-                       return -EINVAL;
+                       if (info.index >=
+                           VFIO_PCI_NUM_REGIONS + vdev->num_regions)
+                               return -EINVAL;
+                       i = info.index - VFIO_PCI_NUM_REGIONS;
+                       info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+                       info.size = vdev->region[i].size;
+                       info.flags = vdev->region[i].flags;
+                       ret = region_type_cap(vdev, &caps,
+                                             vdev->region[i].type,
+                                             vdev->region[i].subtype);
+                       if (ret)
+                               return ret;
+               }
+               if (caps.size) {
+                       info.flags |= VFIO_REGION_INFO_FLAG_CAPS;
+                       if (info.argsz < sizeof(info) + caps.size) {
+                               info.argsz = sizeof(info) + caps.size;
+                               info.cap_offset = 0;
+                       } else {
+                               vfio_info_cap_shift(&caps, sizeof(info));
+                               if (copy_to_user((void __user *)arg +
+                                                 sizeof(info), caps.buf,
+                                                 caps.size)) {
+                                       kfree(caps.buf);
+                                       return -EFAULT;
+                               }
+                               info.cap_offset = sizeof(info);
+                       }
+                       kfree(caps.buf);
                }
  
 -              return copy_to_user((void __user *)arg, &info, minsz);
 +              return copy_to_user((void __user *)arg, &info, minsz) ?
 +                      -EFAULT : 0;
  
        } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
                struct vfio_irq_info info;