drm/i915: mark GEM object pages dirty when mapped & written by the CPU
authorDave Gordon <david.s.gordon@intel.com>
Thu, 10 Dec 2015 18:51:23 +0000 (18:51 +0000)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 11 Dec 2015 17:11:53 +0000 (18:11 +0100)
In various places, a single page of a (regular) GEM object is mapped into
CPU address space and updated. In each such case, either the page or the
the object should be marked dirty, to ensure that the modifications are
not discarded if the object is evicted under memory pressure.

The typical sequence is:
va = kmap_atomic(i915_gem_object_get_page(obj, pageno));
*(va+offset) = ...
kunmap_atomic(va);

Here we introduce i915_gem_object_get_dirty_page(), which performs the
same operation as i915_gem_object_get_page() but with the side-effect
of marking the returned page dirty in the pagecache.  This will ensure
that if the object is subsequently evicted (due to memory pressure),
the changes are written to backing store rather than discarded.

Note that it works only for regular (shmfs-backed) GEM objects, but (at
least for now) those are the only ones that are updated in this way --
the objects in question are contexts and batchbuffers, which are always
shmfs-backed.

Separate patches deal with the cases where whole objects are (or may
be) dirtied.

v3: Mark two more pages dirty in the page-boundary-crossing
    cases of the execbuffer relocation code [Chris Wilson]

Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1449773486-30822-2-git-send-email-david.s.gordon@intel.com
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_render_state.c
drivers/gpu/drm/i915/i915_guc_submission.c
drivers/gpu/drm/i915/intel_lrc.c

index 13fb681665c06f252b4899a6d76e3e5014a6af66..4c611b57e07bbed30ba7ce3ce60f756b1bc09801 100644 (file)
@@ -2907,6 +2907,9 @@ static inline int __sg_page_count(struct scatterlist *sg)
        return sg->length >> PAGE_SHIFT;
 }
 
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n);
+
 static inline struct page *
 i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
 {
index 26eba87ca35c86a1b02e403f57ca7c0d131f7e98..1592c54794635acce708b70817a540b0873c7667 100644 (file)
@@ -5185,6 +5185,21 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj)
        return false;
 }
 
+/* Like i915_gem_object_get_page(), but mark the returned page dirty */
+struct page *
+i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n)
+{
+       struct page *page;
+
+       /* Only default objects have per-page dirty tracking */
+       if (WARN_ON(obj->ops != &i915_gem_object_ops))
+               return NULL;
+
+       page = i915_gem_object_get_page(obj, n);
+       set_page_dirty(page);
+       return page;
+}
+
 /* Allocate a new GEM object and fill it with the supplied data */
 struct drm_i915_gem_object *
 i915_gem_object_create_from_data(struct drm_device *dev,
index 48ec4846e6f29b064a8b47bae8f3e1997699d3cd..5d01ea680dc1ed3ba416b42f235c2296cab0628f 100644 (file)
@@ -264,7 +264,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
        if (ret)
                return ret;
 
-       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
                                reloc->offset >> PAGE_SHIFT));
        *(uint32_t *)(vaddr + page_offset) = lower_32_bits(delta);
 
@@ -273,7 +273,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
 
                if (page_offset == 0) {
                        kunmap_atomic(vaddr);
-                       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
                            (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
                }
 
@@ -355,7 +355,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
        if (ret)
                return ret;
 
-       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
                                reloc->offset >> PAGE_SHIFT));
        clflush_write32(vaddr + page_offset, lower_32_bits(delta));
 
@@ -364,7 +364,7 @@ relocate_entry_clflush(struct drm_i915_gem_object *obj,
 
                if (page_offset == 0) {
                        kunmap_atomic(vaddr);
-                       vaddr = kmap_atomic(i915_gem_object_get_page(obj,
+                       vaddr = kmap_atomic(i915_gem_object_get_dirty_page(obj,
                            (reloc->offset + sizeof(uint32_t)) >> PAGE_SHIFT));
                }
 
index 5026a6267a88034b3cae18acc0674952a711521a..fc7e6d5c625102492a6b4c2343f4c9f73192f496 100644 (file)
@@ -103,7 +103,7 @@ static int render_state_setup(struct render_state *so)
        if (ret)
                return ret;
 
-       page = sg_page(so->obj->pages->sgl);
+       page = i915_gem_object_get_dirty_page(so->obj, 0);
        d = kmap(page);
 
        while (i < rodata->batch_items) {
index 0d23785ba818ce9dacda026ba41b549877bb78af..05aa7e61cbe05952d32281f49511ced642d07ca1 100644 (file)
@@ -568,7 +568,7 @@ static void lr_context_update(struct drm_i915_gem_request *rq)
        WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
        WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
 
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+       page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
        reg_state = kmap_atomic(page);
 
        reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj);
index 7644c48da4ea6e5ae5aabf2bcccbb5cc54dc254b..3aa614731d7e4b7160a85336d96df41469587991 100644 (file)
@@ -372,7 +372,7 @@ static int execlists_update_context(struct drm_i915_gem_request *rq)
        WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
        WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
 
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+       page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
        reg_state = kmap_atomic(page);
 
        reg_state[CTX_RING_TAIL+1] = rq->tail;
@@ -1425,7 +1425,7 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring)
                return ret;
        }
 
-       page = i915_gem_object_get_page(wa_ctx->obj, 0);
+       page = i915_gem_object_get_dirty_page(wa_ctx->obj, 0);
        batch = kmap_atomic(page);
        offset = 0;
 
@@ -2264,7 +2264,7 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
 
        /* The second page of the context object contains some fields which must
         * be set up prior to the first execution. */
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+       page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
        reg_state = kmap_atomic(page);
 
        /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
@@ -2350,9 +2350,6 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
        }
 
        kunmap_atomic(reg_state);
-
-       ctx_obj->dirty = 1;
-       set_page_dirty(page);
        i915_gem_object_unpin_pages(ctx_obj);
 
        return 0;
@@ -2536,7 +2533,7 @@ void intel_lr_context_reset(struct drm_device *dev,
                        WARN(1, "Failed get_pages for context obj\n");
                        continue;
                }
-               page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+               page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
                reg_state = kmap_atomic(page);
 
                reg_state[CTX_RING_HEAD+1] = 0;