diff options
-rw-r--r-- | Documentation/vfio-mediated-device.txt | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/gvt/kvmgt.c | 24 | ||||
-rw-r--r-- | drivers/vfio/mdev/mdev_core.c | 100 | ||||
-rw-r--r-- | drivers/vfio/mdev/mdev_private.h | 29 | ||||
-rw-r--r-- | drivers/vfio/mdev/mdev_sysfs.c | 8 | ||||
-rw-r--r-- | drivers/vfio/mdev/vfio_mdev.c | 12 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 4 | ||||
-rw-r--r-- | drivers/vfio/pci/vfio_pci_rdwr.c | 5 | ||||
-rw-r--r-- | drivers/vfio/vfio_iommu_type1.c | 98 | ||||
-rw-r--r-- | include/linux/mdev.h | 56 | ||||
-rw-r--r-- | samples/Kconfig | 7 | ||||
-rw-r--r-- | samples/Makefile | 3 | ||||
-rw-r--r-- | samples/vfio-mdev/Makefile | 14 | ||||
-rw-r--r-- | samples/vfio-mdev/mtty.c | 32 |
14 files changed, 247 insertions, 172 deletions
diff --git a/Documentation/vfio-mediated-device.txt b/Documentation/vfio-mediated-device.txt index b38afec35edc..d226c7a5ba8b 100644 --- a/Documentation/vfio-mediated-device.txt +++ b/Documentation/vfio-mediated-device.txt | |||
@@ -127,22 +127,22 @@ the VFIO when devices are unbound from the driver. | |||
127 | Physical Device Driver Interface | 127 | Physical Device Driver Interface |
128 | -------------------------------- | 128 | -------------------------------- |
129 | 129 | ||
130 | The physical device driver interface provides the parent_ops[3] structure to | 130 | The physical device driver interface provides the mdev_parent_ops[3] structure |
131 | define the APIs to manage work in the mediated core driver that is related to | 131 | to define the APIs to manage work in the mediated core driver that is related |
132 | the physical device. | 132 | to the physical device. |
133 | 133 | ||
134 | The structures in the parent_ops structure are as follows: | 134 | The structures in the mdev_parent_ops structure are as follows: |
135 | 135 | ||
136 | * dev_attr_groups: attributes of the parent device | 136 | * dev_attr_groups: attributes of the parent device |
137 | * mdev_attr_groups: attributes of the mediated device | 137 | * mdev_attr_groups: attributes of the mediated device |
138 | * supported_config: attributes to define supported configurations | 138 | * supported_config: attributes to define supported configurations |
139 | 139 | ||
140 | The functions in the parent_ops structure are as follows: | 140 | The functions in the mdev_parent_ops structure are as follows: |
141 | 141 | ||
142 | * create: allocate basic resources in a driver for a mediated device | 142 | * create: allocate basic resources in a driver for a mediated device |
143 | * remove: free resources in a driver when a mediated device is destroyed | 143 | * remove: free resources in a driver when a mediated device is destroyed |
144 | 144 | ||
145 | The callbacks in the parent_ops structure are as follows: | 145 | The callbacks in the mdev_parent_ops structure are as follows: |
146 | 146 | ||
147 | * open: open callback of mediated device | 147 | * open: open callback of mediated device |
148 | * close: close callback of mediated device | 148 | * close: close callback of mediated device |
@@ -151,14 +151,14 @@ The callbacks in the parent_ops structure are as follows: | |||
151 | * write: write emulation callback | 151 | * write: write emulation callback |
152 | * mmap: mmap emulation callback | 152 | * mmap: mmap emulation callback |
153 | 153 | ||
154 | A driver should use the parent_ops structure in the function call to register | 154 | A driver should use the mdev_parent_ops structure in the function call to |
155 | itself with the mdev core driver: | 155 | register itself with the mdev core driver: |
156 | 156 | ||
157 | extern int mdev_register_device(struct device *dev, | 157 | extern int mdev_register_device(struct device *dev, |
158 | const struct parent_ops *ops); | 158 | const struct mdev_parent_ops *ops); |
159 | 159 | ||
160 | However, the parent_ops structure is not required in the function call that a | 160 | However, the mdev_parent_ops structure is not required in the function call |
161 | driver should use to unregister itself with the mdev core driver: | 161 | that a driver should use to unregister itself with the mdev core driver: |
162 | 162 | ||
163 | extern void mdev_unregister_device(struct device *dev); | 163 | extern void mdev_unregister_device(struct device *dev); |
164 | 164 | ||
@@ -223,6 +223,9 @@ Directories and files under the sysfs for Each Physical Device | |||
223 | 223 | ||
224 | sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name); | 224 | sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name); |
225 | 225 | ||
226 | (or using mdev_parent_dev(mdev) to arrive at the parent device outside | ||
227 | of the core mdev code) | ||
228 | |||
226 | * device_api | 229 | * device_api |
227 | 230 | ||
228 | This attribute should show which device API is being created, for example, | 231 | This attribute should show which device API is being created, for example, |
@@ -394,5 +397,5 @@ References | |||
394 | 397 | ||
395 | [1] See Documentation/vfio.txt for more information on VFIO. | 398 | [1] See Documentation/vfio.txt for more information on VFIO. |
396 | [2] struct mdev_driver in include/linux/mdev.h | 399 | [2] struct mdev_driver in include/linux/mdev.h |
397 | [3] struct parent_ops in include/linux/mdev.h | 400 | [3] struct mdev_parent_ops in include/linux/mdev.h |
398 | [4] struct vfio_iommu_driver_ops in include/linux/vfio.h | 401 | [4] struct vfio_iommu_driver_ops in include/linux/vfio.h |
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 934963970288..faaae07ae487 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c | |||
@@ -169,7 +169,7 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu, | |||
169 | 169 | ||
170 | static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) | 170 | static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) |
171 | { | 171 | { |
172 | struct device *dev = &vgpu->vdev.mdev->dev; | 172 | struct device *dev = mdev_dev(vgpu->vdev.mdev); |
173 | struct gvt_dma *this; | 173 | struct gvt_dma *this; |
174 | unsigned long g1; | 174 | unsigned long g1; |
175 | int rc; | 175 | int rc; |
@@ -198,7 +198,7 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu) | |||
198 | { | 198 | { |
199 | struct gvt_dma *dma; | 199 | struct gvt_dma *dma; |
200 | struct rb_node *node = NULL; | 200 | struct rb_node *node = NULL; |
201 | struct device *dev = &vgpu->vdev.mdev->dev; | 201 | struct device *dev = mdev_dev(vgpu->vdev.mdev); |
202 | unsigned long gfn; | 202 | unsigned long gfn; |
203 | 203 | ||
204 | mutex_lock(&vgpu->vdev.cache_lock); | 204 | mutex_lock(&vgpu->vdev.cache_lock); |
@@ -399,7 +399,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) | |||
399 | struct device *pdev; | 399 | struct device *pdev; |
400 | void *gvt; | 400 | void *gvt; |
401 | 401 | ||
402 | pdev = mdev->parent->dev; | 402 | pdev = mdev_parent_dev(mdev); |
403 | gvt = kdev_to_i915(pdev)->gvt; | 403 | gvt = kdev_to_i915(pdev)->gvt; |
404 | 404 | ||
405 | type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); | 405 | type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); |
@@ -421,7 +421,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) | |||
421 | mdev_set_drvdata(mdev, vgpu); | 421 | mdev_set_drvdata(mdev, vgpu); |
422 | 422 | ||
423 | gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n", | 423 | gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n", |
424 | dev_name(&mdev->dev)); | 424 | dev_name(mdev_dev(mdev))); |
425 | return 0; | 425 | return 0; |
426 | } | 426 | } |
427 | 427 | ||
@@ -485,7 +485,7 @@ static int intel_vgpu_open(struct mdev_device *mdev) | |||
485 | vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier; | 485 | vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier; |
486 | 486 | ||
487 | events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; | 487 | events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; |
488 | ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events, | 488 | ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, &events, |
489 | &vgpu->vdev.iommu_notifier); | 489 | &vgpu->vdev.iommu_notifier); |
490 | if (ret != 0) { | 490 | if (ret != 0) { |
491 | gvt_err("vfio_register_notifier for iommu failed: %d\n", ret); | 491 | gvt_err("vfio_register_notifier for iommu failed: %d\n", ret); |
@@ -493,7 +493,7 @@ static int intel_vgpu_open(struct mdev_device *mdev) | |||
493 | } | 493 | } |
494 | 494 | ||
495 | events = VFIO_GROUP_NOTIFY_SET_KVM; | 495 | events = VFIO_GROUP_NOTIFY_SET_KVM; |
496 | ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events, | 496 | ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &events, |
497 | &vgpu->vdev.group_notifier); | 497 | &vgpu->vdev.group_notifier); |
498 | if (ret != 0) { | 498 | if (ret != 0) { |
499 | gvt_err("vfio_register_notifier for group failed: %d\n", ret); | 499 | gvt_err("vfio_register_notifier for group failed: %d\n", ret); |
@@ -508,11 +508,11 @@ static int intel_vgpu_open(struct mdev_device *mdev) | |||
508 | return ret; | 508 | return ret; |
509 | 509 | ||
510 | undo_group: | 510 | undo_group: |
511 | vfio_unregister_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, | 511 | vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, |
512 | &vgpu->vdev.group_notifier); | 512 | &vgpu->vdev.group_notifier); |
513 | 513 | ||
514 | undo_iommu: | 514 | undo_iommu: |
515 | vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, | 515 | vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, |
516 | &vgpu->vdev.iommu_notifier); | 516 | &vgpu->vdev.iommu_notifier); |
517 | out: | 517 | out: |
518 | return ret; | 518 | return ret; |
@@ -529,11 +529,11 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu) | |||
529 | if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1)) | 529 | if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1)) |
530 | return; | 530 | return; |
531 | 531 | ||
532 | ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY, | 532 | ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY, |
533 | &vgpu->vdev.iommu_notifier); | 533 | &vgpu->vdev.iommu_notifier); |
534 | WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret); | 534 | WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret); |
535 | 535 | ||
536 | ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY, | 536 | ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_GROUP_NOTIFY, |
537 | &vgpu->vdev.group_notifier); | 537 | &vgpu->vdev.group_notifier); |
538 | WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret); | 538 | WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret); |
539 | 539 | ||
@@ -1111,7 +1111,7 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | |||
1111 | return 0; | 1111 | return 0; |
1112 | } | 1112 | } |
1113 | 1113 | ||
1114 | static const struct parent_ops intel_vgpu_ops = { | 1114 | static const struct mdev_parent_ops intel_vgpu_ops = { |
1115 | .supported_type_groups = intel_vgpu_type_groups, | 1115 | .supported_type_groups = intel_vgpu_type_groups, |
1116 | .create = intel_vgpu_create, | 1116 | .create = intel_vgpu_create, |
1117 | .remove = intel_vgpu_remove, | 1117 | .remove = intel_vgpu_remove, |
@@ -1398,7 +1398,7 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) | |||
1398 | return pfn; | 1398 | return pfn; |
1399 | 1399 | ||
1400 | pfn = INTEL_GVT_INVALID_ADDR; | 1400 | pfn = INTEL_GVT_INVALID_ADDR; |
1401 | dev = &info->vgpu->vdev.mdev->dev; | 1401 | dev = mdev_dev(info->vgpu->vdev.mdev); |
1402 | rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn); | 1402 | rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn); |
1403 | if (rc != 1) { | 1403 | if (rc != 1) { |
1404 | gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc); | 1404 | gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc); |
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index be1ee89ee917..36d75c367d22 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c | |||
@@ -27,6 +27,45 @@ static LIST_HEAD(parent_list); | |||
27 | static DEFINE_MUTEX(parent_list_lock); | 27 | static DEFINE_MUTEX(parent_list_lock); |
28 | static struct class_compat *mdev_bus_compat_class; | 28 | static struct class_compat *mdev_bus_compat_class; |
29 | 29 | ||
30 | static LIST_HEAD(mdev_list); | ||
31 | static DEFINE_MUTEX(mdev_list_lock); | ||
32 | |||
33 | struct device *mdev_parent_dev(struct mdev_device *mdev) | ||
34 | { | ||
35 | return mdev->parent->dev; | ||
36 | } | ||
37 | EXPORT_SYMBOL(mdev_parent_dev); | ||
38 | |||
39 | void *mdev_get_drvdata(struct mdev_device *mdev) | ||
40 | { | ||
41 | return mdev->driver_data; | ||
42 | } | ||
43 | EXPORT_SYMBOL(mdev_get_drvdata); | ||
44 | |||
45 | void mdev_set_drvdata(struct mdev_device *mdev, void *data) | ||
46 | { | ||
47 | mdev->driver_data = data; | ||
48 | } | ||
49 | EXPORT_SYMBOL(mdev_set_drvdata); | ||
50 | |||
51 | struct device *mdev_dev(struct mdev_device *mdev) | ||
52 | { | ||
53 | return &mdev->dev; | ||
54 | } | ||
55 | EXPORT_SYMBOL(mdev_dev); | ||
56 | |||
57 | struct mdev_device *mdev_from_dev(struct device *dev) | ||
58 | { | ||
59 | return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL; | ||
60 | } | ||
61 | EXPORT_SYMBOL(mdev_from_dev); | ||
62 | |||
63 | uuid_le mdev_uuid(struct mdev_device *mdev) | ||
64 | { | ||
65 | return mdev->uuid; | ||
66 | } | ||
67 | EXPORT_SYMBOL(mdev_uuid); | ||
68 | |||
30 | static int _find_mdev_device(struct device *dev, void *data) | 69 | static int _find_mdev_device(struct device *dev, void *data) |
31 | { | 70 | { |
32 | struct mdev_device *mdev; | 71 | struct mdev_device *mdev; |
@@ -42,7 +81,7 @@ static int _find_mdev_device(struct device *dev, void *data) | |||
42 | return 0; | 81 | return 0; |
43 | } | 82 | } |
44 | 83 | ||
45 | static bool mdev_device_exist(struct parent_device *parent, uuid_le uuid) | 84 | static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) |
46 | { | 85 | { |
47 | struct device *dev; | 86 | struct device *dev; |
48 | 87 | ||
@@ -56,9 +95,9 @@ static bool mdev_device_exist(struct parent_device *parent, uuid_le uuid) | |||
56 | } | 95 | } |
57 | 96 | ||
58 | /* Should be called holding parent_list_lock */ | 97 | /* Should be called holding parent_list_lock */ |
59 | static struct parent_device *__find_parent_device(struct device *dev) | 98 | static struct mdev_parent *__find_parent_device(struct device *dev) |
60 | { | 99 | { |
61 | struct parent_device *parent; | 100 | struct mdev_parent *parent; |
62 | 101 | ||
63 | list_for_each_entry(parent, &parent_list, next) { | 102 | list_for_each_entry(parent, &parent_list, next) { |
64 | if (parent->dev == dev) | 103 | if (parent->dev == dev) |
@@ -69,8 +108,8 @@ static struct parent_device *__find_parent_device(struct device *dev) | |||
69 | 108 | ||
70 | static void mdev_release_parent(struct kref *kref) | 109 | static void mdev_release_parent(struct kref *kref) |
71 | { | 110 | { |
72 | struct parent_device *parent = container_of(kref, struct parent_device, | 111 | struct mdev_parent *parent = container_of(kref, struct mdev_parent, |
73 | ref); | 112 | ref); |
74 | struct device *dev = parent->dev; | 113 | struct device *dev = parent->dev; |
75 | 114 | ||
76 | kfree(parent); | 115 | kfree(parent); |
@@ -78,7 +117,7 @@ static void mdev_release_parent(struct kref *kref) | |||
78 | } | 117 | } |
79 | 118 | ||
80 | static | 119 | static |
81 | inline struct parent_device *mdev_get_parent(struct parent_device *parent) | 120 | inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent) |
82 | { | 121 | { |
83 | if (parent) | 122 | if (parent) |
84 | kref_get(&parent->ref); | 123 | kref_get(&parent->ref); |
@@ -86,7 +125,7 @@ inline struct parent_device *mdev_get_parent(struct parent_device *parent) | |||
86 | return parent; | 125 | return parent; |
87 | } | 126 | } |
88 | 127 | ||
89 | static inline void mdev_put_parent(struct parent_device *parent) | 128 | static inline void mdev_put_parent(struct mdev_parent *parent) |
90 | { | 129 | { |
91 | if (parent) | 130 | if (parent) |
92 | kref_put(&parent->ref, mdev_release_parent); | 131 | kref_put(&parent->ref, mdev_release_parent); |
@@ -95,7 +134,7 @@ static inline void mdev_put_parent(struct parent_device *parent) | |||
95 | static int mdev_device_create_ops(struct kobject *kobj, | 134 | static int mdev_device_create_ops(struct kobject *kobj, |
96 | struct mdev_device *mdev) | 135 | struct mdev_device *mdev) |
97 | { | 136 | { |
98 | struct parent_device *parent = mdev->parent; | 137 | struct mdev_parent *parent = mdev->parent; |
99 | int ret; | 138 | int ret; |
100 | 139 | ||
101 | ret = parent->ops->create(kobj, mdev); | 140 | ret = parent->ops->create(kobj, mdev); |
@@ -122,7 +161,7 @@ static int mdev_device_create_ops(struct kobject *kobj, | |||
122 | */ | 161 | */ |
123 | static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) | 162 | static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) |
124 | { | 163 | { |
125 | struct parent_device *parent = mdev->parent; | 164 | struct mdev_parent *parent = mdev->parent; |
126 | int ret; | 165 | int ret; |
127 | 166 | ||
128 | /* | 167 | /* |
@@ -153,10 +192,10 @@ static int mdev_device_remove_cb(struct device *dev, void *data) | |||
153 | * Add device to list of registered parent devices. | 192 | * Add device to list of registered parent devices. |
154 | * Returns a negative value on error, otherwise 0. | 193 | * Returns a negative value on error, otherwise 0. |
155 | */ | 194 | */ |
156 | int mdev_register_device(struct device *dev, const struct parent_ops *ops) | 195 | int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) |
157 | { | 196 | { |
158 | int ret; | 197 | int ret; |
159 | struct parent_device *parent; | 198 | struct mdev_parent *parent; |
160 | 199 | ||
161 | /* check for mandatory ops */ | 200 | /* check for mandatory ops */ |
162 | if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups) | 201 | if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups) |
@@ -229,7 +268,7 @@ EXPORT_SYMBOL(mdev_register_device); | |||
229 | 268 | ||
230 | void mdev_unregister_device(struct device *dev) | 269 | void mdev_unregister_device(struct device *dev) |
231 | { | 270 | { |
232 | struct parent_device *parent; | 271 | struct mdev_parent *parent; |
233 | bool force_remove = true; | 272 | bool force_remove = true; |
234 | 273 | ||
235 | mutex_lock(&parent_list_lock); | 274 | mutex_lock(&parent_list_lock); |
@@ -266,7 +305,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) | |||
266 | { | 305 | { |
267 | int ret; | 306 | int ret; |
268 | struct mdev_device *mdev; | 307 | struct mdev_device *mdev; |
269 | struct parent_device *parent; | 308 | struct mdev_parent *parent; |
270 | struct mdev_type *type = to_mdev_type(kobj); | 309 | struct mdev_type *type = to_mdev_type(kobj); |
271 | 310 | ||
272 | parent = mdev_get_parent(type->parent); | 311 | parent = mdev_get_parent(type->parent); |
@@ -316,6 +355,11 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) | |||
316 | dev_dbg(&mdev->dev, "MDEV: created\n"); | 355 | dev_dbg(&mdev->dev, "MDEV: created\n"); |
317 | 356 | ||
318 | mutex_unlock(&parent->lock); | 357 | mutex_unlock(&parent->lock); |
358 | |||
359 | mutex_lock(&mdev_list_lock); | ||
360 | list_add(&mdev->next, &mdev_list); | ||
361 | mutex_unlock(&mdev_list_lock); | ||
362 | |||
319 | return ret; | 363 | return ret; |
320 | 364 | ||
321 | create_failed: | 365 | create_failed: |
@@ -329,12 +373,30 @@ create_err: | |||
329 | 373 | ||
330 | int mdev_device_remove(struct device *dev, bool force_remove) | 374 | int mdev_device_remove(struct device *dev, bool force_remove) |
331 | { | 375 | { |
332 | struct mdev_device *mdev; | 376 | struct mdev_device *mdev, *tmp; |
333 | struct parent_device *parent; | 377 | struct mdev_parent *parent; |
334 | struct mdev_type *type; | 378 | struct mdev_type *type; |
335 | int ret; | 379 | int ret; |
380 | bool found = false; | ||
336 | 381 | ||
337 | mdev = to_mdev_device(dev); | 382 | mdev = to_mdev_device(dev); |
383 | |||
384 | mutex_lock(&mdev_list_lock); | ||
385 | list_for_each_entry(tmp, &mdev_list, next) { | ||
386 | if (tmp == mdev) { | ||
387 | found = true; | ||
388 | break; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | if (found) | ||
393 | list_del(&mdev->next); | ||
394 | |||
395 | mutex_unlock(&mdev_list_lock); | ||
396 | |||
397 | if (!found) | ||
398 | return -ENODEV; | ||
399 | |||
338 | type = to_mdev_type(mdev->type_kobj); | 400 | type = to_mdev_type(mdev->type_kobj); |
339 | parent = mdev->parent; | 401 | parent = mdev->parent; |
340 | mutex_lock(&parent->lock); | 402 | mutex_lock(&parent->lock); |
@@ -342,6 +404,11 @@ int mdev_device_remove(struct device *dev, bool force_remove) | |||
342 | ret = mdev_device_remove_ops(mdev, force_remove); | 404 | ret = mdev_device_remove_ops(mdev, force_remove); |
343 | if (ret) { | 405 | if (ret) { |
344 | mutex_unlock(&parent->lock); | 406 | mutex_unlock(&parent->lock); |
407 | |||
408 | mutex_lock(&mdev_list_lock); | ||
409 | list_add(&mdev->next, &mdev_list); | ||
410 | mutex_unlock(&mdev_list_lock); | ||
411 | |||
345 | return ret; | 412 | return ret; |
346 | } | 413 | } |
347 | 414 | ||
@@ -349,7 +416,8 @@ int mdev_device_remove(struct device *dev, bool force_remove) | |||
349 | device_unregister(dev); | 416 | device_unregister(dev); |
350 | mutex_unlock(&parent->lock); | 417 | mutex_unlock(&parent->lock); |
351 | mdev_put_parent(parent); | 418 | mdev_put_parent(parent); |
352 | return ret; | 419 | |
420 | return 0; | ||
353 | } | 421 | } |
354 | 422 | ||
355 | static int __init mdev_init(void) | 423 | static int __init mdev_init(void) |
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index d35097cbf3d7..a9cefd70a705 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h | |||
@@ -16,10 +16,33 @@ | |||
16 | int mdev_bus_register(void); | 16 | int mdev_bus_register(void); |
17 | void mdev_bus_unregister(void); | 17 | void mdev_bus_unregister(void); |
18 | 18 | ||
19 | struct mdev_parent { | ||
20 | struct device *dev; | ||
21 | const struct mdev_parent_ops *ops; | ||
22 | struct kref ref; | ||
23 | struct mutex lock; | ||
24 | struct list_head next; | ||
25 | struct kset *mdev_types_kset; | ||
26 | struct list_head type_list; | ||
27 | }; | ||
28 | |||
29 | struct mdev_device { | ||
30 | struct device dev; | ||
31 | struct mdev_parent *parent; | ||
32 | uuid_le uuid; | ||
33 | void *driver_data; | ||
34 | struct kref ref; | ||
35 | struct list_head next; | ||
36 | struct kobject *type_kobj; | ||
37 | }; | ||
38 | |||
39 | #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) | ||
40 | #define dev_is_mdev(d) ((d)->bus == &mdev_bus_type) | ||
41 | |||
19 | struct mdev_type { | 42 | struct mdev_type { |
20 | struct kobject kobj; | 43 | struct kobject kobj; |
21 | struct kobject *devices_kobj; | 44 | struct kobject *devices_kobj; |
22 | struct parent_device *parent; | 45 | struct mdev_parent *parent; |
23 | struct list_head next; | 46 | struct list_head next; |
24 | struct attribute_group *group; | 47 | struct attribute_group *group; |
25 | }; | 48 | }; |
@@ -29,8 +52,8 @@ struct mdev_type { | |||
29 | #define to_mdev_type(_kobj) \ | 52 | #define to_mdev_type(_kobj) \ |
30 | container_of(_kobj, struct mdev_type, kobj) | 53 | container_of(_kobj, struct mdev_type, kobj) |
31 | 54 | ||
32 | int parent_create_sysfs_files(struct parent_device *parent); | 55 | int parent_create_sysfs_files(struct mdev_parent *parent); |
33 | void parent_remove_sysfs_files(struct parent_device *parent); | 56 | void parent_remove_sysfs_files(struct mdev_parent *parent); |
34 | 57 | ||
35 | int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type); | 58 | int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type); |
36 | void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type); | 59 | void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type); |
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index 1a53deb2ee10..802df210929b 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c | |||
@@ -92,7 +92,7 @@ static struct kobj_type mdev_type_ktype = { | |||
92 | .release = mdev_type_release, | 92 | .release = mdev_type_release, |
93 | }; | 93 | }; |
94 | 94 | ||
95 | struct mdev_type *add_mdev_supported_type(struct parent_device *parent, | 95 | struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent, |
96 | struct attribute_group *group) | 96 | struct attribute_group *group) |
97 | { | 97 | { |
98 | struct mdev_type *type; | 98 | struct mdev_type *type; |
@@ -158,7 +158,7 @@ static void remove_mdev_supported_type(struct mdev_type *type) | |||
158 | kobject_put(&type->kobj); | 158 | kobject_put(&type->kobj); |
159 | } | 159 | } |
160 | 160 | ||
161 | static int add_mdev_supported_type_groups(struct parent_device *parent) | 161 | static int add_mdev_supported_type_groups(struct mdev_parent *parent) |
162 | { | 162 | { |
163 | int i; | 163 | int i; |
164 | 164 | ||
@@ -183,7 +183,7 @@ static int add_mdev_supported_type_groups(struct parent_device *parent) | |||
183 | } | 183 | } |
184 | 184 | ||
185 | /* mdev sysfs functions */ | 185 | /* mdev sysfs functions */ |
186 | void parent_remove_sysfs_files(struct parent_device *parent) | 186 | void parent_remove_sysfs_files(struct mdev_parent *parent) |
187 | { | 187 | { |
188 | struct mdev_type *type, *tmp; | 188 | struct mdev_type *type, *tmp; |
189 | 189 | ||
@@ -196,7 +196,7 @@ void parent_remove_sysfs_files(struct parent_device *parent) | |||
196 | kset_unregister(parent->mdev_types_kset); | 196 | kset_unregister(parent->mdev_types_kset); |
197 | } | 197 | } |
198 | 198 | ||
199 | int parent_create_sysfs_files(struct parent_device *parent) | 199 | int parent_create_sysfs_files(struct mdev_parent *parent) |
200 | { | 200 | { |
201 | int ret; | 201 | int ret; |
202 | 202 | ||
diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index ffc36758cb84..fa848a701b8b 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c | |||
@@ -27,7 +27,7 @@ | |||
27 | static int vfio_mdev_open(void *device_data) | 27 | static int vfio_mdev_open(void *device_data) |
28 | { | 28 | { |
29 | struct mdev_device *mdev = device_data; | 29 | struct mdev_device *mdev = device_data; |
30 | struct parent_device *parent = mdev->parent; | 30 | struct mdev_parent *parent = mdev->parent; |
31 | int ret; | 31 | int ret; |
32 | 32 | ||
33 | if (unlikely(!parent->ops->open)) | 33 | if (unlikely(!parent->ops->open)) |
@@ -46,7 +46,7 @@ static int vfio_mdev_open(void *device_data) | |||
46 | static void vfio_mdev_release(void *device_data) | 46 | static void vfio_mdev_release(void *device_data) |
47 | { | 47 | { |
48 | struct mdev_device *mdev = device_data; | 48 | struct mdev_device *mdev = device_data; |
49 | struct parent_device *parent = mdev->parent; | 49 | struct mdev_parent *parent = mdev->parent; |
50 | 50 | ||
51 | if (likely(parent->ops->release)) | 51 | if (likely(parent->ops->release)) |
52 | parent->ops->release(mdev); | 52 | parent->ops->release(mdev); |
@@ -58,7 +58,7 @@ static long vfio_mdev_unlocked_ioctl(void *device_data, | |||
58 | unsigned int cmd, unsigned long arg) | 58 | unsigned int cmd, unsigned long arg) |
59 | { | 59 | { |
60 | struct mdev_device *mdev = device_data; | 60 | struct mdev_device *mdev = device_data; |
61 | struct parent_device *parent = mdev->parent; | 61 | struct mdev_parent *parent = mdev->parent; |
62 | 62 | ||
63 | if (unlikely(!parent->ops->ioctl)) | 63 | if (unlikely(!parent->ops->ioctl)) |
64 | return -EINVAL; | 64 | return -EINVAL; |
@@ -70,7 +70,7 @@ static ssize_t vfio_mdev_read(void *device_data, char __user *buf, | |||
70 | size_t count, loff_t *ppos) | 70 | size_t count, loff_t *ppos) |
71 | { | 71 | { |
72 | struct mdev_device *mdev = device_data; | 72 | struct mdev_device *mdev = device_data; |
73 | struct parent_device *parent = mdev->parent; | 73 | struct mdev_parent *parent = mdev->parent; |
74 | 74 | ||
75 | if (unlikely(!parent->ops->read)) | 75 | if (unlikely(!parent->ops->read)) |
76 | return -EINVAL; | 76 | return -EINVAL; |
@@ -82,7 +82,7 @@ static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, | |||
82 | size_t count, loff_t *ppos) | 82 | size_t count, loff_t *ppos) |
83 | { | 83 | { |
84 | struct mdev_device *mdev = device_data; | 84 | struct mdev_device *mdev = device_data; |
85 | struct parent_device *parent = mdev->parent; | 85 | struct mdev_parent *parent = mdev->parent; |
86 | 86 | ||
87 | if (unlikely(!parent->ops->write)) | 87 | if (unlikely(!parent->ops->write)) |
88 | return -EINVAL; | 88 | return -EINVAL; |
@@ -93,7 +93,7 @@ static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, | |||
93 | static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) | 93 | static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) |
94 | { | 94 | { |
95 | struct mdev_device *mdev = device_data; | 95 | struct mdev_device *mdev = device_data; |
96 | struct parent_device *parent = mdev->parent; | 96 | struct mdev_parent *parent = mdev->parent; |
97 | 97 | ||
98 | if (unlikely(!parent->ops->mmap)) | 98 | if (unlikely(!parent->ops->mmap)) |
99 | return -EINVAL; | 99 | return -EINVAL; |
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index dcd7c2a99618..324c52e3a1a4 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c | |||
@@ -1142,6 +1142,10 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) | |||
1142 | return ret; | 1142 | return ret; |
1143 | 1143 | ||
1144 | vdev->barmap[index] = pci_iomap(pdev, index, 0); | 1144 | vdev->barmap[index] = pci_iomap(pdev, index, 0); |
1145 | if (!vdev->barmap[index]) { | ||
1146 | pci_release_selected_regions(pdev, 1 << index); | ||
1147 | return -ENOMEM; | ||
1148 | } | ||
1145 | } | 1149 | } |
1146 | 1150 | ||
1147 | vma->vm_private_data = vdev; | 1151 | vma->vm_private_data = vdev; |
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 5ffd1d9ad4bd..357243d76f10 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c | |||
@@ -193,7 +193,10 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf, | |||
193 | if (!vdev->has_vga) | 193 | if (!vdev->has_vga) |
194 | return -EINVAL; | 194 | return -EINVAL; |
195 | 195 | ||
196 | switch (pos) { | 196 | if (pos > 0xbfffful) |
197 | return -EINVAL; | ||
198 | |||
199 | switch ((u32)pos) { | ||
197 | case 0xa0000 ... 0xbffff: | 200 | case 0xa0000 ... 0xbffff: |
198 | count = min(count, (size_t)(0xc0000 - pos)); | 201 | count = min(count, (size_t)(0xc0000 - pos)); |
199 | iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1); | 202 | iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1); |
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index f3726ba12aa6..9266271a787a 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c | |||
@@ -268,28 +268,38 @@ static void vfio_lock_acct(struct task_struct *task, long npage) | |||
268 | { | 268 | { |
269 | struct vwork *vwork; | 269 | struct vwork *vwork; |
270 | struct mm_struct *mm; | 270 | struct mm_struct *mm; |
271 | bool is_current; | ||
271 | 272 | ||
272 | if (!npage) | 273 | if (!npage) |
273 | return; | 274 | return; |
274 | 275 | ||
275 | mm = get_task_mm(task); | 276 | is_current = (task->mm == current->mm); |
277 | |||
278 | mm = is_current ? task->mm : get_task_mm(task); | ||
276 | if (!mm) | 279 | if (!mm) |
277 | return; /* process exited or nothing to do */ | 280 | return; /* process exited */ |
278 | 281 | ||
279 | if (down_write_trylock(&mm->mmap_sem)) { | 282 | if (down_write_trylock(&mm->mmap_sem)) { |
280 | mm->locked_vm += npage; | 283 | mm->locked_vm += npage; |
281 | up_write(&mm->mmap_sem); | 284 | up_write(&mm->mmap_sem); |
282 | mmput(mm); | 285 | if (!is_current) |
286 | mmput(mm); | ||
283 | return; | 287 | return; |
284 | } | 288 | } |
285 | 289 | ||
290 | if (is_current) { | ||
291 | mm = get_task_mm(task); | ||
292 | if (!mm) | ||
293 | return; | ||
294 | } | ||
295 | |||
286 | /* | 296 | /* |
287 | * Couldn't get mmap_sem lock, so must setup to update | 297 | * Couldn't get mmap_sem lock, so must setup to update |
288 | * mm->locked_vm later. If locked_vm were atomic, we | 298 | * mm->locked_vm later. If locked_vm were atomic, we |
289 | * wouldn't need this silliness | 299 | * wouldn't need this silliness |
290 | */ | 300 | */ |
291 | vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL); | 301 | vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL); |
292 | if (!vwork) { | 302 | if (WARN_ON(!vwork)) { |
293 | mmput(mm); | 303 | mmput(mm); |
294 | return; | 304 | return; |
295 | } | 305 | } |
@@ -393,77 +403,71 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, | |||
393 | static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, | 403 | static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, |
394 | long npage, unsigned long *pfn_base) | 404 | long npage, unsigned long *pfn_base) |
395 | { | 405 | { |
396 | unsigned long limit; | 406 | unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; |
397 | bool lock_cap = ns_capable(task_active_pid_ns(dma->task)->user_ns, | 407 | bool lock_cap = capable(CAP_IPC_LOCK); |
398 | CAP_IPC_LOCK); | 408 | long ret, pinned = 0, lock_acct = 0; |
399 | struct mm_struct *mm; | ||
400 | long ret, i = 0, lock_acct = 0; | ||
401 | bool rsvd; | 409 | bool rsvd; |
402 | dma_addr_t iova = vaddr - dma->vaddr + dma->iova; | 410 | dma_addr_t iova = vaddr - dma->vaddr + dma->iova; |
403 | 411 | ||
404 | mm = get_task_mm(dma->task); | 412 | /* This code path is only user initiated */ |
405 | if (!mm) | 413 | if (!current->mm) |
406 | return -ENODEV; | 414 | return -ENODEV; |
407 | 415 | ||
408 | ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); | 416 | ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, pfn_base); |
409 | if (ret) | 417 | if (ret) |
410 | goto pin_pg_remote_exit; | 418 | return ret; |
411 | 419 | ||
420 | pinned++; | ||
412 | rsvd = is_invalid_reserved_pfn(*pfn_base); | 421 | rsvd = is_invalid_reserved_pfn(*pfn_base); |
413 | limit = task_rlimit(dma->task, RLIMIT_MEMLOCK) >> PAGE_SHIFT; | ||
414 | 422 | ||
415 | /* | 423 | /* |
416 | * Reserved pages aren't counted against the user, externally pinned | 424 | * Reserved pages aren't counted against the user, externally pinned |
417 | * pages are already counted against the user. | 425 | * pages are already counted against the user. |
418 | */ | 426 | */ |
419 | if (!rsvd && !vfio_find_vpfn(dma, iova)) { | 427 | if (!rsvd && !vfio_find_vpfn(dma, iova)) { |
420 | if (!lock_cap && mm->locked_vm + 1 > limit) { | 428 | if (!lock_cap && current->mm->locked_vm + 1 > limit) { |
421 | put_pfn(*pfn_base, dma->prot); | 429 | put_pfn(*pfn_base, dma->prot); |
422 | pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, | 430 | pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, |
423 | limit << PAGE_SHIFT); | 431 | limit << PAGE_SHIFT); |
424 | ret = -ENOMEM; | 432 | return -ENOMEM; |
425 | goto pin_pg_remote_exit; | ||
426 | } | 433 | } |
427 | lock_acct++; | 434 | lock_acct++; |
428 | } | 435 | } |
429 | 436 | ||
430 | i++; | 437 | if (unlikely(disable_hugepages)) |
431 | if (likely(!disable_hugepages)) { | 438 | goto out; |
432 | /* Lock all the consecutive pages from pfn_base */ | ||
433 | for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; i < npage; | ||
434 | i++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { | ||
435 | unsigned long pfn = 0; | ||
436 | 439 | ||
437 | ret = vaddr_get_pfn(mm, vaddr, dma->prot, &pfn); | 440 | /* Lock all the consecutive pages from pfn_base */ |
438 | if (ret) | 441 | for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage; |
439 | break; | 442 | pinned++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { |
443 | unsigned long pfn = 0; | ||
440 | 444 | ||
441 | if (pfn != *pfn_base + i || | 445 | ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, &pfn); |
442 | rsvd != is_invalid_reserved_pfn(pfn)) { | 446 | if (ret) |
447 | break; | ||
448 | |||
449 | if (pfn != *pfn_base + pinned || | ||
450 | rsvd != is_invalid_reserved_pfn(pfn)) { | ||
451 | put_pfn(pfn, dma->prot); | ||
452 | break; | ||
453 | } | ||
454 | |||
455 | if (!rsvd && !vfio_find_vpfn(dma, iova)) { | ||
456 | if (!lock_cap && | ||
457 | current->mm->locked_vm + lock_acct + 1 > limit) { | ||
443 | put_pfn(pfn, dma->prot); | 458 | put_pfn(pfn, dma->prot); |
459 | pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", | ||
460 | __func__, limit << PAGE_SHIFT); | ||
444 | break; | 461 | break; |
445 | } | 462 | } |
446 | 463 | lock_acct++; | |
447 | if (!rsvd && !vfio_find_vpfn(dma, iova)) { | ||
448 | if (!lock_cap && | ||
449 | mm->locked_vm + lock_acct + 1 > limit) { | ||
450 | put_pfn(pfn, dma->prot); | ||
451 | pr_warn("%s: RLIMIT_MEMLOCK (%ld) " | ||
452 | "exceeded\n", __func__, | ||
453 | limit << PAGE_SHIFT); | ||
454 | break; | ||
455 | } | ||
456 | lock_acct++; | ||
457 | } | ||
458 | } | 464 | } |
459 | } | 465 | } |
460 | 466 | ||
461 | vfio_lock_acct(dma->task, lock_acct); | 467 | out: |
462 | ret = i; | 468 | vfio_lock_acct(current, lock_acct); |
463 | 469 | ||
464 | pin_pg_remote_exit: | 470 | return pinned; |
465 | mmput(mm); | ||
466 | return ret; | ||
467 | } | 471 | } |
468 | 472 | ||
469 | static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, | 473 | static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, |
@@ -473,10 +477,10 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, | |||
473 | long unlocked = 0, locked = 0; | 477 | long unlocked = 0, locked = 0; |
474 | long i; | 478 | long i; |
475 | 479 | ||
476 | for (i = 0; i < npage; i++) { | 480 | for (i = 0; i < npage; i++, iova += PAGE_SIZE) { |
477 | if (put_pfn(pfn++, dma->prot)) { | 481 | if (put_pfn(pfn++, dma->prot)) { |
478 | unlocked++; | 482 | unlocked++; |
479 | if (vfio_find_vpfn(dma, iova + (i << PAGE_SHIFT))) | 483 | if (vfio_find_vpfn(dma, iova)) |
480 | locked++; | 484 | locked++; |
481 | } | 485 | } |
482 | } | 486 | } |
diff --git a/include/linux/mdev.h b/include/linux/mdev.h index ec819e9a115a..b6e048e1045f 100644 --- a/include/linux/mdev.h +++ b/include/linux/mdev.h | |||
@@ -13,34 +13,10 @@ | |||
13 | #ifndef MDEV_H | 13 | #ifndef MDEV_H |
14 | #define MDEV_H | 14 | #define MDEV_H |
15 | 15 | ||
16 | /* Parent device */ | 16 | struct mdev_device; |
17 | struct parent_device { | ||
18 | struct device *dev; | ||
19 | const struct parent_ops *ops; | ||
20 | |||
21 | /* internal */ | ||
22 | struct kref ref; | ||
23 | struct mutex lock; | ||
24 | struct list_head next; | ||
25 | struct kset *mdev_types_kset; | ||
26 | struct list_head type_list; | ||
27 | }; | ||
28 | |||
29 | /* Mediated device */ | ||
30 | struct mdev_device { | ||
31 | struct device dev; | ||
32 | struct parent_device *parent; | ||
33 | uuid_le uuid; | ||
34 | void *driver_data; | ||
35 | |||
36 | /* internal */ | ||
37 | struct kref ref; | ||
38 | struct list_head next; | ||
39 | struct kobject *type_kobj; | ||
40 | }; | ||
41 | 17 | ||
42 | /** | 18 | /** |
43 | * struct parent_ops - Structure to be registered for each parent device to | 19 | * struct mdev_parent_ops - Structure to be registered for each parent device to |
44 | * register the device to mdev module. | 20 | * register the device to mdev module. |
45 | * | 21 | * |
46 | * @owner: The module owner. | 22 | * @owner: The module owner. |
@@ -86,10 +62,9 @@ struct mdev_device { | |||
86 | * @mdev: mediated device structure | 62 | * @mdev: mediated device structure |
87 | * @vma: vma structure | 63 | * @vma: vma structure |
88 | * Parent device that support mediated device should be registered with mdev | 64 | * Parent device that support mediated device should be registered with mdev |
89 | * module with parent_ops structure. | 65 | * module with mdev_parent_ops structure. |
90 | **/ | 66 | **/ |
91 | 67 | struct mdev_parent_ops { | |
92 | struct parent_ops { | ||
93 | struct module *owner; | 68 | struct module *owner; |
94 | const struct attribute_group **dev_attr_groups; | 69 | const struct attribute_group **dev_attr_groups; |
95 | const struct attribute_group **mdev_attr_groups; | 70 | const struct attribute_group **mdev_attr_groups; |
@@ -103,7 +78,7 @@ struct parent_ops { | |||
103 | size_t count, loff_t *ppos); | 78 | size_t count, loff_t *ppos); |
104 | ssize_t (*write)(struct mdev_device *mdev, const char __user *buf, | 79 | ssize_t (*write)(struct mdev_device *mdev, const char __user *buf, |
105 | size_t count, loff_t *ppos); | 80 | size_t count, loff_t *ppos); |
106 | ssize_t (*ioctl)(struct mdev_device *mdev, unsigned int cmd, | 81 | long (*ioctl)(struct mdev_device *mdev, unsigned int cmd, |
107 | unsigned long arg); | 82 | unsigned long arg); |
108 | int (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma); | 83 | int (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma); |
109 | }; | 84 | }; |
@@ -142,27 +117,22 @@ struct mdev_driver { | |||
142 | }; | 117 | }; |
143 | 118 | ||
144 | #define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver) | 119 | #define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver) |
145 | #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) | ||
146 | |||
147 | static inline void *mdev_get_drvdata(struct mdev_device *mdev) | ||
148 | { | ||
149 | return mdev->driver_data; | ||
150 | } | ||
151 | 120 | ||
152 | static inline void mdev_set_drvdata(struct mdev_device *mdev, void *data) | 121 | extern void *mdev_get_drvdata(struct mdev_device *mdev); |
153 | { | 122 | extern void mdev_set_drvdata(struct mdev_device *mdev, void *data); |
154 | mdev->driver_data = data; | 123 | extern uuid_le mdev_uuid(struct mdev_device *mdev); |
155 | } | ||
156 | 124 | ||
157 | extern struct bus_type mdev_bus_type; | 125 | extern struct bus_type mdev_bus_type; |
158 | 126 | ||
159 | #define dev_is_mdev(d) ((d)->bus == &mdev_bus_type) | ||
160 | |||
161 | extern int mdev_register_device(struct device *dev, | 127 | extern int mdev_register_device(struct device *dev, |
162 | const struct parent_ops *ops); | 128 | const struct mdev_parent_ops *ops); |
163 | extern void mdev_unregister_device(struct device *dev); | 129 | extern void mdev_unregister_device(struct device *dev); |
164 | 130 | ||
165 | extern int mdev_register_driver(struct mdev_driver *drv, struct module *owner); | 131 | extern int mdev_register_driver(struct mdev_driver *drv, struct module *owner); |
166 | extern void mdev_unregister_driver(struct mdev_driver *drv); | 132 | extern void mdev_unregister_driver(struct mdev_driver *drv); |
167 | 133 | ||
134 | extern struct device *mdev_parent_dev(struct mdev_device *mdev); | ||
135 | extern struct device *mdev_dev(struct mdev_device *mdev); | ||
136 | extern struct mdev_device *mdev_from_dev(struct device *dev); | ||
137 | |||
168 | #endif /* MDEV_H */ | 138 | #endif /* MDEV_H */ |
diff --git a/samples/Kconfig b/samples/Kconfig index a6d2a43bbf2e..b124f62ed6cb 100644 --- a/samples/Kconfig +++ b/samples/Kconfig | |||
@@ -105,4 +105,11 @@ config SAMPLE_BLACKFIN_GPTIMERS | |||
105 | help | 105 | help |
106 | Build samples of blackfin gptimers sample module. | 106 | Build samples of blackfin gptimers sample module. |
107 | 107 | ||
108 | config SAMPLE_VFIO_MDEV_MTTY | ||
109 | tristate "Build VFIO mtty example mediated device sample code -- loadable modules only" | ||
110 | depends on VFIO_MDEV_DEVICE && m | ||
111 | help | ||
112 | Build a virtual tty sample driver for use as a VFIO | ||
113 | mediated device | ||
114 | |||
108 | endif # SAMPLES | 115 | endif # SAMPLES |
diff --git a/samples/Makefile b/samples/Makefile index e17d66d77f09..86a137e451d9 100644 --- a/samples/Makefile +++ b/samples/Makefile | |||
@@ -2,4 +2,5 @@ | |||
2 | 2 | ||
3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ | 3 | obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ |
4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ | 4 | hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ |
5 | configfs/ connector/ v4l/ trace_printk/ blackfin/ | 5 | configfs/ connector/ v4l/ trace_printk/ blackfin/ \ |
6 | vfio-mdev/ | ||
diff --git a/samples/vfio-mdev/Makefile b/samples/vfio-mdev/Makefile index a932edbe38eb..cbbd868a50a8 100644 --- a/samples/vfio-mdev/Makefile +++ b/samples/vfio-mdev/Makefile | |||
@@ -1,13 +1 @@ | |||
1 | # | obj-$(CONFIG_SAMPLE_VFIO_MDEV_MTTY) += mtty.o | |
2 | # Makefile for mtty.c file | ||
3 | # | ||
4 | KERNEL_DIR:=/lib/modules/$(shell uname -r)/build | ||
5 | |||
6 | obj-m:=mtty.o | ||
7 | |||
8 | modules clean modules_install: | ||
9 | $(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) $@ | ||
10 | |||
11 | default: modules | ||
12 | |||
13 | module: modules | ||
diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index 6b633a4ea333..1fc57a5093a7 100644 --- a/samples/vfio-mdev/mtty.c +++ b/samples/vfio-mdev/mtty.c | |||
@@ -164,7 +164,7 @@ static struct mdev_state *find_mdev_state_by_uuid(uuid_le uuid) | |||
164 | struct mdev_state *mds; | 164 | struct mdev_state *mds; |
165 | 165 | ||
166 | list_for_each_entry(mds, &mdev_devices_list, next) { | 166 | list_for_each_entry(mds, &mdev_devices_list, next) { |
167 | if (uuid_le_cmp(mds->mdev->uuid, uuid) == 0) | 167 | if (uuid_le_cmp(mdev_uuid(mds->mdev), uuid) == 0) |
168 | return mds; | 168 | return mds; |
169 | } | 169 | } |
170 | 170 | ||
@@ -341,7 +341,8 @@ static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, | |||
341 | pr_err("Serial port %d: Fifo level trigger\n", | 341 | pr_err("Serial port %d: Fifo level trigger\n", |
342 | index); | 342 | index); |
343 | #endif | 343 | #endif |
344 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 344 | mtty_trigger_interrupt( |
345 | mdev_uuid(mdev_state->mdev)); | ||
345 | } | 346 | } |
346 | } else { | 347 | } else { |
347 | #if defined(DEBUG_INTR) | 348 | #if defined(DEBUG_INTR) |
@@ -355,7 +356,8 @@ static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, | |||
355 | */ | 356 | */ |
356 | if (mdev_state->s[index].uart_reg[UART_IER] & | 357 | if (mdev_state->s[index].uart_reg[UART_IER] & |
357 | UART_IER_RLSI) | 358 | UART_IER_RLSI) |
358 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 359 | mtty_trigger_interrupt( |
360 | mdev_uuid(mdev_state->mdev)); | ||
359 | } | 361 | } |
360 | mutex_unlock(&mdev_state->rxtx_lock); | 362 | mutex_unlock(&mdev_state->rxtx_lock); |
361 | break; | 363 | break; |
@@ -374,7 +376,8 @@ static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, | |||
374 | pr_err("Serial port %d: IER_THRI write\n", | 376 | pr_err("Serial port %d: IER_THRI write\n", |
375 | index); | 377 | index); |
376 | #endif | 378 | #endif |
377 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 379 | mtty_trigger_interrupt( |
380 | mdev_uuid(mdev_state->mdev)); | ||
378 | } | 381 | } |
379 | 382 | ||
380 | mutex_unlock(&mdev_state->rxtx_lock); | 383 | mutex_unlock(&mdev_state->rxtx_lock); |
@@ -445,7 +448,7 @@ static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, | |||
445 | #if defined(DEBUG_INTR) | 448 | #if defined(DEBUG_INTR) |
446 | pr_err("Serial port %d: MCR_OUT2 write\n", index); | 449 | pr_err("Serial port %d: MCR_OUT2 write\n", index); |
447 | #endif | 450 | #endif |
448 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 451 | mtty_trigger_interrupt(mdev_uuid(mdev_state->mdev)); |
449 | } | 452 | } |
450 | 453 | ||
451 | if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && | 454 | if ((mdev_state->s[index].uart_reg[UART_IER] & UART_IER_MSI) && |
@@ -453,7 +456,7 @@ static void handle_bar_write(unsigned int index, struct mdev_state *mdev_state, | |||
453 | #if defined(DEBUG_INTR) | 456 | #if defined(DEBUG_INTR) |
454 | pr_err("Serial port %d: MCR RTS/DTR write\n", index); | 457 | pr_err("Serial port %d: MCR RTS/DTR write\n", index); |
455 | #endif | 458 | #endif |
456 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 459 | mtty_trigger_interrupt(mdev_uuid(mdev_state->mdev)); |
457 | } | 460 | } |
458 | break; | 461 | break; |
459 | 462 | ||
@@ -504,7 +507,8 @@ static void handle_bar_read(unsigned int index, struct mdev_state *mdev_state, | |||
504 | #endif | 507 | #endif |
505 | if (mdev_state->s[index].uart_reg[UART_IER] & | 508 | if (mdev_state->s[index].uart_reg[UART_IER] & |
506 | UART_IER_THRI) | 509 | UART_IER_THRI) |
507 | mtty_trigger_interrupt(mdev_state->mdev->uuid); | 510 | mtty_trigger_interrupt( |
511 | mdev_uuid(mdev_state->mdev)); | ||
508 | } | 512 | } |
509 | mutex_unlock(&mdev_state->rxtx_lock); | 513 | mutex_unlock(&mdev_state->rxtx_lock); |
510 | 514 | ||
@@ -734,7 +738,7 @@ int mtty_create(struct kobject *kobj, struct mdev_device *mdev) | |||
734 | 738 | ||
735 | for (i = 0; i < 2; i++) { | 739 | for (i = 0; i < 2; i++) { |
736 | snprintf(name, MTTY_STRING_LEN, "%s-%d", | 740 | snprintf(name, MTTY_STRING_LEN, "%s-%d", |
737 | dev_driver_string(mdev->parent->dev), i + 1); | 741 | dev_driver_string(mdev_parent_dev(mdev)), i + 1); |
738 | if (!strcmp(kobj->name, name)) { | 742 | if (!strcmp(kobj->name, name)) { |
739 | nr_ports = i + 1; | 743 | nr_ports = i + 1; |
740 | break; | 744 | break; |
@@ -1298,10 +1302,8 @@ static ssize_t | |||
1298 | sample_mdev_dev_show(struct device *dev, struct device_attribute *attr, | 1302 | sample_mdev_dev_show(struct device *dev, struct device_attribute *attr, |
1299 | char *buf) | 1303 | char *buf) |
1300 | { | 1304 | { |
1301 | struct mdev_device *mdev = to_mdev_device(dev); | 1305 | if (mdev_from_dev(dev)) |
1302 | 1306 | return sprintf(buf, "This is MDEV %s\n", dev_name(dev)); | |
1303 | if (mdev) | ||
1304 | return sprintf(buf, "This is MDEV %s\n", dev_name(&mdev->dev)); | ||
1305 | 1307 | ||
1306 | return sprintf(buf, "\n"); | 1308 | return sprintf(buf, "\n"); |
1307 | } | 1309 | } |
@@ -1402,7 +1404,7 @@ struct attribute_group *mdev_type_groups[] = { | |||
1402 | NULL, | 1404 | NULL, |
1403 | }; | 1405 | }; |
1404 | 1406 | ||
1405 | struct parent_ops mdev_fops = { | 1407 | struct mdev_parent_ops mdev_fops = { |
1406 | .owner = THIS_MODULE, | 1408 | .owner = THIS_MODULE, |
1407 | .dev_attr_groups = mtty_dev_groups, | 1409 | .dev_attr_groups = mtty_dev_groups, |
1408 | .mdev_attr_groups = mdev_dev_groups, | 1410 | .mdev_attr_groups = mdev_dev_groups, |
@@ -1447,6 +1449,7 @@ static int __init mtty_dev_init(void) | |||
1447 | 1449 | ||
1448 | if (IS_ERR(mtty_dev.vd_class)) { | 1450 | if (IS_ERR(mtty_dev.vd_class)) { |
1449 | pr_err("Error: failed to register mtty_dev class\n"); | 1451 | pr_err("Error: failed to register mtty_dev class\n"); |
1452 | ret = PTR_ERR(mtty_dev.vd_class); | ||
1450 | goto failed1; | 1453 | goto failed1; |
1451 | } | 1454 | } |
1452 | 1455 | ||
@@ -1458,7 +1461,8 @@ static int __init mtty_dev_init(void) | |||
1458 | if (ret) | 1461 | if (ret) |
1459 | goto failed2; | 1462 | goto failed2; |
1460 | 1463 | ||
1461 | if (mdev_register_device(&mtty_dev.dev, &mdev_fops) != 0) | 1464 | ret = mdev_register_device(&mtty_dev.dev, &mdev_fops); |
1465 | if (ret) | ||
1462 | goto failed3; | 1466 | goto failed3; |
1463 | 1467 | ||
1464 | mutex_init(&mdev_list_lock); | 1468 | mutex_init(&mdev_list_lock); |