summaryrefslogtreecommitdiffstats
path: root/drivers/vfio
diff options
context:
space:
mode:
authorAntonios Motakis <a.motakis@virtualopensystems.com>2015-03-16 16:08:46 -0400
committerAlex Williamson <alex.williamson@redhat.com>2015-03-16 16:08:46 -0400
commite8909e67cac3ad3868dc86cc6b1445f39c71bf63 (patch)
tree41dc63c1092d66dc8c2e4581d2783bd5f61769b1 /drivers/vfio
parent2e8567bbb536cfc7336f8f105ef43adc98b9c156 (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.c106
-rw-r--r--drivers/vfio/platform/vfio_platform_private.h22
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
26static DEFINE_MUTEX(driver_lock);
27
28static 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;
66err:
67 kfree(vdev->regions);
68 return -EINVAL;
69}
70
71static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
72{
73 vdev->num_regions = 0;
74 kfree(vdev->regions);
75}
76
26static void vfio_platform_release(void *device_data) 77static 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
31static int vfio_platform_open(void *device_data) 92static 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
113err_reg:
114 mutex_unlock(&driver_lock);
115 module_put(THIS_MODULE);
116 return ret;
37} 117}
38 118
39static long vfio_platform_ioctl(void *device_data, 119static 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
30struct 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
21struct vfio_platform_device { 39struct vfio_platform_device {
40 struct vfio_platform_region *regions;
41 u32 num_regions;
42 int refcnt;
43
22 /* 44 /*
23 * These fields should be filled by the bus specific binder 45 * These fields should be filled by the bus specific binder
24 */ 46 */