c538ed0d5c11920eace5047c0606b45f8b4dc79b
[openwrt/staging/ldir.git] /
1 From 10abb46294d1569826854f77bcdb5d38d8db8e79 Mon Sep 17 00:00:00 2001
2 From: Diana Craciun <diana.craciun@nxp.com>
3 Date: Thu, 26 Sep 2019 15:13:24 +0300
4 Subject: [PATCH] vfio/fsl-mc: Implement VFIO_DEVICE_GET_REGION_INFO ioctl call
5
6 Expose to userspace information about the memory regions.
7
8 Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
9 Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
10 ---
11 drivers/vfio/fsl-mc/vfio_fsl_mc.c | 76 ++++++++++++++++++++++++++++++-
12 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 19 ++++++++
13 2 files changed, 94 insertions(+), 1 deletion(-)
14
15 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
16 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
17 @@ -16,16 +16,70 @@
18 #include "vfio_fsl_mc_private.h"
19
20
21 +static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
22 +{
23 + struct fsl_mc_device *mc_dev = vdev->mc_dev;
24 + int count = mc_dev->obj_desc.region_count;
25 + int i;
26 +
27 + vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region),
28 + GFP_KERNEL);
29 + if (!vdev->regions)
30 + return -ENOMEM;
31 +
32 + for (i = 0; i < count; i++) {
33 + struct resource *res = &mc_dev->regions[i];
34 +
35 + vdev->regions[i].addr = res->start;
36 + vdev->regions[i].size = PAGE_ALIGN((resource_size(res)));
37 + vdev->regions[i].flags = 0;
38 + }
39 +
40 + vdev->num_regions = mc_dev->obj_desc.region_count;
41 + return 0;
42 +}
43 +static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
44 +{
45 + vdev->num_regions = 0;
46 + kfree(vdev->regions);
47 +}
48 +
49 static int vfio_fsl_mc_open(void *device_data)
50 {
51 + struct vfio_fsl_mc_device *vdev = device_data;
52 + int ret;
53 +
54 if (!try_module_get(THIS_MODULE))
55 return -ENODEV;
56
57 + mutex_lock(&vdev->driver_lock);
58 + if (!vdev->refcnt) {
59 + ret = vfio_fsl_mc_regions_init(vdev);
60 + if (ret)
61 + goto err_reg_init;
62 + }
63 + vdev->refcnt++;
64 +
65 + mutex_unlock(&vdev->driver_lock);
66 return 0;
67 +
68 +err_reg_init:
69 + mutex_unlock(&vdev->driver_lock);
70 + module_put(THIS_MODULE);
71 + return ret;
72 }
73
74 static void vfio_fsl_mc_release(void *device_data)
75 {
76 + struct vfio_fsl_mc_device *vdev = device_data;
77 +
78 + mutex_lock(&vdev->driver_lock);
79 +
80 + if (!(--vdev->refcnt))
81 + vfio_fsl_mc_regions_cleanup(vdev);
82 +
83 + mutex_unlock(&vdev->driver_lock);
84 +
85 module_put(THIS_MODULE);
86 }
87
88 @@ -59,7 +113,26 @@ static long vfio_fsl_mc_ioctl(void *devi
89 }
90 case VFIO_DEVICE_GET_REGION_INFO:
91 {
92 - return -EINVAL;
93 + struct vfio_region_info info;
94 +
95 + minsz = offsetofend(struct vfio_region_info, offset);
96 +
97 + if (copy_from_user(&info, (void __user *)arg, minsz))
98 + return -EFAULT;
99 +
100 + if (info.argsz < minsz)
101 + return -EINVAL;
102 +
103 + if (info.index >= vdev->num_regions)
104 + return -EINVAL;
105 +
106 + /* map offset to the physical address */
107 + info.offset = VFIO_FSL_MC_INDEX_TO_OFFSET(info.index);
108 + info.size = vdev->regions[info.index].size;
109 + info.flags = vdev->regions[info.index].flags;
110 +
111 + return copy_to_user((void __user *)arg, &info, minsz);
112 +
113 }
114 case VFIO_DEVICE_GET_IRQ_INFO:
115 {
116 @@ -206,6 +279,7 @@ static int vfio_fsl_mc_probe(struct fsl_
117 vfio_iommu_group_put(group, dev);
118 return ret;
119 }
120 + mutex_init(&vdev->driver_lock);
121
122 return ret;
123 }
124 --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
125 +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
126 @@ -7,8 +7,27 @@
127 #ifndef VFIO_FSL_MC_PRIVATE_H
128 #define VFIO_FSL_MC_PRIVATE_H
129
130 +#define VFIO_FSL_MC_OFFSET_SHIFT 40
131 +#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1)
132 +
133 +#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT)
134 +
135 +#define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \
136 + ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)
137 +
138 +struct vfio_fsl_mc_region {
139 + u32 flags;
140 + u32 type;
141 + u64 addr;
142 + resource_size_t size;
143 +};
144 +
145 struct vfio_fsl_mc_device {
146 struct fsl_mc_device *mc_dev;
147 + int refcnt;
148 + u32 num_regions;
149 + struct vfio_fsl_mc_region *regions;
150 + struct mutex driver_lock;
151 };
152
153 #endif /* VFIO_PCI_PRIVATE_H */