diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-17 19:47:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-17 19:47:31 -0500 |
commit | 0f484e42baaf5a38fc79e99b917caa5431651fb1 (patch) | |
tree | d78ade37253f823be49a0bc649352753dc67540f | |
parent | af79ce47efabba36d1db0902d46a80de7f251411 (diff) | |
parent | 659643f7d81432189c2c87230e2feee4c75c14c1 (diff) |
Merge tag 'kvmgt-vfio-mdev-for-v4.10-rc1' of git://github.com/01org/gvt-linux
Pull i915/gvt KVMGT updates from Zhenyu Wang:
"KVMGT support depending on the VFIO/mdev framework"
* tag 'kvmgt-vfio-mdev-for-v4.10-rc1' of git://github.com/01org/gvt-linux:
drm/i915/gvt/kvmgt: add vfio/mdev support to KVMGT
drm/i915/gvt/kvmgt: read/write GPA via KVM API
drm/i915/gvt/kvmgt: replace kmalloc() by kzalloc()
-rw-r--r-- | drivers/gpu/drm/i915/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/gvt/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/gvt/gvt.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/gvt/kvmgt.c | 975 |
4 files changed, 923 insertions, 61 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 5ddde7349fbd..183f5dc1c3f2 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig | |||
@@ -116,6 +116,7 @@ config DRM_I915_GVT_KVMGT | |||
116 | tristate "Enable KVM/VFIO support for Intel GVT-g" | 116 | tristate "Enable KVM/VFIO support for Intel GVT-g" |
117 | depends on DRM_I915_GVT | 117 | depends on DRM_I915_GVT |
118 | depends on KVM | 118 | depends on KVM |
119 | depends on VFIO_MDEV && VFIO_MDEV_DEVICE | ||
119 | default n | 120 | default n |
120 | help | 121 | help |
121 | Choose this option if you want to enable KVMGT support for | 122 | Choose this option if you want to enable KVMGT support for |
diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile index 8a46a7f31d53..b123c20e2097 100644 --- a/drivers/gpu/drm/i915/gvt/Makefile +++ b/drivers/gpu/drm/i915/gvt/Makefile | |||
@@ -5,6 +5,4 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \ | |||
5 | 5 | ||
6 | ccflags-y += -I$(src) -I$(src)/$(GVT_DIR) -Wall | 6 | ccflags-y += -I$(src) -I$(src)/$(GVT_DIR) -Wall |
7 | i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE)) | 7 | i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE)) |
8 | |||
9 | CFLAGS_kvmgt.o := -Wno-unused-function | ||
10 | obj-$(CONFIG_DRM_I915_GVT_KVMGT) += $(GVT_DIR)/kvmgt.o | 8 | obj-$(CONFIG_DRM_I915_GVT_KVMGT) += $(GVT_DIR)/kvmgt.o |
diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index b1a7c8dd4b5f..ad0e9364ee70 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h | |||
@@ -164,15 +164,17 @@ struct intel_vgpu { | |||
164 | 164 | ||
165 | #if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT) | 165 | #if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT) |
166 | struct { | 166 | struct { |
167 | struct device *mdev; | 167 | struct mdev_device *mdev; |
168 | struct vfio_region *region; | 168 | struct vfio_region *region; |
169 | int num_regions; | 169 | int num_regions; |
170 | struct eventfd_ctx *intx_trigger; | 170 | struct eventfd_ctx *intx_trigger; |
171 | struct eventfd_ctx *msi_trigger; | 171 | struct eventfd_ctx *msi_trigger; |
172 | struct rb_root cache; | 172 | struct rb_root cache; |
173 | struct mutex cache_lock; | 173 | struct mutex cache_lock; |
174 | void *vfio_group; | ||
175 | struct notifier_block iommu_notifier; | 174 | struct notifier_block iommu_notifier; |
175 | struct notifier_block group_notifier; | ||
176 | struct kvm *kvm; | ||
177 | struct work_struct release_work; | ||
176 | } vdev; | 178 | } vdev; |
177 | #endif | 179 | #endif |
178 | }; | 180 | }; |
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index dc0365033157..4dd6722a7339 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/device.h> | 32 | #include <linux/device.h> |
33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
34 | #include <linux/mmu_context.h> | ||
34 | #include <linux/types.h> | 35 | #include <linux/types.h> |
35 | #include <linux/list.h> | 36 | #include <linux/list.h> |
36 | #include <linux/rbtree.h> | 37 | #include <linux/rbtree.h> |
@@ -39,24 +40,13 @@ | |||
39 | #include <linux/uuid.h> | 40 | #include <linux/uuid.h> |
40 | #include <linux/kvm_host.h> | 41 | #include <linux/kvm_host.h> |
41 | #include <linux/vfio.h> | 42 | #include <linux/vfio.h> |
43 | #include <linux/mdev.h> | ||
42 | 44 | ||
43 | #include "i915_drv.h" | 45 | #include "i915_drv.h" |
44 | #include "gvt.h" | 46 | #include "gvt.h" |
45 | 47 | ||
46 | static inline long kvmgt_pin_pages(struct device *dev, unsigned long *user_pfn, | ||
47 | long npage, int prot, unsigned long *phys_pfn) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | static inline long kvmgt_unpin_pages(struct device *dev, unsigned long *pfn, | ||
52 | long npage) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static const struct intel_gvt_ops *intel_gvt_ops; | 48 | static const struct intel_gvt_ops *intel_gvt_ops; |
58 | 49 | ||
59 | |||
60 | /* helper macros copied from vfio-pci */ | 50 | /* helper macros copied from vfio-pci */ |
61 | #define VFIO_PCI_OFFSET_SHIFT 40 | 51 | #define VFIO_PCI_OFFSET_SHIFT 40 |
62 | #define VFIO_PCI_OFFSET_TO_INDEX(off) (off >> VFIO_PCI_OFFSET_SHIFT) | 52 | #define VFIO_PCI_OFFSET_TO_INDEX(off) (off >> VFIO_PCI_OFFSET_SHIFT) |
@@ -90,6 +80,15 @@ struct gvt_dma { | |||
90 | kvm_pfn_t pfn; | 80 | kvm_pfn_t pfn; |
91 | }; | 81 | }; |
92 | 82 | ||
83 | static inline bool handle_valid(unsigned long handle) | ||
84 | { | ||
85 | return !!(handle & ~0xff); | ||
86 | } | ||
87 | |||
88 | static int kvmgt_guest_init(struct mdev_device *mdev); | ||
89 | static void intel_vgpu_release_work(struct work_struct *work); | ||
90 | static bool kvmgt_guest_exit(struct kvmgt_guest_info *info); | ||
91 | |||
93 | static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn) | 92 | static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn) |
94 | { | 93 | { |
95 | struct rb_node *node = vgpu->vdev.cache.rb_node; | 94 | struct rb_node *node = vgpu->vdev.cache.rb_node; |
@@ -167,9 +166,10 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu, | |||
167 | 166 | ||
168 | static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) | 167 | static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) |
169 | { | 168 | { |
170 | struct device *dev = vgpu->vdev.mdev; | 169 | struct device *dev = &vgpu->vdev.mdev->dev; |
171 | struct gvt_dma *this; | 170 | struct gvt_dma *this; |
172 | unsigned long pfn; | 171 | unsigned long g1; |
172 | int rc; | ||
173 | 173 | ||
174 | mutex_lock(&vgpu->vdev.cache_lock); | 174 | mutex_lock(&vgpu->vdev.cache_lock); |
175 | this = __gvt_cache_find(vgpu, gfn); | 175 | this = __gvt_cache_find(vgpu, gfn); |
@@ -178,8 +178,9 @@ static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) | |||
178 | return; | 178 | return; |
179 | } | 179 | } |
180 | 180 | ||
181 | pfn = this->pfn; | 181 | g1 = gfn; |
182 | WARN_ON((kvmgt_unpin_pages(dev, &pfn, 1) != 1)); | 182 | rc = vfio_unpin_pages(dev, &g1, 1); |
183 | WARN_ON(rc != 1); | ||
183 | __gvt_cache_remove_entry(vgpu, this); | 184 | __gvt_cache_remove_entry(vgpu, this); |
184 | mutex_unlock(&vgpu->vdev.cache_lock); | 185 | mutex_unlock(&vgpu->vdev.cache_lock); |
185 | } | 186 | } |
@@ -194,15 +195,15 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu) | |||
194 | { | 195 | { |
195 | struct gvt_dma *dma; | 196 | struct gvt_dma *dma; |
196 | struct rb_node *node = NULL; | 197 | struct rb_node *node = NULL; |
197 | struct device *dev = vgpu->vdev.mdev; | 198 | struct device *dev = &vgpu->vdev.mdev->dev; |
198 | unsigned long pfn; | 199 | unsigned long gfn; |
199 | 200 | ||
200 | mutex_lock(&vgpu->vdev.cache_lock); | 201 | mutex_lock(&vgpu->vdev.cache_lock); |
201 | while ((node = rb_first(&vgpu->vdev.cache))) { | 202 | while ((node = rb_first(&vgpu->vdev.cache))) { |
202 | dma = rb_entry(node, struct gvt_dma, node); | 203 | dma = rb_entry(node, struct gvt_dma, node); |
203 | pfn = dma->pfn; | 204 | gfn = dma->gfn; |
204 | 205 | ||
205 | kvmgt_unpin_pages(dev, &pfn, 1); | 206 | vfio_unpin_pages(dev, &gfn, 1); |
206 | __gvt_cache_remove_entry(vgpu, dma); | 207 | __gvt_cache_remove_entry(vgpu, dma); |
207 | } | 208 | } |
208 | mutex_unlock(&vgpu->vdev.cache_lock); | 209 | mutex_unlock(&vgpu->vdev.cache_lock); |
@@ -226,7 +227,53 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt, | |||
226 | return NULL; | 227 | return NULL; |
227 | } | 228 | } |
228 | 229 | ||
230 | static ssize_t available_instance_show(struct kobject *kobj, struct device *dev, | ||
231 | char *buf) | ||
232 | { | ||
233 | struct intel_vgpu_type *type; | ||
234 | unsigned int num = 0; | ||
235 | void *gvt = kdev_to_i915(dev)->gvt; | ||
236 | |||
237 | type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); | ||
238 | if (!type) | ||
239 | num = 0; | ||
240 | else | ||
241 | num = type->avail_instance; | ||
242 | |||
243 | return sprintf(buf, "%u\n", num); | ||
244 | } | ||
245 | |||
246 | static ssize_t device_api_show(struct kobject *kobj, struct device *dev, | ||
247 | char *buf) | ||
248 | { | ||
249 | return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING); | ||
250 | } | ||
251 | |||
252 | static ssize_t description_show(struct kobject *kobj, struct device *dev, | ||
253 | char *buf) | ||
254 | { | ||
255 | struct intel_vgpu_type *type; | ||
256 | void *gvt = kdev_to_i915(dev)->gvt; | ||
257 | |||
258 | type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); | ||
259 | if (!type) | ||
260 | return 0; | ||
261 | |||
262 | return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n" | ||
263 | "fence: %d\n", | ||
264 | BYTES_TO_MB(type->low_gm_size), | ||
265 | BYTES_TO_MB(type->high_gm_size), | ||
266 | type->fence); | ||
267 | } | ||
268 | |||
269 | static MDEV_TYPE_ATTR_RO(available_instance); | ||
270 | static MDEV_TYPE_ATTR_RO(device_api); | ||
271 | static MDEV_TYPE_ATTR_RO(description); | ||
272 | |||
229 | static struct attribute *type_attrs[] = { | 273 | static struct attribute *type_attrs[] = { |
274 | &mdev_type_attr_available_instance.attr, | ||
275 | &mdev_type_attr_device_api.attr, | ||
276 | &mdev_type_attr_description.attr, | ||
230 | NULL, | 277 | NULL, |
231 | }; | 278 | }; |
232 | 279 | ||
@@ -322,7 +369,7 @@ static void kvmgt_protect_table_add(struct kvmgt_guest_info *info, gfn_t gfn) | |||
322 | if (kvmgt_gfn_is_write_protected(info, gfn)) | 369 | if (kvmgt_gfn_is_write_protected(info, gfn)) |
323 | return; | 370 | return; |
324 | 371 | ||
325 | p = kmalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC); | 372 | p = kzalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC); |
326 | if (WARN(!p, "gfn: 0x%llx\n", gfn)) | 373 | if (WARN(!p, "gfn: 0x%llx\n", gfn)) |
327 | return; | 374 | return; |
328 | 375 | ||
@@ -342,6 +389,720 @@ static void kvmgt_protect_table_del(struct kvmgt_guest_info *info, | |||
342 | } | 389 | } |
343 | } | 390 | } |
344 | 391 | ||
392 | static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) | ||
393 | { | ||
394 | struct intel_vgpu *vgpu; | ||
395 | struct intel_vgpu_type *type; | ||
396 | struct device *pdev; | ||
397 | void *gvt; | ||
398 | |||
399 | pdev = mdev->parent->dev; | ||
400 | gvt = kdev_to_i915(pdev)->gvt; | ||
401 | |||
402 | type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); | ||
403 | if (!type) { | ||
404 | gvt_err("failed to find type %s to create\n", | ||
405 | kobject_name(kobj)); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | |||
409 | vgpu = intel_gvt_ops->vgpu_create(gvt, type); | ||
410 | if (IS_ERR_OR_NULL(vgpu)) { | ||
411 | gvt_err("create intel vgpu failed\n"); | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work); | ||
416 | |||
417 | vgpu->vdev.mdev = mdev; | ||
418 | mdev_set_drvdata(mdev, vgpu); | ||
419 | |||
420 | gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n", | ||
421 | dev_name(&mdev->dev)); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int intel_vgpu_remove(struct mdev_device *mdev) | ||
426 | { | ||
427 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
428 | |||
429 | if (handle_valid(vgpu->handle)) | ||
430 | return -EBUSY; | ||
431 | |||
432 | intel_gvt_ops->vgpu_destroy(vgpu); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int intel_vgpu_iommu_notifier(struct notifier_block *nb, | ||
437 | unsigned long action, void *data) | ||
438 | { | ||
439 | struct intel_vgpu *vgpu = container_of(nb, | ||
440 | struct intel_vgpu, | ||
441 | vdev.iommu_notifier); | ||
442 | |||
443 | if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { | ||
444 | struct vfio_iommu_type1_dma_unmap *unmap = data; | ||
445 | unsigned long gfn, end_gfn; | ||
446 | |||
447 | gfn = unmap->iova >> PAGE_SHIFT; | ||
448 | end_gfn = gfn + unmap->size / PAGE_SIZE; | ||
449 | |||
450 | while (gfn < end_gfn) | ||
451 | gvt_cache_remove(vgpu, gfn++); | ||
452 | } | ||
453 | |||
454 | return NOTIFY_OK; | ||
455 | } | ||
456 | |||
457 | static int intel_vgpu_group_notifier(struct notifier_block *nb, | ||
458 | unsigned long action, void *data) | ||
459 | { | ||
460 | struct intel_vgpu *vgpu = container_of(nb, | ||
461 | struct intel_vgpu, | ||
462 | vdev.group_notifier); | ||
463 | |||
464 | /* the only action we care about */ | ||
465 | if (action == VFIO_GROUP_NOTIFY_SET_KVM) { | ||
466 | vgpu->vdev.kvm = data; | ||
467 | |||
468 | if (!data) | ||
469 | schedule_work(&vgpu->vdev.release_work); | ||
470 | } | ||
471 | |||
472 | return NOTIFY_OK; | ||
473 | } | ||
474 | |||
475 | static int intel_vgpu_open(struct mdev_device *mdev) | ||
476 | { | ||
477 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
478 | unsigned long events; | ||
479 | int ret; | ||
480 | |||
481 | vgpu->vdev.iommu_notifier.notifier_call = intel_vgpu_iommu_notifier; | ||
482 | vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier; | ||
483 | |||
484 | events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; | ||
485 | ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events, | ||
486 | &vgpu->vdev.iommu_notifier); | ||
487 | if (ret != 0) { | ||
488 | gvt_err("vfio_register_notifier for iommu failed: %d\n", ret); | ||
489 | goto out; | ||
490 | } | ||
491 | |||
492 | events = VFIO_GROUP_NOTIFY_SET_KVM; | ||
493 | ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events, | ||
494 | &vgpu->vdev.group_notifier); | ||
495 | if (ret != 0) { | ||
496 | gvt_err("vfio_register_notifier for group failed: %d\n", ret); | ||
497 | goto undo_iommu; | ||
498 | } | ||
499 | |||
500 | return kvmgt_guest_init(mdev); | ||
501 | |||
502 | undo_iommu: | ||
503 | vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, | ||
504 | &vgpu->vdev.iommu_notifier); | ||
505 | out: | ||
506 | return ret; | ||
507 | } | ||
508 | |||
509 | static void __intel_vgpu_release(struct intel_vgpu *vgpu) | ||
510 | { | ||
511 | struct kvmgt_guest_info *info; | ||
512 | |||
513 | if (!handle_valid(vgpu->handle)) | ||
514 | return; | ||
515 | |||
516 | vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY, | ||
517 | &vgpu->vdev.iommu_notifier); | ||
518 | vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY, | ||
519 | &vgpu->vdev.group_notifier); | ||
520 | |||
521 | info = (struct kvmgt_guest_info *)vgpu->handle; | ||
522 | kvmgt_guest_exit(info); | ||
523 | vgpu->handle = 0; | ||
524 | } | ||
525 | |||
526 | static void intel_vgpu_release(struct mdev_device *mdev) | ||
527 | { | ||
528 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
529 | |||
530 | __intel_vgpu_release(vgpu); | ||
531 | } | ||
532 | |||
533 | static void intel_vgpu_release_work(struct work_struct *work) | ||
534 | { | ||
535 | struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu, | ||
536 | vdev.release_work); | ||
537 | __intel_vgpu_release(vgpu); | ||
538 | } | ||
539 | |||
540 | static uint64_t intel_vgpu_get_bar0_addr(struct intel_vgpu *vgpu) | ||
541 | { | ||
542 | u32 start_lo, start_hi; | ||
543 | u32 mem_type; | ||
544 | int pos = PCI_BASE_ADDRESS_0; | ||
545 | |||
546 | start_lo = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) & | ||
547 | PCI_BASE_ADDRESS_MEM_MASK; | ||
548 | mem_type = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) & | ||
549 | PCI_BASE_ADDRESS_MEM_TYPE_MASK; | ||
550 | |||
551 | switch (mem_type) { | ||
552 | case PCI_BASE_ADDRESS_MEM_TYPE_64: | ||
553 | start_hi = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space | ||
554 | + pos + 4)); | ||
555 | break; | ||
556 | case PCI_BASE_ADDRESS_MEM_TYPE_32: | ||
557 | case PCI_BASE_ADDRESS_MEM_TYPE_1M: | ||
558 | /* 1M mem BAR treated as 32-bit BAR */ | ||
559 | default: | ||
560 | /* mem unknown type treated as 32-bit BAR */ | ||
561 | start_hi = 0; | ||
562 | break; | ||
563 | } | ||
564 | |||
565 | return ((u64)start_hi << 32) | start_lo; | ||
566 | } | ||
567 | |||
568 | static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf, | ||
569 | size_t count, loff_t *ppos, bool is_write) | ||
570 | { | ||
571 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
572 | unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); | ||
573 | uint64_t pos = *ppos & VFIO_PCI_OFFSET_MASK; | ||
574 | int ret = -EINVAL; | ||
575 | |||
576 | |||
577 | if (index >= VFIO_PCI_NUM_REGIONS) { | ||
578 | gvt_err("invalid index: %u\n", index); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
582 | switch (index) { | ||
583 | case VFIO_PCI_CONFIG_REGION_INDEX: | ||
584 | if (is_write) | ||
585 | ret = intel_gvt_ops->emulate_cfg_write(vgpu, pos, | ||
586 | buf, count); | ||
587 | else | ||
588 | ret = intel_gvt_ops->emulate_cfg_read(vgpu, pos, | ||
589 | buf, count); | ||
590 | break; | ||
591 | case VFIO_PCI_BAR0_REGION_INDEX: | ||
592 | case VFIO_PCI_BAR1_REGION_INDEX: | ||
593 | if (is_write) { | ||
594 | uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu); | ||
595 | |||
596 | ret = intel_gvt_ops->emulate_mmio_write(vgpu, | ||
597 | bar0_start + pos, buf, count); | ||
598 | } else { | ||
599 | uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu); | ||
600 | |||
601 | ret = intel_gvt_ops->emulate_mmio_read(vgpu, | ||
602 | bar0_start + pos, buf, count); | ||
603 | } | ||
604 | break; | ||
605 | case VFIO_PCI_BAR2_REGION_INDEX: | ||
606 | case VFIO_PCI_BAR3_REGION_INDEX: | ||
607 | case VFIO_PCI_BAR4_REGION_INDEX: | ||
608 | case VFIO_PCI_BAR5_REGION_INDEX: | ||
609 | case VFIO_PCI_VGA_REGION_INDEX: | ||
610 | case VFIO_PCI_ROM_REGION_INDEX: | ||
611 | default: | ||
612 | gvt_err("unsupported region: %u\n", index); | ||
613 | } | ||
614 | |||
615 | return ret == 0 ? count : ret; | ||
616 | } | ||
617 | |||
618 | static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, | ||
619 | size_t count, loff_t *ppos) | ||
620 | { | ||
621 | unsigned int done = 0; | ||
622 | int ret; | ||
623 | |||
624 | while (count) { | ||
625 | size_t filled; | ||
626 | |||
627 | if (count >= 4 && !(*ppos % 4)) { | ||
628 | u32 val; | ||
629 | |||
630 | ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), | ||
631 | ppos, false); | ||
632 | if (ret <= 0) | ||
633 | goto read_err; | ||
634 | |||
635 | if (copy_to_user(buf, &val, sizeof(val))) | ||
636 | goto read_err; | ||
637 | |||
638 | filled = 4; | ||
639 | } else if (count >= 2 && !(*ppos % 2)) { | ||
640 | u16 val; | ||
641 | |||
642 | ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), | ||
643 | ppos, false); | ||
644 | if (ret <= 0) | ||
645 | goto read_err; | ||
646 | |||
647 | if (copy_to_user(buf, &val, sizeof(val))) | ||
648 | goto read_err; | ||
649 | |||
650 | filled = 2; | ||
651 | } else { | ||
652 | u8 val; | ||
653 | |||
654 | ret = intel_vgpu_rw(mdev, &val, sizeof(val), ppos, | ||
655 | false); | ||
656 | if (ret <= 0) | ||
657 | goto read_err; | ||
658 | |||
659 | if (copy_to_user(buf, &val, sizeof(val))) | ||
660 | goto read_err; | ||
661 | |||
662 | filled = 1; | ||
663 | } | ||
664 | |||
665 | count -= filled; | ||
666 | done += filled; | ||
667 | *ppos += filled; | ||
668 | buf += filled; | ||
669 | } | ||
670 | |||
671 | return done; | ||
672 | |||
673 | read_err: | ||
674 | return -EFAULT; | ||
675 | } | ||
676 | |||
677 | static ssize_t intel_vgpu_write(struct mdev_device *mdev, | ||
678 | const char __user *buf, | ||
679 | size_t count, loff_t *ppos) | ||
680 | { | ||
681 | unsigned int done = 0; | ||
682 | int ret; | ||
683 | |||
684 | while (count) { | ||
685 | size_t filled; | ||
686 | |||
687 | if (count >= 4 && !(*ppos % 4)) { | ||
688 | u32 val; | ||
689 | |||
690 | if (copy_from_user(&val, buf, sizeof(val))) | ||
691 | goto write_err; | ||
692 | |||
693 | ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), | ||
694 | ppos, true); | ||
695 | if (ret <= 0) | ||
696 | goto write_err; | ||
697 | |||
698 | filled = 4; | ||
699 | } else if (count >= 2 && !(*ppos % 2)) { | ||
700 | u16 val; | ||
701 | |||
702 | if (copy_from_user(&val, buf, sizeof(val))) | ||
703 | goto write_err; | ||
704 | |||
705 | ret = intel_vgpu_rw(mdev, (char *)&val, | ||
706 | sizeof(val), ppos, true); | ||
707 | if (ret <= 0) | ||
708 | goto write_err; | ||
709 | |||
710 | filled = 2; | ||
711 | } else { | ||
712 | u8 val; | ||
713 | |||
714 | if (copy_from_user(&val, buf, sizeof(val))) | ||
715 | goto write_err; | ||
716 | |||
717 | ret = intel_vgpu_rw(mdev, &val, sizeof(val), | ||
718 | ppos, true); | ||
719 | if (ret <= 0) | ||
720 | goto write_err; | ||
721 | |||
722 | filled = 1; | ||
723 | } | ||
724 | |||
725 | count -= filled; | ||
726 | done += filled; | ||
727 | *ppos += filled; | ||
728 | buf += filled; | ||
729 | } | ||
730 | |||
731 | return done; | ||
732 | write_err: | ||
733 | return -EFAULT; | ||
734 | } | ||
735 | |||
736 | static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma) | ||
737 | { | ||
738 | unsigned int index; | ||
739 | u64 virtaddr; | ||
740 | unsigned long req_size, pgoff = 0; | ||
741 | pgprot_t pg_prot; | ||
742 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
743 | |||
744 | index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT); | ||
745 | if (index >= VFIO_PCI_ROM_REGION_INDEX) | ||
746 | return -EINVAL; | ||
747 | |||
748 | if (vma->vm_end < vma->vm_start) | ||
749 | return -EINVAL; | ||
750 | if ((vma->vm_flags & VM_SHARED) == 0) | ||
751 | return -EINVAL; | ||
752 | if (index != VFIO_PCI_BAR2_REGION_INDEX) | ||
753 | return -EINVAL; | ||
754 | |||
755 | pg_prot = vma->vm_page_prot; | ||
756 | virtaddr = vma->vm_start; | ||
757 | req_size = vma->vm_end - vma->vm_start; | ||
758 | pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT; | ||
759 | |||
760 | return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot); | ||
761 | } | ||
762 | |||
763 | static int intel_vgpu_get_irq_count(struct intel_vgpu *vgpu, int type) | ||
764 | { | ||
765 | if (type == VFIO_PCI_INTX_IRQ_INDEX || type == VFIO_PCI_MSI_IRQ_INDEX) | ||
766 | return 1; | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static int intel_vgpu_set_intx_mask(struct intel_vgpu *vgpu, | ||
772 | unsigned int index, unsigned int start, | ||
773 | unsigned int count, uint32_t flags, | ||
774 | void *data) | ||
775 | { | ||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu, | ||
780 | unsigned int index, unsigned int start, | ||
781 | unsigned int count, uint32_t flags, void *data) | ||
782 | { | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu, | ||
787 | unsigned int index, unsigned int start, unsigned int count, | ||
788 | uint32_t flags, void *data) | ||
789 | { | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu, | ||
794 | unsigned int index, unsigned int start, unsigned int count, | ||
795 | uint32_t flags, void *data) | ||
796 | { | ||
797 | struct eventfd_ctx *trigger; | ||
798 | |||
799 | if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { | ||
800 | int fd = *(int *)data; | ||
801 | |||
802 | trigger = eventfd_ctx_fdget(fd); | ||
803 | if (IS_ERR(trigger)) { | ||
804 | gvt_err("eventfd_ctx_fdget failed\n"); | ||
805 | return PTR_ERR(trigger); | ||
806 | } | ||
807 | vgpu->vdev.msi_trigger = trigger; | ||
808 | } | ||
809 | |||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, uint32_t flags, | ||
814 | unsigned int index, unsigned int start, unsigned int count, | ||
815 | void *data) | ||
816 | { | ||
817 | int (*func)(struct intel_vgpu *vgpu, unsigned int index, | ||
818 | unsigned int start, unsigned int count, uint32_t flags, | ||
819 | void *data) = NULL; | ||
820 | |||
821 | switch (index) { | ||
822 | case VFIO_PCI_INTX_IRQ_INDEX: | ||
823 | switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { | ||
824 | case VFIO_IRQ_SET_ACTION_MASK: | ||
825 | func = intel_vgpu_set_intx_mask; | ||
826 | break; | ||
827 | case VFIO_IRQ_SET_ACTION_UNMASK: | ||
828 | func = intel_vgpu_set_intx_unmask; | ||
829 | break; | ||
830 | case VFIO_IRQ_SET_ACTION_TRIGGER: | ||
831 | func = intel_vgpu_set_intx_trigger; | ||
832 | break; | ||
833 | } | ||
834 | break; | ||
835 | case VFIO_PCI_MSI_IRQ_INDEX: | ||
836 | switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { | ||
837 | case VFIO_IRQ_SET_ACTION_MASK: | ||
838 | case VFIO_IRQ_SET_ACTION_UNMASK: | ||
839 | /* XXX Need masking support exported */ | ||
840 | break; | ||
841 | case VFIO_IRQ_SET_ACTION_TRIGGER: | ||
842 | func = intel_vgpu_set_msi_trigger; | ||
843 | break; | ||
844 | } | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | if (!func) | ||
849 | return -ENOTTY; | ||
850 | |||
851 | return func(vgpu, index, start, count, flags, data); | ||
852 | } | ||
853 | |||
854 | static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, | ||
855 | unsigned long arg) | ||
856 | { | ||
857 | struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); | ||
858 | unsigned long minsz; | ||
859 | |||
860 | gvt_dbg_core("vgpu%d ioctl, cmd: %d\n", vgpu->id, cmd); | ||
861 | |||
862 | if (cmd == VFIO_DEVICE_GET_INFO) { | ||
863 | struct vfio_device_info info; | ||
864 | |||
865 | minsz = offsetofend(struct vfio_device_info, num_irqs); | ||
866 | |||
867 | if (copy_from_user(&info, (void __user *)arg, minsz)) | ||
868 | return -EFAULT; | ||
869 | |||
870 | if (info.argsz < minsz) | ||
871 | return -EINVAL; | ||
872 | |||
873 | info.flags = VFIO_DEVICE_FLAGS_PCI; | ||
874 | info.flags |= VFIO_DEVICE_FLAGS_RESET; | ||
875 | info.num_regions = VFIO_PCI_NUM_REGIONS; | ||
876 | info.num_irqs = VFIO_PCI_NUM_IRQS; | ||
877 | |||
878 | return copy_to_user((void __user *)arg, &info, minsz) ? | ||
879 | -EFAULT : 0; | ||
880 | |||
881 | } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { | ||
882 | struct vfio_region_info info; | ||
883 | struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; | ||
884 | int i, ret; | ||
885 | struct vfio_region_info_cap_sparse_mmap *sparse = NULL; | ||
886 | size_t size; | ||
887 | int nr_areas = 1; | ||
888 | int cap_type_id; | ||
889 | |||
890 | minsz = offsetofend(struct vfio_region_info, offset); | ||
891 | |||
892 | if (copy_from_user(&info, (void __user *)arg, minsz)) | ||
893 | return -EFAULT; | ||
894 | |||
895 | if (info.argsz < minsz) | ||
896 | return -EINVAL; | ||
897 | |||
898 | switch (info.index) { | ||
899 | case VFIO_PCI_CONFIG_REGION_INDEX: | ||
900 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
901 | info.size = INTEL_GVT_MAX_CFG_SPACE_SZ; | ||
902 | info.flags = VFIO_REGION_INFO_FLAG_READ | | ||
903 | VFIO_REGION_INFO_FLAG_WRITE; | ||
904 | break; | ||
905 | case VFIO_PCI_BAR0_REGION_INDEX: | ||
906 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
907 | info.size = vgpu->cfg_space.bar[info.index].size; | ||
908 | if (!info.size) { | ||
909 | info.flags = 0; | ||
910 | break; | ||
911 | } | ||
912 | |||
913 | info.flags = VFIO_REGION_INFO_FLAG_READ | | ||
914 | VFIO_REGION_INFO_FLAG_WRITE; | ||
915 | break; | ||
916 | case VFIO_PCI_BAR1_REGION_INDEX: | ||
917 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
918 | info.size = 0; | ||
919 | info.flags = 0; | ||
920 | break; | ||
921 | case VFIO_PCI_BAR2_REGION_INDEX: | ||
922 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
923 | info.flags = VFIO_REGION_INFO_FLAG_CAPS | | ||
924 | VFIO_REGION_INFO_FLAG_MMAP | | ||
925 | VFIO_REGION_INFO_FLAG_READ | | ||
926 | VFIO_REGION_INFO_FLAG_WRITE; | ||
927 | info.size = gvt_aperture_sz(vgpu->gvt); | ||
928 | |||
929 | size = sizeof(*sparse) + | ||
930 | (nr_areas * sizeof(*sparse->areas)); | ||
931 | sparse = kzalloc(size, GFP_KERNEL); | ||
932 | if (!sparse) | ||
933 | return -ENOMEM; | ||
934 | |||
935 | sparse->nr_areas = nr_areas; | ||
936 | cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; | ||
937 | sparse->areas[0].offset = | ||
938 | PAGE_ALIGN(vgpu_aperture_offset(vgpu)); | ||
939 | sparse->areas[0].size = vgpu_aperture_sz(vgpu); | ||
940 | if (!caps.buf) { | ||
941 | kfree(caps.buf); | ||
942 | caps.buf = NULL; | ||
943 | caps.size = 0; | ||
944 | } | ||
945 | break; | ||
946 | |||
947 | case VFIO_PCI_BAR3_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: | ||
948 | info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
949 | info.size = 0; | ||
950 | |||
951 | info.flags = 0; | ||
952 | gvt_dbg_core("get region info bar:%d\n", info.index); | ||
953 | break; | ||
954 | |||
955 | case VFIO_PCI_ROM_REGION_INDEX: | ||
956 | case VFIO_PCI_VGA_REGION_INDEX: | ||
957 | gvt_dbg_core("get region info index:%d\n", info.index); | ||
958 | break; | ||
959 | default: | ||
960 | { | ||
961 | struct vfio_region_info_cap_type cap_type; | ||
962 | |||
963 | if (info.index >= VFIO_PCI_NUM_REGIONS + | ||
964 | vgpu->vdev.num_regions) | ||
965 | return -EINVAL; | ||
966 | |||
967 | i = info.index - VFIO_PCI_NUM_REGIONS; | ||
968 | |||
969 | info.offset = | ||
970 | VFIO_PCI_INDEX_TO_OFFSET(info.index); | ||
971 | info.size = vgpu->vdev.region[i].size; | ||
972 | info.flags = vgpu->vdev.region[i].flags; | ||
973 | |||
974 | cap_type.type = vgpu->vdev.region[i].type; | ||
975 | cap_type.subtype = vgpu->vdev.region[i].subtype; | ||
976 | |||
977 | ret = vfio_info_add_capability(&caps, | ||
978 | VFIO_REGION_INFO_CAP_TYPE, | ||
979 | &cap_type); | ||
980 | if (ret) | ||
981 | return ret; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) { | ||
986 | switch (cap_type_id) { | ||
987 | case VFIO_REGION_INFO_CAP_SPARSE_MMAP: | ||
988 | ret = vfio_info_add_capability(&caps, | ||
989 | VFIO_REGION_INFO_CAP_SPARSE_MMAP, | ||
990 | sparse); | ||
991 | kfree(sparse); | ||
992 | if (ret) | ||
993 | return ret; | ||
994 | break; | ||
995 | default: | ||
996 | return -EINVAL; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | if (caps.size) { | ||
1001 | if (info.argsz < sizeof(info) + caps.size) { | ||
1002 | info.argsz = sizeof(info) + caps.size; | ||
1003 | info.cap_offset = 0; | ||
1004 | } else { | ||
1005 | vfio_info_cap_shift(&caps, sizeof(info)); | ||
1006 | if (copy_to_user((void __user *)arg + | ||
1007 | sizeof(info), caps.buf, | ||
1008 | caps.size)) { | ||
1009 | kfree(caps.buf); | ||
1010 | return -EFAULT; | ||
1011 | } | ||
1012 | info.cap_offset = sizeof(info); | ||
1013 | } | ||
1014 | |||
1015 | kfree(caps.buf); | ||
1016 | } | ||
1017 | |||
1018 | return copy_to_user((void __user *)arg, &info, minsz) ? | ||
1019 | -EFAULT : 0; | ||
1020 | } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { | ||
1021 | struct vfio_irq_info info; | ||
1022 | |||
1023 | minsz = offsetofend(struct vfio_irq_info, count); | ||
1024 | |||
1025 | if (copy_from_user(&info, (void __user *)arg, minsz)) | ||
1026 | return -EFAULT; | ||
1027 | |||
1028 | if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS) | ||
1029 | return -EINVAL; | ||
1030 | |||
1031 | switch (info.index) { | ||
1032 | case VFIO_PCI_INTX_IRQ_INDEX: | ||
1033 | case VFIO_PCI_MSI_IRQ_INDEX: | ||
1034 | break; | ||
1035 | default: | ||
1036 | return -EINVAL; | ||
1037 | } | ||
1038 | |||
1039 | info.flags = VFIO_IRQ_INFO_EVENTFD; | ||
1040 | |||
1041 | info.count = intel_vgpu_get_irq_count(vgpu, info.index); | ||
1042 | |||
1043 | if (info.index == VFIO_PCI_INTX_IRQ_INDEX) | ||
1044 | info.flags |= (VFIO_IRQ_INFO_MASKABLE | | ||
1045 | VFIO_IRQ_INFO_AUTOMASKED); | ||
1046 | else | ||
1047 | info.flags |= VFIO_IRQ_INFO_NORESIZE; | ||
1048 | |||
1049 | return copy_to_user((void __user *)arg, &info, minsz) ? | ||
1050 | -EFAULT : 0; | ||
1051 | } else if (cmd == VFIO_DEVICE_SET_IRQS) { | ||
1052 | struct vfio_irq_set hdr; | ||
1053 | u8 *data = NULL; | ||
1054 | int ret = 0; | ||
1055 | size_t data_size = 0; | ||
1056 | |||
1057 | minsz = offsetofend(struct vfio_irq_set, count); | ||
1058 | |||
1059 | if (copy_from_user(&hdr, (void __user *)arg, minsz)) | ||
1060 | return -EFAULT; | ||
1061 | |||
1062 | if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { | ||
1063 | int max = intel_vgpu_get_irq_count(vgpu, hdr.index); | ||
1064 | |||
1065 | ret = vfio_set_irqs_validate_and_prepare(&hdr, max, | ||
1066 | VFIO_PCI_NUM_IRQS, &data_size); | ||
1067 | if (ret) { | ||
1068 | gvt_err("intel:vfio_set_irqs_validate_and_prepare failed\n"); | ||
1069 | return -EINVAL; | ||
1070 | } | ||
1071 | if (data_size) { | ||
1072 | data = memdup_user((void __user *)(arg + minsz), | ||
1073 | data_size); | ||
1074 | if (IS_ERR(data)) | ||
1075 | return PTR_ERR(data); | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index, | ||
1080 | hdr.start, hdr.count, data); | ||
1081 | kfree(data); | ||
1082 | |||
1083 | return ret; | ||
1084 | } else if (cmd == VFIO_DEVICE_RESET) { | ||
1085 | intel_gvt_ops->vgpu_reset(vgpu); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | return 0; | ||
1090 | } | ||
1091 | |||
1092 | static const struct parent_ops intel_vgpu_ops = { | ||
1093 | .supported_type_groups = intel_vgpu_type_groups, | ||
1094 | .create = intel_vgpu_create, | ||
1095 | .remove = intel_vgpu_remove, | ||
1096 | |||
1097 | .open = intel_vgpu_open, | ||
1098 | .release = intel_vgpu_release, | ||
1099 | |||
1100 | .read = intel_vgpu_read, | ||
1101 | .write = intel_vgpu_write, | ||
1102 | .mmap = intel_vgpu_mmap, | ||
1103 | .ioctl = intel_vgpu_ioctl, | ||
1104 | }; | ||
1105 | |||
345 | static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) | 1106 | static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) |
346 | { | 1107 | { |
347 | if (!intel_gvt_init_vgpu_type_groups(gvt)) | 1108 | if (!intel_gvt_init_vgpu_type_groups(gvt)) |
@@ -349,22 +1110,28 @@ static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) | |||
349 | 1110 | ||
350 | intel_gvt_ops = ops; | 1111 | intel_gvt_ops = ops; |
351 | 1112 | ||
352 | /* MDEV is not yet available */ | 1113 | return mdev_register_device(dev, &intel_vgpu_ops); |
353 | return -ENODEV; | ||
354 | } | 1114 | } |
355 | 1115 | ||
356 | static void kvmgt_host_exit(struct device *dev, void *gvt) | 1116 | static void kvmgt_host_exit(struct device *dev, void *gvt) |
357 | { | 1117 | { |
358 | intel_gvt_cleanup_vgpu_type_groups(gvt); | 1118 | intel_gvt_cleanup_vgpu_type_groups(gvt); |
1119 | mdev_unregister_device(dev); | ||
359 | } | 1120 | } |
360 | 1121 | ||
361 | static int kvmgt_write_protect_add(unsigned long handle, u64 gfn) | 1122 | static int kvmgt_write_protect_add(unsigned long handle, u64 gfn) |
362 | { | 1123 | { |
363 | struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; | 1124 | struct kvmgt_guest_info *info; |
364 | struct kvm *kvm = info->kvm; | 1125 | struct kvm *kvm; |
365 | struct kvm_memory_slot *slot; | 1126 | struct kvm_memory_slot *slot; |
366 | int idx; | 1127 | int idx; |
367 | 1128 | ||
1129 | if (!handle_valid(handle)) | ||
1130 | return -ESRCH; | ||
1131 | |||
1132 | info = (struct kvmgt_guest_info *)handle; | ||
1133 | kvm = info->kvm; | ||
1134 | |||
368 | idx = srcu_read_lock(&kvm->srcu); | 1135 | idx = srcu_read_lock(&kvm->srcu); |
369 | slot = gfn_to_memslot(kvm, gfn); | 1136 | slot = gfn_to_memslot(kvm, gfn); |
370 | 1137 | ||
@@ -384,11 +1151,17 @@ out: | |||
384 | 1151 | ||
385 | static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn) | 1152 | static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn) |
386 | { | 1153 | { |
387 | struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; | 1154 | struct kvmgt_guest_info *info; |
388 | struct kvm *kvm = info->kvm; | 1155 | struct kvm *kvm; |
389 | struct kvm_memory_slot *slot; | 1156 | struct kvm_memory_slot *slot; |
390 | int idx; | 1157 | int idx; |
391 | 1158 | ||
1159 | if (!handle_valid(handle)) | ||
1160 | return 0; | ||
1161 | |||
1162 | info = (struct kvmgt_guest_info *)handle; | ||
1163 | kvm = info->kvm; | ||
1164 | |||
392 | idx = srcu_read_lock(&kvm->srcu); | 1165 | idx = srcu_read_lock(&kvm->srcu); |
393 | slot = gfn_to_memslot(kvm, gfn); | 1166 | slot = gfn_to_memslot(kvm, gfn); |
394 | 1167 | ||
@@ -476,6 +1249,85 @@ static int kvmgt_detect_host(void) | |||
476 | return kvmgt_check_guest() ? -ENODEV : 0; | 1249 | return kvmgt_check_guest() ? -ENODEV : 0; |
477 | } | 1250 | } |
478 | 1251 | ||
1252 | static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm) | ||
1253 | { | ||
1254 | struct intel_vgpu *itr; | ||
1255 | struct kvmgt_guest_info *info; | ||
1256 | int id; | ||
1257 | bool ret = false; | ||
1258 | |||
1259 | mutex_lock(&vgpu->gvt->lock); | ||
1260 | for_each_active_vgpu(vgpu->gvt, itr, id) { | ||
1261 | if (!handle_valid(itr->handle)) | ||
1262 | continue; | ||
1263 | |||
1264 | info = (struct kvmgt_guest_info *)itr->handle; | ||
1265 | if (kvm && kvm == info->kvm) { | ||
1266 | ret = true; | ||
1267 | goto out; | ||
1268 | } | ||
1269 | } | ||
1270 | out: | ||
1271 | mutex_unlock(&vgpu->gvt->lock); | ||
1272 | return ret; | ||
1273 | } | ||
1274 | |||
1275 | static int kvmgt_guest_init(struct mdev_device *mdev) | ||
1276 | { | ||
1277 | struct kvmgt_guest_info *info; | ||
1278 | struct intel_vgpu *vgpu; | ||
1279 | struct kvm *kvm; | ||
1280 | |||
1281 | vgpu = mdev_get_drvdata(mdev); | ||
1282 | if (handle_valid(vgpu->handle)) | ||
1283 | return -EEXIST; | ||
1284 | |||
1285 | kvm = vgpu->vdev.kvm; | ||
1286 | if (!kvm || kvm->mm != current->mm) { | ||
1287 | gvt_err("KVM is required to use Intel vGPU\n"); | ||
1288 | return -ESRCH; | ||
1289 | } | ||
1290 | |||
1291 | if (__kvmgt_vgpu_exist(vgpu, kvm)) | ||
1292 | return -EEXIST; | ||
1293 | |||
1294 | info = vzalloc(sizeof(struct kvmgt_guest_info)); | ||
1295 | if (!info) | ||
1296 | return -ENOMEM; | ||
1297 | |||
1298 | vgpu->handle = (unsigned long)info; | ||
1299 | info->vgpu = vgpu; | ||
1300 | info->kvm = kvm; | ||
1301 | |||
1302 | kvmgt_protect_table_init(info); | ||
1303 | gvt_cache_init(vgpu); | ||
1304 | |||
1305 | info->track_node.track_write = kvmgt_page_track_write; | ||
1306 | info->track_node.track_flush_slot = kvmgt_page_track_flush_slot; | ||
1307 | kvm_page_track_register_notifier(kvm, &info->track_node); | ||
1308 | |||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | static bool kvmgt_guest_exit(struct kvmgt_guest_info *info) | ||
1313 | { | ||
1314 | struct intel_vgpu *vgpu; | ||
1315 | |||
1316 | if (!info) { | ||
1317 | gvt_err("kvmgt_guest_info invalid\n"); | ||
1318 | return false; | ||
1319 | } | ||
1320 | |||
1321 | vgpu = info->vgpu; | ||
1322 | |||
1323 | kvm_page_track_unregister_notifier(info->kvm, &info->track_node); | ||
1324 | kvmgt_protect_table_destroy(info); | ||
1325 | gvt_cache_destroy(vgpu); | ||
1326 | vfree(info); | ||
1327 | |||
1328 | return true; | ||
1329 | } | ||
1330 | |||
479 | static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle) | 1331 | static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle) |
480 | { | 1332 | { |
481 | /* nothing to do here */ | 1333 | /* nothing to do here */ |
@@ -489,63 +1341,72 @@ static void kvmgt_detach_vgpu(unsigned long handle) | |||
489 | 1341 | ||
490 | static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data) | 1342 | static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data) |
491 | { | 1343 | { |
492 | struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; | 1344 | struct kvmgt_guest_info *info; |
493 | struct intel_vgpu *vgpu = info->vgpu; | 1345 | struct intel_vgpu *vgpu; |
494 | 1346 | ||
495 | if (vgpu->vdev.msi_trigger) | 1347 | if (!handle_valid(handle)) |
496 | return eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1; | 1348 | return -ESRCH; |
497 | 1349 | ||
498 | return false; | 1350 | info = (struct kvmgt_guest_info *)handle; |
1351 | vgpu = info->vgpu; | ||
1352 | |||
1353 | if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1) | ||
1354 | return 0; | ||
1355 | |||
1356 | return -EFAULT; | ||
499 | } | 1357 | } |
500 | 1358 | ||
501 | static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) | 1359 | static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) |
502 | { | 1360 | { |
503 | unsigned long pfn; | 1361 | unsigned long pfn; |
504 | struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; | 1362 | struct kvmgt_guest_info *info; |
1363 | struct device *dev; | ||
505 | int rc; | 1364 | int rc; |
506 | 1365 | ||
1366 | if (!handle_valid(handle)) | ||
1367 | return INTEL_GVT_INVALID_ADDR; | ||
1368 | |||
1369 | info = (struct kvmgt_guest_info *)handle; | ||
507 | pfn = gvt_cache_find(info->vgpu, gfn); | 1370 | pfn = gvt_cache_find(info->vgpu, gfn); |
508 | if (pfn != 0) | 1371 | if (pfn != 0) |
509 | return pfn; | 1372 | return pfn; |
510 | 1373 | ||
511 | rc = kvmgt_pin_pages(info->vgpu->vdev.mdev, &gfn, 1, | 1374 | pfn = INTEL_GVT_INVALID_ADDR; |
512 | IOMMU_READ | IOMMU_WRITE, &pfn); | 1375 | dev = &info->vgpu->vdev.mdev->dev; |
1376 | rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn); | ||
513 | if (rc != 1) { | 1377 | if (rc != 1) { |
514 | gvt_err("vfio_pin_pages failed for gfn: 0x%lx\n", gfn); | 1378 | gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc); |
515 | return 0; | 1379 | return INTEL_GVT_INVALID_ADDR; |
516 | } | 1380 | } |
517 | 1381 | ||
518 | gvt_cache_add(info->vgpu, gfn, pfn); | 1382 | gvt_cache_add(info->vgpu, gfn, pfn); |
519 | return pfn; | 1383 | return pfn; |
520 | } | 1384 | } |
521 | 1385 | ||
522 | static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa) | 1386 | static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, |
1387 | void *buf, unsigned long len, bool write) | ||
523 | { | 1388 | { |
524 | unsigned long pfn; | 1389 | struct kvmgt_guest_info *info; |
525 | gfn_t gfn = gpa_to_gfn(gpa); | 1390 | struct kvm *kvm; |
1391 | int ret; | ||
1392 | bool kthread = current->mm == NULL; | ||
526 | 1393 | ||
527 | pfn = kvmgt_gfn_to_pfn(handle, gfn); | 1394 | if (!handle_valid(handle)) |
528 | if (!pfn) | 1395 | return -ESRCH; |
529 | return NULL; | ||
530 | 1396 | ||
531 | return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa); | 1397 | info = (struct kvmgt_guest_info *)handle; |
532 | } | 1398 | kvm = info->kvm; |
533 | 1399 | ||
534 | static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, | 1400 | if (kthread) |
535 | void *buf, unsigned long len, bool write) | 1401 | use_mm(kvm->mm); |
536 | { | ||
537 | void *hva = NULL; | ||
538 | 1402 | ||
539 | hva = kvmgt_gpa_to_hva(handle, gpa); | 1403 | ret = write ? kvm_write_guest(kvm, gpa, buf, len) : |
540 | if (!hva) | 1404 | kvm_read_guest(kvm, gpa, buf, len); |
541 | return -EFAULT; | ||
542 | 1405 | ||
543 | if (write) | 1406 | if (kthread) |
544 | memcpy(hva, buf, len); | 1407 | unuse_mm(kvm->mm); |
545 | else | ||
546 | memcpy(buf, hva, len); | ||
547 | 1408 | ||
548 | return 0; | 1409 | return ret; |
549 | } | 1410 | } |
550 | 1411 | ||
551 | static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa, | 1412 | static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa, |