Re: [RFC v2 06/12] drm/i915/svm: Device memory support

2019-12-18 Thread Niranjana Vishwanathapura

On Tue, Dec 17, 2019 at 08:35:47PM +, Jason Gunthorpe wrote:

On Fri, Dec 13, 2019 at 01:56:08PM -0800, Niranjana Vishwanathapura wrote:

@@ -169,6 +170,11 @@ static int i915_range_fault(struct svm_notifier *sn,
return ret;
}

+   /* For dgfx, ensure the range is in device local memory only */
+   regions = i915_dmem_convert_pfn(vm->i915, &range);
+   if (!regions || (IS_DGFX(vm->i915) && (regions & REGION_SMEM)))
+   return -EINVAL;
+


This is not OK, as I said before, the driver cannot de-reference pfns
before doing the retry check, under lock.



Thanks.
Ok, will push it down and do it after validating the range.


+
+int i915_dmem_convert_pfn(struct drm_i915_private *dev_priv,
+ struct hmm_range *range)
+{
+   unsigned long i, npages;
+   int regions = 0;
+
+   npages = (range->end - range->start) >> PAGE_SHIFT;
+   for (i = 0; i < npages; ++i) {
+   struct i915_buddy_block *block;
+   struct intel_memory_region *mem;
+   struct page *page;
+   u64 addr;
+
+   page = hmm_device_entry_to_page(range, range->pfns[i]);

   ^^

For instance, that cannot be done on a speculatively loaded page.

This also looks like it suffers from the same bug as



Ok.


+   if (!page)
+   continue;
+
+   if (!(range->pfns[i] & range->flags[HMM_PFN_DEVICE_PRIVATE])) {
+   regions |= REGION_SMEM;
+   continue;
+   }
+
+   if (!i915_dmem_page(dev_priv, page)) {
+   WARN(1, "Some unknown device memory !\n");


Why is that a WARN? The user could put other device memory in the
address space. You need to 'segfault' the GPU execution if this happens.



OK, will return an error here if user is trying to bind here.
I agree, we need to segfault the GPU if it is GPU fault handling.


+   range->pfns[i] = 0;
+   continue;
+   }
+
+   regions |= REGION_LMEM;
+   block = page->zone_device_data;
+   mem = block->private;
+   addr = mem->region.start +
+  i915_buddy_block_offset(block);
+   addr += (page_to_pfn(page) - block->pfn_first) << PAGE_SHIFT;
+
+   range->pfns[i] &= ~range->flags[HMM_PFN_DEVICE_PRIVATE];
+   range->pfns[i] &= ((1UL << range->pfn_shift) - 1);
+   range->pfns[i] |= (addr >> PAGE_SHIFT) << range->pfn_shift;


This makes more sense as a direct manipulation of the sgl, not sure
why this routine is split out from the sgl builder?



Ok, yah, let me merge it with sgl building.

Thanks,
Niranjana


Jason

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


Re: [RFC v2 06/12] drm/i915/svm: Device memory support

2019-12-18 Thread Jason Gunthorpe
On Fri, Dec 13, 2019 at 01:56:08PM -0800, Niranjana Vishwanathapura wrote:
> @@ -169,6 +170,11 @@ static int i915_range_fault(struct svm_notifier *sn,
>   return ret;
>   }
>  
> + /* For dgfx, ensure the range is in device local memory only */
> + regions = i915_dmem_convert_pfn(vm->i915, &range);
> + if (!regions || (IS_DGFX(vm->i915) && (regions & REGION_SMEM)))
> + return -EINVAL;
> +

This is not OK, as I said before, the driver cannot de-reference pfns
before doing the retry check, under lock.

> +
> +int i915_dmem_convert_pfn(struct drm_i915_private *dev_priv,
> +   struct hmm_range *range)
> +{
> + unsigned long i, npages;
> + int regions = 0;
> +
> + npages = (range->end - range->start) >> PAGE_SHIFT;
> + for (i = 0; i < npages; ++i) {
> + struct i915_buddy_block *block;
> + struct intel_memory_region *mem;
> + struct page *page;
> + u64 addr;
> +
> + page = hmm_device_entry_to_page(range, range->pfns[i]);
^^

For instance, that cannot be done on a speculatively loaded page.

This also looks like it suffers from the same bug as

> + if (!page)
> + continue;
> +
> + if (!(range->pfns[i] & range->flags[HMM_PFN_DEVICE_PRIVATE])) {
> + regions |= REGION_SMEM;
> + continue;
> + }
> +
> + if (!i915_dmem_page(dev_priv, page)) {
> + WARN(1, "Some unknown device memory !\n");

Why is that a WARN? The user could put other device memory in the
address space. You need to 'segfault' the GPU execution if this happens.

> + range->pfns[i] = 0;
> + continue;
> + }
> +
> + regions |= REGION_LMEM;
> + block = page->zone_device_data;
> + mem = block->private;
> + addr = mem->region.start +
> +i915_buddy_block_offset(block);
> + addr += (page_to_pfn(page) - block->pfn_first) << PAGE_SHIFT;
> +
> + range->pfns[i] &= ~range->flags[HMM_PFN_DEVICE_PRIVATE];
> + range->pfns[i] &= ((1UL << range->pfn_shift) - 1);
> + range->pfns[i] |= (addr >> PAGE_SHIFT) << range->pfn_shift;

This makes more sense as a direct manipulation of the sgl, not sure
why this routine is split out from the sgl builder?

Jason
___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[RFC v2 06/12] drm/i915/svm: Device memory support

2019-12-13 Thread Niranjana Vishwanathapura
Plugin device memory through HMM as DEVICE_PRIVATE.
Add support functions to allocate pages and free pages from device memory.
Implement ioctl to prefetch pages from host to device memory.
For now, only support migrating pages from host memory to device memory.

Cc: Joonas Lahtinen 
Cc: Jon Bloomfield 
Cc: Daniel Vetter 
Cc: Sudeep Dutt 
Signed-off-by: Niranjana Vishwanathapura 
---
 drivers/gpu/drm/i915/Kconfig   |   9 +
 drivers/gpu/drm/i915/Makefile  |   3 +-
 drivers/gpu/drm/i915/gem/i915_gem_object.c |  13 -
 drivers/gpu/drm/i915/i915_buddy.h  |  12 +
 drivers/gpu/drm/i915/i915_drv.c|   1 +
 drivers/gpu/drm/i915/i915_svm.c|   6 +
 drivers/gpu/drm/i915/i915_svm.h|  15 +
 drivers/gpu/drm/i915/i915_svm_devmem.c | 400 +
 drivers/gpu/drm/i915/intel_memory_region.h |  14 +
 drivers/gpu/drm/i915/intel_region_lmem.c   |  10 +
 include/uapi/drm/i915_drm.h|  22 ++
 11 files changed, 491 insertions(+), 14 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_svm_devmem.c

diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 689e57fe3973..66337f2ca2bf 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -141,9 +141,18 @@ config DRM_I915_SVM
bool "Enable Shared Virtual Memory support in i915"
depends on STAGING
depends on DRM_I915
+   depends on ARCH_ENABLE_MEMORY_HOTPLUG
+   depends on ARCH_ENABLE_MEMORY_HOTREMOVE
+   depends on MEMORY_HOTPLUG
+   depends on MEMORY_HOTREMOVE
+   depends on ARCH_HAS_PTE_DEVMAP
+   depends on SPARSEMEM_VMEMMAP
+   depends on ZONE_DEVICE
+   depends on DEVICE_PRIVATE
depends on MMU
select HMM_MIRROR
select MMU_NOTIFIER
+   select MIGRATE_VMA_HELPER
default n
help
  Choose this option if you want Shared Virtual Memory (SVM)
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 7d4cd9eefd12..b574ec31ea2e 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -155,7 +155,8 @@ i915-y += \
 
 # SVM code
 i915-$(CONFIG_DRM_I915_SVM) += gem/i915_gem_svm.o \
-  i915_svm.o
+  i915_svm.o \
+  i915_svm_devmem.o
 
 # general-purpose microcontroller (GuC) support
 obj-y += gt/uc/
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c 
b/drivers/gpu/drm/i915/gem/i915_gem_object.c
index 003d81c171d2..f868a301fc04 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
@@ -504,19 +504,6 @@ int __init i915_global_objects_init(void)
return 0;
 }
 
-static enum intel_region_id
-__region_id(u32 region)
-{
-   enum intel_region_id id;
-
-   for (id = 0; id < INTEL_REGION_UNKNOWN; ++id) {
-   if (intel_region_map[id] == region)
-   return id;
-   }
-
-   return INTEL_REGION_UNKNOWN;
-}
-
 bool
 i915_gem_object_svm_mapped(struct drm_i915_gem_object *obj)
 {
diff --git a/drivers/gpu/drm/i915/i915_buddy.h 
b/drivers/gpu/drm/i915/i915_buddy.h
index ed41f3507cdc..afc493e6c130 100644
--- a/drivers/gpu/drm/i915/i915_buddy.h
+++ b/drivers/gpu/drm/i915/i915_buddy.h
@@ -9,6 +9,9 @@
 #include 
 #include 
 
+/* 512 bits (one per pages) supports 2MB blocks */
+#define I915_BUDDY_MAX_PAGES   512
+
 struct i915_buddy_block {
 #define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12)
 #define I915_BUDDY_HEADER_STATE  GENMASK_ULL(11, 10)
@@ -32,6 +35,15 @@ struct i915_buddy_block {
 */
struct list_head link;
struct list_head tmp_link;
+
+   unsigned long pfn_first;
+   /*
+* FIXME: There are other alternatives to bitmap. Like splitting the
+* block into contiguous 4K sized blocks. But it is part of bigger
+* issues involving partially invalidating large mapping, freeing the
+* blocks etc., revisit.
+*/
+   unsigned long bitmap[BITS_TO_LONGS(I915_BUDDY_MAX_PAGES)];
 };
 
 #define I915_BUDDY_MAX_ORDER  I915_BUDDY_HEADER_ORDER
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 866d3cbb1edf..f1b92fd3d234 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2765,6 +2765,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_VM_CREATE, i915_gem_vm_create_ioctl, 
DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_VM_DESTROY, i915_gem_vm_destroy_ioctl, 
DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_VM_BIND, i915_gem_vm_bind_ioctl, 
DRM_RENDER_ALLOW),
+   DRM_IOCTL_DEF_DRV(I915_GEM_VM_PREFETCH, i915_gem_vm_prefetch_ioctl, 
DRM_RENDER_ALLOW)
 };
 
 static struct drm_driver driver = {
diff --git a/drivers/gpu/drm/i915/i915_svm.c b/drivers/gpu/drm/i915/i915_svm.c
index 5941be5b5803..31a80ae0dd45 100644
--- a/drivers/gpu/drm/i915/i915_sv