diff mbox series

drm/i915/gem: Support discontiguous lmem object maps

Message ID 20200101220927.1074805-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show
Series drm/i915/gem: Support discontiguous lmem object maps | expand

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
diff mbox series

Patch

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 */