diff options
| author | Antonios Motakis <a.motakis@virtualopensystems.com> | 2015-03-16 16:08:46 -0400 |
|---|---|---|
| committer | Alex Williamson <alex.williamson@redhat.com> | 2015-03-16 16:08:46 -0400 |
| commit | e8909e67cac3ad3868dc86cc6b1445f39c71bf63 (patch) | |
| tree | 41dc63c1092d66dc8c2e4581d2783bd5f61769b1 /drivers/vfio | |
| parent | 2e8567bbb536cfc7336f8f105ef43adc98b9c156 (diff) | |
vfio/platform: return info for device memory mapped IO regions
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>
Diffstat (limited to 'drivers/vfio')
| -rw-r--r-- | drivers/vfio/platform/vfio_platform_common.c | 106 | ||||
| -rw-r--r-- | drivers/vfio/platform/vfio_platform_private.h | 22 |
2 files changed, 124 insertions, 4 deletions
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index c2f853a3b3dd..47f6309b4889 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c | |||
| @@ -23,17 +23,97 @@ | |||
| 23 | 23 | ||
| 24 | #include "vfio_platform_private.h" | 24 | #include "vfio_platform_private.h" |
| 25 | 25 | ||
| 26 | static DEFINE_MUTEX(driver_lock); | ||
| 27 | |||
| 28 | static int vfio_platform_regions_init(struct vfio_platform_device *vdev) | ||
| 29 | { | ||
| 30 | int cnt = 0, i; | ||
| 31 | |||
| 32 | while (vdev->get_resource(vdev, cnt)) | ||
| 33 | cnt++; | ||
| 34 | |||
| 35 | vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region), | ||
| 36 | GFP_KERNEL); | ||
| 37 | if (!vdev->regions) | ||
| 38 | return -ENOMEM; | ||
| 39 | |||
| 40 | for (i = 0; i < cnt; i++) { | ||
| 41 | struct resource *res = | ||
| 42 | vdev->get_resource(vdev, i); | ||
| 43 | |||
| 44 | if (!res) | ||
| 45 | goto err; | ||
| 46 | |||
| 47 | vdev->regions[i].addr = res->start; | ||
| 48 | vdev->regions[i].size = resource_size(res); | ||
| 49 | vdev->regions[i].flags = 0; | ||
| 50 | |||
| 51 | switch (resource_type(res)) { | ||
| 52 | case IORESOURCE_MEM: | ||
| 53 | vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO; | ||
| 54 | break; | ||
| 55 | case IORESOURCE_IO: | ||
| 56 | vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO; | ||
| 57 | break; | ||
| 58 | default: | ||
| 59 | goto err; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | vdev->num_regions = cnt; | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | err: | ||
| 67 | kfree(vdev->regions); | ||
| 68 | return -EINVAL; | ||
| 69 | } | ||
| 70 | |||
| 71 | static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev) | ||
| 72 | { | ||
| 73 | vdev->num_regions = 0; | ||
| 74 | kfree(vdev->regions); | ||
| 75 | } | ||
| 76 | |||
| 26 | static void vfio_platform_release(void *device_data) | 77 | static void vfio_platform_release(void *device_data) |
| 27 | { | 78 | { |
| 79 | struct vfio_platform_device *vdev = device_data; | ||
| 80 | |||
| 81 | mutex_lock(&driver_lock); | ||
| 82 | |||
| 83 | if (!(--vdev->refcnt)) { | ||
| 84 | vfio_platform_regions_cleanup(vdev); | ||
| 85 | } | ||
| 86 | |||
| 87 | mutex_unlock(&driver_lock); | ||
| 88 | |||
| 28 | module_put(THIS_MODULE); | 89 | module_put(THIS_MODULE); |
| 29 | } | 90 | } |
| 30 | 91 | ||
| 31 | static int vfio_platform_open(void *device_data) | 92 | static int vfio_platform_open(void *device_data) |
| 32 | { | 93 | { |
| 94 | struct vfio_platform_device *vdev = device_data; | ||
| 95 | int ret; | ||
| 96 | |||
| 33 | if (!try_module_get(THIS_MODULE)) | 97 | if (!try_module_get(THIS_MODULE)) |
| 34 | return -ENODEV; | 98 | return -ENODEV; |
| 35 | 99 | ||
| 100 | mutex_lock(&driver_lock); | ||
| 101 | |||
| 102 | if (!vdev->refcnt) { | ||
| 103 | ret = vfio_platform_regions_init(vdev); | ||
| 104 | if (ret) | ||
| 105 | goto err_reg; | ||
| 106 | } | ||
| 107 | |||
| 108 | vdev->refcnt++; | ||
| 109 | |||
| 110 | mutex_unlock(&driver_lock); | ||
| 36 | return 0; | 111 | return 0; |
| 112 | |||
| 113 | err_reg: | ||
| 114 | mutex_unlock(&driver_lock); | ||
| 115 | module_put(THIS_MODULE); | ||
| 116 | return ret; | ||
| 37 | } | 117 | } |
| 38 | 118 | ||
| 39 | static long vfio_platform_ioctl(void *device_data, | 119 | static long vfio_platform_ioctl(void *device_data, |
| @@ -54,15 +134,33 @@ static long vfio_platform_ioctl(void *device_data, | |||
| 54 | return -EINVAL; | 134 | return -EINVAL; |
| 55 | 135 | ||
| 56 | info.flags = vdev->flags; | 136 | info.flags = vdev->flags; |
| 57 | info.num_regions = 0; | 137 | info.num_regions = vdev->num_regions; |
| 58 | info.num_irqs = 0; | 138 | info.num_irqs = 0; |
| 59 | 139 | ||
| 60 | return copy_to_user((void __user *)arg, &info, minsz); | 140 | return copy_to_user((void __user *)arg, &info, minsz); |
| 61 | 141 | ||
| 62 | } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) | 142 | } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { |
| 63 | return -EINVAL; | 143 | struct vfio_region_info info; |
| 144 | |||
| 145 | minsz = offsetofend(struct vfio_region_info, offset); | ||
| 146 | |||
| 147 | if (copy_from_user(&info, (void __user *)arg, minsz)) | ||
| 148 | return -EFAULT; | ||
| 149 | |||
| 150 | if (info.argsz < minsz) | ||
| 151 | return -EINVAL; | ||
| 152 | |||
| 153 | if (info.index >= vdev->num_regions) | ||
| 154 | return -EINVAL; | ||
| 155 | |||
| 156 | /* map offset to the physical address */ | ||
| 157 | info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index); | ||
| 158 | info.size = vdev->regions[info.index].size; | ||
| 159 | info.flags = vdev->regions[info.index].flags; | ||
| 160 | |||
| 161 | return copy_to_user((void __user *)arg, &info, minsz); | ||
| 64 | 162 | ||
| 65 | else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) | 163 | } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) |
| 66 | return -EINVAL; | 164 | return -EINVAL; |
| 67 | 165 | ||
| 68 | else if (cmd == VFIO_DEVICE_SET_IRQS) | 166 | else if (cmd == VFIO_DEVICE_SET_IRQS) |
diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h index c04698872440..3551f6d97fc3 100644 --- a/drivers/vfio/platform/vfio_platform_private.h +++ b/drivers/vfio/platform/vfio_platform_private.h | |||
| @@ -18,7 +18,29 @@ | |||
| 18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | 20 | ||
| 21 | #define VFIO_PLATFORM_OFFSET_SHIFT 40 | ||
| 22 | #define VFIO_PLATFORM_OFFSET_MASK (((u64)(1) << VFIO_PLATFORM_OFFSET_SHIFT) - 1) | ||
| 23 | |||
| 24 | #define VFIO_PLATFORM_OFFSET_TO_INDEX(off) \ | ||
| 25 | (off >> VFIO_PLATFORM_OFFSET_SHIFT) | ||
| 26 | |||
| 27 | #define VFIO_PLATFORM_INDEX_TO_OFFSET(index) \ | ||
| 28 | ((u64)(index) << VFIO_PLATFORM_OFFSET_SHIFT) | ||
| 29 | |||
| 30 | struct vfio_platform_region { | ||
| 31 | u64 addr; | ||
| 32 | resource_size_t size; | ||
| 33 | u32 flags; | ||
| 34 | u32 type; | ||
| 35 | #define VFIO_PLATFORM_REGION_TYPE_MMIO 1 | ||
| 36 | #define VFIO_PLATFORM_REGION_TYPE_PIO 2 | ||
| 37 | }; | ||
| 38 | |||
| 21 | struct vfio_platform_device { | 39 | struct vfio_platform_device { |
| 40 | struct vfio_platform_region *regions; | ||
| 41 | u32 num_regions; | ||
| 42 | int refcnt; | ||
| 43 | |||
| 22 | /* | ||
