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 | /* | 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 | */ |