Skip to content

Commit

Permalink
vfio/platform: return info for device memory mapped IO regions
Browse files Browse the repository at this point in the history
This patch enables the IOCTLs VFIO_DEVICE_GET_REGION_INFO ioctl call,
which allows the user to learn about the available MMIO resources of
a device.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
Reviewed-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
  • Loading branch information
Antonios Motakis authored and Alex Williamson committed Mar 16, 2015
1 parent 2e8567b commit e8909e6
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 4 deletions.
106 changes: 102 additions & 4 deletions drivers/vfio/platform/vfio_platform_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,97 @@

#include "vfio_platform_private.h"

static DEFINE_MUTEX(driver_lock);

static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
{
int cnt = 0, i;

while (vdev->get_resource(vdev, cnt))
cnt++;

vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),
GFP_KERNEL);
if (!vdev->regions)
return -ENOMEM;

for (i = 0; i < cnt; i++) {
struct resource *res =
vdev->get_resource(vdev, i);

if (!res)
goto err;

vdev->regions[i].addr = res->start;
vdev->regions[i].size = resource_size(res);
vdev->regions[i].flags = 0;

switch (resource_type(res)) {
case IORESOURCE_MEM:
vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;
break;
case IORESOURCE_IO:
vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
break;
default:
goto err;
}
}

vdev->num_regions = cnt;

return 0;
err:
kfree(vdev->regions);
return -EINVAL;
}

static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
{
vdev->num_regions = 0;
kfree(vdev->regions);
}

static void vfio_platform_release(void *device_data)
{
struct vfio_platform_device *vdev = device_data;

mutex_lock(&driver_lock);

if (!(--vdev->refcnt)) {
vfio_platform_regions_cleanup(vdev);
}

mutex_unlock(&driver_lock);

module_put(THIS_MODULE);
}

static int vfio_platform_open(void *device_data)
{
struct vfio_platform_device *vdev = device_data;
int ret;

if (!try_module_get(THIS_MODULE))
return -ENODEV;

mutex_lock(&driver_lock);

if (!vdev->refcnt) {
ret = vfio_platform_regions_init(vdev);
if (ret)
goto err_reg;
}

vdev->refcnt++;

mutex_unlock(&driver_lock);
return 0;

err_reg:
mutex_unlock(&driver_lock);
module_put(THIS_MODULE);
return ret;
}

static long vfio_platform_ioctl(void *device_data,
Expand All @@ -54,15 +134,33 @@ static long vfio_platform_ioctl(void *device_data,
return -EINVAL;

info.flags = vdev->flags;
info.num_regions = 0;
info.num_regions = vdev->num_regions;
info.num_irqs = 0;

return copy_to_user((void __user *)arg, &info, minsz);

} else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
return -EINVAL;
} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
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_PLATFORM_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);

else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
return -EINVAL;

else if (cmd == VFIO_DEVICE_SET_IRQS)
Expand Down
22 changes: 22 additions & 0 deletions drivers/vfio/platform/vfio_platform_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,29 @@
#include <linux/types.h>
#include <linux/interrupt.h>

#define VFIO_PLATFORM_OFFSET_SHIFT 40
#define VFIO_PLATFORM_OFFSET_MASK (((u64)(1) << VFIO_PLATFORM_OFFSET_SHIFT) - 1)

#define VFIO_PLATFORM_OFFSET_TO_INDEX(off) \
(off >> VFIO_PLATFORM_OFFSET_SHIFT)

#define VFIO_PLATFORM_INDEX_TO_OFFSET(index) \
((u64)(index) << VFIO_PLATFORM_OFFSET_SHIFT)

struct vfio_platform_region {
u64 addr;
resource_size_t size;
u32 flags;
u32 type;
#define VFIO_PLATFORM_REGION_TYPE_MMIO 1
#define VFIO_PLATFORM_REGION_TYPE_PIO 2
};

struct vfio_platform_device {
struct vfio_platform_region *regions;
u32 num_regions;
int refcnt;

/*
* These fields should be filled by the bus specific binder
*/
Expand Down

0 comments on commit e8909e6

Please sign in to comment.