@@ -178,6 +178,8 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head)
container_of(head, typeof(*obj), rcu);
struct drm_i915_private *i915 = to_i915(obj->base.dev);
+ /* Reset shared reservation object */
+ obj->base.resv = &obj->base._resv;
dma_resv_fini(&obj->base._resv);
i915_gem_object_free(obj);
@@ -185,7 +187,7 @@ static void __i915_gem_free_object_rcu(struct rcu_head *head)
atomic_dec(&i915->mm.free_count);
}
-static void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
+void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj)
{
/* Skip serialisation and waking the device if known to be not used. */
@@ -287,6 +289,14 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj)
GEM_BUG_ON(i915_gem_object_is_framebuffer(obj));
+ /*
+ * If object had been swapped out, free the hidden object.
+ */
+ if (obj->swapto) {
+ i915_gem_object_put(obj->swapto);
+ obj->swapto = NULL;
+ }
+
/*
* Before we free the object, make sure any pure RCU-only
* read-side critical sections are complete, e.g.
@@ -366,6 +366,8 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
+void __i915_gem_object_free_mmaps(struct drm_i915_gem_object *obj);
+
static inline int __must_check
i915_gem_object_pin_pages(struct drm_i915_gem_object *obj)
{
@@ -316,6 +316,12 @@ struct drm_i915_gem_object {
void *gvt_info;
};
+
+ /**
+ * object to swap-to if non-null.
+ */
+ bool do_swapping;
+ struct drm_i915_gem_object *swapto;
};
static inline struct drm_i915_gem_object *
@@ -231,7 +231,6 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
}
__i915_gem_object_reset_page_iter(obj);
- obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
return pages;
}
@@ -7,11 +7,135 @@
#include "i915_gem_region.h"
#include "i915_drv.h"
#include "i915_trace.h"
+#include "i915_gem_mman.h"
+
+static int
+i915_gem_object_swapout_pages(struct drm_i915_gem_object *obj,
+ struct sg_table *pages, unsigned int sizes)
+{
+ struct drm_i915_private *i915 = to_i915(obj->base.dev);
+ struct drm_i915_gem_object *dst, *src;
+ int err;
+
+ GEM_BUG_ON(obj->swapto);
+ GEM_BUG_ON(i915_gem_object_has_pages(obj));
+ GEM_BUG_ON(obj->mm.madv != I915_MADV_WILLNEED);
+ GEM_BUG_ON(obj->mm.region->type != INTEL_MEMORY_LOCAL);
+
+ assert_object_held(obj);
+
+ /* create a shadow object on smem region */
+ dst = i915_gem_object_create_shmem(i915, obj->base.size);
+ if (IS_ERR(dst))
+ return PTR_ERR(dst);
+
+ /* Share the dma-resv between the shadow- and the parent object */
+ dst->base.resv = obj->base.resv;
+ assert_object_held(dst);
+
+ /*
+ * create working object on the same region as 'obj',
+ * if 'obj' is used directly, it is set pages and is pinned
+ * again, other thread may wrongly use 'obj' pages.
+ */
+ src = i915_gem_object_create_region(obj->mm.region,
+ obj->base.size, 0);
+ if (IS_ERR(src)) {
+ i915_gem_object_put(dst);
+ return PTR_ERR(src);
+ }
+
+ /* set and pin working object pages */
+ i915_gem_object_lock_isolated(src);
+ __i915_gem_object_set_pages(src, pages, sizes);
+ __i915_gem_object_pin_pages(src);
+
+ /* copying the pages */
+ err = i915_gem_object_memcpy(dst, src);
+
+ __i915_gem_object_unpin_pages(src);
+ __i915_gem_object_unset_pages(src);
+ i915_gem_object_unlock(src);
+ i915_gem_object_put(src);
+
+ if (!err)
+ obj->swapto = dst;
+ else
+ i915_gem_object_put(dst);
+
+ return err;
+}
+
+static int
+i915_gem_object_swapin_pages(struct drm_i915_gem_object *obj,
+ struct sg_table *pages, unsigned int sizes)
+{
+ struct drm_i915_gem_object *dst, *src;
+ int err;
+
+ GEM_BUG_ON(!obj->swapto);
+ GEM_BUG_ON(i915_gem_object_has_pages(obj));
+ GEM_BUG_ON(obj->mm.madv != I915_MADV_WILLNEED);
+ GEM_BUG_ON(obj->mm.region->type != INTEL_MEMORY_LOCAL);
+
+ assert_object_held(obj);
+
+ src = obj->swapto;
+
+ /*
+ * create working object on the same region as 'obj',
+ * if 'obj' is used directly, it is set pages and is pinned
+ * again, other thread may wrongly use 'obj' pages.
+ */
+ dst = i915_gem_object_create_region(obj->mm.region,
+ obj->base.size, 0);
+ if (IS_ERR(dst)) {
+ err = PTR_ERR(dst);
+ return err;
+ }
+
+ /* @scr is sharing @obj's reservation object */
+ assert_object_held(src);
+
+ /* set and pin working object pages */
+ i915_gem_object_lock_isolated(dst);
+ __i915_gem_object_set_pages(dst, pages, sizes);
+ __i915_gem_object_pin_pages(dst);
+
+ /* copying the pages */
+ err = i915_gem_object_memcpy(dst, src);
+
+ __i915_gem_object_unpin_pages(dst);
+ __i915_gem_object_unset_pages(dst);
+ i915_gem_object_unlock(dst);
+ i915_gem_object_put(dst);
+
+ if (!err) {
+ obj->swapto = NULL;
+ i915_gem_object_put(src);
+ }
+
+ return err;
+}
void
i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
+ /* if need to save the page contents, swap them out */
+ if (obj->do_swapping) {
+ unsigned int sizes = obj->mm.page_sizes.phys;
+
+ GEM_BUG_ON(obj->mm.madv != I915_MADV_WILLNEED);
+ GEM_BUG_ON(i915_gem_object_is_volatile(obj));
+
+ if (i915_gem_object_swapout_pages(obj, pages, sizes)) {
+ /* swapout failed, keep the pages */
+ __i915_gem_object_set_pages(obj, pages, sizes);
+ return;
+ }
+ }
+
__intel_memory_region_put_pages_buddy(obj->mm.region, &obj->mm.blocks);
obj->mm.dirty = false;
@@ -95,8 +219,19 @@ i915_gem_object_get_pages_buddy(struct drm_i915_gem_object *obj)
sg_mark_end(sg);
i915_sg_trim(st);
- /* Intended for kernel internal use only */
- if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
+ /* if we saved the page contents, swap them in */
+ if (obj->swapto) {
+ GEM_BUG_ON(i915_gem_object_is_volatile(obj));
+
+ ret = i915_gem_object_swapin_pages(obj, st,
+ sg_page_sizes);
+ if (ret) {
+ /* swapin failed, free the pages */
+ __intel_memory_region_put_pages_buddy(mem, blocks);
+ ret = -ENXIO;
+ goto err_free_sg;
+ }
+ } else if (obj->flags & I915_BO_ALLOC_CPU_CLEAR) {
struct scatterlist *sg;
unsigned long i;
@@ -147,6 +147,11 @@ static int intel_memory_region_evict(struct intel_memory_region *mem,
mutex_unlock(&mem->objects.lock);
+ /* tell callee to do swapping */
+ if (i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM)
+ && pass == 1)
+ obj->do_swapping = true;
+
if (!i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE)) {
if (i915_gem_object_trylock(obj)) {
__i915_gem_object_put_pages(obj);
@@ -160,6 +165,7 @@ static int intel_memory_region_evict(struct intel_memory_region *mem,
}
}
+ obj->do_swapping = false;
i915_gem_object_put(obj);
mutex_lock(&mem->objects.lock);