summaryrefslogtreecommitdiff
path: root/drivers/vfio
diff options
context:
space:
mode:
authorBharat Bhushan <Bharat.Bhushan@nxp.com>2017-05-11 07:04:03 (GMT)
committerXie Xiaobo <xiaobo.xie@nxp.com>2017-09-25 07:25:34 (GMT)
commit5637efc7dcfaaf48781a1c0131f8f8ff6bf0a38a (patch)
tree724841ddc3e85a5cf9c26b27be6dde214229b1de /drivers/vfio
parent7a66c154a8e16622f8e8f873220de85f6035c078 (diff)
downloadlinux-5637efc7dcfaaf48781a1c0131f8f8ff6bf0a38a.tar.xz
vfio fsl-mc: Return fsl-mc device MMIO region info
Add support for VFIO_DEVICE_GET_REGION_INFO ioctl call. This allows usespace to know device mmap-able region details. MC device (DPIO) have a region which is cacheable and non-shareable. Describe these regions as cacheable so that during mmap() they will be mapped accordingly. Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
Diffstat (limited to 'drivers/vfio')
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc.c94
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc_private.h20
2 files changed, 113 insertions, 1 deletions
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index b01e9c0..e5a6779 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -28,16 +28,90 @@
#define DRIVER_AUTHOR "Bharat Bhushan <bharat.bhushan@nxp.com>"
#define DRIVER_DESC "VFIO for FSL-MC devices - User Level meta-driver"
+static DEFINE_MUTEX(driver_lock);
+
+/* FSl-MC device regions (address and size) are aligned to 64K.
+ * While MC firmware reports size less than 64K for some objects (it actually
+ * reports size which does not include reserved space beyond valid bytes).
+ * Align the size to PAGE_SIZE for userspace to mmap.
+ */
+static size_t aligned_region_size(struct fsl_mc_device *mc_dev, int index)
+{
+ size_t size;
+
+ size = resource_size(&mc_dev->regions[index]);
+ return PAGE_ALIGN(size);
+}
+
+static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
+{
+ struct fsl_mc_device *mc_dev = vdev->mc_dev;
+ int count = mc_dev->obj_desc.region_count;
+ int i;
+
+ vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
+ GFP_KERNEL);
+ if (!vdev->regions)
+ return -ENOMEM;
+
+ for (i = 0; i < mc_dev->obj_desc.region_count; i++) {
+ vdev->regions[i].addr = mc_dev->regions[i].start;
+ vdev->regions[i].size = aligned_region_size(mc_dev, i);
+ vdev->regions[i].type = VFIO_FSL_MC_REGION_TYPE_MMIO;
+ if (mc_dev->regions[i].flags & IORESOURCE_CACHEABLE)
+ vdev->regions[i].type |=
+ VFIO_FSL_MC_REGION_TYPE_CACHEABLE;
+ vdev->regions[i].flags = 0;
+ }
+
+ vdev->num_regions = mc_dev->obj_desc.region_count;
+ return 0;
+}
+
+static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
+{
+ vdev->num_regions = 0;
+ kfree(vdev->regions);
+}
+
static int vfio_fsl_mc_open(void *device_data)
{
+ struct vfio_fsl_mc_device *vdev = device_data;
+ int ret;
+
if (!try_module_get(THIS_MODULE))
return -ENODEV;
+ mutex_lock(&driver_lock);
+ if (!vdev->refcnt) {
+ ret = vfio_fsl_mc_regions_init(vdev);
+ if (ret)
+ goto error_region_init;
+ }
+
+ vdev->refcnt++;
+ mutex_unlock(&driver_lock);
return 0;
+
+error_region_init:
+ mutex_unlock(&driver_lock);
+ if (ret)
+ module_put(THIS_MODULE);
+
+ return ret;
}
static void vfio_fsl_mc_release(void *device_data)
{
+ struct vfio_fsl_mc_device *vdev = device_data;
+
+ mutex_lock(&driver_lock);
+
+ if (!(--vdev->refcnt))
+ vfio_fsl_mc_regions_cleanup(vdev);
+
+ mutex_unlock(&driver_lock);
+
module_put(THIS_MODULE);
}
@@ -72,7 +146,25 @@ static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
}
case VFIO_DEVICE_GET_REGION_INFO:
{
- return -EINVAL;
+ struct vfio_region_info info;
+
+ minsz = offsetofend(struct vfio_region_info, offset);
+
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ if (info.index >= vdev->num_regions)
+ return -EINVAL;
+
+ /* map offset to the physical address */
+ info.offset = VFIO_FSL_MC_INDEX_TO_OFFSET(info.index);
+ info.size = vdev->regions[info.index].size;
+ info.flags = vdev->regions[info.index].flags;
+
+ return copy_to_user((void __user *)arg, &info, minsz);
}
case VFIO_DEVICE_GET_IRQ_INFO:
{
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
index e680f8e..e9d7f3b 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
@@ -13,8 +13,28 @@
#ifndef VFIO_FSL_MC_PRIVATE_H
#define VFIO_FSL_MC_PRIVATE_H
+#define VFIO_FSL_MC_OFFSET_SHIFT 40
+#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1)
+
+#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT)
+
+#define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
+ ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
+
+struct vfio_fsl_mc_region {
+ u32 flags;
+#define VFIO_FSL_MC_REGION_TYPE_MMIO 1
+#define VFIO_FSL_MC_REGION_TYPE_CACHEABLE 2
+ u32 type;
+ u64 addr;
+ resource_size_t size;
+};
+
struct vfio_fsl_mc_device {
struct fsl_mc_device *mc_dev;
+ int refcnt;
+ u32 num_regions;
+ struct vfio_fsl_mc_region *regions;
};
#endif /* VFIO_PCI_PRIVATE_H */