drm/i915/gem: Support discontiguous lmem object maps
diff mbox series

Message ID 20200101220927.1074805-1-chris@chris-wilson.co.uk
State New
Headers show
Series
  • drm/i915/gem: Support discontiguous lmem object maps
Related show

Commit Message

Chris Wilson Jan. 1, 2020, 10:09 p.m. UTC
Create a vmap for discontinguous lmem objects to support
i915_gem_object_pin_map().

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Matthew Auld <matthew.auld@intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_pages.c | 45 ++++++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)

Comments

Chris Wilson Jan. 2, 2020, 8:45 a.m. UTC | #1
Quoting Chris Wilson (2020-01-01 22:09:27)
> +               ptes = mem;
> +               for_each_sgt_daddr(addr, sgt_iter, sgt)
> +                       **ptes++ = io_wc_pte(addr);

Addr is just relative to the start of lmem, this needs the iobar offset
as well. That magic is that using any old physical address just works,
until you hit something important!
-Chris

Patch
diff mbox series

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
index 75197ca696a8..edc3febbb71d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
@@ -158,10 +158,10 @@  static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj)
 
 static void unmap_object(struct drm_i915_gem_object *obj, void *ptr)
 {
-	if (i915_gem_object_is_lmem(obj))
-		io_mapping_unmap((void __force __iomem *)ptr);
-	else if (is_vmalloc_addr(ptr))
+	if (is_vmalloc_addr(ptr))
 		vunmap(ptr);
+	else if (i915_gem_object_is_lmem(obj))
+		io_mapping_unmap((void __force __iomem *)ptr);
 	else
 		kunmap(kmap_to_page(ptr));
 }
@@ -236,6 +236,12 @@  int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
 	return err;
 }
 
+static inline pte_t io_wc_pte(dma_addr_t addr)
+{
+	return pte_mkspecial(pfn_pte(addr >> PAGE_SHIFT,
+				     pgprot_writecombine(PAGE_KERNEL)));
+}
+
 /* The 'mapping' part of i915_gem_object_pin_map() below */
 static void *i915_gem_object_map(struct drm_i915_gem_object *obj,
 				 enum i915_map_type type)
@@ -251,13 +257,40 @@  static void *i915_gem_object_map(struct drm_i915_gem_object *obj,
 	void *addr;
 
 	if (i915_gem_object_is_lmem(obj)) {
-		void __iomem *io;
+		struct vm_struct *area;
+		dma_addr_t addr;
+		pte_t **ptes;
+		void *mem;
 
 		if (type != I915_MAP_WC)
 			return NULL;
 
-		io = i915_gem_object_lmem_io_map(obj, 0, obj->base.size);
-		return (void __force *)io;
+		if (i915_gem_object_is_contiguous(obj)) {
+			void __iomem *io =
+				i915_gem_object_lmem_io_map(obj,
+							    0, obj->base.size);
+
+			return (void __force *)io;
+		}
+
+		mem = kvmalloc_array(obj->base.size >> PAGE_SHIFT,
+				     sizeof(*ptes),
+				     GFP_KERNEL);
+		if (!mem)
+			return NULL;
+
+		area = alloc_vm_area(obj->base.size, mem);
+		if (!area) {
+			kvfree(mem);
+			return NULL;
+		}
+
+		ptes = mem;
+		for_each_sgt_daddr(addr, sgt_iter, sgt)
+			**ptes++ = io_wc_pte(addr);
+		kvfree(mem);
+
+		return area->addr;
 	}
 
 	/* A single page can always be kmapped */